You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

392 lines
12 KiB
C

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "SWM221.h"
#include "W25N01G.h"
/******************************************************************************************************************************************
* 函数名称: W25N01G_Init()
* 功能说明: W25N01G 初始化
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void W25N01G_Init(void)
{
QSPI_InitStructure QSPI_initStruct;
PORT_Init(PORTC, PIN3, PORTC_PIN3_QSPI0_SCLK, 0);
PORT_Init(PORTC, PIN2, PORTC_PIN2_QSPI0_SSEL, 0);
PORT_Init(PORTA, PIN15, PORTA_PIN15_QSPI0_MOSI, 1);
PORT_Init(PORTB, PIN0, PORTB_PIN0_QSPI0_MISO, 1);
PORT_Init(PORTB, PIN1, PORTB_PIN1_QSPI0_D2, 1);
PORT_Init(PORTB, PIN2, PORTB_PIN2_QSPI0_D3, 1);
QSPI_initStruct.Size = QSPI_Size_128MB;
QSPI_initStruct.ClkDiv = 4;
QSPI_initStruct.ClkMode = QSPI_ClkMode_3;
QSPI_initStruct.SampleShift = (QSPI_initStruct.ClkDiv == 2) ? QSPI_SampleShift_1_SYSCLK : QSPI_SampleShift_NONE;
QSPI_initStruct.IntEn = 0;
QSPI_Init(QSPI0, &QSPI_initStruct);
QSPI_Open(QSPI0);
uint8_t reg = W25N01G_ReadReg(W25N_STATUS_REG2);
reg |= (1 << W25N_STATUS_REG2_BUF_Pos); // Buffer Read Mode
W25N01G_WriteReg(W25N_STATUS_REG2, reg);
}
/******************************************************************************************************************************************
* 函数名称: W25N01G_ReadJEDEC()
* 功能说明: W25N01G 读取 JEDEC ID
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
uint32_t W25N01G_ReadJEDEC(void)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = W25N_CMD_READ_JEDEC;
cmdStruct.AddressMode = QSPI_PhaseMode_None;
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 8;
cmdStruct.DataMode = QSPI_PhaseMode_1bit;
cmdStruct.DataCount = 3;
QSPI_Command(QSPI0, QSPI_Mode_IndirectRead, &cmdStruct);
while(QSPI_FIFOCount(QSPI0) < 3) __NOP();
return (QSPI0->DRB << 16) | (QSPI0->DRB << 8) | QSPI0->DRB;
}
/******************************************************************************************************************************************
* 函数名称: W25N01G_Erase()
* 功能说明: W25N01G 块擦除,块大小为 128KB
* 输 入: uint32_t addr 要擦除的 SPI Flash 地址,必须 128KB 对齐(即 addr 是 0x20000 的整数倍)
* uint8_t wait 是否等待 SPI Flash 完成操作操作1 等待完成 0 立即返回
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void W25N01G_Erase(uint32_t addr, uint8_t wait)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = W25N_CMD_ERASE_BLOCK128KB;
cmdStruct.AddressMode = QSPI_PhaseMode_1bit;
cmdStruct.AddressSize = QSPI_PhaseSize_24bit; // 高 8bit 为 dummy clock低 16bit 为地址
cmdStruct.Address = addr >> 12; // Page Address
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 0;
cmdStruct.DataMode = QSPI_PhaseMode_None;
QSPI_WriteEnable(QSPI0);
QSPI_Command(QSPI0, QSPI_Mode_IndirectWrite, &cmdStruct);
while(QSPI_Busy(QSPI0)) __NOP();
if(wait)
while(W25N01G_FlashBusy()) __NOP();
}
/******************************************************************************************************************************************
* 函数名称: W25N01G_Write_()
* 功能说明: W25N01G 页写入,页大小为 2112 Byte
* 输 入: uint32_t addr 要写入到的 SPI Flash 地址,必须是 0x1000即 4096的整数倍
* uint8_t buff[2048] 要写入 SPI Flash 的数据,数组大小必须是 2048 字节ECC 区域内容由硬件计算生成
* uint8_t data_width 写入使用的数据线个数,有效值包括 1、4
* uint8_t data_phase 是否在此函数内执行数据阶段;若否,可在后续通过 DMA 实现更高效的写入
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void W25N01G_Write_(uint32_t addr, uint8_t buff[2048], uint8_t data_width, uint8_t data_phase)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
uint8_t instruction, dataMode;
switch(data_width)
{
case 1:
instruction = W25N_CMD_PAGE_PROGRAM;
dataMode = QSPI_PhaseMode_1bit;
break;
case 4:
instruction = W25N_CMD_PAGE_PROGRAM_4bit;
dataMode = QSPI_PhaseMode_4bit;
break;
}
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = instruction;
cmdStruct.AddressMode = QSPI_PhaseMode_1bit;
cmdStruct.AddressSize = QSPI_PhaseSize_16bit;
cmdStruct.Address = 0x000; // Column Address
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 0;
cmdStruct.DataMode = dataMode;
cmdStruct.DataCount = 2048;
QSPI_WriteEnable(QSPI0);
QSPI_Command(QSPI0, QSPI_Mode_IndirectWrite, &cmdStruct);
if(data_phase == 0)
return;
if((uint32_t)buff % 4 == 0) // word aligned
{
for(int i = 0; i < 2048 / 4; i++)
{
uint32_t * p_word = (uint32_t *)buff;
while(QSPI_FIFOSpace(QSPI0) < 4) __NOP();
QSPI0->DRW = p_word[i];
}
}
else
{
for(int i = 0; i < 2048; i++)
{
while(QSPI_FIFOSpace(QSPI0) < 1) __NOP();
QSPI0->DRB = buff[i];
}
}
while(QSPI_Busy(QSPI0)) __NOP();
W25N01G_Program_Execute(addr);
while(W25N01G_FlashBusy()) __NOP();
}
/* Program the Data Buffer content into the physical memory page */
void W25N01G_Program_Execute(uint32_t addr)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = W25N_CMD_PROGRAM_EXECUTE;
cmdStruct.AddressMode = QSPI_PhaseMode_1bit;
cmdStruct.AddressSize = QSPI_PhaseSize_24bit; // 高 8bit 为 dummy clock低 16bit 为地址
cmdStruct.Address = addr >> 12; // Page Address
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 0;
cmdStruct.DataMode = QSPI_PhaseMode_None;
QSPI_Command(QSPI0, QSPI_Mode_IndirectWrite, &cmdStruct);
while(QSPI_Busy(QSPI0)) __NOP();
}
/******************************************************************************************************************************************
* 函数名称: W25N01G_Read_()
* 功能说明: W25N01G 页读取,页大小为 2112 Byte
* 输 入: uint32_t addr 要读取自的 SPI Flash 地址,必须是 0x1000即 4096的整数倍
* uint8_t buff[2048] 读取到的数据写入此数组中,数组大小必须是 2048 字节ECC 数据不读取
* uint8_t addr_width 读取使用的地址线个数,有效值包括 1、2、4
* uint8_t data_width 读取使用的数据线个数,有效值包括 1、2、4
* uint8_t data_phase 是否在此函数内执行数据阶段;若否,可在后续通过 DMA 实现更高效的读取
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void W25N01G_Read_(uint32_t addr, uint8_t buff[2048], uint8_t addr_width, uint8_t data_width, uint8_t data_phase)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
/* Transfer the data of specified page into the 2112-Byte Data Buffer */
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = W25N_CMD_PAGE_READ;
cmdStruct.AddressMode = QSPI_PhaseMode_1bit;
cmdStruct.AddressSize = QSPI_PhaseSize_24bit; // 高 8bit 为 dummy clock低 16bit 为地址
cmdStruct.Address = addr >> 12; // Page Address
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 0;
cmdStruct.DataMode = QSPI_PhaseMode_None;
QSPI_Command(QSPI0, QSPI_Mode_IndirectWrite, &cmdStruct);
while(QSPI_Busy(QSPI0)) __NOP();
while(W25N01G_FlashBusy()) __NOP();
uint8_t instruction, addressMode, dataMode, dummyCycles;
switch((addr_width << 4) | data_width)
{
case 0x11:
instruction = W25N_CMD_FAST_READ;
addressMode = QSPI_PhaseMode_1bit;
dummyCycles = 8;
dataMode = QSPI_PhaseMode_1bit;
break;
case 0x12:
instruction = W25N_CMD_FAST_READ_2bit;
addressMode = QSPI_PhaseMode_1bit;
dummyCycles = 8;
dataMode = QSPI_PhaseMode_2bit;
break;
case 0x22:
instruction = W25N_CMD_FAST_READ_IO2bit;
addressMode = QSPI_PhaseMode_2bit;
dummyCycles = 4;
dataMode = QSPI_PhaseMode_2bit;
break;
case 0x14:
instruction = W25N_CMD_FAST_READ_4bit;
addressMode = QSPI_PhaseMode_1bit;
dummyCycles = 8;
dataMode = QSPI_PhaseMode_4bit;
break;
case 0x44:
instruction = W25N_CMD_FAST_READ_IO4bit;
addressMode = QSPI_PhaseMode_4bit;
dummyCycles = 4;
dataMode = QSPI_PhaseMode_4bit;
break;
}
QSPI_CmdStructClear(&cmdStruct);
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = instruction;
cmdStruct.AddressMode = addressMode;
cmdStruct.AddressSize = QSPI_PhaseSize_16bit;
cmdStruct.Address = 0x000; // Column Address
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = dummyCycles;
cmdStruct.DataMode = dataMode;
cmdStruct.DataCount = 2048;
QSPI_Command(QSPI0, QSPI_Mode_IndirectRead, &cmdStruct);
if(data_phase == 0)
return;
if((uint32_t)buff % 4 == 0) // word aligned
{
for(int i = 0; i < 2048 / 4; i++)
{
uint32_t * p_word = (uint32_t *)buff;
while(QSPI_FIFOCount(QSPI0) < 4) __NOP();
p_word[i] = QSPI0->DRW;
}
}
else
{
for(int i = 0; i < 2048; i++)
{
while(QSPI_FIFOCount(QSPI0) < 1) __NOP();
buff[i] = QSPI0->DRB;
}
}
QSPI_Abort(QSPI0);
}
/******************************************************************************************************************************************
* 函数名称: W25N01G_FlashBusy()
* 功能说明: W25N01G 忙检测
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
bool W25N01G_FlashBusy(void)
{
uint8_t reg = W25N01G_ReadReg(W25N_STATUS_REG3);
bool busy = (reg & (1 << W25N_STATUS_REG3_BUSY_Pos));
return busy;
}
/******************************************************************************************************************************************
* 函数名称: W25N01G_FlashProtect()
* 功能说明: W25N01G 写保护配置
* 输 入: 无
* 输 出: 无
* 注意事项: 无
******************************************************************************************************************************************/
void W25N01G_FlashProtect(uint8_t protect)
{
uint8_t tb = (protect >> 4);
uint8_t bp = (protect & 0xF);
uint8_t reg = W25N01G_ReadReg(W25N_STATUS_REG1);
reg &= ~(W25N_STATUS_REG1_TB_Msk | W25N_STATUS_REG1_BP_Msk);
reg |= (tb << W25N_STATUS_REG1_TB_Pos) |
(bp << W25N_STATUS_REG1_BP_Pos);
W25N01G_WriteReg(W25N_STATUS_REG1, reg);
}
void W25N01G_WriteReg(uint8_t reg_addr, uint8_t data)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = W25N_CMD_WRITE_STATUS_REG;
cmdStruct.AddressMode = QSPI_PhaseMode_1bit;
cmdStruct.AddressSize = QSPI_PhaseSize_8bit;
cmdStruct.Address = reg_addr;
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 0;
cmdStruct.DataMode = QSPI_PhaseMode_1bit;
cmdStruct.DataCount = 1;
QSPI_Command(QSPI0, QSPI_Mode_IndirectWrite, &cmdStruct);
QSPI0->DRB = data;
while(QSPI_Busy(QSPI0)) __NOP();
}
uint8_t W25N01G_ReadReg(uint8_t reg_addr)
{
QSPI_CmdStructure cmdStruct;
QSPI_CmdStructClear(&cmdStruct);
cmdStruct.InstructionMode = QSPI_PhaseMode_1bit;
cmdStruct.Instruction = W25N_CMD_READ_STATUS_REG;
cmdStruct.AddressMode = QSPI_PhaseMode_1bit;
cmdStruct.AddressSize = QSPI_PhaseSize_8bit;
cmdStruct.Address = reg_addr;
cmdStruct.AlternateBytesMode = QSPI_PhaseMode_None;
cmdStruct.DummyCycles = 0;
cmdStruct.DataMode = QSPI_PhaseMode_1bit;
cmdStruct.DataCount = 1;
QSPI_Command(QSPI0, QSPI_Mode_IndirectRead, &cmdStruct);
while(QSPI_FIFOEmpty(QSPI0)) __NOP();
return QSPI0->DRB;
}