打印
[STM32F1]

空闲中断+DMA双缓冲+环形缓冲区+flash写入

[复制链接]
1585|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
djz1992|  楼主 | 2020-9-4 16:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
经过多天的折腾,终于成功了。50K的bin文件直接下载写入flash,没有分包,当然这是服务器的局限,我也没办法,最好是分包的。

DMA接收缓冲区长度1024Byte,两个。环形缓冲2048Byte,一个。
在空闲中断和DMA接收完成中断里,都执行切换缓冲区并启动,然后复制数据到环形缓冲区的操作。
在主函数判断环形缓冲区的数据长度,超过2Byte就读出来,按halfword写入flash。

检测进入空闲中断和DMA完成中断的次数,以及进入中断时,环形缓冲区的数据长度,以判断环形缓冲区的大小够不够。
在串口38400的速度下,传输一个60K的bin文件。
大概要进空闲中断300次,此时环形缓冲区的数据最大700+;
进DMA完成中断仅2~3次,此时环形缓冲区的数据长度位1024/1025等等。

如果把两个DMA接收长度都扩大到2048Byte,测试了一次,不会进DMA完成中断,都在串口空闲中断里就接收完了。

实际现象就是即使数据不断地接收,串口空闲中断是经常触发的,反倒是想要连续接收2048字节而不触发空闲,基本上不太可能。
在使用环形缓冲区的时候也发现了一些问题。
在很多教程中,都是用ring.len的++和--来作为长度的判断。实际使用中,读写连续进行,甚至中断会插手的时候,经常出现头部地址与尾部地址不同,但是len却未0的情况。
所有我看有些教程里,len是算出来的,len =(尾部 + 缓冲区总长 - 头部 )% 缓冲区总长;


问题1:也许波特率调高后,进空闲中断会少些?
问题2:即便把len定义成voltail变量,照样出错,是因为主函数中在读取--的时候,进中断又++,导致错乱吗?
问题3:flash的写入速度好像也不是很慢啊?我看网上说写入速度很慢,本来我打算以2400比特率接收的。没想到38400下,写入也跟得上。

如果能不复制数据,传递地址就好了,还没研究。但是复制有复制的好处。
感谢各位大佬的指点。
@dirtwillfly @m564522634 @xyz549040622

使用特权

评论回复
沙发
gyh974| | 2020-9-4 16:37 | 只看该作者
求分享,学习学习

使用特权

评论回复
板凳
ufbycd| | 2020-9-9 17:05 | 只看该作者
如果你的bootloader在flash里执行,写flash时CPU会停机,所以最好不要同时进行写flash跟数据传输。

使用特权

评论回复
地板
yklstudent| | 2020-9-10 20:54 | 只看该作者
对速度有提升吗?

使用特权

评论回复
5
djz1992|  楼主 | 2020-9-11 08:02 | 只看该作者
ufbycd 发表于 2020-9-9 17:05
如果你的bootloader在flash里执行,写flash时CPU会停机,所以最好不要同时进行写flash跟数据传输。 ...

flash分区了也不行吗?
那这么多数据,不写入flash的话,意思是得写入外部的存储器?

使用特权

评论回复
6
djz1992|  楼主 | 2020-9-11 08:03 | 只看该作者
yklstudent 发表于 2020-9-10 20:54
对速度有提升吗?

没做过单字节的中断接收,不清楚效果。

使用特权

评论回复
7
ufbycd| | 2020-9-11 08:45 | 只看该作者
本帖最后由 ufbycd 于 2020-9-11 08:50 编辑
djz1992 发表于 2020-9-11 08:02
flash分区了也不行吗?
那这么多数据,不写入flash的话,意思是得写入外部的存储器? ...

追求快的话,应该将bootloader放RAM里运行。这样写Flash时,CPU就不会停机了,就不会有丢失传输的数据的风险。
我所说的“同时进行写flash跟数据传输”是指写flash的同时又进行数据接收的细节性的动作。
你看ST官方的IAP例程的写操作跟接收操作是分时进行的。



使用特权

评论回复
8
便携手到老| | 2020-9-11 08:46 | 只看该作者
恭喜楼主,我也试试去。

使用特权

评论回复
9
真爱吴迪迪| | 2020-9-11 08:55 | 只看该作者
大概要进空闲中断300次,此时环形缓冲区的数据最大700+;

使用特权

评论回复
10
可爱的烧饼| | 2020-9-11 09:35 | 只看该作者
过多天的折腾,终于成功了。50K的bin文件直接下载写入flash,没有分包,当然这是服务器的局限,我也没办法,最好是分包的。

使用特权

评论回复
11
djz1992|  楼主 | 2020-9-11 11:41 | 只看该作者
ufbycd 发表于 2020-9-11 08:45
追求快的话,应该将bootloader放RAM里运行。这样写Flash时,CPU就不会停机了,就不会有丢失传输的数据的风 ...

膜拜大佬,这个太高深了,晚点研究。先把应用层面的东西搞掂再说

使用特权

评论回复
12
观海| | 2020-10-10 12:04 | 只看该作者
经验之谈呀

使用特权

评论回复
13
guanjiaer| | 2020-10-10 12:04 | 只看该作者
感谢楼主的分享

使用特权

评论回复
14
heimaojingzhang| | 2020-10-10 12:06 | 只看该作者
真的很有想法

使用特权

评论回复
15
keaibukelian| | 2020-10-10 12:07 | 只看该作者
怎么做双缓冲呢

使用特权

评论回复
16
labasi| | 2020-10-10 12:08 | 只看该作者
长知识了 非常感谢楼主

使用特权

评论回复
17
djz1992|  楼主 | 2020-10-12 08:03 | 只看该作者
本帖最后由 djz1992 于 2020-10-12 08:05 编辑

很简单,csdn上很多帖子。最基本的就是两个数组,一个全局变量。用全局变量记录下次接收使用哪个数组接收.
/**
  * 函数功能:串口接收空闲中断函数
  * 输入参数:
  * 返 回 值:
  * 说    明:无
  */
void UsartReceive_IDLE(UART_HandleTypeDef *huart,UartBufferTypedef *UartxRT )
{
        uint32_t temp;
        if((__HAL_UART_GET_FLAG(huart,UART_FLAG_IDLE) != RESET))                                //获取IDLE标志位,如果idle标志被置
        {
                __HAL_UART_CLEAR_IDLEFLAG(huart);                                                                        //清除串口空闲标志
                HAL_UART_DMAStop(huart);
                temp=__HAL_DMA_GET_COUNTER(huart->hdmarx);                                                        //获取DMA中未传输的数据个
                UartxRT->RxDMALen =  MAX_RxDMA_BUFFER - temp;                                                        //总计数减去未传输的数据个数,得到已经接收的数据个

                if(UartxRT->witchbuf==1)                                                                        //之前用的buf1,切换为2
                {
                        UartxRT->witchbuf=2;
                        HAL_UART_Receive_DMA(huart,UartxRT->RxDMA_Buf2,MAX_RxDMA_BUFFER);        //重启串口DMA接收到buf2
                        UartxRT->RxLen+=UartxRT->RxDMALen;
                }
                else if(UartxRT->witchbuf==2)                                                             //之前用的buf2,切换为buf1
                {
                        UartxRT->witchbuf=1;
                        HAL_UART_Receive_DMA(huart,UartxRT->RxDMA_Buf,MAX_RxDMA_BUFFER);                //重启串口DMA接收到buf1
                        UartxRT->RxLen+=UartxRT->RxDMALen;
                }
        }
}


使用特权

评论回复
18
djz1992|  楼主 | 2020-10-12 08:05 | 只看该作者
labasi 发表于 2020-10-10 12:08
长知识了 非常感谢楼主

菜鸟一个,瞎搞而已。

使用特权

评论回复
19
djz1992|  楼主 | 2020-10-12 08:06 | 只看该作者

瞎折腾的,菜鸟,只能到处打补丁一样的瞎搞

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:人生苦短,冬日苦长,正是青葱,却无骄阳

115

主题

620

帖子

5

粉丝