赞
踩
问题:
在使用NRF52832做串口透传的时候,示例程序里UARTE,接收长度为1个字节。如果串口接收到长数据(测试了1K),则很容易导致蓝牙发送的超时重启。
解决方案:使用PPI功能,使串口具备接收不定长数据的能力。
方案参考的是Nordic的libuarte工程,但是我们这里面有soft device,其本身会占用一些外设,比如RTC0,TIMER0等。那我们就只能选择其他外设,这里选用TIMER1和TIMER2。
PPI的配置之后的接收流程如下:
核心代码如下:
- #define AYSN_UARTE NRF_UARTE0 // 使用uarte0
- #define PPI_CH_SETUP(_ch, _evt, _tsk, _fork) \
- ret = nrfx_ppi_channel_assign(_ch, _evt, _tsk); \
- if (ret != NRF_SUCCESS) \
- { \
- return NRF_ERROR_INTERNAL; \
- } \
- if (_fork) \
- { \
- ret = nrfx_ppi_channel_fork_assign(_ch, _fork); \
- if (ret != NRF_SUCCESS) \
- { \
- return NRF_ERROR_INTERNAL; \
- } \
- }
-
- extern gqueue_t qbtTx,qbtRx;
- // 使用uarte0,超时使用timer1,计数使用timer2
- static const nrfx_timer_t timeoutTimer = NRFX_TIMER_INSTANCE(1);
- static const nrfx_timer_t countTimer = NRFX_TIMER_INSTANCE(2);
- static nrf_ppi_channel_t uartePpiChannels[UARTE_ASYNC_PPI_CH_MAX];
- static uint32_t uarteRxOneByteTimeout = 120; // 115200波特率的时候是100us左右
-
- ret_code_t uarte_asyn_init(uarte_asyn_config_t* pconfig)
- {
- ret_code_t ret;
- uint32_t tmr_start_tsk = 0;
- uint32_t tmr_clear_tsk = 0;
- uint32_t tmr_stop_tsk = 0;
- uint32_t tmr_compare_evt = 0;
- uarteRxOneByteTimeout = pconfig->timeout_us;
-
- // 环形接收缓冲区初始化
- uarte_rx_buf_init(puarteRxBuf);
-
- // timeoutTimer init
- nrfx_timer_config_t tmr_config = NRFX_TIMER_DEFAULT_CONFIG;
- tmr_config.frequency = NRF_TIMER_FREQ_1MHz;
- tmr_config.mode = TIMER_MODE_MODE_Timer;
- tmr_config.interrupt_priority = APP_IRQ_PRIORITY_LOW;
-
- ret = nrfx_timer_init(&timeoutTimer, &tmr_config, tmr_evt_handler);
- if (ret != NRFX_SUCCESS)
- {
- return NRF_ERROR_INTERNAL;
- }
- nrfx_timer_compare(&timeoutTimer, NRF_TIMER_CC_CHANNEL0, uarteRxOneByteTimeout, true);
-
- tmr_start_tsk = nrfx_timer_task_address_get(&timeoutTimer, NRF_TIMER_TASK_START);
- tmr_clear_tsk = nrfx_timer_task_address_get(&timeoutTimer, NRF_TIMER_TASK_CLEAR);
- tmr_stop_tsk = nrfx_timer_task_address_get(&timeoutTimer, NRF_TIMER_TASK_SHUTDOWN);
- tmr_compare_evt = nrfx_timer_compare_event_address_get(&timeoutTimer, NRF_TIMER_CC_CHANNEL0);
-
-
- //UART init
- nrf_gpio_pin_set(pconfig->tx_pin);
- nrf_gpio_cfg_output(pconfig->tx_pin);
- nrf_gpio_cfg_input(pconfig->rx_pin, pconfig->pullup_rx ?
- NRF_GPIO_PIN_PULLUP : NRF_GPIO_PIN_NOPULL);
- nrf_uarte_baudrate_set(AYSN_UARTE, pconfig->baudrate);
- nrf_uarte_configure(AYSN_UARTE, pconfig->parity, pconfig->hwfc);
- nrf_uarte_txrx_pins_set(AYSN_UARTE, pconfig->tx_pin, pconfig->rx_pin);
-
- IRQn_Type irqn = NRFX_IRQ_NUMBER_GET(AYSN_UARTE);
- nrf_uarte_int_enable(AYSN_UARTE, UARTE_INTERRUPTS_MASK);
- NVIC_SetPriority(irqn, pconfig->int_prio);
- NVIC_ClearPendingIRQ(irqn);
- NVIC_EnableIRQ(irqn);
-
- nrf_uarte_enable(AYSN_UARTE);
-
- // countTimer init
- nrfx_timer_config_t countTmr_config = NRFX_TIMER_DEFAULT_CONFIG;
- countTmr_config.mode = NRF_TIMER_MODE_COUNTER;
- countTmr_config.bit_width = NRF_TIMER_BIT_WIDTH_32;
- ret = nrfx_timer_init(&countTimer, &countTmr_config, count_tmr_evt_handler);
-
- // 分配ppi channel
- for (int i = 0; i < UARTE_ASYNC_PPI_CH_MAX; i++)
- {
- ret = nrfx_ppi_channel_alloc(&uartePpiChannels[i]);
- if (ret != NRFX_SUCCESS)
- {
- //we don't free already allocated channels, system is wrongly configured.
- return NRF_ERROR_INTERNAL;
- }
- }
-
- // RXDRDY-->TIMER1_START&TIMER1_CLEAR
- // -->TIMER2_COUNT
- // ENDRX-->RXSTART&TIMER2_C1
- // TIMER1_C0-->TIMER1_STOP&TIMER2_C0
- PPI_CH_SETUP(uartePpiChannels[UARTE_ASYNC_PPI_CH_RXRDY_CLEAR],
- nrf_uarte_event_address_get(AYSN_UARTE, NRF_UARTE_EVENT_RXDRDY),
- tmr_start_tsk,
- tmr_clear_tsk);
-
- PPI_CH_SETUP(uartePpiChannels[UARTE_ASYNC_PPI_CH_COMPARE_SHUTDOWN],
- tmr_compare_evt,
- tmr_stop_tsk,
- nrfx_timer_task_address_get(&countTimer, NRF_TIMER_TASK_CAPTURE0));
-
- PPI_CH_SETUP(
- uartePpiChannels[UARTE_DRV_PPI_CH_RXRDY_TIMER_COUNT],
- nrf_uarte_event_address_get(AYSN_UARTE, NRF_UARTE_EVENT_RXDRDY),
- nrfx_timer_task_address_get(&countTimer, NRF_TIMER_TASK_COUNT),
- 0);
-
-
- PPI_CH_SETUP(
- uartePpiChannels[UARTE_DRV_PPI_CH_ENDRX_STARTRX],
- nrf_uarte_event_address_get(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX),
- nrf_uarte_task_address_get(AYSN_UARTE, NRF_UARTE_TASK_STARTRX),
- nrfx_timer_task_address_get(&countTimer, NRF_TIMER_TASK_CAPTURE1));
-
- return NRF_SUCCESS;
- }
-
-
- ret_code_t uarte_asyn_enable(void)
- {
- nrfx_timer_clear(&timeoutTimer);
- nrf_uarte_rx_buffer_set(AYSN_UARTE, puarteRxBuf->pwriteBuf->buf, MAX_DMA_XFER_LEN);
- puarteRxBuf->pwriteBuf = puarteRxBuf->pwriteBuf->pnext;
-
- /* Reset byte counting */
- nrfx_timer_enable(&countTimer);
- nrfx_timer_clear(&countTimer);
-
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX);
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_RXSTARTED);
-
- for (int i = 0; i < UARTE_ASYNC_PPI_CH_MAX; i++)
- {
- nrfx_ppi_channel_enable(uartePpiChannels[i]);
- }
-
- // 触发接收任务
- nrf_uarte_task_trigger(AYSN_UARTE, NRF_UARTE_TASK_STARTRX);
-
- return NRF_SUCCESS;
- }
-
- uarte_tx_result_t uarte_asyn_send(const uint8_t* buf,uint8_t len)
- {
- if(uarteTxCplt == true)
- {
- if(len > MAX_DMA_XFER_LEN)
- {
- return UARTE_TX_TOOLONG;
- }
- uarteTxCplt = false;
- nrf_uarte_tx_buffer_set(AYSN_UARTE, buf, len);
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_TXSTARTED);
- nrf_uarte_task_trigger(AYSN_UARTE, NRF_UARTE_TASK_STARTTX);
- return UARTE_TX_SUCCESS;
- }
- else
- {
- return UARTE_TX_BUSY;
- }
- }
-
-
- static void uarte_timeout_handler(void)
- {
- NRFX_IRQ_DISABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(AYSN_UARTE));
- uint32_t rcvTotalLen = countTimer.p_reg->CC[0];
- if(rcvTotalLen > puarteRxBuf->bufStartCount + puarteRxBuf->readBufIndex)
- {
- uint32_t rcvAmount = rcvTotalLen - puarteRxBuf->bufStartCount - puarteRxBuf->readBufIndex;
- uint32_t actualPushLen = 0;
- gqueue_push_multiple(&qbtTx,&puarteRxBuf->preadBuf->buf[puarteRxBuf->readBufIndex],rcvAmount,&actualPushLen);
- puarteRxBuf->readBufIndex += rcvAmount;
- }
- NRFX_IRQ_ENABLE((IRQn_Type)NRFX_IRQ_NUMBER_GET(AYSN_UARTE));
- }
-
- // 设置了一个字符的超时时间。
- // 如果dma的数据还未到达产生endrx的长度,则过了一个字符的超时时间之后,
- // 可以通过此中断及时从dma的buf中获取一共收到了多少字符
- static void tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
- {
- uarte_timeout_handler();
- }
-
- // 没有中断,不会发生
- static void count_tmr_evt_handler(nrf_timer_event_t event_type, void * p_context)
- {
- UNUSED_PARAMETER(event_type);
- UNUSED_PARAMETER(p_context);
- }
-
- static void irq_handler(void)
- {
- if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_ERROR))
- {
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ERROR);
-
- }
-
- if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_RXSTARTED))
- {
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_RXSTARTED);
- // 切换buf
- nrf_uarte_rx_buffer_set(AYSN_UARTE, puarteRxBuf->pwriteBuf->buf, MAX_DMA_XFER_LEN);
- puarteRxBuf->pwriteBuf = puarteRxBuf->pwriteBuf->pnext;
-
- }
-
- if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX))
- {
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ENDRX);
- // 转存数据
- uint32_t rcvTotalLen = countTimer.p_reg->CC[1];
- if(rcvTotalLen > puarteRxBuf->bufStartCount + puarteRxBuf->readBufIndex)
- {
- uint32_t rcvAmount = rcvTotalLen - puarteRxBuf->bufStartCount - puarteRxBuf->readBufIndex;
- uint32_t actualPushLen = 0;
- gqueue_push_multiple(&qbtTx,&puarteRxBuf->preadBuf->buf[puarteRxBuf->readBufIndex],rcvAmount,&actualPushLen);
- }
- // 设置新的索引
- puarteRxBuf->bufStartCount = countTimer.p_reg->CC[1];
- puarteRxBuf->readBufIndex = 0;
- // 切换下一个缓冲区
- puarteRxBuf->preadBuf = puarteRxBuf->preadBuf->pnext;
- }
-
- if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_TXSTOPPED))
- {
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_TXSTOPPED);
- uarteTxCplt = true;
-
- }
-
- if (nrf_uarte_event_check(AYSN_UARTE, NRF_UARTE_EVENT_ENDTX))
- {
- // uint32_t actualLen = 0;
- nrf_uarte_event_clear(AYSN_UARTE, NRF_UARTE_EVENT_ENDTX);
- uarteTxCplt = true;
- // if(!gqueue_pop_multiple_most(&qbtRx,_uarteTxBuf,MAX_DMA_XFER_LEN,&actualLen))
- // {
- // zy_uarte_asyn_send(_uarteTxBuf,actualLen);
- // }
-
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。