Firmware SDK
twr_spi.c
1 #include <twr_spi.h>
2 #include <twr_scheduler.h>
3 #include <twr_dma.h>
4 #include <twr_system.h>
5 #include <twr_timer.h>
6 #include <stm32l0xx.h>
7 
8 #define _TWR_SPI_EVENT_CLEAR 0
9 
10 static const uint32_t _twr_spi_speed_table[8] =
11 {
12  [TWR_SPI_SPEED_125_KHZ] = 0x38, // :128 (500 kHz)
13  [TWR_SPI_SPEED_250_KHZ] = 0x30, // :64 (250 kHz)
14  [TWR_SPI_SPEED_500_KHZ] = 0x28, // :32 (500 kHz)
15  [TWR_SPI_SPEED_1_MHZ] = 0x20, // :16 (1 MHz)
16  [TWR_SPI_SPEED_2_MHZ] = 0x18, // :8 (2 MHz)
17  [TWR_SPI_SPEED_4_MHZ] = 0x10, // :4 (4 MHz)
18  [TWR_SPI_SPEED_8_MHZ] = 0x08, // :2 (8 MHz)
19  [TWR_SPI_SPEED_16_MHZ] = 0x00 // :1 (16 MHz)
20 };
21 
22 static const uint32_t _twr_spi_mode_table[4] =
23 {
24  [TWR_SPI_MODE_0] = 0x00, // SPI mode of operation is 0 (CPOL = 0, CPHA = 0)
25  [TWR_SPI_MODE_1] = 0x01, // SPI mode of operation is 1 (CPOL = 0, CPHA = 1)
26  [TWR_SPI_MODE_2] = 0x02, // SPI mode of operation is 2 (CPOL = 1, CPHA = 0)
27  [TWR_SPI_MODE_3] = 0x03 // SPI mode of operation is 3 (CPOL = 1, CPHA = 1)
28 };
29 
30 static struct
31 {
32  twr_spi_mode_t mode;
33  twr_spi_speed_t speed;
34  void (*event_handler)(twr_spi_event_t event, void *_twr_spi_event_param);
35  void *event_param;
36  bool in_progress;
37  bool pending_event_done;
38  bool initilized;
39  bool manual_cs_control;
41  uint16_t cs_delay;
42  uint16_t delay;
43  uint16_t cs_quit;
44 
45 } _twr_spi;
46 
47 static twr_dma_channel_config_t _twr_spi_dma_config =
48 {
51  .data_size_memory = TWR_DMA_SIZE_1,
52  .data_size_peripheral = TWR_DMA_SIZE_1,
53  .mode = TWR_DMA_MODE_STANDARD,
54  .address_peripheral = (void *)&SPI2->DR,
55  .priority = TWR_DMA_PRIORITY_HIGH
56 };
57 
58 static uint8_t _twr_spi_transfer_byte(uint8_t value);
59 
60 static void _twr_spi_dma_event_handler(twr_dma_channel_t channel, twr_dma_event_t event, void *event_param);
61 
62 static void _twr_spi_task();
63 
65 {
66  // If is already initilized ...
67  if(_twr_spi.initilized == true)
68  {
69  // ... dont do it again
70  return;
71  }
72  _twr_spi.initilized = true;
73 
74  // Enable GPIOB clock
75  RCC->IOPENR |= RCC_IOPENR_GPIOBEN;
76 
77  // Errata workaround
78  RCC->IOPENR;
79 
80  // Pull-down on MISO pin
81  GPIOB->PUPDR |= GPIO_PUPDR_PUPD14_1;
82 
83  // Very high speed on CS, SCLK, MISO and MOSI pins
84  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEED12 | GPIO_OSPEEDER_OSPEED13 | GPIO_OSPEEDER_OSPEED14 | GPIO_OSPEEDER_OSPEED15;
85 
86  // General purpose output on CS pin and alternate function on SCLK, MISO and MOSI pins
87  GPIOB->MODER &= ~(GPIO_MODER_MODE12_1 | GPIO_MODER_MODE13_0 | GPIO_MODER_MODE14_0 | GPIO_MODER_MODE15_0);
88 
89  // Set CS to inactive level;
90  GPIOB->BSRR = GPIO_BSRR_BS_12;
91 
92  // Enable clock for SPI2
93  RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
94 
95  // Errata workaround
96  RCC->AHBENR;
97 
98  // Software slave management, master configuration
99  SPI2->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_MSTR;
100 
101  // Set SPI speed
102  twr_spi_set_speed(speed);
103 
104  // Set SPI mode
105  twr_spi_set_mode(mode);
106 
107  // Enable SPI
108  SPI2->CR1 |= SPI_CR1_SPE;
109 
110  twr_dma_init();
111 
112  twr_timer_init();
113 
114  twr_dma_set_event_handler(TWR_DMA_CHANNEL_5, _twr_spi_dma_event_handler, NULL);
115 
116  _twr_spi.task_id = twr_scheduler_register(_twr_spi_task, NULL, TWR_TICK_INFINITY);
117 }
118 
120 {
121  uint32_t cr1;
122 
123  // Store desired speed
124  _twr_spi.speed = speed;
125 
126  // Disable SPI
127  SPI2->CR1 &= ~SPI_CR1_SPE;
128 
129  // Edit the registry image
130  cr1 = SPI2->CR1;
131  cr1 &= ~(SPI_CR1_BR_Msk | SPI_CR1_SPE);
132  cr1 |= _twr_spi_speed_table[speed];
133 
134  // Update CR1
135  SPI2->CR1 = cr1;
136 
137  // Enable SPI
138  SPI2->CR1 |= SPI_CR1_SPE;
139 }
140 
141 void twr_spi_set_timing(uint16_t cs_delay, uint16_t delay, uint16_t cs_quit)
142 {
143  _twr_spi.cs_delay = cs_delay;
144 
145  _twr_spi.delay = delay;
146 
147  _twr_spi.cs_quit = cs_quit;
148 }
149 
151 {
152  return _twr_spi.speed;
153 }
154 
156 {
157  uint32_t cr1;
158 
159  // Store desired mode
160  _twr_spi.mode = mode;
161 
162  // Disable SPI
163  SPI2->CR1 &= ~SPI_CR1_SPE;
164 
165  // Edit the registry image
166  cr1 = SPI2->CR1;
167  cr1 &= ~(SPI_CR1_CPHA_Msk | SPI_CR1_CPOL_Msk | SPI_CR1_SPE);
168  cr1 |= _twr_spi_mode_table[mode];
169 
170  // Update CR1
171  SPI2->CR1 = cr1;
172 
173  // Enable SPI
174  SPI2->CR1 |= SPI_CR1_SPE;
175 }
176 
178 {
179  return _twr_spi.mode;
180 }
181 
182 void twr_spi_set_manual_cs_control(bool manual_cs_control)
183 {
184  _twr_spi.manual_cs_control = manual_cs_control;
185 }
186 
188 {
189  return (!_twr_spi.in_progress) && (_twr_spi.pending_event_done == _TWR_SPI_EVENT_CLEAR);
190 }
191 
192 bool twr_spi_transfer(const void *source, void *destination, size_t length)
193 {
194  // If another transfer cannot be executed ...
195  if (_twr_spi.in_progress == true)
196  {
197  // ... dont do it
198  return false;
199  }
200 
201  // Update status
202  _twr_spi.in_progress = true;
203 
204  // Enable PLL and disable sleep
205  twr_system_pll_enable();
206 
207  // Set CS to active level
208  if (!_twr_spi.manual_cs_control)
209  {
210  GPIOB->BSRR = GPIO_BSRR_BR_12;
211  }
212 
213  if (_twr_spi.cs_delay > 0)
214  {
215  twr_timer_start();
216  twr_timer_delay(_twr_spi.cs_delay);
217  twr_timer_stop();
218  }
219 
220  if (source == NULL)
221  {
222  for (size_t i = 0; i < length; i++)
223  {
224  // Read byte
225  *((uint8_t *) destination + i) = _twr_spi_transfer_byte(0);
226  }
227  }
228  else if (destination == NULL)
229  {
230  for (size_t i = 0; i < length; i++)
231  {
232  // Write byte
233  _twr_spi_transfer_byte(*((uint8_t *) source + i));
234  }
235  }
236  else
237  {
238  for (size_t i = 0; i < length; i++)
239  {
240  // Read and write byte
241  *((uint8_t *) destination + i) = _twr_spi_transfer_byte(*((uint8_t *) source + i));
242  }
243  }
244 
245  if (_twr_spi.cs_quit > 0)
246  {
247  twr_timer_start();
248  twr_timer_delay(_twr_spi.cs_quit);
249  twr_timer_stop();
250  }
251 
252  // Set CS to inactive level
253  if (!_twr_spi.manual_cs_control)
254  {
255  GPIOB->BSRR = GPIO_BSRR_BS_12;
256  }
257 
258  // Disable PLL and enable sleep
259  twr_system_pll_disable();
260 
261  // Update status
262  _twr_spi.in_progress = false;
263 
264  return true;
265 }
266 
267 bool twr_spi_async_transfer(const void *source, void *destination, size_t length, void (*event_handler)(twr_spi_event_t event, void *event_param), void (*event_param))
268 {
269  // If another transfer cannot be executed now ...
270  if((_twr_spi.in_progress == true) || (_twr_spi.pending_event_done != _TWR_SPI_EVENT_CLEAR))
271  {
272  // ... dont do it
273  return false;
274  }
275 
276  // Update event related variables
277  _twr_spi.event_handler = event_handler;
278  _twr_spi.event_param = event_param;
279 
280  // Enable PLL and disable sleep
281  twr_system_pll_enable();
282 
283  // If transmit only is requested ...
284  if ((source != NULL) && (destination == NULL))
285  {
286  // ... execute it
287 
288  // Set CS to active level
289  GPIOB->BSRR = GPIO_BSRR_BR_12;
290 
291  // Update status
292  _twr_spi.in_progress = true;
293 
294  // Disable SPI2
295  SPI2->CR1 &= ~SPI_CR1_SPE;
296 
297  // Enable TX DMA request
298  SPI2->CR2 |= SPI_CR2_TXDMAEN;
299 
300  // Enable SPI2
301  SPI2->CR1 |= SPI_CR1_SPE;
302 
303  // Setup DMA channel
304  _twr_spi_dma_config.address_memory = (void *)source;
305  _twr_spi_dma_config.length = length;
306  twr_dma_channel_config(TWR_DMA_CHANNEL_5, &_twr_spi_dma_config);
308 
309  return true;
310  }
311  // If receive only is requested ...
312  else if ((source == NULL) && (destination != NULL))
313  {
314  // TODO Ready to implement another direction
315 
316  // Disable PLL and disable sleep
317  twr_system_pll_disable();
318  }
319  // If transmit and receive is requested ...
320  else
321  {
322  // TODO Ready to implement another direction
323 
324  // Disable PLL and disable sleep
325  twr_system_pll_disable();
326  }
327 
328  return false;
329 }
330 
331 static uint8_t _twr_spi_transfer_byte(uint8_t value)
332 {
333  // Wait until transmit buffer is empty...
334  while ((SPI2->SR & SPI_SR_TXE) == 0)
335  {
336  continue;
337  }
338 
339  // Write data register
340  SPI2->DR = value;
341 
342  // Until receive buffer is empty...
343  while ((SPI2->SR & SPI_SR_RXNE) == 0)
344  {
345  continue;
346  }
347 
348  // Read data register
349  value = SPI2->DR;
350 
351  if (_twr_spi.delay > 0)
352  {
353  twr_timer_start();
354  twr_timer_delay(_twr_spi.delay);
355  twr_timer_stop();
356  }
357 
358  return value;
359 }
360 
361 static void _twr_spi_dma_event_handler(twr_dma_channel_t channel, twr_dma_event_t event, void *event_param)
362 {
363  (void) channel;
364  (void) event_param;
365 
366  if (event == TWR_DMA_EVENT_DONE)
367  {
368  // Update status
369  _twr_spi.in_progress = false;
370  _twr_spi.pending_event_done = true;
371 
372  GPIOB->BSRR = GPIO_BSRR_BS_12;
373 
374  // Plan task that call event handler
375  twr_scheduler_plan_now(_twr_spi.task_id);
376  }
377  else if (event == TWR_DMA_EVENT_ERROR)
378  {
379  twr_system_reset();
380  }
381 }
382 
383 static void _twr_spi_task()
384 {
385  // If is event handler valid ...
386  if (_twr_spi.event_handler != NULL)
387  {
388  // ... call event handler
389  _twr_spi.event_handler(TWR_SPI_EVENT_DONE, _twr_spi.event_param);
390 
391  // Disable PLL and enable sleep
392  twr_system_pll_disable();
393  }
394 
395  _twr_spi.pending_event_done = false;
396 }
void twr_dma_channel_config(twr_dma_channel_t channel, twr_dma_channel_config_t *config)
Configure DMA channel.
Definition: twr_dma.c:95
void twr_dma_channel_run(twr_dma_channel_t channel)
Start DMA channel.
Definition: twr_dma.c:179
void twr_dma_set_event_handler(twr_dma_channel_t channel, void(*event_handler)(twr_dma_channel_t, twr_dma_event_t, void *), void *event_param)
Set callback function.
Definition: twr_dma.c:173
twr_dma_event_t
DMA channel event.
Definition: twr_dma.h:133
void twr_dma_init(void)
Initialize DMA.
Definition: twr_dma.c:56
twr_dma_channel_t
DMA channels.
Definition: twr_dma.h:13
@ TWR_DMA_REQUEST_2
DMA request 2.
Definition: twr_dma.h:48
@ TWR_DMA_EVENT_DONE
DMA channel event done.
Definition: twr_dma.h:141
@ TWR_DMA_EVENT_ERROR
DMA channel event error.
Definition: twr_dma.h:135
@ TWR_DMA_SIZE_1
DMA channel data size 1B.
Definition: twr_dma.h:108
@ TWR_DMA_DIRECTION_TO_PERIPHERAL
DMA channel direction from RAM to peripheral.
Definition: twr_dma.h:96
@ TWR_DMA_PRIORITY_HIGH
DMA channel priority is high.
Definition: twr_dma.h:156
@ TWR_DMA_CHANNEL_5
DMA channel 5, used for SPI.
Definition: twr_dma.h:27
@ TWR_DMA_MODE_STANDARD
DMA channel mode standard.
Definition: twr_dma.h:123
size_t twr_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: twr_scheduler.h:22
void twr_scheduler_plan_now(twr_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
twr_scheduler_task_id_t twr_scheduler_register(void(*task)(void *), void *param, twr_tick_t tick)
Register task in scheduler.
Definition: twr_scheduler.c:53
twr_spi_speed_t
SPI communication speed.
Definition: twr_spi.h:13
bool twr_spi_is_ready(void)
Check if is ready for transfer.
Definition: twr_spi.c:187
bool twr_spi_async_transfer(const void *source, void *destination, size_t length, void(*event_handler)(twr_spi_event_t event, void *event_param), void(*event_param))
Execute async SPI transfer.
Definition: twr_spi.c:267
twr_spi_speed_t twr_spi_get_speed(void)
Get SPI communication speed.
Definition: twr_spi.c:150
twr_spi_mode_t
SPI mode of operation.
Definition: twr_spi.h:43
void twr_spi_set_manual_cs_control(bool manual_cs_control)
Enable manual control of CS pin.
Definition: twr_spi.c:182
bool twr_spi_transfer(const void *source, void *destination, size_t length)
Execute SPI transfer.
Definition: twr_spi.c:192
void twr_spi_set_speed(twr_spi_speed_t speed)
Set SPI communication speed.
Definition: twr_spi.c:119
void twr_spi_set_mode(twr_spi_mode_t mode)
Set SPI mode of operation.
Definition: twr_spi.c:155
twr_spi_mode_t twr_spi_get_mode(void)
Get SPI mode of operation.
Definition: twr_spi.c:177
void twr_spi_init(twr_spi_speed_t speed, twr_spi_mode_t mode)
Initialize SPI channel.
Definition: twr_spi.c:64
void twr_spi_set_timing(uint16_t cs_delay, uint16_t delay, uint16_t cs_quit)
Set SPI timing.
Definition: twr_spi.c:141
twr_spi_event_t
SPI event.
Definition: twr_spi.h:61
@ TWR_SPI_SPEED_16_MHZ
SPI communication speed is 16 MHz.
Definition: twr_spi.h:36
@ TWR_SPI_SPEED_125_KHZ
SPI communication speed is 125 kHz.
Definition: twr_spi.h:15
@ TWR_SPI_SPEED_8_MHZ
SPI communication speed is 8 MHz.
Definition: twr_spi.h:33
@ TWR_SPI_SPEED_250_KHZ
SPI communication speed is 250 kHz.
Definition: twr_spi.h:18
@ TWR_SPI_SPEED_500_KHZ
SPI communication speed is 500 kHz.
Definition: twr_spi.h:21
@ TWR_SPI_SPEED_4_MHZ
SPI communication speed is 4 MHz.
Definition: twr_spi.h:30
@ TWR_SPI_SPEED_2_MHZ
SPI communication speed is 2 MHz.
Definition: twr_spi.h:27
@ TWR_SPI_SPEED_1_MHZ
SPI communication speed is 1 MHz.
Definition: twr_spi.h:24
@ TWR_SPI_MODE_2
SPI mode of operation is 2 (CPOL = 1, CPHA = 0)
Definition: twr_spi.h:51
@ TWR_SPI_MODE_1
SPI mode of operation is 1 (CPOL = 0, CPHA = 1)
Definition: twr_spi.h:48
@ TWR_SPI_MODE_0
SPI mode of operation is 0 (CPOL = 0, CPHA = 0)
Definition: twr_spi.h:45
@ TWR_SPI_MODE_3
SPI mode of operation is 3 (CPOL = 1, CPHA = 1)
Definition: twr_spi.h:54
@ TWR_SPI_EVENT_DONE
SPI event is completed.
Definition: twr_spi.h:63
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
void twr_timer_init(void)
Initialize timer.
Definition: twr_timer.c:23
void twr_timer_delay(uint16_t microseconds)
Relative delay.
Definition: twr_timer.c:59
void twr_timer_stop(void)
Stop timer.
Definition: twr_timer.c:42
void twr_timer_start(void)
Start timer.
Definition: twr_timer.c:28
DMA channel configuration.
Definition: twr_dma.h:166
twr_dma_request_t request
DMA channel request.
Definition: twr_dma.h:168
size_t length
DMA channel data length.
Definition: twr_dma.h:180
void * address_memory
RAM memory address.
Definition: twr_dma.h:186