Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rp2040] I2C implementation #830

Merged
merged 2 commits into from
Feb 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center"></td>
<td align="center"></td>
<td align="center">✅</td>
<td align="center">✅</td>
<td align="center">✅</td>
Expand Down
147 changes: 147 additions & 0 deletions examples/rp_pico/rtc_mcp7941x/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2022, Raphael Lehmann
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include <modm/board.hpp>
#include <modm/debug/logger.hpp>
#include <modm/driver/rtc/mcp7941x.hpp>
#include <modm/processing/protothread.hpp>
#include <modm/processing/timer.hpp>
#include <optional>


// Set the log level
#undef MODM_LOG_LEVEL
#define MODM_LOG_LEVEL modm::log::INFO

// Create an IODeviceWrapper around the Uart Peripheral we want to use
modm::IODeviceWrapper<Uart0, modm::IOBuffer::BlockIfFull> loggerDevice;

// Set all four logger streams to use the UART
modm::log::Logger modm::log::debug(loggerDevice);
modm::log::Logger modm::log::info(loggerDevice);
modm::log::Logger modm::log::warning(loggerDevice);
modm::log::Logger modm::log::error(loggerDevice);


using MyI2cMaster = modm::platform::I2cMaster0;
using I2cScl = modm::platform::Gpio1;
using I2cSda = modm::platform::Gpio0;


class RtcThread : public modm::pt::Protothread
{
public:
bool
update()
{
PT_BEGIN();

if(PT_CALL(rtc.oscillatorRunning())) {
MODM_LOG_ERROR << "RTC oscillator is running." << modm::endl;
}
else {
MODM_LOG_ERROR << "RTC oscillator is NOT running." << modm::endl;
}

MODM_LOG_INFO << "Setting date/time to 01.01.2020 00:00.00h" << modm::endl;
dateTime.days = 1;
dateTime.months = 1;
dateTime.years = 20;
dateTime.hours = 0;
dateTime.minutes = 0;
dateTime.seconds = 0;
while(not PT_CALL(rtc.setDateTime(dateTime))) {
MODM_LOG_ERROR << "Unable to set date/time." << modm::endl;
timeout.restart(500ms);
PT_WAIT_UNTIL(timeout.isExpired());
}

timeout.restart(500ms);
PT_WAIT_UNTIL(timeout.isExpired());

if(PT_CALL(rtc.oscillatorRunning())) {
MODM_LOG_ERROR << "RTC oscillator is running." << modm::endl;
}
else {
MODM_LOG_ERROR << "RTC oscillator is NOT running." << modm::endl;
}

while (true)
{
dateTime2 = PT_CALL(rtc.getDateTime());
if(dateTime2.has_value()) {
MODM_LOG_INFO.printf("%02u.%02u.%02u ", dateTime2->days, dateTime2->months, dateTime2->years);
MODM_LOG_INFO.printf("%02u:%02u.%02uh\n", dateTime2->hours, dateTime2->minutes, dateTime2->seconds);
}
else {
MODM_LOG_ERROR << "Unable to read from RTC." << modm::endl;
}

timeout.restart(2500ms);
PT_WAIT_UNTIL(timeout.isExpired());
}

PT_END();
}

private:
modm::Mcp7941x<MyI2cMaster> rtc{};
modm::mcp7941x::DateTime dateTime{};
std::optional<modm::mcp7941x::DateTime> dateTime2{};
modm::ShortTimeout timeout;
};


using namespace Board;

int
main()
{
Board::initialize();

// initialize Uart0 for MODM_LOG_*
Uart0::connect<GpioOutput16::Tx>();
Uart0::initialize<Board::SystemClock, 115200_Bd>();

Leds::setOutput();

MyI2cMaster::connect<I2cScl::Scl, I2cSda::Sda>();
MyI2cMaster::initialize<SystemClock, 100_kHz>();

MODM_LOG_INFO << "RTC MCP7941x Example on Raspberry Pico" << modm::endl;

modm::Mcp7941xEeprom<MyI2cMaster> eeprom{};
if (auto data = RF_CALL_BLOCKING(eeprom.getUniqueId())) {
MODM_LOG_INFO << "Unique ID (EUI-48/64): ";
MODM_LOG_INFO << modm::hex << (*data)[0] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[1] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[2] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[3] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[4] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[5] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[6] << modm::ascii << ":";
MODM_LOG_INFO << modm::hex << (*data)[7] << modm::ascii << modm::endl;
}
else {
MODM_LOG_ERROR << "Unable to read unique ID from RTC." << modm::endl;
}
modm::delay(500ms);

RtcThread rtcThread;

while (true)
{
LedGreen::toggle();
rtcThread.update();
}

return 0;
}
17 changes: 17 additions & 0 deletions examples/rp_pico/rtc_mcp7941x/project.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<library>
<extends>modm:rp-pico</extends>
<options>
<option name="modm:build:build.path">../../../build/rp_pico/rtc_mcp7941x</option>
<option name="modm:platform:cortex-m:vector_table_location">ram</option>
</options>
<modules>
<module>modm:debug</module>
<module>modm:driver:mcp7941x</module>
<module>modm:io</module>
<module>modm:platform:i2c:0</module>
<module>modm:platform:uart:0</module>
<module>modm:processing:protothread</module>
<module>modm:processing:timer</module>
<module>modm:build:scons</module>
</modules>
</library>
12 changes: 9 additions & 3 deletions src/modm/platform/gpio/rp/base.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ struct Gpio
mA_8 = 2,
mA_12 = 3,
};
enum class
SlewRate : uint8_t
{
Slow = 0,
Fast = 1
};

enum class
Port
Expand Down Expand Up @@ -115,15 +121,15 @@ struct Gpio::PortRegs<Gpio::Port::{{ port | capitalize }}>
{
hw_write_masked(
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
strength << PADS_BANK0_GPIO0_DRIVE_LSB,
uint32_t(strength) << PADS_BANK0_GPIO0_DRIVE_LSB,
PADS_BANK0_GPIO0_DRIVE_BITS
);
}
static void set_slewfast(uint8_t pin, bool fast)
static void set_slewrate(uint8_t pin, uint8_t rate)
{
hw_write_masked(
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
(fast?1:0) << PADS_BANK0_GPIO0_SLEWFAST_LSB,
uint32_t(rate) << PADS_BANK0_GPIO0_SLEWFAST_LSB,
PADS_BANK0_GPIO0_SLEWFAST_BITS
);
}
Expand Down
5 changes: 5 additions & 0 deletions src/modm/platform/gpio/rp/set.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,11 @@ public:
(PortRegs<Gpios::port>::set_pue_pde(Gpios::pin, type==InputType::PullUp, type==InputType::PullDown), ...);
}

static void setSlewRate(SlewRate rate)
{
(PortRegs<Gpios::port>::set_slewrate(Gpios::pin, uint8_t(rate)), ...);
}

static void set()
{
%% for port, id in ports.items()
Expand Down
1 change: 1 addition & 0 deletions src/modm/platform/gpio/rp/static.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public:
static void setInput() { PinSet::setInput(); }
static void setInput(InputType type) { PinSet::setInput(type); }
static void configure(InputType type) { PinSet::configure(type); }
static void setSlewRate(SlewRate rate) { PinSet::setSlewRate(rate); }

static bool read() { return Regs::sio_in() & mask; }

Expand Down
125 changes: 125 additions & 0 deletions src/modm/platform/i2c/rp/i2c_master.cpp.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/*
* Copyright (c) 2022, Andrey Kunitsyn
*
* This file is part of the modm project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
// ----------------------------------------------------------------------------

#include "i2c_master_{{ id }}.hpp"
#include <modm/platform/core/resets.hpp>


namespace
{
struct SimpleWait
{
using State = uint_fast32_t;
static State start() {
return 100'000;
}
static bool check(State& s) {
return --s == 0;
}
};
}
// ----------------------------------------------------------------------------

void modm::platform::I2cMaster{{ id }}::hwReset()
{
Resets::reset(RESETS_RESET_I2C{{ id }}_BITS);
}

void modm::platform::I2cMaster{{ id }}::hwUnReset()
{
Resets::unresetWait(RESETS_RESET_I2C{{ id }}_BITS);
}

void
modm::platform::I2cMaster{{ id }}::reset()
{
errorState = Error::SoftwareReset;
restartOnNext = false;
}

bool
modm::platform::I2cMaster{{ id }}::start(I2cTransaction *transaction, ConfigurationHandler handler)
{
if (!transaction)
{
return true;
}
if (not transaction->attaching())
{
transaction->detaching(modm::I2c::DetachCause::FailedToAttach);
// return false; // done at the end of the function
rleh marked this conversation as resolved.
Show resolved Hide resolved
}
else
{
// reset error state
errorState = Error::NoError;
// call the configuration function
if (handler and configuration != handler) {
configuration = handler;
configuration();
}

// ask the transaction object about address and next operation.
auto starting = transaction->starting();
uint8_t address = (starting.address & 0xfe) >> 1;

hw().enable = 0;
hw().tar = address;
hw().enable = 1;

auto nextOperation = static_cast<modm::I2c::Operation>(starting.next);

do
{
switch (nextOperation)
{
case modm::I2c::Operation::Write:
{
auto writing = transaction->writing();
// what next?
nextOperation = static_cast<modm::I2c::Operation>(writing.next);
doWrite<SimpleWait>(writing.buffer,writing.length,nextOperation!=I2c::Operation::Stop);
} break;

case I2c::Operation::Read:
{
auto reading = transaction->reading();
nextOperation = static_cast<modm::I2c::Operation>(reading.next);
doRead<SimpleWait>(reading.buffer,reading.length,nextOperation!=I2c::Operation::Stop);
break;
}

case I2c::Operation::Restart:
starting = transaction->starting();
nextOperation = static_cast<modm::I2c::Operation>(starting.next);
break;

default:
case I2c::Operation::Stop:
transaction->detaching(modm::I2c::DetachCause::NormalStop);
return true;
}
if (errorState != Error::NoError)
{
transaction->detaching(modm::I2c::DetachCause::ErrorCondition);
return true;
}
}
while (true);
}
return false;
}

modm::I2cMaster::Error
modm::platform::I2cMaster{{ id }}::getErrorState()
{
return errorState;
}
Loading