新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > SST25VF080B SPI接口FLASH STM32驅動

        SST25VF080B SPI接口FLASH STM32驅動

        作者: 時間:2016-12-03 來源:網絡 收藏
        所有的FLASHA 都一樣只能從1變0,要想從0變1 只有擦除一個頁扇,SST25VF080B 最小可以擦除4KB的頁速度也不錯 50MHz 容量1MB 挺夠用的 10萬次的擦寫壽命。最低2.7V 就可正常工作。
        Flexible Erase Capability
        – Uniform 4 KByte sectors
        – Uniform 32 KByte overlay blocks
        – Uniform 64 KByte overlay blocks
        先記下 這些個7788的命令

        SST25VF080B 的各種命令比較繁瑣

        本文引用地址:http://www.104case.com/article/201612/325218.htm

        Status Register這個設置寫保護多點 我這里只用它的判忙BUSY

        一樣先配置SPI與GPIO口上圖~~

        在這也就是CE有用片選嘛~~

        #defineSST_SELECT()GPIO_ResetBits(GPIOC, GPIO_Pin_13)/* SST CS = L */
        #defineSST_DESELECT()GPIO_SetBits(GPIOC, GPIO_Pin_13)/* SST CS = H */

        /***********************************************
        **函數名:FLASH_SPI_Config
        **功能:初始化串行FLASH的SPI接口
        **注意事項:串行FLASH使用了SPI1接口
        ***********************************************/
        void FLASH_SPI_Config(void)
        {
        SPI_InitTypeDef SPI_InitStructure;
        GPIO_InitTypeDef GPIO_InitStructure;

        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC |
        RCC_APB2Periph_AFIO |
        RCC_APB2Periph_SPI1,
        ENABLE);

        /* SCK, MISO and MOSI A5=CLK,A6=MISO,A7=MOSI*/
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        /* PC.13 作片選*/
        GPIO_SetBits(GPIOC, GPIO_Pin_13);//預置為高
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
        GPIO_Init(GPIOC, &GPIO_InitStructure);

        /* SPI1 configuration */
        SPI_Cmd(SPI1, DISABLE); //必須先禁能,才能改變MODE
        SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;//兩線全雙工
        SPI_InitStructure.SPI_Mode = SPI_Mode_Master;//主
        SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;//8位
        SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;//CPOL=0 時鐘懸空低
        SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;//CPHA=0 數據捕獲第1個
        SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;//軟件NSS
        SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;//2分頻=36M SST25VF說是50M沒事
        SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;//高位在前
        SPI_InitStructure.SPI_CRCPolynomial = 7;//CRC7 我不解的是如果出錯要如何處理

        SPI_Init(SPI1, &SPI_InitStructure);
        //SPI_SSOutputCmd(SPI1, ENABLE); //使能NSS腳可用 我這就一個SPI 器件
        SPI_Cmd(SPI1, ENABLE);

        }

        /***************************************
        **函數名:SPIByte
        **功能:讀寫SPI總線
        **注意事項:對于SPI來說,主機的讀也需要先寫,
        **使用此函數,讀的時候建議參數設置為0xff,寫的時候則寫參數.這里使用直接操作寄存器的辦法實現SPI硬件層讀寫,是為了加快速寫速度 在說LCD 的時候我用的就是庫函數 比如

        SPI_I2S_SendDataSPI_I2S_ReceiveData SPI_I2S_GetFlagStatus
        ***************************************/
        static u8 SPIByte(u8 byte)
        {
        /*等待發送寄存器空*/
        while((SPI1->SR & SPI_I2S_FLAG_TXE)==RESET);
        /*發送一個字節*/
        SPI1->DR = byte;
        /* 等待接收寄存器有效*/
        while((SPI1->SR & SPI_I2S_FLAG_RXNE)==RESET);
        return(SPI1->DR);
        }

        //咱用模式0

        /*****************************************
        **函數名:SSTCmd1/2/4
        **功能:寫一個SST命令/寫一個命令后接一個數據/寫一個命令后再寫3個數據
        **注意事項:這是一個完整的單命令操作,不返回
        *****************************************/
        void SSTCmd1(u8 cmd)
        {
        SST_SELECT();
        SPIByte(cmd);
        SST_DESELECT();
        }

        void SSTCmd2(u8 cmd,u8 data)
        {
        SST_SELECT();
        SPIByte(cmd);
        SPIByte(data);
        SST_DESELECT();
        }

        void SSTCmd4(u8 cmd,u8 *addr)
        {
        SST_SELECT();
        SPIByte(cmd);//首命令
        SPIByte(*addr++);
        SPIByte(*addr++);
        SPIByte(*addr);
        SST_DESELECT();
        }

        /****************************************
        **函數名:SSTCmdb1b/SSTCmd4bs
        **功能:寫一個SST命令,返回1字節數據/寫1個命令字,3個地址字,返回多個字節
        **更多使用在讀出上的
        ****************************************/
        u8 SSTCmdb1b(u8 cmd)
        {
        u8 tmp;
        SST_SELECT();
        SPIByte(cmd);
        tmp=SPIByte(0xff);
        SST_DESELECT();
        return(tmp);
        }
        void SSTCmd4bs(u8 cmd,u8* addr,u8* data,u32 no)
        {
        SST_SELECT();
        SPIByte(cmd);//首命令
        SPIByte(*addr++);
        SPIByte(*addr++);
        SPIByte(*addr);
        for(;no>0;no--)
        {
        *data++=SPIByte(0xff);
        }
        SST_DESELECT();
        }

        //命令時序復雜啊~~當然了我這為了求全都寫出來了

        常用的芯片功能

        /***************************************
        SST25WREN 允許寫功能
        ***************************************/
        void SST25WREN(void)
        {
        SSTCmd1(0x06);
        }

        /***********************************
        SST25WRDI 屏蔽寫功能
        ***********************************/
        void SST25WRDI(void)
        {
        SSTCmd1(0x04);
        }

        /**********************************
        SST25BY 檢測忙
        **********************************/
        u8 SST25BY(void)
        {
        u8 sta;
        sta=SSTCmdb1b(0x05);
        return(sta&0x01);
        }

        /***********************************
        SST25WPEN 允許軟件寫保護
        注意事項:25的寫入比較繁瑣,建議在每次操作前都取消掉寫保護,操作完成后則重新允許寫保護

        ***********************************/
        void SST25WPEN(void)
        {
        u8 sta;
        sta=SSTCmdb1b(0x05)|0x1c;//讀出寄存器并加入保護位
        SSTCmd1(0x50);//允許寫Status Register
        SSTCmd2(0x01,sta);
        }

        //先消除保護位,再允許寫位
        void SST25WriteEn(void)
        {
        u8 sta;
        sta=SSTCmdb1b(0x05)&(~0x1c);//讀出寄存器并消除保護位
        SSTCmd1(0x50);//允許寫寄存器Status Register
        SSTCmd2(0x01,sta);//寫寄存器
        SSTCmd1(0x06);//允許寫
        }

        /********************************寄存器Status Register**********************************/

        就是這樣實現寫保護。

        /**********************************
        SST25ReadID 讀取SST的ID 這個功能 呵呵不用多說~當然單純的讀寫操作肯定用不上
        **********************************/
        u16 SST25ReadID(void)
        {
        u8 id[3];
        u8 addr[3]={0,0,0};

        SSTCmd4bs(0x90,addr,id,3);
        return((id[0]<<8)+id[1]);
        }

        /**********************************
        SST25ChipErase 刷除CHIP
        **********************************/
        void SST25ChipErase(void)
        {
        SST25WriteEn();
        SSTCmd1(0x60);
        while(SST25BY());
        SST25WPEN();
        }

        /***********************************
        SST25SectorErase 刷扇區 用的是4kb大小 假如地址在0~4095 之間那么這之間的地址都會刷除

        當然我給 4096 的話4096到4096+4095 之間都會刷掉
        ***********************************/
        void SST25SectorErase(u32 addr)
        {
        u8 ad[3];
        ad[0]=(addr>>16)&0xff;
        ad[1]=(addr>>8)&0xff;
        ad[2]=addr&0xff;


        SST25WriteEn();

        SST_SELECT();
        SPIByte(0x20);
        SPIByte(ad[0]);
        SPIByte(ad[1]);
        SPIByte(ad[2]);
        SST_DESELECT();

        while(SST25BY());
        //SST25WPEN();
        }

        /**********************************
        SST25ByteProgram 寫一個字節*注意在此前要調用取消寫保護,實際寫應使用AAI,此函數在AAI中調用,用于寫奇數個字節
        **********************************/
        void SST25ByteProgram(u32 addr,u8 byte)
        {
        u8 ad[3];
        ad[0]=(addr>>16)&0xff;
        ad[1]=(addr>>8)&0xff;
        ad[2]=addr&0xff;

        SST_SELECT();
        SPIByte(0x02);
        SPIByte(ad[0]);
        SPIByte(ad[1]);
        SPIByte(ad[2]);
        SPIByte(byte);
        SST_DESELECT();
        while(SST25BY());
        }

        /***********************************
        SST25Write 寫多個字節
        ***********************************/
        void SST25Write(u32 addr,u8* p_data,u32 no)
        {
        u8 ad[3];
        u32 cnt;
        if(no==0)
        return;

        SST25WriteEn();

        if(no==1)//no<2則應使用普通單字節方式
        {
        SST25ByteProgram(addr,*p_data);
        //SST25WPEN();
        }
        else
        {
        cnt=no;

        ad[2]=(addr>>16)&0xff;
        ad[1]=(addr>>8)&0xff;
        ad[0]=addr&0xff;

        SST_SELECT();
        SPIByte(0xad);
        SPIByte(ad[2]);
        SPIByte(ad[1]);
        SPIByte(ad[0]);
        SPIByte(*p_data++);
        SPIByte(*p_data++);
        SST_DESELECT();
        cnt-=2;
        while(SST25BY());//判忙

        //中間的雙字節寫
        for(;cnt>1;cnt-=2)
        {
        SST_SELECT();
        SPIByte(0xad);
        SPIByte(*p_data++);
        SPIByte(*p_data++);
        SST_DESELECT();
        while(SST25BY());//判忙
        }
        SST25WRDI();//WRDI用于退出AAI寫模式 所謂AAI 就是地址自動加

        //如果有最后一個字節(no為奇數)
        if(cnt==1)
        {
        SST25WriteEn();
        SST25ByteProgram(addr+no-1,*p_data);
        }
        }
        SST25WPEN();//WP保護
        }

        //我們用的是下邊這種


        /*************************************
        SST25Read 高速讀 對于后續帶5的芯片,可調用此函數讀
        *************************************/
        void SST25Read(u32 addr,u8* p_data,u32 no)
        {
        SST_SELECT();

        SPIByte(0x0b);
        SPIByte(addr>>16);
        SPIByte(addr>>8);
        SPIByte(addr);
        SPIByte(0xff);

        for(;no>0;no--)
        *p_data++=SPIByte(0xff);
        SST_DESELECT();
        }

        /****************************************
        SST25ReadL 低速讀
        ****************************************/
        void SST25ReadL(u32 addr,u8* p_data,u32 no)
        {
        u8 ad[3];
        ad[2]=(addr>>16)&0xff;
        ad[1]=(addr>>8)&0xff;
        ad[0]=addr&0xff;

        SSTCmd4bs(0x03,ad,p_data,no);
        }


        好了 所有的底層讀寫都做好了~!
        后面~~
        SST25SectorErase(0);//擦除 0~4095 地址之間的數據
        SST25Write(addr,db_sst1,64);//往addr 寫入db_sst164個字節
        SST25Read(addr,db_sst1,64);//從addr讀64個字節到db_sst1
        就這些接口常用了~~~



        評論


        技術專區

        關閉
        主站蜘蛛池模板: 宜宾县| 班玛县| 时尚| 平利县| 剑川县| 宜丰县| 东莞市| 德惠市| 太湖县| 泸溪县| 宁武县| 泰来县| 云林县| 榆树市| 柳林县| 安溪县| 额尔古纳市| 自治县| 呼图壁县| 柳林县| 陆川县| 新巴尔虎左旗| 鲁甸县| 宜昌市| 高陵县| 湖北省| 垣曲县| 游戏| 江永县| 甘谷县| 澳门| 上栗县| 胶州市| 曲麻莱县| 栖霞市| 宣武区| 牡丹江市| 威海市| 胶南市| 固始县| 洪泽县|