数码之家

 找回密码
 立即注册
搜索
查看: 1518|回复: 11

[C51] STC15用硬件SPI读取W25Q64FV出错,求指教(已解决)

[复制链接]
发表于 2022-1-12 20:49:30 | 显示全部楼层 |阅读模式
本帖最后由 aqxgm 于 2022-1-14 20:26 编辑

这几天没事在折腾一片无字库液晶,可以成功点亮了,想跟着论坛那些大神们学着用Flash做字库,找了一片W25Q64FV,容量8M,论坛上下载到的字库BIN用编程器写进去。再用STC15的SPI读取总是出错,已经折腾了好几天了,一直搞不定,请指教下

程序用的是STC官方的,只是在调试最简单的读取芯片ID,按照数据手册上25Q64的ID应为 EF 16,而我读出来的总是EE 16,试着读了某个地址的几个字节,发现结果也完全不对。MCU到Flash的线只有十几CM,加了上拉电阻和104电容。

单片机连接25Q64


但是我用PC端CH341A软件读取是正确的,逻辑分析仪抓的数据也对。

比较了一下发现时序并无不同,只是MOSI有轻微的不同,PC端的MOSI发出1个“0”后立即拉高,下个字节再拉低为零,但是Logic软件识别出来数据也是一样的,但是结果却不相同。
实在是搞不定,等下再用软件模拟试试看看

/**********************************************************************************************************************************************************************************************************************************************************************************************/
把25Q64到单片机之间的连线缩短就OK了,TMD折腾了我好几个晚上,太坑了
下图是用0x90命令读取ID,正常的读到了EF 16。


25Q64支持Mode 0 和Mode 3,实测都可正常通讯
下图是读取特定地址,然后发送到串口,数据正确。



今晚上可以睡个好觉了,谢谢各位兄弟的回复!



本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
发表于 2022-1-12 22:05:51 | 显示全部楼层
本帖最后由 inthsunshine 于 2022-1-12 22:26 编辑

我用stm32硬件spi读写过W25Q128,没问题,按手册的时序操作
DI,DO加上拉电阻就可以,不需要加电容

我看了下,应该是SPI初始化的设置不对,W25Q 系列只支持mode0和3, 也就是时钟的极性和相位设置,正确应该在时钟的上升沿有效, 你设置成下降沿

其实用示波器更能看得清楚细节,逻辑分析仪已经处理过,有时反而不容易找到故障点

打赏

参与人数 1家元 +20 收起 理由
aqxgm + 20 以資鼓勵

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2022-1-12 22:43:37 | 显示全部楼层
看两个抓取的时序图,通信频率不太对,看看25Q64默认工作在什么模式下,STC代码对应地作匹配吧。

打赏

参与人数 1家元 +20 收起 理由
aqxgm + 20 以資鼓勵

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2022-1-12 23:14:03 来自手机浏览器 | 显示全部楼层
我哪个能正常读W25Q32,但我没有发完整的程序,我也是搞了很久才搞通,用示波器看了很久,32的时序图也看烂了,才发现STC的程序时序是相反的。

打赏

参与人数 1家元 +20 收起 理由
aqxgm + 20 精彩回帖

查看全部打赏

回复 支持 反对

使用道具 举报

发表于 2022-1-13 10:52:26 | 显示全部楼层
//   W25Q16  ESP8266  15L2k56S2
//            GPIO   
//CS  1       4       5/P1^2
//MI  2/DO    12/MI   7/P1^3
//MO  5/DI    13/MO   6/P1^4
//SCK 6       14/SCK  8/P1^5
//ESP8266 not tested.

bit g_fSpiBusy=0;
void Spi_Init(void){
        ACC    = P_SW1;                                        //切换到第一组SPI
        ACC   &= ~(SPI_S0 | SPI_S1);        //SPI_S0=0 SPI_S1=0
        P_SW1  = ACC;                                        //(P1.2/SS, P1.3/MOSI;;;; P1.4/MISO, P1.5/SCLK)
   
        SPSTAT = SPIF | WCOL;                        //清除SPI状态
    SPCTL  = SSIG | SPEN | MSTR;        //设置SPI为主模式
    IE2   |= ESPI;
}

void spi_isr() interrupt 9{
    SPSTAT = SPIF | WCOL;                        //清除SPI状态位
    g_fSpiBusy = 0;
}

unsigned char SPI_WriteByte(unsigned char dat){
        g_fSpiBusy=1;
        SPDAT = dat;                                        //发送一个字节
        while(g_fSpiBusy);                                //等待SPI数据传输完成
        return SPDAT;
}

unsigned char SPI_ReadByte(){                // 读取状态字节
        return SPI_WriteByte(0);
}

//中间使用了TAB键,网页中又不支持,所以看起来不整齐。

打赏

参与人数 1家元 +20 收起 理由
aqxgm + 20

查看全部打赏

回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-1-13 22:29:06 来自手机浏览器 | 显示全部楼层
zj97czb 发表于 2022-1-12 23:14
我哪个能正常读W25Q32,但我没有发完整的程序,我也是搞了很久才搞通,用示波器看了很久,32的时序图也看烂 ...

能透露一下是哪里吗,有又折腾了一晚上还是不行
回复 支持 反对

使用道具 举报

发表于 2022-1-13 23:33:45 来自手机浏览器 | 显示全部楼层
我明天找个时间发,不过你最好把自己的发出来,因为自己写的,别人帮改了BUG,自己还容易懂,全使用别人的, 也只是能用而以,换个地方,可能又不行了。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-1-14 09:21:38 | 显示全部楼层
zj97czb 发表于 2022-1-13 23:33
我明天找个时间发,不过你最好把自己的发出来,因为自己写的,别人帮改了BUG,自己还容易懂,全使用别人的 ...

用的STC官方例程,时钟极性与相位都是0,选择的是SPI Mode0
void InitSpi()
{
  ACC = P_SW1;                                //切换到第一组SPI
  ACC &= ~(SPI_S0 | SPI_S1);                  //SPI_S0=0 SPI_S1=0
  P_SW1 = ACC;                                //(P1.2/SS, P1.3/MOSI, P1.4/MISO, P1.5/SCLK)
  SPSTAT = SPIF | WCOL;                       //清除SPI状态
  SS = 1;
  SPCTL = SSIG | SPEN | MSTR; //0xd0 设置SPI为主模式
}

unsigned char SpiShift(BYTE dat)        //使用SPI方式与Flash进行数据交换
{
    g_fSpiBusy = TRUE;
    SPDAT = dat;                                //触发SPI发送
    while (g_fSpiBusy);                         //等待SPI数据传输完成
    return SPDAT;
}

bit FlashCheckID()
{
    unsigned char dat1, dat2;
    SS = 0;
    SpiShift(0x90); //发送读取ID命令 0x90 再发送3个空指令
    SpiShift(0x00);                             //空读3个字节
    SpiShift(0x00);
    SpiShift(0x00);
    dat1 = SpiShift(0x00);                      //读取制造商ID1
    dat2 = SpiShift(0x00);                      //读取器件ID
    SS = 1;
    g_fFlashOK = ((dat1 == 0xef) && (dat2 == 0x16));
    return g_fFlashOK;
}
回复 支持 反对

使用道具 举报

发表于 2022-1-14 10:46:38 | 显示全部楼层
有时候,用I/O软件模拟读写还方便一些

打赏

参与人数 1家元 +20 收起 理由
aqxgm + 20 精彩回帖

查看全部打赏

回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-1-14 20:19:28 | 显示全部楼层
试着用I/O模拟了下,简单调试后就可以正常通讯了,开心~~~
回复 支持 反对

使用道具 举报

发表于 2022-1-15 11:17:59 | 显示全部楼层
unsigned char SpiShift(BYTE dat)        //使用SPI方式与Flash进行数据交换
{
    g_fSpiBusy = TRUE;//在这一行,不知你在中断里是怎么定义的,但是,大多数都是填“0”
    SPDAT = dat;                                //触发SPI发送
    while (g_fSpiBusy);                         //等待SPI数据传输完成//这里数值应该是取反的, while (!g_fSpiBusy);   
    return SPDAT;
}

另外 这个SS是不是片选信号?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2022-1-15 12:46:53 | 显示全部楼层
本帖最后由 aqxgm 于 2022-1-15 13:02 编辑

@zj97czb
SS是Slave Select(从机选择)的缩写,对于本例来说,只有一个从机,就无所谓SS了。可随便定义一个I/O 作为CS(Chip Select),单片机拉低CS后开始信号传输。

g_fSpiBusy = TRUE;//在这一行,不知你在中断里是怎么定义的,但是,大多数都是填“0”
SPI忙标志位,将“1”定义为忙或不忙都行

while (g_fSpiBusy);                         //等待SPI数据传输完成//这里数值应该是取反的, while (!g_fSpiBusy);
如果将“1”定义为不忙,就可以这样写,记得在中断服务程序清除该标志位

回复 支持 反对

使用道具 举报

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

本版积分规则

APP|手机版|小黑屋|关于我们|联系我们|法律条款|技术知识分享平台

闽公网安备35020502000485号

闽ICP备2021002735号-2

GMT+8, 2024-4-26 15:55 , Processed in 0.140401 second(s), 12 queries , Redis On.

Powered by Discuz!

© 2006-2023 smzj.net

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