好久没有更新博客,只因最近工作比较忙,今天抽点时间写一下在zedboard平台上挂接文件系统,块设备为S25FL256s,共计32M的flash,flash划分为两部分,0x0---0x1000000,前16M用于存储系统uboot和系统的相关参数,0x1000000---0x2000000为truetffs文件系统,其配置如下:
第一步:在VIP里面增加组件DRV_QSPI_FDT_ZYNQ7K,DRV_SPI_FLASH,INCLUDE_TFFS,INCLUDE_TL_FTL,INCLUDE_TFFS_MOUNT,INCLUDE_TFFS_STUB_VXBFLASH,INCLUDE_MTD_VXBFLASH
第二步:flash预留配置,VXBFLASH_CFG_STR "$spflspilash0#0:0x0,0x1000000,0x100000,rfa0"
第三步:调试驱动,由于zynq系列只能支持3字节地址操作,最大支持16M大小flash操作,而本次系统设计的flash为32M flash,如果要四字节操作,必须使用bank寄存器,首先在设备树配置如下:
qspi0: qspi@e000d000
{
#address-cells = <1>;
#size-cells = <0>;
compatible = "xlnx,zynq7k-qspi";
reg = <0xE000D000 0x100>,
<0xF8000000 0x800>;
interrupts = <51>;
interrupt-parent = <&intc>;
spiflash@0
{
compatible = "spflspilash";
reg = <0>;
data-lines = <4>;
chip-number = <1>;
addr-mode = <1>;
spi-max-frequency = <100000000>;
};
};
addr-mode=1,为三字节地址操作模式,必须修改bank寄存器,所以相关的驱动必须做修改,我在前期调试时,也是由于没有注意到这点,导致flash写0地址时0x1000000地址也被修改,如下时代码:
STATUS spiFlashDataWrite
(
SPI_FLASH_DEV * pDrvCtrl,
UINT32 startAddr,
UINT32 dataLen,
UINT8 * dataBuf
)
{
UINT32 bytesToWrite;
UINT32 writeCmdLen;
UINT8 writeCmdOpcode;
UINT32 windowSize;
UINT8 * pBuf;
UINT32 optAddr;
UINT32 addrDiv;
STATUS rc = OK;
UINT8 status = 0;
UINT8 value = 0;
if ((pDrvCtrl->hd.mode & SPI_PARALLEL) != 0)
{
addrDiv = pDrvCtrl->hd.chipNum;
}
else
{
addrDiv = 1;
}
writeCmdLen = pDrvCtrl->addrWidth + 1;
writeCmdOpcode = SPI_PP_CMD;
pBuf = pDrvCtrl->pWrBuf;
if ((pDrvCtrl->specialInfo != NULL) &&
(pDrvCtrl->specialInfo->flag & SPI_MASTER_TRANS_LIMIT))
{
windowSize = pDrvCtrl->specialInfo->windowSize;
}
else
{
windowSize = 0;
}
//驱动中增加对大于32Mflash的支持,因为zynq不支持大于16Mfalsh的命令,如果大于16M,需要使用bank寄存器,朱红博于2020年10月19日
if(pDrvCtrl->addrMode == 1)
{
value |= startAddr >>24;
spiFlashWriteReg(pDrvCtrl,SPI_WBNK_CMD,value);
}
if (spiFlashWaitReady (pDrvCtrl) != OK)
{
return ERROR;
}
/* clear the Write Enable Latch (WEL) bit to 0 */
if (spiFlashReadSR(pDrvCtrl, &status) == OK)
{
if ((status & SR_WEL) != 0)
{
status &= (UINT8)(~(SR_WEL));
if (spiFlashWriteReg (pDrvCtrl, SPI_WRSR_CMD, status) != OK)
{
return ERROR;
}
}
}
else
{
return ERROR;
}
/* data must be written in "page Size" chunks */
do
{
optAddr = startAddr / addrDiv;