6621E UART1 DMA+超时接收数据

yangzh · 300次点击 · 2023-11-20

我们在使用UART1的接收,实时要求高的通信,不能漏收数据,这里介绍开启DMA方式接收的示例。

1)以simple示例,在main.c文件中添加


//用于测试DMA mem2time的宏定义
#define DMA_DECLARE_LLIP(name, n) static dma_llip_t name[n]   /// Declare link list item
#define CCR_BLOCK_NUM     4                 // the ccr block num

#define DATA_COUNTS 19                  //用于统计buf_32bits_aligned中待搬移数据的个数
#define TIM         HS_TIM0             //选则定时器
#define CHANNEL     TIM_PWM_CHANNEL_0   //选择通道

/*********************************************************************
 * LOCAL VARIABLES
 */
//用于测试DMA mem2time的局部变量

/*********************************************************************
 * GLOBAL VARIABLES
 */
HS_DMA_CH_Type *dma_ch;
uint8_t Uar_recv_Dma_Buffer[BUF_SIZE];
dma_block_t block[1];


/*********************************************************

 *
 *  DMA UART
 *
**********************************************************/

void print_buf(void *buf, int length, char *title)
{
    if (title)
        log_debug("%s:\r\n", title);

    // use length == 0 as string flag.
    if (length == 0)
        log_debug("%s\r\n", (char *)buf);
    else {
        for (int i = 0; i < length; i++)
            log_debug("%02x%s", ((uint8_t *)buf)[i], (i%16 != 15) ? " " : "\r\n");
    }
    //log_debug("\r\n");
}

static void dma_print_block(dma_block_t *block)
{
    for (dma_block_t *p = block; p; p = (dma_block_t *)p->LLPointer)
        log_debug("\nblock: addr = 0x%08x, Ctrl = 0x%08x, \nSrcAddr = 0x%08x, DstAddr = 0x%08x, LLPointer = 0x%08x\r\n",
                  p, p->Ctrl, p->SrcAddr, p->DstAddr, p->LLPointer);
}

/**
 * DMA callback function of type @p dma_callback_t.
 */

static void dma_cb(dma_status_t status, uint32_t cur_src_addr, uint32_t cur_dst_addr, uint32_t xfer_size)
{
    log_debug("\r\n");
    if (status == DMA_STATUS_BLOCK_OK)
    {
        log_debug("DMA block transfer succeed, block info: ");
    }
    else if (status == DMA_STATUS_ABORT)
    {
        log_debug("DMA block transfer aborted, current info: ");
    }
    else
    {
        log_debug("DMA block transfer error, current info: ");
    }
    log_debug("status = 0x%08x, src_addr = 0x%08x, dst_addr = 0x%08x, xfer_size = %d\r\n",
              status, cur_src_addr, cur_dst_addr, xfer_size);
    //fflush(stdout);
    //log_debug_array(Uar_recv_Dma_Buffer, sizeof(Uar_recv_Dma_Buffer)); //full print
    //print_buf(Uar_recv_Dma_Buffer, 0, "Uar_recv_Dma_Buffer");
}


dma_dev_t dma_mem =
{
    .id         = MEM_DMA_ID,
    .addr       = Uar_recv_Dma_Buffer,
    .addr_ctrl  = DMA_ADDR_CTRL_INC,
    .bus_width  = DMA_SLAVE_BUSWIDTH_8BITS,
    .burst_size = DMA_BURST_LEN_1UNITS,
};
dma_dev_t dma_uart =
{
    .id         = UART1_RX_DMA_ID,
    .addr       = (void *) &HS_UART1->RBR,
    .addr_ctrl  = DMA_ADDR_CTRL_FIX,
    .bus_width  = DMA_SLAVE_BUSWIDTH_8BITS,
    .burst_size = DMA_BURST_LEN_1UNITS,
};
dma_block_config_t block_config =
{
    .src                 = &dma_uart,
    .dst                 = &dma_mem,
    //.block_size_in_bytes = 64,
    .block_size_in_bytes = BUF_SIZE,
    .priority            = 0,
    .flow_controller     = DMA_FLOW_CONTROLLER_USE_NONE,
    .intr_en             = false,
};

static void cmd_dma_uart_to_mem(void)
{
    pinmux_config(5, PINMUX_UART1_SDA_O_CFG);
    pinmux_config(6, PINMUX_UART1_SDA_I_CFG);
    uart_open(HS_UART1, 115200, UART_FLOW_CTRL_DISABLED, NULL);
   
    //(void)argc;
#if 0
    if (strcmp(argv[0], "1") != 0)
    {
        log_debug("Only uart 1 is supported by DMA.\r\n");
        return;
    }
#endif
    dma_init();
    // Allocate and init buffers
    for (int i = 0; i < BUF_SIZE; i++)
    {
        Uar_recv_Dma_Buffer[i] = 0xFF;
    }
    log_debug_array(Uar_recv_Dma_Buffer, sizeof(Uar_recv_Dma_Buffer));
    log_debug("\r\n uart1 to mem multiple block transfer test:\r\n");
    log_debug("\r\n Transfer: uart1 => Uar_recv_Dma_Buffer.\r\n");
   
    // Build blocks
//    dma_block_t block[1];
    #if 0
    /* dma_build_block_ex(&block[0], &dma_uart, &dma_mem, 1, 0, DMA_FLOW_CONTROLLER_USE_NONE, false); */
    /* dma_build_block_ex(&block[1], &dma_uart, &dma_mem, 3, 0, DMA_FLOW_CONTROLLER_USE_NONE, false); */
    /* dma_build_block_ex(&block[2], &dma_uart, &dma_mem, 5, 0, DMA_FLOW_CONTROLLER_USE_NONE, false); */
    #endif
    dma_build_block(&block[0], &block_config);
    #if 0
    //block_config.block_size_in_bytes = 64;
    // dma_build_block(&block[1], &block_config);
    // dma_mem.addr = Uar_recv_Dma_Buffer;
    // block_config.block_size_in_bytes = 5;
    // dma_build_block(&block[2], &block_config);
    // dma_append_block(block, block + 1);
    //dma_append_block(block+1, block+2);
    #endif
    //dma_print_block(block);
    // Init DMA and start transfer.
    log_debug("\n1");
    //dma_init();
    log_debug("\n2");
    /**
     * 1. DMA Software Ackknowledge must be executed before start using UART1 DMA after manual UART1 transfers,
     * because UART1 has no DMA enable/disable control, and its DMA interface is always enabled from the start.
     * So any transfer before connecting to DMA module will make the dma_tx/rx_req asserted and keeping, and a
     * dma_tx/rx_ack is required to deassert the corresponding req signal before using DMA.
     * 2. uart.dma_tx_req will always be asserted when the tx fifo is empty, so it can't and there's no need to be cleared.
     * 3. Do not use HS_UART->FCR.bit1 to clear the UART.dma_rx_req signal, cause it reset whole control portion of rx fifo.
     */
    HS_UART1->DMASA = 1;
//    HS_DMA_CH_Type *dma_ch;
        dma_ch = dma_start_transfer(NULL, block, dma_cb);
    //HS_DMA_CH_Type *dma_ch = dma_start_transfer(NULL, block, NULL);
    log_debug("\n3");
    if (dma_ch == NULL)
    {
        log_debug("DMA uart1-to-mem transfer fails.\r\n");
        return;
    }
    log_debug("\n4");
   
    #if 1
    dma_wait_stop(dma_ch);   //
    log_debug("\n5");
    //dma_release(dma_ch);      //
    // Check result by manual
    log_debug("\n6\n");
    //print_buf(Uar_recv_Dma_Buffer, 512, "Uar_recv_Dma_Buffer");
    log_debug_array_ex("dma have stop:",Uar_recv_Dma_Buffer, sizeof(Uar_recv_Dma_Buffer));
    log_debug("DMA uart1-to-mem transfer sucess.\r\n");
    #endif
       
}


2)定时器函数中调用,反复接收

static void simple_timer_handler(co_timer_t *timer, void *param)
{
        // muti dma rec start
    for (int i = 0; i < BUF_SIZE; i++)
    {
        Uar_recv_Dma_Buffer[i] = 0xFF;
    }
    dma_init();
    HS_UART1->DMASA = 1;
    dma_ch = dma_start_transfer(NULL, block, dma_cb);

    if (dma_ch == NULL)
    {
        return;
    }    
    dma_wait_stop(dma_ch);  
}


3) .course-pop { background: #fff; border: 1px solid #ddd; position: absolute; left: 25%; top: 32px; -moz-box-shadow: 0 2px 5px #ddd; -webkit-box-shadow: 0 2px 5px #d9d9d9; box-shadow: 0 2px 5px #d9d9d9; border-radius: 2px; text-align: center; line-height: 32px; width: 50%; z-index: 999; }

被收藏 0  ∙  0 赞  
加入收藏
点赞
0 回复  
善言善语 (您需要 登录 后才能回复 没有账号 ?)

请先登录网站