Open FFBoard
Open source force feedback firmware
SPI.cpp
Go to the documentation of this file.
1#include <algorithm>
2
3#include "SPI.h"
4#include "semaphore.hpp"
5#include "cppmain.h"
6#include "math.h"
7
8static bool operator==(const SPI_InitTypeDef& lhs, const SPI_InitTypeDef& rhs) {
9 return memcmp(&lhs,&rhs,sizeof(SPI_InitTypeDef)) == 0;
10}
11
12
13
14SPIPort::SPIPort(SPI_HandleTypeDef &hspi,const std::vector<OutputPin>& csPins,uint32_t baseclk,bool allowReconfigure)
15: hspi{hspi}{
16 this->current_device = nullptr;
17 this->allowReconfigure = allowReconfigure;
18 this->csPins = csPins;
19 this->freePins = csPins;
20 this->baseclk = baseclk;
21}
22
23// ----------------------------------
24//CS pins
26 auto it = std::find(freePins.begin(), freePins.end(), pin);
27 if(it != freePins.end()){
28 freePins.erase(it);
29 return true;
30 }
31 // Pin not found or not free
32 return false;
33}
34
35
36
38 // is in pins
39 if(std::find(csPins.begin(),csPins.end(), pin) != csPins.end()){
40 // is not in free pins
41 if(std::find(freePins.begin(),freePins.end(), pin) == freePins.end()){
42 freePins.push_back(pin);
43 return true;
44 }
45 }
46
47 // Pin not found
48 return false;
49}
50
52 return(std::find(freePins.begin(),freePins.end(), pin) != freePins.end());
53}
54
55std::vector<OutputPin>& SPIPort::getFreeCsPins(){
56
57 return freePins;
58}
59
60
61std::vector<OutputPin>& SPIPort::getCsPins(){
62 return csPins;
63}
64
66 if(idx < csPins.size()){
67 return &csPins[idx];
68 }
69 return nullptr;
70}
71
72void SPIPort::configurePort(SPI_InitTypeDef* config){
73 if(config == nullptr || hspi.Init == *config){
74 return; // No need to reconfigure
75 }
76 hspi.Init = *config;
77 HAL_SPI_Init(&hspi);
78}
79
80SPI_HandleTypeDef* SPIPort::getPortHandle(){
81 return &hspi;
82}
83
84// ----------------------------------
89void SPIPort::transmit_DMA(const uint8_t* buf,uint16_t size,SPIDevice* device){
90 device->beginSpiTransfer(this);
91 current_device = device; // Will call back this device
92 if(!takenExclusive && this->allowReconfigure){
93 this->configurePort(&device->getSpiConfig()->peripheral);
94 }
95 HAL_SPI_Transmit_DMA(&this->hspi,const_cast<uint8_t*>(buf),size);
96 // Request completes in tx complete callback
97}
98
103void SPIPort::transmitReceive_DMA(const uint8_t* txbuf,uint8_t* rxbuf,uint16_t size,SPIDevice* device){
104 device->beginSpiTransfer(this);
105 if(!takenExclusive && this->allowReconfigure){
106 this->configurePort(&device->getSpiConfig()->peripheral);
107 }
108 current_device = device; // Will call back this device
109 HAL_SPI_TransmitReceive_DMA(&this->hspi,const_cast<uint8_t*>(txbuf),rxbuf,size);
110 // Request completes in rxtx complete callback
111}
112
117void SPIPort::receive_DMA(uint8_t* buf,uint16_t size,SPIDevice* device){
118 device->beginSpiTransfer(this);
119 if(!takenExclusive && this->allowReconfigure){
120 this->configurePort(&device->getSpiConfig()->peripheral);
121 }
122 current_device = device;
123 HAL_SPI_Receive_DMA(&this->hspi,buf,size);
124 // Request completes in rx complete callback
125}
126
127
128void SPIPort::transmit_IT(const uint8_t* buf,uint16_t size,SPIDevice* device){
129 device->beginSpiTransfer(this);
130 current_device = device; // Will call back this device
131 if(!takenExclusive && this->allowReconfigure){
132 this->configurePort(&device->getSpiConfig()->peripheral);
133 }
134 HAL_SPI_Transmit_IT(&this->hspi,const_cast<uint8_t*>(buf),size);
135 // Request completes in tx complete callback
136}
137
138void SPIPort::transmitReceive_IT(const uint8_t* txbuf,uint8_t* rxbuf,uint16_t size,SPIDevice* device){
139 device->beginSpiTransfer(this);
140 if(!takenExclusive && this->allowReconfigure){
141 this->configurePort(&device->getSpiConfig()->peripheral);
142 }
143 current_device = device; // Will call back this device
144 HAL_SPI_TransmitReceive_IT(&this->hspi,const_cast<uint8_t*>(txbuf),rxbuf,size);
145 // Request completes in rxtx complete callback
146}
147
148void SPIPort::receive_IT(uint8_t* buf,uint16_t size,SPIDevice* device){
149 device->beginSpiTransfer(this);
150 if(!takenExclusive && this->allowReconfigure){
151 this->configurePort(&device->getSpiConfig()->peripheral);
152 }
153 current_device = device;
154 HAL_SPI_Receive_IT(&this->hspi,buf,size);
155 // Request completes in rx complete callback
156}
157
158void SPIPort::transmit(const uint8_t* buf,uint16_t size,SPIDevice* device,uint16_t timeout){
159 device->beginSpiTransfer(this);
160 if(!takenExclusive && this->allowReconfigure){
161 this->configurePort(&device->getSpiConfig()->peripheral);
162 }
163 HAL_SPI_Transmit(&this->hspi,const_cast<uint8_t*>(buf),size,timeout);
164 device->endSpiTransfer(this);
165}
166
167void SPIPort::receive(uint8_t* buf,uint16_t size,SPIDevice* device,int16_t timeout){
168 device->beginSpiTransfer(this);
169 if(!takenExclusive && this->allowReconfigure){
170 this->configurePort(&device->getSpiConfig()->peripheral);
171 }
172 HAL_SPI_Receive(&this->hspi,buf,size,timeout);
173 device->endSpiTransfer(this);
174}
175
176void SPIPort::transmitReceive(const uint8_t* txbuf,uint8_t* rxbuf,uint16_t size,SPIDevice* device,uint16_t timeout){
177 device->beginSpiTransfer(this);
178 if(!takenExclusive && this->allowReconfigure){
179 this->configurePort(&device->getSpiConfig()->peripheral);
180 }
181 HAL_SPI_TransmitReceive(&this->hspi,const_cast<uint8_t*>(txbuf),rxbuf,size,timeout);
182 device->endSpiTransfer(this);
183}
184// --------------------------------
185
187 bool isIsr = inIsr();
188
189 if(isIsr){
190 BaseType_t taskWoken = 0;
191 this->semaphore.TakeFromISR(&taskWoken);
192 portYIELD_FROM_ISR(taskWoken);
193 }else{
194 this->semaphore.Take();
195 }
196 isTakenFlag = true;
197}
198
200 bool isIsr = inIsr();
201 isTakenFlag = false;
202 if(isIsr){
203 BaseType_t taskWoken = 0;
204 this->semaphore.GiveFromISR(&taskWoken);
205 portYIELD_FROM_ISR(taskWoken);
206 }else{
207 this->semaphore.Give();
208 }
209
210}
211
213 return isTakenFlag;
214}
215
216void SPIPort::takeExclusive(bool exclusive){
217 takenExclusive = exclusive;
218}
219
221 return !takenExclusive && this->getCsPins().size() > 0;
222}
223
228 return this->baseclk;
229}
230
231// interrupt callbacks
232void SPIPort::SpiTxCplt(SPI_HandleTypeDef *hspi) {
233 if (current_device == nullptr) {
234 return;
235 }
236
237 if (hspi->Instance != this->hspi.Instance) {
238 return;
239 }
242
243 current_device = nullptr;
244
245}
246void SPIPort::SpiRxCplt(SPI_HandleTypeDef *hspi) {
247 if (current_device == nullptr) {
248 return;
249 }
250
251 if (hspi->Instance != this->hspi.Instance) {
252 return;
253 }
256
257 current_device = nullptr;
258}
259void SPIPort::SpiTxRxCplt(SPI_HandleTypeDef *hspi) {
260 if (current_device == nullptr) {
261 return;
262 }
263
264 if (hspi->Instance != this->hspi.Instance) {
265 return;
266 }
269
270 current_device = nullptr;
271}
272
273void SPIPort::SpiError(SPI_HandleTypeDef *hspi) {
274 if (current_device == nullptr) {
275 return;
276 }
277
278 if (hspi->Instance != this->hspi.Instance) {
279 return;
280 }
283
284 current_device = nullptr;
285}
286
291std::pair<uint32_t,float> SPIPort::getClosestPrescaler(float clock){
292 std::vector<std::pair<uint32_t,float>> distances;
293#if defined(SPI_BAUDRATEPRESCALER_2)
294 distances.push_back({SPI_BAUDRATEPRESCALER_2,(baseclk/2.0)});
295#endif
296#if defined(SPI_BAUDRATEPRESCALER_4)
297 distances.push_back({SPI_BAUDRATEPRESCALER_4,(baseclk/4.0)});
298#endif
299#if defined(SPI_BAUDRATEPRESCALER_8)
300 distances.push_back({SPI_BAUDRATEPRESCALER_8,(baseclk/8.0)});
301#endif
302#if defined(SPI_BAUDRATEPRESCALER_16)
303 distances.push_back({SPI_BAUDRATEPRESCALER_16,(baseclk/16.0)});
304#endif
305#if defined(SPI_BAUDRATEPRESCALER_32)
306 distances.push_back({SPI_BAUDRATEPRESCALER_32,(baseclk/32.0)});
307#endif
308#if defined(SPI_BAUDRATEPRESCALER_64)
309 distances.push_back({SPI_BAUDRATEPRESCALER_64,(baseclk/64.0)});
310#endif
311#if defined(SPI_BAUDRATEPRESCALER_128)
312 distances.push_back({SPI_BAUDRATEPRESCALER_128,(baseclk/128.0)});
313#endif
314#if defined(SPI_BAUDRATEPRESCALER_256)
315 distances.push_back({SPI_BAUDRATEPRESCALER_256,(baseclk/256.0)});
316#endif
317 // Calc distances
318 std::pair<uint32_t,float> bestVal = distances[0];
319 float bestDist = INFINITY;
320 for(auto& val : distances){
321 if(std::abs(clock-val.second) < bestDist){
322 bestDist = abs(clock-val.second);
323 bestVal = val;
324 }
325 }
326 return bestVal;
327}
328
329SPIDevice::SPIDevice(SPIPort& port,SPIConfig& spiConfig) : spiPort{port},spiConfig{spiConfig}{
331}
332SPIDevice::SPIDevice(SPIPort& port,OutputPin csPin) : spiPort{port},spiConfig{csPin}{
333 this->spiConfig.cs = csPin;
335}
338}
339
341 if(csPin == spiConfig.cs){
342 return true;
343 }
344 if(!spiPort.isPinFree(csPin)){
345 return false;
346 }
347
349 return false;
350 }
351 spiConfig.cs = csPin;
352 return spiPort.reserveCsPin(csPin);
353}
354
355/*
356 * Called before the spi transfer starts.
357 * Can be used to take the semaphore and set CS pins by default
358 */
360 port->takeSemaphore();
362}
363
364/*
365 * Called after a transfer is finished
366 * Gives a semaphore back and resets the CS pin
367 */
370 port->giveSemaphore();
371}
372
375}
376
379}
static bool operator==(const SPI_InitTypeDef &lhs, const SPI_InitTypeDef &rhs)
Definition: SPI.cpp:8
void write(bool state) const
Definition: GPIOPin.h:46
Definition: SPI.h:100
virtual bool updateCSPin(OutputPin &csPin)
Definition: SPI.cpp:340
SPIPort & spiPort
Definition: SPI.h:124
virtual void beginSpiTransfer(SPIPort *port)
Definition: SPI.cpp:359
SPIDevice(SPIPort &port, OutputPin csPin)
Definition: SPI.cpp:332
virtual ~SPIDevice()
Definition: SPI.cpp:336
void assertChipSelect()
Definition: SPI.cpp:373
virtual void spiTxCompleted(SPIPort *port)
Definition: SPI.h:112
virtual SPIConfig * getSpiConfig()
Definition: SPI.h:120
void clearChipSelect()
Definition: SPI.cpp:377
virtual void endSpiTransfer(SPIPort *port)
Definition: SPI.cpp:368
SPIConfig spiConfig
Definition: SPI.h:125
virtual void spiRequestError(SPIPort *port)
Definition: SPI.h:115
virtual void spiRxCompleted(SPIPort *port)
Definition: SPI.h:113
virtual void spiTxRxCompleted(SPIPort *port)
Definition: SPI.h:114
Definition: SPI.h:43
void transmitReceive(const uint8_t *txbuf, uint8_t *rxbuf, uint16_t size, SPIDevice *device, uint16_t timeout)
Definition: SPI.cpp:176
void transmit_IT(const uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:128
std::vector< OutputPin > & getCsPins()
Definition: SPI.cpp:61
bool hasFreePins()
Definition: SPI.cpp:220
SPIDevice * current_device
Definition: SPI.h:89
SPI_HandleTypeDef & hspi
Definition: SPI.h:88
bool isPinFree(OutputPin pin)
Definition: SPI.cpp:51
void takeExclusive(bool exclusive)
Definition: SPI.cpp:216
void takeSemaphore()
Definition: SPI.cpp:186
bool reserveCsPin(OutputPin pin)
Definition: SPI.cpp:25
std::pair< uint32_t, float > getClosestPrescaler(float clock)
Definition: SPI.cpp:291
uint32_t getBaseClk()
Definition: SPI.cpp:227
std::vector< OutputPin > & getFreeCsPins()
Definition: SPI.cpp:55
std::vector< OutputPin > freePins
Definition: SPI.h:91
SPI_HandleTypeDef * getPortHandle()
Definition: SPI.cpp:80
void receive(uint8_t *buf, uint16_t size, SPIDevice *device, int16_t timeout)
Definition: SPI.cpp:167
void transmitReceive_DMA(const uint8_t *txbuf, uint8_t *rxbuf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:103
void SpiError(SPI_HandleTypeDef *hspi) override
Definition: SPI.cpp:273
void SpiTxCplt(SPI_HandleTypeDef *hspi) override
Definition: SPI.cpp:232
void transmit(const uint8_t *buf, uint16_t size, SPIDevice *device, uint16_t timeout)
Definition: SPI.cpp:158
void receive_DMA(uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:117
bool isTaken()
Definition: SPI.cpp:212
void transmitReceive_IT(const uint8_t *txbuf, uint8_t *rxbuf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:138
bool takenExclusive
Definition: SPI.h:96
void transmit_DMA(const uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:89
OutputPin * getCsPin(uint16_t idx)
Definition: SPI.cpp:65
std::vector< OutputPin > csPins
Definition: SPI.h:90
void SpiTxRxCplt(SPI_HandleTypeDef *hspi) override
Definition: SPI.cpp:259
void configurePort(SPI_InitTypeDef *config)
Definition: SPI.cpp:72
void giveSemaphore()
Definition: SPI.cpp:199
void receive_IT(uint8_t *buf, uint16_t size, SPIDevice *device)
Definition: SPI.cpp:148
bool freeCsPin(OutputPin pin)
Definition: SPI.cpp:37
volatile bool isTakenFlag
Definition: SPI.h:95
bool allowReconfigure
Definition: SPI.h:94
void SpiRxCplt(SPI_HandleTypeDef *hspi) override
Definition: SPI.cpp:246
cpp_freertos::BinarySemaphore semaphore
Definition: SPI.h:93
SPIPort(SPI_HandleTypeDef &hspi, const std::vector< OutputPin > &csPins, uint32_t baseclk, bool allowReconfigure=true)
Definition: SPI.cpp:14
uint32_t baseclk
Definition: SPI.h:97
bool GiveFromISR(BaseType_t *pxHigherPriorityTaskWoken)
Definition: csemaphore.cpp:76
bool TakeFromISR(BaseType_t *pxHigherPriorityTaskWoken)
Definition: csemaphore.cpp:56
bool Take(TickType_t Timeout=portMAX_DELAY)
Definition: csemaphore.cpp:46
static bool inIsr()
Definition: cppmain.h:41
Definition: SPI.h:18
SPI_InitTypeDef peripheral
Definition: SPI.h:38
OutputPin cs
Definition: SPI.h:34
bool cspol
CSPOL=true === active low.
Definition: SPI.h:37