add kv fs component

1. a true wear-leveling kv fs for norflash, especially optimize for some onchip norflash with "write once on one single write unit" like stm32l4, a true "no earse before write" flash algorithm.
2. an "as less as possible" gc strategy, do best to save norflash's life.
3. full "power down protection" support
4. see "examples" of kv, project in "TencentOS_tiny_EVB_MX_Plus", with onchip flash and qspiflash sample.
This commit is contained in:
daishengdong
2019-12-19 16:08:42 +08:00
parent e1c19fd194
commit febcf10911
23 changed files with 8674 additions and 10 deletions

View File

@@ -0,0 +1,78 @@
#include "tos_kv.h"
#include "stm32l4xx.h"
#define ONCHIP_FLASH_ADDR_START 0x08000000 // start address for onchip flash for stm32l431RCTX
#define ONCHIP_FLASH_ADDR_MAX 0x0803FFFF // 256K flash addr for stm32l431RCTX
#define SECTOR_SIZE 2048 // sector size for stm32l431RCTX
#define SECTOR_SIZE_LOG2 11 // 2 ^ 11 = 2048
#define FOR_KV_FLASH_SIZE (2 * SECTOR_SIZE) // storage for kv
#define FOR_KV_FLASH_START 0x803d000
int stm32l4_norflash_onchip_read(uint32_t addr, void *buf, size_t len)
{
memcpy(buf, (void *)addr, len);
return 0;
}
int stm32l4_norflash_onchip_write(uint32_t addr, const void *buf, size_t len)
{
int i = 0;
uint8_t *array = (uint8_t *)buf;
HAL_StatusTypeDef hal_status;
HAL_FLASH_Unlock();
tos_cpu_int_disable();
for (i = 0; i < len; i += 8) {
hal_status = HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD,
addr + i,
*(uint64_t *)&array[i]);
if (hal_status != HAL_OK) {
return -1;
}
}
HAL_FLASH_Lock();
tos_cpu_int_enable();
return 0;
}
int stm32l4_norflash_onchip_erase(uint32_t addr, size_t size)
{
uint32_t page_err = 0;
HAL_StatusTypeDef hal_status;
FLASH_EraseInitTypeDef erase_para;
erase_para.TypeErase = FLASH_TYPEERASE_PAGES;
erase_para.Banks = FLASH_BANK_1;
erase_para.Page = addr / SECTOR_SIZE;
erase_para.NbPages = size / SECTOR_SIZE;
HAL_FLASH_Unlock();
tos_cpu_int_disable();
hal_status = HAL_FLASHEx_Erase(&erase_para, &page_err);
HAL_FLASH_Lock();
tos_cpu_int_enable();
if (hal_status != HAL_OK) {
return -1;
}
return 0;
}
kv_flash_drv_t stm32l4_norflash_onchip_drv = {
.write = stm32l4_norflash_onchip_write,
.read = stm32l4_norflash_onchip_read,
.erase = stm32l4_norflash_onchip_erase,
};
kv_flash_prop_t stm32l4_norflash_onchip_prop = {
.sector_size_log2 = SECTOR_SIZE_LOG2,
.pgm_type = KV_FLASH_PROGRAM_TYPE_DOUBLEWORD,
.flash_start = FOR_KV_FLASH_START,
.flash_size = FOR_KV_FLASH_SIZE,
};

View File

@@ -0,0 +1,407 @@
#include "hal_qspi_flash.h"
#include "stm32l4xx.h"
#ifdef HAL_QSPI_MODULE_ENABLED
#define QSPI_FLASH_PAGESIZE 256
#define QSPI_FLASH_SECTOR 4096
#define QSPI_FLASH_ID 0xEF4017
#define QSPI_FLASH_TOTAL_SIZE 0x7FFFFF
#define QSPI_FLASH_WriteEnable 0x06
#define QSPI_FLASH_WriteDisable 0x04
#define QSPI_FLASH_ReadStatusReg 0x05
#define QSPI_FLASH_WriteStatusReg 0x01
#define QSPI_FLASH_ReadData 0x03
#define QSPI_FLASH_FastReadData 0x0B
#define QSPI_FLASH_FastReadDual 0x3B
#define QSPI_FLASH_PageProgram 0x02
#define QSPI_FLASH_BlockErase 0xD8
#define QSPI_FLASH_SectorErase 0x20
#define QSPI_FLASH_ChipErase 0xC7
#define QSPI_FLASH_PowerDown 0xB9
#define QSPI_FLASH_ReleasePowerDown 0xAB
#define QSPI_FLASH_DeviceID 0xAB
#define QSPI_FLASH_ManufactDeviceID 0x90
#define QSPI_FLASH_JedecDeviceID 0x9F
#define QSPI_FLASH_WIP_FLAG 0x01
#define QSPI_FLASH_DUMMY_BYTE 0xFF
#define CHOOSE_BIT_16 16
#define CHOOSE_BIT_8 8
#define CHECK_RET_RETURN(ret) \
do \
{ \
if ((ret) < 0) \
{ \
return ret; \
} \
} while (0)
extern QSPI_HandleTypeDef hqspi;
/* This function is called by inner-HAL lib */
static void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspInit 0 */
/* USER CODE END QUADSPI_MspInit 0 */
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PB0 ------> QUADSPI_BK1_IO1
PB1 ------> QUADSPI_BK1_IO0
PB10 ------> QUADSPI_CLK
PB11 ------> QUADSPI_BK1_NCS
*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN QUADSPI_MspInit 1 */
/* USER CODE END QUADSPI_MspInit 1 */
}
}
/* This function is called by inner-HAL lib */
static void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* qspiHandle)
{
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspDeInit 0 */
/* USER CODE END QUADSPI_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_QSPI_CLK_DISABLE();
/**QUADSPI GPIO Configuration
PB0 ------> QUADSPI_BK1_IO1
PB1 ------> QUADSPI_BK1_IO0
PB10 ------> QUADSPI_CLK
PB11 ------> QUADSPI_BK1_NCS
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11);
/* USER CODE BEGIN QUADSPI_MspDeInit 1 */
/* USER CODE END QUADSPI_MspDeInit 1 */
}
}
/**
* @brief QSPI<50><49><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
*
* @param instruction Ҫ<><D2AA><EFBFBD>͵<EFBFBD>ָ<EFBFBD><D6B8>
* @param address <09><><EFBFBD>͵<EFBFBD><CDB5><EFBFBD>Ŀ<EFBFBD>ĵ<EFBFBD>ַ
* @param dummyCycles <09><>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param instructionMode ָ<><D6B8>ģʽ;QSPI_INSTRUCTION_NONE,QSPI_INSTRUCTION_1_LINE,QSPI_INSTRUCTION_2_LINE,QSPI_INSTRUCTION_4_LINE
* @param addressMode <09><>ַģʽ; QSPI_ADDRESS_NONE,QSPI_ADDRESS_1_LINE,QSPI_ADDRESS_2_LINE,QSPI_ADDRESS_4_LINE
* @param addressSize <09><>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>;QSPI_ADDRESS_8_BITS,QSPI_ADDRESS_16_BITS,QSPI_ADDRESS_24_BITS,QSPI_ADDRESS_32_BITS
* @param dataMode <09><><EFBFBD><EFBFBD>ģʽ; QSPI_DATA_NONE,QSPI_DATA_1_LINE,QSPI_DATA_2_LINE,QSPI_DATA_4_LINE
*
* @return void
*/
uint32_t QSPI_Send_CMD(uint32_t instruction, uint32_t address, uint32_t dummyCycles, uint32_t instructionMode, uint32_t addressMode, uint32_t addressSize, uint32_t dataMode)
{
QSPI_CommandTypeDef s_command;
s_command.Instruction = instruction; //ָ<><D6B8>
s_command.Address = address; //<2F><>ַ
s_command.DummyCycles = dummyCycles; //<2F><><EFBFBD>ÿ<EFBFBD>ָ<EFBFBD><D6B8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
s_command.InstructionMode = instructionMode; //ָ<><D6B8>ģʽ
s_command.AddressMode = addressMode; //<2F><>ַģʽ
s_command.AddressSize = addressSize; //<2F><>ַ<EFBFBD><D6B7><EFBFBD><EFBFBD>
s_command.DataMode = dataMode; //<2F><><EFBFBD><EFBFBD>ģʽ
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD; //ÿ<>ζ<EFBFBD><CEB6><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><D6B8>
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE; //<2F>޽<EFBFBD><DEBD><EFBFBD><EFBFBD>ֽ<EFBFBD>
s_command.DdrMode = QSPI_DDR_MODE_DISABLE; //<2F>ر<EFBFBD>DDRģʽ
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
return HAL_QSPI_Command(&hqspi, &s_command, 5000);
}
uint8_t QSPI_Receive(const uint8_t * buf, uint32_t datalen)
{
hqspi.Instance->DLR = datalen - 1; //Configuration data length
if(HAL_QSPI_Receive(&hqspi, (uint8_t * )buf, 5000) == HAL_OK) return 0; //receive data
else return 1;
}
uint8_t QSPI_Transmit(const int8_t * buf, uint32_t datalen)
{
hqspi.Instance->DLR = datalen - 1; //Configuration data length
if(HAL_QSPI_Transmit(&hqspi, (uint8_t * )buf, 5000) == HAL_OK) return 0; //send data
else return 1;
}
static void prv_spi_flash_write_enable(void)
{
QSPI_Send_CMD(QSPI_FLASH_WriteEnable, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_NONE);
}
static void prv_spi_flash_wait_write_end(void)
{
uint8_t status = 0;
/* Loop as long as the memory is busy with a write cycle */
do
{
/* Send a dummy byte to generate the clock needed by the FLASH
and put the value of the status register in status variable */
QSPI_Send_CMD(QSPI_FLASH_ReadStatusReg, 0, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_NONE, QSPI_ADDRESS_8_BITS, QSPI_DATA_1_LINE);
QSPI_Receive(&status, 1);
} while ((status & QSPI_FLASH_WIP_FLAG) == SET); /* Write in progress */
}
static int prv_spi_flash_write_page(const uint8_t* buf, uint32_t addr, int32_t len)
{
int ret = 0;
if(0 == len)
{
return 0;
}
prv_spi_flash_write_enable(); //Write enable
QSPI_Send_CMD(QSPI_FLASH_PageProgram, addr, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_1_LINE, QSPI_ADDRESS_24_BITS, QSPI_DATA_1_LINE);
QSPI_Transmit((const int8_t *)buf, len);
prv_spi_flash_wait_write_end(); //Waiting for Writing to End
return ret;
}
int prv_spi_flash_erase_sector(uint32_t addr)
{
//printf("fe:%x\r\n",addr); //<2F><><EFBFBD><EFBFBD>flash<73><68><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
int ret = 0;
prv_spi_flash_write_enable(); //Write enable
prv_spi_flash_wait_write_end();
ret=QSPI_Send_CMD(QSPI_FLASH_SectorErase, addr, 0, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_1_LINE, QSPI_ADDRESS_24_BITS, QSPI_DATA_NONE);
prv_spi_flash_wait_write_end(); //Waiting for Writing to End
return ret;
}
void hal_spi_flash_config(void)
{
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 0;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = POSITION_VAL(0x1000000) - 1;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
Error_Handler();
}
}
int hal_spi_flash_erase(uint32_t addr, int32_t len)
{
uint32_t begin;
uint32_t end;
int i;
if (len < 0
|| addr > QSPI_FLASH_TOTAL_SIZE
|| addr + len > QSPI_FLASH_TOTAL_SIZE)
{
return -1;
}
begin = addr / QSPI_FLASH_SECTOR * QSPI_FLASH_SECTOR;
end = (addr + len - 1) / QSPI_FLASH_SECTOR * QSPI_FLASH_SECTOR;
for (i = begin; i <= end; i += QSPI_FLASH_SECTOR)
{
if (prv_spi_flash_erase_sector(i) == -1)
{
return -1;
}
}
return 0;
}
int hal_spi_flash_write(const void* buf, int32_t len, uint32_t* location)
{
const uint8_t* pbuf = (const uint8_t*)buf;
int page_cnt = 0;
int remain_cnt = 0;
int temp = 0;
uint32_t loc_addr;
uint8_t addr = 0;
uint8_t count = 0;
int i;
int ret = 0;
if (NULL == pbuf
|| NULL == location
|| len < 0
|| *location > QSPI_FLASH_TOTAL_SIZE
|| len + *location > QSPI_FLASH_TOTAL_SIZE)
{
return -1;
}
loc_addr = *location;
addr = loc_addr % QSPI_FLASH_PAGESIZE;
count = QSPI_FLASH_PAGESIZE - addr;
page_cnt = len / QSPI_FLASH_PAGESIZE;
remain_cnt = len % QSPI_FLASH_PAGESIZE;
if (addr == 0) /* addr is aligned to SPI_FLASH_PAGESIZE */
{
if (page_cnt == 0) /* len < SPI_FLASH_PAGESIZE */
{
ret = prv_spi_flash_write_page(pbuf, loc_addr, len);
CHECK_RET_RETURN(ret);
}
else /* len > SPI_FLASH_PAGESIZE */
{
for (i = 0; i < page_cnt; ++i)
{
ret = prv_spi_flash_write_page(pbuf + i * QSPI_FLASH_PAGESIZE, loc_addr, QSPI_FLASH_PAGESIZE);
CHECK_RET_RETURN(ret);
loc_addr += QSPI_FLASH_PAGESIZE;
}
ret = prv_spi_flash_write_page(pbuf + page_cnt * QSPI_FLASH_PAGESIZE, loc_addr, remain_cnt);
CHECK_RET_RETURN(ret);
}
}
else /* addr is not aligned to SPI_FLASH_PAGESIZE */
{
if (page_cnt == 0) /* len < SPI_FLASH_PAGESIZE */
{
if (remain_cnt > count) /* (len + loc_addr) > SPI_FLASH_PAGESIZE */
{
temp = remain_cnt - count;
ret = prv_spi_flash_write_page(pbuf, loc_addr, count);
CHECK_RET_RETURN(ret);
ret = prv_spi_flash_write_page(pbuf + count, loc_addr + count, temp);
CHECK_RET_RETURN(ret);
}
else
{
ret = prv_spi_flash_write_page(pbuf, loc_addr, len);
CHECK_RET_RETURN(ret);
}
}
else /* len > SPI_FLASH_PAGESIZE */
{
len -= count;
page_cnt = len / QSPI_FLASH_PAGESIZE;
remain_cnt = len % QSPI_FLASH_PAGESIZE;
ret = prv_spi_flash_write_page(pbuf, loc_addr, count);
CHECK_RET_RETURN(ret);
loc_addr += count;
for (i = 0; i < page_cnt; ++i)
{
ret = prv_spi_flash_write_page(pbuf + count + i * QSPI_FLASH_PAGESIZE, loc_addr, QSPI_FLASH_PAGESIZE);
CHECK_RET_RETURN(ret);
loc_addr += QSPI_FLASH_PAGESIZE;
}
if (remain_cnt != 0)
{
ret = prv_spi_flash_write_page(pbuf + count + page_cnt * QSPI_FLASH_PAGESIZE, loc_addr, remain_cnt);
CHECK_RET_RETURN(ret);
}
}
}
*location += len;
return ret;
}
int hal_spi_flash_erase_write(const void* buf, int32_t len, uint32_t location)
{
int ret = 0;
ret = hal_spi_flash_erase(location, len);
CHECK_RET_RETURN(ret);
ret = hal_spi_flash_write(buf, len, &location);
return ret;
}
int hal_spi_flash_read(void* buf, int32_t len, uint32_t location)
{
int ret = 0;
uint8_t* pbuf = (uint8_t*)buf;
if (NULL == pbuf
|| len < 0
|| location > QSPI_FLASH_TOTAL_SIZE
|| len + location > QSPI_FLASH_TOTAL_SIZE)
{
return -1;
}
QSPI_Send_CMD(QSPI_FLASH_FastReadData, location, 8, QSPI_INSTRUCTION_1_LINE, QSPI_ADDRESS_1_LINE, QSPI_ADDRESS_24_BITS, QSPI_DATA_1_LINE);
QSPI_Receive(buf, len);
return ret;
}
int hal_spi_flash_get_id(void)
{
QSPI_CommandTypeDef s_command;
uint8_t temp[3];
uint32_t deviceid;
s_command.InstructionMode = QSPI_INSTRUCTION_1_LINE;
s_command.Instruction = QSPI_FLASH_JedecDeviceID;
s_command.AddressMode = QSPI_ADDRESS_1_LINE;
s_command.AddressSize = QSPI_ADDRESS_24_BITS;
s_command.DataMode = QSPI_DATA_1_LINE;
s_command.AddressMode = QSPI_ADDRESS_NONE;
s_command.AlternateByteMode = QSPI_ALTERNATE_BYTES_NONE;
s_command.DummyCycles = 0;
s_command.NbData = 3;
s_command.DdrMode = QSPI_DDR_MODE_DISABLE;
s_command.DdrHoldHalfCycle = QSPI_DDR_HHC_ANALOG_DELAY;
s_command.SIOOMode = QSPI_SIOO_INST_EVERY_CMD;
HAL_QSPI_Command(&hqspi, &s_command, HAL_QPSI_TIMEOUT_DEFAULT_VALUE);
QSPI_Receive(temp, 3);
deviceid = (temp[1]<<8)|( temp[0]<<16)|(temp[2]);
return deviceid;
}
#endif /* HAL_QSPI_MODULE_ENABLED */

View File

@@ -0,0 +1,23 @@
#ifndef __HAL_SPI_FLASH_H__
#define __HAL_SPI_FLASH_H__
#include <stdint.h>
void hal_spi_flash_config(void);
int hal_spi_flash_erase(uint32_t addr, int32_t len);
int hal_spi_flash_write(const void* buf, int32_t len, uint32_t* location);
int hal_spi_flash_erase_write(const void* buf, int32_t len, uint32_t location);
int hal_spi_flash_read(void* buf, int32_t len, uint32_t location);
int hal_spi_flash_get_id(void);
void hal_spi_flash_power_down(void);
void hal_spi_flash_wake_up(void);
#endif /* _HAL_SPI_FLASH_H_ */

View File

@@ -0,0 +1,40 @@
#include "tos_kv.h"
#include "hal_qspi_flash.h"
#define SECTOR_SIZE 4096 // sector size for qspiflash
#define SECTOR_SIZE_LOG2 12 // 2 ^ 12 = 4096
#define FOR_KV_FLASH_SIZE (2 * SECTOR_SIZE)
#define FOR_KV_FLASH_START 0x0
int stm32l4_qspiflash_read(uint32_t addr, void *buf, size_t len)
{
return hal_spi_flash_read(buf, len, addr);
}
int stm32l4_qspiflash_write(uint32_t addr, const void *buf, size_t len)
{
uint32_t location = addr;
return hal_spi_flash_write(buf, len, &location);
}
int stm32l4_qspiflash_erase(uint32_t addr, size_t size)
{
return hal_spi_flash_erase(addr, size);
}
kv_flash_drv_t stm32l4_qspiflash_drv = {
.write = stm32l4_qspiflash_write,
.read = stm32l4_qspiflash_read,
.erase = stm32l4_qspiflash_erase,
};
kv_flash_prop_t stm32l4_qspiflash_prop = {
.sector_size_log2 = SECTOR_SIZE_LOG2,
.pgm_type = KV_FLASH_PROGRAM_TYPE_BYTE,
.flash_start = FOR_KV_FLASH_START,
.flash_size = FOR_KV_FLASH_SIZE,
};

View File

@@ -0,0 +1,79 @@
/**
******************************************************************************
* File Name : QUADSPI.h
* Description : This file provides code for the configuration
* of the QUADSPI instances.
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2019 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __quadspi_H
#define __quadspi_H
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
#include "stm32l4xx_hal.h"
#include "main.h"
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
extern QSPI_HandleTypeDef hqspi;
/* USER CODE BEGIN Private defines */
/* USER CODE END Private defines */
void MX_QUADSPI_Init(void);
/* USER CODE BEGIN Prototypes */
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /*__ quadspi_H */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

View File

@@ -78,7 +78,7 @@
/*#define HAL_OSPI_MODULE_ENABLED */
/*#define HAL_PCD_MODULE_ENABLED */
/*#define HAL_QSPI_MODULE_ENABLED */
/*#define HAL_QSPI_MODULE_ENABLED */
#define HAL_QSPI_MODULE_ENABLED
/*#define HAL_RNG_MODULE_ENABLED */
#define HAL_RTC_MODULE_ENABLED
/*#define HAL_SAI_MODULE_ENABLED */

View File

@@ -0,0 +1,139 @@
/**
******************************************************************************
* File Name : QUADSPI.c
* Description : This file provides code for the configuration
* of the QUADSPI instances.
******************************************************************************
** This notice applies to any and all portions of this file
* that are not between comment pairs USER CODE BEGIN and
* USER CODE END. Other portions of this file, whether
* inserted by the user or by software development tools
* are owned by their respective copyright owners.
*
* COPYRIGHT(c) 2019 STMicroelectronics
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "quadspi.h"
#include "gpio.h"
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
QSPI_HandleTypeDef hqspi;
/* QUADSPI init function */
void MX_QUADSPI_Init(void)
{
hqspi.Instance = QUADSPI;
hqspi.Init.ClockPrescaler = 0;
hqspi.Init.FifoThreshold = 4;
hqspi.Init.SampleShifting = QSPI_SAMPLE_SHIFTING_HALFCYCLE;
hqspi.Init.FlashSize = 25;
hqspi.Init.ChipSelectHighTime = QSPI_CS_HIGH_TIME_4_CYCLE;
hqspi.Init.ClockMode = QSPI_CLOCK_MODE_0;
hqspi.Init.FlashID = QSPI_FLASH_ID_1;
hqspi.Init.DualFlash = QSPI_DUALFLASH_DISABLE;
if (HAL_QSPI_Init(&hqspi) != HAL_OK)
{
return;
}
}
void HAL_QSPI_MspInit(QSPI_HandleTypeDef* qspiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspInit 0 */
/* USER CODE END QUADSPI_MspInit 0 */
/* QUADSPI clock enable */
__HAL_RCC_QSPI_CLK_ENABLE();
/**QUADSPI GPIO Configuration
PB0 ------> QUADSPI_BK1_IO1
PB1 ------> QUADSPI_BK1_IO0
PB10 ------> QUADSPI_CLK
PB11 ------> QUADSPI_BK1_NCS
*/
GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF10_QUADSPI;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/* USER CODE BEGIN QUADSPI_MspInit 1 */
/* USER CODE END QUADSPI_MspInit 1 */
}
}
void HAL_QSPI_MspDeInit(QSPI_HandleTypeDef* qspiHandle)
{
if(qspiHandle->Instance==QUADSPI)
{
/* USER CODE BEGIN QUADSPI_MspDeInit 0 */
/* USER CODE END QUADSPI_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_QSPI_CLK_DISABLE();
/**QUADSPI GPIO Configuration
PB0 ------> QUADSPI_BK1_IO1
PB1 ------> QUADSPI_BK1_IO0
PB10 ------> QUADSPI_CLK
PB11 ------> QUADSPI_BK1_NCS
*/
HAL_GPIO_DeInit(GPIOB, GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_10|GPIO_PIN_11);
/* USER CODE BEGIN QUADSPI_MspDeInit 1 */
/* USER CODE END QUADSPI_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/**
* @}
*/
/**
* @}
*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/