237 lines
7.3 KiB
C
237 lines
7.3 KiB
C
//
|
|
// Created by imi415 on 2019/12/19.
|
|
//
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "stm32h7xx_hal.h"
|
|
#include "w25_qspi.h"
|
|
|
|
HAL_StatusTypeDef _W25_Write_Enable(w25_qspi_t *flash);
|
|
HAL_StatusTypeDef _W25_Write_Volatile_Enable(w25_qspi_t *flash);
|
|
HAL_StatusTypeDef _W25_Wait_Ready(w25_qspi_t *flash);
|
|
HAL_StatusTypeDef _W25_GetDefaultCommand(w25_qspi_t *flash, QSPI_CommandTypeDef *sCommand);
|
|
HAL_StatusTypeDef _W25_QSPI_Identify(w25_qspi_t *flash);
|
|
|
|
HAL_StatusTypeDef W25_QSPI_Init(w25_qspi_t *flash) {
|
|
return _W25_QSPI_Identify(flash);
|
|
}
|
|
|
|
HAL_StatusTypeDef W25_QSPI_Erase_Sector(w25_qspi_t *flash, uint32_t address) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.Instruction = W25_CMD_SECTOR_ERASE;
|
|
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
|
|
sCommand.DataMode = QSPI_DATA_NONE;
|
|
sCommand.NbData = 0;
|
|
sCommand.DummyCycles = 0;
|
|
sCommand.Address = address;
|
|
|
|
_W25_Write_Enable(flash);
|
|
HAL_QSPI_Command(flash->interface, &sCommand, 1000);
|
|
_W25_Wait_Ready(flash);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef W25_QSPI_Program_Page(w25_qspi_t *flash, uint32_t address, uint8_t *data) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.Instruction = W25_CMD_PAGE_PROGRAM;
|
|
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
|
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
|
sCommand.DummyCycles = 0;
|
|
sCommand.NbData = 256;
|
|
sCommand.Address = address;
|
|
|
|
_W25_Write_Enable(flash);
|
|
if(HAL_QSPI_Command(flash->interface, &sCommand, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
if(HAL_QSPI_Transmit(flash->interface, data, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
_W25_Wait_Ready(flash);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef W25_QSPI_Read(w25_qspi_t *flash, uint32_t address, uint8_t *data, uint32_t length) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.Instruction = W25_CMD_READ;
|
|
sCommand.AddressMode = QSPI_ADDRESS_1_LINE;
|
|
sCommand.Address = address;
|
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
|
sCommand.DummyCycles = 0;
|
|
sCommand.NbData = length;
|
|
|
|
if(HAL_QSPI_Command(flash->interface, &sCommand, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
if(HAL_QSPI_Receive(flash->interface, data, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef W25_QSPI_QuadEnable(w25_qspi_t *flash, uint8_t permanent) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.Instruction = W25_CMD_READ_STATUS_2;
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
|
sCommand.NbData = 1;
|
|
sCommand.DummyCycles = 0;
|
|
|
|
uint8_t status_2;
|
|
|
|
if(HAL_QSPI_Command(flash->interface, &sCommand, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
if(HAL_QSPI_Receive(flash->interface, &status_2, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
if(permanent) {
|
|
_W25_Write_Enable(flash);
|
|
}
|
|
else _W25_Write_Volatile_Enable(flash);
|
|
|
|
sCommand.Instruction = W25_CMD_WRITE_STATUS_2;
|
|
status_2 |= 0x02; // BIT 1 QE
|
|
|
|
if(HAL_QSPI_Command(flash->interface, &sCommand, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
if(HAL_QSPI_Transmit(flash->interface, &status_2, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
return HAL_OK;
|
|
|
|
}
|
|
|
|
HAL_StatusTypeDef W25_QPI_Mode(w25_qspi_t *flash, uint8_t enable) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
if(enable) {
|
|
sCommand.Instruction = W25_CMD_QPI_ENABLE;
|
|
}
|
|
else {
|
|
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
|
|
sCommand.Instruction = W25_CMD_QPI_DISABLE;
|
|
}
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
sCommand.DataMode = QSPI_DATA_NONE;
|
|
sCommand.NbData = 0;
|
|
sCommand.DummyCycles = 0;
|
|
|
|
return HAL_QSPI_Command(flash->interface, &sCommand, 1000);
|
|
}
|
|
|
|
HAL_StatusTypeDef W25_QPI_ReadParams(w25_qspi_t *flash, w25_qpi_dummy_t dummy_clocks, w25_qpi_wrap_t wrap_length) {
|
|
uint8_t rd_params = (dummy_clocks & 0x03) << 4 | (wrap_length & 0x03); // BIT 5-4: DUMMY, BIT 1-0 WRAP
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.InstructionMode = QSPI_INSTRUCTION_4_LINES;
|
|
sCommand.Instruction = W25_CMD_QPI_READ_PARAMS;
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
sCommand.DataMode = QSPI_DATA_4_LINES;
|
|
sCommand.NbData = 1;
|
|
sCommand.DummyCycles = 0;
|
|
|
|
if(HAL_QSPI_Command(flash->interface, &sCommand, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
return HAL_QSPI_Transmit(flash->interface, &rd_params, 1000);
|
|
}
|
|
|
|
HAL_StatusTypeDef _W25_Write_Enable(w25_qspi_t *flash) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.Instruction = W25_CMD_WRITE_ENABLE;
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
sCommand.DataMode = QSPI_DATA_NONE;
|
|
sCommand.NbData = 0;
|
|
sCommand.DummyCycles = 0;
|
|
|
|
HAL_QSPI_Command(flash->interface, &sCommand, 1000);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef _W25_Write_Volatile_Enable(w25_qspi_t *flash) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.Instruction = W25_CMD_WRITE_VOLATILE_ENABLE;
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
sCommand.DataMode = QSPI_DATA_NONE;
|
|
sCommand.NbData = 0;
|
|
sCommand.DummyCycles = 0;
|
|
|
|
HAL_QSPI_Command(flash->interface, &sCommand, 1000);
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef _W25_Wait_Ready(w25_qspi_t *flash) {
|
|
QSPI_AutoPollingTypeDef sConfig;
|
|
sConfig.Match = 0x00;
|
|
sConfig.Mask = 0x01;
|
|
sConfig.MatchMode = QSPI_MATCH_MODE_AND;
|
|
sConfig.StatusBytesSize = 1;
|
|
sConfig.Interval = 0x10;
|
|
sConfig.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE;
|
|
|
|
QSPI_CommandTypeDef sCommand;
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
|
sCommand.DummyCycles = 0;
|
|
sCommand.Instruction = W25_CMD_READ_STATUS_1;
|
|
sCommand.NbData = 1;
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
|
|
if(HAL_QSPI_AutoPolling_IT(flash->interface, &sCommand, &sConfig) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef _W25_GetDefaultCommand(w25_qspi_t *flash, QSPI_CommandTypeDef *sCommand) {
|
|
sCommand->InstructionMode = QSPI_INSTRUCTION_1_LINE;
|
|
sCommand->AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
|
|
sCommand->DdrMode = QSPI_DDR_MODE_DISABLE;
|
|
sCommand->DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
|
|
sCommand->SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
|
|
|
|
if(flash->address_size == W25_ADDRESS_32BITS) sCommand->AddressSize = QSPI_ADDRESS_32_BITS;
|
|
else sCommand->AddressSize = QSPI_ADDRESS_24_BITS;
|
|
|
|
return HAL_OK;
|
|
}
|
|
|
|
HAL_StatusTypeDef _W25_QSPI_Identify(w25_qspi_t *flash) {
|
|
QSPI_CommandTypeDef sCommand;
|
|
uint8_t jedec_id[3];
|
|
_W25_GetDefaultCommand(flash, &sCommand);
|
|
sCommand.AddressMode = QSPI_ADDRESS_NONE;
|
|
sCommand.DataMode = QSPI_DATA_1_LINE;
|
|
sCommand.DummyCycles = 0;
|
|
sCommand.Instruction = W25_CMD_READ_JEDEC_ID;
|
|
sCommand.NbData = 3;
|
|
|
|
if(HAL_QSPI_Command(flash->interface, &sCommand, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
if(HAL_QSPI_Receive(flash->interface, jedec_id, 1000) != HAL_OK) {
|
|
return HAL_ERROR;
|
|
}
|
|
|
|
flash->manufacturer = jedec_id[0];
|
|
flash->memory_type = jedec_id[1];
|
|
flash->capacity = 1U << jedec_id[2];
|
|
|
|
return HAL_OK;
|
|
} |