Skip to content

Commit 2ee8e42

Browse files
committed
[platform] Support fibers in resumable drivers
1 parent c9c43cc commit 2ee8e42

18 files changed

+320
-27
lines changed

src/modm/driver/gpio/mcp23_transport_impl.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ template < class SpiMaster, class Cs >
7979
modm::ResumableResult<bool>
8080
modm::Mcp23TransportSpi<SpiMaster, Cs>::ping()
8181
{
82-
return { modm::rf::Stop, true };
82+
RF_BEGIN();
83+
RF_END_RETURN(true);
8384
}
8485

8586
// MARK: - register access

src/modm/driver/gpio/pca8574.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,9 +73,9 @@ class Pca8574 : public pca8574, public modm::I2cDevice< I2cMaster, 2 >, public m
7373
modm::ResumableResult<bool> inline
7474
setOutput(Pins pins)
7575
{
76-
// nothing needs to be changed for switching to output
76+
RF_BEGIN();
7777
direction.set(pins);
78-
return {modm::rf::Stopped, true};
78+
RF_END_RETURN(true);
7979
}
8080

8181
modm::ResumableResult<bool>

src/modm/platform/spi/at90_tiny_mega/module.lb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
def get_properties(env):
1515
device = env[":target"]
1616
driver = device.get_driver("spi:avr")
17-
properties = device.properties
17+
properties = {}
18+
properties["use_fiber"] = env.get(":processing:protothread:use_fiber", False)
1819
properties["target"] = device.identifier
1920
properties["partname"] = device.partname
2021
properties["driver"] = driver

src/modm/platform/spi/at90_tiny_mega/spi_master.cpp.in

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,14 @@ modm::platform::SpiMaster{{ id }}::transfer(uint8_t data)
8888

8989
data = SPDR{{ id }};
9090
return {modm::rf::Stop, data};
91+
%% elif use_fiber
92+
// start transfer by copying data into register
93+
SPDR{{ id }} = data;
94+
95+
do modm::fiber::yield();
96+
while (!(SPSR{{ id }} & (1 << SPIF{{ id }})));
97+
98+
return SPDR{{ id }};
9199
%% else
92100
// this is a manually implemented "fast resumable function"
93101
// there is no context or nesting protection, since we don't need it.
@@ -125,6 +133,14 @@ modm::platform::SpiMaster{{ id }}::transfer(const uint8_t *tx, uint8_t *rx, std:
125133
if (rx) rx[index] = result.getResult();
126134
}
127135
return {modm::rf::Stop};
136+
%% elif use_fiber
137+
for (std::size_t index = 0; index < length; index++)
138+
{
139+
// if tx == 0, we use a dummy byte 0x00 else we copy it from the array
140+
auto result = transfer(tx ? tx[index] : 0);
141+
// if rx != 0, we copy the result into the array
142+
if (rx) rx[index] = result;
143+
}
128144
%% else
129145
// this is a manually implemented "fast resumable function"
130146
// there is no context or nesting protection, since we don't need it.

src/modm/platform/spi/at90_tiny_mega_uart/uart_spi_master.cpp.in

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,30 @@ modm::platform::UartSpiMaster{{id}}::release(void *ctx)
111111
modm::ResumableResult<uint8_t>
112112
modm::platform::UartSpiMaster{{id}}::transfer(uint8_t data)
113113
{
114+
%% if use_fiber
115+
// wait for transmit register empty
116+
while (!((UCSR{{id}}A & (1 << UDRE{{id}}))))
117+
modm::fiber::yield();
118+
119+
%% if not extended
120+
if(dataOrder == DataOrder::MsbFirst) {
121+
data = ::modm::bitReverse(data);
122+
}
123+
%% endif
124+
UDR{{id}} = data;
125+
126+
// wait for receive register not empty
127+
do modm::fiber::yield();
128+
while (!((UCSR{{id}}A & (1 << RXC{{id}}))));
129+
130+
data = UDR{{id}};
131+
%% if not extended
132+
if(dataOrder == DataOrder::MsbFirst) {
133+
data = ::modm::bitReverse(data);
134+
}
135+
%% endif
136+
return data;
137+
%% else
114138
// this is a manually implemented "fast resumable function"
115139
// there is no context or nesting protection, since we don't need it.
116140
// there are only two states encoded into 1 bit (LSB of state):
@@ -148,12 +172,22 @@ modm::platform::UartSpiMaster{{id}}::transfer(uint8_t data)
148172
// transfer finished
149173
state &= ~Bit7;
150174
return {modm::rf::Stop, data};
175+
%% endif
151176
}
152177

153178
modm::ResumableResult<void>
154179
modm::platform::UartSpiMaster{{id}}::transfer(
155180
const uint8_t *tx, uint8_t *rx, std::size_t length)
156181
{
182+
%% if use_fiber
183+
for (std::size_t index = 0; index < length; index++)
184+
{
185+
// if tx == 0, we use a dummy byte 0x00 else we copy it from the array
186+
auto result = transfer(tx ? tx[index] : 0);
187+
// if rx != 0, we copy the result into the array
188+
if (rx) rx[index] = result;
189+
}
190+
%% else
157191
// this is a manually implemented "fast resumable function"
158192
// there is no context or nesting protection, since we don't need it.
159193
// there are only two states encoded into 1 bit (Bit6 of state):
@@ -193,4 +227,5 @@ modm::platform::UartSpiMaster{{id}}::transfer(
193227
state &= ~Bit6;
194228
return {modm::rf::Stop};
195229
}
230+
%% endif
196231
}

src/modm/platform/spi/bitbang/bitbang_spi_master_impl.hpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,11 @@ modm::ResumableResult<uint8_t>
200200
modm::platform::BitBangSpiMaster<Sck, Mosi, Miso>::transfer(uint8_t data)
201201
{
202202
data = transferBlocking(data);
203+
#ifdef MODM_RESUMABLE_IS_FIBER
204+
return data;
205+
#else
203206
return {modm::rf::Stop, data};
207+
#endif
204208
}
205209

206210
template <typename Sck, typename Mosi, typename Miso>
@@ -209,7 +213,9 @@ modm::platform::BitBangSpiMaster<Sck, Mosi, Miso>::transfer(
209213
const uint8_t *tx, uint8_t *rx, std::size_t length)
210214
{
211215
transferBlocking(tx, rx, length);
216+
#ifndef MODM_RESUMABLE_IS_FIBER
212217
return {modm::rf::Stop, 0};
218+
#endif
213219
}
214220

215221
// ----------------------------------------------------------------------------

src/modm/platform/spi/rp/module.lb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ class Instance(Module):
2323
return True
2424

2525
def build(self, env):
26-
env.substitutions = {"id": self.instance}
26+
env.substitutions = {
27+
"id": self.instance,
28+
"use_fiber": env.get(":processing:protothread:use_fiber", False)
29+
}
2730
env.outbasepath = "modm/src/modm/platform/spi"
2831

2932
env.template("spi_master.hpp.in", "spi_master_{}.hpp".format(self.instance))

src/modm/platform/spi/rp/spi_master.cpp.in

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,17 @@ modm::platform::SpiMaster{{ id }}::release(void *ctx)
6161
modm::ResumableResult<uint8_t>
6262
modm::platform::SpiMaster{{ id }}::transfer(uint8_t data)
6363
{
64+
%% if use_fiber
65+
// wait for previous transfer to finish
66+
while (txFifoFull()) modm::fiber::yield();
67+
68+
// start transfer by copying data into register
69+
write(data);
70+
71+
while (rxFifoEmpty()) modm::fiber::yield();
72+
73+
return read();
74+
%% else
6475
// this is a manually implemented "fast resumable function"
6576
// there is no context or nesting protection, since we don't need it.
6677
// there are only two states encoded into 1 bit (LSB of state):
@@ -75,7 +86,7 @@ modm::platform::SpiMaster{{ id }}::transfer(uint8_t data)
7586
return {modm::rf::Running};
7687

7788
// start transfer by copying data into register
78-
write(data);
89+
write(data);
7990

8091
// set LSB = Bit0
8192
state |= Bit0;
@@ -87,12 +98,22 @@ modm::platform::SpiMaster{{ id }}::transfer(uint8_t data)
8798
// transfer finished
8899
state &= ~Bit0;
89100
return {modm::rf::Stop, read()};
101+
%% endif
90102
}
91103

92104
modm::ResumableResult<void>
93105
modm::platform::SpiMaster{{ id }}::transfer(
94106
const uint8_t * tx, uint8_t * rx, std::size_t length)
95107
{
108+
%% if use_fiber
109+
for (std::size_t index = 0; index < length; index++)
110+
{
111+
// if tx == 0, we use a dummy byte 0x00 else we copy it from the array
112+
auto result = transfer(tx ? tx[index] : 0);
113+
// if rx != 0, we copy the result into the array
114+
if (rx) rx[index] = result;
115+
}
116+
%% else
96117
// this is a manually implemented "fast resumable function"
97118
// there is no context or nesting protection, since we don't need it.
98119
// there are only two states encoded into 1 bit (Bit1 of state):
@@ -134,6 +155,7 @@ modm::platform::SpiMaster{{ id }}::transfer(
134155
state &= ~Bit1;
135156
return {modm::rf::Stop};
136157
}
158+
%% endif
137159
}
138160

139161
void modm::platform::SpiMaster{{ id }}::transferBlocking(

src/modm/platform/spi/rp/spi_master_dma_impl.hpp.in

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,33 @@ modm::platform::SpiMaster{{ id }}_Dma<DmaChannelRx, DmaChannelTx>::waitCompleted
113113

114114
template <class DmaChannelRx, class DmaChannelTx>
115115
modm::ResumableResult<void>
116-
modm::platform::SpiMaster{{ id }}_Dma<DmaChannelRx, DmaChannelTx>::transfer(const uint8_t *tx,
117-
uint8_t *rx, std::size_t length)
116+
modm::platform::SpiMaster{{ id }}_Dma<DmaChannelRx, DmaChannelTx>::transfer(
117+
const uint8_t *tx, uint8_t *rx, std::size_t length)
118118
{
119+
%% if use_fiber
120+
if ((!rx and !tx) or length == 0) return;
121+
if constexpr (Dma::RxChannel::mask == 0) rx = nullptr;
122+
123+
startTransfer(tx, rx, length);
124+
125+
while (Dma::TxChannel::isBusy() or (rx and Dma::RxChannel::isBusy()))
126+
modm::fiber::yield();
127+
128+
while (!txFifoEmpty() or (rx and !rxFifoEmpty()) or isBusy())
129+
modm::fiber::yield();
130+
131+
if (!rx) {
132+
// Drain RX FIFO, then wait for shifting to finish (which
133+
// may be *after* TX FIFO drains), then drain RX FIFO again
134+
while (!rxFifoEmpty()) read();
135+
while (isBusy()) modm::fiber::yield();
136+
137+
// Don't leave overrun flag set
138+
spi{{ id }}_hw->icr = SPI_SSPICR_RORIC_BITS;
139+
}
140+
141+
disableDreq(Dma::DreqTx | Dma::DreqRx);
142+
%% else
119143
if ( (!rx && !tx) || length == 0) {
120144
return {modm::rf::Stop};
121145
}
@@ -137,19 +161,16 @@ modm::platform::SpiMaster{{ id }}_Dma<DmaChannelRx, DmaChannelTx>::transfer(cons
137161
[[fallthrough]];
138162

139163
default:
140-
while (true) {
141-
if (Dma::TxChannel::isBusy() or (rx && Dma::RxChannel::isBusy()))
142-
return { modm::rf::Running };
143-
if (!txFifoEmpty() or (rx && !rxFifoEmpty()) or isBusy())
144-
return { modm::rf::Running };
145-
break;
146-
}
164+
if (Dma::TxChannel::isBusy() or (rx && Dma::RxChannel::isBusy()))
165+
return { modm::rf::Running };
166+
if (!txFifoEmpty() or (rx && !rxFifoEmpty()) or isBusy())
167+
return { modm::rf::Running };
147168
if (!rx) {
148169
// Drain RX FIFO, then wait for shifting to finish (which may be *after*
149170
// TX FIFO drains), then drain RX FIFO again
150171
while (!rxFifoEmpty())
151172
(void)read();
152-
while (isBusy())
173+
if (isBusy())
153174
return { modm::rf::Running };
154175

155176
// Don't leave overrun flag set
@@ -162,4 +183,5 @@ modm::platform::SpiMaster{{ id }}_Dma<DmaChannelRx, DmaChannelTx>::transfer(cons
162183
state &= ~Bit1;
163184
return {modm::rf::Stop};
164185
}
186+
%% endif
165187
}

src/modm/platform/spi/sam/module.lb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def get_properties(env):
1414
device = env[":target"]
1515
driver = device.get_driver("spi")
1616
properties = {}
17+
properties["use_fiber"] = env.get(":processing:protothread:use_fiber", False)
1718
properties["target"] = device.identifier
1819
properties["features"] = driver["feature"] if "feature" in driver else []
1920
return properties

0 commit comments

Comments
 (0)