1.使用芯片:STM32F103RCT6
2.使用串口:UART4
3.想实现的功能:UART4使用DMA发送和接收。
4.存在的问题:不使能UART4的DMA发送功能时,DMA可以接收到数据,但是一旦使能UART4的DMA发送,DMA就接收不到数据。
5.代码
(1)UART4配置及中断代码:
void uart_init(u32 baud)
{
float temp;
u16 mantissa;
u16 fraction;
temp=(float)(36*1000000)/(baud*16);//得到USARTDIV pclk1 = 36MHz
mantissa=temp; //得到整数部分
fraction=(temp-mantissa)*16; //得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB1ENR |= 1<<19; // 使能USART4串口时钟
RCC->APB1RSTR |= 1<<19; // 复位USART4
RCC->APB1RSTR &= ~(1<<19); // 停止复位
//波特率设置
UART4->BRR = mantissa; // 波特率设置
UART4->CR1 |= 0X200C; //1位停止,无校验位.
UART4->CR3 = 1<< 6; // DMAR = 1, 使能UART4的DMA接收
// 只要置位DMAT(使能DMA发送),就不能接收???????????????????????????
UART4->CR3 = 1<< 7; // DMAT = 1, 使能UART4的DMA发送
// 只要开启DMA发送使能,就不能接收,奇怪
// ?????????????????????????????????????????
//使能空闲中断
UART4->CR1 |= 1<<4; // IDLEIE = 1, IDLE interrupt enable
MY_NVIC_Init(3,2,UART4_IRQn,2); //抢占3,子优先级3,组2
}
void UART4_IRQHandler(void)
{
u8 tempByte;
u16 tempWord;
// IDLE line detected
if(UART4->SR & (1<<4))
{
DMA2_Channel3->CCR &= ~(1<<0); // 关闭DMA2的通道3
// 清除IDLE标志位方式:先读USART_SR,然后读USART_DR
tempByte = UART4->SR;
tempByte = UART4->DR;
UART4->SR &= ~(1<<4);
uart4RxRevLen = UART4_RX_BUF_LEN - DMA2_Channel3->CNDTR; // 读取接收到的字节数
DMA2_Channel3->CNDTR = UART4_RX_BUF_LEN; // 重置字节数
DMA2_Channel3->CCR |= 1<<0; // 打开DMA2的通道3
}
}
(2)DMA配置及收发代码
void InitDma(void)
{
// ******************************** DMA2 Channel3 - UART4_RX ***************************************
// UART4使用DMA2的通道3作为发送通道
RCC->AHBENR |= 1<<1; // 开启DMA2时钟
delay_ms(5); // 等待DMA时钟稳定
DMA2_Channel3->CPAR = (u32)&UART4->DR; // Peripheral address register, point to UART4_DR
DMA2_Channel3->CMAR = (u32)uart4RxBuf; // Memory address register
DMA2_Channel3->CNDTR = UART4_RX_BUF_LEN; // Number of data
DMA2_Channel3->CCR = 0x00000000; // RESET DMA
DMA2_Channel3->CCR |= 1<<1; // TCIE = 1, transfer complete interrupt enable
DMA2_Channel3->CCR |= 1<<3; // TEIE = 1, Transfer error interrupt enable
DMA2_Channel3->CCR |= 0<<4; // DIR = 0, read from peripheral
DMA2_Channel3->CCR |= 0<<5; // CIRC = 0, circular mode disable
DMA2_Channel3->CCR |= 0<<6; // PINC = 0, Peripheral increment mode disabled
DMA2_Channel3->CCR |= 1<<7; // MINC = 1, Memory increment mode enabled
DMA2_Channel3->CCR |= 0<<8; // PSIZE =0, peripheral data 8-bits
DMA2_Channel3->CCR |= 0<<10; // MSIZE =0, memory data 8-bits
DMA2_Channel3->CCR |= 2<<12; // PL = 1, channel priority level:medium
DMA2_Channel3->CCR |= 0<<14; // MEM2MEM = 0, memory to memory mode disable
DMA2_Channel3->CCR |= 1<<0; // EN = 1, channel enable
MY_NVIC_Init(3,3,DMA2_Channel3_IRQn,2); //抢占3,子优先级3,组2
// ******************************** DMA2 Channel5 - UART4_TX ***************************************
// UART4使用DMA2的通道5作为发送通道
RCC->AHBENR |= 1<<1; // 开启DMA2时钟
delay_ms(5); // 等待DMA时钟稳定
DMA2_Channel5->CPAR = (u32)&UART4->DR; // Peripheral address register, point to UART4_DR
DMA2_Channel5->CMAR = (u32)uart4TxBuf; // Memory address register
DMA2_Channel5->CNDTR = UART4_TX_BUF_LEN; // Number of data,实际设置128
DMA2_Channel5->CCR = 0x00000000; // RESET DMA
DMA2_Channel5->CCR |= 1<<1; // TCIE = 1, transfer complete interrupt enable
DMA2_Channel5->CCR |= 1<<4; // DIR = 1, Read from memory
DMA2_Channel5->CCR |= 0<<5; // CIRC = 0, Circular mode disabled
DMA2_Channel5->CCR |= 0<<6; // PINC = 0, Peripheral increment mode disabled
DMA2_Channel5->CCR |= 1<<7; // MINC = 1, Memory increment mode enabled
DMA2_Channel5->CCR |= 0<<8; // PSIZE =0, peripheral data 8-bits
DMA2_Channel5->CCR |= 0<<10; // MSIZE =0, memory data 8-bits
DMA2_Channel5->CCR |= 1<<12; // PL = 1, channel priority level:medium
DMA2_Channel5->CCR |= 0<<14; // MEM2MEM = 0, memory to memory mode disable
DMA2_Channel5->CCR |= 1<<0; // EN = 1, channel enable
MY_NVIC_Init(2,2,DMA2_Channel4_5_IRQn,2); //抢占3,子优先级3,组2
}
// 在DMA2通道5的发送完成中断中置位允许发送标志,这里用全局变量dmasend
void DMA2_Channel4_5_IRQHandler(void)
{
u8 tempByte;
if(DMA2->ISR & (1<<17))
{
DMA2->IFCR |= 1<<17; // CTCIF5 = 1, Clear transfer complete flag
//DMA2->IFCR |= 1<<19; // CTEIF = 1, Clear Channel 3 transfer error flag
DMA2_Channel5->CCR &=~(1<<0); //关闭DMA传输
dmaSend = 1; // 置位允许发送标值
UART4->SR &= ~(1<<6);
}
}
//开启一次DMA传输
// 主程序中定时调用该函数进行发送
static u8 byteSend1 = 0;
void uart4_dma_send(void)
{
if(dmaSend == 1)
{
// 更新发送缓冲区
uart4TxBuf[0] = byteSend1;
uart4TxBuf[1] = byteSend1+1;
uart4TxBuf[2] = byteSend1+2;
uart4TxBuf[3] = byteSend1+3;
uart4TxBuf[4] = byteSend1+4;
byteSend1 += 1;
DMA2_Channel5->CNDTR = 5; // 重置DMA发送字节数
DMA2_Channel5->CCR |= 1<<0; // 开启DMA传输
dmaSend = 0;
}
}
说明:以上就是DMA发送接收的代码,思路就是定时调用发送函数uart4_dma_send()进行DMA发送;
接收是在UART4的空闲中断中读取DMA缓冲区的数据,并重新启动DMA接收。
现在的问题是,只要在串口配置函数中添加这一行:
UART4->CR3 = 1<< 7; // DMAT = 1, 使能UART4的DMA发送
DMA就不能接收到数据,注释掉就能接收到,不知为何。
还请论坛高手前辈们指点。
|