//example_uart_dmaIrq.c
include "example.h"
/*
样例说明:
以下样例里边,用了串口0和串口1.
串口0是打印log的,就是printf的出口。只是用来检测下运行结果。
串口1是测试dma收和dma发。
使用时,需要在ve里定义串口1的两个引脚,然后PC端接串口1,来进行收发测试。
*/
//
//这里的实现方式是:dma发送 + dma-tc中断。
//这种方式可以用于不太精确的发送完成定位。
//
//因为从细节来说,dma发送完,并不是真正的“tx线上的波形”发送完。
//发送一个字节的流程是:【开始】dma把一个数据搬到uart fifo -> 串口模块从fifo取到数据开始产生tx波形 -> 全部波形发送完毕【结束】
//对于 DMA-TXTC中断来说,第一步结束就产生中断了。而真正的数据发送完是到第三步结束。
//所以,如果是一般使用,不介意最后一个字节的时间的,这个中断是可以使用的。
//
//但如果是用于485传输,需要精确定位到“彻底发送完的那个点”产生中断,那么以上方式是不行的。需要使用uart-tc中断来替换dma-tc中断。
//即,实现方式为:dmaTx + uartTC中断
//在dma的连续发送中,是不会产生的 uartTC中断的,直到全部发送完,才产生该中断。
//
volatile int txIqrFlag = 0, rxIqrFlag = 0;
void DMAC0_INTTC_isr(void)
{
if (DMAC_IsChannelRawIntErrorActive(DMAC_CHANNEL0))
{
//error code
DMAC_ClearChannelIntError(DMAC_CHANNEL0);
}
else if (DMAC_IsChannelRawIntTCActive(DMAC_CHANNEL0))
{
//clear flag
DMAC_ClearChannelIntTC(DMAC_CHANNEL0);
// to do...
txIqrFlag = 1;
}
else if (DMAC_IsChannelRawIntTCActive(DMAC_CHANNEL1))
{
//clear flag
DMAC_ClearChannelIntTC(DMAC_CHANNEL1);
// to do...
rxIqrFlag = 1;
}
}
void TestUartDMAIqr(void)
{
GPIO_AF_ENABLE(UART1_UARTRXD)
GPIO_AF_ENABLE(UART1_UARTTXD);
SYS_EnableAPBClock(APB_MASK_UART1);
//tx buff
const char txbuf[] = "This quick brown fox jumps over the lazy dog!\n";
const volatile uint32_t txLen = sizeof(txbuf) - 1; // Strip the ending '0'
//rx buff
char rxbuf[256] = {0};
int rxLen = 30;
SYS_EnableAHBClock(AHB_MASK_DMAC0);
DMAC_Init();
UART_Init(UART1, 115200, UART_LCR_DATABITS_8, UART_LCR_STOPBITS_1, UART_LCR_PARITY_NONE, UART_LCR_FIFO_16);
UART_SetDmaMode(UART1, UART_DMA_RX_TX);
uint8_t tx_dma_req = UART1_TX_DMA_REQ;
uint8_t rx_dma_req = UART1_RX_DMA_REQ;
//set tx dma
DMAC_Config(DMAC_CHANNEL0, (uint32_t)txbuf, (uint32_t)&UART1->DR,
DMAC_ADDR_INCR_ON, DMAC_ADDR_INCR_OFF,
DMAC_WIDTH_8_BIT, DMAC_WIDTH_8_BIT,
DMAC_BURST_1, DMAC_BURST_1,
txLen, DMAC_MEM_TO_PERIPHERAL_DMA_CTRL,
0, tx_dma_req);
//set rx dma
DMAC_Config(DMAC_CHANNEL1, (uint32_t)&UART1->DR, (uint32_t)rxbuf,
DMAC_ADDR_INCR_OFF, DMAC_ADDR_INCR_ON,
DMAC_WIDTH_8_BIT, DMAC_WIDTH_8_BIT,
DMAC_BURST_1, DMAC_BURST_1,
rxLen, DMAC_PERIPHERAL_TO_MEM_DMA_CTRL, rx_dma_req, 0);
//enable interrupt
INT_EnableIRQ(DMAC0_INTTC_IRQn, PLIC_MAX_PRIORITY);
//test
while(1)
{
UTIL_IdleUs(100e3);
if (rxIqrFlag == 1)
{
rxIqrFlag = 0;
printf("rx:%s\r\n", rxbuf);
//set dma for NEXT receive.
memset(rxbuf, sizeof(rxbuf), 0);
DMAC_Config(DMAC_CHANNEL1, (uint32_t)&UART1->DR, (uint32_t)rxbuf,
DMAC_ADDR_INCR_OFF, DMAC_ADDR_INCR_ON,
DMAC_WIDTH_8_BIT, DMAC_WIDTH_8_BIT,
DMAC_BURST_1, DMAC_BURST_1,
rxLen, DMAC_PERIPHERAL_TO_MEM_DMA_CTRL, rx_dma_req, 0);
}
if (txIqrFlag == 1)
{
txIqrFlag = 0;
printf("tx over\r\n");
}
}
}