littlestone08 发表于 2024-4-11 19:18:22

RL-FLASHFS +W25Q64,F103与F407使用表现差别巨大,找不到原因求助

本帖最后由 littlestone08 于 2024-4-11 19:41 编辑

使用W25Q64,
KEIL4 +MDK4,使用标准库,照参考的代码写了驱动后,基本上没有遇到什么问题,运行自带的File_ex1例子,状态非常好。
于是,同样的代码换成STM32F407, 单片机,连引脚名都没有换,结果就悲剧了,表现如下:

[*]运行"dir"命令时非常慢,文件越大越慢,发现是最终是调用了"ffind"最后到驱动的ReadData函数,似乎是把文件的所有内容都枚举了一遍,最要命的是ReadData读一次只读4字节或8字节,但同样在STM32F103上,也是4字节或8字节的调用,就非常快。经过打印驱动调用过程信息对比,M4的单片机上,似乎枚举了文件的所有内容,而F103上只枚举了需要的部分。
[*] 运行"type"命令(程序中逐个字符读取),同样的情况,F103,瞬间读完1000行文本,而F407则是肉眼可见的慢的速度在打印(使用的是SEGGER RTT,非阻塞SKIP)
[*] F103建立好1000行的文本,拆下芯片放到F407的板子上,仅读取和列出,速度依然很慢。而F407建立好的文件的芯片,放到F103的板子上,速度也很快,说明不是芯片上存储内容差异引起的,进一步推论F407的驱动的代码应该也是没有问题的,要不然,把W25Q64换到F103的板子上,多少会出现问题。
[*] 怀疑M3和M4链接的代码不同,但是因为不是开源,也没有办法验证,于是换了KEIL5+RTE+CUBEMX方式,重新实现了一遍,以为能解决问题,折腾好几天,跑通了,在F407上速度与KEIL4上一样的慢。

抓狂了。Q网络上搜索,似乎RL-FLASH +NOR的贴子并不多,更不用说F407指定型号。Q

以上对比是在相同级别的SPI时钟速度上对比(示波器对比),按说,相同的开发环境,库版本,相同的开发环境和驱动,不应该出现这么大的差别。不知道有没有大佬遇到过可以指点一下或讨论下。

如果有需要,我可以贴出代码或以附件的形式给出完整的工程,在此多谢:handshake

littlestone08 发表于 2024-4-12 08:52:14

看来是发错版块了,看到有一个专门的“文件系统”的版本块,管理如果能挪一下位置最好了。

“文件系统”的那一块也浏览了一个遍,也说EFS有慢的问题,但应该都是可以接受的那种,而我的这个F407上是出奇的不正常。
今天早上又试了一下F103的速度非常的正常,多创建几个“大文件”也是很不错

eric2013 发表于 2024-4-12 09:35:40

F4系列确实没有做SPI Flash的FlashFS例子,方便的话,分享你的工程看下。标准库版的就行。

littlestone08 发表于 2024-4-12 10:50:50

本帖最后由 littlestone08 于 2024-4-12 11:38 编辑

感谢老大回复, 附件如下:

[*]Src_FromSS.zip:项目包,为了减少影响,删减了很多无关的功能,只留下RTT输出,用了RTOS。
[*]comm.zip: 为了方便项目公用RTT,打包在COMM中,项目中打开后可能需要重新修改下里面引用文件的路径。

里面的东西基本上都是F103移过来的,尤其是驱动文件,就担心有些许的不同可能会造成影响。

前两天不知道怎么回事,在SPI长时间访问的时候(比如,执行DIR命令,SPI总线上不停的发出命令),RTT输出就乱了,感觉好像是把缓冲中的数据无规律的发送出来, 不知道如何解决,可能会影响您调试。
-----------
刚抓的效果,与上一个F103的效果对比。可以看到:


[*]建立了三个小文件,就已经无法使用了;
[*]DIR命令输出的时候,越到后面越慢得无法忍受,而且RTT不停的乱输出,我猜测可能是代码中有什么问题,因为这个问题是突然出现的,原来也是同样的慢,也拿不准是不是有关联?
[*]TYPE打印输出时,输出时间越长,每个字符输出速度越慢,1000行的数据时间太久,没法做动图上传上来。
[*]在KEIL5+RTE中,也是同样的慢,但直接使用驱动函数访问存储时明显没有什么问题,速度是可以的。
---------------
老大的回复让我又看见曙光,希望可以有时间指点一番,如果确实不行,我也就死心了:'(

littlestone08 发表于 2024-4-12 11:19:33

本帖最后由 littlestone08 于 2024-4-12 11:52 编辑

这个图是KEIL5+RTE+DRIVER的形式,使用DIR命令的效果要稍快一点,(KEIL4中 DIR执行后,如果有1000行的数据文件, 会等至少20分钟才能输出),但与F103那个表现正常的比起来,还是差太多了,。
做了一个直接使用DRIVER中的ReadData读数据的功能,看显示的速度来说,函数本身应该是没问题的,DIR命令表现也比KEIL4中的要稍好一点点,但也是不正常。
打印的时候,似乎是越到后面输出越慢,难道是每输出一个字符的时候,都是把前面的都读出来?

(图中有RTT抽风式的间歇输出,会影响分析,请海涵)
-------------

附图

eric2013 发表于 2024-4-13 09:09:27

littlestone08 发表于 2024-4-12 10:50
感谢老大回复, 附件如下:

[*]Src_FromSS.zip:项目包,为了减少影响,删减了很多无关的功能,只留下RTT ...

有一种情况不知道你排查了没,标准库使用MDK4里面的FlashFS可以方便的裸机测试,测试过裸机方式没。

littlestone08 发表于 2024-4-13 11:16:53

没有试,意思是有可能是任务的优先级太低?所以会慢?我抽空就去试一下。测试完了及时反馈,感谢提供思路。

-----------------------------------------
另外,M4和M3的CAN控制器的寄存器应该是差不多的用法吧?我粗粗看了一下手册,应该没有什么特别注意的地方吧?

littlestone08 发表于 2024-4-14 10:52:27

eric2013 发表于 2024-4-13 09:09
有一种情况不知道你排查了没,标准库使用MDK4里面的FlashFS可以方便的裸机测试,测试过裸机方式没。

已经测试过下面的过程


[*]Keil4裸机执行问题表象无改善
[*]降低过SPI频率,现象无改善
[*]Keil5+MDK5+RTOS2去掉过OS无改善(因为FS-FLASHFS与OS绑定,也是预料之内)
[*]直接使用驱动函数读取数据,无错误数据,速度也很快
[*]以前Keil4中也使用标准库函数实现的替换掉现在使用的寄存器方式的写法,现象相同,所以后来测试都是以寄存器驱动文件为主

-----------
现在经过测试,又设置下面的场景进行测试:
   都使用KEIL4环境,F103与F407都格式化,并增加一个10行的小文本文件,保证芯片内容相同,并使用TYPE命令输出,记录ReadData驱动函数的调用次数
现象总结:
日志输出格式为[时间]RdDat:[目标地址]-[长度]...[结束时间OK

[*]初始化文件系统时,调用的ReadData次数相同(正常)
[*]使用的输出函数相同,都是使用putchar单个字符输出,但103的输出是整个文件内容输出了,而F407是与驱动调用部分混合的(不知道为什么)
[*]二者格式化调用EraseSection过程相同(正常)
[*]读取目标文件并打印输出,F407调用ReadData的次数不正常的多。(不正常)
[*]DIR命令时,F407调用ReadData的次数不正常的过多(不正常)
[*]数据量过大后,RTT输出紊乱(不正常)
[*]二块电路板,把W25Q64拆下来互换,重复测试,现象相同(以前也测试过,但是没有记录日志,这次是为了保存RTT日志)



个人分析:

[*]每个字符输出(每个字符在FLASH中占4个字节),似乎都是重新从最原始的SECTOR读取,逐个枚举直到找到目标字符,即想读取第3个字符,似乎有点像链表,不访问前面就访问不了后面,文件中越是到后面的内容,越是读取的次数多。
[*]数一下读取第一个字符,调用了5次ReadData,第二个字符6次,第三个字符7次,佐证分析的第1点,而F103的文件中则没有这样的规划
[*]第7次读取时,F103读取了320个字符,而F407仅读取了1个字符,似乎是F103的程序启用了某种缓存机制,而F407则只是字节直接读FLASH(没有能力分析文件的数据结构)


附件中在完整的TYPE 10.TXT命令后的RTT记录输出。关键点应该是这里望老大分析下。



littlestone08 发表于 2024-4-14 11:04:20

本帖最后由 littlestone08 于 2024-4-14 19:47 编辑

eric2013 发表于 2024-4-13 09:09
有一种情况不知道你排查了没,标准库使用MDK4里面的FlashFS可以方便的裸机测试,测试过裸机方式没。
因为去掉RTX和不去掉没有什么区别,所以继续使用OS进行测试,由于看现象是因为F407未使用缓存,尝试各任务STACK多增加了1K,Startup.s文件中的定义也增加了一倍,但运行后是问题现象依旧,没有任何改善。

RL-FLASH中NOR的选项很少,尝试找有没有BUFFER开关类似设置的地方,但尝试无果

eric2013 发表于 2024-4-16 08:47:20

littlestone08 发表于 2024-4-13 11:16
没有试,意思是有可能是任务的优先级太低?所以会慢?我抽空就去试一下。测试完了及时反馈,感谢提供思路。 ...

F1和F4的CAN一样。

eric2013 发表于 2024-4-16 08:50:18

littlestone08 发表于 2024-4-14 11:04
因为去掉RTX和不去掉没有什么区别,所以继续使用OS进行测试,由于看现象是因为F407未使用缓存,尝试各任 ...

驱动上还有一个地方可以看下,就是你看下F4的SPI Flash驱动底层设计,他的SPI上拉电阻使能没。可以使能了试试。

littlestone08 发表于 2024-4-20 16:16:23

eric2013 发表于 2024-4-16 08:50
驱动上还有一个地方可以看下,就是你看下F4的SPI Flash驱动底层设计,他的SPI上拉电阻使能没。可以使能了 ...

还真没有注意W25Q芯片有上拉电阻使能的地方,我现在就去看手册。

littlestone08 发表于 2024-4-20 16:27:53

本帖最后由 littlestone08 于 2024-4-20 16:52 编辑

eric2013 发表于 2024-4-16 08:50
驱动上还有一个地方可以看下,就是你看下F4的SPI Flash驱动底层设计,他的SPI上拉电阻使能没。可以使能了 ...
因为修改帖子需要等审核出来,我直接再回复一下。
刚才应该是理解错了,应该说的是F4芯片的SPI接口上拉使能吧。初始化部分是用标准库写的,用的是带上拉的,按说应该没问题。

-----------------
另外,硬汉哥对8楼的那个调用ReadData函数的调用有什么看法吗?因为看起来F407上只会4字节4 字节的读,而且读下一个字符必须要先读出上一个字符,像是磁带的顺序存储一样,这个表现我感觉很关键,因为ReadData是被动调用的,而在F103上就不会这样,就是不知道为什么F407会这样。能抽空看一下?

eric2013 发表于 2024-4-21 00:47:18

littlestone08 发表于 2024-4-20 16:27
因为修改帖子需要等审核出来,我直接再回复一下。
刚才应该是理解错了,应该说的是F4芯片的SPI接口上拉 ...

你的F4系列底层也是用的类似这种代码吧

这个是FlashFS提供好的一个驱动

/*
*********************************************************************************************************
*
*      模块名称 : SPI驱动模块
*      文件名称 : SPI_STM32F103.c
*      版    本 : V1.0
*      说    明 : 本驱动是基于bsp_spi_bus.c文件实现。
*            (1)使用FlashFS的SPI FLASH文件系统前务必先调用初始化函数bsp_InitSPIBus(在函数bsp.c中初始化)。
*            (2)本文件使用的是官方模板,用户只需添加函数功能即可,故不对变量定义和函数名做重新规范。
*            
*      修改记录 :
*                版本号日期      作者   说明
*                V1.0    2015-09-09 Eric2013正式发布
*
*      Copyright (C), 2015-2020, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/
#include <File_Config.h>
#include "bsp.h"


/*
**********************************************************************************************************
                                                                                        宏定义
**********************************************************************************************************
*/
/*
   SPI 驱动定义
   spi0_drv: 第一个SPI设备驱动
   spi1_drv: 第二个SPI设备驱动
*/

#define __DRV_IDspi0_drv
#define __FPCLK   72000000

/* SPI_SR位定义 */
#define RXNE    0x01
#define TXE   0x02
#define BSY   0x80
#define FPCLK   (__FPCLK/1000)

/* 串行Flsh的片选GPIO端口*/
#define SPI_SelectHard            SPI1
#define SF_RCC_CS                         RCC_APB2Periph_GPIOF
#define SF_PORT_CS                        GPIOF
#define SF_PIN_CS                        GPIO_Pin_11
#define SF_CS_0()                        SF_PORT_CS->BRR = SF_PIN_CS
#define SF_CS_1()                        SF_PORT_CS->BSRR = SF_PIN_CS

/*
**********************************************************************************************************
                                                                                        宏定义
**********************************************************************************************************
*/

/* SPI驱动接口函数 */
static BOOL Init (void);
static BOOL UnInit (void);
static U8   Send (U8 outb);
static BOOL SendBuf (U8 *buf, U32 sz);
static BOOL RecBuf (U8 *buf, U32 sz);
static BOOL BusSpeed (U32 kbaud);
static BOOL SetSS (U32 ss);

/* SPI 设备驱动控制块 */
SPI_DRV __DRV_ID = {
Init,
UnInit,
Send,
SendBuf,
RecBuf,
BusSpeed,
SetSS,
NULL
};


/*
*********************************************************************************************************
*      函 数 名: Init
*      功能说明: 初始化SPI设备,这里仅初始化了SPI Flash的片选,SPI初始化调用函数bsp_InitSPIBus()实现
*      形    参: 无
*      返 回 值: __TRUE
*********************************************************************************************************
*/
static BOOL Init (void)
{
      /*
          安富莱STM32-V4 开发板口线分配:串行Flash型号为 W25Q128 (104MHz)
          片选 PF8/SF_CS
      */
      GPIO_InitTypeDef GPIO_InitStructure;

      /* 使能GPIO 时钟 */
      RCC_APB2PeriphClockCmd(SF_RCC_CS, ENABLE);

      /* 配置片选口线为推挽输出模式 */
      SF_CS_1();                /* 片选置高,不选中 */
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_InitStructure.GPIO_Pin = SF_PIN_CS;
      GPIO_Init(SF_PORT_CS, &GPIO_InitStructure);
      return (__TRUE);
}

/*
*********************************************************************************************************
*      函 数 名: UnInit
*      功能说明: 卸载SPI设备,正常情况下此函数实现卸载需要将SPI接口设置为初始化状态,即未开启状态。
*             由于多个设备使用SPI接口,这里仅是将片选至高。
*      形    参: 无
*      返 回 值: __TRUE
*********************************************************************************************************
*/
static BOOL UnInit (void)
{
SF_CS_1();

return (__TRUE);
}

/*
*********************************************************************************************************
*      函 数 名: Send
*      功能说明: 发送一个字节数据
*      形    参: 无
*      返 回 值: SPI接口返回值
*********************************************************************************************************
*/
static U8 Send (U8 outb)
{
      /* 通过SPI接口读写一个字节 */
      SPI_SelectHard->DR = outb;

      /* 等待数据接收完毕 */
      while (!(SPI_SelectHard->SR & RXNE));
      return (SPI_SelectHard->DR);
}

/*
*********************************************************************************************************
*      函 数 名: SendBuf
*      功能说明: 通过SPI接口发送多个字节
*      形    参: buf 数据地址
*             sz发送数据大小
*      返 回 值: __TRUE
*********************************************************************************************************
*/
static BOOL SendBuf (U8 *buf, U32 sz)
{
      U32 i;

      for (i = 0; i < sz; i++)
      {
                SPI_SelectHard->DR = buf;
                /* 等待发送完成 */
                while (!(SPI_SelectHard->SR & TXE));
                SPI_SelectHard->DR;
      }
      
      /* 等待接收完成 */
      while (SPI_SelectHard->SR & (BSY | RXNE))
      {
                SPI_SelectHard->DR;
      }
      return (__TRUE);
}

/*
*********************************************************************************************************
*      函 数 名: RecBuf
*      功能说明: 通过SPI接口接收多个字节
*      形    参: buf 数据地址
*             sz接收数据大小
*      返 回 值: __TRUE
*********************************************************************************************************
*/
static BOOL RecBuf (U8 *buf, U32 sz)
{
      U32 i;

      for (i = 0; i < sz; i++)
      {
                SPI_SelectHard->DR = 0xFF;
                /* 等待接收完成 */
                while (!(SPI_SelectHard->SR & RXNE));
                buf = SPI_SelectHard->DR;
      }
      return (__TRUE);
}

/*
*********************************************************************************************************
*      函 数 名: BusSpeed
*      功能说明: 设置SPI速度,驱动SPI Flash使用的是18MHz
*      形    参: buf 数据地址
*             sz接收数据大小
*      返 回 值: __TRUE
*********************************************************************************************************
*/
static BOOL BusSpeed (U32 kbaud)
{
      U8 br;

      if      (kbaud >= FPCLK / 2)   br = 0;                     /* FPCLK/2    */
      else if (kbaud >= FPCLK / 4)   br = 1;                     /* FPCLK/4    */
      else if (kbaud >= FPCLK / 8)   br = 2;                     /* FPCLK/8    */
      else if (kbaud >= FPCLK / 16)br = 3;                     /* FPCLK/16   */
      else if (kbaud >= FPCLK / 32)br = 4;                     /* FPCLK/32   */
      else if (kbaud >= FPCLK / 64)br = 5;                     /* FPCLK/64   */
      else if (kbaud >= FPCLK / 128) br = 6;                     /* FPCLK/128*/
      else                           br = 7;                     /* FPCLK/256*/

      SPI_SelectHard->CR1 = (SPI_SelectHard->CR1 & ~(7 << 3)) | (br << 3);
      return (__TRUE);
}

/*
*********************************************************************************************************
*      函 数 名: BusSpeed
*      功能说明: 设置SPI速度,驱动SPI Flash使用的是18MHz
*      形    参: ss
*             0 表示选中设备
*             1 表示取消选中
*      返 回 值: __TRUE
*********************************************************************************************************
*/
static BOOL SetSS (U32 ss) {
      if(ss == 0)
      {
                bsp_SpiBusEnter();      /* 占用SPI总线, 用于总线共享 */
               
                bsp_SPI_Init(SPI_Direction_2Lines_FullDuplex | SPI_Mode_Master | SPI_DataSize_8b
                        | SPI_CPOL_High | SPI_CPHA_2Edge | SPI_NSS_Soft | SPI_BaudRatePrescaler_4 | SPI_FirstBit_MSB);
                SF_CS_0();
               
      }
      else
      {
                SF_CS_1();
                bsp_SpiBusExit();      /* 释放SPI总线, 用于总线共享 */
      }
      
return (__TRUE);
}

/***************************** 安富莱电子 www.armfly.com (END OF FILE) ********************************

littlestone08 发表于 2024-4-22 10:29:21

eric2013 发表于 2024-4-21 00:47
你的F4系列底层也是用的类似这种代码吧

这个是FlashFS提供好的一个驱动


感谢硬汉大佬。

我以前用过这个类似的代码试过,不过和我原来的效果不多,所以就还用我当前的代码试。

我现在用这个代码再试下,反馈结果上来。如果还不行,暂时放弃,想办法用下littleFS了。
页: [1]
查看完整版本: RL-FLASHFS +W25Q64,F103与F407使用表现差别巨大,找不到原因求助