285 lines
8.0 KiB
C
285 lines
8.0 KiB
C
/* Config */
|
|
#include "FlashConfig.h"
|
|
|
|
/* HAL */
|
|
#include "stm32h7xx_hal.h"
|
|
|
|
/* Private */
|
|
#include "FlashOperations.h"
|
|
|
|
#define APP_FLASH_COMMAND_TIMEOUT (5000)
|
|
|
|
static QSPI_HandleTypeDef hqspi;
|
|
|
|
static int SystemClock_Config(void) {
|
|
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
|
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
|
|
|
/** Supply configuration update enable
|
|
*/
|
|
HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
|
|
|
|
/** Configure the main internal regulator output voltage
|
|
*/
|
|
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);
|
|
|
|
while (!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {
|
|
}
|
|
|
|
/** Initializes the RCC Oscillators according to the specified parameters
|
|
* in the RCC_OscInitTypeDef structure.
|
|
*/
|
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
|
|
RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
|
|
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
|
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
|
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
|
|
/** Initializes the CPU, AHB and APB buses clocks
|
|
*/
|
|
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 |
|
|
RCC_CLOCKTYPE_PCLK2 | RCC_CLOCKTYPE_D3PCLK1 | RCC_CLOCKTYPE_D1PCLK1;
|
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
|
|
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
|
|
RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
|
|
RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;
|
|
|
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) {
|
|
return -2;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void GPIO_Init(void) {
|
|
GPIO_InitTypeDef GPIO_InitStruct = {0};
|
|
|
|
/* GPIO Ports Clock Enable */
|
|
__HAL_RCC_GPIOG_CLK_ENABLE();
|
|
__HAL_RCC_GPIOH_CLK_ENABLE();
|
|
__HAL_RCC_GPIOF_CLK_ENABLE();
|
|
__HAL_RCC_GPIOB_CLK_ENABLE();
|
|
__HAL_RCC_GPIOA_CLK_ENABLE();
|
|
|
|
/*Configure GPIO pin Output Level */
|
|
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1 | GPIO_PIN_0, GPIO_PIN_SET);
|
|
|
|
/*Configure GPIO pin Output Level */
|
|
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
|
|
|
|
/*Configure GPIO pins : PB1 PB0 */
|
|
GPIO_InitStruct.Pin = GPIO_PIN_1 | GPIO_PIN_0;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
|
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
|
|
|
|
/*Configure GPIO pin : PA3 */
|
|
GPIO_InitStruct.Pin = GPIO_PIN_3;
|
|
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
|
|
GPIO_InitStruct.Pull = GPIO_NOPULL;
|
|
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
|
|
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
|
|
}
|
|
|
|
static int QSPI_Init(void) {
|
|
hqspi.Instance = QUADSPI;
|
|
hqspi.Init.ClockPrescaler = 1;
|
|
hqspi.Init.FifoThreshold = 4;
|
|
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_NONE;
|
|
hqspi.Init.FlashSize = APP_FLASH_BITS;
|
|
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_1_CYCLE;
|
|
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
|
|
hqspi.Init.DualFlash = QSPI_DUALFLASH_ENABLE;
|
|
if (HAL_QSPI_Init(&hqspi) != HAL_OK) {
|
|
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 0);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Flash_Wait_Busy(uint32_t timeout) {
|
|
QSPI_AutoPollingTypeDef poll_def = {
|
|
.Match = 0U,
|
|
.Mask = (1 << 8U) | 1U, /* Status register: Bit 0 and Bit 8 */
|
|
.Interval = 0xFFFFU,
|
|
.StatusBytesSize = 2,
|
|
.MatchMode = QSPI_MATCH_MODE_AND,
|
|
.AutomaticStop = QSPI_AUTOMATIC_STOP_ENABLE,
|
|
};
|
|
|
|
QSPI_CommandTypeDef cmd = {
|
|
.Instruction = 0x05, /* SR1 */
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.AddressMode = QSPI_ADDRESS_NONE,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
|
|
.DataMode = QSPI_DATA_1_LINE,
|
|
};
|
|
|
|
if (HAL_QSPI_AutoPolling(&hqspi, &cmd, &poll_def, timeout) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Flash_Write_Enable(void) {
|
|
QSPI_CommandTypeDef cmd = {
|
|
.Instruction = 0x06, /* Write Enable */
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.AddressMode = QSPI_ADDRESS_NONE,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
|
|
.DataMode = QSPI_DATA_NONE,
|
|
};
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &cmd, APP_FLASH_COMMAND_TIMEOUT) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Flash_Init(void) {
|
|
int ret;
|
|
|
|
SystemInit();
|
|
|
|
ret = SystemClock_Config();
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
GPIO_Init();
|
|
|
|
ret = QSPI_Init();
|
|
if (ret != 0) {
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Flash_EraseSector(uint32_t addr) {
|
|
if (Flash_Write_Enable() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
QSPI_CommandTypeDef cmd = {
|
|
.Instruction = 0x21,
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.Address = addr & ~(APP_FLASH_SECTOR_SIZE - 1),
|
|
.AddressMode = QSPI_ADDRESS_1_LINE,
|
|
.AddressSize = QSPI_ADDRESS_32_BITS,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
|
|
.DataMode = QSPI_DATA_NONE,
|
|
};
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &cmd, APP_FLASH_COMMAND_TIMEOUT) != HAL_OK) {
|
|
return -2;
|
|
}
|
|
|
|
if (Flash_Wait_Busy(APP_FLASH_SECTOR_ERASE_TIMEOUT) != 0) {
|
|
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, 0);
|
|
return -3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Flash_ProgramPage(uint32_t addr, uint8_t *data, uint32_t len) {
|
|
if (Flash_Write_Enable() != 0) {
|
|
return -1;
|
|
}
|
|
|
|
QSPI_CommandTypeDef cmd = {
|
|
.Instruction = 0x34, /* Quad input page program with 4 byte address */
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.Address = addr,
|
|
.AddressMode = QSPI_ADDRESS_1_LINE,
|
|
.AddressSize = QSPI_ADDRESS_32_BITS,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
|
|
.DataMode = QSPI_DATA_4_LINES,
|
|
.DummyCycles = 0U,
|
|
.NbData = len,
|
|
};
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &cmd, APP_FLASH_COMMAND_TIMEOUT) != HAL_OK) {
|
|
return -2;
|
|
}
|
|
|
|
if (HAL_QSPI_Transmit(&hqspi, data, APP_FLASH_COMMAND_TIMEOUT) != HAL_OK) {
|
|
return -3;
|
|
}
|
|
|
|
if (Flash_Wait_Busy(APP_FLASH_PAGE_PROGRAM_TIMEOUT) != 0) {
|
|
return -4;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int Flash_EraseChip(void) {
|
|
if (Flash_Write_Enable() != HAL_OK) {
|
|
return -1;
|
|
}
|
|
|
|
QSPI_CommandTypeDef cmd = {
|
|
.Instruction = 0xC7, /* Chip erase */
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.AddressMode = QSPI_ADDRESS_NONE,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE,
|
|
.DataMode = QSPI_DATA_NONE,
|
|
};
|
|
|
|
if (HAL_QSPI_Command(&hqspi, &cmd, APP_FLASH_COMMAND_TIMEOUT) != HAL_OK) {
|
|
return -2;
|
|
}
|
|
|
|
if (Flash_Wait_Busy(APP_FLASH_CHIP_ERASE_TIMEOUT) != 0) {
|
|
return -3;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Flash_Map(void) {
|
|
QSPI_CommandTypeDef cmd = {
|
|
.Instruction = 0xEC, /* Fast read quad IO with 4 byte address */
|
|
.InstructionMode = QSPI_INSTRUCTION_1_LINE,
|
|
.AddressMode = QSPI_ADDRESS_4_LINES,
|
|
.AddressSize = QSPI_ADDRESS_32_BITS,
|
|
.AlternateByteMode = QSPI_ALTERNATE_BYTES_4_LINES,
|
|
.DataMode = QSPI_DATA_4_LINES,
|
|
.DummyCycles = 4U,
|
|
};
|
|
|
|
QSPI_MemoryMappedTypeDef mmap = {
|
|
.TimeOutPeriod = 0xFFFFU,
|
|
.TimeOutActivation = QSPI_TIMEOUT_COUNTER_DISABLE,
|
|
};
|
|
|
|
if (HAL_QSPI_MemoryMapped(&hqspi, &cmd, &mmap) != HAL_OK) {
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Flash_UnMap(void) {
|
|
/* De-init and re-init QSPI, as HAL driver has too much magic. */
|
|
HAL_StatusTypeDef ret;
|
|
do {
|
|
ret = HAL_QSPI_Abort(&hqspi);
|
|
} while (ret != HAL_OK);
|
|
return 0;
|
|
}
|
|
|
|
int Flash_Deinit(void) {
|
|
HAL_QSPI_DeInit(&hqspi);
|
|
return 0;
|
|
} |