当前位置: 首页 > article >正文

【CC2640R2F】香瓜CC2640R2F之SPI读写W25Q80

本文最后修改时间:2022年01月08日 10:45

一、本节简介

本节以simple_peripheral工程为例,介绍如何使用SPI读写W25Q80(外部flash)。

二、实验平台

1)CC2640R2F平台

①协议栈版本:CC2640R2 SDK v1.40.00.45

②编译软件:CCS7.3.0.00019

③硬件平台:香瓜CC2640R2F开发板

④仿真器:香瓜XDS100V3下载器

2)外设

①板载在香瓜CC2640R2F开发板底板上的芯片:W25Q80

三、版权声明

1)作者:甜甜的大香瓜

2)声明:喝水不忘挖井人,转载请注明出处。

3)纠错/业务合作:897503845@qq.com

4)香瓜BLE之CC2640R2F群:557278427

5)本文出处:原创连载资料《简单粗暴学蓝牙5》

6)完整开源资料下载地址(电脑端打开):

opengua.taobao.com

7)香瓜CC2640R2F开发板购买链接:

https://item.taobao.com/item.htm?spm=a1z10.1-c-s.w4023-16963296339.8.21bfc58419sWKt&id=558653143169

四、实验前提

1、在进行本文步骤前,请先阅读以下章节:

1)《简单粗暴学蓝牙5》的“第一章至第四章”章节​。

2、在进行本文步骤前,请先实现以下章节:

1)《简单粗暴学蓝牙5》的“第三章 软件的安装及使用”章节。

五、基础知识

1、W25Q80是什么?

答: W25Q80是winbond(华邦)公司出的8M bit(也就是1MB)的flash芯片。同系列常用的型号还有W25Q16(16Mb=2MB)、W25Q32(32Mb=4MB)等。

2、W25Q80的基本信息?

答:

如上图,W25Q80一次可写256字节、可4K字节扇区擦除、32K或者64K块擦除、整片擦除。

使用的是SPI接口、2.7V~3.6V电压范围,香瓜购买的是8-pin SOIC 208-mil封装。

如上图,W25Q80的厂商ID是0xEF,设备ID是0x13。这个用于初始化时识别flash芯片用。

六、硬件原理

1、W25Q80芯片引脚图

如上图,W25Q80一共8个脚,其中GND和VCC供电3.3V(范围在2.7V~3.6V)即可,其他4个SPI引脚DO(输出)、DI(输入)、CLK(时钟)、CS(片选)。

WP(写保护)、HOLD(保持输入)这两个引脚本文并没有用到,且“/WP”中的“/”是低电平有效的意思,所以我们本文将WP和HOLD两引脚拉高到VCC即可。

2、W25Q80与香瓜CC2640R2F开发板的对应关系

W25Q80引脚

香瓜CC2640R2F开发板引脚

引脚1(/CS)

DIO_30

引脚2(DO)

DIO_8

引脚3(/WP)

置高到VCC

引脚4(GND)

GND

引脚5(DI)

DIO_9

引脚6(CLK)

DIO_10

引脚7(/HOLD)

置高到VCC

引脚6(VCC)

3.3V

3、硬件原理图

七、实验步骤

1、编写并添加自定义的W25Q80驱动

1)写一个驱动GUA_ExtFlash.c(存放在“……

\simplelink_cc2640r2_sdk_1_40_00_45\examples\rtos\CC2640R2_LAUNCHXL\ble5stack\simple_peripheral\src\app\GUA“路径下)

//**********************************************************************

//name:         GUA_ExtFlash.c

//introduce:    外部flash驱动

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

#include “string.h”

#include <ti/devices/cc26x0r2/driverlib/Ssi.h>

#include <ti/drivers/spi/SPICC26XXDMA.h>

#include <ti/drivers/dma/UDMACC26XX.h>

#include <ti/drivers/SPI.h>

#include “GUA_ExtFlash.h”

/*********************宏定义************************/

//SPI引脚

#define GUA_CC2640R2_SPI0_MISO              IOID_8

#define GUA_CC2640R2_SPI0_MOSI              IOID_9

#define GUA_CC2640R2_SPI0_CLK               IOID_10

#define GUA_CC2640R2_SPI0_CSN               PIN_UNASSIGNED

#define GUA_Spi_flash_CS                    IOID_30

//SPI片选开关宏

#define GUA_FLASH_CS_ON                     0

#define GUA_FLASH_CS_OFF                    1

/* Instruction codes */

#define GUA_BLS_CODE_PROGRAM                0x02 /**< Page Program */

#define GUA_BLS_CODE_READ                   0x03 /**< Read Data */

#define GUA_BLS_CODE_READ_STATUS            0x05 /**< Read Status Register */

#define GUA_BLS_CODE_WRITE_ENABLE           0x06 /**< Write Enable */

#define GUA_BLS_CODE_SECTOR_ERASE           0x20 /**< Sector Erase */

#define GUA_BLS_CODE_MDID                   0x90 /**< Manufacturer Device ID */

#define GUA_BLS_CODE_DP                     0xB9 /**< Power down */

#define GUA_BLS_CODE_RDP                    0xAB /**< Power standby */

/* Erase instructions */

#define GUA_BLS_CODE_ERASE_4K               0x20 /**< Sector Erase */

#define GUA_BLS_CODE_ERASE_32K              0x52

#define GUA_BLS_CODE_ERASE_64K              0xD8

#define GUA_BLS_CODE_ERASE_ALL              0xC7 /**< Mass Erase */

/* Bitmasks of the status register */

#define GUA_BLS_STATUS_SRWD_BM              0x80

#define GUA_BLS_STATUS_BP_BM                0x0C

#define GUA_BLS_STATUS_WEL_BM               0x02

#define GUA_BLS_STATUS_WIP_BM               0x01

#define GUA_BLS_STATUS_BIT_BUSY             0x01 /**< Busy bit of the status register */

/* Part specific constants */

#define GUA_BLS_PROGRAM_PAGE_SIZE           256

#define GUA_BLS_ERASE_SECTOR_SIZE           4096

/* Manufacturer IDs */

#define GUA_MF_MACRONIX                     0xC2

#define GUA_MF_WINBOND                      0xEF

typedef enum GUA_CC2640R2_SPIName {

GUA_CC2640R2_SPI0 = 0,

GUA_CC2640R2_SPICOUNT

} GUA_CC2640R2_SPIName;

SPICC26XXDMA_Object GUA_spiCC26XXDMAObjects[GUA_CC2640R2_SPICOUNT];

//SPI速度4M

#define GUA_SPI_BIT_RATE                    4000000

//flash每页大小4K

#define GUA_EXT_FLASH_PAGE_SIZE             4096

/*********************内部变量************************/

const SPICC26XXDMA_HWAttrsV1 GUA_spiCC26XXDMAHWAttrs[GUA_CC2640R2_SPICOUNT] = {

{

        .baseAddr           = SSI0_BASE,

        .intNum             = INT_SSI0_COMB,

        .intPriority        = ~0,

        .swiPriority        = 0,

        .powerMngrId        = PowerCC26XX_PERIPH_SSI0,

        .defaultTxBufValue  = 0,

        .rxChannelBitMask   = 1<<UDMA_CHAN_SSI0_RX,

        .txChannelBitMask   = 1<<UDMA_CHAN_SSI0_TX,

        .mosiPin            = GUA_CC2640R2_SPI0_MOSI,

        .misoPin            = GUA_CC2640R2_SPI0_MISO,

        .clkPin             = GUA_CC2640R2_SPI0_CLK,

        .csnPin             = GUA_CC2640R2_SPI0_CSN

}

};

const SPI_Config GUA_SPI_config[GUA_CC2640R2_SPICOUNT] = {

{

         .fxnTablePtr = &SPICC26XXDMA_fxnTable,

         .object      = &GUA_spiCC26XXDMAObjects[GUA_CC2640R2_SPI0],

         .hwAttrs     = &GUA_spiCC26XXDMAHWAttrs[GUA_CC2640R2_SPI0]

},

};

const uint_least8_t GUA_SPI_count = GUA_CC2640R2_SPICOUNT;

static PIN_Config GUA_BoardFlashPinTable[] =

{

GUA_Spi_flash_CS | PIN_GPIO_OUTPUT_EN | PIN_GPIO_LOW | PIN_PUSHPULL | PIN_DRVSTR_MIN, /* Ext. flash chip select */

PIN_TERMINATE

};

static PIN_Handle GUA_hFlashPin = NULL;

static PIN_State GUA_pinState;

// Supported flash devices

static GUA_ExtFlashInfo_t GUA_flashInfo[] =

{

{

        .manfId = GUA_MF_MACRONIX,  // Macronics

        .devId = 0x15,              // MX25R1635F

        .deviceSize = 0x200000      // 2 Mbyte (16 Mbit)

},

{

        .manfId = GUA_MF_MACRONIX,  // Macronics

        .devId = 0x14,              // MX25R8035F

        .deviceSize = 0x100000      // 1 Mbyte (8 Mbit)

},

{

        .manfId = GUA_MF_WINBOND,   // WinBond

        .devId = 0x13,              // W25Q80DV

        .deviceSize = 0x100000      // 1 Mbyte (8 Mbit)

},

{

        .manfId = GUA_MF_WINBOND,   // WinBond

        .devId = 0x12,              // W25X40CL

        .deviceSize = 0x080000      // 512 Kbyte (4 Mbit)

},

{

        .manfId = GUA_MF_WINBOND,   // WinBond

        .devId = 0x11,              // W25X20CL

        .deviceSize = 0x040000      // 256 Kbyte (2 Mbit)

},

{

        .manfId = 0x0,

        .devId = 0x0,

        .deviceSize = 0x0

}

};

// Flash information

static GUA_ExtFlashInfo_t *pGUA_flashInfo = NULL;

static GUA_U8 GUA_infoBuf[2];

// SPI interface

static SPI_Handle GUA_spiHandle = NULL;

static SPI_Params GUA_spiParams;

/*********************内部函数************************/

static int GUA_Spi_write(const GUA_U8 *pGUA_buf, size_t GUA_length);

static int GUA_Spi_read(GUA_U8 *pGUA_buf, size_t GUA_length);

static bool GUA_Spi_open(GUA_U32 GUA_bitRate);

static void GUA_Spi_close(void);

static void GUA_Spi_flash(void);

static void GUA_extFlashSelect(void);

static void GUA_extFlashDeselect(void);

static bool GUA_extFlashPowerDown(void);

static bool GUA_extFlashPowerStandby(void);

static bool GUA_ExtFlash_readInfo(void);

static bool GUA_extFlashVerifyPart(void);

static int GUA_ExtFlash_waitReady(void);

static int GUA_ExtFlash_powerDown(void);

static int GUA_ExtFlash_writeEnable(void);

//**********************************************************************

//name:         GUA_Spi_write

//introduce:    SPI设备

//parameter:    pGUA_buf:写缓存

//              GUA_len:数据长度

//return:       如果操作正常,返回0;反之返回1

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static int GUA_Spi_write(const GUA_U8 *pGUA_buf, size_t GUA_len)

{

SPI_Transaction masterTransaction;

masterTransaction.count  = GUA_len;

masterTransaction.txBuf  = (void*)pGUA_buf;

masterTransaction.arg    = NULL;

masterTransaction.rxBuf  = NULL;

return SPI_transfer(GUA_spiHandle, &masterTransaction) ? 0 : -1;

}

//**********************************************************************

//name:         GUA_Spi_read

//introduce:    SPI设备

//parameter:    pGUA_buf:读缓存

//              GUA_len:数据长度

//return:       如果操作正常,返回0;反之返回1

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static int GUA_Spi_read(GUA_U8 *pGUA_buf, size_t GUA_len)

{

SPI_Transaction masterTransaction;

masterTransaction.count = GUA_len;

masterTransaction.txBuf = NULL;

masterTransaction.arg = NULL;

masterTransaction.rxBuf = pGUA_buf;

return SPI_transfer(GUA_spiHandle, &masterTransaction) ? 0 : -1;

}

//**********************************************************************

//name:         GUA_Spi_open

//introduce:    打开SPI

//parameter:    GUA_bitRate:要设置的SPI速度

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static bool GUA_Spi_open(GUA_U32 GUA_bitRate)

{

/*  Configure SPI as master */

SPI_Params_init(&GUA_spiParams);

GUA_spiParams.bitRate = GUA_bitRate;

GUA_spiParams.mode = SPI_MASTER;

GUA_spiParams.transferMode = SPI_MODE_BLOCKING;

/* Attempt to open SPI. */

GUA_spiHandle = SPI_open(GUA_CC2640R2_SPI0, &GUA_spiParams);

return GUA_spiHandle != NULL;

}

//**********************************************************************

//name:         GUA_Spi_close

//introduce:    关闭SPI

//parameter:    none

//return:       none

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static void GUA_Spi_close(void)

{

if (GUA_spiHandle != NULL)

{

        // Close the RTOS driver

        SPI_close(GUA_spiHandle);

        GUA_spiHandle = NULL;

}

}

//**********************************************************************

//name:         GUA_Spi_flash

//introduce:    把没用的垃圾数据处理掉

//parameter:    none

//return:       none

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static void GUA_Spi_flash(void)

{

/* make sure SPI hardware module is done  */

while(SSIBusy(((SPICC26XXDMA_HWAttrsV1*)GUA_spiHandle->hwAttrs)->baseAddr))

{ };

}

//**********************************************************************

//name:         GUA_extFlashSelect

//introduce:    片选引脚选择外部flash

//parameter:    none

//return:       none

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static void GUA_extFlashSelect(void)

{

PIN_setOutputValue(GUA_hFlashPin, GUA_Spi_flash_CS, GUA_FLASH_CS_ON);

}

//**********************************************************************

//name:         GUA_extFlashDeselect

//introduce:    取消片选引脚选择外部flash

//parameter:    none

//return:       none

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static void GUA_extFlashDeselect(void)

{

PIN_setOutputValue(GUA_hFlashPin, GUA_Spi_flash_CS, GUA_FLASH_CS_OFF);

}

//**********************************************************************

//name:         GUA_extFlashPowerDown

//introduce:    让设备进入低功耗模式,不能访问数据,只能读取寄存器状态

//parameter:    none

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static bool GUA_extFlashPowerDown(void)

{

GUA_U8 GUA_cmd;

bool GUA_success;

GUA_cmd = GUA_BLS_CODE_DP;

GUA_extFlashSelect();

GUA_success = GUA_Spi_write(&GUA_cmd, sizeof(GUA_cmd)) == 0;

GUA_extFlashDeselect();

return GUA_success;

}

//**********************************************************************

//name:         GUA_extFlashPowerStandby

//introduce:    退出低功耗模式

//parameter:    none

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static bool GUA_extFlashPowerStandby(void)

{

GUA_U8 GUA_cmd;

bool GUA_success;

GUA_cmd = GUA_BLS_CODE_RDP;

GUA_extFlashSelect();

GUA_success = GUA_Spi_write(&GUA_cmd, sizeof(GUA_cmd)) == 0;

GUA_extFlashDeselect();

if(GUA_success)

{

        if(GUA_ExtFlash_waitReady() != 0)

        {

            GUA_success = false;

        }

}

return GUA_success;

}

//**********************************************************************

//name:         GUA_ExtFlash_readInfo

//introduce:    flash信息(厂商ID和设备ID

//parameter:    none

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static bool GUA_ExtFlash_readInfo(void)

{

const GUA_U8 GUA_wbuf[] = {GUA_BLS_CODE_MDID, 0xFF, 0xFF, 0x00};

GUA_extFlashSelect();

int GUA_ret = GUA_Spi_write(GUA_wbuf, sizeof(GUA_wbuf));

if(GUA_ret)

{

        GUA_extFlashDeselect();

        return false;

}

GUA_ret = GUA_Spi_read(GUA_infoBuf, sizeof(GUA_infoBuf));

GUA_extFlashDeselect();

return GUA_ret == 0;

}

//**********************************************************************

//name:         GUA_extFlashVerifyPart

//introduce:    校验flash芯片是否是驱动支持的flash

//parameter:    none

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static bool GUA_extFlashVerifyPart(void)

{

if(!GUA_ExtFlash_readInfo())

{

        return false;

}

pGUA_flashInfo = GUA_flashInfo;

while(pGUA_flashInfo->deviceSize > 0)

{

        if(GUA_infoBuf[0] == pGUA_flashInfo->manfId && GUA_infoBuf[1] == pGUA_flashInfo->devId)

        {

            break;

        }

        pGUA_flashInfo++;

}

return pGUA_flashInfo->deviceSize > 0;

}

//**********************************************************************

//name:         GUA_ExtFlash_waitReady

//introduce:    等待当前擦除、编程的操作结束

//parameter:    none

//return:       如果操作正常,返回0;反之返回非0

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static int GUA_ExtFlash_waitReady(void)

{

const GUA_U8 GUA_wbuf[1] = {GUA_BLS_CODE_READ_STATUS};

int GUA_ret;

/* Throw away all garbage */

GUA_extFlashSelect();

GUA_Spi_flash();

GUA_extFlashDeselect();

for(;;)

{

        GUA_U8 GUA_buf;

        GUA_extFlashSelect();

        GUA_Spi_write(GUA_wbuf, sizeof(GUA_wbuf));

        GUA_ret = GUA_Spi_read(&GUA_buf, sizeof(GUA_buf));

        GUA_extFlashDeselect();

        if(GUA_ret)

        {

            /* Error */

            return -2;

        }

        if(!(GUA_buf & GUA_BLS_STATUS_BIT_BUSY))

        {

            /* Now ready */

            break;

        }

}

return 0;

}

//**********************************************************************

//name:         GUA_ExtFlash_powerDown

//introduce:    等待进入低功耗模式

//parameter:    none

//return:       如果操作正常,返回0;反之返回非0

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static int GUA_ExtFlash_powerDown(void)

{

GUA_U8 GUA_i;

GUA_i = 0;

while(GUA_i < 10)

{

        if(!GUA_ExtFlash_readInfo())

        {

            return 0;

        }

        GUA_i++;

}

return -1;

}

//**********************************************************************

//name:         GUA_ExtFlash_writeEnable

//introduce:    启动写操作

//parameter:    none

//return:       如果操作正常,返回0;反之返回非0

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

static int GUA_ExtFlash_writeEnable(void)

{

const GUA_U8 GUA_wbuf[] = {GUA_BLS_CODE_WRITE_ENABLE};

GUA_extFlashSelect();

int GUA_ret = GUA_Spi_write(GUA_wbuf, sizeof(GUA_wbuf));

GUA_extFlashDeselect();

if(GUA_ret)

{

        return -3;

}

return 0;

}

//**********************************************************************

//name:         GUA_ExtFlash_open

//introduce:    初始化flash

//parameter:    none

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

bool GUA_ExtFlash_open(void)

{

bool GUA_f;

GUA_hFlashPin = PIN_open(&GUA_pinState, GUA_BoardFlashPinTable);

if(GUA_hFlashPin == NULL)

{

        return false;

}

/* Initialise SPI. Subsequent calls will do nothing. */

SPI_init();

/* Make sure SPI is available */

GUA_f = GUA_Spi_open(GUA_SPI_BIT_RATE);

if (GUA_f)

{

        /* Put the part is standby mode */

        GUA_f = GUA_extFlashPowerStandby();

        if(GUA_f)

        {

            /* Verify manufacturer and device ID */

            GUA_f = GUA_extFlashVerifyPart();

        }

        if(!GUA_f)

        {

            GUA_ExtFlash_close();

        }

}

return GUA_f;

}

//**********************************************************************

//name:         GUA_ExtFlash_close

//introduce:    关闭flash

//parameter:    none

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

void GUA_ExtFlash_close(void)

{

if(GUA_hFlashPin != NULL)

{

        // Put the part in low power mode

        GUA_extFlashPowerDown();

        if(pGUA_flashInfo->manfId == GUA_MF_WINBOND)

        {

            GUA_ExtFlash_powerDown();

        }

        /* Make sure SPI lines have a defined state */

        GUA_Spi_close();

        PIN_close(GUA_hFlashPin);

        GUA_hFlashPin = NULL;

}

}

//**********************************************************************

//name:         GUA_ExtFlash_read

//introduce:    flash

//parameter:    GUA_offset:偏移地址

//              GUA_length:数据长度

//              pGUA_buf:接收缓存区

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

bool GUA_ExtFlash_read(size_t GUA_offset, size_t GUA_length, GUA_U8 *pGUA_buf)

{

GUA_U8 GUA_wbuf[4];

/* Wait till previous erase/program operation completes */

int GUA_ret = GUA_ExtFlash_waitReady();

if(GUA_ret)

{

        return false;

}

/* SPI is driven with very low frequency (1MHz < 33MHz fR spec)

* in this temporary implementation.

* and hence it is not necessary to use fast read. */

GUA_wbuf[0] = GUA_BLS_CODE_READ;

GUA_wbuf[1] = (GUA_offset >> 16) & 0xff;

GUA_wbuf[2] = (GUA_offset >> 8) & 0xff;

GUA_wbuf[3] = GUA_offset & 0xff;

GUA_extFlashSelect();

if(GUA_Spi_write(GUA_wbuf, sizeof(GUA_wbuf)))

{

        /* failure */

        GUA_extFlashDeselect();

        return false;

}

GUA_ret = GUA_Spi_read(pGUA_buf, GUA_length);

GUA_extFlashDeselect();

return GUA_ret == 0;

}

//**********************************************************************

//name:         GUA_ExtFlash_write

//introduce:    flash

//parameter:    GUA_offset:偏移地址

//              GUA_length:数据长度

//              pGUA_buf:发送缓存区

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

bool GUA_ExtFlash_write(size_t GUA_offset, size_t GUA_length, const GUA_U8 *pGUA_buf)

{

GUA_U8 GUA_wbuf[4];

while(GUA_length > 0)

{

        /* Wait till previous erase/program operation completes */

        int GUA_ret = GUA_ExtFlash_waitReady();

        if(GUA_ret)

        {

            return false;

        }

        GUA_ret = GUA_ExtFlash_writeEnable();

        if (GUA_ret)

        {

            return false;

        }

        size_t GUA_ilen; /* interim GUA_length per instruction */

        GUA_ilen = GUA_BLS_PROGRAM_PAGE_SIZE – (GUA_offset % GUA_BLS_PROGRAM_PAGE_SIZE);

        if (GUA_length < GUA_ilen)

        {

            GUA_ilen = GUA_length;

        }

        GUA_wbuf[0] = GUA_BLS_CODE_PROGRAM;

        GUA_wbuf[1] = (GUA_offset >> 16) & 0xff;

        GUA_wbuf[2] = (GUA_offset >> 8) & 0xff;

        GUA_wbuf[3] = GUA_offset & 0xff;

        GUA_offset += GUA_ilen;

        GUA_length -= GUA_ilen;

        /* Up to 100ns CS hold time (which is not clear

        * whether it’s application only in between reads)

        * is not imposed here since above instructions

        * should be enough to delay

        * as much. */

        GUA_extFlashSelect();

        if (GUA_Spi_write(GUA_wbuf, sizeof(GUA_wbuf)))

        {

            /* failure */

            GUA_extFlashDeselect();

            return false;

        }

        if (GUA_Spi_write(pGUA_buf, GUA_ilen))

        {

            /* failure */

            GUA_extFlashDeselect();

            return false;

        }

        pGUA_buf += GUA_ilen;

        GUA_extFlashDeselect();

}

return true;

}

//**********************************************************************

//name:         GUA_ExtFlash_erase

//introduce:    擦除flash

//parameter:    GUA_offset:偏移地址

//              GUA_length:数据长度

//              pGUA_buf:发送缓存区

//return:       如果操作正常,返回true;反之返回false

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

bool GUA_ExtFlash_erase(size_t GUA_offset, size_t GUA_length)

{

/* Note that Block erase might be more efficient when the floor map

* is well planned for OTA but to simplify for the temporary implementation,

* sector erase is used blindly. */

GUA_U8 GUA_wbuf[4];

size_t GUA_i, GUA_numsectors;

GUA_wbuf[0] = GUA_BLS_CODE_SECTOR_ERASE;

{

        size_t GUA_endoffset = GUA_offset + GUA_length – 1;

        GUA_offset = (GUA_offset / GUA_BLS_ERASE_SECTOR_SIZE) * GUA_BLS_ERASE_SECTOR_SIZE;

        GUA_numsectors = (GUA_endoffset – GUA_offset + GUA_BLS_ERASE_SECTOR_SIZE – 1) /

            GUA_BLS_ERASE_SECTOR_SIZE;

}

for(GUA_i = 0; GUA_i < GUA_numsectors; GUA_i++)

{

        /* Wait till previous erase/program operation completes */

        int GUA_ret = GUA_ExtFlash_waitReady();

        if(GUA_ret)

        {

            return false;

        }

        GUA_ret = GUA_ExtFlash_writeEnable();

        if(GUA_ret)

        {

            return false;

        }

        GUA_wbuf[1] = (GUA_offset >> 16) & 0xff;

        GUA_wbuf[2] = (GUA_offset >> 8) & 0xff;

        GUA_wbuf[3] = GUA_offset & 0xff;

        GUA_extFlashSelect();

        if(GUA_Spi_write(GUA_wbuf, sizeof(GUA_wbuf)))

        {

            /* failure */

            GUA_extFlashDeselect();

            return false;

        }

        GUA_extFlashDeselect();

        GUA_offset += GUA_BLS_ERASE_SECTOR_SIZE;

}

return true;

}

//**********************************************************************

//name:         GUA_ExtFlash_info

//introduce:    获取当前连接的外部flash的信息

//parameter:    none

//return:       ExtFlashInfo_t(包含设备内存大小、厂商ID、设备ID)

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

GUA_ExtFlashInfo_t *GUA_ExtFlash_info(void)

{

return pGUA_flashInfo;

}

2)写一个驱动头文件GUA_ExtFlash.h(存放在“……

\simplelink_cc2640r2_sdk_1_40_00_45\examples\rtos\CC2640R2_LAUNCHXL\ble5stack\simple_peripheral\src\app\GUA“路径下)

//**********************************************************************

//name:         GUA_ExtFlash.h

//introduce:    外部flash驱动的头文件

//author:       甜甜的大香瓜

//email:        897503845@qq.com

//QQ group:     香瓜BLECC2640R2F(557278427)

//shop:         opengua.taobao.com

//changetime:   2021.08.02

//**********************************************************************

#ifndef GUA_EXT_FLASH_H

#define GUA_EXT_FLASH_H

//头文件

#include <stdlib.h>

#include <stdbool.h>

/*********************宏定义************************/

//类型宏

#ifndef GUA_C

typedef char GUA_C;

#endif

#ifndef GUA_U8

typedef unsigned char GUA_U8;

#endif

#ifndef GUA_8

typedef signed char GUA_8;

#endif

#ifndef GUA_U16

typedef unsigned short GUA_U16;

#endif

#ifndef GUA_16

typedef signed short GUA_16;

#endif

#ifndef GUA_U32

typedef unsigned long GUA_U32;

#endif

#ifndef GUA_32

typedef signed long GUA_32;

#endif

#ifndef GUA_U64

typedef unsigned long long GUA_U64;

#endif

#ifndef GUA_64

typedef signed long long GUA_64;

#endif

/*********************外部变量************************/

//设备信息结构体

typedef struct

{

GUA_U32 deviceSize; // bytes

GUA_U8 manfId;      // manufacturer ID

GUA_U8 devId;       // device ID

} GUA_ExtFlashInfo_t;

/*********************函数声明************************/

extern bool GUA_ExtFlash_open(void);

extern void GUA_ExtFlash_close(void);

extern bool GUA_ExtFlash_read(size_t GUA_offset, size_t GUA_length, GUA_U8 *pGUA_buf);

extern bool GUA_ExtFlash_write(size_t GUA_offset, size_t GUA_length, const GUA_U8 *pGUA_buf);

extern bool GUA_ExtFlash_erase(size_t GUA_offset, size_t GUA_length);

extern GUA_ExtFlashInfo_t *GUA_ExtFlash_info(void);

#endif

3、工程中添加驱动文件GUA_ExtFlash.c、GUA_ExtFlash.h

注:拖拽至CCS工程的Application文件夹下

添加文件过程中,选项选择如下

4、应用层调用

1)添加头文件(simple_peripheral.c中)

//GUA

#include “GUA_ ExtFlash.h”

//GUA

2)添加测试代码(simple_peripheral.c的SimpleBLEPeripheral_init函数末尾中)

//GUA

GUA_U32 GUA_offset = 0x012233;

GUA_U8 GUA_write_buf[7] = {‘o’,’p’,’e’,’n’,’g’,’u’,’a’};

GUA_U8 GUA_read_buf[7] = {0};

bool GUA_flash_Ret;

//初始化flash

GUA_flash_Ret = GUA_ExtFlash_open();

if(GUA_flash_Ret == true)

{

        //擦除flash

        GUA_flash_Ret = GUA_ExtFlash_erase(GUA_offset, sizeof(GUA_write_buf));

        if(GUA_flash_Ret == true)

        {

            //flash

            GUA_flash_Ret = GUA_ExtFlash_write(GUA_offset, sizeof(GUA_write_buf), GUA_write_buf);

            if(GUA_flash_Ret == true)

            {

                //flash

                GUA_flash_Ret = GUA_ExtFlash_read(GUA_offset, sizeof(GUA_read_buf), GUA_read_buf);

                if(GUA_flash_Ret == true)

                {

                    //读正确后关flash

                    GUA_ExtFlash_close();

                }

            }

        }

}

//GUA

上述代码,先将0x012233地址擦除7个字节,再写入7个字节“opengua”,再读出7个字节,判断是否读出的是“opengua”,以此来判断是否有正常写入。

八、注意事项

1、W25Q80的内存大小是1M,也就是0x100000,所以读、写、擦除的范围就是0~0x100000。

2、在写入之前,需要先擦除,否则会写入不成功。

3、本文驱动会与《香瓜CC2640R2F之LCD》冲突,因为都是使用SPI。如果只是想检测flash是否良好,可以在oled启动之前,测试一下flash再关闭。思路如下

//flash测试代码

//……

//oled初始化代码

//……

//GUA

//oled显示flash的好坏

if(GUA_flash_Ret == true)

{

        GUA_LCD_WriteString(“flash OK”, GUA_LCD_LINE7);

}

else

{

        GUA_LCD_WriteString(“flash error”, GUA_LCD_LINE7);

}

//GUA

九、实验结果

仿真并设置断点,查看读出的flash数据

可见读出的是“opengua”,与写入的数据一样,表示读写正常。

因此,实验成功。


http://www.kler.cn/a/508304.html

相关文章:

  • [MySQL | 二、基本数据类型]
  • web worker 前端多线程一、
  • 2024CVPR《HomoFormer》
  • 群论学习笔记
  • Json转换类型报错问题:java.lang.Integer cannot be cast to java.math.BigDecimal
  • 深入理解 Entity、VO、QO、DTO 的区别及其在 MVC 架构中的应用
  • 【老白学 Java】线程的并发问题(二)
  • JDK 8 - 新日期格式化类 DateTimeFormatter 使用
  • Spring boot框架下的RabbitMQ消息中间件
  • Spring声明式事务
  • 第22篇 基于ARM A9处理器用汇编语言实现中断<四>
  • “AI智能防控识别系统:守护安全的“智慧卫士”
  • 【进程与线程】进程的基础
  • 深度学习-88-大语言模型LLM之基于langchain的检索链
  • 【网络协议】【http】【https】AES-TLS1.2
  • 软考信安24~工控安全需求分析与安全保护工程
  • AXIOS的引入和封装
  • 对MySQL滴MVCC理解(超详细)
  • 【蓝桥杯选拔赛真题62】C++求和 第十四届蓝桥杯青少年创意编程大赛 算法思维 C++编程选拔赛真题解
  • “AI开放式目标检测系统:开启智能识别新时代
  • Linux《Linux简介与环境的搭建》
  • React 表单处理与网络请求封装详解[特殊字符][特殊字符]
  • java请编写程序,分别定义8种基本数据类型的变量,并打印变量的值。
  • 左神算法基础提升--2
  • MySQL(高级特性篇) 06 章——索引的数据结构
  • 深入浅出:Go语言中的Unicode与字符编码详解