STM32H750VB_Bootloader/Core/Src/w25_qspi.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;
}