当前位置:   article > 正文

NRF52832 UART接收不定长数据

NRF52832 UART接收不定长数据

问题:

在使用NRF52832做串口透传的时候,示例程序里UARTE,接收长度为1个字节。如果串口接收到长数据(测试了1K),则很容易导致蓝牙发送的超时重启。

解决方案:使用PPI功能,使串口具备接收不定长数据的能力。

方案参考的是Nordic的libuarte工程,但是我们这里面有soft device,其本身会占用一些外设,比如RTC0,TIMER0等。那我们就只能选择其他外设,这里选用TIMER1和TIMER2。

PPI的配置之后的接收流程如下:

  1. 设置接收缓冲区,缓冲区的长度为UARTE能接受的最大长度。
  2. 触发UARTE的NRF_UARTE_TASK_STARTRX任务。
  3. 任务开始之后会触发NRF_UARTE_EVENT_RXSTARTED,在这个事件中断里切换缓冲区。由于UARTE的缓冲区指针是双缓冲的,所以此次设置的缓冲区为下次接收的缓冲区。
  4. 接收到数据触发NRF_UARTE_EVENT_RXDRDY事件,NRF_UARTE_EVENT_RXDRDY自动触发TIMER1的NRF_TIMER_TASK_START和NRF_TIMER_TASK_CLEAR。TIMER1的超时时间比UARTE接收一个字符的时间稍长,模拟的32类的单片机UART的IDLE功能。NRF_UARTE_EVENT_RXDRDY同时触发TIMER2的计数,记录一共接收了多少字节。
  5. NRF_UARTE_EVENT_ENDRX触发TIMER2的NRF_TIMER_TASK_CAPTURE1,获取到一共接收了多少数据,同时触发NRF_UARTE_TASK_STARTRX,将接收到的数据存入下一个缓冲区中。由于TIMER2捕获了一共接收的数据长度,则可以很容易的知道未处理的数据有多少,在中断中直接缓存数据即可。

核心代码如下:

  1. #define AYSN_UARTE NRF_UARTE0 // 使用uarte0
  2. #define PPI_CH_SETUP(_ch, _evt, _tsk, _fork) \
  3. ret = nrfx_ppi_channel_assign(_ch, _evt, _tsk); \
  4. if (ret != NRF_SUCCESS) \
  5. { \
  6. return NRF_ERROR_INTERNAL; \
  7. } \
  8. if (_fork) \
  9. { \
  10. ret = nrfx_ppi_channel_fork_assign(_ch, _fork); \
  11. if (ret != NRF_SUCCESS) \
  12. { \
  13. return NRF_ERROR_INTERNAL; \
  14. } \
  15. }
  16. extern gqueue_t qbtTx,qbtRx;
  17. // 使用uarte0,超时使用timer1,计数使用timer2
  18. static const nrfx_timer_t timeoutTimer = NRFX_TIMER_INSTANCE(1);
  19. static const nrfx_timer_t countTimer = NRFX_TIMER_INSTANCE(2);
  20. static nrf_ppi_channel_t uartePpiChannels[UARTE_ASYNC_PPI_CH_MAX];
  21. static uint32_t uarteRxOneByteTimeout = 120; // 115200波特率的时候是100us左右
  22. ret_code_t uarte_asyn_init(uarte_asyn_config_t* pconfig)
  23. {
  24. ret_code_t ret;
  25. uint32_t tmr_start_tsk = 0;
  26. uint32_t tmr_clear_tsk = 0;
  27. uint32_t tmr_stop_tsk = 0;
  28. uint32_t tmr_compare_evt = 0;
  29. uarteRxOneByteTimeout = pconfig->timeout_us;
  30. // 环形接收缓冲区初始化
  31. uarte_rx_buf_init(puarteRxBuf);
  32. // timeoutTimer init
  33. nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
  34. tmr_config.frequency = NRF_TIMER_FREQ_1MHz;
  35. tmr_config.mode = TIMER_MODE_MODE_Timer;
  36. tmr_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
  37. ret = nrfx_timer_init(&timeoutTimer, &tmr_config, tmr_evt_handler);
  38. if (ret != NRFX_SUCCESS)
  39. {
  40. return NRF_ERROR_INTERNAL;
  41. }
  42. nrfx_timer_compare(&timeoutTimer, NRF_TIMER_CC_CHANNEL0, uarteRxOneByteTimeout, true);
  43. tmr_start_tsk = nrfx_timer_task_address_get(&timeoutTimer, NRF_TIMER_TASK_START);
  44. tmr_clear_tsk = nrfx_timer_task_address_get(&timeoutTimer, NRF_TIMER_TASK_CLEAR);
  45. tmr_stop_tsk = nrfx_timer_task_address_get(&timeoutTimer, NRF_TIMER_TASK_SHUTDOWN);
  46. tmr_compare_evt = nrfx_timer_compare_event_address_get(&timeoutTimer, NRF_TIMER_CC_CHANNEL0);
  47. //UART init
  48. nrf_gpio_pin_set(pconfig->tx_pin);
  49. nrf_gpio_cfg_output(pconfig->tx_pin);
  50. nrf_gpio_cfg_input(pconfig->rx_pin, pconfig->pullup_rx ?
  51. NRF_GPIO_PIN_PULLUP : NRF_GPIO_PIN_NOPULL);
  52. nrf_uarte_baudrate_set(AYSN_UARTE, pconfig->baudrate);
  53. nrf_uarte_configure(AYSN_UARTE, pconfig->parity, pconfig->hwfc);
  54. nrf_uarte_txrx_pins_set(AYSN_UARTE, pconfig->tx_pin, pconfig->rx_pin);
  55. IRQn_Type irqn = NRFX_IRQ_NUMBER_GET(AYSN_UARTE);
  56. nrf_uarte_int_enable(AYSN_UARTE, UARTE_INTERRUPTS_MASK);
  57. NVIC_SetPriority(irqn, pconfig->int_prio);
  58. NVIC_ClearPendingIRQ(irqn);
  59. NVIC_EnableIRQ(irqn);
  60. nrf_uarte_enable(AYSN_UARTE);
  61. // countTimer init
  62. nrfx_timer_config_t countTmr_config = NRFX_TIMER_DEFAULT_CONFIG;
  63. countTmr_config.mode = NRF_TIMER_MODE_COUNTER;
  64. countTmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
  65. ret = nrfx_timer_init(&countTimer, &countTmr_config, count_tmr_evt_handler);
  66. // 分配ppi channel
  67. for (int i = 0; i < UARTE_ASYNC_PPI_CH_MAX; i++)
  68. {
  69. ret = nrfx_ppi_channel_alloc(&uartePpiChannels[i]);
  70. if (ret != NRFX_SUCCESS)
  71. {
  72. //we don't free already allocated channels, system is wrongly configured.
  73. return NRF_ERROR_INTERNAL;
  74. }
  75. }
  76. // RXDRDY-->TIMER1_START&TIMER1_CLEAR
  77. // -->TIMER2_COUNT
  78. // ENDRX-->RXSTART&TIMER2_C1
  79. // TIMER1_C0-->TIMER1_STOP&TIMER2_C0
  80. PPI_CH_SETUP(uartePpiChannels[UARTE_ASYNC_PPI_CH_RXRDY_CLEAR],
  81. nrf_uarte_event_address_get(AYSN_UARTE, NRF_UARTE_EVENT_RXDRDY),
  82. tmr_start_tsk,
  83. tmr_clear_tsk);
  84. PPI_CH_SETUP(uartePpiChannels[UARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN],
  85. tmr_compare_evt,
  86. tmr_stop_tsk,
  87. nrfx_timer_task_address_get(&countTimer, NRF_TIMER_TASK_CAPTURE0));
  88. PPI_CH_SETUP(
  89. uartePpiChannels[UARTE_DRV_PPI_CH_RXRDY_TIMER_COUNT],
  90. nrf_uarte_event_address_get(AYSN_UARTE, NRF_UARTE_EVENT_RXDRDY),
  91. nrfx_timer_task_address_get(&countTimer, NRF_TIMER_TASK_COUNT),
  92. 0);
  93. PPI_CH_SETUP(
  94. uartePpiChannels[UARTE_DRV_PPI_CH_ENDRX_STARTRX],
  95. nrf_uarte_event_address_get(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX),
  96. nrf_uarte_task_address_get(AYSN_UARTE, NRF_UARTE_TASK_STARTRX),
  97. nrfx_timer_task_address_get(&countTimer, NRF_TIMER_TASK_CAPTURE1));
  98. return NRF_SUCCESS;
  99. }
  100. ret_code_t uarte_asyn_enable(void)
  101. {
  102. nrfx_timer_clear(&timeoutTimer);
  103. nrf_uarte_rx_buffer_set(AYSN_UARTE, puarteRxBuf->pwriteBuf->buf, MAX_DMA_XFER_LEN);
  104. puarteRxBuf->pwriteBuf = puarteRxBuf->pwriteBuf->pnext;
  105. /* Reset byte counting */
  106. nrfx_timer_enable(&countTimer);
  107. nrfx_timer_clear(&countTimer);
  108. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX);
  109. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_RXSTARTED);
  110. for (int i = 0; i < UARTE_ASYNC_PPI_CH_MAX; i++)
  111. {
  112. nrfx_ppi_channel_enable(uartePpiChannels[i]);
  113. }
  114. // 触发接收任务
  115. nrf_uarte_task_trigger(AYSN_UARTE, NRF_UARTE_TASK_STARTRX);
  116. return NRF_SUCCESS;
  117. }
  118. uarte_tx_result_t uarte_asyn_send(const uint8_t* buf,uint8_t len)
  119. {
  120. if(uarteTxCplt == true)
  121. {
  122. if(len > MAX_DMA_XFER_LEN)
  123. {
  124. return UARTE_TX_TOOLONG;
  125. }
  126. uarteTxCplt = false;
  127. nrf_uarte_tx_buffer_set(AYSN_UARTE, buf, len);
  128. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_TXSTARTED);
  129. nrf_uarte_task_trigger(AYSN_UARTE, NRF_UARTE_TASK_STARTTX);
  130. return UARTE_TX_SUCCESS;
  131. }
  132. else
  133. {
  134. return UARTE_TX_BUSY;
  135. }
  136. }
  137. static void uarte_timeout_handler(void)
  138. {
  139. NRFX_IRQ_DISABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(AYSN_UARTE));
  140. uint32_t rcvTotalLen = countTimer.p_reg->CC[0];
  141. if(rcvTotalLen > puarteRxBuf->bufStartCount + puarteRxBuf->readBufIndex)
  142. {
  143. uint32_t rcvAmount = rcvTotalLen - puarteRxBuf->bufStartCount - puarteRxBuf->readBufIndex;
  144. uint32_t actualPushLen = 0;
  145. gqueue_push_multiple(&qbtTx,&puarteRxBuf->preadBuf->buf[puarteRxBuf->readBufIndex],rcvAmount,&actualPushLen);
  146. puarteRxBuf->readBufIndex += rcvAmount;
  147. }
  148. NRFX_IRQ_ENABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(AYSN_UARTE));
  149. }
  150. // 设置了一个字符的超时时间。
  151. // 如果dma的数据还未到达产生endrx的长度,则过了一个字符的超时时间之后,
  152. // 可以通过此中断及时从dma的buf中获取一共收到了多少字符
  153. static void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
  154. {
  155. uarte_timeout_handler();
  156. }
  157. // 没有中断,不会发生
  158. static void count_tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
  159. {
  160. UNUSED_PARAMETER(event_type);
  161. UNUSED_PARAMETER(p_context);
  162. }
  163. static void irq_handler(void)
  164. {
  165. if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_ERROR))
  166. {
  167. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ERROR);
  168. }
  169. if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_RXSTARTED))
  170. {
  171. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_RXSTARTED);
  172. // 切换buf
  173. nrf_uarte_rx_buffer_set(AYSN_UARTE, puarteRxBuf->pwriteBuf->buf, MAX_DMA_XFER_LEN);
  174. puarteRxBuf->pwriteBuf = puarteRxBuf->pwriteBuf->pnext;
  175. }
  176. if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX))
  177. {
  178. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX);
  179. // 转存数据
  180. uint32_t rcvTotalLen = countTimer.p_reg->CC[1];
  181. if(rcvTotalLen > puarteRxBuf->bufStartCount + puarteRxBuf->readBufIndex)
  182. {
  183. uint32_t rcvAmount = rcvTotalLen - puarteRxBuf->bufStartCount - puarteRxBuf->readBufIndex;
  184. uint32_t actualPushLen = 0;
  185. gqueue_push_multiple(&qbtTx,&puarteRxBuf->preadBuf->buf[puarteRxBuf->readBufIndex],rcvAmount,&actualPushLen);
  186. }
  187. // 设置新的索引
  188. puarteRxBuf->bufStartCount = countTimer.p_reg->CC[1];
  189. puarteRxBuf->readBufIndex = 0;
  190. // 切换下一个缓冲区
  191. puarteRxBuf->preadBuf = puarteRxBuf->preadBuf->pnext;
  192. }
  193. if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_TXSTOPPED))
  194. {
  195. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_TXSTOPPED);
  196. uarteTxCplt = true;
  197. }
  198. if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_ENDTX))
  199. {
  200. // uint32_t actualLen = 0;
  201. nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ENDTX);
  202. uarteTxCplt = true;
  203. // if(!gqueue_pop_multiple_most(&qbtRx,_uarteTxBuf,MAX_DMA_XFER_LEN,&actualLen))
  204. // {
  205. // zy_uarte_asyn_send(_uarteTxBuf,actualLen);
  206. // }
  207. }
  208. }

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/194305
推荐阅读
相关标签
  

闽ICP备14008679号