博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
NRF52832与W25Q80通信
阅读量:6594 次
发布时间:2019-06-24

本文共 7633 字,大约阅读时间需要 25 分钟。

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 
#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 flag spi_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

你可能感兴趣的文章
javascript不可用的问题探究
查看>>
[置顶] jQuery乱谈(五)
查看>>
have sth done/doing的区别
查看>>
paste用法
查看>>
《java开发实战经典》读书笔记——第3章 Java基础程序设计之数据类型划分20151026...
查看>>
C. Tanya and Toys_模拟
查看>>
Swift 表达式
查看>>
iOS - iOS 适配
查看>>
JS实例(一)百度前端技术学院任务(十三)
查看>>
DEBUG(2)--函数的输入参数要做适当的检查
查看>>
1.python基础语法
查看>>
Kafka学习-Producer和Customer
查看>>
js适配器模式
查看>>
社会网络分析之”组成部分”、小圈子和聚类
查看>>
ORA-16019搭建DG设置归档线程参数报错
查看>>
xocde7下导入libsqlite3.tbd编译报错的解决办法
查看>>
100c之39:年龄问题
查看>>
吴忠军人民微博主页
查看>>
java 浅复制 深复制
查看>>
day09 函数
查看>>