1. SPI总线原理
SPI是串行外设接口 (Serial Peripheral 的缩写 是一种高速 、 全双工 、 同步的通
信总线。 SPI 是 Motorola 公司推出的一种同步串行接口技术 SPI 由一个主设备和一个或多
个从设备组成,在一次数据传输过程中,接口上只能有一个主机和一个从机能够通信。
SPI总线的优点是操作简单、 数据传输速率 较高、全双工,缺点是 只支持单个主机 、 没
有指定的流控制,没有应答机制确认是否接收到数据。
1.1. 接口信号定义
SPI总线 接口包括以下四种信号:
1) MOSI Master Output Slave Input ):主器件数据输出,从器件数据输入。
2) MISO Master Input Slave Output ):主器件数据输入,从器件数据输出。
3) SCK Serial Clock ):有时也称为 SCLK ,时钟信号,由主器件产生。
4) CS Chip select ):有时也称为 SS ,从器件使能信号,由主器件控制,实际使用时,经
常用 GPIO 来代替。
SPI总线 支持连接多个从机,如下图所示, SPI 主机通过连接到从机的片选信号使能 禁
止从机, 并且同时只能使能一个从机,因此总线里面有多少个从机,就需要多少个片选信号。
当 SPI 主机需要和总线中某个从机进行通讯时,主机会拉低对应的 CS 信号使能该从机,之
后发起通讯,通讯完成后,拉高 CS 信号,解除总线的占用。
对于SPI 总线,我们还需要能深刻理解下面几个知识点。
1. 硬件片选和软件片选的区别
所谓硬件片选指的是SPI 本身具有片选信号,当我们通过 SPI 发送数据时, SPI 外设自
动拉低 CS 信号使能从机,发送完成后自动拉高 CS 信号释放从机,这个过程是不需要软件
操作的。而软件片选则是需要使用 GPIO 作为片选信号, SPI 在发送数据之前,需要先通过
软件设置作为片选信号的 GPIO 输出低电平,发送完成之后再设置该 GPIO 输出高电平。
2. SPI 总线是回环结构
SPI是一个环形总线结构,如下图所示,主设备和从设备构成一个环形。在时钟 SCK
的作用下, 主设备发送一个位到从设备,因为是环形结构,所以从设备必定会同时传送一个
位到主设备。同样,主设备向从设备发送一个字节,从设备也必定会同时传送一个字节到主
设备。理解了环形结构,就很容易理解下面几点:
SP I 是全双工,同步的通信总线。
主设备向从设备发送数据时,无论 我们 需不需要从设备返回数据,从设备都会返回数据。
主设备从从设备读取一个字节数据时,为什么需要写一个字节 数据到从设备:因为是环
形结构,不写数据过去,对方的数据就不会被移位过来。
3. SPI 主机和从机之间连接时信号不需要交叉
SPI主机和从机连接时, MOSI 和 MISO 信号是不需要交叉连接的,因为 MOSI 本身就
表示了主机输出、从机输入, MISO 表示主机输入、从机输出,因此不能交叉连接。
1.2. SPI 的 4 种工作模式
SPI总线共有 4 种工作模式:模式 0~ 模式 3 ,这 4 种工作模式是由 时钟相位 和 时钟极性
确定的。
1. 时钟相位 CPOL C l ock polarity SPI 总线空闲时,时钟信号 SCLK 的电平称为时钟极
性, 有以下两种模式:
CPOL=0 SPI 总线空闲时,时钟信号为低电平。
CPOL=1 SPI 总线空闲时,时钟信号为高电平。
2. 时钟极性 CPHA Clock phase SPI 在 时钟信号 SCLK 第几个边沿开始采样 数据,有
以下两种模式:
CPHA =0 :在第 1 个时钟边沿进行数据采样。
CPHA =1 :在第 2 个时钟边沿进行数据采样。
时钟极性 CPOL 时钟相位 CPHA 各有 2 种模式,它们两两组合就形成了 SPI 的 4 种工
作模式,如下表所示。
SPI的 4 种模式中,最常用的是模式 0 和模式 3 。正是由于 SPI 有 4 种工作模式,因此
当我们使用 SPI 总线时,需要去查询 SPI 总线中主机设备(如 nRF52832 )和从机设备(如SPI Flash)的数据手册,确定它们支持什么模式,从而选择适合的工作模式。)的数据手册,确定它们支持什么模式,从而选择适合的工作模式。
SPI的的44种模式种模式的时序图如下。的时序图如下。
时钟相位 CPHA=0 时的时序
时钟相位 CPHA= 1 时的时序
2. nRF52832的SPIM
学习nRF52832 的 SPI 前,我们首先要清楚 nRF52832 芯片的 SPI 、 SPIM 和 SPIS 的概
念, nRF52832 片内集成的 SPI 分为三种,称为 SPI 、 SPIM 和 SPIS ,它们的区别如下
SPI :不含 EasyDMA 的 SPI 主机,不推荐使用。
SPIM :含 EasyDMA 的 SPI 主机 。
SPIS :含 EasyDMA 的 SPI 从机 。
SPI
、 SPIM 和 SPIS 的寄存器是共用相同内存的,也就是说, SPI 、 SPIM 和 SPIS ,我们
同时只能用一个,如我们使用了 SPIM0 ,那么就不能同时使用 SPI0 和 SPIS0 。
本章的讲解是针对
SPIM 的,即带 EasyDMA 的 SPI 主机。
SPIM
SPI master with EasyDMA )),表示具有 EasyDMA 的 SPI 主机 ,其特点如下
片内集成 3 个 SPI 主机。
SPIM 没有专 用 的片选引脚,连接多个从机时需要使用 IO 作为片选引脚区分从机。
可以通过 EasyDMA 从 RAM 存取数据 。
SPIM 支持 4 种 SPI 模式:模式 0~ 模式 3 。
SPI 的引脚可以通过配置相应的引脚配置寄存器映射到任意 IO 。
2.1. EasyDMA
SPI主机使用 EasyDMA 从 RAM 读取数据,而无需 CPU 参与。 RXD.PTR 和 TXD.PTR
分别指向接收缓存和发送缓存, RXD.MAXCNT 和 TXD.MAXCNT 描述了 接收缓存和发送
缓存的字节数。
SPI主机 传输了 TXD.MAXCNT 个字节后或接收了 RXD.MAXCNT 个字节后会自动停止,
如果 TXD.MAXCNT 大于 RXD.MAXCNT ,多余接收的字节会被丢弃。如果 R XD.MAXCNT
大于 T XD.MAXCNT 则剩余的发送字节将包含 ORC 寄存器中定义的值 。
RXD.PTR和 TXD.PTR 必须指向片内 RAM 区域, 如果 RXD.PTR 和 TXD.PTR 未指向
数据 RAM 区域,则 EasyDMA 传输可能导致 HardFault 或 RAM 损坏 。
.PTR和 .MAXCNT 寄存器是双缓冲的,因此 它们可以在收到 STARTED 事件后立即更新
并准备好进行下一次传输 。
ENDRX / ENDTX事件表示 EasyDMA 已完成分别访问 RAM 中的 RX / TX 缓存 区。当
RX 和 TX 都完成访问 RAM 中的 缓存 区时,会生成 END 事件 。
2.2. SPI 主机事务序列
如下图所示,
SPI 主机 通过触发 START 任务启动 SPI 事务,当发送器发送完
TXD.MAXCNT 寄存器中指定的 TXD 缓存 区中的所有字节时,将产生 ENDTX 事件。接收
器接收数据后填充到 RXD 缓存 区 ,当填入到 缓存 区的数据字节数达到 RXD.MAXCNT 寄存
器中指定的 数值时 将产生 ENDRX 事件 。
SPI主机 执行 START 任务后,当 ENDRX 和 ENDTX 都产生 时, SPI 主机 将 产生 END
事件 。
SPI主机 通过触发 STOP 任务 停止 SPI SPI 主机 停止时会产生 STOPPED 事件, 如果在SPI
主机停止时尚未产生 ENDRX 事件,则 SPI 主机同样会产生 ENDRX 事件,即使 RX 缓
存区未满。如果SPI 主机 停止时尚未产生 ENDTX 事件,则 SPI 主机 将会产生 ENDTX 事件,即使
TXD.MAXCNT 寄存器中指定的 TXD 缓存中的所有字节均未传输。
2.3. 低功耗
当系统处于低功耗且不需要SPIM 外设时, 为了尽可能降低功耗,应先 停止 SPIM ,然后 禁用 SPIM 外设来实现最低功耗。
如果SPIM 已经停止,则不需要触发 STOP 任务 停止 SPIM ,但是如 SPIM 正在执行发送,则 应等待直到收到 STOPPED 事件作为响应,然后再通过 ENABLE 寄存器禁用外设。
3、驱动GD25q16e 与 测试代码
main.c
/*** Copyright (c) 2015 - 2020, Nordic Semiconductor ASA** All rights reserved.** Redistribution and use in source and binary forms, with or without modification,* are permitted provided that the following conditions are met:** 1. Redistributions of source code must retain the above copyright notice, this* list of conditions and the following disclaimer.** 2. Redistributions in binary form, except as embedded into a Nordic* Semiconductor ASA integrated circuit in a product or a software update for* such product, must reproduce the above copyright notice, this list of* conditions and the following disclaimer in the documentation and/or other* materials provided with the distribution.** 3. Neither the name of Nordic Semiconductor ASA nor the names of its* contributors may be used to endorse or promote products derived from this* software without specific prior written permission.** 4. This software, with or without modification, must only be used with a* Nordic Semiconductor ASA integrated circuit.** 5. Any software provided in binary form under this license must not be reverse* engineered, decompiled, modified and/or disassembled.** THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES* OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE* DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.**/
#include "nrf_drv_spi.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "boards.h"
#include "app_error.h"
#include <string.h>
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"#define CORE_SPI_FLASH_WRITE_BUSYBIT (0X01)
#define CORE_SPI_FLASH_ReadData_CMD (0x03) /* Read from Memory instruction */
#define CORE_SPI_FLASH_WriteEnable_CMD (0x06)
#define CORE_SPI_FLASH_WriteDisable_CMD (0x04)
#define CORE_SPI_FLASH_PageProgram_CMD (0x02) /* Write to Memory instruction */
#define CORE_SPI_FLASH_WriteSR_CMD (0x01)
#define CORE_SPI_FLASH_SecErase_CMD (0x20) /* Sector Erase instruction */#define CORE_SPI_FLASH_BlockErase_CMD (0xD8) /* Bulk Erase instruction */
//#define CORE_SPI_FLASH_BlockErase_CMD (0x60) /* Bulk Erase instruction */ #define CORE_SPI_FLASH_READ_DeviceID (0xAB) ///< ¶ÁÈ¡É豸ºÅ
#define CORE_SPI_FLASH_READ_ManufactDeviceID (0x90) ///< ¶ÁÈ¡³§ÉÌID
#define CORE_SPI_FLASH_READ_RDID (0x9F) ///< ¶ÁÈ¡³§ÉÌIdentification
#define CORE_SPI_FLASH_READ_RDSR (0x05) /* Read Status Register instruction */
#define CORE_SPI_FLASH_SET (0x01) /* Read Status Register instruction */#define CORE_SPI_FLASH_CMD_LENGTH (0x04)#define CORE_SPI_FLASH_DUMMY_BYTE (0xA5)
#define CORE_SPI_FLASH_WIP_Flag (0x01) /* Write In Progress (WIP) flag */#define CORE_SPI_TXRX_MAX_LEN (255)#define CORE_SPI_FLASH_PAGE_SIZE (256) /*#define SPI_FLASH_PageSize 0x100*/
#define CORE_SPI_FLASH_SECBYTE_LENGTH (1024*4)
#define CORE_SPI_FLASH_BLOCK_NUM (32)
#define CORE_SPI_FLASH_SECTOR_NUM (4)
#define CORE_SPI_FLASH_PAGE_NUM (16)//SPI·¢ËÍ»º´æÊý×飬ʹÓÃEASYDMAʱһ¶¨Òª¶¨ÒåΪstatic ÀàÐÍ
static uint8_t spi_tx_buf[6];
//SPI½ÓÊÕ»º´æÊý×飬ʹÓÃEASYDMAʱһ¶¨Òª¶¨ÒåΪstatic ÀàÐÍ
static uint8_t spi_rx_buf[6]; //SPIÇý¶¯³ÌÐòʵÀýID,IDºÍÍâÉè±àºÅ¶ÔÓ¦£¬0:SPI0 1:SPI1 2:SPI2
#define SPI_INSTANCE 0 /**< SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE); /**< SPI instance. */
static volatile bool spi_xfer_done; /**< Flag used to indicate that SPI instance completed the transfer. */#define TEST_CORE_SPI_FLASH_BUF_SIZE (32)
#define TEST_CORE_SPI_FLASH_TEST_ADDR (0x00)//SPI·¢ËÍ»º´æÊý×飬ʹÓÃEasyDMAʱһ¶¨Òª¶¨ÒåΪstaticÀàÐÍ
static uint8_t my_tx_buf[4096];
//SPI½ÓÊÕ»º´æÊý×飬ʹÓÃEasyDMAʱһ¶¨Òª¶¨ÒåΪstaticÀàÐÍ
static uint8_t my_rx_buf[4096]; static uint8_t s_write_test_buf[TEST_CORE_SPI_FLASH_BUF_SIZE];/*** @brief SPI user event handler.* @param event*/
static void pi_spi_event_handler(nrf_drv_spi_evt_t const * p_event,void *p_context)
{spi_xfer_done = true;
}bool pi_spi_init(void)
{nrf_gpio_cfg_output(BN_CONTAINER_SPI_SS_PIN);nrf_gpio_pin_set(BN_CONTAINER_SPI_SS_PIN);nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG; spi_config.ss_pin = NRFX_SPIM_PIN_NOT_USED;spi_config.miso_pin = BN_CONTAINER_SPI_MISO_PIN;spi_config.mosi_pin = BN_CONTAINER_SPI_MOSI_PIN;spi_config.sck_pin = BN_CONTAINER_SPI_SCK_PIN;if(NRF_SUCCESS != nrf_drv_spi_init(&spi, &spi_config, pi_spi_event_handler, NULL)){NRF_LOG_INFO("nrf_drv_spi_transfer failed\n");return true;}return false;
}void pi_spi_cs_enable(void)
{nrf_gpio_pin_clear(BN_CONTAINER_SPI_SS_PIN);
}void pi_spi_cs_disable(void)
{nrf_gpio_pin_set(BN_CONTAINER_SPI_SS_PIN);
}bool bn_pi_spi_transfer(uint8_t const * p_tx_buffer,uint8_t tx_buffer_length,uint8_t * p_rx_buffer,uint8_t rx_buffer_length)
{// Reset rx buffer and transfer done flagspi_xfer_done = false;if(NRF_SUCCESS != nrf_drv_spi_transfer(&spi, p_tx_buffer, tx_buffer_length, p_rx_buffer, rx_buffer_length)){NRF_LOG_INFO("nrf_drv_spi_transfer failed\n");return true;}while (!spi_xfer_done){__WFE();}return false;
}bool pi_spi_deinit(void)
{nrf_drv_spi_uninit(&spi); return false;
}bool spi_flash_init(void)
{return pi_spi_init();
}bool spi_flash_deinit(void)
{return pi_spi_deinit();
}/*** @brief Sends a byte through the SPI interface and return the byte received from the SPI bus* @param byte : byte to send* @retval The value of the received byte*/
static bool spi_flash_WriteByte(uint8_t Dat)
{spi_tx_buf[0] = Dat;pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf, 1, spi_rx_buf, 0)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer write one failed");return true;}pi_spi_cs_disable();return false;
}/*** @brief Enables the write access to the FLASH* @param None* @retval None*/
static bool spi_flash_Write_Enable(void)
{bool errcode = true;errcode = spi_flash_WriteByte(CORE_SPI_FLASH_WriteEnable_CMD); if(false != errcode){ NRF_LOG_INFO("spi_flash_WriteByte failed");return true;}return false;
}/*** @brief Disables the write access to the FLASH* @param None* @retval None*/
static bool spi_flash_Write_disable(void)
{bool errcode = true;return false;errcode = spi_flash_WriteByte(CORE_SPI_FLASH_WriteDisable_CMD);if(false != errcode){ NRF_LOG_INFO("spi_flash_WriteByte failed");return true;}return false;
}/*** @brief Reads a byte from the SPI Flash* @param None * @retval Byte Read from the SPI Flash*/
bool spi_flash_ReadByte(uint8_t *ret_data)
{uint8_t len = 1;uint8_t tx_buf = CORE_SPI_FLASH_DUMMY_BYTE;if(NULL == ret_data){NRF_LOG_INFO("bad param!");return true;}pi_spi_cs_enable();if(false != bn_pi_spi_transfer(&tx_buf, len, ret_data, len)){pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer read one failed");return true;}pi_spi_cs_disable();return false;
}/*** @brief Reads FLASH identification* @param None* @retval FLASH identification*/
bool spi_flash_ReadManufacture(uint32_t *Manufacture)
{#define CORE_SPI_FLASH_MANUFACTURE_SIZE (6)uint8_t len;if(NULL == Manufacture){NRF_LOG_INFO("bad param\n");return true;}memset(spi_rx_buf,0,sizeof(spi_rx_buf));spi_tx_buf[0] = CORE_SPI_FLASH_READ_ManufactDeviceID;spi_tx_buf[1] = 0x00;spi_tx_buf[2] = 0x00;spi_tx_buf[3] = 0x00;spi_tx_buf[4] = CORE_SPI_FLASH_DUMMY_BYTE;spi_tx_buf[5] = CORE_SPI_FLASH_DUMMY_BYTE;len = CORE_SPI_FLASH_MANUFACTURE_SIZE;pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf, len, spi_rx_buf, len)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer write page failed");return true;}pi_spi_cs_disable();*Manufacture = (spi_rx_buf[4]<<8)|(spi_rx_buf[5]<<0);return false;
}bool spi_flash_ReadDeviceID(uint8_t *DeviceID)
{#define CORE_SPI_FLASH_DEV_ID_SIZE (5)uint8_t len;if(NULL == DeviceID){NRF_LOG_INFO("bad param\n");return true;}spi_tx_buf[0] = CORE_SPI_FLASH_READ_DeviceID;spi_tx_buf[1] = CORE_SPI_FLASH_DUMMY_BYTE;spi_tx_buf[2] = CORE_SPI_FLASH_DUMMY_BYTE;spi_tx_buf[3] = CORE_SPI_FLASH_DUMMY_BYTE;spi_tx_buf[4] = CORE_SPI_FLASH_DUMMY_BYTE;len = CORE_SPI_FLASH_DEV_ID_SIZE;memset(spi_rx_buf,0,sizeof(spi_rx_buf));pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf, len, spi_rx_buf, len)){ pi_spi_cs_disable();NRF_LOG_INFO("pi_spi_transfer write page failed");return true;}*DeviceID = spi_rx_buf[4];pi_spi_cs_disable();return false;
}bool spi_flash_Read_ID(uint8_t *ID)
{#define CORE_SPI_FLASH_ID_SIZE (4)uint8_t len;if(NULL == ID){NRF_LOG_INFO("bad param\n");return true;}spi_tx_buf[0] = CORE_SPI_FLASH_READ_RDID;spi_tx_buf[1] = CORE_SPI_FLASH_DUMMY_BYTE;spi_tx_buf[2] = CORE_SPI_FLASH_DUMMY_BYTE;spi_tx_buf[3] = CORE_SPI_FLASH_DUMMY_BYTE;len = CORE_SPI_FLASH_ID_SIZE;memset(spi_rx_buf,0,sizeof(spi_rx_buf));pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf, len, spi_rx_buf, len)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer write page failed");return true;}pi_spi_cs_disable();memcpy(ID,&spi_rx_buf[1],CORE_SPI_FLASH_ID_SIZE - 1);return false;
}static uint8_t spi_flash_ReadSR(void)
{spi_tx_buf[0] = CORE_SPI_FLASH_READ_RDSR;spi_tx_buf[1] = 0x00;pi_spi_cs_enable();memset(spi_rx_buf,0,sizeof(spi_rx_buf));if(false != bn_pi_spi_transfer(spi_tx_buf, 2, spi_rx_buf, 2)){ pi_spi_cs_disable();NRF_LOG_INFO("pi_spi_transfer write page failed");return 1;} pi_spi_cs_disable();return spi_rx_buf[1];
}/**
* @brief Polls the status of the Write In Progress (WIP) flag in the FLASH's status register
* @param None
* @retval None
*/
void spi_flash_WaitForWriteEnd(void)
{ uint8_t counter = 0;while((spi_flash_ReadSR()&CORE_SPI_FLASH_WIP_Flag)==CORE_SPI_FLASH_WIP_Flag){counter ++;if(counter > 100){nrf_delay_ms(200); break;}}
}/*** @brief Erases the specified FLASH sector* @param SectorAddr: address of the sector to erase* @retval None
*/
bool spi_flash_Erase_Sector(uint32_t SectorAddr)
{ #define CORE_SPI_FLASH_ERASE_SECTOR_SIZE (5)/* Send write enable instruction */spi_flash_Write_Enable();/* Send Sector Erase instruction */spi_tx_buf[0] = CORE_SPI_FLASH_SecErase_CMD;/* Send SectorAddr high nibble address byte */spi_tx_buf[1] = (uint8_t)((SectorAddr & 0xFF0000) >> 16);/* Send SectorAddr medium nibble address byte */spi_tx_buf[2] = (uint8_t)((SectorAddr & 0xFF00) >> 8);/* Send SectorAddr low nibble address byte */spi_tx_buf[3] = (uint8_t)(SectorAddr & 0xFF); pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf,CORE_SPI_FLASH_CMD_LENGTH,spi_rx_buf,0)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer erase sector failed");return true;}pi_spi_cs_disable();nrf_delay_ms(20); /* Wait the end of Flash writing */spi_flash_WaitForWriteEnd();spi_flash_Write_disable();return false;
}/*** @brief Erases the entire FLASH need 40 second* @param None* @retval None */
bool SPI_FLASH_BulkErase(uint32_t bulkAddr)
{/* Bulk Erase *//* Send write enable instruction */spi_flash_Write_Enable();/* Send Bulk Erase instruction */spi_tx_buf[0] = CORE_SPI_FLASH_BlockErase_CMD;/* Send SectorAddr high nibble address byte */spi_tx_buf[1] = (uint8_t)((bulkAddr & 0xFF0000) >> 16);/* Send SectorAddr medium nibble address byte */spi_tx_buf[2] = (uint8_t)((bulkAddr & 0xFF00) >> 8);/* Send SectorAddr low nibble address byte */spi_tx_buf[3] = (uint8_t)(bulkAddr & 0xFF); pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf,CORE_SPI_FLASH_CMD_LENGTH,spi_rx_buf,0)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer erase sector failed");return true;}pi_spi_cs_disable();nrf_delay_ms(100);/* Wait the end of Flash writing */spi_flash_WaitForWriteEnd();spi_flash_Write_disable();return false;
}/*** @brief Writes more than one byte to the FLASH ÏòÖ¸¶¨µÄµØַдÈëÊý¾Ý£¬×î´óдÈëµÄ³¤¶È²»Äܳ¬¹ý¸ÃµØÖ·Ëù´¦Ò³ÃæµÄÊ£Óà¿Õ¼ä* @param pBuffer : pointer to the buffer* @param WriteAddr : FLASH's internal address to write to* @param size : number of bytes to write to the FLASH Ò»´ÎÐÔ×î¶à256¸ö×Ö½Ú* @retval None */
static bool spi_flash_Write_Page(uint8_t *pBuffer, uint32_t WriteAddr, uint32_t size)
{if(NULL == pBuffer){NRF_LOG_INFO("bad param!\n");return true;}//¼ì²éдÈëµÄÊý¾Ý³¤¶ÈÊÇ·ñºÏ·¨£¬Ð´È볤¶È²»Äܳ¬¹ýÒ³ÃæµÄ´óСif (size > (CORE_SPI_FLASH_PAGE_SIZE - (WriteAddr%CORE_SPI_FLASH_PAGE_SIZE))){NRF_LOG_INFO("SPI_FLASH_WRITE_PAGE_NUM_OVER");return true;}if (size == 0){return false;}/* Enable the write access to the FLASH */ spi_flash_Write_Enable(); /* Select the FLASH: Chip Select low */memset(spi_tx_buf,0,sizeof(spi_tx_buf));/* Send "Write to Memory " instruction */spi_tx_buf[0] = CORE_SPI_FLASH_PageProgram_CMD;/* Send WriteAddr high nibble address byte to write to */spi_tx_buf[1] = (uint8_t)((WriteAddr&0x00ff0000)>>16);/* Send WriteAddr medium nibble address byte to write to */spi_tx_buf[2] = (uint8_t)((WriteAddr&0x0000ff00)>>8);/* Send WriteAddr low nibble address byte to write to */spi_tx_buf[3] = (uint8_t)(WriteAddr&0xff);spi_tx_buf[4] = *pBuffer;pi_spi_cs_enable();if(false != bn_pi_spi_transfer(spi_tx_buf,CORE_SPI_FLASH_CMD_LENGTH+1, spi_rx_buf,0)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer erase sector failed");return true;} if(false != bn_pi_spi_transfer(pBuffer+1,size-1, spi_rx_buf,0)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer erase sector failed");return true;}pi_spi_cs_disable();/* Wait the end of Flash writing */spi_flash_WaitForWriteEnd();/* Deselect the FLASH: Chip Select high */spi_flash_Write_disable();return false;
}/**
* @brief Writes block of data to the FLASH
* @param pBuffer : pointer to the buffer
* @param WriteAddr : FLASH's internal address to write to
* @param NumByteToWrite : number of bytes to write to the FLASH
* @retval None
*/
bool spi_flash_Write(uint8_t * pBuffer, uint32_t WriteAddr, uint32_t NumByteToWrite){bool errcode = true;uint8_t NumOfPage = 0, NumOfSingle = 0, Addr = 0, count = 0, temp = 0;if(NULL == pBuffer){NRF_LOG_INFO("bad param!\n");return true;}Addr = WriteAddr % CORE_SPI_FLASH_PAGE_SIZE;count = CORE_SPI_FLASH_PAGE_SIZE - Addr;NumOfPage = NumByteToWrite / CORE_SPI_FLASH_PAGE_SIZE;NumOfSingle = NumByteToWrite % CORE_SPI_FLASH_PAGE_SIZE;/* WriteAddr is SPI_FLASH_PageSize aligned */if (Addr == 0){ /* NumByteToWrite < SPI_FLASH_PageSize */if (NumOfPage == 0) {errcode = spi_flash_Write_Page(pBuffer, WriteAddr, NumByteToWrite);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}}else /* NumByteToWrite > SPI_FLASH_PageSize */{while (NumOfPage--){errcode = spi_flash_Write_Page(pBuffer, WriteAddr, CORE_SPI_FLASH_PAGE_SIZE);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}WriteAddr += CORE_SPI_FLASH_PAGE_SIZE;pBuffer += CORE_SPI_FLASH_PAGE_SIZE;}errcode = spi_flash_Write_Page(pBuffer, WriteAddr, NumOfSingle);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}}}else /* WriteAddr is not SPI_FLASH_PageSize aligned */{if (NumOfPage == 0){/* (NumByteToWrite + WriteAddr) > SPI_FLASH_PageSize */if (NumOfSingle > count) {temp = NumOfSingle - count;errcode = spi_flash_Write_Page(pBuffer, WriteAddr, count);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}WriteAddr += count;pBuffer += count;errcode = spi_flash_Write_Page(pBuffer, WriteAddr, temp);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}}else{errcode = spi_flash_Write_Page(pBuffer, WriteAddr, NumByteToWrite);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}}}else /* NumByteToWrite > SPI_FLASH_PageSize */{NumByteToWrite -= count;NumOfPage = NumByteToWrite / CORE_SPI_FLASH_PAGE_SIZE;NumOfSingle = NumByteToWrite % CORE_SPI_FLASH_PAGE_SIZE;errcode = spi_flash_Write_Page(pBuffer, WriteAddr, count);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}WriteAddr += count;pBuffer += count;while (NumOfPage--){errcode = spi_flash_Write_Page(pBuffer, WriteAddr, CORE_SPI_FLASH_PAGE_SIZE);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}WriteAddr += CORE_SPI_FLASH_PAGE_SIZE;pBuffer += CORE_SPI_FLASH_PAGE_SIZE;}if (NumOfSingle != 0){errcode = spi_flash_Write_Page(pBuffer, WriteAddr, NumOfSingle);if(false != errcode){NRF_LOG_INFO("spi_flash_Write_Page_gd25q16e failed");return errcode;}}}}return false;
}/*** @brief Reads a block of data from the FLASH ´ÓÖ¸¶¨µÄµØÖ·¶Á³öÖ¸¶¨³¤¶ÈµÄÊý¾Ý* @param pBuffer : pointer to the buffer that receives the data read from the FLASH* @param ReadAddr : FLASH's internal address to read from* @param size : number of bytes to read from the FLASH ×¢Òâsize²»Äܳ¬¹ýpBufferµÄ´óС£¬·ñÔòÊý×é»áÒç³ö* @retval None */
bool spi_flash_Read(uint8_t *pBuffer,uint32_t ReadAddr,uint32_t size)
{uint8_t read_size;/* Send "Read from Memory " instruction */spi_tx_buf[0] = CORE_SPI_FLASH_ReadData_CMD;/* Send ReadAddr high nibble address byte to read from */spi_tx_buf[1] = (uint8_t)((ReadAddr&0x00ff0000)>>16);/* Send ReadAddr medium nibble address byte to read from */spi_tx_buf[2] = (uint8_t)((ReadAddr&0x0000ff00)>>8);/* Send ReadAddr low nibble address byte to read from */spi_tx_buf[3] = (uint8_t)(ReadAddr & 0xFF);pi_spi_cs_enable();/* while there is data to be written on the FLASH */if(false != bn_pi_spi_transfer(spi_tx_buf,CORE_SPI_FLASH_CMD_LENGTH, spi_rx_buf,0)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer erase sector failed");return true;}//¿ªÊ¼¶ÁÈ¡Êý¾Ýwhile(size != 0){if(size <= CORE_SPI_TXRX_MAX_LEN){read_size = size;size = 0;}else{read_size = CORE_SPI_TXRX_MAX_LEN;size -= CORE_SPI_TXRX_MAX_LEN;}/* while there is data to be written on the FLASH */if(false != bn_pi_spi_transfer(spi_tx_buf,0, pBuffer,read_size)){ pi_spi_cs_disable();NRF_LOG_INFO("bn_pi_spi_transfer erase sector failed");return true;}pBuffer += read_size;}pi_spi_cs_disable();return false;
}static bool unit_test_core_spi_flash_init(void)
{bool errcode = false;errcode = spi_flash_init();if(false != errcode){NRF_LOG_INFO("core_spi_flash_init failed\n");return errcode;}NRF_LOG_INFO("core_spi_flash_init success\n");return false;
}static bool unit_test_core_spi_flash_deinit(void)
{bool errcode = false;errcode = spi_flash_deinit();if(false != errcode){NRF_LOG_INFO("spi_flash_deinit failed\n");return errcode;}NRF_LOG_INFO("spi_flash_deinit success\n");return errcode;
}/*bn_core_spi_flash_Erase_Sector_gd25q16e(0); //????????
nrf_delay_ms(100);
SpiFlash_Write_Page(Tx_Buffer,0x00,5);//??5?????
SpiFlash_Read(Rx_Buffer,0x00,5); //??5?????*/
static bool unit_test_core_spi_flash_erase_sector(void)
{bool errcode = false; uint8_t read_test_buf[TEST_CORE_SPI_FLASH_BUF_SIZE];int16_t i = 0;errcode = spi_flash_Erase_Sector(TEST_CORE_SPI_FLASH_TEST_ADDR);if(false != errcode){NRF_LOG_INFO("core_spi_flash_Erase_Sector failed\n");return errcode;} memset(read_test_buf,0,sizeof(read_test_buf));errcode = spi_flash_Read(read_test_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,TEST_CORE_SPI_FLASH_BUF_SIZE);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < TEST_CORE_SPI_FLASH_BUF_SIZE; i ++){if(0xff != read_test_buf[i]){NRF_LOG_INFO("core_spi_flash_Erase_Sector failed\n");return true;}}NRF_LOG_INFO("spi_flash_Erase_Sector success\n");return errcode;
}static bool unit_test_core_spi_flash_write_page(void)
{ int16_t i = 0;bool errcode = false; memset(s_write_test_buf,0,sizeof(s_write_test_buf));for(i = 0; i < TEST_CORE_SPI_FLASH_BUF_SIZE; i ++){s_write_test_buf[i] = i;}errcode = spi_flash_Write(s_write_test_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,TEST_CORE_SPI_FLASH_BUF_SIZE);if(false != errcode){NRF_LOG_INFO("spi_flash_Write failed\n");return errcode;}NRF_LOG_INFO("spi_flash_Write success\n");return false;
}static bool unit_test_core_spi_flash_read(void)
{uint8_t read_test_buf[TEST_CORE_SPI_FLASH_BUF_SIZE];int16_t i = 0;bool errcode = false; memset(read_test_buf,0,sizeof(read_test_buf));errcode = spi_flash_Read(read_test_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,TEST_CORE_SPI_FLASH_BUF_SIZE);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < TEST_CORE_SPI_FLASH_BUF_SIZE; i ++){if(s_write_test_buf[i] != read_test_buf[i]){NRF_LOG_INFO("spi_flash_Read failed\n");return true;}}NRF_LOG_INFO("spi_flash_Read success\n");return false;
}static bool unit_test_core_spi_flash_Read_ALL_ID(void)
{uint32_t Manufacture = 0;uint8_t DeviceID = 0;uint8_t id[3] = {0};bool errcode = false; errcode = spi_flash_ReadManufacture(&Manufacture);if(false != errcode){NRF_LOG_INFO("core_spi_flash_ReadManufacture failed\n");return errcode;}NRF_LOG_INFO("spi_flash_ReadManufacture success Manufacture=0x%x\n",Manufacture);errcode = spi_flash_ReadDeviceID(&DeviceID);if(false != errcode){NRF_LOG_INFO("spi_flash_ReadDeviceID failed\n");return errcode;}NRF_LOG_INFO("spi_flash_ReadDeviceID success v=0x%x\n",DeviceID);errcode = spi_flash_Read_ID(id);if(false != errcode){NRF_LOG_INFO("spi_flash_Read_ID failed\n");return errcode;}NRF_LOG_INFO("spi_flash_Read_ID success 0x%x 0x%x 0x%x\n",id[0],id[1],id[2]);return false;
}static bool unit_test_core_spi_flash_batch_test(void)
{uint32_t i,test_len;static uint8_t j = 1;bool errcode = false;//1.????256??test_len = 256; for(i=0;i<test_len;i++)my_tx_buf[i] = j++;errcode = spi_flash_Erase_Sector(TEST_CORE_SPI_FLASH_TEST_ADDR);if(false != errcode){NRF_LOG_INFO("spi_flash_Erase_Sector failed\n");return errcode;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < test_len; i ++){if(0xff != my_rx_buf[i]){NRF_LOG_INFO("spi_flash_Read failed\n");return true;}}errcode = spi_flash_Write(my_tx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Write failed\n");return true;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < test_len; i ++){if(my_tx_buf[i] != my_rx_buf[i]){NRF_LOG_INFO("spi_flash_Write failed\n");return true;}} //2.????500??test_len = 500; for(i=0;i<test_len;i++)my_tx_buf[i] = j++;errcode = spi_flash_Erase_Sector(TEST_CORE_SPI_FLASH_TEST_ADDR);if(false != errcode){NRF_LOG_INFO("spi_flash_Erase_Sector failed\n");return errcode;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < test_len; i ++){if(0xff != my_rx_buf[i]){NRF_LOG_INFO("spi_flash_Read failed\n");return true;}}errcode = spi_flash_Write(my_tx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Write failed\n");return true;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < test_len; i ++){if(my_tx_buf[i] != my_rx_buf[i]){NRF_LOG_INFO("spi_flash_Read failed\n");return true;}}//3.????4096??test_len = 4096; for(i=0;i<test_len;i++)my_tx_buf[i] = j++;errcode = spi_flash_Erase_Sector(TEST_CORE_SPI_FLASH_TEST_ADDR);if(false != errcode){NRF_LOG_INFO("spi_flash_Erase_Sector failed\n");return errcode;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < test_len; i ++){if(0xff != my_rx_buf[i]){NRF_LOG_INFO("spi_flash_Read failed\n");return true;}}errcode = spi_flash_Write(my_tx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Write failed\n");return true;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,test_len);if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < test_len; i ++){if(my_tx_buf[i] != my_rx_buf[i]){NRF_LOG_INFO("spi_flash_Read failed\n");return true;}} //4.?????errcode = SPI_FLASH_BulkErase(TEST_CORE_SPI_FLASH_TEST_ADDR); if(false != errcode){NRF_LOG_INFO("SPI_FLASH_BulkErase failed\n");return true;}memset(my_rx_buf,0,sizeof(my_rx_buf)); errcode = spi_flash_Read(my_rx_buf,TEST_CORE_SPI_FLASH_TEST_ADDR,sizeof(my_rx_buf));if(false != errcode){NRF_LOG_INFO("spi_flash_Read failed\n");return errcode;}for(i = 0; i < sizeof(my_rx_buf); i ++){if(0xff != my_rx_buf[i]){NRF_LOG_INFO("SPI_FLASH_BulkErase failed\n");return true;}}return false;}bool unit_test_core_spi_flash_test(void)
{bool errcode = false;int32_t index = 0;errcode = unit_test_core_spi_flash_init();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_init failed\n");return errcode;}errcode = unit_test_core_spi_flash_Read_ALL_ID();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_Read_ALL_ID failed\n");return errcode;}for(index = 0; index < 2; index ++){nrf_delay_ms(1000);index ++;}errcode = unit_test_core_spi_flash_erase_sector();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_erase_sector failed\n");return errcode;}for(index = 0; index < 2; index ++){nrf_delay_ms(1000);index ++;}errcode = unit_test_core_spi_flash_write_page();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_write_page failed\n");return errcode;}errcode = unit_test_core_spi_flash_read();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_read failed\n");return errcode;}errcode = unit_test_core_spi_flash_batch_test();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_batch_test failed\n");return errcode;}errcode = unit_test_core_spi_flash_deinit();if(false != errcode){NRF_LOG_INFO("unit_test_core_spi_flash_deinit failed\n");return errcode;}return false;
}int32_t main(void)
{APP_ERROR_CHECK(NRF_LOG_INIT(NULL));NRF_LOG_DEFAULT_BACKENDS_INIT();unit_test_core_spi_flash_test();
}