本文主要是介绍【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)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!