Nordic52810入门篇-串口UARTE外设

一、前言

Nordic52810串口外设手册命名为 UARTE,直译的意思就是带EasyDma的通用异步收发器
52810仅一路UARTE0外设,应用中如果需要多路串口进行通信的话,可以重新映射到任意的GPIO引脚上,实现异步的串口切换(无法同时进行多路收发)

二、工作原理详解

UARTE功能特点

  • 全双工
  • 硬件流控制
  • EasyDMA
  • 高达1Mpbs波特率

UARTE原理框图

如下图,RXD输入信号通过FIFO经由EasyDMA输出到RXD缓存中,输出反之EasyDMA读取TXD缓存,调制后经由TXD引脚发送

原理框图

数据发送

如下图

  • TXD.MAXCNT计数器中存放了需要发送的数据长度,使能STARTTX任务后即开始进行发送(将会生成一个TXSTARTTED指示开始发送)
  • 每发送一个字节后,会触发一个TXDRDY事件
  • 当数据发送完成后(MAXCNT)将会生成ENDTX事件
  • 使能STOPTX任务后,串口发送停止时将会触发一个TXSTOPPED事件
  • 当UARTE发送器停止时,如果尚未生成ENDTX事件,UARTE将显式生成ENDTX事件
  • 如果启用了发送流控CTS,当CTS被停用时传输将自动挂起,当CTS再次被激活时将继续传输

在这里插入图片描述

数据接收

EasyDma将串口接收的数据传到数据缓存中,如下图

  • RX缓存地址通过RXD.PTR寄存器指定
  • RX缓存大小由RXD.MAXCNT寄存器配置,当RX缓存填满后将会触发ENDRX事件
  • RXD每接收一个字节数据,将会产生RXDRDY事件
  • RXD.AMOUNT寄存器指示有多少数据已经被搬移到RAM中

在这里插入图片描述

三、寄存器

  • SHORTS [5-6]:地址偏移0x200,ENDRX_STARTRX写1开启DMA接收任务,ENDRX_STOPRX写1停止接收任务
  • INTEN [0-2/4/7-9/17/19-20/22]:中断控制寄存器,写0禁用中断,写1使能中断
  • INTENSET:中断使能寄存器,写1使能中断,写0无效
  • INTENCLR:中断禁用寄存器,写1禁止中断,写0无效
  • ERRORSRC:错误状态寄存器,当串口异常触发时,可读取该寄存器(帧错误、校验错误),写1可进行清状态
  • ENABLE:写1使能串口,写1禁用串口
  • PSEL.RTS[0-4]: RTS映射寄存器,将串口RTS信号关联到指定的引脚
  • PSEL.TXD[0-4]:TXD映射寄存器,将串口TXD信号关联到指定的引脚
  • PSEL.CTS[0-4]:CTS映射寄存器,将串口CTS信号关联到指定的引脚
  • PSEL.RXD[0-4]:RXD映射寄存器,将串口RXD信号关联到指定的引脚
  • BAUDRATE[0-31]:波特率控制寄存器(1200baud - 1Mbaud)
  • RXD.PTR:接收数据制作
  • RXD.MAXCNT:接收缓存数据大小
  • RXD.AMOUNT:接收数据长度
  • TXD.PTR:发送数据指针
  • TXD.MAXCNT:发送缓存数据大小
  • TXD.AMOUNT: 发送数据长度
  • CONFIG: 配置寄存器,配置校验与硬件流控

四、相关接口

UARTE的相关接口在nrfx_uarte.c中

串口UARTE初始化接口nrfx_uarte_init

nrfx_err_t nrfx_uarte_init(nrfx_uarte_t const *        p_instance,
                           nrfx_uarte_config_t const * p_config,
                           nrfx_uarte_event_handler_t  event_handler)
{
    NRFX_ASSERT(p_config);
    uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
    nrfx_err_t err_code = NRFX_SUCCESS;

    if (p_cb->state != NRFX_DRV_STATE_UNINITIALIZED)
    {
        err_code = NRFX_ERROR_INVALID_STATE;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

#if NRFX_CHECK(NRFX_PRS_ENABLED)
    static nrfx_irq_handler_t const irq_handlers[NRFX_UARTE_ENABLED_COUNT] = {
        #if NRFX_CHECK(NRFX_UARTE0_ENABLED)
        nrfx_uarte_0_irq_handler,
        #endif
        #if NRFX_CHECK(NRFX_UARTE1_ENABLED)
        nrfx_uarte_1_irq_handler,
        #endif
    };
    if (nrfx_prs_acquire(p_instance->p_reg,
            irq_handlers[p_instance->drv_inst_idx]) != NRFX_SUCCESS)
    {
        err_code = NRFX_ERROR_BUSY;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }
#endif // NRFX_CHECK(NRFX_PRS_ENABLED)

    apply_config(p_instance, p_config);

    p_cb->handler   = event_handler;
    p_cb->p_context = p_config->p_context;

    if (p_cb->handler)
    {
        interrupts_enable(p_instance, p_config->interrupt_priority);
    }

    nrf_uarte_enable(p_instance->p_reg);
    p_cb->rx_buffer_length           = 0;
    p_cb->rx_secondary_buffer_length = 0;
    p_cb->tx_buffer_length           = 0;
    p_cb->state                      = NRFX_DRV_STATE_INITIALIZED;
    NRFX_LOG_WARNING("Function: %s, error code: %s.",
                     __func__,
                     NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

串口UARTE发送接口nrfx_uarte_tx

nrfx_err_t nrfx_uarte_tx(nrfx_uarte_t const * p_instance,
                         uint8_t const *      p_data,
                         size_t               length)
{
    uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];
    NRFX_ASSERT(p_cb->state == NRFX_DRV_STATE_INITIALIZED);
    NRFX_ASSERT(p_data);
    NRFX_ASSERT(length > 0);
    NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length));

    nrfx_err_t err_code;

    // EasyDMA requires that transfer buffers are placed in DataRAM,
    // signal error if the are not.
    if (!nrfx_is_in_ram(p_data))
    {
        err_code = NRFX_ERROR_INVALID_ADDR;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

    if (nrfx_uarte_tx_in_progress(p_instance))
    {
        err_code = NRFX_ERROR_BUSY;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }
    p_cb->tx_buffer_length = length;
    p_cb->p_tx_buffer      = p_data;

    NRFX_LOG_INFO("Transfer tx_len: %d.", p_cb->tx_buffer_length);
    NRFX_LOG_DEBUG("Tx data:");
    NRFX_LOG_HEXDUMP_DEBUG(p_cb->p_tx_buffer,
                           p_cb->tx_buffer_length * sizeof(p_cb->p_tx_buffer[0]));

    err_code = NRFX_SUCCESS;

    nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX);
    nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED);
    nrf_uarte_tx_buffer_set(p_instance->p_reg, p_cb->p_tx_buffer, p_cb->tx_buffer_length);
    nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTTX);

    if (p_cb->handler == NULL)
    {
        bool endtx;
        bool txstopped;
        do
        {
            endtx     = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDTX);
            txstopped = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_TXSTOPPED);
        }
        while ((!endtx) && (!txstopped));

        if (txstopped)
        {
            err_code = NRFX_ERROR_FORBIDDEN;
        }
        p_cb->tx_buffer_length = 0;
    }

    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

串口UARTE接收接口nrfx_uarte_rx

nrfx_err_t nrfx_uarte_rx(nrfx_uarte_t const * p_instance,
                         uint8_t *            p_data,
                         size_t               length)
{
    uarte_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];

    NRFX_ASSERT(m_cb[p_instance->drv_inst_idx].state == NRFX_DRV_STATE_INITIALIZED);
    NRFX_ASSERT(p_data);
    NRFX_ASSERT(length > 0);
    NRFX_ASSERT(UARTE_LENGTH_VALIDATE(p_instance->drv_inst_idx, length));

    nrfx_err_t err_code;

    // EasyDMA requires that transfer buffers are placed in DataRAM,
    // signal error if the are not.
    if (!nrfx_is_in_ram(p_data))
    {
        err_code = NRFX_ERROR_INVALID_ADDR;
        NRFX_LOG_WARNING("Function: %s, error code: %s.",
                         __func__,
                         NRFX_LOG_ERROR_STRING_GET(err_code));
        return err_code;
    }

    bool second_buffer = false;

    if (p_cb->handler)
    {
        nrf_uarte_int_disable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
                                                 NRF_UARTE_INT_ENDRX_MASK);
    }
    if (p_cb->rx_buffer_length != 0)
    {
        if (p_cb->rx_secondary_buffer_length != 0)
        {
            if (p_cb->handler)
            {
                nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
                                                        NRF_UARTE_INT_ENDRX_MASK);
            }
            err_code = NRFX_ERROR_BUSY;
            NRFX_LOG_WARNING("Function: %s, error code: %s.",
                             __func__,
                             NRFX_LOG_ERROR_STRING_GET(err_code));
            return err_code;
        }
        second_buffer = true;
    }

    if (!second_buffer)
    {
        p_cb->rx_buffer_length = length;
        p_cb->p_rx_buffer      = p_data;
        p_cb->rx_secondary_buffer_length = 0;
    }
    else
    {
        p_cb->p_rx_secondary_buffer = p_data;
        p_cb->rx_secondary_buffer_length = length;
    }

    NRFX_LOG_INFO("Transfer rx_len: %d.", length);

    err_code = NRFX_SUCCESS;

    nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX);
    nrf_uarte_event_clear(p_instance->p_reg, NRF_UARTE_EVENT_RXTO);
    nrf_uarte_rx_buffer_set(p_instance->p_reg, p_data, length);
    if (!second_buffer)
    {
        nrf_uarte_task_trigger(p_instance->p_reg, NRF_UARTE_TASK_STARTRX);
    }
    else
    {
        nrf_uarte_shorts_enable(p_instance->p_reg, NRF_UARTE_SHORT_ENDRX_STARTRX);
    }

    if (m_cb[p_instance->drv_inst_idx].handler == NULL)
    {
        bool endrx;
        bool rxto;
        bool error;
        do {
            endrx  = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ENDRX);
            rxto   = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_RXTO);
            error  = nrf_uarte_event_check(p_instance->p_reg, NRF_UARTE_EVENT_ERROR);
        } while ((!endrx) && (!rxto) && (!error));

        m_cb[p_instance->drv_inst_idx].rx_buffer_length = 0;

        if (error)
        {
            err_code = NRFX_ERROR_INTERNAL;
        }

        if (rxto)
        {
            err_code = NRFX_ERROR_FORBIDDEN;
        }
    }
    else
    {
        nrf_uarte_int_enable(p_instance->p_reg, NRF_UARTE_INT_ERROR_MASK |
                                                NRF_UARTE_INT_ENDRX_MASK);
    }
    NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
}

串口UARTE事件中断接口uarte_irq_handler

static void uarte_irq_handler(NRF_UARTE_Type *        p_uarte,
                              uarte_control_block_t * p_cb)
{
    if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ERROR))
    {
        nrfx_uarte_event_t event;

        nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ERROR);

        event.type                   = NRFX_UARTE_EVT_ERROR;
        event.data.error.error_mask  = nrf_uarte_errorsrc_get_and_clear(p_uarte);
        event.data.error.rxtx.bytes  = nrf_uarte_rx_amount_get(p_uarte);
        event.data.error.rxtx.p_data = p_cb->p_rx_buffer;

        // Abort transfer.
        p_cb->rx_buffer_length = 0;
        p_cb->rx_secondary_buffer_length = 0;

        p_cb->handler(&event, p_cb->p_context);
    }
    else if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDRX))
    {
        nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDRX);
        size_t amount = nrf_uarte_rx_amount_get(p_uarte);
        // If the transfer was stopped before completion, amount of transfered bytes
        // will not be equal to the buffer length. Interrupted transfer is ignored.
        if (amount == p_cb->rx_buffer_length)
        {
            if (p_cb->rx_secondary_buffer_length)
            {
                uint8_t * p_data = p_cb->p_rx_buffer;
                nrf_uarte_shorts_disable(p_uarte, NRF_UARTE_SHORT_ENDRX_STARTRX);
                p_cb->rx_buffer_length = p_cb->rx_secondary_buffer_length;
                p_cb->p_rx_buffer = p_cb->p_rx_secondary_buffer;
                p_cb->rx_secondary_buffer_length = 0;
                rx_done_event(p_cb, amount, p_data);
            }
            else
            {
                p_cb->rx_buffer_length = 0;
                rx_done_event(p_cb, amount, p_cb->p_rx_buffer);
            }
        }
    }

    if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_RXTO))
    {
        nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_RXTO);
        if (p_cb->rx_buffer_length)
        {
            p_cb->rx_buffer_length = 0;
            rx_done_event(p_cb, nrf_uarte_rx_amount_get(p_uarte), p_cb->p_rx_buffer);
        }
    }

    if (nrf_uarte_event_check(p_uarte, NRF_UARTE_EVENT_ENDTX))
    {
        nrf_uarte_event_clear(p_uarte, NRF_UARTE_EVENT_ENDTX);
        if (p_cb->tx_buffer_length)
        {
            tx_done_event(p_cb, nrf_uarte_tx_amount_get(p_uarte));
        }
    }
}

五、实例

代码实例主要是参考app_uart的工程,添加nrfx_uarte.capp_fifoapp_uart_fifo.c,并在sdk_config.h中使能串口

#define APP_UART_ENABLED 1
/**@brief   Function for handling app_uart events.
 *
 * @details This function will receive a single character from the app_uart module and append it to
 *          a string. The string will be be sent over BLE when the last character received was a
 *          'new line' '\n' (hex 0x0A) or if the string has reached the maximum data length.
 */
/**@snippet [Handling the data received over UART] */
void uart_event_handle(app_uart_evt_t * p_event)
{
    switch (p_event->evt_type)
    {
        case APP_UART_DATA_READY://处理接收到的数据

            break;

        case APP_UART_COMMUNICATION_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_communication);
            break;

        case APP_UART_FIFO_ERROR:
            APP_ERROR_HANDLER(p_event->data.error_code);
            break;

        default:
            break;
    }
}

/**@brief  Function for initializing the UART module.
 */
/**@snippet [UART Initialization] */
static void uart_init(void)//串口初始化
{
    uint32_t                     err_code;
    app_uart_comm_params_t const comm_params =
    {
        .rx_pin_no    = RX_PIN_NUMBER,
        .tx_pin_no    = TX_PIN_NUMBER,
        .rts_pin_no   = RTS_PIN_NUMBER,
        .cts_pin_no   = CTS_PIN_NUMBER,
        .flow_control = APP_UART_FLOW_CONTROL_DISABLED,
        .use_parity   = false,
#if defined (UART_PRESENT)
        .baud_rate    = NRF_UART_BAUDRATE_115200
#else
        .baud_rate    = NRF_UARTE_BAUDRATE_115200
#endif
    };

    APP_UART_FIFO_INIT(&comm_params,
                       UART_RX_BUF_SIZE,
                       UART_TX_BUF_SIZE,
                       uart_event_handle,
                       APP_IRQ_PRIORITY_LOWEST,
                       err_code);
    APP_ERROR_CHECK(err_code);
}



int main(void)
{

    app_timer_init();
    // Initialize.

    bsp_InitLED();
    uart_init();

    ble_stack_init();

    app_timer_create(&led_timer_id,APP_TIMER_MODE_REPEATED,led_callback);
    app_timer_start(led_timer_id,APP_TIMER_TICKS(1000), NULL); //1000ms



    while(1)
    {
       app_uart_put('A');//发送单个字节数据
       nrf_delay_ms(500);
    }

}

在这里插入图片描述
官方技术手册

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章