Firmware SDK
twr_spirit1.c
1 #include <twr_spirit1.h>
2 #include <twr_scheduler.h>
3 #include <twr_exti.h>
4 #include <twr_system.h>
5 #include <twr_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  TWR_SPIRIT1_STATE_INIT = 0,
14  TWR_SPIRIT1_STATE_SLEEP = 1,
15  TWR_SPIRIT1_STATE_TX = 2,
16  TWR_SPIRIT1_STATE_RX = 3
17 
18 } twr_spirit1_state_t;
19 
20 typedef struct
21 {
22  int initialized_semaphore;
23  void (*event_handler)(twr_spirit1_event_t, void *);
24  void *event_param;
26  twr_spirit1_state_t desired_state;
27  twr_spirit1_state_t current_state;
28  uint8_t tx_buffer[TWR_SPIRIT1_MAX_PACKET_SIZE];
29  size_t tx_length;
30  uint8_t rx_buffer[TWR_SPIRIT1_MAX_PACKET_SIZE];
31  size_t rx_length;
32  int rx_rssi;
33  twr_tick_t rx_timeout;
34  twr_tick_t rx_tick_timeout;
35 
37 
38 static twr_spirit1_t _twr_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 _twr_spirit1_enter_state_tx(void);
82 static void _twr_spirit1_check_state_tx(void);
83 static void _twr_spirit1_enter_state_rx(void);
84 static void _twr_spirit1_check_state_rx(void);
85 static void _twr_spirit1_enter_state_sleep(void);
86 
87 void twr_spirit1_hal_chip_select_low(void);
88 void twr_spirit1_hal_chip_select_high(void);
89 uint8_t twr_spirit1_hal_transfer_byte(uint8_t value);
90 static void twr_spirit1_hal_init_gpio(void);
91 static void twr_spirit1_hal_deinit_gpio(void);
92 static void twr_spirit1_hal_init_spi(void);
93 static void twr_spirit1_hal_deinit_spi(void);
94 
95 static void _twr_spirit1_task(void *param);
96 static void _twr_spirit1_interrupt(twr_exti_line_t line, void *param);
97 
98 bool twr_spirit1_init(void)
99 {
100  if (_twr_spirit1.initialized_semaphore > 0)
101  {
102  _twr_spirit1.initialized_semaphore++;
103 
104  return true;
105  }
106 
107  memset(&_twr_spirit1, 0, sizeof(_twr_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  twr_spirit1_hal_shutdown_high();
128 
129  twr_spirit1_hal_deinit_spi();
130 
131  twr_spirit1_hal_deinit_gpio();
132 
133  return false;
134  }
135 
136  /* Spirit Packet config */
137  SpiritPktBasicInit(&xBasicInit);
138 
139  SpiritPktBasicAddressesInit(&xAddressInit);
140 
141  _twr_spirit1.desired_state = TWR_SPIRIT1_STATE_SLEEP;
142 
143  _twr_spirit1.task_id = twr_scheduler_register(_twr_spirit1_task, NULL, 0);
144 
145  _twr_spirit1.initialized_semaphore++;
146 
147  return true;
148 }
149 
151 {
152  if (--_twr_spirit1.initialized_semaphore != 0)
153  {
154  return false;
155  }
156 
157  twr_spirit1_hal_shutdown_high();
158 
159  twr_spirit1_hal_deinit_spi();
160 
161  twr_spirit1_hal_deinit_gpio();
162 
163  twr_scheduler_unregister(_twr_spirit1.task_id);
164 
166 
167  return true;
168 }
169 
170 void twr_spirit1_set_event_handler(void (*event_handler)(twr_spirit1_event_t, void *), void *event_param)
171 {
172  _twr_spirit1.event_handler = event_handler;
173  _twr_spirit1.event_param = event_param;
174 }
175 
177 {
178  return _twr_spirit1.tx_buffer;
179 }
180 
181 void twr_spirit1_set_tx_length(size_t length)
182 {
183  _twr_spirit1.tx_length = length;
184 }
185 
187 {
188  return _twr_spirit1.tx_length;
189 }
190 
192 {
193  return _twr_spirit1.rx_buffer;
194 }
195 
197 {
198  return _twr_spirit1.rx_length;
199 }
200 
202 {
203  return _twr_spirit1.rx_rssi;
204 }
205 
207 {
208  _twr_spirit1.rx_timeout = timeout;
209 
210  if (_twr_spirit1.current_state == TWR_SPIRIT1_STATE_RX)
211  {
212  if (_twr_spirit1.rx_timeout == TWR_TICK_INFINITY)
213  {
214  _twr_spirit1.rx_tick_timeout = TWR_TICK_INFINITY;
215  }
216  else
217  {
218  _twr_spirit1.rx_tick_timeout = twr_tick_get() + _twr_spirit1.rx_timeout;
219  }
220 
221  if (_twr_spirit1.initialized_semaphore > 0)
222  {
223  twr_scheduler_plan_absolute(_twr_spirit1.task_id, _twr_spirit1.rx_tick_timeout);
224  }
225  }
226 }
227 
228 void twr_spirit1_tx(void)
229 {
230  _twr_spirit1.desired_state = TWR_SPIRIT1_STATE_TX;
231 
232  if (_twr_spirit1.initialized_semaphore > 0)
233  {
234  twr_scheduler_plan_now(_twr_spirit1.task_id);
235  }
236 }
237 
238 void twr_spirit1_rx(void)
239 {
240  _twr_spirit1.desired_state = TWR_SPIRIT1_STATE_RX;
241 
242  if (_twr_spirit1.initialized_semaphore > 0)
243  {
244  twr_scheduler_plan_now(_twr_spirit1.task_id);
245  }
246 }
247 
249 {
250  _twr_spirit1.desired_state = TWR_SPIRIT1_STATE_SLEEP;
251 
252  if (_twr_spirit1.initialized_semaphore > 0)
253  {
254  twr_scheduler_plan_now(_twr_spirit1.task_id);
255  }
256 }
257 
258 static void _twr_spirit1_task(void *param)
259 {
260  (void) param;
261 
262  if ((_twr_spirit1.current_state == TWR_SPIRIT1_STATE_RX) && (twr_tick_get() >= _twr_spirit1.rx_tick_timeout))
263  {
264  if (_twr_spirit1.event_handler != NULL)
265  {
266  _twr_spirit1.event_handler(TWR_SPIRIT1_EVENT_RX_TIMEOUT, _twr_spirit1.event_param);
267  }
268  }
269 
270  if (_twr_spirit1.desired_state != _twr_spirit1.current_state)
271  {
272  if (_twr_spirit1.desired_state == TWR_SPIRIT1_STATE_TX)
273  {
274  _twr_spirit1_enter_state_tx();
275 
276  return;
277  }
278  else if (_twr_spirit1.desired_state == TWR_SPIRIT1_STATE_RX)
279  {
280  _twr_spirit1_enter_state_rx();
281 
282  return;
283  }
284  else if (_twr_spirit1.desired_state == TWR_SPIRIT1_STATE_SLEEP)
285  {
286  _twr_spirit1_enter_state_sleep();
287 
288  return;
289  }
290 
291  return;
292  }
293 
294  if (_twr_spirit1.current_state == TWR_SPIRIT1_STATE_TX)
295  {
296  _twr_spirit1_check_state_tx();
297 
298  return;
299  }
300  else if (_twr_spirit1.current_state == TWR_SPIRIT1_STATE_RX)
301  {
302  _twr_spirit1_check_state_rx();
303 
304  return;
305  }
306 }
307 
308 static void _twr_spirit1_enter_state_tx(void)
309 {
310  GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_1;
311 
312  _twr_spirit1.current_state = TWR_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(_twr_spirit1.tx_length);
323 
324  // TODO Why needed?
325  SpiritPktBasicSetDestinationAddress(0x35);
326 
327  SpiritSpiWriteLinearFifo(_twr_spirit1.tx_length, _twr_spirit1.tx_buffer);
328 
329  twr_exti_register(TWR_EXTI_LINE_PA7, TWR_EXTI_EDGE_FALLING, _twr_spirit1_interrupt, NULL);
330 
331  SpiritCmdStrobeTx();
332 }
333 
334 static void _twr_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  _twr_spirit1.desired_state = TWR_SPIRIT1_STATE_SLEEP;
345 
346  if (_twr_spirit1.event_handler != NULL)
347  {
348  _twr_spirit1.event_handler(TWR_SPIRIT1_EVENT_TX_DONE, _twr_spirit1.event_param);
349  }
350 
351  if (_twr_spirit1.desired_state == TWR_SPIRIT1_STATE_RX)
352  {
353  _twr_spirit1_enter_state_rx();
354  }
355  else if (_twr_spirit1.desired_state == TWR_SPIRIT1_STATE_SLEEP)
356  {
357  _twr_spirit1_enter_state_sleep();
358  }
359  else if (_twr_spirit1.desired_state == TWR_SPIRIT1_STATE_TX)
360  {
361  _twr_spirit1_enter_state_tx();
362  }
363  }
364 }
365 
366 static void _twr_spirit1_enter_state_rx(void)
367 {
368  GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_1;
369 
370  _twr_spirit1.current_state = TWR_SPIRIT1_STATE_RX;
371 
372  if (_twr_spirit1.rx_timeout == TWR_TICK_INFINITY)
373  {
374  _twr_spirit1.rx_tick_timeout = TWR_TICK_INFINITY;
375  }
376  else
377  {
378  _twr_spirit1.rx_tick_timeout = twr_tick_get() + _twr_spirit1.rx_timeout;
379  }
380 
381  twr_scheduler_plan_current_absolute(_twr_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  twr_exti_register(TWR_EXTI_LINE_PA7, TWR_EXTI_EDGE_FALLING, _twr_spirit1_interrupt, NULL);
404 
405  /* RX command */
406  SpiritCmdStrobeRx();
407 }
408 
409 static void _twr_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 <= TWR_SPIRIT1_MAX_PACKET_SIZE)
430  {
431  /* Read the RX FIFO */
432  SpiritSpiReadLinearFifo(cRxData, _twr_spirit1.rx_buffer);
433 
434  _twr_spirit1.rx_length = cRxData;
435 
436  uint8_t rssi_level;
437 
438  twr_spirit1_read(RSSI_LEVEL_BASE, &rssi_level, 1);
439 
440  _twr_spirit1.rx_rssi = ((int) rssi_level) / 2 - 130;
441 
442  if (_twr_spirit1.rx_timeout == TWR_TICK_INFINITY)
443  {
444  _twr_spirit1.rx_tick_timeout = TWR_TICK_INFINITY;
445  }
446  else
447  {
448  _twr_spirit1.rx_tick_timeout = twr_tick_get() + _twr_spirit1.rx_timeout;
449  }
450 
451  twr_scheduler_plan_current_absolute(_twr_spirit1.rx_tick_timeout);
452 
453  if (_twr_spirit1.event_handler != NULL)
454  {
455  _twr_spirit1.event_handler(TWR_SPIRIT1_EVENT_RX_DONE, _twr_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 _twr_spirit1_enter_state_sleep(void)
468 {
469  _twr_spirit1.current_state = TWR_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 twr_spirit_status_t twr_spirit1_command(uint8_t command)
481 {
482  // Enable PLL
483  twr_system_pll_enable();
484 
485  // Set chip select low
486  twr_spirit1_hal_chip_select_low();
487 
488  // Write header byte and read status bits (MSB)
489  uint16_t status_value = twr_spirit1_hal_transfer_byte(0x80) << 8;
490 
491  // Write memory map address and read status bits (LSB)
492  status_value |= twr_spirit1_hal_transfer_byte(command);
493 
494  // Set chip select high
495  twr_spirit1_hal_chip_select_high();
496 
497  // Disable PLL
498  twr_system_pll_disable();
499 
500  twr_spirit_status_t *status = ((twr_spirit_status_t *) &status_value);
501 
502  // TODO Why this cast?
503  return *status;
504 }
505 
506 twr_spirit_status_t twr_spirit1_write(uint8_t address, const void *buffer, size_t length)
507 {
508  // Enable PLL
509  twr_system_pll_enable();
510 
511  // Set chip select low
512  twr_spirit1_hal_chip_select_low();
513 
514  // Write header byte and read status bits (MSB)
515  uint16_t status_value = twr_spirit1_hal_transfer_byte(0) << 8;
516 
517  // Write memory map address and read status bits (LSB)
518  status_value |= twr_spirit1_hal_transfer_byte(address);
519 
520  // Write buffer
521  for (size_t i = 0; i < length; i++)
522  {
523  // Write data
524  twr_spirit1_hal_transfer_byte(*((uint8_t *) buffer + i));
525  }
526 
527  // Set chip select high
528  twr_spirit1_hal_chip_select_high();
529 
530  // Disable PLL
531  twr_system_pll_disable();
532 
533  twr_spirit_status_t *status = ((twr_spirit_status_t *) &status_value);
534 
535  // TODO Why this cast?
536  return *status;
537 }
538 
539 twr_spirit_status_t twr_spirit1_read(uint8_t address, void *buffer, size_t length)
540 {
541  // Enable PLL
542  twr_system_pll_enable();
543 
544  // Set chip select low
545  twr_spirit1_hal_chip_select_low();
546 
547  // Write header byte and read status bits (MSB)
548  uint16_t status_value = twr_spirit1_hal_transfer_byte(1) << 8;
549 
550  // Write memory map address and read status bits (LSB)
551  status_value |= twr_spirit1_hal_transfer_byte(address);
552 
553  // Read buffer
554  for (size_t i = 0; i < length; i++)
555  {
556  // Write dummy byte and read data
557  *((uint8_t *) buffer + i) = twr_spirit1_hal_transfer_byte(0);
558  }
559 
560  // Set chip select high
561  twr_spirit1_hal_chip_select_high();
562 
563  // Disable PLL
564  twr_system_pll_disable();
565 
566  twr_spirit_status_t *status = ((twr_spirit_status_t *) &status_value);
567 
568  // TODO Why this cast?
569  return *status;
570 }
571 
572 void twr_spirit1_hal_init(void)
573 {
574  // Initialize timer
575  twr_timer_init();
576 
577  // Initialize GPIO
578  twr_spirit1_hal_init_gpio();
579 
580  // Initialize SPI
581  twr_spirit1_hal_init_spi();
582 
583  // Activate shutdown (forces delay)
584  twr_spirit1_hal_shutdown_high();
585 }
586 
587 void twr_spirit1_hal_shutdown_low(void)
588 {
589  // Output log. 0 on SDN pin
590  GPIOB->BSRR = GPIO_BSRR_BR_7;
591 
592  // Output log. 1 on CS pin
593  GPIOA->BSRR = GPIO_BSRR_BS_15;
594 
595  // TODO This delay might not exist (maybe poll GPIO?)...
596 
597  twr_timer_start();
598 
599  twr_timer_delay(10000);
600 
601  twr_timer_stop();
602 }
603 
604 void twr_spirit1_hal_shutdown_high(void)
605 {
606  // Enable PLL
607  twr_system_pll_enable();
608 
609  // Output log. 0 on CS pin
610  GPIOA->BSRR = GPIO_BSRR_BR_15;
611 
612  // Output log. 1 on SDN pin
613  GPIOB->BSRR = GPIO_BSRR_BS_7;
614 
615  twr_timer_start();
616 
617  twr_timer_delay(50000);
618 
619  twr_timer_clear();
620 
621  twr_timer_delay(50000);
622 
623  twr_timer_stop();
624 
625  // Disable PLL
626  twr_system_pll_disable();
627 }
628 
629 void twr_spirit1_hal_chip_select_low(void)
630 {
631  // Set CS pin to log. 0
632  GPIOA->BSRR = GPIO_BSRR_BR_15;
633 
634  twr_timer_start();
635 
636  while(twr_timer_get_microseconds() < 4)
637  {
638  continue;
639  }
640 
641  twr_timer_stop();
642 }
643 
644 void twr_spirit1_hal_chip_select_high(void)
645 {
646  twr_timer_start();
647 
648  while(twr_timer_get_microseconds() < 4)
649  {
650  continue;
651  }
652 
653  // Set CS pin to log. 1
654  GPIOA->BSRR = GPIO_BSRR_BS_15;
655 
656  while(twr_timer_get_microseconds() < 8)
657  {
658  continue;
659  }
660 
661  twr_timer_stop();
662 }
663 
664 uint8_t twr_spirit1_hal_transfer_byte(uint8_t value)
665 {
666  // Wait until transmit buffer is empty
667  while ((SPI1->SR & SPI_SR_TXE) == 0)
668  {
669  continue;
670  }
671 
672  // Write data register
673  SPI1->DR = value;
674 
675  // Wait until receive buffer is full
676  while ((SPI1->SR & SPI_SR_RXNE) == 0)
677  {
678  continue;
679  }
680 
681  // Read data register
682  value = SPI1->DR;
683 
684  return value;
685 }
686 
687 static void twr_spirit1_hal_init_gpio(void)
688 {
689  // Enable clock for GPIOH, GPIOB and GPIOA
690  RCC->IOPENR |= RCC_IOPENR_GPIOHEN | RCC_IOPENR_GPIOBEN | RCC_IOPENR_GPIOAEN;
691 
692  // Errata workaround
693  RCC->IOPENR;
694 
695  // Output log. 1 on SDN pin
696  GPIOB->BSRR = GPIO_BSRR_BS_7;
697 
698  // Pull-down on GPIO_0 pin
699  GPIOA->PUPDR |= GPIO_PUPDR_PUPD7_1;
700 
701  // Pull-down on MISO pin
702  GPIOB->PUPDR |= GPIO_PUPDR_PUPD4_1;
703 
704  // Pull-down on GPIO_1 pin
705  GPIOH->PUPDR |= GPIO_PUPDR_PUPD0_1;
706 
707  // Very high speed on CS pin
708  GPIOA->OSPEEDR |= GPIO_OSPEEDER_OSPEED15_1 | GPIO_OSPEEDER_OSPEED15_0;
709 
710  // Very high speed on MOSI and SCLK pins
711  GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEED5_1 | GPIO_OSPEEDER_OSPEED5_0 | GPIO_OSPEEDER_OSPEED3_1 | GPIO_OSPEEDER_OSPEED3_0;
712 
713  // General purpose output on CS pin, input on GPIO_0 pin
714  GPIOA->MODER &= ~(GPIO_MODER_MODE15_1 | GPIO_MODER_MODE7_1 | GPIO_MODER_MODE7_0);
715 
716  // General purpose output on SDN pin, alternate function on MOSI, MISO and SCLK pins
717  GPIOB->MODER &= ~(GPIO_MODER_MODE7_1 | GPIO_MODER_MODE5_0 | GPIO_MODER_MODE4_0 | GPIO_MODER_MODE3_0);
718 
719  // Input on GPIO_1 pin
720  GPIOH->MODER &= ~(GPIO_MODER_MODE0_1 | GPIO_MODER_MODE0_0);
721 }
722 
723 static void twr_spirit1_hal_deinit_gpio(void)
724 {
725  // Low speed on CS pin
726  GPIOA->OSPEEDR &= ~GPIO_OSPEEDER_OSPEED15_Msk;
727 
728  // Low speed on CS pin, input on GPIO_0 pin
729  GPIOB->OSPEEDR &= ~(GPIO_OSPEEDER_OSPEED5_Msk | GPIO_OSPEEDER_OSPEED3_Msk);
730 
731  // Analog on CS pin, input on GPIO_0 pin
732  GPIOA->MODER |= GPIO_MODER_MODE15_Msk | GPIO_MODER_MODE7_Msk;
733 
734  // Analog on SDN pin, alternate function on MOSI, MISO and SCLK pins
735  GPIOB->MODER |= GPIO_MODER_MODE7_Msk | GPIO_MODER_MODE5_Msk | GPIO_MODER_MODE4_Msk | GPIO_MODER_MODE3_Msk;
736 
737  // Analog on GPIO_1 pin
738  GPIOH->MODER |= GPIO_MODER_MODE0_Msk;
739 
740  // Output log. 0 on SDN pin
741  GPIOB->BSRR = GPIO_BSRR_BR_7;
742 
743  // No pull-down on GPIO_0 pin
744  GPIOA->PUPDR &= ~GPIO_PUPDR_PUPD7_Msk;
745 
746  // No pull-down on MISO pin
747  GPIOB->PUPDR &= ~GPIO_PUPDR_PUPD4_Msk;
748 
749  // No pull-down on GPIO_1 pin
750  GPIOH->PUPDR &= ~GPIO_PUPDR_PUPD0_Msk;
751 }
752 
753 static void twr_spirit1_hal_init_spi(void)
754 {
755  // Enable clock for SPI1
756  RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
757 
758  // Software slave management, baud rate control = fPCLK / 8, master configuration
759  SPI1->CR1 = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_BR_1 | SPI_CR1_MSTR;
760 
761  // Enable SPI
762  SPI1->CR1 |= SPI_CR1_SPE;
763 }
764 
765 static void twr_spirit1_hal_deinit_spi(void)
766 {
767  // Disable SPI
768  SPI1->CR1 = 0;
769 
770  // Disable clock for SPI1
771  RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
772 }
773 
774 static void _twr_spirit1_interrupt(twr_exti_line_t line, void *param)
775 {
776  (void) line;
777  (void) param;
778 
779  twr_scheduler_plan_now(_twr_spirit1.task_id);
780 }
void twr_exti_register(twr_exti_line_t line, twr_exti_edge_t edge, void(*callback)(twr_exti_line_t, void *), void *param)
Enable EXTI line interrupt and register callback function.
Definition: twr_exti.c:17
void twr_exti_unregister(twr_exti_line_t line)
Disable EXTI line interrupt.
Definition: twr_exti.c:90
twr_exti_line_t
EXTI lines.
Definition: twr_exti.h:22
@ TWR_EXTI_LINE_PA7
EXTI line PA7.
Definition: twr_exti.h:45
@ TWR_EXTI_EDGE_FALLING
EXTI line is configured to falling edge sensitivity.
Definition: twr_exti.h:201
void twr_scheduler_plan_current_absolute(twr_tick_t tick)
Schedule current task to absolute tick.
void twr_scheduler_plan_absolute(twr_scheduler_task_id_t task_id, twr_tick_t tick)
Schedule specified task to absolute tick.
void twr_scheduler_unregister(twr_scheduler_task_id_t task_id)
Unregister specified task.
Definition: twr_scheduler.c:77
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
bool twr_spirit1_deinit(void)
Deitialize.
Definition: twr_spirit1.c:150
void * twr_spirit1_get_rx_buffer(void)
Get RX buffer.
Definition: twr_spirit1.c:191
void * twr_spirit1_get_tx_buffer(void)
Get TX buffer.
Definition: twr_spirit1.c:176
void twr_spirit1_tx(void)
Enter TX state.
Definition: twr_spirit1.c:228
twr_spirit1_event_t
Callback events.
Definition: twr_spirit1.h:19
void twr_spirit1_set_rx_timeout(twr_tick_t timeout)
Set TX timeout.
Definition: twr_spirit1.c:206
size_t twr_spirit1_get_tx_length(void)
Get TX buffer length.
Definition: twr_spirit1.c:186
int twr_spirit1_get_rx_rssi(void)
Get RSSI.
Definition: twr_spirit1.c:201
void twr_spirit1_sleep(void)
Enter sleep state.
Definition: twr_spirit1.c:248
void twr_spirit1_set_tx_length(size_t length)
Set TX buffer length.
Definition: twr_spirit1.c:181
bool twr_spirit1_init(void)
Initialize.
Definition: twr_spirit1.c:98
size_t twr_spirit1_get_rx_length(void)
Get RX buffer length.
Definition: twr_spirit1.c:196
void twr_spirit1_rx(void)
Enter RX state.
Definition: twr_spirit1.c:238
void twr_spirit1_set_event_handler(void(*event_handler)(twr_spirit1_event_t, void *), void *event_param)
Set callback function.
Definition: twr_spirit1.c:170
@ TWR_SPIRIT1_EVENT_RX_TIMEOUT
Event is RX timeout.
Definition: twr_spirit1.h:27
@ TWR_SPIRIT1_EVENT_TX_DONE
Event is TX done.
Definition: twr_spirit1.h:21
@ TWR_SPIRIT1_EVENT_RX_DONE
Event is RX done.
Definition: twr_spirit1.h:24
#define TWR_TICK_INFINITY
Maximum timestamp value.
Definition: twr_tick.h:12
twr_tick_t twr_tick_get(void)
Get absolute timestamp since start of program.
Definition: twr_tick.c:7
uint64_t twr_tick_t
Timestamp data type.
Definition: twr_tick.h:16
void twr_timer_clear(void)
Clear timer counter.
Definition: twr_timer.c:69
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
uint16_t twr_timer_get_microseconds(void)
Get actual tick of timer.
Definition: twr_timer.c:54