Skip to content

Commit 23b4c06

Browse files
committed
[rp2040] I2C implementation
1 parent 72d35c7 commit 23b4c06

File tree

8 files changed

+552
-4
lines changed

8 files changed

+552
-4
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,7 @@ Please [discover modm's peripheral drivers for your specific device][discover].
342342
<td align="center">○</td>
343343
<td align="center">○</td>
344344
<td align="center">○</td>
345-
<td align="center"></td>
345+
<td align="center"></td>
346346
<td align="center">✅</td>
347347
<td align="center">✅</td>
348348
<td align="center">✅</td>

src/modm/platform/gpio/rp/base.hpp.in

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,12 @@ struct Gpio
5555
mA_8 = 2,
5656
mA_12 = 3,
5757
};
58+
enum class
59+
SlewRate : uint8_t
60+
{
61+
Slow = 0,
62+
Fast = 1
63+
};
5864

5965
enum class
6066
Port
@@ -115,15 +121,15 @@ struct Gpio::PortRegs<Gpio::Port::{{ port | capitalize }}>
115121
{
116122
hw_write_masked(
117123
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
118-
strength << PADS_BANK0_GPIO0_DRIVE_LSB,
124+
uint32_t(strength) << PADS_BANK0_GPIO0_DRIVE_LSB,
119125
PADS_BANK0_GPIO0_DRIVE_BITS
120126
);
121127
}
122-
static void set_slewfast(uint8_t pin, bool fast)
128+
static void set_slewrate(uint8_t pin, uint8_t rate)
123129
{
124130
hw_write_masked(
125131
&pads{{(pads_names[port] or port) | lower}}_hw->io[pin],
126-
(fast?1:0) << PADS_BANK0_GPIO0_SLEWFAST_LSB,
132+
uint32_t(rate) << PADS_BANK0_GPIO0_SLEWFAST_LSB,
127133
PADS_BANK0_GPIO0_SLEWFAST_BITS
128134
);
129135
}

src/modm/platform/gpio/rp/set.hpp.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ public:
9191
(PortRegs<Gpios::port>::set_pue_pde(Gpios::pin, type==InputType::PullUp, type==InputType::PullDown), ...);
9292
}
9393

94+
static void setSlewRate(SlewRate rate)
95+
{
96+
(PortRegs<Gpios::port>::set_slewrate(Gpios::pin, uint8_t(rate)), ...);
97+
}
98+
9499
static void set()
95100
{
96101
%% for port, id in ports.items()

src/modm/platform/gpio/rp/static.hpp.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ public:
6464
static void setInput() { PinSet::setInput(); }
6565
static void setInput(InputType type) { PinSet::setInput(type); }
6666
static void configure(InputType type) { PinSet::configure(type); }
67+
static void setSlewRate(SlewRate rate) { PinSet::setSlewRate(rate); }
6768

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

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* Copyright (c) 2022, Andrey Kunitsyn
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#include "i2c_master_{{ id }}.hpp"
13+
#include <modm/platform/core/resets.hpp>
14+
15+
16+
namespace
17+
{
18+
struct SimpleWait
19+
{
20+
using State = uint_fast32_t;
21+
static State start() {
22+
return 100'000;
23+
}
24+
static bool check(State& s) {
25+
return --s == 0;
26+
}
27+
};
28+
}
29+
// ----------------------------------------------------------------------------
30+
31+
void modm::platform::I2cMaster{{ id }}::hwReset()
32+
{
33+
Resets::reset(RESETS_RESET_I2C{{ id }}_BITS);
34+
}
35+
36+
void modm::platform::I2cMaster{{ id }}::hwUnReset()
37+
{
38+
Resets::unresetWait(RESETS_RESET_I2C{{ id }}_BITS);
39+
}
40+
41+
void
42+
modm::platform::I2cMaster{{ id }}::reset()
43+
{
44+
errorState = Error::SoftwareReset;
45+
restartOnNext = false;
46+
}
47+
48+
bool
49+
modm::platform::I2cMaster{{ id }}::start(I2cTransaction *transaction, ConfigurationHandler handler)
50+
{
51+
if (!transaction)
52+
{
53+
return true;
54+
}
55+
if (not transaction->attaching())
56+
{
57+
transaction->detaching(modm::I2c::DetachCause::FailedToAttach);
58+
// return false; // done at the end of the function
59+
}
60+
else
61+
{
62+
// reset error state
63+
errorState = Error::NoError;
64+
// call the configuration function
65+
if (handler and configuration != handler) {
66+
configuration = handler;
67+
configuration();
68+
}
69+
70+
// ask the transaction object about address and next operation.
71+
auto starting = transaction->starting();
72+
uint8_t address = (starting.address & 0xfe) >> 1;
73+
74+
hw().enable = 0;
75+
hw().tar = address;
76+
hw().enable = 1;
77+
78+
auto nextOperation = static_cast<modm::I2c::Operation>(starting.next);
79+
80+
do
81+
{
82+
switch (nextOperation)
83+
{
84+
case modm::I2c::Operation::Write:
85+
{
86+
auto writing = transaction->writing();
87+
// what next?
88+
nextOperation = static_cast<modm::I2c::Operation>(writing.next);
89+
doWrite<SimpleWait>(writing.buffer,writing.length,nextOperation!=I2c::Operation::Stop);
90+
} break;
91+
92+
case I2c::Operation::Read:
93+
{
94+
auto reading = transaction->reading();
95+
nextOperation = static_cast<modm::I2c::Operation>(reading.next);
96+
doRead<SimpleWait>(reading.buffer,reading.length,nextOperation!=I2c::Operation::Stop);
97+
break;
98+
}
99+
100+
case I2c::Operation::Restart:
101+
starting = transaction->starting();
102+
nextOperation = static_cast<modm::I2c::Operation>(starting.next);
103+
break;
104+
105+
default:
106+
case I2c::Operation::Stop:
107+
transaction->detaching(modm::I2c::DetachCause::NormalStop);
108+
return true;
109+
}
110+
if (errorState != Error::NoError)
111+
{
112+
transaction->detaching(modm::I2c::DetachCause::ErrorCondition);
113+
return true;
114+
}
115+
}
116+
while (true);
117+
}
118+
return false;
119+
}
120+
121+
modm::I2cMaster::Error
122+
modm::platform::I2cMaster{{ id }}::getErrorState()
123+
{
124+
return errorState;
125+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright (c) 2022, Andrey Kunitsyn
3+
*
4+
* This file is part of the modm project.
5+
*
6+
* This Source Code Form is subject to the terms of the Mozilla Public
7+
* License, v. 2.0. If a copy of the MPL was not distributed with this
8+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
9+
*/
10+
// ----------------------------------------------------------------------------
11+
12+
#pragma once
13+
14+
#include "../device.hpp"
15+
#include <modm/platform/gpio/connector.hpp>
16+
#include <modm/architecture/interface/i2c_master.hpp>
17+
#include <modm/math/algorithm/prescaler.hpp>
18+
#include <hardware/structs/i2c.h>
19+
20+
namespace modm::platform
21+
{
22+
23+
/**
24+
* I2cMaster implementation of I2C{{ id }} module.
25+
*
26+
* @author Andrey Kunitsyn
27+
* @ingroup modm_platform_i2c modm_platform_i2c_{{id}}
28+
*/
29+
class I2cMaster{{ id }} : public ::modm::I2cMaster
30+
{
31+
public:
32+
static inline i2c_hw_t& hw() { return *i2c{{ id }}_hw; }
33+
public:
34+
template<class... Signals, ResetDevices reset = ResetDevices::Standard>
35+
static void
36+
connect(PullUps pullups = PullUps::External)
37+
{
38+
using Connector = GpioConnector<Peripheral::I2c{{ id }}, Signals...>;
39+
using Scl = typename Connector::template GetSignal<Gpio::Signal::Scl>;
40+
using Sda = typename Connector::template GetSignal<Gpio::Signal::Sda>;
41+
static_assert(sizeof...(Signals) == 2 and
42+
Connector::template IsValid<Scl> and Connector::template IsValid<Sda>,
43+
"I2cMaster{{id}}::connect() requires one Scl and one Sda signal!");
44+
const Gpio::InputType input =
45+
(pullups == PullUps::Internal) ? Gpio::InputType::PullUp : Gpio::InputType::Floating;
46+
47+
Connector::disconnect();
48+
Scl::configure(input);
49+
Scl::setSlewRate(Gpio::SlewRate::Slow);
50+
Sda::configure(input);
51+
Sda::setSlewRate(Gpio::SlewRate::Slow);
52+
if (reset != ResetDevices::NoReset) resetDevices<Scl, uint32_t(reset)>();
53+
Connector::connect();
54+
}
55+
56+
static void hwReset();
57+
static void hwUnReset();
58+
59+
/**
60+
* Set up the I2C module for master operation.
61+
*
62+
* @param rate
63+
* `Standard` or `Fast` or `Fast+`, `High` datarate is not supported
64+
*/
65+
template<class SystemClock, baudrate_t baudrate=kBd(100), percent_t tolerance=pct(5)>
66+
static void
67+
initialize();
68+
69+
template< class SystemClock, baudrate_t baudrate, percent_t tolerance=pct(5)>
70+
static uint32_t
71+
setBaudrate();
72+
73+
// start documentation inherited
74+
static bool
75+
start(I2cTransaction *transaction, ConfigurationHandler handler = nullptr);
76+
77+
static Error
78+
getErrorState();
79+
80+
static void
81+
reset();
82+
// end documentation inherited
83+
84+
template <typename Wait>
85+
static Error transfer(uint8_t addr,const uint8_t* write,size_t writeLen,
86+
uint8_t* read, size_t readLen);
87+
88+
private:
89+
template <typename Wait>
90+
static void doWrite(const uint8_t* write,size_t writeLen,bool nostop);
91+
template <typename Wait>
92+
static void doRead(uint8_t* read,size_t readLen,bool nostop);
93+
static bool isReadAvailable() {
94+
return hw().rxflr;
95+
}
96+
static bool isWriteAvailable() {
97+
constexpr size_t IC_TX_BUFFER_DEPTH = 16;
98+
return IC_TX_BUFFER_DEPTH - hw().txflr;
99+
}
100+
static inline Error errorState{Error::NoError};
101+
static inline I2c::ConfigurationHandler configuration{nullptr};
102+
static inline bool restartOnNext{false};
103+
};
104+
105+
} // namespace modm::platform
106+
#include "i2c_master_impl_{{id}}.hpp"

0 commit comments

Comments
 (0)