HC32F460 QSPI底层驱动(W25Q128)
//QSPI========================================================================================================
#define QSPI_BASE (0x9c000000UL) //寄存器基址
typedef struct
{
vu32 CR; //控制寄存器
vu32 CSCR; //片选控制寄存器
vu32 FCR; //格式控制寄存器
vu32 SR; //状态寄存器
vu32 DCOM; //直接通信指令寄存器
vu32 CCMD; //指令代码寄存器
vu32 XCMD; //XIP模式代码寄存器
u32 Reserved1;
vu32 SR2; //标志清除寄存器(只写 0x0024h
u32 Reserved2;
vu32 EXAR;
}QSPI_TypeDef;
#define QSPI ((QSPI_TypeDef *) QSPI_BASE)
/*************************************************************************************************************
* 文件名 : hc32f46x_qspi.c
* 功能 : HC32F46X QSPI驱动
* 作者 : cp1300@139.com
* 创建时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 详细 : 使用直接模式进行访问,关闭XIP模式;
*************************************************************************************************************/
#include "hc32f46x.h"
#include "hc32f46x_map.h"
#include "system.h"
#include "hc32f46x_qspi.h"
void QSPI_SPI_WriteByte(u8 data) {QSPI->DCOM = data;} //QSPI直通模式下扩展SPI模式发送一字节数据
u8 QSPI_SPI_ReadByte(void) {return QSPI->DCOM;} //QSPI直通模式下扩展SPI模式读取一字节数据
void QSPI_EnterDirectMode(void) {QSPI->CR |= BIT5;} //进入直接模式-准备开始执行命令
void QSPI_ExitDirectMode(void){QSPI->CR &= ~BIT5;} //退出直接模式-一条命令执行结束,拉高CS
/*************************************************************************************************************************
* 函数 : void QSPI_Init(QSPI_ADDR_WIDTH AddrWidth, u8 ClockDiv, u8 DummyCnt)
* 功能 : QSPI初始化
* 参数 : AddrWidth:地址宽度;ClockDiv:HCLK时钟分频(2-64分频);DummyCnt:虚拟周期数量
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 : 默认初始化后为标准读取-1位,扩展SPI模式,ROM映射模式
*************************************************************************************************************************/
void QSPI_Init(QSPI_ADDR_WIDTH AddrWidth, u8 ClockDiv, u8 DummyCnt)
{
SYS_DeviceClockEnable(DEV_QSPI, TRUE); //使能时钟
QSPI->CR = 0;
QSPI->CSCR = 0;
QSPI->CSCR |= 2<<4;//将 QSSN有效时间延长 128个 QSCK周期
QSPI->CSCR |= 1<<0;//SSN信号最小无效时间选择 2个QSCLK周期
QSPI->FCR = 0;
QSPI->FCR |= 1<<6;//WP高电平
QSPI->FCR |= 1<<5;//比 QSCK第一个上升沿提前 1.5个 QSCK输出 QSSN
QSPI->FCR |= 1<<4;//比 QSCK最后一个上升沿滞后 1.5个 QSCK释放 QSSN
QSPI_SetClockDiv(ClockDiv); //设置时钟分频
QSPI_SetAddrWidth(AddrWidth); //QSPI设置地址线宽度
QSPI_SetDummyCnt(DummyCnt); //QSPI设置虚拟周期数量(只对快速指令ROM映射模式下有效)
QSPI->SR2 |= BIT7; //清除RAER位
}
/*************************************************************************************************************************
* 函数 : void QSPI_SetClockDiv(u8 ClockDiv)
* 功能 : QSPI时钟分频设置
* 参数 : ClockDiv:HCLK时钟分频(2-64分频)
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 :
*************************************************************************************************************************/
void QSPI_SetClockDiv(u8 ClockDiv)
{
u32 temp;
if(ClockDiv < 2) ClockDiv = 2;
if(ClockDiv > 64) ClockDiv = 64;
if(ClockDiv % 2) //奇数分频,设置占空比修正
{
QSPI->FCR |= BIT15;
}
else
{
QSPI->FCR &= ~BIT15;
}
temp = QSPI->CR;
temp &= ~(0x3F<<16); //清除之前配置
temp |= (u32)(ClockDiv-1) << 16;
QSPI->CR = temp;
}
/*************************************************************************************************************************
* 函数 : void QSPI_SetMode(QSPI_MODE_SELECT mode)
* 功能 : QSPI工作模式设置
* 参数 : mode工作模式
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 : QSPI_STAND_READ = 0, //标准读取-1位
QSPI_FAST_READ = 1, //快速读取-1位
QSPI_2WIRE_FAST_READ = 2, //二线式输出快速读-只有数据是2位
QSPI_2WIRE_IO_FAST_READ = 3, //二线式输入输出快速读-地址与数据都是2位
QSPI_4WIRE_FAST_READ = 4, //四线式输出快速读-只有数据是4位,地址还是1位
QSPI_4WIRE_IO_FAST_READ = 5, //四线式输入输出快速读-就是使用4位的数据与地址线
由于常用的W25Q系列只支持1-4-4 也就是命令阶段只支持1线模式,因此无论哪种模式下,命令均为1线模式,也就是命令
发送阶段均固定为扩展SPI模式
*************************************************************************************************************************/
void QSPI_SetMode(QSPI_MODE_SELECT mode)
{
u32 temp = QSPI->CR;
temp &= ~(0X3F<<8); //清除SPI协议设置,全部变为默认的扩展SPI协议,也就是1线
temp &= ~0x07; //清除掉工作模式,设置为标准模式
switch(mode)
{
case QSPI_STAND_READ: //标准读取-1位1-1-1
{
}break;
case QSPI_FAST_READ : //快速读取-1位 1-1-1
{
temp |= QSPI_FAST_READ;
}break;
case QSPI_2WIRE_FAST_READ: //二线式输出快速读-只有数据是2位 1-1-2
{
temp |= QSPI_2WIRE_FAST_READ;
temp |= QSPI_PROTO_2_WIRE << 12; //设置数据阶段SPI协议
}break;
case QSPI_2WIRE_IO_FAST_READ://二线式输入输出快速读-地址与数据都是2位1-2-2
{
temp |= QSPI_2WIRE_IO_FAST_READ;
temp |= QSPI_PROTO_2_WIRE << 12; //设置数据阶段SPI协议
temp |= QSPI_PROTO_2_WIRE << 10; //设置地址阶段SPI协议
}break;
case QSPI_4WIRE_FAST_READ: //四线式输出快速读-只有数据是4位,地址还是1位1-1-4
{
temp |= QSPI_4WIRE_FAST_READ;
temp |= QSPI_PROTO_4_WIRE << 12; //设置数据阶段SPI协议
}break;
case QSPI_4WIRE_IO_FAST_READ://四线式输入输出快速读-就是使用4位的数据与地址线 1-4-4
{
temp |= QSPI_4WIRE_IO_FAST_READ;
temp |= QSPI_PROTO_4_WIRE << 12; //设置数据阶段SPI协议
temp |= QSPI_PROTO_4_WIRE << 10; //设置地址阶段SPI协议
}break;
default: //使用默认的1-1-1
{
}break;
}
QSPI->CR = temp;
}
/*************************************************************************************************************************
* 函数 : void QSPI_SetAddrWidth(QSPI_ADDR_WIDTH width)
* 功能 : QSPI设置地址线宽度
* 参数 : width:地址线宽度,见 QSPI_ADDR_WIDTH
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 : QSPI_ADDR_WIDTH:
QSPI_ADDR_8BIT = 0,
QSPI_ADDR_16BIT = 1,
QSPI_ADDR_24BIT = 2,
QSPI_ADDR_32BIT = 3,
*************************************************************************************************************************/
void QSPI_SetAddrWidth(QSPI_ADDR_WIDTH width)
{
u32 temp;
temp = QSPI->FCR;
temp &= ~(0x07<<0); //清除之前配置
temp |= width;
if(width == QSPI_ADDR_32BIT)
{
temp |= BIT2; //使能4字节地址读指令代码
}
QSPI->FCR = temp;
}
/*************************************************************************************************************************
* 函数 : void QSPI_SetDummyCnt(u8 cnt)
* 功能 : QSPI设置虚拟周期数量(只对快速指令ROM映射模式下有效)
* 参数 : cnt:虚拟周期数量3-18个
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 :
*************************************************************************************************************************/
void QSPI_SetDummyCnt(u8 cnt)
{
u32 temp;
if(cnt < 3) cnt = 3;
if(cnt > 18) cnt = 18;
temp = QSPI->FCR;
temp &= ~(0x0f<<8); //清除之前配置
temp |= (u32)(cnt-3) << 8;
QSPI->FCR = temp;
}
/*************************************************************************************************************************
* 函数 : void QSPI_EnterRomMode(bool isEnable)
* 功能 : QSPI设置是否使能ROM访问模式
* 参数 : isEnable:TRUE:使能ROM访问模式;FALSE:退出ROM访问模式
* 返回 : 无
* 依赖 : 底层读写函数
* 作者 : cp1300@139.com
* 时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 说明 : 使能ROM访问模式后,将开启预读取功能
直通模式下,必须退出ROM模式才能完成一次命令发送,只有进入ROM模式才能出发NSS变为高电平
*************************************************************************************************************************/
void QSPI_EnterRomMode(bool isEnable)
{
if(isEnable) //使能
{
QSPI->CR &= ~BIT5; //使能ROM访问模式
QSPI->CR |= BIT3; //使能预读取功能
}
else
{
QSPI->CR |= BIT5; //关闭ROM访问模式
QSPI->CR &= ~BIT3; //关闭预读取功能
}
}
/*************************************************************************************************************
* 文件名 : hc32f46x_qspi.h
* 功能 : HC32F46X QSPI驱动
* 作者 : cp1300@139.com
* 创建时间 : 2021-08-25
* 最后修改时间 : 2021-08-25
* 详细 :
*************************************************************************************************************/
#ifndef _HC32F46X_QSPI_H_
#define _HC32F46X_QSPI_H_
#include "hc32f46x_system.h"
//SPI协议选择
typedef enum
{
QSPI_PROTO_EXPAND = 0, //扩展SPI协议
QSPI_PROTO_2_WIRE = 1, //二线式 SPI协议
QSPI_PROTO_4_WIRE = 1, //四线式 SPI协议
}QSPI_PROTO_SELECT;
//SPI接口读取模式选择
typedef enum
{
QSPI_STAND_READ = 0, //标准读取-1位 1-1-1
QSPI_FAST_READ = 1, //快速读取-1位 1-1-1
QSPI_2WIRE_FAST_READ = 2, //二线式输出快速读-只有数据是2位 1-1-2
QSPI_2WIRE_IO_FAST_READ = 3, //二线式输入输出快速读-地址与数据都是2位 1-2-2
QSPI_4WIRE_FAST_READ = 4, //四线式输出快速读-只有数据是4位,地址还是1位 1-1-4
QSPI_4WIRE_IO_FAST_READ = 5, //四线式输入输出快速读-就是使用4位的数据与地址线 1-4-4
//QSPI_CUSTOM_STAND_READ = 6, //自定义标准读取
//QSPI_CUSTOM_FAST_READ = 7, //自定义快速读取
}QSPI_MODE_SELECT;
//地址长度定义
typedef enum
{
QSPI_ADDR_8BIT = 0,
QSPI_ADDR_16BIT = 1,
QSPI_ADDR_24BIT = 2,
QSPI_ADDR_32BIT = 3,
}QSPI_ADDR_WIDTH;
void QSPI_Init(QSPI_ADDR_WIDTH AddrWidth, u8 ClockDiv, u8 DummyCnt);//QSPI初始化
void QSPI_SetClockDiv(u8 ClockDiv); //QSPI时钟分频设置
void QSPI_SetMode(QSPI_MODE_SELECT mode); //QSPI工作模式设置
void QSPI_SetDummyCnt(u8 cnt); //QSPI设置虚拟周期数量(只对快速指令ROM映射模式下有效)
void QSPI_EnterRomMode(bool isEnable); //QSPI设置是否使能ROM访问模式
void QSPI_SetAddrWidth(QSPI_ADDR_WIDTH width); //QSPI设置地址线宽度
void QSPI_SPI_WriteByte(u8 data); //QSPI直通模式下扩展SPI模式发送一字节数据
u8 QSPI_SPI_ReadByte(void); //QSPI直通模式下扩展SPI模式读取一字节数据
void QSPI_EnterDirectMode(void); //进入直接模式-准备开始执行命令
void QSPI_ExitDirectMode(void); //退出直接模式-一条命令执行结束,拉高CS
#endif //_HC32F46X_QSPI_H_
进行测试 W25Q128JV 支持4线操作
/*************************************************************************************************************
* 文件名: QSPI_test.c
* 功能: QSPI测试
* 作者: cp1300@139.com
* 创建时间: 2021-08-25
* 最后修改时间: 2021-08-25
* 详细: FLASH要用W25Q128JV系列
*************************************************************************************************************/
#include "system.h"
#include "hc32f46x_system.h"
#include "test.h"
#include "hc32f46x_qspi.h"
#include "W25QxxJV.h"
W25QxxJV_HANDLE mW25QxxJV_Handle;
u8 buff;
//QSPI测试
void QSPI_test(void)
{
W25QxxJV_ID id;
u16 i;
u8 *p = (u8 *)0x98000000; //QSPI地址映射
QSPI_Init(QSPI_ADDR_24BIT, 8, 6);//QSPI初始化
//初始化QSPI IO接口
//CS:PB1CLK:PB14D0:PB13 D1:PB12 D2:PB10 D3:PB2
SYS_GPIOx_SetAF(GPIOB, 1, 7);
SYS_GPIOx_SetAF(GPIOB, 14, 7);
SYS_GPIOx_SetAF(GPIOB, 13, 7);
SYS_GPIOx_SetAF(GPIOB, 12, 7);
SYS_GPIOx_SetAF(GPIOB, 10, 7);
SYS_GPIOx_SetAF(GPIOB, 2, 7);
QSPI_SetMode(QSPI_STAND_READ); //QSPI工作模式设置
QSPI_EnterRomMode(FALSE); //QSPI设置是否使能ROM访问模式-退出ROM模式
while(1)
{
id = W25QxxJV_Init(&mW25QxxJV_Handle,
QSPI_SPI_ReadByte, QSPI_SPI_WriteByte,
QSPI_EnterDirectMode, QSPI_ExitDirectMode,
SYS_DelayMS);
if(id != FLASH_NULL) break;
SYS_DelayMS(1000);
}
//写入flash
for(i = 0;i < 256;i ++)
{
buff = i;
}
uart_printf("开始写入W25QxxJv测试...\r\n");
if(W25QxxJV_Write(&mW25QxxJV_Handle, buff, 0, 256) == TRUE)//写SPI FLASH 在指定地址开始写入指定长度的数据
{
uart_printf("写入W25QxxJv成功\r\n");
}
else
{
uart_printf("写入W25QxxJv失败\r\n");
}
QSPI_SetMode(QSPI_4WIRE_IO_FAST_READ); //QSPI工作模式设置
QSPI_EnterRomMode(TRUE); //QSPI设置是否使能ROM访问模式-使能ROM模式
uart_printf("开始读取W25QxxJv测试...\r\n");
for(i = 0;i < 256;i ++)
{
uart_printf("%02X ", p);
}
uart_printf("\r\n");
QSPI_SetMode(QSPI_STAND_READ); //QSPI工作模式设置
QSPI_EnterRomMode(FALSE); //QSPI设置是否使能ROM访问模式-退出ROM模式
while(1)
{
uart_printf("ID:0x%X\r\n", W25QxxJV_ReadStatus(&mW25QxxJV_Handle));
SYS_DelayMS(1000);
}
}
注意:对flash的读取使用ROM模式,直接访问指定地址即可读取,任何其它操作,包括写,读取状态等,都需要退出4线模式以及ROM模式,进入直通模式,操作完成后,设置为1-4-4也就是1命令线,4地址线,4数据线模式,然后进入ROM模式,即可直接通过地址映射方式读取flash。
使用fatfs读写速度怎么样 w25q128的驱动和w25q64一样吗 如何使用w25q128升级程序 驱动的速度怎么样 能使用操作系统吗? QSPI? HC32F460速度怎么样 没有工程文件吗? HC32F460 没有eeprom吗? 这个是官网的程序吗
页:
[1]