加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

spi flash 驱动

发布时间:2020-12-15 06:12:54 所属栏目:百科 来源:网络整理
导读:抓狂的 spi 终于弄完了,想死的心都有了,本来不想到这么麻烦,大意了。 ? 一、都不知道从何说起了,先说说我们的 spi 的“变态点”吧。 ? 变态点一: 四种模式( CONTROL0 寄存器 TMOD 域),一个简单的 spi 协议还得搞出四种模式,好智能

抓狂的spi终于弄完了,想死的心都有了,本来不想到这么麻烦,大意了。

?

一、都不知道从何说起了,先说说我们的spi的“变态点”吧。

?

变态点一:

四种模式(CONTROL0 寄存器TMOD域),一个简单的spi协议还得搞出四种模式,好智能啊。

变态点二:

CS信号和SCLK信号不能单独受控,只能由写操作来控制,好智能啊。

变态点三:

我把你前两点的脾气摸到了之后,我该能控制你了吧,不行,你还非得在给我弄出一个EEPROM Read的模式,这个模式更智能,在写完命令和地址之后,SCLK信号自己产生,不用再用写操作来控制了,好智能啊。

?

真得谢谢设计这东西的人,你太为我们软件着想了,把我们的事都给干了,你想让我们下岗啊。

?

二、奥,想起怎么写了,得总结一下我的各种需要怎么来仿真

?

1、 flash芯片的状态寄存器,代码如下

??? UINT8 byte = 0;??

?

?? ?// 读之前,必须得设置一下模式

??? NST_SPI->SSIENR= 0x00;

??? NST_SPI->CTRLR0= (SPI_TMOD_TR << SPI_TMOD_OFFSET) | (SPI_FRF_SPI << SPI_FRF_OFFSET) |(SPI_FRM_SIZE - 1) |( SPI_MODE_3 << 6);

NST_SPI->SSIENR= 0x01;

?

??? NST_SPI->DR = FLASH_CMD_SRR;

?? ?// 发送一个伪码为的是产生时钟和CS有效

??? NST_SPI->DR = DUMMY_BYTE;

??? BSP_SpiWait();?? //到这里,我们一个模拟过程算是完成了

??? byte = NST_SPI->DR;? //在这种模式下,只要sck有,cs为低,sdi就会被采样,我们在FIFO中就能读到(必须在调用BSP_SpiWait函数之后,再读),因此我们必须得把命令占的一个时钟从sdi移位到FIFO中的数据丢掉。

???

??? byte = NST_SPI->DR;? // 这才是真正想要的数据

???

return byte;

?

备注:

1)、BSP_SpiWait函数如下,该函数用于一次读写逻辑过程的完成。

VOID BSP_SpiWait(VOID)

{

?????? UINT8 retry=0;

??????

?????? while(!(NST_SPI->SR & SR_TF_EMPT))//等待发送区空??????

?????? {

????????????? retry++;

?????? }

?

?

?????? retry=0;

?????? while(NST_SPI->SR & SR_BUSY) //等待接收完一个byte?

????????????? retry++;

}

2)、FIFO现在默认的大小是8,因此你一次读逻辑只能获得7个以下的字节(8得减去命令所占时钟,还得减去地址所占的时钟)

3)、上面加红的部分全部是变态点

2、 flash芯片的写一个字节,代码如下:

VOID BSP_SpiFlashWriteByte(UINT8 Byte,UINT32 WriteAddr)

{

UINT32 FlashAdr = (((WriteAddr/FLASH_PAGE_SIZE) << 9) | (WriteAddr % FLASH_PAGE_SIZE));

?

// 写之前,得设置一下模式

??? NST_SPI->CTRLR0=? (SPI_TMOD_TO << SPI_TMOD_OFFSET) | (SPI_FRF_SPI << SPI_FRF_OFFSET) |(SPI_FRM_SIZE - 1) |( SPI_MODE_3 << 6);

??? NST_SPI->SSIENR= 0x01;

???

??? NST_SPI->DR = FLASH_CMD_MMPPTB1;

??? NST_SPI->DR = (UINT8)((FlashAdr)>>16);

??? NST_SPI->DR = (UINT8)((FlashAdr)>>8);

??? NST_SPI->DR = (UINT8)FlashAdr;

??? while(!(NST_SPI->SR & SR_TF_NOT_FULL)); //spi的状态寄存器就是这么用,很经典。

??????? NST_SPI->DR = Byte;

??? BSP_SpiWait(); //一个写逻辑的完成

BSP_SpiFlashWaitBusy(); //等待芯片写操作完成,这和芯片有关跟我们内部spi没有关系

}

备注:

你还别说他搞的这个写的时候自动产生时钟和cs有效,对于写还是很好用的,上面我标准红色的比较少,说明写还是很让人满意的。

3、 flash芯片的连续读,代码如下:

VOID? SPI_FlashRead(UINT8* pBuf)?

{

? ??UINT32 ReadAddr = 0;

??? UINT8* pRxData = pBuf;

??? UINT32 FWLen = 0;

??? UINT32 DnldByteCnt = 0;

??? UINT32 BatchRdCnt = 0; // 批量读的次数

??? UINT32 FlashAdr = (((ReadAddr/FLASH_PAGE_SIZE) << 9) | (ReadAddr % FLASH_PAGE_SIZE));?? //需要按照芯片手册转换一下地址,在读命令中会介绍地址怎么安排。

??? //BSP_SpiFlashEraseChip();

//BSP_SpiFlashWaitBusy();

// 读之前,得设置一下模式

??? NST_SPI->CTRLR0=? (SPI_TMOD_EPROMREAD << SPI_TMOD_OFFSET) | (SPI_FRF_SPI << SPI_FRF_OFFSET) |(SPI_FRM_SIZE - 1) |( SPI_MODE_3 << 6);

??? NST_SPI->CTRLR1= MAX_FLASH_RD_SIZE - 1;? /* 连续读数据个数*/

??? NST_SPI->SSIENR= 0x01;

??? BSP_SpiWriteByte(FLASH_CMD_CARLF);

??? BSP_SpiWriteByte((FlashAdr>>16) & 0xFF);

??? BSP_SpiWriteByte((FlashAdr>>8) & 0xFF);

??? BSP_SpiWriteByte(FlashAdr & 0xFF);

??? BSP_SpiRead(MAX_FLASH_RD_SIZE,pRxData);

??? BSP_SpiWait();??? //一个读逻辑的完成

??? DnldByteCnt += MAX_FLASH_RD_SIZE;

??? ReadAddr += MAX_FLASH_RD_SIZE;

??? FWLen = *(UINT32*)pRxData;

??? pRxData += MAX_FLASH_RD_SIZE;

??? DBGPRINT(DEBUG_INFO,"READ FLASH BatchRdCnt =%d,pBuf=0x%xn",++BatchRdCnt,pBuf);

??? //??? UsDelay(30000);

??? while(FWLen > DnldByteCnt)

??? {

??????? UINT32 RdCnt = (FWLen - DnldByteCnt) > MAX_FLASH_RD_SIZE ? MAX_FLASH_RD_SIZE : (FWLen - DnldByteCnt);

??????? FlashAdr = (((ReadAddr/FLASH_PAGE_SIZE) << 9) | (ReadAddr % FLASH_PAGE_SIZE));

???????

??????? //BSP_SpiFlashWaitBusy();

??????? // 读之前,得设置一下模式

??????? NST_SPI->SSIENR= 0x00;

??????? NST_SPI->CTRLR0=? (SPI_TMOD_EPROMREAD << SPI_TMOD_OFFSET) | (SPI_FRF_SPI << SPI_FRF_OFFSET) |(SPI_FRM_SIZE - 1) |( SPI_MODE_3 << 6);

??????? NST_SPI->CTRLR1= RdCnt - 1; //连续读写数据个数

??????? NST_SPI->SSIENR= 0x01;

??????? // send cmd

??????? BSP_SpiWriteByte(FLASH_CMD_CARLF);

??????? BSP_SpiWriteByte((FlashAdr>>16) & 0xFF);

??????? BSP_SpiWriteByte((FlashAdr>>8) & 0xFF);

??????? BSP_SpiWriteByte(FlashAdr & 0xFF);

??????? BSP_SpiRead(RdCnt,pRxData);

??????? BSP_SpiWait();?? //一个读逻辑的完成

??????? DnldByteCnt += RdCnt;

??????? ReadAddr += RdCnt;

??????? pRxData += RdCnt;

??????? DBGPRINT(DEBUG_INFO,MS Song">??????? //?? UsDelay(1000);

??? }

???

}

备注:

BSP_SpiRead函数如下:

VOID BSP_SpiRead(UINT32 RdCnt,UINT8* pBuf)??

??? UINT8 RxByte;

??? while(RdCnt > 0)

??? {

??????? if(NST_SPI->SR & SR_RF_NOT_EMPT)?? //SPI状态寄存器RFNE域的经典用法

??????? {

??????????? *pBuf++ =? NST_SPI->DR;

??????????? RdCnt--;

??????? }

??? }

?

// throw the redundant bytes

??? if(NST_SPI->SR & SR_RF_NOT_EMPT)

??????? RxByte =? NST_SPI->DR;

??????? RxByte =RxByte; // remove warning

?? ?}

}

2)、这个EEPROM Read模式不知道的不会用,知道时会吓一跳,总体感觉要理解这哥们太难了,在读之前只能发送一个命令和三个地址,如果在发送一个伪码读回来就会少一个字节,同时读回来的数据是CONTROL1来决定的(最大是64K)。

这种模式的总体感觉就是:你在被他的智能吓一跳的同时,又会觉得这个模式太苛刻了,都不知道该骂他还是赞美他了。

?

?

三、调试中的难点:

简单点就是,要在心里把一个变态看成正常人太难了。

?

复杂点,罗列如下:

1、 知道用? BSP_SpiWait函数来表示一个读写逻辑的结束

2、 知道在一个读写逻辑没结束之前,要狂写和狂读,当然在每一次狂写和狂读之前要判读读写FIFO的空满情况。

3、 要去理解EEPROM Read模式

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读