diff --git a/targets/TARGET_STM/TARGET_STM32L4/common_objects.h b/targets/TARGET_STM/TARGET_STM32L4/common_objects.h index 268b8ead01..22fc902c83 100644 --- a/targets/TARGET_STM/TARGET_STM32L4/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32L4/common_objects.h @@ -111,6 +111,11 @@ struct i2c_s { #endif }; +struct flash_s { + /* nothing to be stored for now */ + uint32_t dummy; +}; + #include "gpio_object.h" #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32L4/flash_api.c b/targets/TARGET_STM/TARGET_STM32L4/flash_api.c new file mode 100644 index 0000000000..1dd5b224cf --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32L4/flash_api.c @@ -0,0 +1,246 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "flash_api.h" +#include "mbed_critical.h" + +#if DEVICE_FLASH +#include "mbed_assert.h" +#include "cmsis.h" + +/** + * @brief Gets the page of a given address + * @param Addr: Address of the FLASH Memory + * @retval The page of a given address + */ +static uint32_t GetPage(uint32_t Addr) +{ + uint32_t page = 0; + + if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + /* Bank 1 */ + page = (Addr - FLASH_BASE) / FLASH_PAGE_SIZE; + } else { + /* Bank 2 */ + page = (Addr - (FLASH_BASE + FLASH_BANK_SIZE)) / FLASH_PAGE_SIZE; + } + + return page; +} + +/** + * @brief Gets the bank of a given address + * @param Addr: Address of the FLASH Memory + * @retval The bank of a given address + */ +static uint32_t GetBank(uint32_t Addr) +{ + uint32_t bank = 0; +#if defined(SYSCFG_MEMRMP_FB_MODE) + if (READ_BIT(SYSCFG->MEMRMP, SYSCFG_MEMRMP_FB_MODE) == 0) { + /* No Bank swap */ + if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + bank = FLASH_BANK_1; + } else { + bank = FLASH_BANK_2; + } + } else { + /* Bank swap */ + if (Addr < (FLASH_BASE + FLASH_BANK_SIZE)) { + bank = FLASH_BANK_2; + } else { + bank = FLASH_BANK_1; + } + } +#else + /* Device like L432KC */ + bank = FLASH_BANK_1; +#endif + + return bank; +} + +/** Initialize the flash peripheral and the flash_t object + * + * @param obj The flash object + * @return 0 for success, -1 for error + */ +int32_t flash_init(flash_t *obj) +{ + /* Unlock the Flash to enable the flash control register access *************/ + HAL_FLASH_Unlock(); + return 0; +} + +/** Uninitialize the flash peripheral and the flash_t object + * + * @param obj The flash object + * @return 0 for success, -1 for error + */ +int32_t flash_free(flash_t *obj) +{ + /* Lock the Flash to disable the flash control register access (recommended + * to protect the FLASH memory against possible unwanted operation) *********/ + HAL_FLASH_Lock(); + return 0; +} + +/** Erase one sector starting at defined address + * + * The address should be at sector boundary. This function does not do any check for address alignments + * @param obj The flash object + * @param address The sector starting address + * @return 0 for success, -1 for error + */ +int32_t flash_erase_sector(flash_t *obj, uint32_t address) +{ + uint32_t FirstPage = 0, BankNumber = 0; + uint32_t PAGEError = 0; + FLASH_EraseInitTypeDef EraseInitStruct; + + if ((address >= (FLASH_BASE + FLASH_SIZE)) || (address < FLASH_BASE)) { + + return -1; + } + + /* Clear OPTVERR bit set on virgin samples */ + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_OPTVERR); + /* Get the 1st page to erase */ + FirstPage = GetPage(address); + /* MBED HAL erases 1 page / sector at a time */ + /* Get the bank */ + BankNumber = GetBank(address); + /* Fill EraseInit structure*/ + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.Banks = BankNumber; + EraseInitStruct.Page = FirstPage; + EraseInitStruct.NbPages = 1; + + /* Note: If an erase operation in Flash memory also concerns data in the data or instruction cache, + you have to make sure that these data are rewritten before they are accessed during code + execution. If this cannot be done safely, it is recommended to flush the caches by setting the + DCRST and ICRST bits in the FLASH_CR register. */ + + if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK) { + return -1; + } else { + return 0; + } +} + +/** Program one page starting at defined address + * + * The page should be at page boundary, should not cross multiple sectors. + * This function does not do any check for address alignments or if size + * is aligned to a page size. + * @param obj The flash object + * @param address The sector starting address + * @param data The data buffer to be programmed + * @param size The number of bytes to program + * @return 0 for success, -1 for error + */ +int32_t flash_program_page(flash_t *obj, uint32_t address, + const uint8_t *data, uint32_t size) +{ + uint32_t StartAddress = 0; + + if ((address >= (FLASH_BASE + FLASH_SIZE)) || (address < FLASH_BASE)) { + return -1; + } + + if ((size % 8) != 0) { + /* L4 flash devices can only be programmed 64bits/8 bytes at a time */ + return -1; + } + + /* Program the user Flash area word by word */ + StartAddress = address; + + /* HW needs an aligned address to program flash, which data + * parameters doesn't ensure */ + if ((uint32_t) data % 4 != 0) { + volatile uint64_t data64; + while (address < (StartAddress + size)) { + for (uint8_t i =0; i < 8; i++) { + *(((uint8_t *) &data64) + i) = *(data + i); + } + + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, data64) == HAL_OK) { + address = address + 8; + data = data + 8; + } else { + return -1; + } + } + } else { /* case where data is aligned, so let's avoid any copy */ + while (address < (StartAddress + size)) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, address, *((uint64_t*) data)) == HAL_OK) { + address = address + 8; + data = data + 8; + } else { + return -1; + } + } + } + + return 0; +} + +/** Get sector size + * + * @param obj The flash object + * @param address The sector starting address + * @return The size of a sector + */ +uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) { + /* considering 1 sector = 1 page */ + if ((address >= (FLASH_BASE + FLASH_SIZE)) || (address < FLASH_BASE)) { + return MBED_FLASH_INVALID_SIZE; + } else { + return FLASH_PAGE_SIZE; + } +} + +/** Get page size + * + * @param obj The flash object + * @param address The page starting address + * @return The size of a page + */ +uint32_t flash_get_page_size(const flash_t *obj) { + /* considering 1 sector = 1 page */ + return FLASH_PAGE_SIZE; +} + +/** Get start address for the flash region + * + * @param obj The flash object + * @return The start address for the flash region + */ +uint32_t flash_get_start_address(const flash_t *obj) { + return FLASH_BASE; +} + +/** Get the flash region size + * + * @param obj The flash object + * @return The flash region size + */ +uint32_t flash_get_size(const flash_t *obj) { + return FLASH_SIZE; +} + +#endif diff --git a/targets/targets.json b/targets/targets.json index 084a08fb06..7c73779e19 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -1136,7 +1136,7 @@ "inherits": ["Target"], "detect_code": ["0770"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2"], - "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "CAN", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "CAN", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32L432KC" }, @@ -1149,7 +1149,7 @@ "inherits": ["Target"], "detect_code": ["0765"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2","USBHOST_OTHER"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32L476RG", "bootloader_supported": true @@ -1163,7 +1163,7 @@ "inherits": ["Target"], "detect_code": ["0827"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2","USBHOST_OTHER"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_ASYNCH", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32L486RG" }, @@ -1329,7 +1329,7 @@ "supported_toolchains": ["ARM", "uARM", "IAR", "GCC_ARM"], "detect_code": ["0820"], "macros": ["TRANSACTION_QUEUE_SIZE_SPI=2", "USBHOST_OTHER"], - "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG"], + "device_has": ["ANALOGIN", "ANALOGOUT", "CAN", "I2C", "I2CSLAVE", "I2C_ASYNCH", "INTERRUPTIN", "LOWPOWERTIMER", "PORTIN", "PORTINOUT", "PORTOUT", "PWMOUT", "RTC", "SERIAL", "SERIAL_FC", "SLEEP", "SPI", "SPISLAVE", "SPI_ASYNCH", "STDIO_MESSAGES", "TRNG", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32L476VG" },