【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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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: 香瓜BLE之CC2640R2F(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
本文最后修改时间:2022年01月08日 10:45 一、本节简介 本节以simple_peripheral工程为例,介绍如何使用SPI读写W25Q80(外部flash)。 二、实验平台 1)CC2640R2F平台 ①协议栈版本:CC2640R2 SDK v1.40.00.4…...
探秘Shortest与Stagehand:开启高效测试与自动化新篇
探秘Shortest与Stagehand:开启高效测试与自动化新篇 在数字化浪潮的推动下,网页自动化工具如同繁星般涌现,为众多行业带来了效率的变革。在这些工具中,Shortest和Stagehand凭借其出色的表现,成为了众多开发者、测试人…...
llama 3 笔记
0.简介 llama 3 是在 15 万亿个 Token 上预训练的语言模型,具有 8B 和 70B 两种参数规模,可以支持广泛的用户场景,在各种行业基准上取得了最先进的性能,并提供了一些新功能,包括改进的推理能力。 1.改进亮点 参数规模与模型架构:Llama 3提供了8B和70B两种参数规模的模…...

写作利器:如何用 PicGo + GitHub 图床提高创作效率
你好呀,欢迎来到 Dong雨 的技术小栈 🌱 在这里,我们一同探索代码的奥秘,感受技术的魅力 ✨。 👉 我的小世界:Dong雨 📌 分享我的学习旅程 🛠️ 提供贴心的实用工具 💡 记…...

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

嵌入式产品级-超小尺寸热成像相机(从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,榨干双核性能实现LVGL和成图任务并行。ST7789驱动240280屏,CST8…...

三维扫描赋能文化:蔡司3D扫描仪让木质文化遗产焕发新生-沪敖3D
挪威文化历史博物馆在其修复工作中融入现代3D扫描技术,让数百年的历史焕发新生。 文化历史博物馆的工作 文化历史博物馆是奥斯陆大学的一个院系。凭借其在文化历史管理、研究和传播方面的丰富专业知识,该博物馆被誉为挪威博物馆研究领域的领先机构。馆…...
《自动驾驶与机器人中的SLAM技术》ch8:基于预积分和图优化的紧耦合 LIO 系统
目录 1 预积分 LIO 系统的经验 2 预积分图优化的顶点 3 预积分图优化的边 3.1 NDT 残差边(观测值维度为 3 维的单元边) 4 基于预积分和图优化 LIO 系统的实现 4.1 IMU 静止初始化 4.2 使用预积分预测 4.3 使用 IMU 预测位姿进行运动补偿 4.4 位姿配准部…...

Linux下PostgreSQL-12.0安装部署详细步骤
一、安装环境 postgresql-12.0 CentOS-7.6 注意:确认linux系统可以正常连接网络,因为在后面需要添加依赖包。 二、pg数据库安装包下载 下载地址:PostgreSQL: File Browser 选择要安装的版本进行下载: 三、安装依赖包 在要安…...
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是栈,后入先出 stack的…...

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

简述mysql 主从复制原理及其工作过程,配置一主两从并验证
第一种基于binlog的主从同步 首先对主库进行配置: [rootopenEuler-1 ~]# vim /etc/my.cnf 启动服务 [rootopenEuler-1 ~]# systemctl enable --now mysqld 主库的配置 从库的配置 第一个从库 [rootopenEuler-1 ~]# vim /etc/my.cnf [rootopenEuler-1 ~]# sys…...
oracle之行转列
对于Oracle的行转列功能一直云里雾里,马马虎虎,对行转列的使用场景和使用方法都不够深刻,最近有空理解一下。 Oracle 11g后有专门的函数pivot,对于特定的场景可以直接套用。 需求:求各份job不同员工工资是多少…...

Windows电脑安装USB Redirector并实现内外网跨网USB共享通信访问
文章目录 前言1. 安装下载软件1.1 内网安装使用USB Redirector1.2 下载安装cpolar内网穿透 2. 完成USB Redirector服务端和客户端映射连接3. 设置固定的公网地址 前言 我们每天都在与各种智能设备打交道,从手机到电脑,再到各种外设,它们已经…...
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搭建监控大屏
本文介绍生产系统监控大屏的搭建,比较实用也是实际应用比较多的方式,希望能够帮助大家对监控系统有一定的认识。 0、规划 grafana主要是展示和报警,Prometheus用于保存监控数据,node_exporter用于实时采集各个应用服务器的事实状…...
深度学习在语音识别中的应用
引言 语音识别技术是人工智能领域中的一个重要分支,它使得机器能够理解和转换人类的语音为文本。深度学习的出现极大地推动了语音识别技术的发展。本文将介绍如何使用深度学习构建一个基本的语音识别系统,并提供一个实践案例。 环境准备 在开始之前&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数据库存储
要实现将医学影像数据(如DICOM文件或其他医学图像格式)存储到MySQL数据库中,并使用VTK进行数据读取和处理的C示例代码,可以按照以下步骤进行。这个示例将展示如何将DICOM图像数据存储到MySQL数据库,然后使用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;创建存储过程 -- 创建存…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...
基于Uniapp开发HarmonyOS 5.0旅游应用技术实践
一、技术选型背景 1.跨平台优势 Uniapp采用Vue.js框架,支持"一次开发,多端部署",可同步生成HarmonyOS、iOS、Android等多平台应用。 2.鸿蒙特性融合 HarmonyOS 5.0的分布式能力与原子化服务,为旅游应用带来…...

1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
【学习笔记】深入理解Java虚拟机学习笔记——第4章 虚拟机性能监控,故障处理工具
第2章 虚拟机性能监控,故障处理工具 4.1 概述 略 4.2 基础故障处理工具 4.2.1 jps:虚拟机进程状况工具 命令:jps [options] [hostid] 功能:本地虚拟机进程显示进程ID(与ps相同),可同时显示主类&#x…...

短视频矩阵系统文案创作功能开发实践,定制化开发
在短视频行业迅猛发展的当下,企业和个人创作者为了扩大影响力、提升传播效果,纷纷采用短视频矩阵运营策略,同时管理多个平台、多个账号的内容发布。然而,频繁的文案创作需求让运营者疲于应对,如何高效产出高质量文案成…...
【Android】Android 开发 ADB 常用指令
查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

认识CMake并使用CMake构建自己的第一个项目
1.CMake的作用和优势 跨平台支持:CMake支持多种操作系统和编译器,使用同一份构建配置可以在不同的环境中使用 简化配置:通过CMakeLists.txt文件,用户可以定义项目结构、依赖项、编译选项等,无需手动编写复杂的构建脚本…...

协议转换利器,profinet转ethercat网关的两大派系,各有千秋
随着工业以太网的发展,其高效、便捷、协议开放、易于冗余等诸多优点,被越来越多的工业现场所采用。西门子SIMATIC S7-1200/1500系列PLC集成有Profinet接口,具有实时性、开放性,使用TCP/IP和IT标准,符合基于工业以太网的…...

rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...

麒麟系统使用-进行.NET开发
文章目录 前言一、搭建dotnet环境1.获取相关资源2.配置dotnet 二、使用dotnet三、其他说明总结 前言 麒麟系统的内核是基于linux的,如果需要进行.NET开发,则需要安装特定的应用。由于NET Framework 是仅适用于 Windows 版本的 .NET,所以要进…...