OpenEdv-开源电子网

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

AD采集到的实时数据全部存入nand flash和定义大数组的问题

[复制链接]

3

主题

10

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2014-10-20
在线时间
0 小时
发表于 2015-3-18 15:23:22 | 显示全部楼层 |阅读模式
5金钱

使用STM32ADC1ADC2同步采集2路外部信号,且定时器中断(TIM2_CC2,每0.01ms采集一次,即采样率为100ksps)触发ADC1ADC2同时采集。
其中ADC1采集的数据保存在ADC_DR的低16位,ADC2采集的数据保存在ADC_DR的高16位。
然后将ADC1ADC2采集的数据通过DMA方式将ADC_DR中的字数据传输至数组 unsigner int  AD_Value[ADC_BufferLength]中,最后将保存在数组
 AD_Value中的数据写入nand flash中保存起来。
现在主要有两个问题:
问题1:由于数组AD_Value中保存的是数据,而目前所使用的nand  flash K9F1G08U0E8位的,因此,在将数组AD_Value中的数据写入flash 之前,需要先将数组AD_Value数据分解字节数据,并将这些字节数据保存在字节数组unsigner char TxBuffer[ADC_BufferLength*4]中。
比如通过以下方式:

[mw_shl_code=c,true] for(i=0;i<ADC_BufferLength;i++) { TxBuffer[i*4] = (u8)((AD_Value)&0xff); TxBuffer[i*4+1] = (u8)(((AD_Value)&0xff00)>>8); //ADC1:低字 TxBuffer[i*4+2] = (u8)(((AD_Value)&0xff0000)>>16); TxBuffer[i*4+3] = (u8)(((AD_Value)&0xff000000)>>24);//ADC2:高字 } [/mw_shl_code]
但是,这样势必影响到数据存储的速度,从而影响到实时数据的保存。该怎么办呢?
问题2:两路AD同步采集,且采集速率都是100ksps,而nand  flash的页编程时间一般为300us~700us,那么,在flash的页编程时间里,2路AD采集
到的数据量=2*100k*700us*2Byte(每个AD采集数据为2个字节)=280Byte,因此,为了能够保证保存AD采集的全部实时数据,那么缓冲区的大小
就至少为280Byte。
于是我就将ADC_BufferLength定义为128:#define ADC_BufferLength  128

这样一来,缓冲区的实际大小就是128*4=512Byte,这是满足要求的。
程序编译通过了,nand  flash的读写也是正确的。
但考虑到nand flash的一页是2k=2048个字节,于是,将于是我就将ADC_BufferLength定义为512,即2048个字节,恰好是falsh一页的大小。
编译能够通过,但是程序却一直在“字转字节”的小程序中循环:


我尝试着将堆区扩大,将Stack_Size      EQU     0x00000800 改成 Stack_Size      EQU     0x00008000
结果依然是:在”字转字节“的小程序中死循环,全速运行,也不会到达断点处;
然后我将数组unsigner char TxBuffer[ADC_BufferLength*4]由局部变量改成全局变量,
结果依然是:在”字转字节“的小程序中陷入了死循环,即使全速运行,也不能到达断点处,当停止全速运行时,通过memory窗口
查看数组TxBuffer中数据时,发现,只能看到数据的前1024个数据,即TxBuffer[0]~TxBuffer[1023],之后的1024个数据则全部为
0x00。
这又该怎么办呢?


最佳答案

查看完整内容[请看2#楼]

直接强转成u8的指针,然后保存,然后按u8读,都出来直接再强转回来即可
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

4

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2015-3-9
在线时间
9 小时
发表于 2015-3-18 15:23:23 | 显示全部楼层
直接强转成u8的指针,然后保存,然后按u8读,都出来直接再强转回来即可
来来,我是一个白菜,菜菜菜。。。。。
回复

使用道具 举报

105

主题

522

帖子

1

精华

金牌会员

Rank: 6Rank: 6

积分
1386
金钱
1386
注册时间
2012-10-23
在线时间
97 小时
发表于 2015-3-18 20:26:21 | 显示全部楼层
会不会是i的定义有问题   定义的u8???
回复

使用道具 举报

3

主题

10

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2014-10-20
在线时间
0 小时
 楼主| 发表于 2015-3-19 17:46:59 | 显示全部楼层
回复【2楼】miaoguoqiang:
---------------------------------
是的  很抱歉   犯了这种不该犯的错误,不过还是感谢您的提醒
回复

使用道具 举报

3

主题

10

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2014-10-20
在线时间
0 小时
 楼主| 发表于 2015-3-19 20:01:28 | 显示全部楼层
在一位坛友的帮助下,使用了共用体结构(union)
typedef union
{
  unsigned int Value_int[512];
  unsigned char Value_char[2048];
}AD_Value;
挺好用的。谢谢这位坛友,也谢谢坛友的热心帮忙!
回复

使用道具 举报

3

主题

10

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2014-10-20
在线时间
0 小时
 楼主| 发表于 2015-3-21 11:49:05 | 显示全部楼层
上次说使用了uinon结构,
typedef union
{
 unsigned int Value_int[512];
 unsigned char Value_char[2048];
} AD_Value;
AD_Value AD;
ADC1和ADC2每采集一次,DMA就立即将该数据传输给数组AD1.Value_int,
当512个字全部传输完毕,进入DMA中断;
DMA中断程序主要是将刚刚采集到的512个字,即2048个字节写入flash中。
关于“在DMA中断函数中完成写flash”,这是我自己比较惆怅的地方:
之所以很难保证AD采集数据的完整性,flash的存储速度跟不上就是主要的原因。
而现在在中断程序中完成flash写操作,除去flash页编程的时间不说,还有额外的进入中断和
退出中断的时间。这无疑是雪上加霜啊。   
ADC1和ADC2的同步采集是由定时器2中断(IM2_CC)触发的,采样率控制为100ksps,也就是    
说,采样的时间间隔是10us。
而当开始第一次采集到一次写flash完成的时间,设为T,则     
T=AD采集时间+DMA传输时间(虽然时间很短很短)+进入DMA中断时间+在中断中写flash时间+退出DMA中断时间。
T应该是大于10us,所以实际写入flash的数据不是AD第一次采集的数据。因为AD1_Value_int中的数据每10us就会改变一次,而T却比10us大,所以,实际写入flash的数据也不知道是AD第几次采集的。
除非一进入DMA中断,就关闭定时器或者关闭DMA传输,那么写入flash的数据则是关闭定时器之前时AD采集的数据。
但是这样的话,AD的采集频率就不再是100ksps,肯定比100ksps小。
所以,我现在在考虑:
(1)不要在DMA中断函数中完成flash写操作,但不在DMA中断函数中写,又该怎么弄呢?
(2)坛友提到的“双缓冲模式”,定义两个缓冲区,一个缓冲区存满之后,就存第二个缓冲区,同时将第一个缓冲区中数据写入flash中;等第二个缓冲区满了,重新回来存第一个缓冲区,同时,将第二个缓冲区中的数据写入flash中。                  
用两个缓冲区交替工作来保证采集的连续性。道理是明白的,但程序实现上,还是挺茫然的。
回复

使用道具 举报

0

主题

0

帖子

0

精华

新手上路

积分
22
金钱
22
注册时间
2019-3-18
在线时间
5 小时
发表于 2017-4-1 11:34:37 | 显示全部楼层
楼主,你后来解决了没?我现在遇到的问题几乎跟你是一样的,能否赐教,谢谢。
回复

使用道具 举报

259

主题

806

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1887
金钱
1887
注册时间
2012-10-28
在线时间
353 小时
发表于 2017-4-1 15:11:35 | 显示全部楼层
估计是没有下文了哟
回复

使用道具 举报

40

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
459
金钱
459
注册时间
2016-5-19
在线时间
192 小时
发表于 2020-3-25 15:37:54 | 显示全部楼层
本帖最后由 h418452224 于 2020-3-25 15:39 编辑

在DMA2_Config里加上    DMA_DoubleBufferModeConfig(DMA2_Stream0,(uint32_t)(u16 *)(uAD_Buff_B),DMA_Memory_0);    //DMA_Memory_0首先被传输
  DMA_DoubleBufferModeCmd(DMA2_Stream0,ENABLE);
然后再中断里加上
void DMA2_Stream0_IRQHandler(void)  
{
        
         DMA_ClearITPendingBit(DMA2_Stream0, DMA_IT_TCIF0);
         if(DMA_GetCurrentMemoryTarget(DMA2_Stream0) == DMA_Memory_0)
         {
             ADC_ConvertedValueptr = uAD_Buff_A;
         }
         else
         {
             ADC_ConvertedValueptr = uAD_Buff_B;
         }
}
开启双缓冲模式
回复

使用道具 举报

40

主题

259

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
459
金钱
459
注册时间
2016-5-19
在线时间
192 小时
发表于 2020-3-25 15:40:15 | 显示全部楼层
我现在也遇到这个问题了o(︶︿︶)o  难搞啊
回复

使用道具 举报

85

主题

249

帖子

0

精华

高级会员

Rank: 4

积分
674
金钱
674
注册时间
2020-12-5
在线时间
202 小时
发表于 2020-12-21 11:28:55 | 显示全部楼层
您好,冒昧问一下我最近在学习单片机,现在在进行尝试ADC采集数据经过DMA方式然后存放数组里,但是现在不太明白如何合适的构建数组,看到您的帖子,想询问您一下是否可以把您的程序发我一份学习一下,如果可以,感激不尽,当然如果不可以也非常感谢您,谢谢。935089561@qq.com
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手入门

积分
19
金钱
19
注册时间
2021-12-12
在线时间
5 小时
发表于 2022-8-22 15:47:17 | 显示全部楼层
车嘉炜 发表于 2020-12-21 11:28
您好,冒昧问一下我最近在学习单片机,现在在进行尝试ADC采集数据经过DMA方式然后存放数组里,但是现在不太 ...

您好,请问您搞定那个将ADC采集的数据存在数组里的方法了吗,我最近也不知道如何建立数组
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-2-26 06:52

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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