本帖最后由 saccapanna 于 2019-10-26 11:06 编辑
I/D-Cache 都已经关闭。 main.c 主要功能,从 USART4 接收数据,然后原封不动返回相同数据。多字节 DMA 发送没有任何问题。 但是当 USART4 接收到一个字节时,把单个字节写入到 USART4 发送缓冲区,然后启动 DMA 数据传输,而 DMA 实际传输的是以前缓冲区的值,而不是新写入的值。 单字节写入后,延迟 10us,或者打断点等待一下,再启动 DMA 传输也没有问题。 这个问题我分析了好久,实在没有找到软件的问题,后来解决方法如下,在启动DMA前做一下判断,如果长度为1,写4次缓冲…… 这个算不算芯片的 Bug ?
if( usart4_tx_dma_len == 1 ) { // -- 如果是单字节发送,DMA会出问题
temp = usart4_tx_buff[usart4_tx_sp]; // -- 数据重写四次,问题解决了,重写三次都不行!!!
usart4_tx_buff[usart4_tx_sp] = temp; //
usart4_tx_buff[usart4_tx_sp] = temp; //
usart4_tx_buff[usart4_tx_sp] = temp; //
usart4_tx_buff[usart4_tx_sp] = temp; //
} //
整个测试过程大概如下:
main()
{
……
sub_usart4_init( 9600, 0 ); // 串口初始化
while (1) { //
i = sub_usart4_get_receive_buff_len(); // 从 USART4 接收数据,然后原封不动发送相同数据。
if( i != 0 ) { //
sub_usart4_read_receive_buff( test_buff, i ); // -- 如果 i==1,也就是从串口接收一个字节,
sub_usart4_write_send_buff( test_buff, i ); // -- 单字节写入触发DMA传输,这个函数 DMA 传输出问题
} //
}
//==============================================================================================================
// 函数名称:sub_usart4_write_send_buff
// 函数功能:写数据到 usart4 发射缓冲区
// DMA1_Stream4:USART4_RX(63) ---> DMAMUX1_Channel_04 ---> DMA1_Stream4_Request
// DMA1_Stream5:USART4_TX(64) ---> DMAMUX1_Channel_05 ---> DMA1_Stream5_Request
// 入口参数:data:数据指针,length:数据长度
// 出口参数:BOOL_FALSE:数据太长,将导致缓冲区溢出,写入失败
// BOOL_TRUE:写入成功
// 程序版本:1.0
// 编写日期:2019-05-05
// 程序作者:
// 修改次数:
// 修改作者:
// 修改日期:
// 修改内容:
// 版本升级:
//==============================================================================================================
BOOLEAN sub_usart4_write_send_buff( const INT8U * data, INT16U length )
{
INT16U i; //
INT16U usart4_tx_len; //
if( length > USART4_TX_BUFF ) { // 检测写入数据长度
return BOOL_FALSE; //
} //
ENTER_CRITICAL(); //
usart4_tx_len = usart4_tx_buff_len + length; //
EXIT_CRITICAL(); //
if( usart4_tx_len > USART4_TX_BUFF ) { // 数据太长,写入失败
return BOOL_FALSE; //
} //
for( i=0; i<length; i++ ) { // 写数据到缓冲区
usart4_tx_buff[usart4_tx_ep] = data
; //
usart4_tx_ep++; //
if( usart4_tx_ep >= USART4_TX_BUFF ){ //
usart4_tx_ep = 0; //
} //
} //
// sub_system_raw_delay_10us(1); // 如果使用延迟,DMA发送数据没有任何问题。
// __asm("NOP"); // 如果断点打在这里,然后再F5全速跑,DMA发送也没问题。
// __asm("NOP"); // 但是如果这里不延迟,不打断点,单字节启动DMA,
// __asm("NOP"); // DMA传输的数据,是之前 usart4_tx_buff 中的数据。
// __asm("NOP"); // 也就是说,新的数据没有真正的写入到 usart4_tx_buff 中。
// __asm("NOP"); //
// __asm("NOP"); // 说明:为了便于测试观看,buff 大小都只设置到了 16 字节。
// __asm("NOP"); //
// __asm("NOP"); //
ENTER_CRITICAL(); //
usart4_tx_buff_len += length; // 缓冲区长度增加
if( ((DMA1_Stream5->CR) & DMA_SxCR_EN) == 0 ) { // 开启 DMA 数据传输
DMA1_Stream5->CR = 0x00000000; //
DMA1_Stream5->FCR = 0x00000000; // -- 使用直接模式
DMA1_Stream5->PAR = (INT32U)(&(USART4->TDR)); // -- 设置 外设 地址
DMA1_Stream5->M0AR = (INT32U)( usart4_tx_buff+usart4_tx_sp ); // -- 设置 Memory 地址
if( usart4_tx_ep > usart4_tx_sp ) { //
usart4_tx_dma_len = usart4_tx_ep - usart4_tx_sp; //
} //
else { //
usart4_tx_dma_len = USART4_TX_BUFF - usart4_tx_sp; //
} //
DMA1_Stream5->NDTR = usart4_tx_dma_len; // -- 设置传输长度
// if( usart4_tx_dma_len == 1 ) { // -- 如果是单字节发送,DMA会出问题
// temp = usart4_tx_buff[usart4_tx_sp]; // -- 数据重写四次,问题解决了,重写三次都不行!!
// usart4_tx_buff[usart4_tx_sp] = temp; //
// usart4_tx_buff[usart4_tx_sp] = temp; //
// usart4_tx_buff[usart4_tx_sp] = temp; //
// usart4_tx_buff[usart4_tx_sp] = temp; //
// } //
DMAMUX1_Channel5->CCR = 64; // -- 选择触发信号
DMA1_Stream5->CR |= DMA_SxCR_MINC | DMA_SxCR_DIR_0; // -- Memory 自增,01: Memory-to-peripheral,DMA优先级为低。
DMA1->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5; // -- 清除传输完毕标识
DMA1_Stream5->CR |= DMA_SxCR_TCIE; // -- 开启传输完毕中断
DMA1_Stream5->CR |= DMA_SxCR_EN; // -- 启动 DMA 传输
USART4->CR3 |= USART_CR3_DMAT; //
} //
EXIT_CRITICAL(); //
return BOOL_TRUE; //
} //
测试工程文件:
STM32H743_USART4_DMA_ERR.rar
(739.96 KB, 下载次数: 1)
2019-10-26 10:35 上传
点击文件名下载附件
一周热门 更多>