【STM32】STM32学习笔记-软件SPI读写W25Q64(38)

2024-01-25 03:36

本文主要是介绍【STM32】STM32学习笔记-软件SPI读写W25Q64(38),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

00. 目录

文章目录

    • 00. 目录
    • 01. SPI简介
    • 02. W25Q64简介
    • 03. 软件SPI读写W25Q64接线图
    • 04. 软件SPI读取设备ID示例
    • 05. 软件SPI读写W25Q64Flash示例
    • 06. 示例下载
    • 07. 附录

01. SPI简介

在大容量产品和互联型产品上,SPI接口可以配置为支持SPI协议或者支持I 2 S音频协议。SPI接口默认工作在SPI方式,可以通过软件把功能从SPI模式切换到I2S模式。

在小容量和中容量产品上,不支持I 2 S音频协议。

串行外设接口(SPI)允许芯片与外部设备以半/全双工、同步、串行方式通信。此接口可以被配置成主模式,并为外部从设备提供通信时钟(SCK)。接口还能以多主配置方式工作。

它可用于多种用途,包括使用一条双向数据线的双线单工同步传输,还可使用CRC校验的可靠通信。

I2S也是一种3引脚的同步串行接口通讯协议。它支持四种音频标准,包括飞利浦I 2 S标准,MSB和LSB对齐标准,以及PCM标准。它在半双工通讯中,可以工作在主和从2种模式下。当它作为主设备时,通过接口向外部的从设备提供时钟信号。

02. W25Q64简介

•W25Qxx系列是一种低成本、小型化、使用简单的非易失性存储器,常应用于数据存储、字库存储、固件程序存储等场景

•存储介质:Nor Flash(闪存)

•时钟频率:80MHz / 160MHz (Dual SPI) / 320MHz (Quad SPI)

•存储容量(24位地址)

03. 软件SPI读写W25Q64接线图

在这里插入图片描述

CS: PA4

CLK: PA5

DO: PA6

DI: PA7

04. 软件SPI读取设备ID示例

spi.h

#ifndef __SPI_H__
#define __SPI_H__#include "stm32f10x.h"  void spi_init(void);void spi_start(void);void spi_stop(void);uint8_t spi_swap_byte(uint8_t val);#endif /*__SPI_H__*/

spi.c

#include "spi.h"/*
CS: PA4
CLK: PA5
DO: PA6
DI: PA7
*///SS写  PA4
void spi_W_SS(uint8_t bitval)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)bitval);
}//CLK写 PA5
void spi_W_SCK(uint8_t bitval)
{GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)bitval);
}//DI写 MOSI PA7
void spi_W_MOSI(uint8_t bitval)
{GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)bitval);
}//DO读   MISO PA6
uint8_t spi_R_MISO(void)
{return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}void spi_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;//使能时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//A4 A5 A7GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);//A6GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);	spi_W_SS(1);spi_W_SCK(0);
}void spi_start(void)
{spi_W_SS(0);
}void spi_stop(void)
{spi_W_SS(1);
}uint8_t spi_swap_byte(uint8_t val)
{uint8_t i = 0;uint8_t value = 0;//模式0 第一个边沿移入数据 第二个边沿移出数据for (i = 0; i < 8; i++){spi_W_MOSI(val & (0x80 >> i));spi_W_SCK(1);if (spi_R_MISO() == 1){value |= 0x80 >> i;}spi_W_SCK(0);}return value;
}

w25q64.h

#ifndef __W25Q64_H__#define __W25Q64_H__#include "stm32f10x.h"  #define W25Q64_WRITE_ENABLE							0x06
#define W25Q64_WRITE_DISABLE						0x04
#define W25Q64_READ_STATUS_REGISTER_1				0x05
#define W25Q64_READ_STATUS_REGISTER_2				0x35
#define W25Q64_WRITE_STATUS_REGISTER				0x01
#define W25Q64_PAGE_PROGRAM							0x02
#define W25Q64_QUAD_PAGE_PROGRAM					0x32
#define W25Q64_BLOCK_ERASE_64KB						0xD8
#define W25Q64_BLOCK_ERASE_32KB						0x52
#define W25Q64_SECTOR_ERASE_4KB						0x20
#define W25Q64_CHIP_ERASE							0xC7
#define W25Q64_ERASE_SUSPEND						0x75
#define W25Q64_ERASE_RESUME							0x7A
#define W25Q64_POWER_DOWN							0xB9
#define W25Q64_HIGH_PERFORMANCE_MODE				0xA3
#define W25Q64_CONTINUOUS_READ_MODE_RESET			0xFF
#define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID		0xAB
#define W25Q64_MANUFACTURER_DEVICE_ID				0x90
#define W25Q64_READ_UNIQUE_ID						0x4B
#define W25Q64_JEDEC_ID								0x9F
#define W25Q64_READ_DATA							0x03
#define W25Q64_FAST_READ							0x0B
#define W25Q64_FAST_READ_DUAL_OUTPUT				0x3B
#define W25Q64_FAST_READ_DUAL_IO					0xBB
#define W25Q64_FAST_READ_QUAD_OUTPUT				0x6B
#define W25Q64_FAST_READ_QUAD_IO					0xEB
#define W25Q64_OCTAL_WORD_READ_QUAD_IO				0xE3#define W25Q64_DUMMY_BYTE							0xFFvoid W25Q64_init(void);void W25Q64_read_id(uint8_t *mid, uint16_t *did);#endif /*__W25Q64_H__*/

w25q64.c

#include "w25q64.h"
#include "spi.h"void W25Q64_init(void)
{spi_init();
}void W25Q64_read_id(uint8_t *mid, uint16_t *did)
{spi_start();spi_swap_byte(W25Q64_JEDEC_ID);*mid = spi_swap_byte(W25Q64_DUMMY_BYTE);*did = spi_swap_byte(W25Q64_DUMMY_BYTE);*did <<= 8;*did |= spi_swap_byte(W25Q64_DUMMY_BYTE);spi_stop();
}

main.c

#include "stm32f10x.h"#include "delay.h"
#include "oled.h"
#include "w25q64.h"int main(void){	uint8_t mid;uint16_t did;//初始化OLED_Init();W25Q64_init();//显示一个字符//OLED_ShowChar(1, 1, 'A');//显示字符串//OLED_ShowString(1, 3, "SPI Test");OLED_ShowString(1, 1, "MID:   DID:");OLED_ShowString(2, 1, "W:");OLED_ShowString(3, 1, "R:");W25Q64_read_id(&mid, &did);OLED_ShowHexNum(1, 5, mid, 2);OLED_ShowHexNum(1, 12, did, 4);while(1){}return 0;}

05. 软件SPI读写W25Q64Flash示例

spi.h

#ifndef __SPI_H__
#define __SPI_H__#include "stm32f10x.h"  void spi_init(void);void spi_start(void);void spi_stop(void);uint8_t spi_swap_byte(uint8_t val);#endif /*__SPI_H__*/

spi.c

#include "spi.h"/*
CS: PA4
CLK: PA5
DO: PA6
DI: PA7
*///SS写  PA4
void spi_W_SS(uint8_t bitval)
{GPIO_WriteBit(GPIOA, GPIO_Pin_4, (BitAction)bitval);
}//CLK写 PA5
void spi_W_SCK(uint8_t bitval)
{GPIO_WriteBit(GPIOA, GPIO_Pin_5, (BitAction)bitval);
}//DI写 MOSI PA7
void spi_W_MOSI(uint8_t bitval)
{GPIO_WriteBit(GPIOA, GPIO_Pin_7, (BitAction)bitval);
}//DO读   MISO PA6
uint8_t spi_R_MISO(void)
{return GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6);
}void spi_init(void)
{GPIO_InitTypeDef GPIO_InitStruct;//使能时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//A4 A5 A7GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);//A6GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6;GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStruct);	spi_W_SS(1);spi_W_SCK(0);
}void spi_start(void)
{spi_W_SS(0);
}void spi_stop(void)
{spi_W_SS(1);
}uint8_t spi_swap_byte(uint8_t val)
{uint8_t i = 0;uint8_t value = 0;//模式0 第一个边沿移入数据 第二个边沿移出数据for (i = 0; i < 8; i++){spi_W_MOSI(val & (0x80 >> i));spi_W_SCK(1);if (spi_R_MISO() == 1){value |= 0x80 >> i;}spi_W_SCK(0);}return value;
}

w25q64.h

#ifndef __W25Q64_H__#define __W25Q64_H__#include "stm32f10x.h"  #define W25Q64_WRITE_ENABLE							0x06
#define W25Q64_WRITE_DISABLE						0x04
#define W25Q64_READ_STATUS_REGISTER_1				0x05
#define W25Q64_READ_STATUS_REGISTER_2				0x35
#define W25Q64_WRITE_STATUS_REGISTER				0x01
#define W25Q64_PAGE_PROGRAM							0x02
#define W25Q64_QUAD_PAGE_PROGRAM					0x32
#define W25Q64_BLOCK_ERASE_64KB						0xD8
#define W25Q64_BLOCK_ERASE_32KB						0x52
#define W25Q64_SECTOR_ERASE_4KB						0x20
#define W25Q64_CHIP_ERASE							0xC7
#define W25Q64_ERASE_SUSPEND						0x75
#define W25Q64_ERASE_RESUME							0x7A
#define W25Q64_POWER_DOWN							0xB9
#define W25Q64_HIGH_PERFORMANCE_MODE				0xA3
#define W25Q64_CONTINUOUS_READ_MODE_RESET			0xFF
#define W25Q64_RELEASE_POWER_DOWN_HPM_DEVICE_ID		0xAB
#define W25Q64_MANUFACTURER_DEVICE_ID				0x90
#define W25Q64_READ_UNIQUE_ID						0x4B
#define W25Q64_JEDEC_ID								0x9F
#define W25Q64_READ_DATA							0x03
#define W25Q64_FAST_READ							0x0B
#define W25Q64_FAST_READ_DUAL_OUTPUT				0x3B
#define W25Q64_FAST_READ_DUAL_IO					0xBB
#define W25Q64_FAST_READ_QUAD_OUTPUT				0x6B
#define W25Q64_FAST_READ_QUAD_IO					0xEB
#define W25Q64_OCTAL_WORD_READ_QUAD_IO				0xE3#define W25Q64_DUMMY_BYTE							0xFFvoid W25Q64_init(void);void W25Q64_read_id(uint8_t *mid, uint16_t *did);//写使能
void W25Q64_write_enable(void);//等待 直到空闲
void W25Q64_wait_busy(void);void W25Q64_sector_erase(uint32_t addr);void W25Q64_page_program(uint32_t addr, uint8_t *arr, uint16_t len);void W25Q64_read_data(uint32_t addr, uint8_t *arr, uint16_t len);#endif /*__W25Q64_H__*/

w25q64.c

#include "w25q64.h"
#include "spi.h"void W25Q64_init(void)
{spi_init();
}void W25Q64_read_id(uint8_t *mid, uint16_t *did)
{spi_start();spi_swap_byte(W25Q64_JEDEC_ID);*mid = spi_swap_byte(W25Q64_DUMMY_BYTE);*did = spi_swap_byte(W25Q64_DUMMY_BYTE);*did <<= 8;*did |= spi_swap_byte(W25Q64_DUMMY_BYTE);spi_stop();
}void W25Q64_write_enable(void)
{spi_start();spi_swap_byte(W25Q64_WRITE_ENABLE);spi_stop();
}void W25Q64_wait_busy(void)
{uint32_t timeout;spi_start();spi_swap_byte(W25Q64_READ_STATUS_REGISTER_1);	timeout = 100000;while((spi_swap_byte(W25Q64_DUMMY_BYTE) & 0x1) == 0x01){timeout--;if (0 == timeout){break;}}spi_stop();
}void W25Q64_page_program(uint32_t addr, uint8_t *arr, uint16_t len)
{uint8_t i;W25Q64_write_enable();spi_start();spi_swap_byte(W25Q64_PAGE_PROGRAM);	spi_swap_byte(addr >> 16);spi_swap_byte(addr >> 8);spi_swap_byte(addr);	for (i = 0; i < len; i++){spi_swap_byte(arr[i]);}spi_stop();W25Q64_wait_busy();
}void W25Q64_sector_erase(uint32_t addr)
{W25Q64_write_enable();spi_start();spi_swap_byte(W25Q64_SECTOR_ERASE_4KB);	spi_swap_byte(addr >> 16);spi_swap_byte(addr >> 8);spi_swap_byte(addr);spi_stop();W25Q64_wait_busy();}void W25Q64_read_data(uint32_t addr, uint8_t *arr, uint16_t len)
{uint8_t i = 0;spi_start();spi_swap_byte(W25Q64_READ_DATA);	spi_swap_byte(addr >> 16);spi_swap_byte(addr >> 8);spi_swap_byte(addr);for (i = 0; i < len; i++){arr[i] = spi_swap_byte(W25Q64_DUMMY_BYTE);}spi_stop();
}

main.c

#include "stm32f10x.h"#include "delay.h"
#include "oled.h"
#include "w25q64.h"int main(void){	uint8_t mid;uint16_t did;uint8_t array_w[4] = {0x11, 0x22, 0x33, 0x44};uint8_t array_r[4];//初始化OLED_Init();W25Q64_init();//显示一个字符//OLED_ShowChar(1, 1, 'A');//显示字符串//OLED_ShowString(1, 3, "SPI Test");OLED_ShowString(1, 1, "MID:   DID:");OLED_ShowString(2, 1, "W:");OLED_ShowString(3, 1, "R:");W25Q64_read_id(&mid, &did);OLED_ShowHexNum(1, 5, mid, 2);OLED_ShowHexNum(1, 12, did, 4);//擦除扇区W25Q64_sector_erase(0x0);//写扇区W25Q64_page_program(0x0, array_w, 4);//读数据W25Q64_read_data(0x0, array_r, 4);OLED_ShowHexNum(2, 3, array_w[0], 2);OLED_ShowHexNum(2, 6, array_w[1], 2);OLED_ShowHexNum(2, 9, array_w[2], 2);OLED_ShowHexNum(2, 12, array_w[3], 2);	 OLED_ShowHexNum(3, 3, array_r[0], 2);OLED_ShowHexNum(3, 6, array_r[1], 2);OLED_ShowHexNum(3, 9, array_r[2], 2);OLED_ShowHexNum(3, 12, array_r[3], 2);			 while(1){}return 0;}

06. 示例下载

30-软件SPI.rar

07. 附录

参考: 【STM32】江科大STM32学习笔记汇总

这篇关于【STM32】STM32学习笔记-软件SPI读写W25Q64(38)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/641966

相关文章

一文彻底搞懂Java 中的 SPI 是什么

《一文彻底搞懂Java中的SPI是什么》:本文主要介绍Java中的SPI是什么,本篇文章将通过经典题目、实战解析和面试官视角,帮助你从容应对“SPI”相关问题,赢得技术面试的加分项,需要的朋... 目录一、面试主题概述二、高频面试题汇总三、重点题目详解✅ 面试题1:Java 的 SPI 是什么?如何实现一个

如何确定哪些软件是Mac系统自带的? Mac系统内置应用查看技巧

《如何确定哪些软件是Mac系统自带的?Mac系统内置应用查看技巧》如何确定哪些软件是Mac系统自带的?mac系统中有很多自带的应用,想要看看哪些是系统自带,该怎么查看呢?下面我们就来看看Mac系统内... 在MAC电脑上,可以使用以下方法来确定哪些软件是系统自带的:1.应用程序文件夹打开应用程序文件夹

ShardingSphere之读写分离方式

《ShardingSphere之读写分离方式》:本文主要介绍ShardingSphere之读写分离方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录ShardingSphere-读写分离读写分离mysql主从集群创建 user 表主节点执行见表语句项目代码读写分

Dubbo之SPI机制的实现原理和优势分析

《Dubbo之SPI机制的实现原理和优势分析》:本文主要介绍Dubbo之SPI机制的实现原理和优势,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Dubbo中SPI机制的实现原理和优势JDK 中的 SPI 机制解析Dubbo 中的 SPI 机制解析总结Dubbo中

重新对Java的类加载器的学习方式

《重新对Java的类加载器的学习方式》:本文主要介绍重新对Java的类加载器的学习方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍1.1、简介1.2、符号引用和直接引用1、符号引用2、直接引用3、符号转直接的过程2、加载流程3、类加载的分类3.1、显示

Java学习手册之Filter和Listener使用方法

《Java学习手册之Filter和Listener使用方法》:本文主要介绍Java学习手册之Filter和Listener使用方法的相关资料,Filter是一种拦截器,可以在请求到达Servl... 目录一、Filter(过滤器)1. Filter 的工作原理2. Filter 的配置与使用二、Listen

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

SpringBoot实现数据库读写分离的3种方法小结

《SpringBoot实现数据库读写分离的3种方法小结》为了提高系统的读写性能和可用性,读写分离是一种经典的数据库架构模式,在SpringBoot应用中,有多种方式可以实现数据库读写分离,本文将介绍三... 目录一、数据库读写分离概述二、方案一:基于AbstractRoutingDataSource实现动态

Redis中高并发读写性能的深度解析与优化

《Redis中高并发读写性能的深度解析与优化》Redis作为一款高性能的内存数据库,广泛应用于缓存、消息队列、实时统计等场景,本文将深入探讨Redis的读写并发能力,感兴趣的小伙伴可以了解下... 目录引言一、Redis 并发能力概述1.1 Redis 的读写性能1.2 影响 Redis 并发能力的因素二、

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx