久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4494|回復: 0
打印 上一主題 下一主題
收起左側

STM32之SPI讀寫外部FLASH

[復制鏈接]
跳轉到指定樓層
樓主
ID:98924 發表于 2015-12-9 02:50 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)

SPI_FLASH_Write_SR(0x02);//使能狀態寄存器中的寫存儲器

         SST25V_DBSY();

 

SPI_FLASH_Write_SR(0x02);//使能狀態寄存器中的寫存儲器

         SST25V_DBSY();

實驗目的:將數據寫入外部FLASH中,然后再讀出來顯示在LCD

實驗平臺:基于STM32F103C8T6的彩屏開發板

FLASHSST25VF016B

 

 

圖1:FLASH硬件接口

 

 


圖2:SST25VF016地址自增寫數據

 

 


圖3:SST25VF016的狀態寄存器

 

 


圖4:SST25VF016指令碼

 

 



 

主要的實驗代碼:

 

Flash.h

#ifndef __FLASH_H

#define __FLASH_H                        

#include "sys.h"

 

#define       SPI_FLASH_CS PAout(9)  //選中FLASH                                       

////////////////////////////////////////////////////////////////////////////

//SST25VF016讀寫

#define FLASH_ID 0XBF41

//指令表

#define SST25_ReadData                         0x03

#define SST25_FastReadData                     0x0B

#define SST25_4KByte_BlockERASE                0x20

#define SST25_32KByte_BlockErase               0x52

#define SST25_64KByte_BlockErase               0xD8

#define SST25_ChipErase                        0xC7

#define SST25_ByteProgram                      0x02

#define SST25_AAI_WordProgram                  0xAD

#define SST25_ReadStatusReg                    0x05

#define SST25_EnableWriteStatusReg             0x50

#define SST25_WriteStatusReg                   0x01

#define SST25_WriteEnable                      0x06

#define SST25_WriteDisable                     0x04

#define SST25_ManufactDeviceID                 0x90

#define SST25_JedecDeviceID                    0x9F

#define SST25_EBSY                             0x70

#define SST25_DBSY                             0x80

 

 

void SPI_Flash_Init(void);

u16  SPI_Flash_ReadID(void);                //讀取FLASH ID

u8     SPI_Flash_ReadSR(void);        //讀取狀態寄存器

void SPI_FLASH_Write_SR(u8 sr);     //寫狀態寄存器

void SPI_FLASH_Write_Enable(void);  //寫使能

void SPI_FLASH_Write_Disable(void); //寫保護

void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //讀取flash

void SPI_Flash_Erase_Chip(void);        //整片擦除

void SPI_Flash_Erase_Sector(u32 Dst_Addr);//扇區擦除

void SPI_Flash_Wait_Busy(void);           //等待空閑

void SST25V_EBSY(void);

void SST25V_DBSY(void);

void Flash_WriteByte(u8* pBuffer,u32 WriteAddr);//寫入1Byte數據

void AutoAddressIncrement_WordProgramA(u8 Byte1, u8 Byte2, u32 Addr);//地址自動增加的寫數據A

void AutoAddressIncrement_WordProgramB(u8 state,u8 Byte1, u8 Byte2);//地址自動增加的寫數據B

void SPI_Flash_Write(u8 pBuffer[],u32 WriteAddr,u16 NumByteToWrite);//結合AB構成的地址自動增加的連續數據的寫入

#endif

 

 

flash.c

#include "flash.h"

#include "spi.h"

#include "delay.h"

//4Kbytes為一個Sector

//16個扇區為1Block

//SST25VF016B

//容量為2M字節,共有32Block(),512Sector(扇區)

//初始化SPI FLASHIO

//修改狀態寄存器,允許芯片存儲器被寫

void SPI_Flash_Init(void)

{

         RCC->APB2ENR|=1<<2;       //PORTA時鐘使能        

         GPIOA->CRH&=0XFFFFFF0F;

         GPIOA->CRH|=0X00000030;//PA9 推挽         

         GPIOA->ODR|=1<<9;    //PA9上拉

         SPIx_Init();                     //初始化SPI

 

      SPI_FLASH_Write_SR(0x02);//使能狀態寄存器中的寫存儲器

         SST25V_DBSY();

 

} 

//讀取SPI_FLASH的狀態寄存器

//BIT7  6   5   4   3   2   1   0

//SPR   RV  TB BP2 BP1 BP0 WEL BUSY

//SPR:默認0,狀態寄存器保護位,配合WP使用

//TB,BP2,BP1,BP0:FLASH區域寫保護設置

//WEL:寫使能鎖定

//BUSY:忙標記位(1,;0,空閑)

//默認:0x00

u8 SPI_Flash_ReadSR(void)  

{ 

         u8 byte=0;  

         SPI_FLASH_CS=0;                            //使能器件  

         SPIx_ReadWriteByte(SST25_ReadStatusReg);    //發送讀取狀態寄存器命令   

         byte=SPIx_ReadWriteByte(0Xff);             //讀取一個字節 

         SPI_FLASH_CS=1;                            //取消片選    

         return byte;  

}

//SPI_FLASH狀態寄存器

//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以寫!!!

void SPI_FLASH_Write_SR(u8 sr)  

{  

         SPI_FLASH_CS=0;    //片選

         SPIx_ReadWriteByte(SST25_EnableWriteStatusReg);  //使能寫狀態寄存器命令  

         SPI_FLASH_CS=1;    //取消片選

         SPI_FLASH_CS=0; //片選                        

         SPIx_ReadWriteByte(SST25_WriteStatusReg);   //發送寫取狀態寄存器命令   

         SPIx_ReadWriteByte(sr);               //寫入一個字節 

         SPI_FLASH_CS=1;                           //取消片選                 

}  

//SPI_FLASH寫使能

//WEL置位  

void SPI_FLASH_Write_Enable(void)  

{

         SPI_FLASH_CS=0;                            //使能器件  

    SPIx_ReadWriteByte(SST25_WriteEnable);      //發送寫使能 

         SPI_FLASH_CS=1;                            //取消片選               

}

//SPI_FLASH寫禁止

//WEL清零 

void SPI_FLASH_Write_Disable(void)  

{ 

         SPI_FLASH_CS=0;                            //使能器件  

    SPIx_ReadWriteByte(SST25_WriteDisable);     //發送寫禁止指令   

         SPI_FLASH_CS=1;                            //取消片選               

}                             

//讀取芯片ID SST25VF016的是 0XBF41

u16 SPI_Flash_ReadID(void)

{

         u16 Temp = 0;      

         SPI_FLASH_CS=0;   

         //發送讀取ID命令                           

         SPIx_ReadWriteByte(0x90);

         //發送24位的地址        

         SPIx_ReadWriteByte(0x00);             

         SPIx_ReadWriteByte(0x00);             

         SPIx_ReadWriteByte(0x00);

         //讀取返回的16位值                              

         Temp=SPIx_ReadWriteByte(0xFF)<<8;//8位數據

         Temp+=SPIx_ReadWriteByte(0xFF);      //底八位數據

 

         SPI_FLASH_CS=1;                                   

         return Temp;

}

//讀取SPI FLASH 

//在指定地址開始讀取指定長度的數據

//pBuffer:數據存儲區

//ReadAddr:開始讀取的地址(24bit)

//NumByteToRead:要讀取的字節數(最大6553564k)

void SPI_Flash_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)  

{

        u16 i;                                                                                                                

         SPI_FLASH_CS=0;                            //使能器件  

    SPIx_ReadWriteByte(SST25_ReadData);         //發送讀取命令

         //發送24bit地址   

    SPIx_ReadWriteByte((u8)((ReadAddr)>>16));   

    SPIx_ReadWriteByte((u8)((ReadAddr)>>8));  

    SPIx_ReadWriteByte((u8)ReadAddr);

          

    for(i=0;i<NumByteToRead;i++)

         {

        pBuffer[i]=SPIx_ReadWriteByte(0XFF);   //循環讀數 

    }

         SPI_FLASH_CS=1;                            //取消片選               

} 

//地址自動增加的寫數據A

void AutoAddressIncrement_WordProgramA(u8 Byte1, u8 Byte2, u32 Addr)

{

         SPI_FLASH_Write_Enable();

         SPI_FLASH_CS=0;

         SPIx_ReadWriteByte(SST25_AAI_WordProgram);

         //輸入所要寫數據的起始地址

         SPIx_ReadWriteByte((Addr & 0xFF0000) >> 16);

         SPIx_ReadWriteByte((Addr & 0xFF00) >> 8);

         SPIx_ReadWriteByte(Addr & 0xFF);

         //發送最初的兩個數據

         SPIx_ReadWriteByte(Byte1);

         SPIx_ReadWriteByte(Byte2);

        

         SPI_FLASH_CS=1;

         SPI_Flash_Wait_Busy();

}

 

//地址自動增加的寫數據B

void AutoAddressIncrement_WordProgramB(u8 state,u8 Byte1, u8 Byte2)

{

         SPI_FLASH_Write_Enable();

         SPI_FLASH_CS=0;

         SPIx_ReadWriteByte(SST25_AAI_WordProgram);

        

         SPIx_ReadWriteByte(Byte1);

         SPIx_ReadWriteByte(Byte2);

        

         SPI_FLASH_CS=1;

         SPI_Flash_Wait_Busy();

        

         if(state==1)

         {

         SPI_FLASH_Write_Disable();

         }

         SPI_Flash_Wait_Busy();

}

 

//結合AB構成的地址自動增加的連續數據的寫入

//具有先擦除待寫區域的功能

//pBuffer:為待寫數據組

//WriteAddr:所寫數據的起始地址

//NumByteToWrite:所要寫的數據的長度

void SPI_Flash_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)

{

         u16 i,temp;

         u32 secpos;

         u16 secoff;

         u16 secremain;

         //以下代碼為擦除待寫區域的代碼

         secpos=WriteAddr/4096;//扇區(4K)地址0~511 for     SST25VF016

         secoff=WriteAddr@96;//在扇區內的偏移

         secremain=4096-secoff;//扇區剩余空間大小

         if(NumByteToWrite<secremain)//剩余空間大于所存數據

         {

                   temp=1;

         }

         else//剩余空間小于所存數據

         {

                   i=NumByteToWrite-secremain;

                   //判斷還占了幾個扇區

                   if(i@96==0)

                   {

                            temp=i/4096+1;

                   }

                   else

                   {      

                            temp=i/4096+2;

                   }

         }

         for(i=0;i<temp;i++)

         {

                   SPI_Flash_Erase_Sector((secpos+i)*4096); //擦除將要寫入數據的扇區   

         }

 

         //以下代碼為將數據寫入指定地址的代碼

         if(NumByteToWrite%2==0)

         {

                   temp=NumByteToWrite/2-1;

         }

         else

         {

                   temp=NumByteToWrite/2;

         }

         AutoAddressIncrement_WordProgramA(pBuffer[0], pBuffer[1],WriteAddr );        //開始寫數據

          for(i=1;i<temp;i++)

          {

                 AutoAddressIncrement_WordProgramB(0,pBuffer[2*i], pBuffer[2*i+1]);

          }

          if(NumByteToWrite%2==0)

         {

                 AutoAddressIncrement_WordProgramB(1,pBuffer[NumByteToWrite-2], pBuffer[NumByteToWrite-1]);   //結束寫數據

          }

          else

          {

                 AutoAddressIncrement_WordProgramB(1,pBuffer[NumByteToWrite-1],0); //結束寫數據

          }

}

 

//寫入1Byte數據

//pBuffer:待寫的數據

//WriteAddr:待寫數據的地址

void Flash_WriteByte(u8* pBuffer,u32 WriteAddr)

{

         u32 secpos;

         secpos=WriteAddr/4096;//扇區地址 0~511 for w25x16  4096=4k

         SPI_Flash_Erase_Sector(secpos);//擦除這個扇區

        

         SPI_FLASH_Write_Enable();                  //SET WEL

         SPI_FLASH_CS=0;                           //使能器件  

    SPIx_ReadWriteByte(SST25_ByteProgram );     //發送寫頁命令

         //發送24bit地址   

    SPIx_ReadWriteByte((u8)((WriteAddr)>>16));  

    SPIx_ReadWriteByte((u8)((WriteAddr)>>8));  

    SPIx_ReadWriteByte((u8)WriteAddr);

         //發送待寫的數據

         SPIx_ReadWriteByte(pBuffer[0]);

         SPI_FLASH_CS=1; 

         SPI_Flash_Wait_Busy();//等待寫完成

                  

}

//擦除整個芯片

//整片擦除時間:

//W25X16:25s

//W25X32:40s

//W25X64:40s

//等待時間超長...

void SPI_Flash_Erase_Chip(void)  

{                                            

    SPI_FLASH_Write_Enable();                  //SET WEL

    SPI_Flash_Wait_Busy();  

       SPI_FLASH_CS=0;                            //使能器件  

    SPIx_ReadWriteByte(SST25_ChipErase);        //發送片擦除命令 

         SPI_FLASH_CS=1;                            //取消片選               

         SPI_Flash_Wait_Busy();                                   //等待芯片擦除結束

}  

//擦除一個扇區

//Dst_Addr:扇區地址 0~511 for w25x16

//擦除一個山區的最少時間:150ms

void SPI_Flash_Erase_Sector(u32 Dst_Addr)  

{  

    SPI_FLASH_Write_Enable();                  //SET WEL           

    SPI_Flash_Wait_Busy();  

       SPI_FLASH_CS=0;                            //使能器件  

    SPIx_ReadWriteByte(SST25_4KByte_BlockERASE);      //發送扇區擦除指令

    SPIx_ReadWriteByte((u8)((Dst_Addr)>>16));  //發送24bit地址   

    SPIx_ReadWriteByte((u8)((Dst_Addr)>>8));  

    SPIx_ReadWriteByte((u8)Dst_Addr); 

         SPI_FLASH_CS=1;                            //取消片選               

    SPI_Flash_Wait_Busy();                                    //等待擦除完成

} 

//等待空閑

void SPI_Flash_Wait_Busy(void)  

{  

         while ((SPI_Flash_ReadSR()&0x01)==0x01);   // 等待BUSY位清空

} 

void SST25V_EBSY(void)

{

         SPI_FLASH_CS=0;

         SPIx_ReadWriteByte( SST25_EBSY);

         SPI_FLASH_CS=1;   

}

void SST25V_DBSY(void)

{

         SPI_FLASH_CS=0;

         SPIx_ReadWriteByte( SST25_DBSY);

         SPI_FLASH_CS=1;   

}

 

 

主函數:

#include<stm32f10x_lib.h>

#include"common.h"

#include"TFTLCD.h"

#include"spi.h"

#include"key.h"

#include"flash.h"

const u8 TEXT_Buffer[]={"Chen An SST25VF"};//待寫入flash的數據

#define SIZE sizeof(TEXT_Buffer) //計算待寫入數據的長度

int main(void)

{

         u8 key;

         u8 datatemp[SIZE]; //開辟空間用于存放從flash讀回的數據

         Stm32_Clock_Init(9); //系統時鐘初始化

         delay_init(72);//延時函數的初始化

         JTAG_Set(JTAG_SWD_DISABLE);//屏蔽JTAGSWD調試,防止和LCD沖突

         LCD_Init();         //LCD初始化

         KEY_Init();         //按鍵初始化

         SPI_Flash_Init();//SPI關于flash的硬件接口初始化

         POINT_COLOR=RED;//設置字體顏色

         while(SPI_Flash_ReadID()!=FLASH_ID)//檢驗flash是否存在

         {

                   LCD_ShowString(60,130,"SST25VF Check Failed!");

                   delay_ms(500);

         }

         LCD_ShowString(60,130,"SST25VF Ready!");

         LCD_ShowString(60,150,"KEY1:Write KEY2:Read");

         POINT_COLOR=BLUE;

         while(1)

         {

                   key=KEY_Scan();        //按鍵掃描

                   if(key==1)//按鍵1按下,開始寫數據到flash

                   {

                            LCD_Fill(0,170,239,319,WHITE);

                            LCD_ShowString(60,170,"Start Write SST25V");

                            SPI_Flash_Write((u8*)TEXT_Buffer,1000,SIZE); //寫數據

                            LCD_ShowString(60,170,"SST25V Write Finished");

                   }

                   if(key==2) //按鍵2按下,開始從flash讀回數據

                   {

                            LCD_ShowString(60,170,"Start Read SST25V");

                            SPI_Flash_Read(datatemp,1000,SIZE); //讀數據 

                            LCD_ShowString(60,170,"The Data Is");

                            LCD_ShowString(60,190,datatemp);

 

                   }      

         }

}

 

總結:1.開始的時候,讀取FLASH的ID成功,我覺得芯片一切正常,但是寫入數據后讀回來的全是“滿屏”,糾結了一天才發現原 

        來是FLASH沒有進行初始化,沒有寫 (SPI_FLASH_Write_SR(0x02);//使能狀態寄存器中的寫存儲器  SST25V_DBSY() )

        這兩句導致數據無法寫入FLASH。

      2.我在寫程序的時候犯了個很低級的失誤,在寫乘法時用了 2i 結果一直提示有錯誤卻沒發現,直到過了半個小時才反應過

        該寫成 2*i

      3.這個SST25VF016的關鍵在于連續數據的寫入,需要仔細研究圖二,我也是參考了一個網友的思路,在他得基礎(A和B)拓

        展出最后的 SPI_FlashWrite 函數的,不過該函數還有很多的不確定因素,大家要結合主函數中的 SIZE 來進行思考。

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 午夜精品一区 | 成人av免费 | 中文在线视频 | 超碰操| 亚洲激情一区二区三区 | 国产视频一二三区 | 亚洲综合大片69999 | www.成人在线视频 | 亚洲欧美日韩在线不卡 | 狠狠综合久久av一区二区小说 | 91精品国产91久久久久久最新 | 日本在线网址 | 亚洲一区高清 | 久久久久久久电影 | 午夜视频在线 | 国产99精品 | 欧美综合一区二区 | 国产福利资源在线 | 亚洲精品99 | 中文在线播放 | 国产精品久久国产精品 | 操视频网站 | 午夜精品久久 | 日韩久久久一区二区 | www亚洲精品 | 青青操av| 成人午夜视频在线观看 | 国产精品久久久av | 欧美电影在线观看网站 | 国产成人a亚洲精品 | 蜜臀网 | 涩涩视频在线观看免费 | 日本免费一区二区三区视频 | 精品日韩一区二区 | 国产成人高清在线观看 | 日本成人福利 | 国产成人91 | 久久69精品久久久久久久电影好 | 特黄小视频 | 欧美韩一区二区三区 | 成年免费大片黄在线观看一级 |