Firmware SDK
 All Data Structures Functions Variables Typedefs Enumerations Enumerator Groups Pages
bc_spirit1.c
1 #include <bc_spirit1.h>
2 #include <bc_scheduler.h>
3 #include <bc_exti.h>
4 #include <bc_system.h>
5 #include <bc_timer.h>
6 #include <stm32l0xx.h>
7 #include "SPIRIT_Config.h"
8 #include "SDK_Configuration_Common.h"
9 #include "MCU_Interface.h"
10 
11 typedef enum
12 {
13  BC_SPIRIT1_STATE_INIT = 0,
14  BC_SPIRIT1_STATE_SLEEP = 1,
15  BC_SPIRIT1_STATE_TX = 2,
16  BC_SPIRIT1_STATE_RX = 3
17 
18 } bc_spirit1_state_t;
19 
20 typedef struct
21 {
22  int initialized_semaphore;
23  void (*event_handler)(bc_spirit1_event_t, void *);
24  void *event_param;
25  bc_scheduler_task_id_t task_id;
26  bc_spirit1_state_t desired_state;
27  bc_spirit1_state_t current_state;
28  uint8_t tx_buffer[BC_SPIRIT1_MAX_PACKET_SIZE];
29  size_t tx_length;
30  uint8_t rx_buffer[BC_SPIRIT1_MAX_PACKET_SIZE];
31  size_t rx_length;
32  int rx_rssi;
33  bc_tick_t rx_timeout;
34  bc_tick_t rx_tick_timeout;
35 
36 } bc_spirit1_t;
37 
38 static bc_spirit1_t _bc_spirit1;
39 
40 #define XTAL_FREQUENCY 50000000
41 
42 SRadioInit xRadioInit = {
43  XTAL_OFFSET_PPM,
44  BASE_FREQUENCY,
45  CHANNEL_SPACE,
46  CHANNEL_NUMBER,
47  MODULATION_SELECT,
48  DATARATE,
49  FREQ_DEVIATION,
50  BANDWIDTH
51 };
52 
53 PktBasicInit xBasicInit={
54  PREAMBLE_LENGTH,
55  SYNC_LENGTH,
56  SYNC_WORD,
57  LENGTH_TYPE,
58  LENGTH_WIDTH,
59  CRC_MODE,
60  CONTROL_LENGTH,
61  EN_ADDRESS,
62  EN_FEC,
63  EN_WHITENING
64 };
65 
66 PktBasicAddressesInit xAddressInit={
67  EN_FILT_MY_ADDRESS,
68  MY_ADDRESS,
69  EN_FILT_MULTICAST_ADDRESS,
70  MULTICAST_ADDRESS,
71  EN_FILT_BROADCAST_ADDRESS,
72  BROADCAST_ADDRESS
73 };
74 
75 SGpioInit xGpioIRQ={
76  SPIRIT_GPIO_0,
77  SPIRIT_GPIO_MODE_DIGITAL_OUTPUT_LP,
78  SPIRIT_GPIO_DIG_OUT_IRQ
79 };
80 
81 static void _bc_spirit1_enter_state_tx(void);
82 static void _bc_spirit1_check_state_tx(void);
83 static void _bc_spirit1_enter_state_rx(void);
84 static void _bc_spirit1_check_state_rx(void);
85 static void _bc_spirit1_enter_state_sleep(void);
86 
87 void bc_spirit1_hal_chip_select_low(void);
88 void bc_spirit1_hal_chip_select_high(void);
89 uint8_t bc_spirit1_hal_transfer_byte(uint8_t value);
90 static void bc_spirit1_hal_init_gpio(void);
91 static void bc_spirit1_hal_deinit_gpio(void);
92 static void bc_spirit1_hal_init_spi(void);
93 static void bc_spirit1_hal_deinit_spi(void);
94 
95 static void _bc_spirit1_task(void *param);
96 static void _bc_spirit1_interrupt(bc_exti_line_t line, void *param);
97 
98 bool bc_spirit1_init(void)
99 {
100  if (_bc_spirit1.initialized_semaphore > 0)
101  {
102  _bc_spirit1.initialized_semaphore++;
103 
104  return true;
105  }
106 
107  memset(&_bc_spirit1, 0, sizeof(_bc_spirit1));
108 
109  SpiritRadioSetXtalFrequency(XTAL_FREQUENCY);
110 
111  SpiritSpiInit();
112 
113  /* Spirit ON */
114  SpiritEnterShutdown();
115 
116  SpiritExitShutdown();
117 
118  SpiritManagementWaExtraCurrent();
119 
120  /* Spirit IRQ config */
121  SpiritGpioInit(&xGpioIRQ);
122 
123  /* Spirit Radio config */
124  if (SpiritRadioInit(&xRadioInit) != 0)
125  {
126 
127  bc_spirit1_hal_shutdown_high();
128 
129  bc_spirit1_hal_deinit_spi();
130 
131  bc_spirit1_hal_deinit_gpio();
132 
133  return false;
134  }
135 
136  /* Spirit Packet config */
137  SpiritPktBasicInit(&xBasicInit);
138 
139  SpiritPktBasicAddressesInit(&xAddressInit);
140 
141  _bc_spirit1.desired_state = BC_SPIRIT1_STATE_SLEEP;
142 
143  _bc_spirit1.task_id = bc_scheduler_register(_bc_spirit1_task, NULL, 0);
144 
145  _bc_spirit1.initialized_semaphore++;
146 
147  return true;
148 }
149 
151 {
152  if (--_bc_spirit1.initialized_semaphore != 0)
153  {
154  return false;
155  }
156 
157  bc_spirit1_hal_shutdown_high();
158 
159  bc_spirit1_hal_deinit_spi();
160 
161  bc_spirit1_hal_deinit_gpio();
162 
163  bc_scheduler_unregister(_bc_spirit1.task_id);
164 
166 
167  return true;
168 }
169 
170 void bc_spirit1_set_event_handler(void (*event_handler)(bc_spirit1_event_t, void *), void *event_param)
171 {
172  _bc_spirit1.event_handler = event_handler;
173  _bc_spirit1.event_param = event_param;
174 }
175 
177 {
178  return _bc_spirit1.tx_buffer;
179 }
180 
181 void bc_spirit1_set_tx_length(size_t length)
182 {
183  _bc_spirit1.tx_length = length;
184 }
185 
187 {
188  return _bc_spirit1.tx_length;
189 }
190 
192 {
193  return _bc_spirit1.rx_buffer;
194 }
195 
197 {
198  return _bc_spirit1.rx_length;
199 }
200 
202 {
203  return _bc_spirit1.rx_rssi;
204 }
205 
207 {
208  _bc_spirit1.rx_timeout = timeout;
209 
210  if (_bc_spirit1.current_state == BC_SPIRIT1_STATE_RX)
211  {
212  if (_bc_spirit1.rx_timeout == BC_TICK_INFINITY)
213  {
214  _bc_spirit1.rx_tick_timeout = BC_TICK_INFINITY;
215  }
216  else
217  {
218  _bc_spirit1.rx_tick_timeout = bc_tick_get() + _bc_spirit1.rx_timeout;
219  }
220 
221  if (_bc_spirit1.initialized_semaphore > 0)
222  {
223  bc_scheduler_plan_absolute(_bc_spirit1.task_id, _bc_spirit1.rx_tick_timeout);
224  }
225  }
226 }
227 
228 void bc_spirit1_tx(void)
229 {
230  _bc_spirit1.desired_state = BC_SPIRIT1_STATE_TX;
231 
232  if (_bc_spirit1.initialized_semaphore > 0)
233  {
234  bc_scheduler_plan_now(_bc_spirit1.task_id);
235  }
236 }
237 
238 void bc_spirit1_rx(void)
239 {
240  _bc_spirit1.desired_state = BC_SPIRIT1_STATE_RX;
241 
242  if (_bc_spirit1.initialized_semaphore > 0)
243  {
244  bc_scheduler_plan_now(_bc_spirit1.task_id);
245  }
246 }
247 
249 {
250  _bc_spirit1.desired_state = BC_SPIRIT1_STATE_SLEEP;
251 
252  if (_bc_spirit1.initialized_semaphore > 0)
253  {
254  bc_scheduler_plan_now(_bc_spirit1.task_id);
255  }
256 }
257 
258 static void _bc_spirit1_task(void *param)
259 {
260  (void) param;
261 
262  if ((_bc_spirit1.current_state == BC_SPIRIT1_STATE_RX) && (bc_tick_get() >= _bc_spirit1.rx_tick_timeout))
263  {
264  if (_bc_spirit1.event_handler != NULL)
265  {
266  _bc_spirit1.event_handler(BC_SPIRIT1_EVENT_RX_TIMEOUT, _bc_spirit1.event_param);
267  }
268  }
269 
270  if (_bc_spirit1.desired_state != _bc_spirit1.current_state)
271  {
272  if (_bc_spirit1.desired_state == BC_SPIRIT1_STATE_TX)
273  {
274  _bc_spirit1_enter_state_tx();
275 
276  return;
277  }
278  else if (_bc_spirit1.desired_state == BC_SPIRIT1_STATE_RX)
279  {
280  _bc_spirit1_enter_state_rx();
281 
282  return;
283  }
284  else if (_bc_spirit1.desired_state == BC_SPIRIT1_STATE_SLEEP)
285  {
286  _bc_spirit1_enter_state_sleep();
287 
288  return;
289  }
290 
291  return;
292  }
293 
294  if (_bc_spirit1.current_state == BC_SPIRIT1_STATE_TX)
295  {
296  _bc_spirit1_check_state_tx();
297 
298  return;
299  }
300  else if (_bc_spirit1.current_state == BC_SPIRIT1_STATE_RX)
301  {
302  _bc_spirit1_check_state_rx();
303 
304  return;
305  }
306 }
307 
308 static void _bc_spirit1_enter_state_tx(void)
309 {
310  GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_1;
311 
312  _bc_spirit1.current_state = BC_SPIRIT1_STATE_TX;
313 
314  SpiritCmdStrobeSabort();
315  SpiritCmdStrobeReady();
316  SpiritCmdStrobeFlushTxFifo();
317 
318  SpiritIrqDeInit(NULL);
319  SpiritIrqClearStatus();
320  SpiritIrq(TX_DATA_SENT, S_ENABLE);
321 
322  SpiritPktBasicSetPayloadLength(_bc_spirit1.tx_length);
323 
324  // TODO Why needed?
325  SpiritPktBasicSetDestinationAddress(0x35);
326 
327  SpiritSpiWriteLinearFifo(_bc_spirit1.tx_length, _bc_spirit1.tx_buffer);
328 
329  bc_exti_register(BC_EXTI_LINE_PA7, BC_EXTI_EDGE_FALLING, _bc_spirit1_interrupt, NULL);
330 
331  SpiritCmdStrobeTx();
332 }
333 
334 static void _bc_spirit1_check_state_tx(void)
335 {
336  SpiritIrqs xIrqStatus;
337 
338  SpiritIrqGetStatus(&xIrqStatus);
339 
340  if (xIrqStatus.IRQ_TX_DATA_SENT)
341  {
342  SpiritIrqClearStatus();
343 
344  _bc_spirit1.desired_state = BC_SPIRIT1_STATE_SLEEP;
345 
346  if (_bc_spirit1.event_handler != NULL)
347  {
348  _bc_spirit1.event_handler(BC_SPIRIT1_EVENT_TX_DONE, _bc_spirit1.event_param);
349  }
350 
351  if (_bc_spirit1.desired_state == BC_SPIRIT1_STATE_RX)
352  {
353  _bc_spirit1_enter_state_rx();
354  }
355  else if (_bc_spirit1.desired_state == BC_SPIRIT1_STATE_SLEEP)
356  {
357  _bc_spirit1_enter_state_sleep();
358  }
359  else if (_bc_spirit1.desired_state == BC_SPIRIT1_STATE_TX)
360  {
361  _bc_spirit1_enter_state_tx();
362  }
363  }
364 }
365 
366 static void _bc_spirit1_enter_state_rx(void)
367 {
368  GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_1;
369 
370  _bc_spirit1.current_state = BC_SPIRIT1_STATE_RX;
371 
372  if (_bc_spirit1.rx_timeout == BC_TICK_INFINITY)
373  {
374  _bc_spirit1.rx_tick_timeout = BC_TICK_INFINITY;
375  }
376  else
377  {
378  _bc_spirit1.rx_tick_timeout = bc_tick_get() + _bc_spirit1.rx_timeout;
379  }
380 
381  bc_scheduler_plan_current_absolute(_bc_spirit1.rx_tick_timeout);
382 
383  SpiritIrqs xIrqStatus;
384 
385  SpiritIrqDeInit(&xIrqStatus);
386  SpiritIrq(RX_DATA_DISC, S_ENABLE);
387  SpiritIrq(RX_DATA_READY, S_ENABLE);
388 
389  /* payload length config */
390  SpiritPktBasicSetPayloadLength(20);
391 
392  /* enable SQI check */
393  SpiritQiSetSqiThreshold(SQI_TH_0);
394  SpiritQiSqiCheck(S_ENABLE);
395 
396  /* RX timeout config */
397  SpiritTimerSetRxTimeoutMs(1000.0);
398  SpiritTimerSetRxTimeoutStopCondition(SQI_ABOVE_THRESHOLD);
399 
400  /* IRQ registers blanking */
401  SpiritIrqClearStatus();
402 
403  bc_exti_register(BC_EXTI_LINE_PA7, BC_EXTI_EDGE_FALLING, _bc_spirit1_interrupt, NULL);
404 
405  /* RX command */
406  SpiritCmdStrobeRx();
407 }
408 
409 static void _bc_spirit1_check_state_rx(void)
410 {
411  SpiritIrqs xIrqStatus;
412 
413  /* Get the IRQ status */
414  SpiritIrqGetStatus(&xIrqStatus);
415 
416  /* Check the SPIRIT RX_DATA_DISC IRQ flag */
417  if (xIrqStatus.IRQ_RX_DATA_DISC)
418  {
419  /* RX command - to ensure the device will be ready for the next reception */
420  SpiritCmdStrobeRx();
421  }
422 
423  /* Check the SPIRIT RX_DATA_READY IRQ flag */
424  if (xIrqStatus.IRQ_RX_DATA_READY)
425  {
426  /* Get the RX FIFO size */
427  uint8_t cRxData = SpiritLinearFifoReadNumElementsRxFifo();
428 
429  if (cRxData <= BC_SPIRIT1_MAX_PACKET_SIZE)
430  {
431  /* Read the RX FIFO */
432  SpiritSpiReadLinearFifo(cRxData, _bc_spirit1.rx_buffer);
433 
434  _bc_spirit1.rx_length = cRxData;
435 
436  uint8_t rssi_level;
437 
438  bc_spirit1_read(RSSI_LEVEL_BASE, &rssi_level, 1);
439 
440  _bc_spirit1.rx_rssi = ((int) rssi_level) / 2 - 130;
441 
442  if (_bc_spirit1.rx_timeout == BC_TICK_INFINITY)
443  {
444  _bc_spirit1.rx_tick_timeout = BC_TICK_INFINITY;
445  }
446  else
447  {
448  _bc_spirit1.rx_tick_timeout = bc_tick_get() + _bc_spirit1.rx_timeout;
449  }
450 
451  bc_scheduler_plan_current_absolute(_bc_spirit1.rx_tick_timeout);
452 
453  if (_bc_spirit1.event_handler != NULL)
454  {
455  _bc_spirit1.event_handler(BC_SPIRIT1_EVENT_RX_DONE, _bc_spirit1.event_param);
456  }
457  }
458  }
459 
460  /* Flush the RX FIFO */
461  SpiritCmdStrobeFlushRxFifo();
462 
463  /* RX command - to ensure the device will be ready for the next reception */
464  SpiritCmdStrobeRx();
465 }
466 
467 static void _bc_spirit1_enter_state_sleep(void)
468 {
469  _bc_spirit1.current_state = BC_SPIRIT1_STATE_SLEEP;
470 
471  SpiritCmdStrobeSabort();
472  SpiritCmdStrobeReady();
473  SpiritIrqDeInit(NULL);
474  SpiritIrqClearStatus();
475  SpiritCmdStrobeStandby();
476 
477  GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD7_1;
478 }
479 
480 bc_spirit_status_t bc_spirit1_command(uint8_t command)
481 {
482  // Enable PLL
483  bc_system_pll_enable();
484 
485  // Set chip select low
486  bc_spirit1_hal_chip_select_low();
487 
488  // Write header byte and read status bits (MSB)
489  uint16_t status = bc_spirit1_hal_transfer_byte(0x80) << 8;
490 
491  // Write memory map address and read status bits (LSB)
492  status |= bc_spirit1_hal_transfer_byte(command);
493 
494  // Set chip select high
495  bc_spirit1_hal_chip_select_high();
496 
497  // Disable PLL
498  bc_system_pll_disable();
499 
500  // TODO Why this cast?
501  return *((bc_spirit_status_t *) &status);
502 }
503 
504 bc_spirit_status_t bc_spirit1_write(uint8_t address, const void *buffer, size_t length)
505 {
506  // Enable PLL
507  bc_system_pll_enable();
508 
509  // Set chip select low
510  bc_spirit1_hal_chip_select_low();
511 
512  // Write header byte and read status bits (MSB)
513  uint16_t status = bc_spirit1_hal_transfer_byte(0) << 8;
514 
515  // Write memory map address and read status bits (LSB)
516  status |= bc_spirit1_hal_transfer_byte(address);
517 
518  // Write buffer
519  for (size_t i = 0; i < length; i++)
520  {
521  // Write data
522  bc_spirit1_hal_transfer_byte(*((uint8_t *) buffer + i));
523  }
524 
525  // Set chip select high
526  bc_spirit1_hal_chip_select_high();
527 
528  // Disable PLL
529  bc_system_pll_disable();
530 
531  // TODO Why this cast?
532  return *((bc_spirit_status_t *) &status);
533 }
534 
535 bc_spirit_status_t bc_spirit1_read(uint8_t address, void *buffer, size_t length)
536 {
537  // Enable PLL
538  bc_system_pll_enable();
539 
540  // Set chip select low
541  bc_spirit1_hal_chip_select_low();
542 
543  // Write header byte and read status bits (MSB)
544  uint16_t status = bc_spirit1_hal_transfer_byte(1) << 8;
545 
546  // Write memory map address and read status bits (LSB)
547  status |= bc_spirit1_hal_transfer_byte(address);
548 
549  // Read buffer
550  for (size_t i = 0; i < length; i++)
551  {
552  // Write dummy byte and read data
553  *((uint8_t *) buffer + i) = bc_spirit1_hal_transfer_byte(0);
554  }
555 
556  // Set chip select high
557  bc_spirit1_hal_chip_select_high();
558 
559  // Disable PLL
560  bc_system_pll_disable();
561 
562  // TODO Why this cast?
563  return *((bc_spirit_status_t *) &status);
564 }
565 
566 void bc_spirit1_hal_init(void)
567 {
568  // Initialize timer
569  bc_timer_init();
570 
571  // Initialize GPIO
572  bc_spirit1_hal_init_gpio();
573 
574  // Initialize SPI
575  bc_spirit1_hal_init_spi();
576 
577  // Activate shutdown (forces delay)
578  bc_spirit1_hal_shutdown_high();
579 }
580 
581 void bc_spirit1_hal_shutdown_low(void)
582 {
583  // Output log. 0 on SDN pin
584  GPIOB->BSRR = GPIO_BSRR_BR_7;
585 
586  // Output log. 1 on CS pin
587  GPIOA->BSRR = GPIO_BSRR_BS_15;
588 
589  // TODO This delay might not exist (maybe poll GPIO?)...
590 
591  bc_timer_start();
592 
593  bc_timer_delay(10000);
594 
595  bc_timer_stop();
596 }
597 
598 void bc_spirit1_hal_shutdown_high(void)
599 {
600  // Enable PLL
601  bc_system_pll_enable();
602 
603  // Output log. 0 on CS pin
604  GPIOA->BSRR = GPIO_BSRR_BR_15;
605 
606  // Output log. 1 on SDN pin
607  GPIOB->BSRR = GPIO_BSRR_BS_7;
608 
609  bc_timer_start();
610 
611  bc_timer_delay(50000);
612 
613  bc_timer_clear();
614 
615  bc_timer_delay(50000);
616 
617  bc_timer_stop();
618 
619  // Disable PLL
620  bc_system_pll_disable();
621 }
622 
623 void bc_spirit1_hal_chip_select_low(void)
624 {
625  // Set CS pin to log. 0
626  GPIOA->BSRR = GPIO_BSRR_BR_15;
627 
628  bc_timer_start();
629 
630  while(bc_timer_get_microseconds() < 4)
631  {
632  continue;
633  }
634 
635  bc_timer_stop();
636 }
637 
638 void bc_spirit1_hal_chip_select_high(void)
639 {
640  bc_timer_start();
641 
642  while(bc_timer_get_microseconds() < 4)
643  {
644  continue;
645  }
646 
647  // Set CS pin to log. 1
648  GPIOA->BSRR = GPIO_BSRR_BS_15;
649 
650  while(bc_timer_get_microseconds() < 8)
651  {
652  continue;
653  }
654 
655  bc_timer_stop();
656 }
657 
658 uint8_t bc_spirit1_hal_transfer_byte(uint8_t value)
659 {
660  // Wait until transmit buffer is empty
661  while ((SPI1->SR & SPI_SR_TXE) == 0)
662  {
663  continue;
664  }
665 
666  // Write data register
667  SPI1->DR = value;
668 
669  // Wait until receive buffer is full
670  while ((SPI1->SR & SPI_SR_RXNE) == 0)
671  {
672  continue;
673  }
674 
675  // Read data register
676  value = SPI1->DR;
677 
678  return value;
679 }
680 
681 static void bc_spirit1_hal_init_gpio(void)
682 {
683  // Enable clock for GPIOH, GPIOB and GPIOA
684  RCC->IOPENR |= RCC_IOPENR_GPIOHEN | RCC_IOPENR_GPIOBEN | RCC_IOPENR_GPIOAEN;
685 
686  // Errata workaround
687  RCC->IOPENR;
688 
689  // Output log. 1 on SDN pin
690  GPIOB->BSRR = GPIO_BSRR_BS_7;
691 
692  // Pull-down on GPIO_0 pin
693  GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_1;
694 
695  // Pull-down on MISO pin
696  GPIOB->PUPDR |= GPIO_PUPDR_PUPD4_1;
697 
698  // Pull-down on GPIO_1 pin
699  GPIOH->PUPDR |= GPIO_PUPDR_PUPD0_1;
700 
701  // Very high speed on CS pin
702  GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEED15_1 | GPIO_OSPEEDER_OSPEED15_0;
703 
704  // Very high speed on MOSI and SCLK pins
705  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEED5_1 | GPIO_OSPEEDER_OSPEED5_0 | GPIO_OSPEEDER_OSPEED3_1 | GPIO_OSPEEDER_OSPEED3_0;
706 
707  // General purpose output on CS pin, input on GPIO_0 pin
708  GPIOA->MODER &= ~(GPIO_MODER_MODE15_1 | GPIO_MODER_MODE7_1 | GPIO_MODER_MODE7_0);
709 
710  // General purpose output on SDN pin, alternate function on MOSI, MISO and SCLK pins
711  GPIOB->MODER &= ~(GPIO_MODER_MODE7_1 | GPIO_MODER_MODE5_0 | GPIO_MODER_MODE4_0 | GPIO_MODER_MODE3_0);
712 
713  // Input on GPIO_1 pin
714  GPIOH->MODER &= ~(GPIO_MODER_MODE0_1 | GPIO_MODER_MODE0_0);
715 }
716 
717 static void bc_spirit1_hal_deinit_gpio(void)
718 {
719  // Low speed on CS pin
720  GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED15_Msk;
721 
722  // Low speed on CS pin, input on GPIO_0 pin
723  GPIOB->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEED5_Msk | GPIO_OSPEEDER_OSPEED3_Msk);
724 
725  // Analog on CS pin, input on GPIO_0 pin
726  GPIOA->MODER |= GPIO_MODER_MODE15_Msk | GPIO_MODER_MODE7_Msk;
727 
728  // Analog on SDN pin, alternate function on MOSI, MISO and SCLK pins
729  GPIOB->MODER |= GPIO_MODER_MODE7_Msk | GPIO_MODER_MODE5_Msk | GPIO_MODER_MODE4_Msk | GPIO_MODER_MODE3_Msk;
730 
731  // Analog on GPIO_1 pin
732  GPIOH->MODER |= GPIO_MODER_MODE0_Msk;
733 
734  // Output log. 0 on SDN pin
735  GPIOB->BSRR = GPIO_BSRR_BR_7;
736 
737  // No pull-down on GPIO_0 pin
738  GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD7_Msk;
739 
740  // No pull-down on MISO pin
741  GPIOB->PUPDR &= ~GPIO_PUPDR_PUPD4_Msk;
742 
743  // No pull-down on GPIO_1 pin
744  GPIOH->PUPDR &= ~GPIO_PUPDR_PUPD0_Msk;
745 }
746 
747 static void bc_spirit1_hal_init_spi(void)
748 {
749  // Enable clock for SPI1
750  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
751 
752  // Software slave management, baud rate control = fPCLK / 8, master configuration
753  SPI1->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_BR_1 | SPI_CR1_MSTR;
754 
755  // Enable SPI
756  SPI1->CR1 |= SPI_CR1_SPE;
757 }
758 
759 static void bc_spirit1_hal_deinit_spi(void)
760 {
761  // Disable SPI
762  SPI1->CR1 = 0;
763 
764  // Disable clock for SPI1
765  RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
766 }
767 
768 static void _bc_spirit1_interrupt(bc_exti_line_t line, void *param)
769 {
770  (void) line;
771  (void) param;
772 
773  bc_scheduler_plan_now(_bc_spirit1.task_id);
774 }
bool bc_spirit1_deinit(void)
Deitialize.
Definition: bc_spirit1.c:150
void * bc_spirit1_get_tx_buffer(void)
Get TX buffer.
Definition: bc_spirit1.c:176
uint64_t bc_tick_t
Timestamp data type.
Definition: bc_tick.h:16
void bc_scheduler_plan_absolute(bc_scheduler_task_id_t task_id, bc_tick_t tick)
Schedule specified task to absolute tick.
Definition: bc_scheduler.c:124
bool bc_spirit1_init(void)
Initialize.
Definition: bc_spirit1.c:98
void bc_spirit1_tx(void)
Enter TX state.
Definition: bc_spirit1.c:228
void bc_spirit1_rx(void)
Enter RX state.
Definition: bc_spirit1.c:238
size_t bc_spirit1_get_tx_length(void)
Get TX buffer length.
Definition: bc_spirit1.c:186
void bc_timer_start(void)
Start timer.
Definition: bc_timer.c:24
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
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_timer_delay(uint16_t microseconds)
Relative delay.
Definition: bc_timer.c:40
void bc_scheduler_plan_current_absolute(bc_tick_t tick)
Schedule current task to absolute tick.
Definition: bc_scheduler.c:144
void bc_spirit1_sleep(void)
Enter sleep state.
Definition: bc_spirit1.c:248
bc_tick_t bc_tick_get(void)
Get absolute timestamp since start of program.
Definition: bc_tick.c:7
void bc_timer_stop(void)
Stop timer.
Definition: bc_timer.c:55
void bc_spirit1_set_event_handler(void(*event_handler)(bc_spirit1_event_t, void *), void *event_param)
Set callback function.
Definition: bc_spirit1.c:170
size_t bc_scheduler_task_id_t
Task ID assigned by scheduler.
Definition: bc_scheduler.h:18
void bc_timer_clear(void)
Clear timer counter.
Definition: bc_timer.c:50
void bc_exti_register(bc_exti_line_t line, bc_exti_edge_t edge, void(*callback)(bc_exti_line_t, void *), void *param)
Enable EXTI line interrupt and register callback function.
Definition: bc_exti.c:17
void bc_exti_unregister(bc_exti_line_t line)
Disable EXTI line interrupt.
Definition: bc_exti.c:90
EXTI line PA7.
Definition: bc_exti.h:45
uint16_t bc_timer_get_microseconds(void)
Get actual tick of timer.
Definition: bc_timer.c:35
Event is RX timeout.
Definition: bc_spirit1.h:27
bc_exti_line_t
EXTI lines.
Definition: bc_exti.h:21
size_t bc_spirit1_get_rx_length(void)
Get RX buffer length.
Definition: bc_spirit1.c:196
#define BC_TICK_INFINITY
Maximum timestamp value.
Definition: bc_tick.h:12
Event is RX done.
Definition: bc_spirit1.h:24
void bc_spirit1_set_rx_timeout(bc_tick_t timeout)
Set TX timeout.
Definition: bc_spirit1.c:206
void * bc_spirit1_get_rx_buffer(void)
Get RX buffer.
Definition: bc_spirit1.c:191
Event is TX done.
Definition: bc_spirit1.h:21
void bc_timer_init(void)
Initialize timer.
Definition: bc_timer.c:18
void bc_spirit1_set_tx_length(size_t length)
Set TX buffer length.
Definition: bc_spirit1.c:181
void bc_scheduler_unregister(bc_scheduler_task_id_t task_id)
Unregister specified task.
Definition: bc_scheduler.c:80
EXTI line is configured to falling edge sensitivity.
Definition: bc_exti.h:201
int bc_spirit1_get_rx_rssi(void)
Get RSSI.
Definition: bc_spirit1.c:201
bc_spirit1_event_t
Callback events.
Definition: bc_spirit1.h:18