stm32专题十八:stm32读写SPI FLASH

发布者:光速思考最新更新时间:2021-10-25 来源: eefocus关键字:stm32  读写SPI  FLASH 手机看文章 扫描二维码
随时随地手机看文章

直接上代码:


bsp_spi_flash.c


/**

  ******************************************************************************

  * @file    bsp_spi_flash.c

  * @author  STMicroelectronics

  * @version V1.0

  * @date    2019

  * @brief   SPI FLASH(W25Q64)应用函数bsp

  ******************************************************************************

  */ 

 

#include "bsp_spi_flash.h"

#include "./usart/bsp_usart.h"

 

 

static __IO uint32_t  SPITimeout = SPIT_LONG_TIMEOUT;   

 

 

static uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode);

 

 

/**

  * @brief  SPI I/O配置

  * @param  无

  * @retval 无

  */

static void SPI_GPIO_Config(void)

{

  GPIO_InitTypeDef  GPIO_InitStructure; 

 

/* 使能与 SPI 有关的时钟 */

FLASH_SPI_APBxClock_FUN(FLASH_SPI_CLK, ENABLE);

FLASH_SPI_GPIO_APBxClock_FUN(FLASH_SPI_GPIO_CLK, ENABLE);

    

  /* MISO MOSI SCK */

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_SCK_PIN;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        // SCK 推挽复用

  GPIO_Init(FLASH_SPI_SCK_PORT, &GPIO_InitStructure);

  GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MOSI_PIN;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        // MOSI 推挽复用

  GPIO_Init(FLASH_SPI_MOSI_PORT, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = FLASH_SPI_MISO_PIN;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // MOSI 浮空输入

  GPIO_Init(FLASH_SPI_MISO_PORT, &GPIO_InitStructure);

// 初始化CS引脚,使用软件控制,所以直接配置为推挽输出

GPIO_InitStructure.GPIO_Pin = FLASH_SPI_CS_PIN;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      // CS 推挽输出

  GPIO_Init(FLASH_SPI_CS_PORT, &GPIO_InitStructure);

// 拉高CS,使SPI处于空闲状态

FLASH_SPI_CS_HIGH;

}

 

 

/**

  * @brief  SPI 工作模式配置

  * @param  无

  * @retval 无

  */

static void SPI_Mode_Config(void)

{

  SPI_InitTypeDef SPI_InitStructure; 

 

  SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;

SPI_InitStructure.SPI_Mode = SPI_Mode_Master;

SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;

SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;

SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;

SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;

SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;

SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;

SPI_InitStructure.SPI_CRCPolynomial = 0; // 不使用CRC功能,数值随便写

  

SPI_Init(FLASH_SPIx, &SPI_InitStructure);

SPI_Cmd(FLASH_SPIx, ENABLE);

}

 

 

/**

  * @brief  I2C 外设(EEPROM)初始化

  * @param  无

  * @retval 无

  */

void SPI_FLASH_Init(void)

{

  SPI_GPIO_Config(); 

  SPI_Mode_Config();

}

 

// 发送并接收一个字节

uint8_t SPI_FLASH_Send_Byte(uint8_t data)

{

SPITimeout = SPIT_FLAG_TIMEOUT;

// 检查并等待至TX缓冲区为空

while (SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_TXE) == RESET)

{

if ((SPITimeout--) == 0)

{

return SPI_TIMEOUT_UserCallback(0);

}

}

// 程序执行到此处,TX缓冲区已空

SPI_I2S_SendData(FLASH_SPIx, data);

SPITimeout = SPIT_FLAG_TIMEOUT;

// 检查并等待至RX缓冲区非空

while (SPI_I2S_GetFlagStatus(FLASH_SPIx, SPI_I2S_FLAG_RXNE) == RESET)

{

if ((SPITimeout--) == 0)

{

return SPI_TIMEOUT_UserCallback(0);

}

}

// 程序执行到此处,说明数据发送完毕,并接收到一个字节

return SPI_I2S_ReceiveData(FLASH_SPIx);

}

 

 

// 接收一个字节

uint8_t SPI_FLASH_Read_Byte(void)

{

return SPI_FLASH_Send_Byte(DUMMY);

}

 

// 读取FLASH ID

uint32_t SPI_Read_ID(void)

{

uint32_t flash_id = 0;

// 片选使能

FLASH_SPI_CS_LOW;

 

SPI_FLASH_Send_Byte(JEDEC_ID); // 发送命令码

flash_id = SPI_FLASH_Read_Byte();

flash_id <<= 8;

flash_id |= SPI_FLASH_Read_Byte();

flash_id <<= 8;

flash_id |= SPI_FLASH_Read_Byte();

 

FLASH_SPI_CS_HIGH;

return flash_id;

}

 

// 写入

 

// Flash写入使能

void SPI_WriteEnable(void)

{

FLASH_SPI_CS_LOW;

 

SPI_FLASH_Send_Byte(WRITE_ENABLE); // 发送命令码

FLASH_SPI_CS_HIGH;

}

 

 

// 擦除Flash指定扇区

void SPI_Erase_Sector(uint32_t addr)

{

SPI_WriteEnable(); // 擦除之前先调用写使能

// 片选使能

FLASH_SPI_CS_LOW;

SPI_FLASH_Send_Byte(ERASE_SECTOR);

 

SPI_FLASH_Send_Byte((addr >> 16) & (0xFF)); // 发送命令码

SPI_FLASH_Send_Byte((addr >> 8) & (0xFF));

 

SPI_FLASH_Send_Byte((addr) & (0xFF));

FLASH_SPI_CS_HIGH;

// Flash的擦除需要时间,要通过读取状态寄存器,来判断是否擦除完成

SPI_WaitForWriteEnd();

}

 

// 读取Flash的内容

void SPI_Read_Data(uint32_t addr, uint8_t *read_buff, uint32_t numByteToRead)

{

// 片选使能

FLASH_SPI_CS_LOW;

SPI_FLASH_Send_Byte(READ_DATA);

 

SPI_FLASH_Send_Byte((addr >> 16) & (0xFF));

SPI_FLASH_Send_Byte((addr >> 8) & (0xFF));

 

SPI_FLASH_Send_Byte((addr) & (0xFF));

while (numByteToRead--)

{

*read_buff = SPI_FLASH_Read_Byte();

read_buff++;

}

FLASH_SPI_CS_HIGH;

}

 

 

// 向Flash中写入内容(一次最多写256字节)

void SPI_Write_Data(uint32_t addr, uint8_t *write_buff, uint32_t numByteToWrite)

{

SPI_WriteEnable(); // 写入之前先调用写使能

// 片选使能

FLASH_SPI_CS_LOW;

SPI_FLASH_Send_Byte(WRITE_DATA);

 

SPI_FLASH_Send_Byte((addr >> 16) & (0xFF));

SPI_FLASH_Send_Byte((addr >> 8) & (0xFF));

 

SPI_FLASH_Send_Byte((addr) & (0xFF));

while (numByteToWrite--)

{

SPI_FLASH_Send_Byte(*write_buff);

write_buff++;

}

FLASH_SPI_CS_HIGH;

SPI_WaitForWriteEnd();

}

 

 

 

// 等待Flash内部时序操作完成

void SPI_WaitForWriteEnd(void)

{

uint8_t status = 0;

// 片选使能

FLASH_SPI_CS_LOW;

 

SPI_FLASH_Send_Byte(STATUS); // 发送命令码

do

{

status = SPI_FLASH_Read_Byte();

}

while ((status & 0x01) == 1); // SPI 总线忙碌

FLASH_SPI_CS_HIGH;

}

 

 

/**

  * @brief  Basic management of the timeout situation.

  * @param  errorCode:错误代码,可以用来定位是哪个环节出错.

  * @retval 返回0,表示SPI读取失败.

  */

static  uint32_t SPI_TIMEOUT_UserCallback(uint8_t errorCode)

{

  /* Block communication and all processes */

  FLASH_ERROR("SPI 等待超时!errorCode = %d",errorCode);

  

  return 0;

}

 

/*********************************************END OF FILE**********************/

 

bsp_spi_flash.h


#ifndef __BSP_SPI_FLASH_H

#define __BSP_SPI_FLASH_H

 

 

#include "stm32f10x.h"

 

 

/**************************I2C参数定义,I2C1或I2C2********************************/

#define             FLASH_SPIx                             SPI1

#define             FLASH_SPI_APBxClock_FUN                   RCC_APB2PeriphClockCmd

#define             FLASH_SPI_CLK                             RCC_APB2Periph_SPI1

#define             FLASH_SPI_GPIO_APBxClock_FUN              RCC_APB2PeriphClockCmd

#define             FLASH_SPI_GPIO_CLK                        (RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC) 

 

#define             FLASH_SPI_SCK_PORT                        GPIOA   

#define             FLASH_SPI_SCK_PIN                         GPIO_Pin_5

 

#define             FLASH_SPI_MISO_PORT                       GPIOA

#define             FLASH_SPI_MISO_PIN                        GPIO_Pin_6

 

#define             FLASH_SPI_MOSI_PORT                       GPIOA 

#define             FLASH_SPI_MOSI_PIN                        GPIO_Pin_7

 

#define             FLASH_SPI_CS_PORT                        GPIOC 

#define             FLASH_SPI_CS_PIN                          GPIO_Pin_0

 

#define DUMMY (0X00)

#define JEDEC_ID (0X9F)

#define ERASE_SECTOR (0X20)

#define STATUS (0X05)

#define READ_DATA (0X03)

#define WRITE_ENABLE (0X06)

#define WRITE_DATA (0X02)

 

/*等待超时时间*/

#define SPIT_FLAG_TIMEOUT         ((uint32_t)0x1000)

#define SPIT_LONG_TIMEOUT         ((uint32_t)(10 * SPIT_FLAG_TIMEOUT))

 

/* CS引脚配置 */

#define FLASH_SPI_CS_HIGH do{GPIO_SetBits(FLASH_SPI_CS_PORT,FLASH_SPI_CS_PIN);}while(0)

#define FLASH_SPI_CS_LOW do{GPIO_ResetBits(FLASH_SPI_CS_PORT,FLASH_SPI_CS_PIN);}while(0)

 

/*信息输出*/

#define FLASH_DEBUG_ON          0

 

#define FLASH_INFO(fmt,arg...)            printf("<<-FLASH-INFO->> "fmt"n",##arg)

#define FLASH_ERROR(fmt,arg...)          printf("<<-FLASH-ERROR->> "fmt"n",##arg)

#define FLASH_DEBUG(fmt,arg...)          do{

                                          if(EEPROM_DEBUG_ON)

                                          printf("<<-FLASH-DEBUG->> [%d]"fmt"n",__LINE__, ##arg);

[1] [2] [3]
关键字:stm32  读写SPI  FLASH 引用地址:stm32专题十八:stm32读写SPI FLASH

上一篇:stm32专题十八:详细分析SPI FLASH
下一篇:stm32专题十九:FatFs文件系统简介

推荐阅读最新更新时间:2024-11-09 11:21

对使用STM32加密库开发比特币应用作一些补充的技术说明
前言 比特币是一个基于区块链和密码技术的应用。本文针对STM32客户的反馈,对那些使用STM32加密库开发比特币应用作了一些补充的技术说明。 STM32 加密库 STM32 加密库提供对称加解密,非对称加解密,以及HASH算法,并通过了CAVP FIPS认证,可使用在各类安全相关的应用。 对称加解密算法支持AES、DES、3DES、RC5、Chacha20、Poly1305。其中针对特定算法,如AES,又支持多种加密模式如ECB、CBC、CTR、GCM、CCM、XTS、Cipher-wrap等。非对称加解密算法支持RSA、ECC。Hash算法支持SHA-1、SHA-224、SHA-256、SHA-384、SHA-512、MD5
[单片机]
对使用<font color='red'>STM32</font>加密库开发比特币应用作一些补充的技术说明
STM32的ADC编程方法总结
这里的ADC转换也来使用DMA---这个也是STM32的ADC转换最常见的方式。 第一步是了解STM32的ADC对应的GPIO口如下图不用记住,可以查询,我是将它剪下来粘贴到书本的相应章节! 第二步是配置相应ADC转换的GPIO口这里使用PC0--PC1 static void ADC1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开DMA1的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 “ RCC_APB
[单片机]
STM32单片的启动过程解析
一、STM32启动文件详细解析 STM32启动文件详细解析(V3.5.0) 以:startup_stm32f10x_hd.s为例 ;********************(C)COPYRIGHT2011STMicroelectronics******************** ;*FileName:startup_stm32f10x_hd.s ;*Author:MCDApplicationTeam ;*Version:V3.5.0 ;*Date:11-March-2011 ;*Description:STM32F10xHighDensityDevicesvectortableforMDK-ARM ;*toolchain. ;*
[单片机]
stm32定时器优先级
什么是优先级   优先级是具有高抢占式优先级的中断可以在具有低抢占式优先级的中断处理过程中被响应,即中断嵌套,或者说高抢占式优先级的中断可以嵌套低抢占式优先级的中断。   当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断表中的排位顺序决定先处理哪一个。 stm32定时器优先级   STM32 可以支持的 68 个外部中断通道,已经固定的分配给相应的外部设备。每个中断通道都具备自己
[单片机]
基于STM32单片机的智能书桌设计与实现
研究结果表明,学生的读写姿势不正确率高达70%甚至85%以上 。不良的读写姿势、不合适的光照条件会令学生不停地调整眼睛的睫状肌,容易降低睫状肌调节能力,进而导致近视 。从长远看,不良的读写姿势还会对学生的脊柱和颈椎形状,乃至整体形貌和健康产生负面影响;另一方面,久坐的办公方式容易导致肌肉骨骼疾患和颈椎、腰椎疾病 。 桌椅高度和光照情况是决定学生能否形成良好读写习惯的重要因素。传统桌椅高度固定,不能很好适应个性化的身高。所以,为了让不同身高的使用者培养良好的使用习惯,本项目设计了一款能根据使用者情况自动调节桌面高度的智能书桌系统。在此基本功能之外,该智能书桌还具有久坐提醒、坐姿不正提醒、随环境光照自动控制亮度的LED台灯、随环境
[单片机]
意法半导体STM32Cube.AI 开发工具增加深度量化神经网络支持
意法半导体(ST)发布了STM32Cube.AI version 7.2.0,这是微控制器厂商推出的首款支持超高效深度量化神经网络的人工智能(AI)开发工具。 STM32Cube.AI 将预先训练好的神经网络转换成STM32微控制器(MCU)可以运行的C语言代码 ,是充分利用嵌入式产品有限的内存容量和算力开发尖端人工智能解决方案的重要工具,将人工智能从云端下移到边缘设备,能够为应用带来巨大的优势,其中包括原生隐私保护、确定性实时响应、更高的可靠性和更低的功耗。边缘人工智能还有助于优化云计算使用率。 现在,通过支持 qKeras 或 Larq 等深度量化输入格式,开发者可以进一步降低神经网络代码量、内存占用和响应延迟
[物联网]
意法半导体STM32Cube.AI 开发工具增加深度量化神经网络支持
Keil5配置与新建STM32工程的步骤及注意事项
新建工程文件夹 建立名字为LED的文件夹存放工程文件,其中再建立两个文件夹,Listing文件夹用于存放编译器编译时候产生的C语言、汇编、链接文件,Output文件夹用于存放编译产生的调试信息、hex文件、预览信息、封装库等。 文件夹建好之后,在LED文件夹下存放startup_stm32f10x_hd.s、stm32f10x.h、main.c文件。前两个文件可以在STM32F1xx的固件库中找到,第三个文件是空文件。 在Keil5中新建工程的步骤 如下图所示,Project-New,新建工程,工程名为Led,点击保存。 点击保存之后,弹出如下窗口,选择芯片型号。根据你开发板使用的芯片具体的型号来选择。如果这里没有出
[单片机]
Keil5配置与新建<font color='red'>STM32</font>工程的步骤及注意事项
基于OpenHarmony的智能金属探测器
一、简介 智能金属探测器是基于 OpenAtom OpenHarmony(以下简称“OpenHarmony”)操作系统,利用电磁感应原理来探测周围的金属物体。该样例采用多设备协同的方式,兼容 OpenHarmony 设备开发与应用开发,整个样例体现了 OpenHarmony 的 NAPI、eTS UI、UI 管理状态 @state 和音频播放等技术特性。 本项目由 Geek_Lite_Board 开发板和润和 RK3568 开发板构成,Geek_Lite_Board 开发板主控芯片为 STM32F427IIH6,作为设备端检测磁场强度的变化,使用的是 OpenHarmony 3.0 LTS 版本。润和 RK3568 开发板是由
[单片机]
基于OpenHarmony的智能金属探测器
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
  • 学习ARM开发(16)
    ARM有很多东西要学习,那么中断,就肯定是需要学习的东西。自从CPU引入中断以来,才真正地进入多任务系统工作,并且大大提高了工作效率。采 ...
  • 学习ARM开发(17)
    因为嵌入式系统里全部要使用中断的,那么我的S3C44B0怎么样中断流程呢?那我就需要了解整个流程了。要深入了解,最好的方法,就是去写程序 ...
  • 学习ARM开发(18)
    上一次已经了解ARM的中断处理过程,并且可以设置中断函数,那么它这样就可以工作了吗?答案是否定的。因为S3C44B0还有好几个寄存器是控制中 ...
  • 嵌入式系统调试仿真工具
    嵌入式硬件系统设计出来后就要进行调试,不管是硬件调试还是软件调试或者程序固化,都需要用到调试仿真工具。 随着处理器新品种、新 ...
  • 最近困扰在心中的一个小疑问终于解惑了~~
    最近在驱动方面一直在概念上不能很好的理解 有时候结合别人写的一点usb的例子能有点感觉,但是因为arm体系里面没有像单片机那样直接讲解引脚 ...
  • 学习ARM开发(1)
  • 学习ARM开发(2)
  • 学习ARM开发(4)
  • 学习ARM开发(6)
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved