MT25QL256的数据手册:
https://download.csdn.net/download/weixin_47041339/85933399?spm=1001.2014.3001.5501
关于FLASH的具体信息自行查看数据手册。
有一点特别注意:MT25QL如果有#HOLD引脚,必须要拉高!不然数据写不进去
mt25ql.h
#ifndef _MT25QL_H
#define _MT25QL_H
# ifdef __cplusplus
extern "C" {
# endif
/***用华大的库****/
#include "hc32_ddl.h"
#include "cmsis_os2.h"
/* 片选信号控制引脚 */
#define SPI_CSPIN_HIGH() (GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_02))
#define SPI_CSPIN_LOW() (GPIO_ResetPins(GPIO_PORT_B,GPIO_PIN_02))
/**MT25QL256有HOLD引脚,发数据时必须拉高**/
#define SPI_HOLD_PIN_HIGH() (GPIO_SetPins(GPIO_PORT_B, GPIO_PIN_08))
#define SPI_HOLD_PIN_LOW() (GPIO_ResetPins(GPIO_PORT_B,GPIO_PIN_08))
#define FLASH_MAX_ADDR (0xFFFFFFUL) //最大地址
#define FLASH_PAGE_SIZE (0x100U) //一页大小,最大256字节
/************************指令定义***********************************/
//写命令
#define WRITE_ENABLE_cmd (0x06U) //允许写/写使能
#define WRITE_RESET_cmd (0x66) //允许写/写使能
#define WRITE_DISABLE_cmd (0x04U) //禁止写
#define WRITE_PAGE_cmd (0X02U) //写一页
#define WRITE_STATUS_REG_cmd (0x01U) //写状态寄存器
//读命令
#define READ_STATUS_REG_cmd 0x05 //读取状态寄存器
#define READ_FLAG_STATUS_REG 0x70 //读状态寄存器标志位
#define READ_cmd 0x03
#define READ_4BYTE_cmd 0x13
#define READ_ID_cmd 0X9E
#define Page_Read_Cmd 0xD2 //读取一页
///擦除命令
#define ERASE_32KB_cmd 0x52 //擦除32KB
#define ERASE_4KB_cmd 0x20 //擦除4KB
#define ERASE_SECTOR_cmd 0XD8 //擦除扇区
#define ERASE_BULK_cmd 0x60 //擦除磁盘
#define ERASE_4BYTE_cmd 0xDC //擦除4字节
/******************************************************************/
uint32_t SPI_FLASH_test_fuc(void) ; //测试函数
void mt25ql_init(p_mt25ql_dev_t pdev,read_write_t fun) ; //初始化函数
unsigned char StatusRegisterRead(void);
# ifdef __cplusplus
}
# endif
# endif
mt25ql.c
#include "mt25ql.h"
#include "bspspi.h"
#include "bspuart.h"
#include "string.h"
static p_mt25ql_dev_t p_mt25ql_dev;
/********************************************************
*功能描述:初始化#CS片选引脚和#HOLD引脚
*******************************************************/
static void mt25ql_gpio_init(void)
{
stc_gpio_init_t stcGpioInit;
/* Register write enable for some required peripherals. */
GPIO_Unlock();
(void)GPIO_StructInit(&stcGpioInit);
stcGpioInit.u16PinDir = PIN_DIR_OUT;
stcGpioInit.u16PullUp = PIN_PU_ON;
stcGpioInit.u16PinDrv = PIN_DRV_HIGH;
(void)GPIO_Init(GPIO_PORT_B,GPIO_PIN_02, &stcGpioInit);
(void)GPIO_Init(GPIO_PORT_B,GPIO_PIN_08, &stcGpioInit);
/* Register write protected for some required peripherals. */
GPIO_Lock();
SPI_CSPIN_HIGH() ;
SPI_HOLD_PIN_HIGH() ;
}
/**********************************************
功能描述:读取FLASH的状态
参数输入:无
返 回:状态寄存器的内容
***********************************************/
unsigned char StatusRegisterRead(void)
{
unsigned char status;
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(READ_STATUS_REG_cmd);
status = spi3_read_write_byte(0xff);
SPI_CSPIN_HIGH();
return status;
}
/********************************************************
* 功能描述: SPI flash 允许写/写使能
*******************************************************/
static void SpiFlash_WriteEnable(void)
{
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(WRITE_ENABLE_cmd);
SPI_CSPIN_HIGH();
}
/********************************************************
*功能描述: SPI flash RESET
*******************************************************/
static void SpiFlash_RESET_FUC(void)
{
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(WRITE_RESET_cmd); //允许复位
SPI_CSPIN_HIGH();
DDL_DelayMS(3);
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(0x99); //复位
SPI_CSPIN_HIGH();
}
/********************************************************
* 功能描述: SPI flash wait for write operation end function
* //SPI等待写完
* @retval Ok //写入成功
* @retval ErrorTimeout //超时
*******************************************************/
static en_result_t SpiFlash_WaitForWriteEnd(void)
{
en_result_t enRet = Ok;
uint8_t u8Status;
uint32_t u32Timeout;
stc_clk_freq_t stcClkFreq;
(void)CLK_GetClockFreq(&stcClkFreq);
u32Timeout = stcClkFreq.sysclkFreq / 1000U;
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(READ_STATUS_REG_cmd); //读状态寄存器
do
{
u8Status = spi3_read_write_byte(0xffU);
u32Timeout--;
} while ((u32Timeout != 0UL) &&
((u8Status & FLASH_BUSY_BIT_flag) == FLASH_BUSY_BIT_flag));
if (FLASH_BUSY_BIT_flag == u8Status)
{
enRet = ErrorTimeout;
}
SPI_CSPIN_HIGH();
return enRet;
}
/*****************************************************************************
* @brief SPI flash page write program function
* //SPI flash写一页函数
* @param [in] u32Addr 地址
* @param [in] pData 发送数据缓冲区的指针
* @param [in] len 发送数据长度
* @retval Error 写入失败
* @retval Ok 写入成功
*****************************************************************************/
static en_result_t SpiFlash_WritePage(uint32_t u32Addr, const uint8_t pData[], uint16_t len)
{
en_result_t enRet;
uint16_t u16Index = 0U;
if ((u32Addr > FLASH_MAX_ADDR) || (NULL == pData) || (len > FLASH_PAGE_SIZE))
{
enRet = Error;
}
else
{
SpiFlash_WriteEnable();
/* Send data to flash */
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(WRITE_PAGE_cmd);
(void)spi3_read_write_byte((uint8_t)((u32Addr & 0xFF0000UL) >> 16U));
(void)spi3_read_write_byte((uint8_t)((u32Addr & 0xFF00U) >> 8U));
(void)spi3_read_write_byte((uint8_t)(u32Addr & 0xFFU));
while (0U != (len--))
{
(void)spi3_read_write_byte(pData[u16Index]);
u16Index++;
}
SPI_CSPIN_HIGH();
/* Wait for flash idle */
enRet = SpiFlash_WaitForWriteEnd();
}
return enRet;
}
/**************************************************************************
* @brief SPI flash read data function
* //读取FLASH
* @param [in] u32Addr FLASH地址
* @param [out] pData 数据缓冲区指针
* @param [in] len 读取的数据长度
* @retval Error 读取失败
* @retval Ok 读取成功
*************************************************************************************/
static en_result_t SpiFlash_ReadData(uint32_t u32Addr, uint8_t pData[], uint16_t len)
{
en_result_t enRet = Ok;
uint16_t u16Index = 0U;
if ((u32Addr > FLASH_MAX_ADDR) || (NULL == pData))
{
enRet = Error;
}
else
{
SpiFlash_WriteEnable();
/* 向flash发送指令*/
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(READ_cmd);
(void)spi3_read_write_byte((uint8_t)((u32Addr & 0xFF0000UL) >> 16U));
(void)spi3_read_write_byte((uint8_t)((u32Addr & 0xFF00U) >> 8U));
(void)spi3_read_write_byte((uint8_t)(u32Addr & 0xFFU));
while (0U != (len--))
{
pData[u16Index] = spi3_read_write_byte(FLASH_DUMMY_BYTE_VALUE);
u16Index++;
}
SPI_CSPIN_HIGH();
}
return enRet;
}
/****************************************************
* @brief 读FLASH ID //一般用来测试
* @param [in] None
* @retval uint8_t Flash ID
***************************************************/
static uint8_t SpiFlash_ReadID(void)
{
uint32_t u8IdRead;
uint8_t ID[15];
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(READ_ID_cmd);
(void)spi3_read_write_byte((uint8_t)0x00U);
(void)spi3_read_write_byte((uint8_t)0x00U);
(void)spi3_read_write_byte((uint8_t)0x00U);
u8IdRead = spi3_read_write_byte((uint8_t)0xffU);
SPI_CSPIN_HIGH();
return u8IdRead;
}
/***************************************************************
* @brief SPI flash erase 4Kb sector function
//擦除4KB扇区
* @param [in] u32Addr FLASH地址
* @retval Error 擦除失败
* @retval Ok 擦除成功
***************************************************************/
static en_result_t SpiFlash_Erase4KbSector(uint32_t u32Addr)
{
en_result_t enRet;
if (u32Addr >= FLASH_MAX_ADDR)
{
enRet = Error;
}
else
{
SpiFlash_WriteEnable();
/*向flash发送指令 */
SPI_CSPIN_LOW();
(void)spi3_read_write_byte(ERASE_4KB_cmd);
(void)spi3_read_write_byte((uint8_t)((u32Addr & 0xFF0000UL) >> 16U));
(void)spi3_read_write_byte((uint8_t)((u32Addr & 0xFF00U) >> 8U));
(void)spi3_read_write_byte((uint8_t)(u32Addr & 0xFFU));
//SPI_GetStatus(const M4_SPI_TypeDef *SPIx, uint32_t u32Flag) //todo
SPI_CSPIN_HIGH();
/* Wait for flash idle */
enRet = SpiFlash_WaitForWriteEnd();
}
return enRet;
}
/**********************************************************
* FLASH测试函数:
写入一串字符,然后读出来比较
************************************************************/
uint32_t SPI_FLASH_test_fuc(void)
{
SPI_HOLD_PIN_HIGH(); //HOLD
uint32_t flashAddr = 0x00;
uint16_t bufferLen;
char txBuffer[] = "SPI read and write flash test fuction";
uint8_t rxBuffer[128];
/* Get tx buffer length */
bufferLen = (uint16_t)sizeof(txBuffer);
DDL_DelayMS(10);
(void)memset(rxBuffer, 0L, sizeof(rxBuffer));
/* Erase sector */
(void)SpiFlash_Erase4KbSector(flashAddr);
/* Write data to flash */
(void)SpiFlash_WritePage(flashAddr, (uint8_t*)&txBuffer[0], bufferLen);
/* Read data from flash */
DDL_DelayMS(10);
(void)SpiFlash_ReadData(flashAddr, (uint8_t*)&rxBuffer[0], bufferLen);
/* Compare txBuffer and rxBuffer */
if (memcmp(txBuffer, rxBuffer, (uint32_t)bufferLen) != 0)
{
return 0; //结果不一样进这里,说明读取失败
}
else
{
return 5; //结果一致进这里,说明读写成功
}
}
void mt25ql_init(p_mt25ql_dev_t pdev,read_write_t fun)
{
p_mt25ql_dev = pdev;
p_mt25ql_dev->spi_read_write = fun; //SPI接口
mt25ql_gpio_init(); //片选初始化
DDL_DelayMS(50); //上电延迟50ms
}
/**********************************************
功能描述:从flash读一串字符串
参数输入:读取数据起始地址,数据长度
返 回:0
***********************************************/
int spi_read(uint8_t *adder,size_t size)
{
uint16_t i;
char a;
for(i=0;i<size;i++ )
{
a = spi3_read_write_byte(0xff);
*(adder+i) = a;
}
return 0;
}
/**********************************************
功能描述:往flash写一串字符串
参数输入:写入地址,数据长度
返 回:0
***********************************************/
int spi_write(uint8_t *adder,size_t size)
{
uint16_t i;
char a;
for(i=0;i<size;i++ )
{
a= *(adder+i);
spi3_read_write_byte(*(adder+i));
}
return 0;
}
第一次上传文章,望大家支持!!
有问题可以在评论区留言,后期不定期更新