• 【框架】SPI四种模式+通用设备驱动实现-源码



    前言

    • SPI 介绍为搜集百度资料+个人理解
    • 其余为原创(有误请指正)
    • 集四种模式于一身
    • demo 采用MX25L64的FLASH芯片

    bsp_spi.c

    /**
      ******************************************************************************
      * @file    bsp_spi.c
      * @author  lzm
      * @version V1.0
      * @date    2020-09-26
      * @brief    采用 软件 SPI
      * @attention
      *
      * 实验平台:LZM
      * 
      ******************************************************************************
      */
    #include "bsp_spi.h"
    
    /*
    *********************************************************************************************************
    *                  DEFINE STATIC FUNCTION (API)
    *********************************************************************************************************
    */
    /* basic */
    #define spiOutHi(gpio, pin) {gpio->BSRR=pin;}	 //输出为高电平		
    #define spiOutLo(gpio, pin) {gpio->BRR=pin;}	 //输出为低电平		
    #define spiOut(gpio, pin, lev) (lev)?(gpio->BSRR=pin):(gpio->BRR=pin)
    #define spiIn(gpio, pin) GPIO_ReadInputDataBit(gpio, pin)
    /* top */
    
    /* spi 为指针 */
    #define spiCsOutHi(spi) spiOutHi(spi->csGpiox, spi->csPin)
    #define spiCsOutLo(spi) spiOutLo(spi->csGpiox, spi->csPin)
    #define spiSckOutHi(spi) spiOutHi(spi->sckGpiox, spi->sckPin)
    #define spiSckOutLo(spi) spiOutLo(spi->sckGpiox, spi->sckPin)
    #define spiMosiOutHi(spi) spiOutHi(spi->mosiGpiox, spi->mosiPin)
    #define spiMosiOutLo(spi) spiOutLo(spi->mosiGpiox, spi->mosiPin)
    #define spiMisoIn(spi)    spiIn(spi->misoGpiox, spi->misoPin)
    
    /*
    *********************************************************************************************************
    *                                                 DEFINE
    *********************************************************************************************************
    */
    // spi 驱动元素(驱动表)
    spi_t spiDriverElem[spiSPI_DRIVER_COUNT];
    
    /**
      * @brief  选出时钟信号线
      * @param 
      * @retval 
      * @author lzm
      */
    static uint32_t __selectClkByGpio(const uint32_t addr)
    {
        switch(addr)
        {
            case GPIOA_BASE:
                return RCC_APB2Periph_GPIOA;
            case GPIOB_BASE:
                return RCC_APB2Periph_GPIOB;
            case GPIOC_BASE:
                return RCC_APB2Periph_GPIOC;
            case GPIOD_BASE:
                return RCC_APB2Periph_GPIOD;
            case GPIOE_BASE:
                return RCC_APB2Periph_GPIOE;
            case GPIOF_BASE:
                return RCC_APB2Periph_GPIOF;
            case GPIOG_BASE:
                return RCC_APB2Periph_GPIOG;
        }
        return NULL;
    }
    
    /**
      * @brief  初始化 SPI 引脚 
      * @param 
      * @retval 
      * @author lzm
      */
    void spiGpioInit(eSPI_ID id)
    {
    	GPIO_InitTypeDef        GPIO_InitStructure;  //定义结构体
    	uint32_t                csGpioClk;
    	uint32_t                sckGpioClk;
    	uint32_t                mosiGpioClk;
    	uint32_t                misoGpioClk;
    	const spi_t *           spi = &spiDriverElem[id];
    
    	csGpioClk   = __selectClkByGpio((uint32_t)(spi->csGpiox));
    	sckGpioClk  = __selectClkByGpio((uint32_t)(spi->sckGpiox));
    	mosiGpioClk = __selectClkByGpio((uint32_t)(spi->csGpiox));
    	misoGpioClk = __selectClkByGpio((uint32_t)(spi->misoGpiox));
    
    	RCC_APB2PeriphClockCmd(csGpioClk | sckGpioClk | mosiGpioClk | misoGpioClk, ENABLE);  //打开时钟
    
    	GPIO_InitStructure.GPIO_Pin = spi->csPin;     //配置端口及引脚(指定方向)
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Speed =  GPIO_Speed_50MHz;	     
    	GPIO_Init(spi->csGpiox, &GPIO_InitStructure);    //初始化端口(开往指定方向)
    
    	GPIO_InitStructure.GPIO_Pin = spi->sckPin;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(spi->sckGpiox, &GPIO_InitStructure);
    	
    	GPIO_InitStructure.GPIO_Pin = spi->mosiPin;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    	GPIO_Init(spi->mosiGpiox, &GPIO_InitStructure);
    
    	GPIO_InitStructure.GPIO_Pin = spi->misoPin;
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    	GPIO_Init(spi->misoGpiox, &GPIO_InitStructure);
    	
    	spiCsOutHi(spi);
    }
    
    
    
    /**
      * @brief  SPI 发送
      * @param 
      * @retval 
      * @author lzm
      */
    void spiWriteOneByte(eSPI_ID id, unsigned char data)
    {
    	unsigned char i;
    	const spi_t * spi = &spiDriverElem[id];
    	
    	if(spi->CPHA){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    //	spi->delayUsFun(spi->readDelayUsCnt);
    	
    	for(i=0; i<8; i++)
    	{
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));
    		if(data & 0x80){
    			spiMosiOutHi(spi);
    		}
    		else{
    			spiMosiOutLo(spi);
    		}
    		data <<= 1;
    		spi->delayUsFun(spi->readDelayUsCnt);
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));
    	}
    	if(!(spi->CPHA)){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    }
    
    /**
      * @brief  SPI 读取
      * @param 
      * @retval 
      * @author lzm
      */
    unsigned char spiReadOneByte(eSPI_ID id)
    {
    	unsigned char i;
    	unsigned char ret;
    	const spi_t * spi = &spiDriverElem[id];
    	
    	for(i=0; i<8; i++)
    	{
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));	
    		ret <<= 1;
    		if(spiMisoIn(spi))
    			ret |= 0x01;
    		else
    			ret &= 0xfe;
    		spi->delayUsFun(spi->readDelayUsCnt);
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));
    	}
    	spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	return ret;
    }
    
    /**
      * @brief  SPI 读写
      * @param 
      * @retval 
      * @author lzm
      */
    unsigned char spiRWOneByte(eSPI_ID id, unsigned char data)
    {
    	unsigned char i;
    	unsigned char ret;
    	const spi_t * spi = &spiDriverElem[id];
    	
    	if(spi->CPHA){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    	
    	for(i=0; i<8; i++)
    	{
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL != spi->CPHA));
    		if(data & 0x80){
    			spiMosiOutHi(spi);
    		}
    		else{
    			spiMosiOutLo(spi);
    		}
    		data <<= 1;
    		spi->delayUsFun(spi->readDelayUsCnt);
    		spiOut(spi->sckGpiox, spi->sckPin, (spi->CPOL == spi->CPHA));
    		ret <<= 1;
    		if(spiMisoIn(spi))
    			ret |= 0x01;
    		else
    			ret &= 0xfe;
    		spi->delayUsFun(spi->readDelayUsCnt);
    	}
    	if(!(spi->CPHA)){
    		spiOut(spi->sckGpiox, spi->sckPin, spi->CPOL);
    	}
    }
    
    /**
      * @brief  SPI 片选使能
      * @param 
      * @retval 
      * @author lzm
      */
    void spiCSOut(eSPI_ID id, unsigned char lev)
    {
    	const spi_t * spi = &spiDriverElem[id];
    	
    	spiOut(spi->csGpiox, spi->csPin, lev);
    }
    
    /*
    *********************************************************************************************************
    *                                                 DEFINE [API] FUNCTION
    *********************************************************************************************************
    */
    /**
      * @brief  注册SPI设备
      * spiDriverElem[spiID].id = spiID; // 保持下标与ID相等,查找时可以直接定位,实现时间复杂度为O(1);
      * @param 
      * @retval 
      * @author lzm
      */
    void REGISTER_SPI_DEV(spi_t * spi)
    {
    	if(spi->id >= espiSPI_DRIVER_COUNT)
    		return;
      spiDriverElem[spi->id].id = spi->id;
    	spiDriverElem[spi->id].method = spi->method;
    	spiDriverElem[spi->id].CPOL = spi->CPOL;
    	spiDriverElem[spi->id].CPHA = spi->CPHA;
    	spiDriverElem[spi->id].readDelayUsCnt = spi->readDelayUsCnt;
    	spiDriverElem[spi->id].delayUsFun = spi->delayUsFun;
    	spiDriverElem[spi->id].csGpiox = spi->csGpiox;
    	spiDriverElem[spi->id].csPin = spi->csPin;
    	spiDriverElem[spi->id].sckGpiox = spi->sckGpiox;
      spiDriverElem[spi->id].sckPin = spi->sckPin;
    	spiDriverElem[spi->id].mosiGpiox = spi->mosiGpiox;
      spiDriverElem[spi->id].mosiPin = spi->mosiPin;
    	spiDriverElem[spi->id].misoGpiox = spi->misoGpiox;
      spiDriverElem[spi->id].misoPin = spi->misoPin;
    }
    

    bsp_spi.h

    /**
      ******************************************************************************
      * @file    bsp_spi.h
      * @author  lzm
      * @version V1.0
      * @date    2020-09-26
      * @brief    采用 硬件 SPI
      * @attention
      *
      * 实验平台:LZM
      * 
      ******************************************************************************
      */
    
    #ifndef _BSP_SPI_H_
    #define _BSP_SPI_H_
    
    #include "LssAppConfig.h"
    
    /*
    *********************************************************************************************************
    *                                                 CONFIG API
    *********************************************************************************************************
    */
    // [注][spi]实时修改
    // spi 设备数量
    #define spiSPI_DRIVER_COUNT 1
    /* spi id. */
    typedef enum
    {
      espiFLASH_A = 0,
    	
    	espiSPI_DRIVER_COUNT,
    }eSPI_ID;
    
    /* spi mode. */
    typedef enum
    {
      espiHARDWARE = 0,
    	
    	espiSOFTWARE,
    }eSPI_METHOD;
    
    /*
    *********************************************************************************************************
    *                                                 BASIC
    *********************************************************************************************************
    */
    /* spi */
    struct SPI_T{
    	/* id */
    	eSPI_ID id;
    	
    	/* software spi */
    	/* method */
    	eSPI_METHOD method;
    	/* CPOL CPHA : 00 01 10 11*/
    	/* cpol */
    	unsigned char CPOL;
    	/* cpha */
    	unsigned char CPHA;
    	/* delay */
    	/* cnt */
    	unsigned int readDelayUsCnt;
    	/* function */
      void ( *delayUsFun )(int cnt);
    	
    	/* hardware spi */
    	SPI_TypeDef* SPIx;
    	
    	/* pin */
    	GPIO_TypeDef *  csGpiox;
    	uint16_t        csPin;
    	GPIO_TypeDef *  sckGpiox;
    	uint16_t        sckPin;
    	GPIO_TypeDef *  mosiGpiox;
    	uint16_t        mosiPin;
    	GPIO_TypeDef *  misoGpiox;
    	uint16_t        misoPin;	
    };
    typedef struct SPI_T spi_t;
    
    
    
    
    /*
    *********************************************************************************************************
    *                                          BROADCAST 
    *********************************************************************************************************
    */
    /* device table */
    extern spi_t spiDriverElem[spiSPI_DRIVER_COUNT];
    
    /* function */
    void spiGpioInit(eSPI_ID id);
    void spiWriteOneByte(eSPI_ID id, unsigned char data);
    unsigned char spiReadOneByte(eSPI_ID id);
    void spiCSOut(eSPI_ID id, unsigned char lev);
    void REGISTER_SPI_DEV(spi_t * spi);
    
    #endif
    
    

    bsp_flash.c

    /**
      ******************************************************************************
      * @file    bsp_flash.c
      * @author  lzm
      * @version V1.0
      * @date    2020-10-29
      * @brief    
      * @attention
      *
      * 实验平台:LZM
      * 
      ******************************************************************************
      */
    
    #include "bsp_flash.h"
    #include "lss_IO.h"
    #include "boardInfo.h"
    
    /*
    *********************************************************************************************************
    *                                                 DEFINE
    *********************************************************************************************************
    */
    // flash 设备元素(设备表)
    flash_t flashDeviceElem[flashFLASH_DEVICE_COUNT];
    
    
    /**
      * @brief  写一个字节到外挂 Flash
      * @param  id :   flash 设备 id
      * @param  data : 需要写入的数据
      * @retval 
      * @author lzm
      */
    void flashWriteByte(eFLASH_ID id, unsigned char data)
    {
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	spiWriteOneByte(spiid, data);
    }
    
    /**
      * @brief  从外挂flash中读取一个字节
      * @param  id :   flash 设备 id
      * @param  data : 需要写入的数据
      * @retval 
      * @author lzm
      */
    unsigned char flashReadByte(eFLASH_ID id)
    {
    	unsigned char ch;
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	ch = spiReadOneByte(spiid);
    	return ch;
    }
    
    
    /*
    *********************************************************************************************************
    *                         [业务]
    *********************************************************************************************************
    */
    /**
      * @brief  读取flash状态寄存器
      * @brief  BIT7  6   5   4   3   2   1   0
      * @brief  SPR   RV  TB BP2 BP1 BP0 WEL BUSY
      * @brief  SPR:默认0,状态寄存器保护位,配合WP使用
      * @brief  TB,BP2,BP1,BP0:FLASH区域写保护设置
      * @brief  WEL:写使能锁定
      * @brief  BUSY:忙标记位(1,忙;0,空闲)
      * @brief  默认:0x00
      * @param  id :   flash 设备 id
      * @author lzm
      */
    unsigned char mx25lxxReadSR(eFLASH_ID id)
    {
    	unsigned char ch;
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);
    	spiWriteOneByte(spiid, mx25lxxREAD_STATUS_REG);
    	ch = spiReadOneByte(spiid);
    	spiCSOut(spiid, 1);
    	
    	return ch;
    }
    
    /**
      * @brief  写flash状态寄存器
      * @brief  只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!
      * @param  id :   flash 设备 id
      * @author lzm
      */
    void mx25lxxWriteSR(eFLASH_ID id, unsigned char data)
    {
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);
    	spiWriteOneByte(spiid, mx25lxxWRITE_STATUS_REG);
    	spiWriteOneByte(spiid, data);
    	spiCSOut(spiid, 1);
    }
    
    /**
      * @brief  等待空闲
      * @param  id :   flash 设备 id
      * @author lzm
      */
    void mx25lxxWaitBusy(eFLASH_ID id)
    {
    	while((mx25lxxReadSR(id)&0x01)==0x01);  		// 等待BUSY位清空
    }  
    
    /**
      * @brief  写使能
      * @param  id :   flash 设备 id
      * @author lzm
      */
    void mx25lxxWriteEnable(eFLASH_ID id)
    {
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);
    	spiWriteOneByte(spiid, mx25lxxWRITE_ENABLE);
    	spiCSOut(spiid, 1);
    }
    
    /**
      * @brief  写禁止
      * @param  id :   flash 设备 id
      * @author lzm
      */
    void mx25lxxWriteDisable(eFLASH_ID id)
    {
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);
    	spiWriteOneByte(spiid, mx25lxxWRITE_DISABLE);
    	spiCSOut(spiid, 1);
    }
    
    /**
      * @brief  读取芯片ID
      * @param id :   flash 设备 id
      * @retval 0Xxx13,表示芯片型号为W25Q80  
      * @retval 0Xxx14,表示芯片型号为W25Q16    
      * @retval 0Xxx15,表示芯片型号为W25Q32  
      * @retval 0Xxx16,表示芯片型号为W25Q64 
      * @retval 0Xxx17,表示芯片型号为W25Q128 	
      * @author lzm
      */
    unsigned int mx25lxxReadID(eFLASH_ID id)
    {
    	unsigned int ret;
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);	
    	
    	spiWriteOneByte(spiid, 0x90);
    	spiWriteOneByte(spiid, 0x00);
    	spiWriteOneByte(spiid, 0x00);
    	spiWriteOneByte(spiid, 0x00);
    	ret |= spiReadOneByte(spiid)<<8;
    	ret |= spiReadOneByte(spiid);
    	
    	spiCSOut(spiid, 1);	
    	
    	return ret;
    }
    
    /**
      * @brief  在指定地址开始读取指定长度的数据
      * @param  id :   flash 设备 id
    	* @param  readAddr : 开始读取的地址(24bit)
    	* @param  pReadBuff : 数据存储区
    	* @param  size : 字节数
      * @author lzm
      */
    void mx25lxxReadBytes(eFLASH_ID id, uint32_t readAddr, uint8_t * pReadBuff, uint16_t size)
    {
    	uint16_t i;
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);	
    	
    	spiWriteOneByte(spiid, mx25lxxREAD_DATA);
    	spiWriteOneByte(spiid, (u8)((readAddr)>>16));
    	spiWriteOneByte(spiid, (u8)((readAddr)>>8));
    	spiWriteOneByte(spiid, (u8)readAddr);
    	for(i=0;i<size;i++)
    	{ 
            pReadBuff[i]=spiReadOneByte(spiid);   	//循环读数  
      }
    	
    	spiCSOut(spiid, 1);	
    
    }
    
    /**
      * @brief  在指定地址开始写入最大256字节的数据
      * @param  id :   flash 设备 id
    	* @param  writeAddr : 开始写的地址(24bit)
    	* @param  pReadBuff : 数据存储区
    	* @param  size : 字节数
      * @author lzm
      */
    void mx25lxxWriteBytes(eFLASH_ID id, uint32_t writeAddr, uint8_t * pWriteBuff, uint16_t size)
    {
    	uint16_t i;
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	mx25lxxWriteEnable(id);
    	spiCSOut(spiid, 0);	
    	
    	spiWriteOneByte(spiid, mx25lxxPAGE_PROGRAM);
    	spiWriteOneByte(spiid, (u8)((writeAddr)>>16));
    	spiWriteOneByte(spiid, (u8)((writeAddr)>>8));
    	spiWriteOneByte(spiid, (u8)writeAddr);
    	for(i=0;i<size;i++)
    	{ 
    		spiWriteOneByte(spiid,pWriteBuff[i]);   	//循环读数  
      }
    	
    	spiCSOut(spiid, 1);	
    }
    
    /**
      * @brief  无检验写SPI FLASH 
      * @brief  必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!
      * @brief  具有自动换页功能 
      * @brief  在指定地址开始写入指定长度的数据,但是要确保地址不越界!
      * @param  id :   flash 设备 id
    	* @param  readAddr : 开始读取的地址(24bit)
    	* @param  pReadBuff : 数据存储区
    	* @param  size : 字节数
      * @author lzm
      */
    void mx25lxxWriteNoCheck(eFLASH_ID id, uint32_t writeAddr, uint8_t * pWriteBuff, uint16_t size)
    {
    	uint16_t residueSize;
    	
    	residueSize = 0xFF - writeAddr%0XFF;
    	if(size<=residueSize) residueSize=size;//不大于256个字节
    	
    	while(1)
    	{
    		mx25lxxWriteBytes(id, writeAddr, pWriteBuff, residueSize);
    		if(size==residueSize)
    			break;//写入结束了
    	 	else //size>pageremain
    		{
    			pWriteBuff+=residueSize;
    			writeAddr+=residueSize;		
    
    			size-=residueSize;			  //减去已经写入了的字节数
    			if(size>256)residueSize=256; //一次可以写入256个字节
    			else residueSize=size; 	  //不够256个字节了
    		}
    	}
    }
    
    /**
      * @brief  擦除一个扇区(擦除一个扇区的最少时间:150ms)
      * @param  id :   flash 设备 id
    	* @param  eraseAddr : 扇区地址 根据实际容量设置
      * @author lzm
      */
    void mx25lxxEraseSector(eFLASH_ID id, uint32_t eraseAddr)
    {
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
     	eraseAddr*=4096;
    	mx25lxxWriteEnable(id);  	//SET WEL 	 
    	mx25lxxWaitBusy(id);   
    	spiCSOut(spiid, 0);	 	//使能器件   
    	spiWriteOneByte(spiid, mx25lxxSECTOR_ERASE);      	//发送扇区擦除指令 
    	spiWriteOneByte(spiid, (u8)((eraseAddr)>>16));  	//发送24bit地址    
    	spiWriteOneByte(spiid, (u8)((eraseAddr)>>8));   
    	spiWriteOneByte(spiid, (u8)eraseAddr);  
    	spiCSOut(spiid, 1);	 	//取消片选     	      
    	mx25lxxWaitBusy(id);   		 	//等待擦除完成 
    }	
    	
    /**
      * @brief  进入掉电模式
      * @param  id :   flash 设备 id
      * @author lzm
      */
    void mx25lxxPowerDown(eFLASH_ID id)   
    { 
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);	 	//使能器件     
      spiWriteOneByte(spiid, mx25lxxPOWER_DOWN);        //发送掉电命令  
    	spiCSOut(spiid, 1);	 	//取消片选     	     
    }  
    
    /**
      * @brief  唤醒
      * @param  id :   flash 设备 id
      * @author lzm
      */
    void mx25lxxWakeUp(eFLASH_ID id)   
    { 
    	eSPI_ID spiid = flashDeviceElem[id].spiID;
    	
    	spiCSOut(spiid, 0);	 	//使能器件     
      spiWriteOneByte(spiid, mx25lxxRELEASE_POWER_DOWN);        //发送掉电命令  
    	spiCSOut(spiid, 1);	 	//取消片选     	     
    }  
    	
    /**
      * @brief  擦除其实就是写 1
      * @param  id :   flash 设备 id
    	* @param  eraseAddr : 开始写的地址(24bit)
    	* @param  pEraseBuff : 数据存储区
    	* @param  size : 字节数
      * @author lzm
      */
    uint8_t mx25lxxBUFFER[4096];		
    void mx25lxxEraseBytes(eFLASH_ID id, uint32_t eraseAddr, uint8_t * pEraseBuff, uint16_t size)
    {
    	uint16_t i;
    	uint32_t secAddr; //扇区地址  
    	uint16_t secOff; //在扇区内的偏移
    	uint16_t secResidueSize; //扇区剩余空间大小   
    	u8 * mx25lxxBUF;
    	
    	mx25lxxBUF = mx25lxxBUFFER;
     	secAddr=eraseAddr/4096;//扇区地址  
    	secOff=eraseAddr%4096;//在扇区内的偏移
    	secResidueSize=4096-secOff;//扇区剩余空间大小  
     	if(size<=secResidueSize)secResidueSize=size;//不大于4096个字节
    	while(1) 
    	{	
    		mx25lxxReadBytes(id, secAddr*4096, mx25lxxBUFFER, 4096);//读出整个扇区的内容 
    		for(i=0;i<secResidueSize;i++)//校验数据
    		{
    			if(mx25lxxBUF[secOff+i]!=0XFF)break;//需要擦除  	  
    		}
    		if(i<secResidueSize)//需要擦除
    		{
    			mx25lxxEraseSector(id, secAddr);		//擦除这个扇区
    			for(i=0;i<secResidueSize;i++)	   		//复制
    			{
    				mx25lxxBUF[i+secOff]=pEraseBuff[i];	  
    			}
    			mx25lxxWriteNoCheck(id,secAddr*4096,mx25lxxBUF,4096);//写入整个扇区 
    
    		}
    		else 
    			mx25lxxWriteNoCheck(id,eraseAddr,pEraseBuff,secResidueSize);//写已经擦除了的,直接写入扇区剩余区间.
    		
    		if(size==secResidueSize)
    			break;//写入结束了
    		else//写入未结束
    		{
    			secAddr++;//扇区地址增1
    			secOff=0;//偏移位置为0 	
    
    			pEraseBuff+=secResidueSize;  				//指针偏移
    			eraseAddr+=secResidueSize;				//写地址偏移	   
    			size-=secResidueSize;			//字节数递减
    			if(size>4096)   
    				secResidueSize=4096;//下一个扇区还是写不完
    			else 
    				secResidueSize=size;		//下一个扇区可以写完了
    		}	 
    	};	 
    }
    
    /**
      * @brief  擦除整个芯片(时间较长)
      * @param  id :   flash 设备 id
      * @author lzm
      */
    
    void ITC_MX25LXX_EraseChip(eFLASH_ID id)   
    {        
    	eSPI_ID spiid = flashDeviceElem[id].spiID;	
    	
    	mx25lxxWriteEnable(id);                 	 	//SET WEL 
    	mx25lxxWaitBusy(id);     
    	spiCSOut(spiid, 0);		//使能器件   
    	spiWriteOneByte(spiid, mx25lxxCHIP_ERASE);        	//发送片擦除命令  
    	spiCSOut(spiid, 1);	  	//取消片选     	      
    	mx25lxxWaitBusy(id);   				   		//等待芯片擦除结束
    }
    
    /**
      * @brief  所有外挂FLASH设备初始化
      * @param 
      * @retval 
      * @author lzm
      */
    void flashInit(void)
    {
    	uint8_t  flashID;
    	spi_t    spi;
    	unsigned int devID;
    
    	// 先注册 SPI 驱动
    	spi.id = espiFLASH_A;
    	spi.method = espiSOFTWARE; 
    	spi.CPOL = 1; 
    	spi.CPHA = 1; 
    	spi.readDelayUsCnt = 1; 
    	spi.delayUsFun = dwtDelayUs; 
    	spi.csGpiox = mx25lxxFLASH_SPI_CS_PORT; 
    	spi.csPin = mx25lxxFLASH_SPI_CS_PIN; 
    	spi.sckGpiox = mx25lxxFLASH_SPI_SCK_PORT; 
      spi.sckPin = mx25lxxFLASH_SPI_SCK_PIN; 
    	spi.mosiGpiox = mx25lxxFLASH_SPI_MOSI_PORT; 
      spi.mosiPin = mx25lxxFLASH_SPI_MOSI_PIN; 
    	spi.misoGpiox = mx25lxxFLASH_SPI_MISO_PORT; 
      spi.misoPin = mx25lxxFLASH_SPI_MISO_PIN; 
    	REGISTER_SPI_DEV(&spi);
    	// 注册 FLASH 设备并绑定 i2c
    	REGISTER_FLASH_DEV(eMX25lXX_1, espiFLASH_A);
    
    	for (flashID = 0; flashID < flashFLASH_DEVICE_COUNT; flashID++) 
    	{ 
    		// 初始化 I2C
    		spiGpioInit( (eSPI_ID)(espiFLASH_A + flashID) );
    		
    		devID = mx25lxxReadID((eFLASH_ID)flashID);
    		if(devID == 0XFFFF)
    		{
    			printf("
    [flashInit] [faild] and error devID is [%d]", devID);
    		}
    		else
    		{
    			printf("
    [flashInit] [successful] devID is [%d]", devID);
    		}
    	}
    }
    

    bsp_flash.h

    /**
      ******************************************************************************
      * @file    flash.h
      * @author  lzm
      * @version V1.0
      * @date    2020-10-29
      * @brief    
      * @attention
      *
      * 实验平台:ITC
      * 
      ******************************************************************************
      */
    
    #ifndef  _BSP_FLASH_H_
    #define  _BSP_FLASH_H_
    
    #include "LssAppConfig.h"
    #include "bsp_spi.h"
    
    /*
    *********************************************************************************************************
    *                                      MX25L64 指令表 [业务]
    *********************************************************************************************************
    */
    #define mx25lxxWRITE_ENABLE		0x06 
    #define mx25lxxWRITE_DISABLE		0x04 
    #define mx25lxxREAD_STATUS_REG		0x05 
    #define mx25lxxWRITE_STATUS_REG		0x01 
    #define mx25lxxREAD_DATA			  0x03 
    #define mx25lxxFAST_READ_DATA		0x0B 
    #define mx25lxxFAST_READ_DUAL		0x3B 
    #define mx25lxxPAGE_PROGRAM		0x02 
    #define mx25lxxBLOCK_ERASE			0xD8 
    #define mx25lxxSECTOR_ERASE		0x20 
    #define mx25lxxCHIP_ERASE			0xC7 
    #define mx25lxxPOWER_DOWN			0xB9 
    #define mx25lxxRELEASE_POWER_DOWN	0xAB 
    #define mx25lxxDEVICE_ID			  0xAB 
    #define mx25lxxMANUFACT_DEVICE_ID	0x90 
    #define mx25lxxJEDCE_DEVICE_ID		0x9F 
    
    /*
    *********************************************************************************************************
    *                                                 CONFIG API
    *********************************************************************************************************
    */
    /* [注][flash]实时修改 */
    // flash 设备数量
    #define flashFLASH_DEVICE_COUNT 1
    
    /* flash id. */
    typedef enum
    {
      eMX25lXX_1 = 0, // 
    	
    	eflashFLASH_DEVICE_COUNT,
    }eFLASH_ID;
    
    
    
    /*
    *********************************************************************************************************
    *                                                 BASIC
    *********************************************************************************************************
    */
    /* flash */
    struct FLASH_T{
        /* id */
        eFLASH_ID ID; 
        /* spi id */
        eSPI_ID spiID;
    };
    typedef struct FLASH_T flash_t;
    
    /*
    *********************************************************************************************************
    *                                                 DEFINE [API] FUNCTION
    *********************************************************************************************************
    */
    /**
      * @brief  注册IIC设备
      * @param 
      * @retval 
      * @author lzm
      */
    #define REGISTER_FLASH_DEV(flashid, spicid) 
    { 
        flashDeviceElem[flashid].ID = flashid; 
        flashDeviceElem[flashid].spiID = spicid; 
    }
    
    /*
    *********************************************************************************************************
    *                                          BROADCAST 
    *********************************************************************************************************
    */
    /* device table */
    extern flash_t flashDeviceElem[flashFLASH_DEVICE_COUNT];
    
    /* function */
    unsigned char mx25lxxReadSR(eFLASH_ID id);
    void mx25lxxWriteSR(eFLASH_ID id, unsigned char data);
    void mx25lxxWaitBusy(eFLASH_ID id);
    void mx25lxxWriteEnable(eFLASH_ID id);
    void mx25lxxWriteDisable(eFLASH_ID id);
    unsigned int mx25lxxReadID(eFLASH_ID id);
    void mx25lxxReadBytes(eFLASH_ID id, uint32_t readAddr, uint8_t * pReadBuff, uint16_t size);
    void mx25lxxWriteBytes(eFLASH_ID id, uint32_t writeAddr, uint8_t * pWriteBuff, uint16_t size);
    void mx25lxxWriteNoCheck(eFLASH_ID id, uint32_t writeAddr, uint8_t * pWriteBuff, uint16_t size);
    void mx25lxxEraseBytes(eFLASH_ID id, uint32_t eraseAddr, uint8_t * pEraseBuff, uint16_t size);
    void mx25lxxEraseSector(eFLASH_ID id, uint32_t eraseAddr);
    void mx25lxxPowerDown(eFLASH_ID id);
    void flashInit(void);
    #endif
    
    
    
  • 相关阅读:
    vue 购买弹出框 动画
    vue 和animate.css 的动画使用
    获得url地址?后的参数
    Java 实现随机数组元素升降序
    java for循环实现九九乘法表
    java 随机生成字符串验证码
    Mysql插入值时,避免重复插入
    Mysql的unique和primary key
    2020 3.6日电话面试(某外包公司)
    Intellij IDEA配置javaweb项目
  • 原文地址:https://www.cnblogs.com/lizhuming/p/13944602.html
Copyright © 2020-2023  润新知