6621D UART1 DMA+超时方式接收数据

yangzh · 219次点击 · 2023-11-15

我们在使用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)
{
//    wdt_keepalive();
//    pmu_dump(printf);
   
    // 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);
    log_debug("\n-3");
    if (dma_ch == NULL)
    {
        log_debug("DMA uart1-to-mem transfer fails.\r\n");
        return;
    }
    log_debug("\n-4");  
       
    dma_wait_stop(dma_ch);   //    
        log_debug_array_ex("dma have stop:",Uar_recv_Dma_Buffer, sizeof(Uar_recv_Dma_Buffer));  
}


3)main函数中调用

cmd_dma_uart_to_mem();//init dma uart


4)dma_nds.c修改如下:

void dma_wait_stop(HS_DMA_CH_Type *ch)
{
    uint32_t ch_index = DMA_CH2INDEX(ch);
    uint32_t ch_mask = 1u << ch_index;

//    while(ch->Ctrl.Enable || ch->TranSize || ch->LLPointer);

    uint32_t wait_time = 3500000;//5000000;
    while (ch->Ctrl.Enable || ch->TranSize || ch->LLPointer)
    {
        wait_time--;
        if(wait_time ==0)
          break;  
    };  
   
    HS_DMAC->IntStatus.TC    = ch_mask;
    HS_DMAC->IntStatus.Abort = ch_mask;
    HS_DMAC->IntStatus.Error = ch_mask;

    pmu_lowpower_allow(pmu_lp_dma_ch(ch_index));
}


5)打印如下:

image.png

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

请先登录网站