Skip to content

Commit 1f2c444

Browse files
mcbridejcsalkinium
authored andcommitted
[samg] Add faster transmit only method to SPI driver
Synchronous transfer is slowed down by the having to wait for a complete transfer to read the received byte. When only transmit is required, this method allows for writing the next transmit byte while the current byte is being written out to increase throughput. Also, removes unnecessary setOutput calls in connect method.
1 parent 79eb43b commit 1f2c444

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

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

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,9 @@ modm::platform::SpiMaster{{ id }}::transfer(uint8_t data)
6464
// LSB != Bit0 ?
6565
if ( !(state & Bit0) )
6666
{
67+
// Clear any stale rx data ready status
68+
read();
69+
6770
// wait for previous transfer to finish
6871
if (!isTransmitDataRegisterEmpty())
6972
return {modm::rf::Running};
@@ -129,3 +132,19 @@ modm::platform::SpiMaster{{ id }}::transfer(
129132
return {modm::rf::Stop};
130133
}
131134
}
135+
136+
void modm::platform::SpiMaster{{ id }}::transferBlocking(
137+
const uint8_t *tx, std::size_t length)
138+
{
139+
uint8_t index = 0;
140+
while(index < length) {
141+
// Wait for tx empty
142+
while(!isTransmitDataRegisterEmpty());
143+
// Write next byte
144+
write(tx ? tx[index] : 0);
145+
index++;
146+
}
147+
// wait for the internal shift register to be empty, indicating the transmission of the final byte is complete
148+
while(!isTxEmpty());
149+
}
150+

src/modm/platform/spi/sam/spi_master.hpp.in

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@ class SpiMaster{{ id }} : public modm::SpiMaster {
4141
return Regs()->SPI_SR & SPI_SR_TDRE;
4242
}
4343

44+
static inline bool
45+
isTxEmpty() {
46+
return Regs()->SPI_SR & SPI_SR_TXEMPTY;
47+
}
48+
4449
static inline bool
4550
isReceiveDataRegisterFull() {
4651
return Regs()->SPI_SR & SPI_SR_RDRF;
@@ -68,12 +73,10 @@ public:
6873

6974
if constexpr (!std::is_void<SckPin>::value) {
7075
using SckConnector = typename SckPin::template Connector<Flexcom, Flexcom::Sck>;
71-
SckPin::setOutput();
7276
SckConnector::connect();
7377
}
7478
if constexpr (!std::is_void<MisoPin>::value) {
7579
using MisoConnector = typename MisoPin::template Connector<Flexcom, Flexcom::Miso>;
76-
MisoPin::setOutput();
7780
MisoConnector::connect();
7881
}
7982
if constexpr (!std::is_void<MosiPin>::value) {
@@ -124,7 +127,13 @@ public:
124127

125128
static void
126129
transferBlocking(const uint8_t *tx, uint8_t *rx, std::size_t length) {
127-
RF_CALL_BLOCKING(transfer(tx, rx, length));
130+
// If we do not need to receive data, use a more efficient
131+
// transmit-only routine to increase throughput
132+
if(rx) {
133+
RF_CALL_BLOCKING(transfer(tx, rx, length));
134+
} else {
135+
transferBlocking(tx, length);
136+
}
128137
}
129138

130139
static modm::ResumableResult<uint8_t>
@@ -143,6 +152,17 @@ public:
143152
Regs()->SPI_MR &= ~SPI_MR_LLB;
144153
}
145154
}
155+
156+
protected:
157+
/** Perform transmit-only transaction
158+
*
159+
* A faster version of blocking transfer when transmitting only.
160+
*
161+
* If no receive is needed, the next byte can be loaded while the
162+
* current transfer is in progress.
163+
*/
164+
static void
165+
transferBlocking(const uint8_t *tx, std::size_t length);
146166
};
147167

148168
} // namespace modm::platform

0 commit comments

Comments
 (0)