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 *
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
3128modm::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