我们在使用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)打印如下: |