2
2
* Copyright (c) 2013-2018, Niklas Hauser
3
3
* Copyright (c) 2014, Sascha Schade
4
4
* Copyright (c) 2017, Fabian Greif
5
+ * Copyright (c) 2021, Thomas Sommer
5
6
*
6
7
* This file is part of the modm project.
7
8
*
18
19
19
20
#include <modm/math/utils/bit_constants.hpp>
20
21
#include <modm/architecture/interface/atomic_lock.hpp>
22
+ #include <modm/architecture/interface/interrupt.hpp>
21
23
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);
27
25
28
- void *
29
- modm::platform::SpiMaster{{ id }}::context(nullptr);
26
+ void* modm::platform::SpiMaster{{ id }}::context(nullptr);
30
27
31
28
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
+ }
33
108
// ----------------------------------------------------------------------------
34
109
35
- void
36
- modm::platform::SpiMaster{{ id }}::initialize(Prescaler prescaler)
110
+ void modm::platform::SpiMaster{{ id }}::initialize(Prescaler prescaler)
37
111
{
38
112
modm::atomic::Lock lock;
39
113
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) ;
43
117
}
44
118
// ----------------------------------------------------------------------------
45
119
@@ -49,17 +123,18 @@ modm::platform::SpiMaster{{ id }}::acquire(void *ctx, ConfigurationHandler handl
49
123
if (context == nullptr)
50
124
{
51
125
context = ctx;
52
- state = (state & ~0x3f) | 1;
126
+ count = 1;
53
127
// if handler is not nullptr and is different from previous configuration
54
- if (handler and configuration != handler) {
128
+ if (handler and configuration != handler)
129
+ {
55
130
configuration = handler;
56
131
configuration();
57
132
}
58
133
return 1;
59
134
}
60
135
61
136
if (ctx == context)
62
- return (++state & 0x3f) ;
137
+ return ++count ;
63
138
64
139
return 0;
65
140
}
@@ -69,101 +144,8 @@ modm::platform::SpiMaster{{ id }}::release(void *ctx)
69
144
{
70
145
if (ctx == context)
71
146
{
72
- if ((--state & 0x3f) == 0)
147
+ if (--count == 0)
73
148
context = nullptr;
74
149
}
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