1 NRF52832SPI主机的功能描述
nRF52832SPIM的主要特征
3个SPI实例
支持SPI的模式0到模式3
支持DMA
Individual selection of IO pin for each SPI signal
注意:SPI主控制器不支持直接片选,因此SPI主机的CPU必须使用可用的GPIO来实现对从机的片选控制。另外,SPI可与和它具有相同ID的其他外设共享寄存器和其他一些资源。配置和使用SPI之前必须关闭与它有相同ID的外设。关闭与SPI有相同ID的外设,不会复位与SPI共享的寄存器。因此为了确保SPI正常运行,必须配置相关的SPI寄存器。
2 软件设计
2.1

#define NRF_DRV_SPI_DEFAULT_CONFIG                           \
{                                                            \.sck_pin      = NRF_DRV_SPI_PIN_NOT_USED,                \  //SCK时钟引脚.mosi_pin     = NRF_DRV_SPI_PIN_NOT_USED,                \  //MOSI引脚.miso_pin     = NRF_DRV_SPI_PIN_NOT_USED,                \  //MISO引脚.ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,                \  //SS引脚.irq_priority = SPI_DEFAULT_CONFIG_IRQ_PRIORITY,         \  //中断优先级.orc          = 0xFF,                                    \.frequency    = NRF_DRV_SPI_FREQ_4M,                     \  //SPI通信的速率.mode         = NRF_DRV_SPI_MODE_0,                      \  //SPI的工作模式.bit_order    = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,         \  //MSB先行或LSB先行
}

NRF_DRV_SPI_DEFAULT_CONFIG宏用来配置SPI的基本信息。其中SPI_DEFAULT_CONFIG_IRQ_PRIORITY用来配置SPI的中断优先级,在写程序时要注意合理的配置中断优先级,防止两个外设的中断优先级相同,在nRF52832中,中断号为0代表中断优先级最高。
2.2 代码

#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 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_STRING "Nordic"
//static uint8_t       m_tx_buf[] = TEST_STRING;           /**< TX buffer. */
//static uint8_t       m_rx_buf[sizeof(TEST_STRING) + 1];    /**< RX buffer. */
//static const uint8_t m_length = sizeof(m_tx_buf);        /**< Transfer length. */#define W25X_WriteEnable 0x06
#define W25X_JedecDeviceID 0X9F
#define W25X_ReadStatusReg 0x05
#define W25X_SectorErase 0xD8
#define W25X_PageProgram 0x02
#define W25X_ReadData 0x03
#define W25X_ChipErase 0xC7
#define FLASH_ID 0XEF4015  //器件ID
#define Dummy_Byte 0XFF
#define WIP_Flag  0x01#define SPI_BUFSIZE 8 //SPI缓存的大小
uint8_t   SPI_Tx_Buf[SPI_BUFSIZE];  //发送
uint8_t   SPI_Rx_Buf[SPI_BUFSIZE];  //接收
uint32_t ID = 0;
volatile  uint8_t   SPIReadLength, SPIWriteLength;
/*** @brief SPI user event handler.* @param event*/
void spi_event_handler(nrf_drv_spi_evt_t const * p_event,void *                    p_context)
{spi_xfer_done = true;
}
/*
向W25Q80中写入数据
参数 reg 寄存器地址data 要写入的数据
*/
void W25Q80_write_reg(int data)
{spi_xfer_done = false;SPIWriteLength = 1;SPIReadLength = 0;SPI_Tx_Buf[0] = data;  APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, SPI_Tx_Buf, SPIWriteLength, SPI_Rx_Buf, SPIReadLength));while(spi_xfer_done == false);
}
/*
从W25Q80中读取数据
参数: reg 寄存器地址
*/
uint8_t W25Q80_read_reg(int reg)
{spi_xfer_done = false;SPI_Tx_Buf[0] = reg;APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, SPI_Tx_Buf, 0, SPI_Rx_Buf,1));while(spi_xfer_done == false);return SPI_Rx_Buf[0];
}
/*
读取W25Q80的器件ID
*/
uint32_t W25Q80_ReadID(void)
{uint32_t temp = 0,temp0 = 0,temp1 = 0,temp2 = 0;nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_JedecDeviceID);temp0 = W25Q80_read_reg(0XFF);temp1 = W25Q80_read_reg(0XFF);temp2 = W25Q80_read_reg(0XFF);nrf_gpio_pin_set(SPI_SS_PIN);  //片选无效temp = (temp0 << 16)| (temp1 << 8) | temp2;return temp;
}
/*
写使能命令
*/
void W25Q80_WriteEnable()
{nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_WriteEnable);nrf_gpio_pin_set(SPI_SS_PIN);  //片选有效
}
/*
通过读状态寄存器等待FLASH芯片空闲
*/
void W25Q80_WaitForWriteEnd()
{unsigned char FLASH_Status = 0;nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_ReadStatusReg); //发送读状态寄存器do{FLASH_Status = W25Q80_read_reg(Dummy_Byte);}while((WIP_Flag & FLASH_Status) == 1);nrf_gpio_pin_set(SPI_SS_PIN);  //片选无效}
/*
擦除FLASH的扇区
参数 SectorAddr 要擦除的扇区地址
*/
void W25Q80_FLASH_SectorErase(uint32_t SectorAddr)
{W25Q80_WriteEnable();  //发送FLASH写使能命令W25Q80_WaitForWriteEnd();  //等待写完成nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_SectorErase);  //发送扇区擦除指令W25Q80_write_reg((SectorAddr & 0XFF0000) >> 16); //发送扇区擦除地址的高位W25Q80_write_reg((SectorAddr & 0XFF00) >> 8);W25Q80_write_reg(SectorAddr & 0XFF);nrf_gpio_pin_set(SPI_SS_PIN);  //片选无效W25Q80_WaitForWriteEnd();  //等待擦除完成
}
/*
FLASH页写入指令
参数:
备注:使用页写入指令最多可以一次向FLASH传输256个字节的数据
*/
void W25Q80_FLASH_PageWrite(unsigned char* pBuffer, uint32_t WriteAddr, uint16_t NumByteToWrite)
{W25Q80_WriteEnable();  //发送FLASH写使能命令nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_PageProgram);  //发送写指令W25Q80_write_reg((WriteAddr & 0XFF0000) >> 16); //发送写地址的高位W25Q80_write_reg((WriteAddr & 0XFF00) >> 8);W25Q80_write_reg(WriteAddr & 0XFF);if(NumByteToWrite > 256){NRF_LOG_INFO("write too large!\r\n");return ;}while(NumByteToWrite--){W25Q80_write_reg(*pBuffer);pBuffer++;}nrf_gpio_pin_set(SPI_SS_PIN);  //片选无效W25Q80_WaitForWriteEnd();  //等待写完成
}
/*
从FLASH中读取数据
*/
void W25Q80_Flash_BufferRead(uint8_t* pBuffer, uint32_t ReadAddr, uint16_t NumByteToRead)
{nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_ReadData);  //发送写指令W25Q80_write_reg((ReadAddr & 0XFF0000) >> 16); //发送写地址的高位W25Q80_write_reg((ReadAddr & 0XFF00) >> 8);W25Q80_write_reg(ReadAddr & 0XFF);while(NumByteToRead--){*pBuffer = W25Q80_read_reg(Dummy_Byte);pBuffer++;}nrf_gpio_pin_set(SPI_SS_PIN);  //片选无效
}
/*
全片擦除
*/
void W25Q80_Chip_Erase()
{W25Q80_WriteEnable();  //发送FLASH写使能命令nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效W25Q80_write_reg(W25X_ChipErase);  //全片擦除nrf_gpio_pin_set(SPI_SS_PIN);  //片选无效W25Q80_WaitForWriteEnd();  //等待写完成
}
void W25Q80_init()
{//初始化SPI引脚nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
//    spi_config.ss_pin   = SPI_SS_PIN;  //把SS引脚禁用spi_config.miso_pin = SPI_MISO_PIN;spi_config.mosi_pin = SPI_MOSI_PIN;spi_config.sck_pin  = SPI_SCK_PIN;nrf_gpio_cfg_output(SPI_SS_PIN);nrf_gpio_pin_clear(SPI_SS_PIN);  //片选有效APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));nrf_delay_ms(500);nrf_gpio_pin_set(15);//读取寄存器的值,判断器件是否存在 ID=W25Q80_ReadID();if(ID != FLASH_ID){NRF_LOG_INFO("init w25q80 error\r\n");}else{NRF_LOG_INFO("init w25q80 ok!\r\n");NRF_LOG_INFO("FLASH ID is %X",ID);}
}
#define countof(a)      (sizeof(a) / sizeof(*(a)))
#define  BufferSize (countof(Tx_Buffer)-1)
int main(void)
{unsigned char Tx_Buffer[] = "This is a demo about FLASH WRITE BY Manual";unsigned char Rx_Buffer[250];bsp_board_init(BSP_INIT_LEDS);  //初始化开发板上的指示灯APP_ERROR_CHECK(NRF_LOG_INIT(NULL));NRF_LOG_DEFAULT_BACKENDS_INIT();NRF_LOG_INFO("SPI example started.");W25Q80_init();W25Q80_Chip_Erase();  //全片擦除   //全片擦除所需的时间比较长W25Q80_FLASH_PageWrite(Tx_Buffer,0x00000,BufferSize);NRF_LOG_INFO("%s\r\n",Tx_Buffer);W25Q80_Flash_BufferRead(Rx_Buffer,0x000000,BufferSize);NRF_LOG_INFO("%s\r\n",Rx_Buffer);while (1){// Reset rx buffer and transfer done flagspi_xfer_done = false;NRF_LOG_FLUSH();nrf_delay_ms(200);}
}

参考资料:
1 nRF52832数据手册
2 《低功耗蓝牙技术快速入门》
3 W25Q80数据手册
4 《零死角玩转STM32F103指南者》

转载于:https://www.cnblogs.com/Manual-Linux/p/10628951.html

NRF52832与W25Q80通信相关推荐

  1. nrf52832与nrf24L01+通信

    使用2.4G无线芯片nrf24L01+与蓝牙芯片nrf52832通信,nrf52832工作在2.4G模式. nrf24L01+使用以前调试通过程序,两个nrf24L01+通信良好. nrf52832模 ...

  2. NRF52832 ESB通信

    esb通信,也就是纯2.4g的一个通信,据说是兼容24L01+芯片,没有试过,这里是用两个nrf52832芯片做的通信实验. 相关历程参考 如下: 历程里面注释确实不多. 里面函数api介绍可以参考官 ...

  3. NRF52832之ESB功能与NRF24L01进行2.4G通信

    NRF52之ESB学习笔记 目的:为了能与NRF24L01通信,工程中加入nrf_esb.c, nrf_esb.h 先了解RADIO的各种工作状态及流程 1状态 RADIO的工作状态: DISABLE ...

  4. nrf52832 学习笔记(五)蓝牙主从机连接和连接参数更新

    nrf52832 学习笔记(五)蓝牙主从机连接和连接参数更新 主机连接 nrf52832 SDK中主机连接从机需要使用 sd_ble_gap_connect(ble_gap_addr_t const ...

  5. nrf52832 学习笔记(三)蓝牙从机广播

    nrf52832 学习笔记(三)蓝牙从机广播 蓝牙从机要想被主机连接,首先需要发送广播信息,周围主机通过扫描广播信号,根据从机的广播信息,判断是否连接. 蓝牙协议栈初始化 不管是主机还是从机,要想使用 ...

  6. nrf52832 学习笔记(六)配对和绑定

    nrf52832 学习笔记(六)配对和绑定 配对绑定推荐博客低功耗蓝牙配对绑定解读和实践 蓝牙在配对之前都是明文通信的,也就是说主从机之间传输的数据包可以被第三方抓取分析逆向,而且如果没有配对,谁都可 ...

  7. nRF52832调试

    需要用蓝牙芯片做无线串口,选择使用nRF52832.taobao上买了一个hc-42的小板子自己调试用. 1 第一步,测试板子串口转蓝牙是否正常--正常 2 第二步,烧写程序 将板子上的SWDIO.S ...

  8. NRF52832学习笔记(11)——蓝牙MAC地址

    一.背景 一个 BLE 设备,可以使用两种类型的地址(一个 BLE 设备可同时具备两种地址): Public Device Address(公共设备地址) Random Device Address( ...

  9. NRF52832之蓝牙MAC地址修改

    一.背景 一个 BLE 设备,可以使用两种类型的地址(一个 BLE 设备可同时具备两种地址): Public Device Address(公共设备地址) Random Device Address( ...

最新文章

  1. 如何去应付你的上司给你一个变化无常的需求?
  2. ado批量执行sql mysql_C++ 使用 ADO 批量操作数据库
  3. SSIS中的容器和数据流—举例说明数据转换任务
  4. Webdriver使用Chrome模拟手机浏览器测试移动版网站
  5. php语句过滤掉html标签_php过滤html标签
  6. 人工智能和机器学习的前世今生
  7. 在Windows系统下搭建ELK日志分析平台
  8. 深入理解IIS工作原理
  9. Java 数据库连接池的实现
  10. mysql的学生信息建表语句_SQL语句创建学生信息数据库表的示例
  11. 2015年换工作感想
  12. 家谱树 (并查集拓扑排序)
  13. 贪心、动态规划:钢条切割
  14. Arduino造轮子—FlashSRAM优化代码
  15. 3秒测试:组建一个网络,需要几个硬件设备搞定?
  16. Node.js结合wechaty实现个人微信机器人助手
  17. MYSQL系列---默认隔离级别所引发的问题
  18. 【Linux 从入门到精通】第一篇 常见指令及初识权限
  19. 谈谈卷积神经网络和循环神经网络
  20. chmod不是内部或外部命令

热门文章

  1. SQL Server执行计划的理解
  2. NS_OPTIONS枚举的用法
  3. Bash,Vim,gdbgit常用命令
  4. android自定义View-垂直滚动的TextView
  5. [ASP.NET 控件实作 Day31] TBContextMenu 控件三种不同模式的 Click 动作
  6. 日记 [2007年01月26日] 用 phpMyAdmin 让 MySQL 数据库管理温和化
  7. IOS 滑动指示导航栏 渐变
  8. 读书笔记之《实战Java虚拟机》(2):认识Java虚拟机的基本结构
  9. 开题:在移动开发中使用JavaScript进行混合编程提高代码复用率
  10. 寄存器理解 及 X86汇编入门