digital_signal.c 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. #include "digital_signal.h"
  2. #include <furi.h>
  3. #include <stm32wbxx_ll_dma.h>
  4. #include <stm32wbxx_ll_tim.h>
  5. #include <math.h>
  6. #define F_TIM (64000000.0)
  7. #define T_TIM (1.0 / F_TIM)
  8. DigitalSignal* digital_signal_alloc(uint32_t max_edges_cnt) {
  9. DigitalSignal* signal = malloc(sizeof(DigitalSignal));
  10. signal->start_level = true;
  11. signal->edges_max_cnt = max_edges_cnt;
  12. signal->edge_timings = malloc(max_edges_cnt * sizeof(float));
  13. signal->reload_reg_buff = malloc(max_edges_cnt * sizeof(uint32_t));
  14. signal->edge_cnt = 0;
  15. return signal;
  16. }
  17. void digital_signal_free(DigitalSignal* signal) {
  18. furi_assert(signal);
  19. free(signal->edge_timings);
  20. free(signal->reload_reg_buff);
  21. free(signal);
  22. }
  23. bool digital_signal_append(DigitalSignal* signal_a, DigitalSignal* signal_b) {
  24. furi_assert(signal_a);
  25. furi_assert(signal_b);
  26. if(signal_a->edges_max_cnt < signal_a->edge_cnt + signal_b->edge_cnt) {
  27. return false;
  28. }
  29. bool end_level = signal_a->start_level;
  30. if(signal_a->edge_cnt) {
  31. end_level = signal_a->start_level ^ !(signal_a->edge_cnt % 2);
  32. }
  33. uint8_t start_copy = 0;
  34. if(end_level == signal_b->start_level) {
  35. if(signal_a->edge_cnt) {
  36. signal_a->edge_timings[signal_a->edge_cnt - 1] += signal_b->edge_timings[0];
  37. start_copy += 1;
  38. } else {
  39. signal_a->edge_timings[signal_a->edge_cnt] += signal_b->edge_timings[0];
  40. }
  41. }
  42. memcpy(
  43. &signal_a->edge_timings[signal_a->edge_cnt],
  44. &signal_b->edge_timings[start_copy],
  45. (signal_b->edge_cnt - start_copy) * sizeof(float));
  46. signal_a->edge_cnt += signal_b->edge_cnt - start_copy;
  47. return true;
  48. }
  49. bool digital_signal_get_start_level(DigitalSignal* signal) {
  50. furi_assert(signal);
  51. return signal->start_level;
  52. }
  53. uint32_t digital_signal_get_edges_cnt(DigitalSignal* signal) {
  54. furi_assert(signal);
  55. return signal->edge_cnt;
  56. }
  57. float digital_signal_get_edge(DigitalSignal* signal, uint32_t edge_num) {
  58. furi_assert(signal);
  59. furi_assert(edge_num < signal->edge_cnt);
  60. return signal->edge_timings[edge_num];
  61. }
  62. static void digital_signal_prepare_arr(DigitalSignal* signal) {
  63. float t_signal = 0;
  64. float t_current = 0;
  65. float r = 0;
  66. float r_int = 0;
  67. float r_dec = 0;
  68. for(size_t i = 0; i < signal->edge_cnt - 1; i++) {
  69. t_signal += signal->edge_timings[i];
  70. r = (t_signal - t_current) / T_TIM;
  71. r_dec = modff(r, &r_int);
  72. if(r_dec < 0.5f) {
  73. signal->reload_reg_buff[i] = (uint32_t)r_int - 1;
  74. } else {
  75. signal->reload_reg_buff[i] = (uint32_t)r_int;
  76. }
  77. t_current += (signal->reload_reg_buff[i] + 1) * T_TIM;
  78. }
  79. }
  80. bool digital_signal_send(DigitalSignal* signal, const GpioPin* gpio) {
  81. furi_assert(signal);
  82. furi_assert(gpio);
  83. // Configure gpio as output
  84. furi_hal_gpio_init(gpio, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
  85. // Init gpio buffer and DMA channel
  86. uint16_t gpio_reg = gpio->port->ODR;
  87. uint16_t gpio_buff[2];
  88. if(signal->start_level) {
  89. gpio_buff[0] = gpio_reg | gpio->pin;
  90. gpio_buff[1] = gpio_reg & ~(gpio->pin);
  91. } else {
  92. gpio_buff[0] = gpio_reg & ~(gpio->pin);
  93. gpio_buff[1] = gpio_reg | gpio->pin;
  94. }
  95. LL_DMA_InitTypeDef dma_config = {};
  96. dma_config.MemoryOrM2MDstAddress = (uint32_t)gpio_buff;
  97. dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (gpio->port->ODR);
  98. dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
  99. dma_config.Mode = LL_DMA_MODE_CIRCULAR;
  100. dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
  101. dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
  102. dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_HALFWORD;
  103. dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
  104. dma_config.NbData = 2;
  105. dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
  106. dma_config.Priority = LL_DMA_PRIORITY_VERYHIGH;
  107. LL_DMA_Init(DMA1, LL_DMA_CHANNEL_1, &dma_config);
  108. LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_1, 2);
  109. LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
  110. // Init timer arr register buffer and DMA channel
  111. digital_signal_prepare_arr(signal);
  112. dma_config.MemoryOrM2MDstAddress = (uint32_t)signal->reload_reg_buff;
  113. dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (TIM2->ARR);
  114. dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
  115. dma_config.Mode = LL_DMA_MODE_NORMAL;
  116. dma_config.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
  117. dma_config.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
  118. dma_config.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
  119. dma_config.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
  120. dma_config.NbData = signal->edge_cnt - 2;
  121. dma_config.PeriphRequest = LL_DMAMUX_REQ_TIM2_UP;
  122. dma_config.Priority = LL_DMA_PRIORITY_HIGH;
  123. LL_DMA_Init(DMA1, LL_DMA_CHANNEL_2, &dma_config);
  124. LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_2, signal->edge_cnt - 2);
  125. LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_2);
  126. // Set up timer
  127. LL_TIM_SetCounterMode(TIM2, LL_TIM_COUNTERMODE_UP);
  128. LL_TIM_SetClockDivision(TIM2, LL_TIM_CLOCKDIVISION_DIV1);
  129. LL_TIM_SetPrescaler(TIM2, 0);
  130. LL_TIM_SetAutoReload(TIM2, 10);
  131. LL_TIM_SetCounter(TIM2, 0);
  132. LL_TIM_EnableUpdateEvent(TIM2);
  133. LL_TIM_EnableDMAReq_UPDATE(TIM2);
  134. // Start transactions
  135. LL_TIM_GenerateEvent_UPDATE(TIM2); // Do we really need it?
  136. LL_TIM_EnableCounter(TIM2);
  137. while(!LL_DMA_IsActiveFlag_TC2(DMA1))
  138. ;
  139. LL_DMA_ClearFlag_TC1(DMA1);
  140. LL_DMA_ClearFlag_TC2(DMA1);
  141. LL_TIM_DisableCounter(TIM2);
  142. LL_TIM_SetCounter(TIM2, 0);
  143. LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_1);
  144. LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_2);
  145. return true;
  146. }