最近项目用来了QSPI驱动W25Q256FV这款芯片。
由于SFUD有这款芯片的驱动,就找了bsp STM32l475-atk-pandora下的port 烧录后的现象是可以识别芯片,但是读写不正常。
然后就仔细检查了port文件:
有bug的是下面一段代码
void w25qxx_enter_qspi_mode(struct rt_qspi_device *device)
{
char status = 0;
/* 0x38 enter qspi mode */
char write_status2_buf[2] = {0};
/* 0x31 write status register2 */
write_status2_buf[0] = 0x31;
status = w25qxx_read_status_register2(device);
if (!(status & 0x02))
{
status |= 1 << 1;
w25qxx_write_enable(device);
write_status2_buf[1] = status;
rt_qspi_send(device, &write_status2_buf, 2);
rt_qspi_send(device, &instruction, 1);
rt_kprintf("flash already enter qspi mode
");
rt_thread_mdelay(10);
}
}
rt_qspi_send(device, &write_status2_buf, 2) 是明显有问题的,
修改成rt_qspi_send(device, write_status2_buf, 2);
本以为问题就解决了,但是没想到还一直有问题。
没办法,接上逻辑分析仪,看了下时许,
发现rt_qspi_send(device, write_status2_buf, 2)这句spi没有发送对应指令,这个指令是开启QSPI,问题应该在这里。
一开始没想是内核代码的问题,一追踪才发现,QSPI内核代码有这样的判断
if (length > 1)
{
if (device->config.medium_size > 0x1000000 && length >= 5)
{
/* medium size greater than 16Mb, address size is 4 Byte */
message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
message.address.size = 32;
message.address.qspi_lines = 1;
count += 4;
}
else if (length >= 4)
{
/* address size is 3 Byte */
message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
message.address.size = 24;
message.address.qspi_lines = 1;
count += 3;
}
else
{
return -RT_ERROR;
}
}
所以当length>1后,内核认为一定存在address,所以对于2-3长度的数据都不予处理,直接报错,
所以这rt_qspi_send(device, write_status2_buf, 2);这句直接报错返回了。
这显然是不合理的,先不说在send函数中做了逻辑判断。
关键是qspi发送就不应该有这个逻辑,个人理解这里应该qspi内核的一个bug。
这里rt_qspi_send(device, write_status2_buf, 2)对应的是如下时序,
也是开启芯片QSPI的方法。
至于为什么有的人可以驱动成功,我也查了一些资料,有人说W25Q256有JV和FV两种,JV不需要开启QSPI就可以用QSPI读取,而FV需要开启,不知道是不是这原因导致.
这边为了让驱动能正确运行,我临时修改了一点代码,只是临时解决下问题:
if (length > 1)
{
if (device->config.medium_size > 0x1000000 && length >= 5)
{
/* medium size greater than 16Mb, address size is 4 Byte */
message.address.content = (ptr[1] << 24) | (ptr[2] << 16) | (ptr[3] << 8) | (ptr[4]);
message.address.size = 32;
message.address.qspi_lines = 1;
count += 4;
}
else if (length >= 4)
{
/* address size is 3 Byte */
message.address.content = (ptr[1] << 16) | (ptr[2] << 8) | (ptr[3]);
message.address.size = 24;
message.address.qspi_lines = 1;
count += 3;
}else if(length == 2){
message.address.content = 0 ;
message.address.qspi_lines = 0;
message.address.size = 0;
}else
return -RT_ERROR;
}