Jicheng 在http://blog.chinaaet.com/detail/27546 博客中给出了eDMA完成串口发送的例程,本博客结合一个实际客户需求,在其代码基础上实现使用DMA完成串口接收的功能。
功能:使用DMA将UART接收到的数据放在RAM区中(定义一个16字节的数组),数组接收满时,进入中断,在中断服务函数中将接收到的数据再打印出来。
下面只介绍需要改动的地方:
(1)将以下代码
/* 以下为使能UART的DMA功能 */
UART_C2_REG(uartch) |= UART_C2_TIE_MASK; /* 使能UART发送中断或者DMA请求 */
UART_C2_REG(uartch) &= ~UART_C2_TCIE_MASK; /* 禁止发送中断,只使能DMA请求*/
UART_C5_REG(uartch) |= UART_C5_TDMAS_MASK; /* 打开UART发送的DMA请求 */
改为:
/* 以下为使能UART的DMA接收功能 */
UART_C2_REG(uartch) |= UART_C2_RIE_MASK; /* 使能UART接收中断或者DMA请求 */
UART_C5_REG(uartch) |= UART_C5_RDMAS_MASK; /* 打开UART接收的DMA请求 */
在这里我另外将其单独写了一个函数:
void UART_ITDMAConfig(UART_MemMapPtr uartch)
{
UART_C2_REG(uartch)|= UART_C2_RIE_MASK;
UART_C5_REG(uartch)|= UART_C5_RDMAS_MASK;
}
(2) myDMA_Config()函数里将
DMA_BASE_PTR->TCD[DMA_CHn].SOFF = 0x0001; /* 每次操作完源地址,源地址增加1 */
DMA_BASE_PTR->TCD[DMA_CHn].DOFF = 0x0000; /* 每次操作完目标地址,目标地址不增加 */
改为:
DMA_BASE_PTR->TCD[DMA_CHn].SOFF = 0x0000; /* 每次操作完源地址,源地址不增加 */
DMA_BASE_PTR->TCD[DMA_CHn].DOFF = 0x0001; /* 每次操作完目标地址,目标地址增加1 */
(3) myDMA_Config()函数里将:
DMA_BASE_PTR->TCD[DMA_CHn].DLAST_SGA = 0x00; /* DMA完成一次输出之后即major_loop衰减完之后不更改目标地址 */
改为:
DMA_BASE_PTR->TCD[DMA_CHn].DLAST_SGA = 0xFFFFFFF0; /* DMA完成一次接收之后,更改目标地址,使其回到初始值,0xFFFFFFF0为16的补码*/
(4) myDMA_Config()函数里将:
DMA_BASE_PTR->TCD[DMA_CHn].CSR |= DMA_CSR_DREQ_MASK; /* major_loop递减为0时自动关闭DMA,即只进行一次DMA传输 */
改为:
DMA_BASE_PTR->TCD[DMA_CHn].CSR &= ~DMA_CSR_DREQ_MASK; /* major_loop递减为0时不关闭DMA,继续等待触发源触发 */
原来的例子只进行一次DMA传输,现在需要连续接收。
(5) myDMA_Config()函数里将:
DMA_BASE_PTR->TCD[DMA_CHn].CSR &= ~DMA_CSR_INTMAJOR_MASK; /*关闭DMA major_loop完成中断 */
改为:
DMA_BASE_PTR->TCD[DMA_CHn].CSR |= DMA_CSR_INTMAJOR_MASK; /*开启DMA major_loop完成中断 */
打开中断功能。
(6) 现在就可以写应用代码了,如下:
#define UART1_D_Addr 0x4006B007 // UART1_D 的地址
/* 接收缓冲区 */
static uint8_t UART_Buffer[16];
/* 中断服务函数 */
void DMA_ISR(void)
{
uint32_t i;
DMA_BASE_PTR->CINT = DMA_CINT_CINT(1); /* 清中断标志*/
for(i=0;i<sizeof(UART_RxBuffer);i++)
printf("%c",UART_RxBuffer[i]);
printf("\r\n");
}
void uartdma_task
(
uint32_t initial_data
)
{
(void)initial_data; /* disable 'unused variable' warning */
rs232_init(); // 串口初始化
UART_ITDMAConfig(UART1_BASE_PTR);/* 打开UART1 DMA接收功能 */
myDMA_Config2(1,DMA_UART1_R,UART1_D_Addr,(uint32)UART_RxBuffer,sizeof(UART_RxBuffer));
/* 以下四句话为MQX中中断配置 */
_bsp_int_disable(INT_DMA1);
_int_install_isr(INT_DMA1,DMA_ISR,NULL);
_bsp_int_init(INT_DMA1, 5, 0, TRUE);
_bsp_int_enable(INT_DMA1);
myDMA_Start(1); // 启动DMA
while(1)
{
}
}
注:我是在MQX中做的,在哪里实现无所谓,原理都是一样的。
最终的效果如下:
在串口调试中发送16字节数据,可以看到接收缓冲求就会收到相应的数据,同时在中断服务函数中会打印出数据。