OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 11409|回复: 16

DMA通过485发送数据有点问题

[复制链接]

19

主题

121

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
218
金钱
218
注册时间
2011-8-8
在线时间
0 小时
发表于 2011-11-22 13:21:34 | 显示全部楼层 |阅读模式
DMA传输是好的,问题是,DMA传输完成之后需要把485的控制端拉低变成接收模式,如果直接在DMA完成中断里转换,会丢失最后两个数据,因为还没发出去。
现在只能是在DMA的完成中断中开启串口发送中断,然后再转换状态。好麻烦,还有什么好方法。
世界上有10种人,一种是懂二进制的,另一种是不懂二进制的。。。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2012-7-25 15:42:16 | 显示全部楼层
加个定时器 2ms 

在定时器内 置为输入状态,然后关闭定时器

在 DMA TC中断内,启动定时器
回复 支持 1 反对 0

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165524
金钱
165524
注册时间
2010-12-1
在线时间
2116 小时
发表于 2011-11-22 13:42:32 | 显示全部楼层
回复【楼主位】sixear:
---------------------------------
试试在DMA完成中断里面查询串口发送空标志。以判断串口是否还在发送。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

19

主题

121

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
218
金钱
218
注册时间
2011-8-8
在线时间
0 小时
 楼主| 发表于 2011-11-22 14:08:02 | 显示全部楼层
回复【2楼】正点原子:
---------------------------------
不好,不好
世界上有10种人,一种是懂二进制的,另一种是不懂二进制的。。。
回复 支持 反对

使用道具 举报

14

主题

75

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
248
金钱
248
注册时间
2011-10-16
在线时间
31 小时
发表于 2012-2-28 23:08:31 | 显示全部楼层
兄弟 你这个问题是这么解决的啊 ?我也碰到了相同的问题
如果在DMA TC 中断里就去打开RS485的接收功能 ,会造成2哥BYTE的数据发送不出去,用查询的方式发送空的方式应该不行吧,因为每次DMA TC中断产生后还有至少2个数据没传走,如果只有一个 这种方式还可以,
我现在干脆在里面加了哥2MS的延时,不知道有没有更加高明的办法 
回复 支持 反对

使用道具 举报

14

主题

75

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
248
金钱
248
注册时间
2011-10-16
在线时间
31 小时
发表于 2012-2-28 23:08:50 | 显示全部楼层
回复【3楼】sixear:
回复【2楼】正点原子:
---------------------------------
不好,不好
---------------------------------
兄弟 你这个问题是这么解决的啊 ?我也碰到了相同的问题 
如果在DMA TC 中断里就去打开RS485的接收功能 ,会造成2哥BYTE的数据发送不出去,用查询的方式发送空的方式应该不行吧,因为每次DMA TC中断产生后还有至少2个数据没传走,如果只有一个 这种方式还可以,
 我现在干脆在里面加了哥2MS的延时,不知道有没有更加高明的办法 
回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2012-7-25 15:45:05 | 显示全部楼层
void DMA1_Channel2_IRQHandler(void)
{
if( DMA1->GetFlag(DMAType::_TC2))
{
// msg_Master.TransOk();
TIM1->Enable();
msg_Master.SendOkDlyCnt =0 ;
DMA1->ClearFlag( DMAType::_GL2 ) ;
}
}

void TIM1_UP_IRQHandler(void)
{

if ((TIM1->SR & TIM_IT_Update) != RESET) 
{
     TIM1->SR &= ~TIM_IT_Update; // clear UIF flag

// Modbus.UART_CHK_TIMEOUT(5);
msg_Master.Chk_TimeOut(2);
msg_Master.TransOk();
RS485_INPUT();
TIM1->Disable();
}
}
回复 支持 反对

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
发表于 2016-12-16 11:02:08 | 显示全部楼层
okyihu 发表于 2012-2-28 23:08
兄弟 你这个问题是这么解决的啊 ?我也碰到了相同的问题
如果在DMA TC 中断里就去打开 ...

在中断里面加延时能行得通吗?我加延时最多传输一帧报文,然后就接收不到了
回复 支持 反对

使用道具 举报

25

主题

138

帖子

0

精华

高级会员

Rank: 4

积分
612
金钱
612
注册时间
2016-6-7
在线时间
59 小时
发表于 2016-12-16 11:03:04 | 显示全部楼层
正点原子 发表于 2011-11-22 13:42
回复【楼主位】sixear:
---------------------------------
试试在DMA完成中断里面查询串口发送空标志。以 ...

原子哥有没有搜集到这个问题的解决方法啊
回复 支持 反对

使用道具 举报

2

主题

8

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2016-12-15
在线时间
3 小时
发表于 2016-12-16 11:27:09 | 显示全部楼层
同问,小弟最近刚好在学这个,也用到了485.
现在还有个问题啊,顺便在这里问大家了,就是我的DMA发送和接收都只能执行一次,
执行下面代码时发现,DMAy_Streamx里的CR寄存器里的使能位置0后,无法置回1,这是怎么回事?
        DMA_Cmd(MyDMA_Structure->DMAy_Streamx, DISABLE);                //EN位 = 0
        DMA_SetCurrDataCounter(MyDMA_Structure->DMAy_Streamx,MyDMA_Structure->BufSize);
        DMA_Cmd(MyDMA_Structure->DMAy_Streamx, ENABLE);                //EN位 = 0(应为1才对呀)
回复 支持 反对

使用道具 举报

2

主题

8

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2016-12-15
在线时间
3 小时
发表于 2016-12-16 11:30:02 | 显示全部楼层
这是DMA配置代码,调试时发现,只要每次重新配置后,EN位才能变回1.。
void DMA_Config(USER_DMASTRUCTURE*        MyDMA_Structure)
{
        DMA_InitTypeDef DMA_InitStructure;
       
        if (MyDMA_Structure->DMAy_Streamx < DMA2_Stream0)
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);        //DMA时钟使能
        else
                RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
       
        DMA_DeInit(MyDMA_Structure->DMAy_Streamx);                                                //将DMA的通道寄存器重设为缺省值               
        while (DMA_GetCmdStatus(MyDMA_Structure->DMAy_Streamx) != DISABLE){}       
        DMA_InitStructure.DMA_Channel                        =        MyDMA_Structure->DMAChannel;        //通道设置
        DMA_InitStructure.DMA_PeripheralBaseAddr=        MyDMA_Structure->PerBaseAddr;        //外设基地址
        DMA_InitStructure.DMA_Memory0BaseAddr        =        MyDMA_Structure->MemBaseAddr;        //存储器基地址
        DMA_InitStructure.DMA_DIR                                =        MyDMA_Structure->DIR;                        //数据传输方向
        DMA_InitStructure.DMA_BufferSize                =        MyDMA_Structure->BufSize;                //DMA缓存大小
        DMA_InitStructure.DMA_PeripheralInc                =        DMA_PeripheralInc_Disable;                //外设地址寄存器不变
        DMA_InitStructure.DMA_MemoryInc                        =        DMA_MemoryInc_Enable;                        //内存地址寄存器递增
        DMA_InitStructure.DMA_PeripheralDataSize=        DMA_PeripheralDataSize_Byte;        //数据宽度为8位
        DMA_InitStructure.DMA_MemoryDataSize        =        DMA_MemoryDataSize_Byte;                //数据宽度为8位
        DMA_InitStructure.DMA_Mode                                =        DMA_Mode_Normal;//DMA_Mode_Circular;//DMA_Mode_Normal;                                //工作在正常模式
        DMA_InitStructure.DMA_Priority                        =        DMA_Priority_Medium;                        //DMA数据流x拥有中优先级
        DMA_InitStructure.DMA_FIFOMode                        =        DMA_FIFOMode_Disable;                        //FIFO模式关闭
        DMA_InitStructure.DMA_FIFOThreshold                =        DMA_FIFOThreshold_1QuarterFull;
        DMA_InitStructure.DMA_MemoryBurst                =        DMA_MemoryBurst_Single;
        DMA_InitStructure.DMA_PeripheralBurst        =        DMA_PeripheralBurst_Single;
       
        DMA_Init(MyDMA_Structure->DMAy_Streamx, &DMA_InitStructure);                                                //初始化DMA配置

}
回复 支持 反对

使用道具 举报

2

主题

8

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2016-12-15
在线时间
3 小时
发表于 2016-12-16 14:31:35 | 显示全部楼层
发现问题啦,原来是在使能前把中断标志位清错了。
C:\Users\牧羊犬\Desktop\捕获.PNG
回复 支持 反对

使用道具 举报

2

主题

8

帖子

0

精华

新手上路

积分
30
金钱
30
注册时间
2016-12-15
在线时间
3 小时
发表于 2016-12-16 14:37:39 | 显示全部楼层
对于最开始的问题,我想到别人用的UCOS操作系统,所以在DMA发送成功中断函数里通过发送邮箱,消息等,通知外部任务,然后再在任务里延时下,再把485的使能位拉低就好啦!   不知道大家认不认可这样的想法?
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2018-2-9
在线时间
15 小时
发表于 2018-2-9 10:36:57 | 显示全部楼层
6# 正解,dma 接受中断  用定时器延时2ms或者3ms打开485接收,最后的两字节就有了,哈哈哈
回复 支持 反对

使用道具 举报

1

主题

4

帖子

0

精华

初级会员

Rank: 2

积分
64
金钱
64
注册时间
2018-2-9
在线时间
15 小时
发表于 2018-2-9 10:47:33 | 显示全部楼层
好整以暇 发表于 2018-2-9 10:36
6# 正解,dma 接受中断  用定时器延时2ms或者3ms打开485接收,最后的两字节就有了,哈哈哈

又试了一下,定时器延时4ms 才可以,波特率9600,如果延时时间短,最后一个字节会出错,
回复 支持 反对

使用道具 举报

3

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
132
金钱
132
注册时间
2018-8-25
在线时间
33 小时
发表于 2019-1-17 11:21:51 | 显示全部楼层
本帖最后由 LevenC 于 2019-1-17 11:24 编辑

根据手册:
  • DMA TCIF置位
  • 软件清除TCIF位
  • 等待USART TC置位
  • 软件清除TC位
  • 切换RS485状态

虽然看起来麻烦,但这是符合硬件逻辑的做法,应该是可取的。

加入延时的做法应该是不妥的,这个延时的大小跟传输数据的大小有关,如果这个大小不可控且不可知,就更明显了。
USART_DMA_Send.jpg
回复 支持 反对

使用道具 举报

0

主题

5

帖子

0

精华

初级会员

Rank: 2

积分
179
金钱
179
注册时间
2019-2-25
在线时间
53 小时
发表于 2019-7-21 23:53:14 | 显示全部楼层
终于找到答案了。谢谢大家
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-8 10:56

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表