OpenEdv-开源电子网

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

关于单片机录音和播放的问题

[复制链接]

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
发表于 2024-11-12 08:16:49 | 显示全部楼层 |阅读模式
10金钱
我现在用W25N01G这个芯片存储音频电压数据,现在遇到的问题是我想快速的把adc转换的数据通过dma传输然后存储,但是放在while循环里存储总是出问题,先放在缓存数组里存储的话又没有这么大的数组能存(2分钟的录音,得有十几万字节),然后从这个芯片里利用dma+dac转换也是,想要连贯的输出读取一个输出一个又太慢,临时放在缓存数组又放不开,用的是东软载波的单片机

最佳答案

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

这种情况通常是因为堆栈溢出,由于局部变量一般是放在堆栈中的,所以建议局部变量不要占用太多空间, 局部大数组建议拿出来定义为全局变量(可分时复用),或将堆栈设置大一些(应该有个startup.s文件里可以设置堆栈大小).
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-12 08:16:50 | 显示全部楼层
meihua 发表于 2024-11-15 14:06
数组应该也不能超吧,我查着这故障一般是什么数组超了,地址太多啥的,但是缓存数组和全局变量数组都是大 ...

这种情况通常是因为堆栈溢出,由于局部变量一般是放在堆栈中的,所以建议局部变量不要占用太多空间,
局部大数组建议拿出来定义为全局变量(可分时复用),或将堆栈设置大一些(应该有个startup.s文件里可以设置堆栈大小).
傲游截图20241115141401.jpg
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-12 08:19:50 | 显示全部楼层
if(voctype==3&&PPT_in[0]==0)//此时录得是前导音
        {

                while(PPT_in[0]==0        )//暂时用这个当判断条件    麦克风输入音频record_readay==2
                {               
                        md_delay_us(10);
                        music_buf[mus]=(_env.buf[5]&0x0f00)>>8;//      比如 0x0c7a  music_buf[0]=0x0c  music_buf[1]=0x7a   后面再拼接起来
                        music_buf[mus+1]=_env.buf[5]&0x00ff;               
                        if(mus>2000)
                        {       
                                if(mus3==0)
                                {
                                W25Nx_Buf_Write_Nx_Data( music_buf,  0, 0,  0,  2000);
                                //        w25q32_write(0,music_buf,2000);
                                }
                                if(mus3==1)
                                {
                                W25Nx_Buf_Write_Nx_Data( music_buf,  0, 1,  0,  2000);
                                }
                                if(mus3==2)
                                {
                                W25Nx_Buf_Write_Nx_Data( music_buf,  0, 2,  0,  2000);
                                }
                                        if(mus3==3)
                                {
                                W25Nx_Buf_Write_Nx_Data( music_buf,  0, 3,  0,  2000);
                                }
                                if(mus3==4)
                                {
                                W25Nx_Buf_Write_Nx_Data( music_buf,  0, 4,  0,  2000);
                                }
                                mus2=mus2+48;
                                mus=0;
                        }
                                        mus2=mus2+2;//mus2是输入的所有音频电压数据
                        mus=mus+2;               
                        if(mus2>2048)
                        {               
                                mus3++;
                                mus2=0;
                               
                        }
                        if(mus3>4)
                        {
                        record_readay=5;
                                break;
                        }
                }
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-12 11:58:08 | 显示全部楼层
采样率多少?
while循环里存储有啥问题?
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-12 12:36:20 | 显示全部楼层
LcwSwust 发表于 2024-11-12 11:58
采样率多少?
while循环里存储有啥问题?

大概50KHz采样,while循环转换一个存一个目前要么读取出来是0,要么是0xff
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-12 13:06:47 | 显示全部楼层
meihua 发表于 2024-11-12 12:36
大概50KHz采样,while循环转换一个存一个目前要么读取出来是0,要么是0xff

哦,那就先单独把存储功能测试好再说。
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-12 13:19:56 | 显示全部楼层
LcwSwust 发表于 2024-11-12 13:06
哦,那就先单独把存储功能测试好再说。

存储单独拿出来是没问题的,我怀疑是不是短时间存的数量太多,但是不确定到底为啥,只能用上面那种if数组一次存一个页面的,if多了以后会莫名进入死循环
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-12 14:06:46 | 显示全部楼层
meihua 发表于 2024-11-12 13:19
存储单独拿出来是没问题的,我怀疑是不是短时间存的数量太多,但是不确定到底为啥,只能用上面那种if数组 ...

死在了哪里,分析一下原因
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-12 17:06:54 | 显示全部楼层
LcwSwust 发表于 2024-11-12 14:06
死在了哪里,分析一下原因

我现在先用if数组进行一小部分字节随存随取,然后有个新问题就是我读取了两页数据,是一样的,但是如果在while循环里存完就读取就不一样
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-13 09:28:10 | 显示全部楼层
本帖最后由 LcwSwust 于 2024-11-13 09:43 编辑
meihua 发表于 2024-11-12 17:06
我现在先用if数组进行一小部分字节随存随取,然后有个新问题就是我读取了两页数据,是一样的,但是如果在 ...

不知你是否了解它的读\写\擦除功能?
W25Nx_Buf_Write_Nx_Data各参数的定义或作用是啥?
为什么搞那么多if而不是用一句" W25Nx_Buf_Write_Nx_Data( music_buf,  0, mus3,  0,  2000);"来代替?
_env.buf[5]是啥?
是否试过生成一段十几万字节已知数据,写入\读取是否一致?
要不你还是直接上传工程吧,一个一个的问太麻烦.


专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 11:31:15 | 显示全部楼层
LcwSwust 发表于 2024-11-13 09:28
不知你是否了解它的读\写\擦除功能?
W25Nx_Buf_Write_Nx_Data各参数的定义或作用是啥?
为什么搞那么多i ...

上面贴的那个是为了测试是不是分别存储能好一点,我把现在的工程上传你看看,现在最多存过几万,因为太多会莫名崩掉
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 11:56:51 | 显示全部楼层
LcwSwust 发表于 2024-11-13 09:28
不知你是否了解它的读\写\擦除功能?
W25Nx_Buf_Write_Nx_Data各参数的定义或作用是啥?
为什么搞那么多i ...

怎么直接传压缩包啊,好像只能贴代码
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-13 11:58:36 | 显示全部楼层
meihua 发表于 2024-11-13 11:56
怎么直接传压缩包啊,好像只能贴代码

高级模式添加附件
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 12:01:11 | 显示全部楼层
  1. //写入起始地址为:块地址BlockAddr(0~1023),页地址PageAddr(0~63),具体字节地址BytesAddr(0~2047)的连续Size个数据,数据个数(0~65535)
  2. w25n_status_t W25Nx_Buf_Write_Nx_Data(uint8_t *pData, uint16_t BlockAddr, uint8_t PageAddr, uint16_t BytesAddr, uint16_t Size)
  3. {
  4.         uint8_t cmd[7];
  5.         uint16_t i;

  6.         uint8_t Page_data[2060];
  7.         /* Configure the command */
  8.         cmd[0] = WRITE_DATA_CMD;   //0x02                             //数据装入缓冲区命令
  9.         cmd[1] = (uint8_t)((BytesAddr >> 8) & 0x07);
  10.         cmd[2] = (uint8_t)(BytesAddr & 0xFF);
  11.        
  12.         cmd[3] = WRITE_INPUT_PAGE_ADDR_CMD;   //0x10                  //程序执行,写入主存区命令
  13.         cmd[4] = Dummy_Byte;
  14.         cmd[5] = (uint8_t)((BlockAddr >> 2) & 0xFF);           //主存区页地址
  15.         cmd[6] = (uint8_t)(((BlockAddr << 6)+PageAddr) & 0xFF);
  16.        

  17.        
  18.         //先赋三个命令在开头
  19.                 for(i=0;i<3;i++)         
  20.                 {
  21.                         Page_data[i] = cmd[i];
  22.                 }

  23.                 for(i=3;i<(Size + 3);i++)          //存储页数据
  24.                 {
  25.                         Page_data[i] = *pData;
  26.                         pData++;               
  27.                 }
  28.                
  29.                
  30.                 W25Q32_CS_CLR();
  31.                 if(ald_spi_send_byte_fast(&h_spi, WRITE_ENABLE_CMD) != OK)
  32.                 {
  33.                         W25Q32_CS_SET();
  34.                         return W25N_ERROR;
  35.                 }
  36.                 W25Q32_CS_SET();
  37.                
  38.                 md_delay_us(100);
  39.                 W25Q32_CS_CLR();
  40.                 for(i=0;i<(Size + 3);i++)
  41.                 {
  42.                         if (ald_spi_send_byte_fast(&h_spi, Page_data[i]) != OK)
  43.                         {
  44.                                 W25Q32_CS_SET();
  45.                                 return W25N_ERROR;
  46.                         }
  47.                 }
  48.                 W25Q32_CS_SET();
  49.                         md_delay_us(100);
  50.                 //md_delay_1ms(10);
  51.                 W25Q32_CS_CLR();
  52.                 for(i=3;i<7;i++)//写剩余指令
  53.                 {
  54.                         if (ald_spi_send_byte_fast(&h_spi, cmd[i]) != OK)
  55.                                 {
  56.                                         W25Q32_CS_SET();
  57.                                 }
  58.                 }


  59.                 W25_Wait_Busy();
  60.         W25Q32_CS_SET();
  61.                 return W25N_OK;

  62.        
  63.        
  64. }

  65. /***********************************************************************************************
  66. **     name: W25_PageDataRead
  67. ** function: 读取指定页地址的数据,并移动到缓冲区
  68. **parameter: BlockAddr 写入的块地址(0-1023)
  69.              PageAddr  写入的页地址(0-63)  
  70. **   return: void

  71. ************************************************************************************************/

  72. void W25_PageDataRead(uint16_t BlockAddr,uint8_t PageAddr)
  73.         {
  74.                 uint16_t i = 0;

  75.                 uint8_t cmd[4];
  76.        

  77.         cmd[0] = PAGE_READ_CMD;                                           //主存区页数据传至缓冲区
  78.         cmd[1] = Dummy_Byte;
  79.         cmd[2] = (uint8_t)((BlockAddr >> 2) & 0xFF);                      //页地址
  80.         cmd[3] = (uint8_t)(((BlockAddr << 6)|PageAddr) & 0xFF);        
  81.         W25Q32_CS_CLR();   
  82.                 if (ald_spi_send_byte_fast(&h_spi, PAGE_READ_CMD) != OK) {
  83.                 W25Q32_CS_SET();       
  84.         }
  85.             for (i = 0; i < 4; i++)
  86.         {
  87.                 if (ald_spi_send_byte_fast(&h_spi, cmd[i]) != OK) {
  88.                         W25Q32_CS_SET();
  89.                 }
  90.         }                           
  91.         W25Q32_CS_SET();       
  92.                 W25_Wait_Busy();
  93. }
  94.         /***********************************************************************************************
  95. **     name: W25_Read
  96. ** function: 读取SPI FLASH,在指定地址开始读取指定长度的数据
  97. **parameter: pBuffer 数据存储区
  98.              BytesAddr 写入的具体字节地址(0-1023)
  99.                                                  BlockAddr 写入的块地址(0-1023)
  100.              PageAddr  写入的页地址(0-63)
  101.              NumByteToWrite 要写入的数据个数(0-65535),该数不应该超过该页的剩余字节数!!!
  102. **   return: void
  103. 需要改造,和W25N.C文件里可以写多页的函数整合
  104. ************************************************************************************************/
  105. void W25_Read(uint8_t* pBuffer,uint16_t BlockAddr,uint8_t PageAddr,uint16_t BytesAddr,uint16_t NumByteToRead)
  106.         {
  107.        
  108.         uint16_t i = 0;
  109.                 uint8_t cmd[4];
  110.        
  111. int r_flag = 0;
  112.         cmd[0] = READ_CMD;                                                //读出缓冲区数据
  113.         cmd[1] = (uint8_t)((BytesAddr >> 8) & 0x07);
  114.         cmd[2] = (uint8_t)(BytesAddr & 0xFF);
  115.         cmd[3] = Dummy_Byte;
  116.        
  117.         W25_PageDataRead(BlockAddr,PageAddr);                  //先读取页地址数据,送到缓冲区
  118.                 md_delay_1ms(10);
  119.        
  120.                 W25Q32_CS_CLR();                                              //使能器件  
  121.          for (i = 0; i < 4; i++)
  122.         {
  123.                 if (ald_spi_send_byte_fast(&h_spi, cmd[i]) != OK) {
  124.                         W25Q32_CS_SET();
  125.                 }
  126.         }
  127.         for(i = 0; i < NumByteToRead; i++){  
  128.                 pBuffer[i] = ald_spi_recv_byte_fast(&h_spi, &r_flag);                  //循环读数  
  129.        
  130.         if (r_flag != OK) {
  131.                         W25Q32_CS_SET();
  132.                        
  133.                 }
  134.         }
  135.        
  136.                 W25Q32_CS_SET();                                         
  137. }  
  138. void vol_made(void)//关闭-转换的数据存储-开启转换    外部音频输入
  139. {       
  140. //        uint8_t j,i;//,music_buf1[15000]
  141. //        uint16_t k;
  142.         if(voctype==3&&PPT_in[0]==0)//此时录得是前导音
  143.         {

  144.                 while(PPT_in[0]==0        )//暂时用这个当判断条件    麦克风输入音频record_readay==2
  145.                 {               
  146.                         md_delay_us(10);
  147.                         music_buf[mus]=(_env.buf[5]&0x0f00)>>8;//      比如 0x0c7a  music_buf[0]=0x0c  music_buf[1]=0x7a   后面再拼接起来
  148.                         music_buf[mus+1]=_env.buf[5]&0x00ff;               
  149.                         if(mus>2000)
  150.                         {       
  151.                                 W25Nx_Buf_Write_Nx_Data( music_buf,  0, mus3,  0,  2000);       
  152.                                 mus3++;
  153.                                 mus=0;
  154.                         }

  155.                         mus=mus+2;               
  156.                         if(mus3>2)
  157.                         {
  158.                                 mus3=0;
  159.                         record_readay=5;
  160.                                 break;
  161.                         }
  162.                 }
  163.        
  164.                 if(record_readay==5)
  165.                 {       
  166.                         record_readay=3;
  167.                         keepvideo_led(1,OFF);
  168.                         keepvideo_led(3,OFF);
  169.                         }
  170.                 if(voc_in[2]==0)
  171.                 {
  172.                         mus=0;
  173.                         record_readay=3;
  174.                 }
  175.         }
  176. //        if(voctype==1||voctype==2)
  177. //        {
  178. //                 if(PPT_in[0]==1&&ch_env[6].vol>0)//此时是外部输入音频          只要开始录音,就把此时的转换后的数值当做第1位开始存储
  179. //                {
  180. //                                        music_buf[mus]=ch_env[6].vol|0x0fff;//45us左右存一个值,0x0fff
  181. //                                                mus++;
  182. //                        if(voc_in[2]==0)//只要按下停止键,数组就不再继续存[img]https://pica.zhimg.com/v2-cb0d564789c96e1c16887ca65b696f06_r.jpg[/img]?source=1def8aca
  183. //                                        {
  184. //                                                record_readay=3;
  185. //                                                mus=0;
  186. //                                        }
  187. //                }
  188. //        }
  189.                
  190. }
复制代码
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 12:40:53 | 显示全部楼层
这是我写的整体的代码,那些H文件啥的容量太大了传不了

Projects.rar

85.66 KB, 下载次数: 1

代码

回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 12:41:27 | 显示全部楼层
LcwSwust 发表于 2024-11-13 11:58
高级模式添加附件

上传了,你看一下吧
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-13 14:37:58 | 显示全部楼层
meihua 发表于 2024-11-13 12:41
上传了,你看一下吧

我好像打不开工程,可能我的KEIL版本有点低.
目前只找到一个问题,W25_PageDataRead里多写了一个字节PAGE_READ_CMD,你看是不是这问题:
(正如正点原子所说,得检查底层驱动)
傲游截图20241113143448.jpg
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 15:20:45 | 显示全部楼层
LcwSwust 发表于 2024-11-13 14:37
我好像打不开工程,可能我的KEIL版本有点低.
目前只找到一个问题,W25_PageDataRead里多写了一个字节PAGE_ ...

方便加个微信吗,沟通方便一点,这个地方我昨天改了测试来着,然后我一去掉第一个使能,读取就出问题,要么是0要么是别的,没办法只能又改回来了
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-13 15:30:08 | 显示全部楼层
meihua 发表于 2024-11-13 15:20
方便加个微信吗,沟通方便一点,这个地方我昨天改了测试来着,然后我一去掉第一个使能,读取就出问题,要 ...

就在这聊挺好的.
怎么能去掉第一个呢.
建议把344\345\346行去掉.
做个简单的测试,比如定义一个32位变量,
把这个变量存入数组,存一个就加1,存满一页就向W25写入一页,
写两页(或更多页)然后读出来,发到串口调试助手,看看对不对.
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 15:50:55 | 显示全部楼层
LcwSwust 发表于 2024-11-13 15:30
就在这聊挺好的.
怎么能去掉第一个呢.
建议把344\345\346行去掉.

你看,这是我把那几行删了之后的区别,ff的是删掉的,正常读取了的是没删的
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-13 16:20:58 | 显示全部楼层
meihua 发表于 2024-11-13 15:50
你看,这是我把那几行删了之后的区别,ff的是删掉的,正常读取了的是没删的

奇怪,图片一直转圈圈,啥也看不到,是文件太大了吗?
是否在高级模式下上传图片或附件?
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-13 16:28:40 | 显示全部楼层
LcwSwust 发表于 2024-11-13 16:20
奇怪,图片一直转圈圈,啥也看不到,是文件太大了吗?
是否在高级模式下上传图片或附件?

我看着也是转圈圈,但是点进编辑就能正常看。。。奇怪,我再发一遍。这是我把那几行删了之后的区别,ff的是删掉的,正常读取了的是没删的

下载 (1).png
下载.png
download.png
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-13 17:03:14 | 显示全部楼层
本帖最后由 LcwSwust 于 2024-11-13 17:05 编辑
meihua 发表于 2024-11-13 16:28
我看着也是转圈圈,但是点进编辑就能正常看。。。奇怪,我再发一遍。这是我把那几行删了之后的区别,ff的 ...

这次能看到图了,虽然按你的说法确实有问题,但是还是建议用示波器看看波形,确定ald_spi_send_byte_fast函数执行完毕时,数据有没发送完成(SCK);
有些程序为了省时间就只是把数据丢给SPI但没等待发送完成就退出函数了,也就没管MOSI接收的数据,
如果不了解这情况可能造成数据错位。
(比如这样测:CS置低,发送一字节,CS置高,用示波器两通道同时监测CS、SCK)
还有个建议,若不能确定硬件SPI的特性,建议先用软件模拟SPI。

问题多半就在这一块了。

专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 09:10:02 | 显示全部楼层
LcwSwust 发表于 2024-11-13 17:03
这次能看到图了,虽然按你的说法确实有问题,但是还是建议用示波器看看波形,确定ald_spi_send_byte_fast ...

有点晕。。我看波形怎么clk没有波形,然后di也没有,不应该啊,那这是怎么传输了的,这是它自带的传输函数,cs只能在断点处看到电压高低电平变了,我把时间量程调大了也没有。。
int32_t ald_spi_send_byte_fast(spi_handle_t *hperh, uint8_t data)
{
        uint16_t cnt = 5000, temp;

        while(hperh->perh->STAT & SPI_STAT_TXF_MSK);
        hperh->perh->DATA = data;
        while (((hperh->perh->STAT & SPI_STAT_TXE_MSK) == 0) && (--cnt));

        cnt = 5000;
        while (((hperh->perh->STAT & SPI_STAT_RXE_MSK) == SPI_STAT_RXE_MSK) && (--cnt));
        temp = hperh->perh->DATA;
        UNUSED(temp);

        return cnt == 0 ? -1 : 0;
}
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-14 09:45:13 | 显示全部楼层
本帖最后由 LcwSwust 于 2024-11-14 09:58 编辑
meihua 发表于 2024-11-14 09:10
有点晕。。我看波形怎么clk没有波形,然后di也没有,不应该啊,那这是怎么传输了的,这是它自带的传输函 ...

那得好好检查一下,一定要保证各个信号(CS\SCK\MOSI\MISO)都正常才行。
我不熟悉这单片机,看这函数的意思是有等待发送完成、接收完成才退出函数,
但不知为什么会有个“fast”名称,按我的理解,这只是一般速度或常规操作,想要fast则应是只有两步:
1.等待发送缓冲区有空;
2.往DATA写入数据;
我在GD32F303里就是这么写的:
  1. //写数据不等待读取,可加快速度,数据之间无间断
  2. void SPI0_SendByte_F(U8 d)
  3. {
  4.         while((SPI_STAT(SPI0)&SPI_FLAG_TBE)==0);//等待发送缓冲区空        
  5.         SPI_DATA(SPI0)=d;
  6. }
复制代码



专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 10:18:17 | 显示全部楼层
LcwSwust 发表于 2024-11-14 09:45
那得好好检查一下,一定要保证各个信号(CS\SCK\MOSI\MISO)都正常才行。
我不熟悉这单片机,看这函数的意 ...

这是这段程序的波形。。感觉这clk这么奇怪呢
1735339beee1aa767f5ace83203fb91.jpg
1731550523501.png
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 10:37:57 | 显示全部楼层
LcwSwust 发表于 2024-11-14 09:45
那得好好检查一下,一定要保证各个信号(CS\SCK\MOSI\MISO)都正常才行。
我不熟悉这单片机,看这函数的意 ...

我最新抓的波形,我把发送速度降到最低了抓的

这是发送函数

这是发送函数

这是第一个接收函数

这是第一个接收函数

这是第二个接收函数

这是第二个接收函数
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-14 11:17:00 | 显示全部楼层
meihua 发表于 2024-11-14 10:37
我最新抓的波形,我把发送速度降到最低了抓的

1通道测的CS?2通道测的SCK?

每格10ms,采样率较低,看不到细节,建议调到每格10us或更小,
另外单独写个函数,只保留284~290行,就测这一个函数。
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 13:08:13 | 显示全部楼层
LcwSwust 发表于 2024-11-14 11:17
1通道测的CS?2通道测的SCK?

每格10ms,采样率较低,看不到细节,建议调到每格10us或更小,

我试了一下,直接抓不到波形了,只能在中间加了几十毫秒才能看到,clk抓不住                W25Q32_CS_CLR();                md_delay_1ms(20);
                if(ald_spi_send_byte_fast(&h_spi, WRITE_ENABLE_CMD) != OK)
                {
                        W25Q32_CS_SET();
                        return W25N_ERROR;
                }
                W25Q32_CS_SET();

单个.jpg
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 13:21:55 | 显示全部楼层
LcwSwust 发表于 2024-11-14 11:17
1通道测的CS?2通道测的SCK?

每格10ms,采样率较低,看不到细节,建议调到每格10us或更小,

得把后面的一部分放开,才能抓到clk
W25Q32_CS_CLR();
                md_delay_1ms(5);
                if(ald_spi_send_byte_fast(&h_spi, WRITE_ENABLE_CMD) != OK)
                {
                        W25Q32_CS_SET();
                        return W25N_ERROR;
                }
                W25Q32_CS_SET();
//                md_delay_1ms(10);
                md_delay_us(100);
                W25Q32_CS_CLR();
                for(i=0;i<(Size + 3);i++)
                {
                        if (ald_spi_send_byte_fast(&h_spi, Page_data) != OK)
                        {
                                W25Q32_CS_SET();
                                return W25N_ERROR;
                        }
                }
                W25Q32_CS_SET();

发数据.jpg
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-14 13:38:36 | 显示全部楼层
meihua 发表于 2024-11-14 13:21
得把后面的一部分放开,才能抓到clk
W25Q32_CS_CLR();
                md_delay_1ms(5);

此时示波器采样率较低,就算SCK有波形(可能就几微秒)也可能采不到。
这么看来,你的硬件SPI可能没有正确运行。
建议用软件模拟SPI,波形应类似于下图:
傲游截图20241114133801.jpg
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 13:40:07 | 显示全部楼层
LcwSwust 发表于 2024-11-14 13:38
此时示波器采样率较低,就算SCK有波形(可能就几微秒)也可能采不到。
这么看来,你的硬件SPI可能没有正 ...

我刚发现件事,我之前是放在初始化中读取,我试了下放在主循环里一直执行读函数,波形是这样的
循环.png
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-14 13:53:59 | 显示全部楼层
meihua 发表于 2024-11-14 13:40
我刚发现件事,我之前是放在初始化中读取,我试了下放在主循环里一直执行读函数,波形是这样的

这波形算是正常的SPI波形。
也就是之前你是还没初始化SPI就在向SPI发送数据?
专治疑难杂症
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-14 14:07:14 | 显示全部楼层
建议再研究一下W25N的手册,看看极性、相位等应该怎么配置。
建议SCK设置为默认低电平。
然后读取器件ID看是否正确,再写入、读取数据看是否一致。
傲游截图20241114140351.jpg
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 14:20:37 | 显示全部楼层
LcwSwust 发表于 2024-11-14 13:53
这波形算是正常的SPI波形。
也就是之前你是还没初始化SPI就在向SPI发送数据?

之前是初始化紧挨着就发数据,然后现在波形看着是正常,我想着是不是spi的配置问题,我看着说明书上是这样的(如图)我就改成了第一个跳变沿读取,h_spi.perh           = SPI1;        h_spi.init.mode      = SPI_MODE_MASTER;//设置SPI工作模式:设置为主SPI
        h_spi.init.dir       = SPI_DIRECTION_2LINES;//SPI设置为双线双向全双工
        h_spi.init.data_size = SPI_DATA_SIZE_8;//设置SPI的数据大小:SPI发送接收8位帧结构   暂定,待改
        h_spi.init.baud      = SPI_BAUD_256;
        h_spi.init.phase     = SPI_CPHA_FIRST;//串行同步时钟的第二个跳变沿(上升或下降)数据被采样
        h_spi.init.polarity  = SPI_CPOL_LOW;//串行同步时钟的空闲状态为高电平
        h_spi.init.first_bit = SPI_FIRSTBIT_MSB;//指定数据传输从MSB位还是LSB位开始:数据传输从MSB位开始
        h_spi.init.ss_en     = DISABLE;
        h_spi.init.crc_calc  = DISABLE;
然后不多发使能,还是没法正常读取,之前多发一个使能的时候,是第二个跳变沿读取,平时高电平波形是这样,就能正常读取,看不出有啥区别


11.png
多发使能.jpg
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 14:23:18 | 显示全部楼层
LcwSwust 发表于 2024-11-14 14:07
建议再研究一下W25N的手册,看看极性、相位等应该怎么配置。
建议SCK设置为默认低电平。
然后读取器件ID ...

你看这是clk平时低电平的
3.jpg
22.jpg
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 14:56:09 | 显示全部楼层
LcwSwust 发表于 2024-11-14 14:07
建议再研究一下W25N的手册,看看极性、相位等应该怎么配置。
建议SCK设置为默认低电平。
然后读取器件ID ...

我试了读id,然后id读出来了,存储的数还是全ff。。更懵了
uint32_t meter_bsp_spi_flash_read_id(void)
{

        int r_flag = 0;

  uint32_t JEDECID = 0;
  W25Q32_CS_CLR();
        ald_spi_send_byte_fast(&h_spi, 0x9f);
ald_spi_send_byte_fast(&h_spi, 0x00);
JEDECID +=ald_spi_recv_byte_fast(&h_spi,&r_flag);

  JEDECID <<= 8;
  JEDECID +=ald_spi_recv_byte_fast(&h_spi, &r_flag);
  JEDECID <<= 8;
  JEDECID +=ald_spi_recv_byte_fast(&h_spi,&r_flag);
  W25Q32_CS_SET();
  return JEDECID;
}

id.png
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 2024-11-14 15:08:35 | 显示全部楼层
meihua 发表于 2024-11-14 14:23
你看这是clk平时低电平的

区别嘛,数据个数不一样呗。
还有就是,可以用一个通道测SCK,另一个通道测DI或DO看数据对不对。
另外我发现你程序中GPIO初始化之前就在操作W25N,确定没问题?
一般要在GPIO、SPI等片内外设都初始化完成后再来操作外部设备。

傲游截图20241114145829.jpg
傲游截图20241114145152.jpg
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 2024-11-14 17:12:35 | 显示全部楼层
LcwSwust 发表于 2024-11-14 15:08
区别嘛,数据个数不一样呗。
还有就是,可以用一个通道测SCK,另一个通道测DI或DO看数据对不对。
另外 ...

没问题,不同功能的引脚我是分开初始化的,然后我现在对比波形 ,写数据看着是对的,读取还是没搞明白,然后发现有个新问题就是比如我在地址0-5写了5个数,又在6-10写了5个数,读取的时候0-5的变成ff了。。
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 7 天前 | 显示全部楼层
本帖最后由 LcwSwust 于 2024-11-15 09:13 编辑
meihua 发表于 2024-11-14 17:12
没问题,不同功能的引脚我是分开初始化的,然后我现在对比波形 ,写数据看着是对的,读取还是没搞明白, ...

你看看手册里这两个指令的区别:
傲游截图20241115090904.jpg

傲游截图20241115091123.jpg

再查查"WRITE_INPUT_PAGE_ADDR_CMD"存了多少字节
专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 7 天前 | 显示全部楼层
LcwSwust 发表于 2024-11-15 09:11
你看看手册里这两个指令的区别:

写入.jpg 我看了下是02没错,我看这介绍是会把没使用的字节重置为ff,但是已经存储进去了读的时候还是ff,那可能是读的这个缓存区了对吧,我先改成84H试试随机加载程序
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 7 天前 | 显示全部楼层
LcwSwust 发表于 2024-11-15 09:11
你看看手册里这两个指令的区别:

我改成0x84之后在读取是正常的,改回02还是那样,然后我去删了一条读取使能,保持0x02,现在接收正常了。。好奇怪,也没改别的,就是把设定缓冲读取放在初始化中的函数解除屏蔽了,不知道是不是暂时的,我试试在其他地方应用
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 7 天前 | 显示全部楼层
meihua 发表于 2024-11-15 11:04
我改成0x84之后在读取是正常的,改回02还是那样,然后我去删了一条读取使能,保持0x02,现在接收正常了。 ...

专治疑难杂症
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 7 天前 | 显示全部楼层

还有个问题就是正常来说一页有2048个字节能存,但是我存超过2000(大多数时候)都会直接进入故障死循环,我找到进入故障的点是写入函数最后一句(走完括号直接进循环了)
死循环.png
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 7 天前 | 显示全部楼层
meihua 发表于 2024-11-15 14:04
还有个问题就是正常来说一页有2048个字节能存,但是我存超过2000(大多数时候)都会直接进入故障死循环, ...

数组应该也不能超吧,我查着这故障一般是什么数组超了,地址太多啥的,但是缓存数组和全局变量数组都是大的。。。
回复

使用道具 举报

6

主题

45

帖子

0

精华

初级会员

Rank: 2

积分
80
金钱
80
注册时间
2020-8-10
在线时间
20 小时
 楼主| 发表于 7 天前 | 显示全部楼层
LcwSwust 发表于 2024-11-15 14:17
这种情况通常是因为堆栈溢出,由于局部变量一般是放在堆栈中的,所以建议局部变量不要占用太多空间,
局部 ...

拿出来就好了,我把堆栈都改大了试了还不行,就直接把他设置成全局变量了,试了可以,我之前以为是存储设的那个全局变量占用太大了,改了好几次也不行。。。
回复

使用道具 举报

10

主题

3280

帖子

1

精华

论坛元老

Rank: 8Rank: 8

积分
8182
金钱
8182
注册时间
2020-5-11
在线时间
3694 小时
发表于 7 天前 | 显示全部楼层
meihua 发表于 2024-11-15 15:05
拿出来就好了,我把堆栈都改大了试了还不行,就直接把他设置成全局变量了,试了可以,我之前以为是存储设 ...

哦,所有的问题已经解决了吗?
专治疑难杂症
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-11-22 01:34

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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