HC32F460 DMA TX RX
前言
利用DMA 进行串口读写,主要内容包括:
DMA 通道 *2
串口发送空中断,发送完成中断
串口接收中断,接收超时中断
定时器 (串口接收超时定时器 )
发送/接收功能 比较
功能 | 触发 | DMA传输次数 | DMA中断 | 结束标志 |
---|---|---|---|---|
TX | TI中断 | 适应接收字节个数 | DMA传输完成中断 | 发送完成标志中断 |
RX | RI中断 | 无数次 | DMA块完成中断 | 接收超时中断 |
接收超时定时器通道选择
默认关系,无法任意选择通道,根据实际使用的串口确认定时器通道
TIMEOUT 计数器采用Timer0 模块的计数器,具体对应关系如下:
USART1:Timer0 Unit1 A 通道
USART2:Timer0 Unit1 B 通道
USART3:Timer0 Unit2 A 通道
USART4:Timer0 Unit2 B 通道
串口初始化
/**
*******************************************************************************
** \brief Usart_init function of project
**
** \param None
**
** \retval void
**
******************************************************************************/
void Usart_init(void)
{
en_result_t enRet = Ok;
stc_irq_regi_conf_t stcIrqRegiCfg;
stc_port_init_t stc_485_RE_PortInit,stc_485_TX_PortInit;
uint32_t u32Fcg1Periph = PWC_FCG1_PERIPH_USART1 | PWC_FCG1_PERIPH_USART2 | \
PWC_FCG1_PERIPH_USART3 | PWC_FCG1_PERIPH_USART4;
const stc_usart_uart_init_t stcInitCfg = {
UsartIntClkCkNoOutput,//时钟源可选:内部时钟源(内部波特率生成器生成的时钟)/外部时钟源( CKn管脚输入的时钟)
UsartClkDiv_1,
UsartDataBits8,//数据长度可编程:8位/9位
UsartDataLsbFirst,
UsartOneStopBit,//停止位可配置:1 位/2位
UsartParityNone,//校验功能可配置:奇校验/偶校验/无校验
UsartSampleBit8,
UsartStartBitFallEdge,
UsartRtsEnable,
};
/* Initialize Timer0 */
Timer0Init();
/* Initialize DMA */
DmaInit();
DmaInit_Tx();
/* Enable peripheral clock */
PWC_Fcg1PeriphClockCmd(u32Fcg1Periph, Enable);
/* Initialize USART IO */
PORT_SetFunc(USART_RX_PORT, USART_RX_PIN, USART_RX_FUNC, Disable);
MEM_ZERO_STRUCT(stc_485_TX_PortInit);
stc_485_TX_PortInit.enPullUp=Enable;
PORT_Init(USART_TX_PORT,USART_TX_PIN,&stc_485_TX_PortInit);
PORT_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_FUNC, Disable);
/* configuration RS485_RE structure initialization */
MEM_ZERO_STRUCT(stc_485_RE_PortInit);
stc_485_RE_PortInit.enPinMode = Pin_Mode_Out;
PORT_Init(USART_RE_PORT, USART_RE_PIN, &stc_485_RE_PortInit);
PORT_ResetBits(USART_RE_PORT, USART_RE_PIN);
/* Initialize UART */
enRet = USART_UART_Init(USART_CH, &stcInitCfg);
if (enRet != Ok)
{
while (1)
{
}
}
/* Set baudrate */
enRet = USART_SetBaudrate(USART_CH, USART_BAUDRATE);
if (enRet != Ok)
{
while (1)
{
}
}
/* Set USART RX IRQ */
stcIrqRegiCfg.enIRQn = USART_RI_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartRxIrqCallback;
stcIrqRegiCfg.enIntSrc = USART_RI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART RX error IRQ */
stcIrqRegiCfg.enIRQn = USART_EI_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartErrIrqCallback;
stcIrqRegiCfg.enIntSrc = USART_EI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART RX timeout error IRQ */
stcIrqRegiCfg.enIRQn = USART_RTO_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartTimeoutIrqCallback;
stcIrqRegiCfg.enIntSrc = USART_RTO_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART TX IRQ */
stcIrqRegiCfg.enIRQn = USART_TI_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartTxIrqCallback;
stcIrqRegiCfg.enIntSrc = USART_TI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/* Set USART TX complete IRQ */
stcIrqRegiCfg.enIRQn = USART_TCI_IRQn;
stcIrqRegiCfg.pfnCallback = &UsartTxCmpltIrqCallback;
stcIrqRegiCfg.enIntSrc = USART_TCI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/*Enable RX && RX interupt && timeout interrupt function*/
USART_FuncCmd(USART_CH, UsartNoiseFilter,Enable);
USART_FuncCmd(USART_CH, UsartRx, Enable);
USART_FuncCmd(USART_CH, UsartRxInt, Enable);
USART_FuncCmd(USART_CH, UsartTimeOut, Enable);
USART_FuncCmd(USART_CH, UsartTimeOutInt, Enable);
/*Enable TX && RX && RX interrupt function*/
}
DMA初始化
static void DmaInit(void)
{
stc_dma_config_t stcDmaInit;
stc_irq_regi_conf_t stcIrqRegiCfg;
/* Enable peripheral clock */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA1 | PWC_FCG0_PERIPH_DMA2,Enable);
/* Enable DMA. */
DMA_Cmd(DMA_UNIT,Enable);
/* Initialize DMA. */
MEM_ZERO_STRUCT(stcDmaInit);
stcDmaInit.u16BlockSize = 1u; /* 1 block */
stcDmaInit.u32SrcAddr = ((uint32_t)(&USART_CH->DR)+2ul); /* Set source address. */
stcDmaInit.u32DesAddr = (uint32_t)(&m_stcRingBuf.au8Buf); /* Set destination address. */
stcDmaInit.stcDmaChCfg.enSrcInc = AddressFix; /* Set source address mode. */
stcDmaInit.stcDmaChCfg.enDesInc = AddressIncrease; /* Set destination address mode. */
stcDmaInit.stcDmaChCfg.enIntEn = Enable; /* Enable interrupt. */
stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit; /* Set data width 8bit. */
stcDmaInit.u16DesRptSize=m_stcRingBuf.u16Capacity;
/* Disable linked list transfer. */
stcDmaInit.stcDmaChCfg.enLlpEn = Disable;
/* Enable repeat function. */
stcDmaInit.stcDmaChCfg.enDesRptEn = Enable;
DMA_InitChannel(DMA_UNIT, DMA_CH, &stcDmaInit);
/* Enable the specified DMA channel. */
DMA_ChannelCmd(DMA_UNIT, DMA_CH, Enable);
/* Clear DMA flag. */
DMA_ClearIrqFlag(DMA_UNIT, DMA_CH, TrnCpltIrq);
/* Enable peripheral circuit trigger function. */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS,Enable);
/* Set DMA trigger source. */
DMA_SetTriggerSrc(DMA_UNIT, DMA_CH, DMA_TRG_SEL);
/* Set DMA block transfer complete IRQ */
stcIrqRegiCfg.enIRQn = DMA_BTC_INT_IRQn;
stcIrqRegiCfg.pfnCallback = &DmaBtcIrqCallback;
stcIrqRegiCfg.enIntSrc = DMA_BTC_INT_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
}
static void DmaInit_Tx(void)
{
stc_dma_config_t stcDmaInit;
stc_irq_regi_conf_t stcIrqRegiCfg;
/* Enable peripheral clock */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA1 | PWC_FCG0_PERIPH_DMA2,Enable);
/* Enable DMA. */
DMA_Cmd(DMA_UNIT_TX,Enable);
/* Initialize DMA. */
MEM_ZERO_STRUCT(stcDmaInit);
stcDmaInit.u16BlockSize = 1u; /* 1 block */
stcDmaInit.u32SrcAddr = (uint32_t)(&m_stcTingBuf.au8Buf); /* Set source address. */
stcDmaInit.u32DesAddr = ((uint32_t)(&USART_CH->DR)); /* Set destination address. */ //TDR
stcDmaInit.stcDmaChCfg.enSrcInc = AddressIncrease; /* Set source address mode. */
stcDmaInit.stcDmaChCfg.enDesInc = AddressFix; /* Set destination address mode. */
stcDmaInit.stcDmaChCfg.enIntEn = Enable; /* Enable interrupt. */
stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit; /* Set data width 8bit. */
stcDmaInit.u16TransferCnt=11;//根据长度
DMA_InitChannel(DMA_UNIT_TX, DMA_CH_TX, &stcDmaInit);
/* Enable the specified DMA channel. */
DMA_ChannelCmd(DMA_UNIT_TX, DMA_CH_TX, Enable);
/* Clear DMA flag. */
DMA_ClearIrqFlag(DMA_UNIT_TX, DMA_CH_TX, TrnCpltIrq);
/* Enable peripheral circuit trigger function. */
PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS,Enable);
/* Set DMA trigger source. */
DMA_SetTriggerSrc(DMA_UNIT_TX, DMA_CH_TX, DMA_TRG_SEL_TX);
/* Set DMA transfer complete IRQ */
stcIrqRegiCfg.enIRQn = DMA_BTC_INT_IRQn_TX;
stcIrqRegiCfg.pfnCallback = &DmaTcIrqCallback_TX;
stcIrqRegiCfg.enIntSrc = DMA_BTC_INT_NUM_TX;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
}
定时器初始化
/**
*******************************************************************************
** \brief Initliaze Timer0.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void Timer0Init(void)
{
stc_clk_freq_t stcClkTmp;
stc_tim0_base_init_t stcTimerCfg;
stc_tim0_trigger_init_t StcTimer0TrigInit;
MEM_ZERO_STRUCT(stcClkTmp);
MEM_ZERO_STRUCT(stcTimerCfg);
MEM_ZERO_STRUCT(StcTimer0TrigInit);
/* Timer0 peripheral enable */
PWC_Fcg2PeriphClockCmd(TMR_FCG_PERIPH, Enable);
CLK_LrcCmd(Enable);
/* Clear CNTAR register for channel B */
// TIMER0_WriteCntReg(TMR_UNIT, Tim0_ChannelA, 0u);
TIMER0_WriteCntReg(TMR_UNIT, Tim0_ChannelB, 0u);
/* Config register for channel B */
stcTimerCfg.Tim0_CounterMode = Tim0_Async;
stcTimerCfg.Tim0_AsyncClockSource = Tim0_LRC;
stcTimerCfg.Tim0_ClockDivision = Tim0_ClkDiv8;//32/8 =4K 0.25ms
stcTimerCfg.Tim0_CmpValue = 2;//0.25*2=0.5ms 3.5个字节
TIMER0_BaseInit(TMR_UNIT, Tim0_ChannelB, &stcTimerCfg);
/* Clear compare flag */
TIMER0_ClearFlag(TMR_UNIT, Tim0_ChannelB);
/* Config timer0 hardware trigger */
StcTimer0TrigInit.Tim0_InTrigEnable = false;
StcTimer0TrigInit.Tim0_InTrigClear = true;
StcTimer0TrigInit.Tim0_InTrigStart = true;
StcTimer0TrigInit.Tim0_InTrigStop = false;
TIMER0_HardTriggerInit(TMR_UNIT, Tim0_ChannelB, &StcTimer0TrigInit);
}
串口DMA 发送
en_result_t UART_Transmit_DMA(M4_USART_TypeDef *huart, uint8_t *pData, uint16_t Size)
{
if(DMA_TxComplete==0)
{
if ((pData == NULL) || (Size == 0U))
{
return Error;
}
DMA_TxComplete=1;
DMA_SetSrcAddress (DMA_UNIT_TX,DMA_CH_TX,(uint32_t)pData);
DMA_SetTransferCnt(DMA_UNIT_TX,DMA_CH_TX, Size);
PORT_SetBits(USART_RE_PORT, USART_RE_PIN);
while( PORT_GetBit(USART_RE_PORT, USART_RE_PIN)!=1){}
DMA_ChannelCmd(DMA_UNIT_TX, DMA_CH_TX, Enable);
USART_FuncCmd(huart, UsartTxAndTxEmptyInt, Enable);
return Ok;
}
else
{
return ErrorNotReady;
}
}
DMA_TX发送流程图
发送相关中断
/**
*******************************************************************************
** \brief DMA block transfer complete irq callback function.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void DmaTcIrqCallback_TX(void)
{
DMA_ClearIrqFlag(DMA_UNIT_TX, DMA_CH_TX, TrnCpltIrq);
DMA_ChannelCmd(DMA_UNIT_TX, DMA_CH_TX, Disable);
USART_FuncCmd(USART_CH, UsartTxEmptyInt, Disable);
USART_FuncCmd(USART_CH, UsartTxCmpltInt, Enable);
}
/**
*******************************************************************************
** \brief USART TX complete irq callback function.
**
** \param [in] None
**
** \retval None
**
******************************************************************************/
static void UsartTxCmpltIrqCallback(void)
{
USART_FuncCmd(USART_CH, UsartTx, Disable);
USART_FuncCmd(USART_CH, UsartTxCmpltInt, Disable);
PORT_ResetBits(USART_RE_PORT, USART_RE_PIN);
while( PORT_GetBit(USART_RE_PORT, USART_RE_PIN)!=0){}
DMA_TxComplete=0;
}
static void UsartTxIrqCallback(void)
{
// uint8_t u8Data = 0u;
// if (Ok == RingBufRead(&m_stcRingBuf, &u8Data))
// {
// PORT_SetBits(USART_RE_PORT, USART_RE_PIN);
// USART_SendData(USART_CH, (uint16_t)u8Data);
USART_SendData(USART_CH, 0x55);
// }
// if (IS_RING_BUFFER_EMPTY(&m_stcRingBuf))
// {
// USART_FuncCmd(USART_CH, UsartTxEmptyInt, Disable);
// USART_FuncCmd(USART_CH, UsartTxCmpltInt, Enable);
// }
}
串口DMA 接收
DMA_RX 流程图
接收相关中断
static void DmaBtcIrqCallback(void)
{
DMA_ClearIrqFlag(DMA_UNIT, DMA_CH, BlkTrnCpltIrq);
RingBufWrite_DMA(&m_stcRingBuf);
}
static void UsartTimeoutIrqCallback(void)//
{
TIMER0_Cmd(TMR_UNIT, Tim0_ChannelB,Disable);
USART_ClearStatus(USART_CH, UsartRxTimeOut);
// DMA_SetDesAddress(DMA_UNIT, DMA_CH, (uint32_t)(&m_stcRingBuf.au8Buf));// Reset DesAddress
DMA_RxComplete=1;
}