Skip to content

Commit 1da0881

Browse files
committed
Spi::transfer16, Spi::transfer(.., repeat), Avr SPI: ISR support, Spi-state as MODM_FLAGS8
1 parent d135b07 commit 1da0881

16 files changed

+711
-237
lines changed

src/modm/platform/dma/stm32/dma.hpp.in

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,18 @@ public:
189189
ChannelHal::setPeripheralAddress(address);
190190
}
191191

192+
static void
193+
setMemoryDataSize(MemoryDataSize memoryDataSize)
194+
{
195+
ChannelHal::setMemoryDataSize(memoryDataSize);
196+
}
197+
198+
static void
199+
setPeripheralDataSize(PeripheralDataSize peripheralDataSize)
200+
{
201+
ChannelHal::setPeripheralDataSize(peripheralDataSize);
202+
}
203+
192204
/**
193205
* Enable/disable memory increment
194206
*

src/modm/platform/dma/stm32/dma_base.hpp.in

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ public:
152152
Bit16 = HalfWord,
153153
Word = {{ reg_prefix }}_MSIZE_1,
154154
Bit32 = Word,
155+
All = DMA_CCR_MSIZE_0 | DMA_CCR_MSIZE_1
155156
};
156157

157158
enum class
@@ -163,6 +164,7 @@ public:
163164
Bit16 = HalfWord,
164165
Word = {{ reg_prefix }}_PSIZE_1,
165166
Bit32 = Word,
167+
All = DMA_CCR_PSIZE_0 | DMA_CCR_PSIZE_1
166168
};
167169

168170
enum class

src/modm/platform/dma/stm32/dma_hal.hpp.in

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,22 @@ public:
200200
Base->CPAR = address;
201201
}
202202

203+
static void
204+
setMemoryDataSize(MemoryDataSize memoryDataSize)
205+
{
206+
DMA_Channel_TypeDef *Base = (DMA_Channel_TypeDef *) CHANNEL_BASE;
207+
Base->CCR &= ~uint32_t(MemoryDataSize::All);
208+
Base->CCR |= uint32_t(memoryDataSize);
209+
}
210+
211+
static void
212+
setPeripheralDataSize(PeripheralDataSize peripheralDataSize)
213+
{
214+
DMA_Channel_TypeDef *Base = (DMA_Channel_TypeDef *) CHANNEL_BASE;
215+
Base->CCR &= ~uint32_t(PeripheralDataSize::All);
216+
Base->CCR |= uint32_t(peripheralDataSize);
217+
}
218+
203219
/**
204220
* Enable/disable memory increment
205221
*
@@ -240,9 +256,11 @@ public:
240256

241257
/**
242258
* Set length of data to transfer
259+
*
260+
* @param lenght range: 0-65535
243261
*/
244262
static void
245-
setDataLength(std::size_t length)
263+
setDataLength(uint16_t length)
246264
{
247265
DMA_Channel_TypeDef *Base = (DMA_Channel_TypeDef *) CHANNEL_BASE;
248266
Base->CNDTR = length;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ class Instance(Module):
5050

5151
env.template("spi.hpp.in", "spi{}.hpp".format(self.instance))
5252
env.template("spi_master.hpp.in", "spi_master{}.hpp".format(self.instance))
53+
env.template("spi_master_impl.hpp.in", "spi_master{}_impl.hpp".format(self.instance))
5354
env.template("spi_master.cpp.in", "spi_master{}.cpp".format(self.instance))
5455

5556
def init(module):
@@ -87,6 +88,7 @@ def build(env):
8788
env.outbasepath = "modm/src/modm/platform/spi"
8889

8990
if "instance" not in driver:
91+
env.template("spi.hpp.in")
9092
env.template("spi_master.hpp.in")
93+
env.template("spi_master_impl.hpp.in")
9194
env.template("spi_master.cpp.in")
92-
env.template("spi.hpp.in")

src/modm/platform/spi/at90_tiny_mega/spi.hpp.in

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ struct Spi
7171
Div64 = (1 << SPR1{{ id }}),
7272
Div128 = (1 << SPR1{{ id }}) | (1 << SPR0{{ id }}),
7373
};
74+
75+
enum State : uint8_t {
76+
Word = Bit0, // 0: Byte (uint8_t) transaction, 1: Word (uint16_t) transaction
77+
AutoIncr = Bit1, // 0: Always send first data of tx, 1: Send consecutive data of tx
78+
Idle = Bit2, // 1: Transaction is Running
79+
ByteHigh = Bit3, // 1: High byte of word has been send
80+
};
81+
MODM_FLAGS8(State);
7482
};
7583

7684
} // namespace platform

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

Lines changed: 94 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* Copyright (c) 2013-2018, Niklas Hauser
33
* Copyright (c) 2014, Sascha Schade
44
* Copyright (c) 2017, Fabian Greif
5+
* Copyright (c) 2021, Thomas Sommer
56
*
67
* This file is part of the modm project.
78
*
@@ -18,28 +19,101 @@
1819

1920
#include <modm/math/utils/bit_constants.hpp>
2021
#include <modm/architecture/interface/atomic_lock.hpp>
22+
#include <modm/architecture/interface/interrupt.hpp>
2123

22-
// bit 7 (0x80) is used for transfer 1 byte
23-
// bit 6 (0x40) is used for transfer multiple byte
24-
// bit 5-0 (0x3f) are used to store the acquire count
25-
uint8_t
26-
modm::platform::SpiMaster{{ id }}::state(0);
24+
uint8_t modm::platform::SpiMaster{{ id }}::count(0);
2725

28-
void *
29-
modm::platform::SpiMaster{{ id }}::context(nullptr);
26+
void* modm::platform::SpiMaster{{ id }}::context(nullptr);
3027

3128
modm::Spi::ConfigurationHandler
32-
modm::platform::SpiMaster{{ id }}::configuration(nullptr);
29+
modm::platform::SpiMaster{{ id }}::configuration(nullptr);
30+
31+
using State = modm::platform::Spi::State;
32+
modm::platform::Spi::State_t state(0);
33+
34+
// ----------------------------------------------------------------------------
35+
36+
void* tx(nullptr);
37+
std::size_t index(0);
38+
std::size_t length(0);
39+
40+
void* rx(nullptr);
41+
uint16_t temp(0);
42+
43+
// ----------------------------------------------------------------------------
44+
45+
MODM_ISR(SPI_STC{{ id }}) {
46+
// High byte of word is out?
47+
if(state.all(State::ByteHigh)) {
48+
// Send low byte of word
49+
const std::size_t i = state.all(State::AutoIncr) ? index : 0;
50+
SPDR{{ id }} = static_cast<uint16_t*>(tx)[i];
51+
state.reset(State::ByteHigh);
52+
return;
53+
}
54+
55+
// Increment index
56+
if (++index == length) {
57+
if(state.all(State::AutoIncr) and rx) {
58+
// TODO Store last received data
59+
static_cast<uint8_t*>(rx)[index - 1] = SPDR{{ id }};
60+
}
61+
62+
// Job Done, disable Interrupt
63+
SPCR{{ id }} &= ~(1 << SPIE{{ id }});
64+
return;
65+
}
66+
67+
// Send next Item
68+
const std::size_t i = state.all(State::AutoIncr) ? index : 0;
69+
if(state.all(State::Word)) {
70+
// TODO Store high byte of word
71+
// if(rx)
72+
// static_cast<uint16_t*>(rx)[i] = SPDR{{ id }};
73+
74+
// Send high byte of word
75+
SPDR{{ id }} = static_cast<uint16_t*>(tx)[i] >> 8;
76+
state.set(State::ByteHigh);
77+
} else {
78+
// TODO Store byte
79+
// if(rx)
80+
// static_cast<uint8_t*>(rx)[i] = SPDR{{ id }};
81+
// Send byte
82+
SPDR{{ id }} = static_cast<uint8_t*>(tx)[i];
83+
}
84+
}
85+
86+
template <>
87+
void modm::platform::SpiMaster{{ id }}::begin<uint8_t>() {
88+
index = 0;
89+
state.set(State::Idle);
90+
state.reset(State::Word);
91+
92+
// start transfer by copying data into register
93+
SPDR{{ id }} = static_cast<uint8_t*>(tx)[index];
94+
SPCR{{ id }} |= (1 << SPIE{{ id }}); // enable Interrupt
95+
}
96+
97+
template <>
98+
void modm::platform::SpiMaster{{ id }}::begin<uint16_t>() {
99+
index = 0;
100+
state.set(State::Idle);
101+
state.set(State::Word);
102+
state.set(State::ByteHigh);
103+
104+
// start transfer by copying data into register
105+
SPDR{{ id }} = static_cast<uint16_t*>(tx)[index] >> 8;
106+
SPCR{{ id }} |= (1 << SPIE{{ id }}); // enable Interrupt
107+
}
33108
// ----------------------------------------------------------------------------
34109

35-
void
36-
modm::platform::SpiMaster{{ id }}::initialize(Prescaler prescaler)
110+
void modm::platform::SpiMaster{{ id }}::initialize(Prescaler prescaler)
37111
{
38112
modm::atomic::Lock lock;
39113

40-
SPCR{{ id }} = (1 << SPE{{ id }}) | (1 << MSTR{{ id }}) | (static_cast<uint8_t>(prescaler) & ~0x80);
41-
SPSR{{ id }} = (static_cast<uint8_t>(prescaler) & 0x80) ? (1 << SPI2X{{ id }}) : 0;
42-
state &= 0x3f;
114+
SPCR{{ id }} = (1 << SPE) | (1 << MSTR) | (static_cast<uint8_t>(prescaler) & ~0x80);
115+
SPSR{{ id }} = (static_cast<uint8_t>(prescaler) & 0x80) ? (1 << SPI2X) : 0;
116+
state = State(0);
43117
}
44118
// ----------------------------------------------------------------------------
45119

@@ -49,17 +123,18 @@ modm::platform::SpiMaster{{ id }}::acquire(void *ctx, ConfigurationHandler handl
49123
if (context == nullptr)
50124
{
51125
context = ctx;
52-
state = (state & ~0x3f) | 1;
126+
count = 1;
53127
// if handler is not nullptr and is different from previous configuration
54-
if (handler and configuration != handler) {
128+
if (handler and configuration != handler)
129+
{
55130
configuration = handler;
56131
configuration();
57132
}
58133
return 1;
59134
}
60135

61136
if (ctx == context)
62-
return (++state & 0x3f);
137+
return ++count;
63138

64139
return 0;
65140
}
@@ -69,101 +144,8 @@ modm::platform::SpiMaster{{ id }}::release(void *ctx)
69144
{
70145
if (ctx == context)
71146
{
72-
if ((--state & 0x3f) == 0)
147+
if (--count == 0)
73148
context = nullptr;
74149
}
75-
return (state & 0x3f);
76-
}
77-
// ----------------------------------------------------------------------------
78-
79-
modm::ResumableResult<uint8_t>
80-
modm::platform::SpiMaster{{ id }}::transfer(uint8_t data)
81-
{
82-
%% if options["busywait"]
83-
SPDR{{ id }} = data;
84-
85-
// wait for transfer to finish
86-
while (!(SPSR{{ id }} & (1 << SPIF{{ id }})))
87-
;
88-
89-
data = SPDR{{ id }};
90-
return {modm::rf::Stop, data};
91-
%% else
92-
// this is a manually implemented "fast resumable function"
93-
// there is no context or nesting protection, since we don't need it.
94-
// there are only two states encoded into 1 bit (LSB of state):
95-
// 1. waiting to start, and
96-
// 2. waiting to finish.
97-
98-
// MSB != Bit7 ?
99-
if ( !(state & Bit7) )
100-
{
101-
// start transfer by copying data into register
102-
SPDR{{ id }} = data;
103-
104-
// set MSB = Bit7
105-
state |= Bit7;
106-
}
107-
108-
// wait for transfer to finish
109-
if (!(SPSR{{ id }} & (1 << SPIF{{ id }})))
110-
return {modm::rf::Running};
111-
112-
data = SPDR{{ id }};
113-
state &= ~Bit7;
114-
return {modm::rf::Stop, data};
115-
%% endif
116-
}
117-
118-
modm::ResumableResult<void>
119-
modm::platform::SpiMaster{{ id }}::transfer(const uint8_t *tx, uint8_t *rx, std::size_t length)
120-
{
121-
%% if options["busywait"]
122-
for (std::size_t index = 0; index < length; index++)
123-
{
124-
modm::ResumableResult<uint8_t> result = transfer(tx ? tx[index] : 0);
125-
if (rx) rx[index] = result.getResult();
126-
}
127-
return {modm::rf::Stop};
128-
%% else
129-
// this is a manually implemented "fast resumable function"
130-
// there is no context or nesting protection, since we don't need it.
131-
// there are only two states encoded into 1 bit (Bit6 of state):
132-
// 1. initialize index, and
133-
// 2. wait for 1-byte transfer to finish.
134-
135-
// we need to globally remember which byte we are currently transferring
136-
static std::size_t index = 0;
137-
138-
// we are only interested in Bit6
139-
switch(state & Bit6)
140-
{
141-
case 0:
142-
// we will only visit this state once
143-
state |= Bit6;
144-
145-
// initialize index and check range
146-
index = 0;
147-
while (index < length)
148-
{
149-
default:
150-
{
151-
// call the resumable function
152-
modm::ResumableResult<uint8_t> result = transfer(tx ? tx[index] : 0);
153-
154-
// if the resumable function is still running, so are we
155-
if (result.getState() > modm::rf::NestingError)
156-
return {modm::rf::Running};
157-
158-
// if rx != 0, we copy the result into the array
159-
if (rx) rx[index] = result.getResult();
160-
}
161-
index++;
162-
}
163-
164-
// clear the state
165-
state &= ~Bit6;
166-
return {modm::rf::Stop};
167-
}
168-
%% endif
169-
}
150+
return count;
151+
}

0 commit comments

Comments
 (0)