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

这篇具有很好参考价值的文章主要介绍了【STM32】STM32学习笔记-软件SPI读写W25Q64(38)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

00. 目录

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接线图

【STM32】STM32学习笔记-软件SPI读写W25Q64(38),STM32F103,stm32,学习,笔记,江科大,江科大stm32,spi,spi协议

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 A7
	GPIO_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);
	
	//A6
	GPIO_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							0xFF



void 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 A7
	GPIO_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);
	
	//A6
	GPIO_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							0xFF



void 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学习笔记汇总文章来源地址https://www.toymoban.com/news/detail-821316.html

到了这里,关于【STM32】STM32学习笔记-软件SPI读写W25Q64(38)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【STM32】SPI初步使用 读写FLASH W25Q64

    (1) SS( Slave Select):从设备选择信号线,常称为片选信号线,每个从设备都有独立的这一条 NSS 信号线,当主机要选择从设备时,把该从设备的 NSS 信号线设置为低电平,该从设备即被选中,即片选有效,接着主机开始与被选中的从设备进行 SPI通讯。所以 SPI通讯以 NSS 线置低电

    2024年02月10日
    浏览(56)
  • 26、江科大stm32视频学习笔记——I2C读写W25Q64

    一、W25Q64简介 1、W25Q64的内存空间结构:  一页256字节,4K(4096 字节)为一个扇区,16个扇区为1块,容量为8M字节,共有128个块,2048 个扇区。   2、W25Q64每页大小由256字节组成,每页的256字节用一次页编程指令即可完成。 3、擦除指令分别支持: 16页(1个扇区)、128页、256页、全片

    2024年01月25日
    浏览(55)
  • STM32驱动W25Q64读写数据

    1.采用串行Nor flash外扩存储芯片 2.支持SPI接口 3.工作电压:2.7~3.6V 4.容量: 32Mbit(W25Q32) 64Mbit(W25Q64) 128Mbit(W25Q128) 此处使用硬件SPI 引脚 功能 CS(NSS) 片选,低电平有效 SCK 时钟信号引脚 MISO/DO 模块数据输出引脚 MOSI/DI 模块数据输入引脚 W25Q64模块 STM32F103C8T6 VCC 3.3V SPI_CS GPIO

    2023年04月08日
    浏览(52)
  • STM32--SPI通信与W25Q64(2)

    STM32–SPI通信与W25Q64(1) STM32内部集成了硬件SPI收发电路,可以由硬件自动执行时钟生成、数据收发等功能,减轻CPU的负担 。 3线全双工同步传输 8或16位传输帧格式选择 主或从操作 支持多主模式 8个主模式波特率预分频系数(最大为fPCLK/2) 主模式和从模式下均可以由软件或硬

    2024年02月10日
    浏览(48)
  • STM32--SPI通信与W25Q64(1)

    USART串口链接入口 I2C通信链接入口 SPI(Serial Peripheral Interface)是一种高速的、全双工、同步的串行通信协议 。通常用于连接主控芯片和外围设备,比如传感器、存储器、显示屏等。SPI使用简单,只需要几根线就可以实现进行通信。 主要线路: SCLK(时钟信号) :由主设备产

    2024年02月11日
    浏览(70)
  • 【STM32 CubeMX】SPI W25Q64功能实现

    SPI Flash 存储器在嵌入式系统中扮演着重要角色,它可以为微控制器提供额外的存储空间,并且具有快速的读写速度和较大的存储容量。W25Q64 是一款常见的 SPI Flash 存储器,容量为64Mb,采用 SPI 接口进行通信。在 STM32 微控制器上实现对 W25Q64 的功能使用,可以通过 STM32 CubeMX 和

    2024年02月22日
    浏览(73)
  • 【STM32CubeMX学习】SPI读写W25Q16

            SPI分为主从工作模式,通常有一个主设备和一个或多个从设备,本文中MCU为主机,W25Q16为从机。 SPI通信有以下四根线: MISO:主设备数据输入,从设备数据输出。 MOSI:主设备数据输出,从设备数据输入。 SCLK:时钟信号,由主设备产生。 CS:从设备片选信号,由

    2024年02月03日
    浏览(50)
  • 26、江科大stm32视频学习笔记——W25Q64简介

    一、W25Q64简介 1、W25Q64的内存空间结构:  一页256字节,4K(4096 字节)为一个扇区,16个扇区为1块,容量为8M字节,共有128个块,2048 个扇区。   2、W25Q64每页大小由256字节组成,每页的256字节用一次页编程指令即可完成。 3、擦除指令分别支持: 16页(1个扇区)、128页、256页、全片

    2024年01月22日
    浏览(53)
  • 【STM32篇】SPI时序驱动W25Q64(硬件SPI和模拟SPI)

            由于MCU的FLASH空间有限,在特殊使用场所中会存在FLASH存储不够使用的情况。例如上篇中驱动LCD屏,需要将一个中文字库保存到MCU的FLASH中是不太现实的(STM32F103ZET6内部FLASH大小512KB),为此可使用外部FLASH作为拓展。         W25Q64(64Mbit)是为系统提供一个最小的空

    2024年02月08日
    浏览(51)
  • STM32使用QUADSPI读写外部Nor Flash(以W25Q64为例)

    QUADSPI 是一种专用的通信接口,连接单、双或四(条数据线) SPI Flash 存储介质。该接 口可以在以下三种模式下工作: ①间接模式:使用 QUADSPI 寄存器执行全部操作。 ②状态轮询模式:周期性读取外部 Flash 状态寄存器,而且标志位置 1 时会产生中断(如擦除或烧写完成,会

    2024年02月11日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包