在之前的学习中,使用其他开发板读写W25Q64时,遇到过时序上的问题,见《【STCAi8051U】使用Ai8051U的SPI外设读写W25Q128
》(https://forum.eepw.com.cn/thread/394802/1)。在发送完读取指令和地址后,在发送用的SCK的最后一个脉冲的下降沿开始读取来自Flash的数据。而本次使用CH582M开发板,按照这个模式去操作就遇到了问题。表现为在读取JEDEC ID时,返回的数据为0x17 00 00。
读取的程序代码为:
/**
* @brief SPI0 单字节收发(全双工,直接操作寄存器)
*/
static uint8_t SPI0_SendRecvByte(uint8_t byte) {
SPI0_MasterSendByte(byte);
return SPI0_MasterRecvByte();
}
/**
* @brief 读 JEDEC ID (Manufacturer + Memory Type + Capacity)
* @retval 例如 W25Q64 返回 0xEF4017
*/
uint32_t W25Q64_ReadJEDECID(void) {
uint32_t id = 0;
W25Q64_CS_LOW();
SPI0_SendRecvByte(W25X_JEDEC_ID);
id |= ((uint32_t)SPI0_SendRecvByte(0xFF) << 16); /* Manufacturer ID */
id |= ((uint32_t)SPI0_SendRecvByte(0xFF) << 8); /* Memory Type */
id |= SPI0_SendRecvByte(0xFF); /* Capacity */
W25Q64_CS_HIGH();
return id;
}
由逻串口输出调试日志:

逻辑分析仪获取到的信号波形:

由时序信号上看,
1、Flash已经正确返回了JEDEC ID,即:0xEF 40 17
2、这个读取过程返回了多余的4个0xFF数据
仔细分析W25Q64_ReadJEDECID这个函数的代码,发现问题所在。
1、在使用SPI0_SendRecvByte函数发送W25X_JEDEC_ID对应的指令时,产生的逻辑处理时是:
1)发送W25X_JEDEC_ID指令
2)接收数据
2、接下来由执行了三次SPI0_SendRecvByte(0xFF),也就是三组
1)发送0xFF
2)接收数据
从信号时序上看,感觉发送三个0xFF的动作是多余的,在发送完W25X_JEDEC_ID指令后应该完全转入读取的动作。至于为什么会多出来四个0xFF数据,是因为每执行一次SPI0_MasterRecvByte()处理,就会产生一次0xFF的发送动作。加上执行W25X_JEDEC_ID指令时产生的SPI0_MasterRecvByte()处理,刚好是四个0xFF信号。
按照上面的分析,修改代码为:
/**
* @brief 读 JEDEC ID (Manufacturer + Memory Type + Capacity)
* @retval 例如 W25Q64 返回 0xEF4017
*/
uint32_t W25Q64_ReadJEDECID(void) {
uint32_t id = 0;
uint8_t id1 = 0, id2 = 0, id3 = 0;
W25Q64_CS_LOW();
SPI0_MasterSendByte(W25X_JEDEC_ID);
id1 = SPI0_MasterRecvByte();
id2 = SPI0_MasterRecvByte();
id3 = SPI0_MasterRecvByte();
W25Q64_CS_HIGH();
id = ((uint32_t)id1 << 16) + ((uint32_t)id2 << 8) + id3;
return id;
}编译、烧录、运行,由逻辑分析仪获取到逻辑信号:

这次终于正确了,多余的0xFF数据也消失了。
这里对比Ai8051U的读写处理,还有一点不同。在Ai8051U的读写处理中,发出W25X_JEDEC_ID指令后的最后一个SCK脉冲的下降沿开始读取数据,而在CH582M中,使用的是SPI的模式0,是在发出W25X_JEDEC_ID指令后,新发出的SCK脉冲的上升沿开始读取数据。为什么会是这样,我也是百思而不得其解啊。
我要赚赏金
