直接上代码:


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文件系统简介

推荐阅读

Micro LED是新一代显示技术,比现有的OLED技术亮度更高、发光效率更好、但功耗更低。2017年5月,苹果已经开始新一代显示技术的开发。2018年2月,三星在CES 2018上推出了Micro LED电视。如今,MicroLED显示器已被视为显示器明日之星,近年有许多厂商投入开发,就在技术瓶颈逐渐克服之际,产业研究机构Yole Développement表示,2019年MicroLED将走上量...
通过几天的AVR单片机学习,用AVR系列单片机中的ATMEGA16,LCD液晶屏LC1602,温度采集模块DS18B20,时钟模块DS1302,5V升压IC,和三个按键,以及一些电子元件完成了数字时钟系统的设计。在一块液晶显示屏上实现动态,时、分、秒、年、月、日、星期、温度数据的显示, 通过三个按键,S1调时键、S2时间加键、S3时间减键、实现时钟的年、月、日、星期、时、分、...
Android 11正式版于9月8日正式上线,虽然一个多月时间过去了,但是Android 11上的Bug仍然困扰着游戏玩家。在Android 11上部分游戏横屏时无法全屏显示,导航栏和状态栏遮挡了游戏界面(如下图所示),导致游戏界面的部分选项无法点击。外媒称这一问题早在Android 11 Beta版阶段用户就已向谷歌报告,但是谷歌似乎并没有彻底解决。无独有偶,去年在Pixel...
10月25日,杭州凯尔达焊接机器人股份有限公司(下称“凯尔达”)登陆科创板,自2009年创立,到2021年走向资本市场,凯尔达用了13年。据了解,凯尔达此次目标为募资9.24亿元,资金投入项目主要用于三方面,包括智能焊接机器人生产线建设项目、装配检测实验大楼建设项目、补充流动资金等。凯尔达方面表示,公司以“以焊接应用为切入口,发展多领域工业机器人...

史海拾趣

问答坊 | AI 解惑

GPS系统在车辆领域中的应用

GPS系统在出租车行业的应用   GPS系统在出租车行业的应用主要体现在灵活的出租车调度系统中,用户只需要拨打调度中心电话,中心将自动寻找最近的空车,在电话还没挂断之前,便可以告诉乘客“车牌号为XXX的车将在X分钟之内到达。”这种"叫车服 ...…

查看全部问答∨

AD9851中文资料

本帖最后由 paulhyde 于 2014-9-15 09:27 编辑 AD9851中文资料  …

查看全部问答∨

无铅工艺分析

无铅工艺分析好东西与大家分享! 《无铅工艺分析》 图文介绍: 1.锡膏印刷工艺 2.回流焊接工艺 3.波峰焊接工艺 4.手工焊接工艺 …

查看全部问答∨

汇编高手,ldr伪指令的奇怪问题,谁能解决

在调程序的时候老是出错,然后单步跟发现问题出在ldr伪指令上,于是专门写了个汇编文件在arm上跑了一下,发现一个奇怪的现象 开发环境ADS1.2 整个工程就这一个2410.s文件,全部代码如下: Usr_Size EQU 5         AREA  ...…

查看全部问答∨

VxWorks中任务迁移

当一个任务执行过程中出现问题,我想把这个任务的信息Copy到另一个任务中,然启动这个任务,让这个任务开始执行。这里涉及到任务的迁移问题,我知道每个任务的状态信息位于WIND_TCB当中,但是不知道需要保存那些信息的,有没有人做过这个,给些指点 ...…

查看全部问答∨

自定义链表报Access Violation错

自定义链表是这样的 typedef struct ListNode {     char data[20];     ListNode * next; }; 在初始化的时候报Access Violation错,不知从哪更改.有知道的指点一下吧. ListNode *h h = new ListNode; …

查看全部问答∨

看家的宝贝-100个经典C语言程序资料

看家的宝贝-100个经典C语言程序资料…

查看全部问答∨

SerialApp例程透传失败,求指点正常实验现象

小弟初学ZIGBEE,用的是CROSSO STUDIO的实验板,在刷SerialApp例程做PC串口透传时失败,请做过该例程的高手前辈指点迷津,现象如下: 1.显示屏无显示,(不知是否正常,文件中包含了OLED和LCD的初始化文件了) 2.COOD和router都是红色LED3灯常亮 ...…

查看全部问答∨

晒WEBENCH设计的过程+2阶低通滤波器

还没试试WEBENCH在滤波器方面的设计性能咋样呢,今天就试试低通滤波器的效果咋样。这一次要得到一个低通滤波器,截止频率300Hz,   阻带频率800Hz。 设计需求如下: 于是,生成的方案如下: 得到的原理图如下,是一个2阶低通滤波 ...…

查看全部问答∨
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

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