【框架】SPI四种模式+通用设备驱动实现-源码
阅读原文时间:2023年07月10日阅读:3

目录


前言

  • 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("\r\n[flashInit] [faild] and error devID is [%d]", devID);
        }
        else
        {
            printf("\r\n[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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章