Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_spi.c
1 #include <bc_spi.h>
2 #include <bc_scheduler.h>
3 #include <bc_dma.h>
4 #include <bc_system.h>
5 #include <bc_timer.h>
6 #include <stm32l0xx.h>
7 
8 #define _BC_SPI_EVENT_CLEAR 0
9 
10 static const uint32_t _bc_spi_speed_table[8] =
11 {
12  [BC_SPI_SPEED_125_KHZ] = 0x38, // :128 (500 kHz)
13  [BC_SPI_SPEED_250_KHZ] = 0x30, // :64 (250 kHz)
14  [BC_SPI_SPEED_500_KHZ] = 0x28, // :32 (500 kHz)
15  [BC_SPI_SPEED_1_MHZ] = 0x20, // :16 (1 MHz)
16  [BC_SPI_SPEED_2_MHZ] = 0x18, // :8 (2 MHz)
17  [BC_SPI_SPEED_4_MHZ] = 0x10, // :4 (4 MHz)
18  [BC_SPI_SPEED_8_MHZ] = 0x08, // :2 (8 MHz)
19  [BC_SPI_SPEED_16_MHZ] = 0x00 // :1 (16 MHz)
20 };
21 
22 static const uint32_t _bc_spi_mode_table[4] =
23 {
24  [BC_SPI_MODE_0] = 0x00, // SPI mode of operation is 0 (CPOL = 0, CPHA = 0)
25  [BC_SPI_MODE_1] = 0x01, // SPI mode of operation is 1 (CPOL = 0, CPHA = 1)
26  [BC_SPI_MODE_2] = 0x02, // SPI mode of operation is 2 (CPOL = 1, CPHA = 0)
27  [BC_SPI_MODE_3] = 0x03 // SPI mode of operation is 3 (CPOL = 1, CPHA = 1)
28 };
29 
30 static struct
31 {
32  bc_spi_mode_t mode;
33  bc_spi_speed_t speed;
34  void (*event_handler)(bc_spi_event_t event, void *_bc_spi_event_param);
35  void *event_param;
36  bool in_progress;
37  bool pending_event_done;
38  bool initilized;
39  bool manual_cs_control;
40  bc_scheduler_task_id_t task_id;
41  uint16_t cs_delay;
42  uint16_t delay;
43  uint16_t cs_quit;
44 
45 } _bc_spi;
46 
47 static bc_dma_channel_config_t _bc_spi_dma_config =
48 {
50  .direction = BC_DMA_DIRECTION_TO_PERIPHERAL,
51  .data_size_memory = BC_DMA_SIZE_1,
52  .data_size_peripheral = BC_DMA_SIZE_1,
53  .mode = BC_DMA_MODE_STANDARD,
54  .address_peripheral = (void *)&SPI2->DR,
55  .priority = BC_DMA_PRIORITY_HIGH
56 };
57 
58 static uint8_t _bc_spi_transfer_byte(uint8_t value);
59 
60 static void _bc_spi_dma_event_handler(bc_dma_channel_t channel, bc_dma_event_t event, void *event_param);
61 
62 static void _bc_spi_task();
63 
65 {
66  // If is already initilized ...
67  if(_bc_spi.initilized == true)
68  {
69  // ... dont do it again
70  return;
71  }
72  _bc_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  bc_spi_set_speed(speed);
103 
104  // Set SPI mode
105  bc_spi_set_mode(mode);
106 
107  // Enable SPI
108  SPI2->CR1 |= SPI_CR1_SPE;
109 
110  bc_dma_init();
111 
112  bc_timer_init();
113 
114  bc_dma_set_event_handler(BC_DMA_CHANNEL_5, _bc_spi_dma_event_handler, NULL);
115 
116  _bc_spi.task_id = bc_scheduler_register(_bc_spi_task, NULL, BC_TICK_INFINITY);
117 }
118 
120 {
121  uint32_t cr1;
122 
123  // Store desired speed
124  _bc_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 |= _bc_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 bc_spi_set_timing(uint16_t cs_delay, uint16_t delay, uint16_t cs_quit)
142 {
143  _bc_spi.cs_delay = cs_delay;
144 
145  _bc_spi.delay = delay;
146 
147  _bc_spi.cs_quit = cs_quit;
148 }
149 
151 {
152  return _bc_spi.speed;
153 }
154 
156 {
157  uint32_t cr1;
158 
159  // Store desired mode
160  _bc_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 |= _bc_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 _bc_spi.mode;
180 }
181 
182 void bc_spi_set_manual_cs_control(bool manual_cs_control)
183 {
184  _bc_spi.manual_cs_control = manual_cs_control;
185 }
186 
187 bool bc_spi_is_ready(void)
188 {
189  return (!_bc_spi.in_progress) && (_bc_spi.pending_event_done == _BC_SPI_EVENT_CLEAR);
190 }
191 
192 bool bc_spi_transfer(const void *source, void *destination, size_t length)
193 {
194  // If another transfer cannot be executed ...
195  if (_bc_spi.in_progress == true)
196  {
197  // ... dont do it
198  return false;
199  }
200 
201  // Update status
202  _bc_spi.in_progress = true;
203 
204  // Enable PLL and disable sleep
205  bc_system_pll_enable();
206 
207  // Set CS to active level
208  if (!_bc_spi.manual_cs_control)
209  {
210  GPIOB->BSRR = GPIO_BSRR_BR_12;
211  }
212 
213  if (_bc_spi.cs_delay > 0)
214  {
215  bc_timer_start();
216  bc_timer_delay(_bc_spi.cs_delay);
217  bc_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) = _bc_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  _bc_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) = _bc_spi_transfer_byte(*((uint8_t *) source + i));
242  }
243  }
244 
245  if (_bc_spi.cs_quit > 0)
246  {
247  bc_timer_start();
248  bc_timer_delay(_bc_spi.cs_quit);
249  bc_timer_stop();
250  }
251 
252  // Set CS to inactive level
253  if (!_bc_spi.manual_cs_control)
254  {
255  GPIOB->BSRR = GPIO_BSRR_BS_12;
256  }
257 
258  // Disable PLL and enable sleep
259  bc_system_pll_disable();
260 
261  // Update status
262  _bc_spi.in_progress = false;
263 
264  return true;
265 }
266 
267 bool bc_spi_async_transfer(const void *source, void *destination, size_t length, void (*event_handler)(bc_spi_event_t event, void *event_param), void (*event_param))
268 {
269  // If another transfer cannot be executed now ...
270  if((_bc_spi.in_progress == true) || (_bc_spi.pending_event_done != _BC_SPI_EVENT_CLEAR))
271  {
272  // ... dont do it
273  return false;
274  }
275 
276  // Update event related variables
277  _bc_spi.event_handler = event_handler;
278  _bc_spi.event_param = event_param;
279 
280  // Enable PLL and disable sleep
281  bc_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  _bc_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  _bc_spi_dma_config.address_memory = (void *)source;
305  _bc_spi_dma_config.length = length;
306  bc_dma_channel_config(BC_DMA_CHANNEL_5, &_bc_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  bc_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  bc_system_pll_disable();
326  }
327 
328  return false;
329 }
330 
331 static uint8_t _bc_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 (_bc_spi.delay > 0)
352  {
353  bc_timer_start();
354  bc_timer_delay(_bc_spi.delay);
355  bc_timer_stop();
356  }
357 
358  return value;
359 }
360 
361 static void _bc_spi_dma_event_handler(bc_dma_channel_t channel, bc_dma_event_t event, void *event_param)
362 {
363  (void) channel;
364  (void) event_param;
365 
366  if (event == BC_DMA_EVENT_DONE)
367  {
368  // Update status
369  _bc_spi.in_progress = false;
370  _bc_spi.pending_event_done = true;
371 
372  GPIOB->BSRR = GPIO_BSRR_BS_12;
373 
374  // Plan task that call event handler
375  bc_scheduler_plan_now(_bc_spi.task_id);
376  }
377  else if (event == BC_DMA_EVENT_ERROR)
378  {
379  bc_system_reset();
380  }
381 }
382 
383 static void _bc_spi_task()
384 {
385  // If is event handler valid ...
386  if (_bc_spi.event_handler != NULL)
387  {
388  // ... call event handler
389  _bc_spi.event_handler(BC_SPI_EVENT_DONE, _bc_spi.event_param);
390 
391  // Disable PLL and enable sleep
392  bc_system_pll_disable();
393  }
394 
395  _bc_spi.pending_event_done = false;
396 }
size_t length
DMA channel data length.
Definition: bc_dma.h:180
SPI communication speed is 16 MHz.
Definition: bc_spi.h:36
void bc_spi_set_speed(bc_spi_speed_t speed)
Set SPI communication speed.
Definition: bc_spi.c:119
DMA channel configuration.
Definition: bc_dma.h:165
SPI mode of operation is 2 (CPOL = 1, CPHA = 0)
Definition: bc_spi.h:51
void bc_spi_set_manual_cs_control(bool manual_cs_control)
Enable manual control of CS pin.
Definition: bc_spi.c:182
DMA request 2.
Definition: bc_dma.h:48
bc_dma_event_t
DMA channel event.
Definition: bc_dma.h:132
bc_dma_channel_t
DMA channels.
Definition: bc_dma.h:12
SPI communication speed is 8 MHz.
Definition: bc_spi.h:33
void bc_spi_set_mode(bc_spi_mode_t mode)
Set SPI mode of operation.
Definition: bc_spi.c:155
bc_spi_mode_t
SPI mode of operation.
Definition: bc_spi.h:42
void bc_timer_start(void)
Start timer.
Definition: bc_timer.c:24
SPI communication speed is 500 kHz.
Definition: bc_spi.h:21
SPI event is completed.
Definition: bc_spi.h:63
bc_scheduler_task_id_t bc_scheduler_register(void(*task)(void *), void *param, bc_tick_t tick)
Register task in scheduler.
Definition: bc_scheduler.c:56
SPI mode of operation is 1 (CPOL = 0, CPHA = 1)
Definition: bc_spi.h:48
void bc_scheduler_plan_now(bc_scheduler_task_id_t task_id)
Schedule specified task for immediate execution.
Definition: bc_scheduler.c:119
void bc_dma_set_event_handler(bc_dma_channel_t channel, void(*event_handler)(bc_dma_channel_t, bc_dma_event_t, void *), void *event_param)
Set callback function.
Definition: bc_dma.c:173
void bc_timer_delay(uint16_t microseconds)
Relative delay.
Definition: bc_timer.c:40
void * address_memory
RAM memory address.
Definition: bc_dma.h:186
bc_dma_request_t request
DMA channel request.
Definition: bc_dma.h:168
void bc_dma_init(void)
Initialize DMA.
Definition: bc_dma.c:56
SPI communication speed is 125 kHz.
Definition: bc_spi.h:15
void bc_timer_stop(void)
Stop timer.
Definition: bc_timer.c:55
void bc_dma_channel_run(bc_dma_channel_t channel)
Start DMA channel.
Definition: bc_dma.c:179
SPI communication speed is 4 MHz.
Definition: bc_spi.h:30
DMA channel direction from RAM to peripheral.
Definition: bc_dma.h:96
SPI communication speed is 250 kHz.
Definition: bc_spi.h:18
SPI mode of operation is 3 (CPOL = 1, CPHA = 1)
Definition: bc_spi.h:54
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
DMA channel priority is high.
Definition: bc_dma.h:156
bool bc_spi_is_ready(void)
Check if is ready for transfer.
Definition: bc_spi.c:187
SPI communication speed is 2 MHz.
Definition: bc_spi.h:27
bc_spi_mode_t bc_spi_get_mode(void)
Get SPI mode of operation.
Definition: bc_spi.c:177
bool bc_spi_async_transfer(const void *source, void *destination, size_t length, void(*event_handler)(bc_spi_event_t event, void *event_param), void(*event_param))
Execute async SPI transfer.
Definition: bc_spi.c:267
void bc_spi_set_timing(uint16_t cs_delay, uint16_t delay, uint16_t cs_quit)
Set SPI timing.
Definition: bc_spi.c:141
bc_spi_speed_t
SPI communication speed.
Definition: bc_spi.h:12
bc_spi_event_t
SPI event.
Definition: bc_spi.h:60
void bc_spi_init(bc_spi_speed_t speed, bc_spi_mode_t mode)
Initialize SPI channel.
Definition: bc_spi.c:64
DMA channel data size 1B.
Definition: bc_dma.h:108
SPI communication speed is 1 MHz.
Definition: bc_spi.h:24
DMA channel mode standard.
Definition: bc_dma.h:123
bc_spi_speed_t bc_spi_get_speed(void)
Get SPI communication speed.
Definition: bc_spi.c:150
void bc_dma_channel_config(bc_dma_channel_t channel, bc_dma_channel_config_t *config)
Configure DMA channel.
Definition: bc_dma.c:95
SPI mode of operation is 0 (CPOL = 0, CPHA = 0)
Definition: bc_spi.h:45
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
bool bc_spi_transfer(const void *source, void *destination, size_t length)
Execute SPI transfer.
Definition: bc_spi.c:192
void bc_timer_init(void)
Initialize timer.
Definition: bc_timer.c:18
DMA channel event error.
Definition: bc_dma.h:135
DMA channel 5, used for SPI.
Definition: bc_dma.h:27
DMA channel event done.
Definition: bc_dma.h:141