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

【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”,与写入的数据一样,表示读写正常。

因此,实验成功。

相关文章:

【CC2640R2F】香瓜CC2640R2F之SPI读写W25Q80

本文最后修改时间&#xff1a;2022年01月08日 10:45 一、本节简介 本节以simple_peripheral工程为例&#xff0c;介绍如何使用SPI读写W25Q80&#xff08;外部flash&#xff09;。 二、实验平台 1&#xff09;CC2640R2F平台 ①协议栈版本&#xff1a;CC2640R2 SDK v1.40.00.4…...

探秘Shortest与Stagehand:开启高效测试与自动化新篇

探秘Shortest与Stagehand&#xff1a;开启高效测试与自动化新篇 在数字化浪潮的推动下&#xff0c;网页自动化工具如同繁星般涌现&#xff0c;为众多行业带来了效率的变革。在这些工具中&#xff0c;Shortest和Stagehand凭借其出色的表现&#xff0c;成为了众多开发者、测试人…...

llama 3 笔记

0.简介 llama 3 是在 15 万亿个 Token 上预训练的语言模型,具有 8B 和 70B 两种参数规模,可以支持广泛的用户场景,在各种行业基准上取得了最先进的性能,并提供了一些新功能,包括改进的推理能力。 1.改进亮点 参数规模与模型架构:Llama 3提供了8B和70B两种参数规模的模…...

写作利器:如何用 PicGo + GitHub 图床提高创作效率

你好呀&#xff0c;欢迎来到 Dong雨 的技术小栈 &#x1f331; 在这里&#xff0c;我们一同探索代码的奥秘&#xff0c;感受技术的魅力 ✨。 &#x1f449; 我的小世界&#xff1a;Dong雨 &#x1f4cc; 分享我的学习旅程 &#x1f6e0;️ 提供贴心的实用工具 &#x1f4a1; 记…...

【文件篇】11.磁盘文件系统

上一篇博客中我们介绍到如果我们要访问文件首先需要打开这个文件&#xff0c;而文件是在磁盘上存储的&#xff0c;也就是说需要在磁盘上找到这个文件的路径。但是磁盘上有很多文件&#xff0c;这些文件都有自己的路径的&#xff0c;这些文件还有内容和属性&#xff0c;它们都是…...

嵌入式产品级-超小尺寸热成像相机(从0到1 硬件-软件-外壳)

Thermal_Imaging_Camera This is a small thermal imaging camera that includes everything from hardware and software. 小尺寸热成像相机-Pico-LVGL-RTOS 基于RP2040 Pico主控与RTOS&#xff0c;榨干双核性能实现LVGL和成图任务并行。ST7789驱动240280屏&#xff0c;CST8…...

三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D

挪威文化历史博物馆在其修复工作中融入现代3D扫描技术&#xff0c;让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识&#xff0c;该博物馆被誉为挪威博物馆研究领域的领先机构。馆…...

《自动驾驶与机器人中的SLAM技术》ch8:基于预积分和图优化的紧耦合 LIO 系统

目录 1 预积分 LIO 系统的经验 2 预积分图优化的顶点 3 预积分图优化的边 3.1 NDT 残差边&#xff08;观测值维度为 3 维的单元边&#xff09; 4 基于预积分和图优化 LIO 系统的实现 4.1 IMU 静止初始化 4.2 使用预积分预测 4.3 使用 IMU 预测位姿进行运动补偿 4.4 位姿配准部…...

Linux下PostgreSQL-12.0安装部署详细步骤

一、安装环境 postgresql-12.0 CentOS-7.6 注意&#xff1a;确认linux系统可以正常连接网络&#xff0c;因为在后面需要添加依赖包。 二、pg数据库安装包下载 下载地址&#xff1a;PostgreSQL: File Browser 选择要安装的版本进行下载&#xff1a; 三、安装依赖包 在要安…...

STL—stack与queue

目录 Stack stack的使用 stack的模拟实现 queue queue的使用 queue的模拟实现 priority_queue priority_queue的用法 priority_queue的模拟实现 容器适配器 种类 Stack http://www.cplusplus.com/reference/stack/stack/?kwstack stack是栈&#xff0c;后入先出 stack的…...

docker 使用远程镜像启动一个容器

使用前提&#xff1a; 首先你得安装docker,其次你得拥有一个远程镜像 docker run --name io_11281009 --rm -it -p 2233:22 -v .:/root/py -e ed25519_rootAAAAC3NzaC1lZDI1********Oy7zR7l7aUniR2rul ghcr.lizzie.fun/fj0r/io srv对上述命令解释&#xff1a; 1.docker run:…...

简述mysql 主从复制原理及其工作过程,配置一主两从并验证

第一种基于binlog的主从同步 首先对主库进行配置&#xff1a; [rootopenEuler-1 ~]# vim /etc/my.cnf 启动服务 [rootopenEuler-1 ~]# systemctl enable --now mysqld 主库的配置 从库的配置 第一个从库 [rootopenEuler-1 ~]# vim /etc/my.cnf [rootopenEuler-1 ~]# sys…...

oracle之行转列

对于Oracle的行转列功能一直云里雾里&#xff0c;马马虎虎&#xff0c;对行转列的使用场景和使用方法都不够深刻&#xff0c;最近有空理解一下。 Oracle 11g后有专门的函数pivot&#xff0c;对于特定的场景可以直接套用。 需求&#xff1a;求各份job不同员工工资是多少&#xf…...

Windows电脑安装USB Redirector并实现内外网跨网USB共享通信访问

文章目录 前言1. 安装下载软件1.1 内网安装使用USB Redirector1.2 下载安装cpolar内网穿透 2. 完成USB Redirector服务端和客户端映射连接3. 设置固定的公网地址 前言 我们每天都在与各种智能设备打交道&#xff0c;从手机到电脑&#xff0c;再到各种外设&#xff0c;它们已经…...

kafka学习笔记4-TLS加密 —— 筑梦之路

1. 准备证书文件 mkdir /opt/kafka/pkicd !$# 生成CA证书 openssl req -x509 -nodes -days 3650 -newkey rsa:4096 -keyout ca.key -out ca.crt -subj "/CNKafka-CA"# 生成私钥 openssl genrsa -out kafka.key 4096# 生成证书签名请求 (CSR) openssl req -new -key …...

grafana + Prometheus + node_exporter搭建监控大屏

本文介绍生产系统监控大屏的搭建&#xff0c;比较实用也是实际应用比较多的方式&#xff0c;希望能够帮助大家对监控系统有一定的认识。 0、规划 grafana主要是展示和报警&#xff0c;Prometheus用于保存监控数据&#xff0c;node_exporter用于实时采集各个应用服务器的事实状…...

深度学习在语音识别中的应用

引言 语音识别技术是人工智能领域中的一个重要分支&#xff0c;它使得机器能够理解和转换人类的语音为文本。深度学习的出现极大地推动了语音识别技术的发展。本文将介绍如何使用深度学习构建一个基本的语音识别系统&#xff0c;并提供一个实践案例。 环境准备 在开始之前&a…...

RabbitMQ 高级特性

目录 1.消息确认 1.1 消息确认机制 1.2 手动确认方法 1. 2.1肯定确认 1.2.2 否定确认 1.3 SpringBoot 代码示例 1.3.1 配置确认机制 1.3.2 配置队列,交换机,绑定关系 1.3.3 生产者(向 rabbitmq 发送消息) 1.3.4 消费者(消费队列中的信息) 2.持久性 2.1 交换机…...

第01章 07 MySQL+VTK C++示例代码,实现医学影像数据的IO数据库存储

要实现将医学影像数据&#xff08;如DICOM文件或其他医学图像格式&#xff09;存储到MySQL数据库中&#xff0c;并使用VTK进行数据读取和处理的C示例代码&#xff0c;可以按照以下步骤进行。这个示例将展示如何将DICOM图像数据存储到MySQL数据库&#xff0c;然后使用VTK读取并显…...

Mysql创建定时任务

mysql查看存储过程 SHOW PROCEDURE STATUS;查看event_scheduler show events;查看当前event_scheduler的状态 SHOW VARIABLES LIKE event_scheduler;关闭event_scheduler set GLOBAL event_schedulerOFF;删除event_scheduler drop event event_name;创建存储过程 -- 创建存…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

【机器视觉】单目测距——运动结构恢复

ps&#xff1a;图是随便找的&#xff0c;为了凑个封面 前言 在前面对光流法进行进一步改进&#xff0c;希望将2D光流推广至3D场景流时&#xff0c;发现2D转3D过程中存在尺度歧义问题&#xff0c;需要补全摄像头拍摄图像中缺失的深度信息&#xff0c;否则解空间不收敛&#xf…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容

目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法&#xff0c;当前调用一个医疗行业的AI识别算法后返回…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill

视觉语言模型&#xff08;Vision-Language Models, VLMs&#xff09;&#xff0c;为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展&#xff0c;机器人仍难以胜任复杂的长时程任务&#xff08;如家具装配&#xff09;&#xff0c;主要受限于人…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...

Linux系统部署KES

1、安装准备 1.版本说明V008R006C009B0014 V008&#xff1a;是version产品的大版本。 R006&#xff1a;是release产品特性版本。 C009&#xff1a;是通用版 B0014&#xff1a;是build开发过程中的构建版本2.硬件要求 #安全版和企业版 内存&#xff1a;1GB 以上 硬盘&#xf…...

android RelativeLayout布局

<?xml version"1.0" encoding"utf-8"?> <RelativeLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"android:gravity&…...

uniapp 小程序 学习(一)

利用Hbuilder 创建项目 运行到内置浏览器看效果 下载微信小程序 安装到Hbuilder 下载地址 &#xff1a;开发者工具默认安装 设置服务端口号 在Hbuilder中设置微信小程序 配置 找到运行设置&#xff0c;将微信开发者工具放入到Hbuilder中&#xff0c; 打开后出现 如下 bug 解…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”

非常好&#xff0c;我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题&#xff0c;统一使用 二重复合函数&#xff1a; z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y))​ 来全面说明。我们会展示其全微分形式&#xff08;偏导…...