【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

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

10. 文件的读写

10.1 文本文件 操作文件三大类: ofstream:写操作ifstream:读操作fstream:读写操作 打开方式解释ios::in为了读文件而打开文件ios::out为了写文件而打开文件,如果当前文件存在则清空当前文件在写入ios::app追加方式写文件ios::trunc如果文件存在先删除,在创建ios::ate打开文件之后令读写位置移至文件尾端ios::binary二进制方式

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

软件设计师备考——计算机系统

学习内容源自「软件设计师」 上午题 #1 计算机系统_哔哩哔哩_bilibili 目录 1.1.1 计算机系统硬件基本组成 1.1.2 中央处理单元 1.CPU 的功能 1)运算器 2)控制器 RISC && CISC 流水线控制 存储器  Cache 中断 输入输出IO控制方式 程序查询方式 中断驱动方式 直接存储器方式(DMA)  ​编辑 总线 ​编辑

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识