#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; }