|
|
使用SWM34S串口DMA通讯时遇到一个奇怪问题,SWM34S循环发送modbus命令向从机获取数据,正常情况下一切正常,不正常的情况就在于如果在通讯过程中突然拔掉串口数据线,然后再插上就会导致通讯失败(SWM34S端串口无法再获取到从机数据),通过逻辑分析仪捕捉数据发现SWM34S还在正常发送数据,并且从机也正常回应数据,但通过仿真调试发现SWM34S在数据线拔掉再接上之后,DMA接收数据存入的数据缓冲区数据错乱,我的DMA每次发送数据前都是会重新配置的,代码如下
#include "sys.h"
u8 rx_buff[33];
u8 tx_buff[13];
/*---------------------------------------------------
配置uart_rx_dma
des_addr 内存地址
bcnt 数据传输长度
----------------------------------------------------*/
void uart_rx_dma_config(u32 rx_addr, u16 bcnt)
{
DMA_InitStructure DMA_initStruct;
DMA_initStruct.Mode = DMA_MODE_SINGLE;
DMA_initStruct.Unit = DMA_UNIT_BYTE;
DMA_initStruct.Count = bcnt;
DMA_initStruct.SrcAddr = (uint32_t)&UART3->DATA;
DMA_initStruct.SrcAddrInc = 0;
DMA_initStruct.DstAddr = (uint32_t)rx_addr;
DMA_initStruct.DstAddrInc = 1;
DMA_initStruct.Handshake = DMA_CH1_UART3RX;
DMA_initStruct.Priority = DMA_PRI_LOW;
DMA_initStruct.INTEn = 0;
DMA_CH_Init(DMA_CH1, &DMA_initStruct);
DMA_CH_Open(DMA_CH1);
}
/*---------------------------------------------------
配置uart_rx_dma
des_addr 内存地址
bcnt 数据传输长度
----------------------------------------------------*/
void uart_tx_dma_config(u32 tx_addr, u16 bcnt)
{
DMA_InitStructure DMA_initStruct;
DMA_initStruct.Mode = DMA_MODE_SINGLE;
DMA_initStruct.Unit = DMA_UNIT_BYTE;
DMA_initStruct.Count = bcnt;
DMA_initStruct.SrcAddr = (uint32_t)tx_addr;
DMA_initStruct.SrcAddrInc = 1;
DMA_initStruct.DstAddr = (uint32_t)&UART3->DATA;
DMA_initStruct.DstAddrInc = 0;
DMA_initStruct.Handshake = DMA_CH0_UART3TX;
DMA_initStruct.Priority = DMA_PRI_LOW;
DMA_initStruct.INTEn = 0;
DMA_CH_Init(DMA_CH0, &DMA_initStruct);
DMA_CH_Open(DMA_CH0);
}
void uart_process()
{
volatile static u16 tx_len, rx_len;
volatile u32 crc, dat, adr=1318;
/*- 发命令 -*/
tx_buff[0] = 1; //站号
tx_buff[1] = 0x03; //功能码
tx_buff[2] = adr >> 8; //地址
tx_buff[3] = adr;
tx_buff[4] = 0; //寄存器数量
tx_buff[5] = 2;
crc=GetCRC16(tx_buff,6); //CRC16
tx_buff[7] = crc >> 8;
tx_buff[6] = crc;
tx_len = 8; //发送长度
rx_len = 9; //接收长度
uart_rx_dma_config((u32)rx_buff, rx_len);
uart_tx_dma_config((u32)tx_buff, tx_len);
/*- 接收数据 -*/
volatile u32 timeout=10000000;
while((DMA_CH_INTStat(DMA_CH1, DMA_IT_DONE)==0) && (timeout--));
DMA_CH_INTClr(DMA_CH1, DMA_IT_DONE);
if(timeout > 0)
{
crc =GetCRC16(rx_buff, rx_len-2);
u16 ret =rx_buff[rx_len-2];
ret|=rx_buff[rx_len-1]<<8;
if(crc==ret) //CRC16
{
dat =rx_buff[3]<<24;
dat|=rx_buff[4]<<16;
dat|=rx_buff[5]<<8;
dat|=rx_buff[6]<<0;
reg[0].dat =dat; //实际数据
}
}
}
这个程序已经是简化过的,为了方便排查问题,在主线程循环调用uart_process()函数,只要在上电通讯前数据线是插着的那么就一切正常,一旦中途拔掉通讯线就会出现DMA接收数据错乱,我猜测是uart_rx_dma_config((u32)rx_buff, rx_len) 这个设置函数没能完全清除上一切DMA接收的数据计数导致的,也就是拔掉数据线时可能DMA已经接收了一定长度的数据,再次插上数据线后DMA接收到的数据还是从上一次位置存入数据
|
|