打印
[DemoCode下载]

N76E003 软SPI 驱动 W25X大容量EEPROM,附全部源文件

[复制链接]
2055|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tianxj01|  楼主 | 2018-7-29 09:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 tianxj01 于 2018-7-29 10:09 编辑

因为003芯片硬件SPI已经被单独占用,而外部W25X64使用频率不高,因此用IO模拟SPI进行驱动是一个很好的方法。硬件连接:由于W25X64 是3.3V,而我的003用的是5V,所以这里全部采用外接3.3K电阻上拉3.3V,003端口输入采用高阻外部上拉,输出采用开漏,上拉。

下面给出全部源代码:(SPI_Flash_cmd.h)
#ifndef __SPI_FLASH_CMD_H__
#define __SPI_FLASH_CMD_H__

#define W25X_BUSY       0
#define W25X_NotBUSY    1   
#define Dummy_Byte1     0xFF

/*********************************************
- W25X的操作指令表,MCU通过向W25X
  发送以下指令就可以对W25X进行以下的操作
*********************************************/
#define W25X_WriteEnable            0x06    //Write Enable
#define W25X_WriteEnableVSR         0x50    //Write Enable for Volatile Status Register
#define W25X_WriteDisable           0x04    //Write Disable
#define W25X_ReadStatusReg1         0x05    //读状态寄存器1:S7~S0
#define W25X_ReadStatusReg2         0x35    //读状态寄存器2:S15~S8
#define W25X_WriteStatusReg         0x01    //写读状态寄存器:BYTE1:S7~S0  BYTE2:S15~S8
#define W25X_PageProgram            0x02    //单页编程:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:D7~D0
#define W25X_SectorErase            0x20    //扇区擦除:4K  BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0
#define W25X_BlockErase32K          0x52    //块擦除:32K  BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0
#define W25X_BlockErase64K          0xD8    //块擦除:64K  BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0
#define W25X_ChipErase              0xC7    //芯片擦除
#define W25X_EraseSuspend           0x75    //暂停擦除
#define W25X_EraseResume            0x7A    //恢复擦除
#define W25X_PowerDown              0xB9    //掉电
#define W25X_ContinuousReadMode     0xFF    //连续读模式
#define W25X_ReadData               0x03    //读数据:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:D7~D0
#define W25X_FastReadData           0x0B    //快速读取:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:dummy  BYTE5:D7~D0
#define W25X_FastReadDual           0x3B    //快速双读取:BYTE1:A23~A16  BYTE2:A15~A8  BYTE3:A7~A0  BYTE4:dummy  BYTE5:D7~D0
#define W25X_ReleasePowerDown       0xAB   
#define W25X_DeviceID               0xAB
#define W25X_ManufactDeviceID       0x90
#define W25X_JedecDeviceID          0x9F

#endif
SPI_Flash_reg.h:
/**************************************
软SPI端口连接
P16  -- spi cs
P15  -- spi clock
P14  -- spi MOSI
P13  -- spi MISO   
***************************************/
#define SPI_CS                P16
#define SPI_CLK                P15
#define SPI_MOSI        P14
#define SPI_MISO        P13

void SPI_Flash_Init_IO (void);
void SPI_Flash_WriteEnable  (void);
void SPI_Flash_WriteDisable (void);
void SPI_Flash_Wait_Busy (void);
void SPI_Flash_Read ( u32 ReadAddr , u8* pBuffer , u16 NumByteToRead );
void SPI_Flash_Write_Page (u32 WriteAddr, u8* pBuffer , u16 NumByteToWrite);
void SPI_Flash_Erase_Block( u32 Erase_Addr ,u8 mode );

unsigned int  SPI_Flash_ReadID(void);
unsigned char SPI_Flash_Read_Busy(void);
unsigned char SPI_Flash_Write_Byte(unsigned char Data);





沙发
tianxj01|  楼主 | 2018-7-29 09:58 | 只看该作者
什么情况,怎么没有发完整,晕

使用特权

评论回复
板凳
tianxj01|  楼主 | 2018-7-29 10:02 | 只看该作者
本帖最后由 tianxj01 于 2018-7-29 10:05 编辑

继续:
SPI_Flash_reg.c:
#include <stdio.h>
#include "N76E003.h"
#include "Common.h"
#include "SFR_Macro.h"
#include "Function_define.h"
#include "SPI_Flash_reg.h"
#include "SPI_Flash_cmd.h"

#define NOP()                _nop_();
/**************************************
软SPI端口连接
P16  -- spi cs
P15  -- spi clock
P14  -- spi MOSI
P13  -- spi MISO   
***************************************/

void SPI_Flash_Init_IO(void)
        {
               
P13_Input_Mode;
P14_OpenDrain_Mode;P14=0;
P15_OpenDrain_Mode;P15=0;
P16_OpenDrain_Mode;P16=1;
}
/***************************************************************************
函 数 名:SPI_Flash_Write_Byte
功    能:软SPI_Flash 总线驱动基础函数,发送单个字节到MOSI,并同时接受MISO数据
参    数:unsigned char Data MOSI数据线上发送的数据
返    回:unsigned char Out         MISO数据线上接受的数据
****************************************************************************/
unsigned char SPI_Flash_Write_Byte(unsigned char Data)
        {
                unsigned char Out = 0;
                unsigned char i;// = 0;
                //SPI_CLK = 0;
                for(i = 8; i > 0; i--)
                        {
                                SPI_CLK = 0;
                                SPI_MOSI=Data>>7;
                                Data <<= 1;
                                NOP();
                                NOP();
                                NOP();
                                NOP();
                                NOP();
                                Out<<=1;
                                SPI_CLK = 1;
                                Out|=SPI_MISO;
                        }
                SPI_CLK = 0;
                return Out;
        }
//*************** 写使能 ****************************  OK
void SPI_Flash_WriteEnable  (void)
        {
                SPI_CS = 0;
                NOP();
                NOP();
                SPI_Flash_Write_Byte(W25X_WriteEnable);
                NOP();
                NOP();
                SPI_CS = 1;
        }

//*************** 写禁止 ****************************    OK
void SPI_Flash_WriteDisable (void)
        {
                SPI_CS = 0;
                NOP();
                NOP();
                SPI_Flash_Write_Byte(W25X_WriteDisable);
                NOP();
                NOP();
                SPI_CS = 1;
        }

/***************BUSY等待*********************************************
函 数 名:SPI_Flash_Wait_Busy
功    能:读FLASH的BUSY,如果忙就等待。BUSY的原因是擦除,或是连续读写
*********************************************************************/
void SPI_Flash_Wait_Busy(void)
        {                                
                unsigned char test;        
                SPI_CS = 0;
            do
                        {
                                SPI_Flash_Write_Byte(W25X_ReadStatusReg1);
                                test = SPI_Flash_Write_Byte(Dummy_Byte1);
                                //  连续读StatusReg1,不影响总操作时间,也就是芯片不会添忙
                        }
                while ((test&0x01)==0x01);
                SPI_CS = 1;
        }
/***************读BUSY*********************************************
函 数 名:SPI_Flash_Read_Busy
功    能:读FLASH的BUSY
返    回:空返回NotBUSY,忙返回BUSY
*********************************************************************/
unsigned char SPI_Flash_Read_Busy(void)
        {                                
                unsigned char test;        
                SPI_CS = 0;
            SPI_Flash_Write_Byte(W25X_ReadStatusReg1);
                test = SPI_Flash_Write_Byte(Dummy_Byte1);
                SPI_CS = 1;
                if(test&0x01)return (W25X_BUSY);
                else return (W25X_NotBUSY);
        }
/************************************************************************
函 数 名:SPI_Flash_Erase_Block
功能描述: 擦除一个32K or 64K 块
输入参数: u32 Data_Addr 开始擦除的块首地址
mode        擦除模式 1=32K 其他=64K
************************************************************************/
void SPI_Flash_Erase_Block( u32 Erase_Addr ,u8 mode )
        {
                SPI_Flash_WriteEnable();
                SPI_Flash_Wait_Busy();
                SPI_CS = 0;
                if(mode==1){SPI_Flash_Write_Byte(W25X_BlockErase32K);}  //根据定义,发送32K或64K擦除指令
                else {SPI_Flash_Write_Byte(W25X_BlockErase64K);}
                SPI_Flash_Write_Byte(Erase_Addr >> 16);
            SPI_Flash_Write_Byte(Erase_Addr >> 8);
            SPI_Flash_Write_Byte(Erase_Addr);
                SPI_CS = 1;
                SPI_Flash_Wait_Busy();                //等待擦除完成
        }

/************************************************************************
函 数 名  : SPI_Flash_Read
功能描述  : 在指定地址开始读取指定长度的数据
输入参数  : u32 ReadAddr       开始读取的地址(24bit)
u8* pBuffer        数据存储区
u16 NumByteToRead  要读取的字节数(最大65535)
*****************************************************************************/
void SPI_Flash_Read ( u32 ReadAddr , u8* pBuffer , u16 NumByteToRead )
        {
                u16 i;
                SPI_CS = 0;/* Enable chip select */
                SPI_Flash_Write_Byte(W25X_ReadData);
                SPI_Flash_Write_Byte(ReadAddr >> 16);
                SPI_Flash_Write_Byte(ReadAddr >> 8);
                SPI_Flash_Write_Byte(ReadAddr);
                for(i=0;i<NumByteToRead;i++)
                        {
                                pBuffer[i] = SPI_Flash_Write_Byte(Dummy_Byte1); //Read one byte
                        }
                SPI_CS = 1;/* Disable chip select */
        }
/*************************************************************************
函 数 名:SPI_Flash_Write_Page
功    能:SPI在一页(0~65535)的指定地址开始写入最大256字节的数据
输入参数:pBuffer:数据存储区
WriteAddr:开始写入的地址(24bit)
NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!
***************************************************************************/
void SPI_Flash_Write_Page (u32 WriteAddr, u8* pBuffer , u16 NumByteToWrite)
        {
                u16 i;  
                SPI_Flash_WriteEnable();                  //SET WEL
                SPI_CS = 0;
                SPI_Flash_Write_Byte(W25X_PageProgram);      //发送写页命令   
                SPI_Flash_Write_Byte((u8)((WriteAddr)>>16)); //发送24bit地址   
                SPI_Flash_Write_Byte((u8)((WriteAddr)>>8));   
                SPI_Flash_Write_Byte((u8)WriteAddr);   
                for(i=0;i<NumByteToWrite;i++)SPI_Flash_Write_Byte(pBuffer[i]);//循环写数  
                SPI_CS = 1;                                          //取消片选
        SPI_Flash_Wait_Busy();                  //等待写入结束
                SPI_Flash_WriteDisable();
        }

/*******************************************************************************
* Function Name  : SPI_FLASH_ReadID
* Description    : Reads FLASH identification.
* Input          : None
* Output         : None
* Return         : FLASH identification
*******************************************************************************/
unsigned int SPI_Flash_ReadID(void)
        {
                u16        Temp = 0;
                /* Enable chip select */
                SPI_CS = 0;
                /* Send "RDID " instruction */
                SPI_Flash_Write_Byte(W25X_ManufactDeviceID);
                SPI_Flash_Write_Byte(0x00);
                SPI_Flash_Write_Byte(0x00);
                SPI_Flash_Write_Byte(0x00);
                /* Read a byte from the FLASH */
                Temp|= SPI_Flash_Write_Byte(Dummy_Byte1)<<8;
                Temp|= SPI_Flash_Write_Byte(Dummy_Byte1);
                /* Disable chip select */
                SPI_CS = 1;
                return Temp;
        }

使用特权

评论回复
地板
xuanhuanzi| | 2018-7-29 12:57 | 只看该作者
不错,好资料,注释的完整啊。

使用特权

评论回复
5
xixi2017| | 2018-7-29 16:21 | 只看该作者
楼主这个掌握的不错。

使用特权

评论回复
6
xinxianshi| | 2018-7-29 19:05 | 只看该作者
51内核的跑模拟通信接口最合适了。

使用特权

评论回复
7
21mengnan| | 2018-7-29 19:29 | 只看该作者
不错,这个宏替换搞的好,可以随意修改IO。

使用特权

评论回复
8
mintspring| | 2018-7-29 20:16 | 只看该作者
我擦,给力,我要保存下来。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

17

主题

3210

帖子

87

粉丝