串口DMA发送+中断接收的例程

描述

LPC5500的SDK中提供了非常丰富的串口例程(如下图所示):

dma

但是,偏偏没有串口DMA发送+中断接收这种组合。

实话说小编觉得这种组合才是大部分MCU场景中最常用的。尤其是对一些RX数据量不大(比如只是解析一些命令)但是TX数据量大的应用(比如定时,高频发送数据)再合适不过,该架构模型简单,非常容易理解。

本篇文章就手把手教大家分分钟撸一个DMA发送+中断接收的例程:

我们复制一个dma_transfer例程作为模板,重命名为dma_tx_int_rx(名字无所谓,自己起即可)。打开,编译下载运行一下,确保原版demo在自己的板子上可以顺利的运行,咱们把前期工作都铺垫好。

下面我们开始改代码:dma_transfer原版代码是TX和RX都是dma传输,我们只需要将RX改为中断接收数据即可。

  1. 首先将USART_TransferCreateHandleDMA函数修改下,将所有RX DMA有关的东西去掉,handler填NULL就可以。这样usart_dmadriver就不会处理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:%c ", 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发送完成回调函数。

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_DMA ";

#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%X ", 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:%c ", 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 INTERRUPT ");

  PRINTF("press 's' for DMA TX tranmsit ");

 

  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);

  while (1);

}

 

  审核编辑:汤梓红
 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分