Skip to content

Commit 7866e40

Browse files
committed
AVR ISR: Better + faster, supports u8, u16 & u32spi
1 parent a077855 commit 7866e40

File tree

8 files changed

+472
-198
lines changed

8 files changed

+472
-198
lines changed

src/modm/driver/display/ili9341_impl.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,10 +225,10 @@ Ili9341<Interface, Reset, Backlight>::fillRectangle(
225225
setClipping(upperLeft.getX(), upperLeft.getY(), width, height);
226226
while (pixelCount > std::numeric_limits<uint16_t>::max())
227227
{
228-
this->writeDataRepeat(&foregroundColor, std::numeric_limits<uint16_t>::max());
228+
this->writeDataRepeat(foregroundColor, std::numeric_limits<uint16_t>::max());
229229
pixelCount -= std::numeric_limits<uint16_t>::max();
230230
}
231-
this->writeDataRepeat(&foregroundColor, pixelCount);
231+
this->writeDataRepeat(foregroundColor, pixelCount);
232232
}
233233

234234
template <class Interface, class Reset, class Backlight>

src/modm/driver/display/ili9341_spi.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,15 +69,15 @@ class Ili9341SPIInterface: public ili9341, public modm::SpiDevice<SPI>
6969
}
7070

7171
void
72-
writeData(color::Rgb565 data)
72+
writeData(color::Rgb565 rgb565)
7373
{
7474
if constexpr ( SupportsBit16<SPI> )
7575
SPI::setDataSize(SPI::DataSize::Bit16);
7676
SPI::transferBlocking(rgb565.color);
7777
}
7878

7979
void
80-
writeDataRepeat(color::Rgb565 const *data, std::size_t repeat)
80+
writeDataRepeat(color::Rgb565 rgb565, std::size_t repeat)
8181
{
8282
if constexpr ( SupportsBit16<SPI> )
8383
SPI::setDataSize(SPI::DataSize::Bit16);

src/modm/math/utils/binary.hpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2021, Thomas Sommer
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+
#include <limits>
12+
#include <concepts>
13+
14+
namespace modm {
15+
template<typename T>
16+
concept unsigned_integral_max8 = std::unsigned_integral<T> and std::numeric_limits<T>::digits <= 8;
17+
18+
template<typename T>
19+
concept unsigned_integral_max16 = std::unsigned_integral<T> and std::numeric_limits<T>::digits <= 16;
20+
21+
template<typename T>
22+
concept unsigned_integral_max32 = std::unsigned_integral<T> and std::numeric_limits<T>::digits <= 32;
23+
24+
template<typename T>
25+
concept unsigned_integral_max64 = std::unsigned_integral<T> and std::numeric_limits<T>::digits <= 64;
26+
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -73,12 +73,18 @@ struct Spi
7373
};
7474

7575
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
76+
Idle = Bit6, // Transaction is running
77+
Repeat = Bit7, // Send same tx multiple times
8078
};
8179
MODM_FLAGS8(State);
80+
81+
enum Type : uint8_t {
82+
Byte = 0, // 1 byte
83+
HalfWord = 1, // 2 bytes
84+
Word = 2, // 4 bytes
85+
// WordWord = 3 // 8 bytes
86+
};
87+
typedef Value<State_t, 2> Type_t;
8288
};
8389

8490
} // namespace platform

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

Lines changed: 159 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
*/
1313
// ----------------------------------------------------------------------------
1414

15-
#include "spi_master{{ id }}.hpp"
15+
#include "spi_master.hpp"
1616

1717
#include <avr/io.h>
1818
#include <avr/interrupt.h>
@@ -21,91 +21,179 @@
2121
#include <modm/architecture/interface/atomic_lock.hpp>
2222
#include <modm/architecture/interface/interrupt.hpp>
2323

24-
uint8_t modm::platform::SpiMaster{{ id }}::count(0);
24+
using State = modm::platform::Spi::State;
25+
using Type = modm::platform::Spi::Type;
2526

26-
void* modm::platform::SpiMaster{{ id }}::context(nullptr);
27+
// ----------------------------------------------------------------------------
2728

29+
uint8_t modm::platform::SpiMaster{{ id }}::count(0);
30+
void *modm::platform::SpiMaster{{ id }}::context(nullptr);
2831
modm::Spi::ConfigurationHandler
2932
modm::platform::SpiMaster{{ id }}::configuration(nullptr);
3033

31-
using State = modm::platform::Spi::State;
32-
modm::platform::Spi::State_t state(0);
33-
3434
// ----------------------------------------------------------------------------
3535

36-
void* tx(nullptr);
37-
std::size_t index(0);
38-
std::size_t length(0);
36+
modm::platform::Spi::State_t
37+
modm::platform::SpiMaster{{ id }}::state(0);
38+
uint8_t modm::platform::SpiMaster{{ id }}::shift(0);
39+
uint32_t modm::platform::SpiMaster{{ id }}::temp(0);
40+
41+
modm::platform::SpiMaster{{ id }}::unsigned_types_const
42+
modm::platform::SpiMaster{{ id }}::tx{nullptr};
43+
modm::platform::SpiMaster{{ id }}::unsigned_types_const
44+
modm::platform::SpiMaster{{ id }}::tx_end{nullptr};
45+
46+
modm::platform::SpiMaster{{ id }}::unsigned_types
47+
modm::platform::SpiMaster{{ id }}::rx{nullptr};
48+
modm::platform::SpiMaster{{ id }}::unsigned_types
49+
modm::platform::SpiMaster{{ id }}::rx_end{nullptr};
3950

40-
void* rx(nullptr);
41-
uint16_t temp(0);
4251

4352
// ----------------------------------------------------------------------------
4453

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+
MODM_ISR(SPI_STC)
55+
{
56+
modm::platform::SpiMaster{{ id }}::isr_handler();
57+
}
5458

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 }};
59+
void modm::platform::SpiMaster{{ id }}::isr_handler()
60+
{
61+
constexpr State_t state_normal = State::Idle;
62+
constexpr State_t state_repeat = State::Idle | State::Repeat;
63+
64+
switch (state.value) {
65+
case state_normal.value | Type::Byte:
66+
// Store received byte
67+
if (rx.u8)
68+
*rx.u8++ = SPDR{{ id }};
69+
if (++tx.u8 == tx_end.u8)
70+
{
71+
// Job done, disable Interrupt.
72+
SPCR{{ id }} &= ~(1 << SPIE);
73+
return;
6074
}
61-
62-
// Job Done, disable Interrupt
63-
SPCR{{ id }} &= ~(1 << SPIE{{ id }});
75+
// Transmit next byte
76+
SPDR{{ id }} = *tx.u8;
77+
return;
78+
case state_repeat.value | Type::Byte:
79+
if(++tx.repeat == tx_end.repeat)
80+
{
81+
// Job done, disable Interrupt.
82+
SPCR{{ id }} &= ~(1 << SPIE);
83+
return;
84+
}
85+
// Transmit byte again
86+
SPDR{{ id }} = uint8_t(temp);
87+
return;
88+
case state_normal.value | Type::HalfWord:
89+
if (shift)
90+
{
91+
// Store received byte
92+
if (rx.u8)
93+
*rx.u16 = uint16_t(SPDR{{ id }}) << 8; // << shift
94+
// Transmit next byte
95+
shift = 0;
96+
SPDR{{ id }} = *tx.u16;
97+
return;
98+
}
99+
// Store received byte
100+
if (rx.u16)
101+
*rx.u16++ |= SPDR{{ id }};
102+
if (++tx.u16 == tx_end.u16)
103+
{
104+
// Job done, disable Interrupt.
105+
SPCR{{ id }} &= ~(1 << SPIE);
106+
return;
107+
}
108+
// Transmit next halfword
109+
shift = 1 * 8;
110+
SPDR{{ id }} = *tx.u16 >> shift;
111+
return;
112+
case state_repeat.value | Type::HalfWord:
113+
if (shift)
114+
{
115+
// Transmit next sub-byte
116+
shift = 0;
117+
SPDR{{ id }} = uint16_t(temp);
118+
return;
119+
}
120+
if(++tx.repeat == tx_end.repeat)
121+
{
122+
// Job done, disable Interrupt.
123+
SPCR{{ id }} &= ~(1 << SPIE);
124+
return;
125+
}
126+
// Transmit halfword again
127+
shift = 1 * 8;
128+
SPDR{{ id }} = uint16_t(temp) >> shift;
129+
return;
130+
case state_normal.value | Type::Word:
131+
if (shift)
132+
{
133+
// Store received sub-byte
134+
if (rx.u32)
135+
*rx.u32 |= uint32_t(SPDR{{ id }}) << shift;
136+
// Transmit next sub-byte
137+
shift -= 8;
138+
SPDR{{ id }} = *tx.u32 >> shift;
139+
return;
140+
}
141+
// Store received sub-byte
142+
if (rx.u32) {
143+
*rx.u32++ |= SPDR{{ id }};
144+
*rx.u32 = 0;
145+
}
146+
if (++tx.u32 == tx_end.u32)
147+
{
148+
// Job done, disable Interrupt.
149+
SPCR{{ id }} &= ~(1 << SPIE);
150+
return;
151+
}
152+
// Transmit next word
153+
shift = 3 * 8;
154+
SPDR{{ id }} = *tx.u32 >> shift;
155+
return;
156+
case state_repeat.value | Type::Word:
157+
if (shift)
158+
{
159+
// Transmit next sub-byte
160+
shift -= 8;
161+
SPDR{{ id }} = uint32_t(temp) >> shift;
162+
return;
163+
}
164+
if(++tx.repeat == tx_end.repeat)
165+
{
166+
// Job done, disable Interrupt.
167+
SPCR{{ id }} &= ~(1 << SPIE);
168+
return;
169+
}
170+
// Transmit word again
171+
shift = 3 * 8;
172+
SPDR{{ id }} = uint32_t(temp) >> shift;
64173
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];
83174
}
84175
}
85176

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-
}
177+
/* modm::ResumableResult<uint8_t>
178+
modm::platform::SpiMaster{{ id }}::transmit(const uint8_t data)
179+
{
180+
// FIXME does not yet work when called before a regular transmit()
181+
// cause interrupt is not enabled here, witch signales a running condition
182+
// ot the regular transmit.
96183

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-
}
108-
// ----------------------------------------------------------------------------
184+
// Interrupt enabled? transmission in progress!
185+
if (SPCR{{ id }} & (1 << SPIE))
186+
return {modm::rf::Running};
187+
188+
SPDR{{ id }} = data;
189+
// wait for transfer to finish
190+
if (!(SPSR{{ id }} & (1 << SPIF)))
191+
return {modm::rf::Running};
192+
193+
return {modm::rf::Stop, SPDR{{ id }}};
194+
} */
195+
196+
// ---------------------------------------------------------------------------
109197

110198
void modm::platform::SpiMaster{{ id }}::initialize(Prescaler prescaler)
111199
{
@@ -115,7 +203,6 @@ void modm::platform::SpiMaster{{ id }}::initialize(Prescaler prescaler)
115203
SPSR{{ id }} = (static_cast<uint8_t>(prescaler) & 0x80) ? (1 << SPI2X) : 0;
116204
state = State(0);
117205
}
118-
// ----------------------------------------------------------------------------
119206

120207
uint8_t
121208
modm::platform::SpiMaster{{ id }}::acquire(void *ctx, ConfigurationHandler handler)
@@ -142,10 +229,8 @@ modm::platform::SpiMaster{{ id }}::acquire(void *ctx, ConfigurationHandler handl
142229
uint8_t
143230
modm::platform::SpiMaster{{ id }}::release(void *ctx)
144231
{
145-
if (ctx == context)
146-
{
147-
if (--count == 0)
148-
context = nullptr;
149-
}
232+
if (ctx == context and --count == 0)
233+
context = nullptr;
234+
150235
return count;
151236
}

0 commit comments

Comments
 (0)