电子说
LPC5500
串口DMA
LPC5500的SDK中提供了非常丰富的串口例程(如下图所示):
但是,偏偏没有串口DMA发送+中断接收这种组合。
实话说小编觉得这种组合才是大部分MCU场景中最常用的。尤其是对一些RX数据量不大(比如只是解析一些命令)但是TX数据量大的应用(比如定时,高频发送数据)再合适不过,该架构模型简单,非常容易理解。
本篇文章就手把手教大家分分钟撸一个DMA发送+中断接收的例程:
我们复制一个dma_transfer例程作为模板,重命名为dma_tx_int_rx(名字无所谓,自己起即可)。打开,编译下载运行一下,确保原版demo在自己的板子上可以顺利的运行,咱们把前期工作都铺垫好。
下面我们开始改代码:dma_transfer原版代码是TX和RX都是dma传输,我们只需要将RX改为中断接收数据即可。
首先将USART_TransferCreateHandleDMA函数修改下,将所有RX DMA有关的东西去掉,handler填NULL就可以。这样usart_dma driver就不会处理RX DMA有关的操作了:
USART_TransferCreateHandleDMA(DEMO_USART, g_uartDmaHandle, USART_UserCallback, NULL, g_uartTxDmaHandle, NULL);
2. 开启usart RX中断,没啥可说的,常规操作:
/* Enable RX interrupt. */ USART_EnableInterrupts(DEMO_USART, kUSART_RxLevelInterruptEnable | kUSART_RxErrorInterruptEnable); EnableIRQ(DEMO_USART_IRQn);
3. 在app层定义(接管)串口硬件中断,并在中断中处理串口RX接收到的数据:
#define DEMO_USART_IRQHandler FLEXCOMM0_IRQHandler #define DEMO_USART_IRQn FLEXCOMM0_IRQn void DEMO_USART_IRQHandler(void) { uint8_t data; /* If new data arrived. */ if ((kUSART_RxFifoNotEmptyFlag | kUSART_RxError | kUSART_RxFifoFullFlag) USART_GetStatusFlags(DEMO_USART)) { data = USART_ReadByte(DEMO_USART); PRINTF("usart rx interrupt:%crn", data); if(data == 's') { /* Send g_tipString out. */ xfer.data = g_tipString; xfer.dataSize = sizeof(g_tipString) - 1; g_uartDmaHandle.txState = kUSART_TxIdle; USART_TransferSendDMA(DEMO_USART, g_uartDmaHandle, xfer); } } if ((0U != (DEMO_USART->INTENSET USART_INTENSET_TXIDLEEN_MASK)) (0U != (DEMO_USART->INTSTAT USART_INTSTAT_TXIDLE_MASK))) { USART_TransferDMAHandleIRQ(DEMO_USART, g_uartDmaHandle); } }
注意,这里需要在硬件串口中断里判断TXIDLE中断,并调用USART_TransferDMAHandleIRQ。这是仿照fsl_usart_dma.c中的写法(fsl_usart_dma中开启了TXIDLE中断,并使用TXIDLE中断来调用dma handle用户回调函数,现在硬件串口中断已经被app层接管,所以我们同样要实现这部分功能)。
4. 测试:改好代码,下载运行:当串口敲入任意键时候,程序都会回显接收到数据,当按键”s”时,会调用USART_TransferSendDMA函数使用DMA发送一串数据,并进入DMA发送完成回调函数。
代码清单
以下是完整代码清单(可以直接复制到usart_dma_transfer.c里运行):
/* * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright 2016-2017 NXP * All rights reserved. * * SPDX-License-Identifier: BSD-3-Clause */ #include "pin_mux.h" #include "board.h" #include "fsl_usart.h" #include "fsl_usart_dma.h" #include "fsl_dma.h" #include "fsl_debug_console.h" #include #include "fsl_power.h" #define DEMO_USART USART0 #define DEMO_USART_CLK_SRC kCLOCK_Flexcomm0 #define DEMO_USART_CLK_FREQ CLOCK_GetFlexCommClkFreq(0U) #define USART_RX_DMA_CHANNEL 4 #define USART_TX_DMA_CHANNEL 5 #define EXAMPLE_UART_DMA_BASEADDR DMA0 #define DEMO_USART_IRQHandler FLEXCOMM0_IRQHandler #define DEMO_USART_IRQn FLEXCOMM0_IRQn #define ECHO_BUFFER_LENGTH 8 usart_transfer_t xfer; usart_dma_handle_t g_uartDmaHandle; dma_handle_t g_uartTxDmaHandle; uint8_t g_tipString[] = "This string is send from UART_DMArn"; #define kUSART_TxIdle 0 void USART_UserCallback(USART_Type *base, usart_dma_handle_t *handle, status_t status, void *userData) { userData = userData; if (kStatus_USART_TxIdle == status) { PRINTF("USART_UserCallback, status:0x%Xrn", status); } } void DEMO_USART_IRQHandler(void) { uint8_t data; /* If new data arrived. */ if ((kUSART_RxFifoNotEmptyFlag | kUSART_RxError | kUSART_RxFifoFullFlag) USART_GetStatusFlags(DEMO_USART)) { data = USART_ReadByte(DEMO_USART); PRINTF("usart rx interrupt:%crn", data); if(data == 's') { /* Send g_tipString out. */ xfer.data = g_tipString; xfer.dataSize = sizeof(g_tipString) - 1; g_uartDmaHandle.txState = kUSART_TxIdle; USART_TransferSendDMA(DEMO_USART, g_uartDmaHandle, xfer); } } if ((0U != (DEMO_USART->INTENSET USART_INTENSET_TXIDLEEN_MASK)) (0U != (DEMO_USART->INTSTAT USART_INTSTAT_TXIDLE_MASK))) { USART_TransferDMAHandleIRQ(DEMO_USART, g_uartDmaHandle); } } int main(void) { usart_config_t config; /* set BOD VBAT level to 1.65V */ POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false); /* attach 12 MHz clock to FLEXCOMM0 (debug console) */ CLOCK_AttachClk(kFRO12M_to_FLEXCOMM0); BOARD_InitBootPins(); BOARD_InitBootClocks(); BOARD_InitDebugConsole(); PRINTF("USART: TX DMA, RX INTERRUPTrn"); PRINTF("press 's' for DMA TX tranmsitrn"); USART_GetDefaultConfig( config); config.baudRate_Bps = BOARD_DEBUG_UART_BAUDRATE; config.enableTx = true; config.enableRx = true; USART_Init(DEMO_USART, config, DEMO_USART_CLK_FREQ); /* Configure DMA. */ DMA_Init(EXAMPLE_UART_DMA_BASEADDR); DMA_EnableChannel(EXAMPLE_UART_DMA_BASEADDR, USART_TX_DMA_CHANNEL); DMA_EnableChannel(EXAMPLE_UART_DMA_BASEADDR, USART_RX_DMA_CHANNEL); DMA_CreateHandle( g_uartTxDmaHandle, EXAMPLE_UART_DMA_BASEADDR, USART_TX_DMA_CHANNEL); USART_TransferCreateHandleDMA(DEMO_USART, g_uartDmaHandle, USART_UserCallback, NULL, g_uartTxDmaHandle, NULL); /* Send g_tipString out. */ xfer.data = g_tipString; xfer.dataSize = sizeof(g_tipString) - 1; USART_TransferSendDMA(DEMO_USART, g_uartDmaHandle, xfer); /* Enable RX interrupt. */ USART_EnableInterrupts(DEMO_USART, kUSART_RxLevelInterruptEnable | kUSART_RxErrorInterruptEnable); EnableIRQ(DEMO_USART_IRQn);
来源:恩智浦MCU加油站
审核编辑:汤梓红
全部0条评论
快来发表一下你的评论吧 !