From 0d09f6d788bb4efd37a447b5276a4bf93871421b Mon Sep 17 00:00:00 2001 From: bcostm Date: Tue, 12 Dec 2017 16:52:32 +0100 Subject: [PATCH 1/5] STM32F3: add Flash api --- .../TARGET_STM32F3/common_objects.h | 7 + targets/TARGET_STM/TARGET_STM32F3/flash_api.c | 173 ++++++++++++++++++ 2 files changed, 180 insertions(+) create mode 100644 targets/TARGET_STM/TARGET_STM32F3/flash_api.c diff --git a/targets/TARGET_STM/TARGET_STM32F3/common_objects.h b/targets/TARGET_STM/TARGET_STM32F3/common_objects.h index ba731890ce5..590b60d94c6 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/common_objects.h +++ b/targets/TARGET_STM/TARGET_STM32F3/common_objects.h @@ -132,6 +132,13 @@ struct can_s { }; #endif +#if DEVICE_FLASH +struct flash_s { + /* nothing to be stored for now */ + uint32_t dummy; +}; +#endif + #include "gpio_object.h" #ifdef __cplusplus diff --git a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c new file mode 100644 index 00000000000..459294d045f --- /dev/null +++ b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c @@ -0,0 +1,173 @@ +/* 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" + +#define NUM_PAGES_IN_SECTOR (1U) +#define FLASH_SIZE (uint32_t)(*((uint16_t *)FLASHSIZE_BASE) * 1024U) + +int32_t flash_init(flash_t *obj) +{ + return 0; +} + +int32_t flash_free(flash_t *obj) +{ + return 0; +} + +static int32_t flash_unlock(void) +{ + /* Allow Access to Flash control registers and user Falsh */ + if (HAL_FLASH_Unlock()) { + return -1; + } else { + return 0; + } +} + +static int32_t flash_lock(void) +{ + /* Disable the Flash option control register access (recommended to protect + the option Bytes against possible unwanted operations) */ + if (HAL_FLASH_Lock()) { + return -1; + } else { + return 0; + } +} + +int32_t flash_erase_sector(flash_t *obj, uint32_t address) +{ + uint32_t PAGEError = 0; + FLASH_EraseInitTypeDef EraseInitStruct; + int32_t status = 0; + + if (!(IS_FLASH_PROGRAM_ADDRESS(address))) { + return -1; + } + + if (flash_unlock() != HAL_OK) { + return -1; + } + + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR); + /* MBED HAL erases 1 sector at a time */ + /* Fill EraseInit structure*/ + EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; + EraseInitStruct.PageAddress = address; + EraseInitStruct.NbPages = NUM_PAGES_IN_SECTOR; + + /* 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) { + status = -1; + } + + flash_lock(); + + return status; + +} + +int32_t flash_program_page(flash_t *obj, uint32_t address, + const uint8_t *data, uint32_t size) +{ + uint32_t StartAddress = 0; + int32_t status = 0; + + if (!(IS_FLASH_PROGRAM_ADDRESS(address))) { + return -1; + } + + if ((size % 4) != 0) { + /* F3 flash devices can only be programmed 32bits/4 bytes at a time */ + return -1; + } + + if (flash_unlock() != HAL_OK) { + 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 uint32_t data32; + while (address < (StartAddress + size) && (status == 0)) { + for (uint8_t i =0; i < 4; i++) { + *(((uint8_t *) &data32) + i) = *(data + i); + } + + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data32) == HAL_OK) { + address = address + 4; + data = data + 4; + } else { + status = -1; + } + } + } else { /* case where data is aligned, so let's avoid any copy */ + while ((address < (StartAddress + size)) && (status == 0)) { + if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *((uint32_t*) data)) == HAL_OK) { + address = address + 4; + data = data + 4; + } else { + status = -1; + } + } + } + + flash_lock(); + + return status; +} + +uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) +{ + if (!(IS_FLASH_PROGRAM_ADDRESS(address))) { + return MBED_FLASH_INVALID_SIZE; + } else { + return (NUM_PAGES_IN_SECTOR * FLASH_PAGE_SIZE); + } +} + +uint32_t flash_get_page_size(const flash_t *obj) +{ + /* Page size is the minimum programmable size, which is 4 bytes */ + return 4; +} + +uint32_t flash_get_start_address(const flash_t *obj) +{ + return FLASH_BASE; +} + +uint32_t flash_get_size(const flash_t *obj) +{ + return FLASH_SIZE; +} + +#endif From 92394e4f13dc45c6ab09f8a8a987254116728029 Mon Sep 17 00:00:00 2001 From: bcostm Date: Tue, 12 Dec 2017 17:09:22 +0100 Subject: [PATCH 2/5] STM32F303xE: add FLASH support in targets.json --- targets/targets.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/targets/targets.json b/targets/targets.json index a9f032c925c..48cbbfd9642 100644 --- a/targets/targets.json +++ b/targets/targets.json @@ -959,7 +959,7 @@ } }, "detect_code": ["0745"], - "device_has_add": ["ANALOGOUT", "CAN", "LOWPOWERTIMER", "SERIAL_ASYNCH", "SERIAL_FC"], + "device_has_add": ["ANALOGOUT", "CAN", "LOWPOWERTIMER", "SERIAL_ASYNCH", "SERIAL_FC", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32F303RE" }, @@ -976,7 +976,7 @@ } }, "detect_code": ["0747"], - "device_has_add": ["ANALOGOUT", "CAN", "LOWPOWERTIMER"], + "device_has_add": ["ANALOGOUT", "CAN", "LOWPOWERTIMER", "FLASH"], "release_versions": ["2", "5"], "device_name": "STM32F303ZE" }, From b5324cae32af013b1f58c85e61899c0cf479e300 Mon Sep 17 00:00:00 2001 From: bcostm Date: Wed, 13 Dec 2017 09:59:49 +0100 Subject: [PATCH 3/5] STM32F3: flash_api typos --- targets/TARGET_STM/TARGET_STM32F3/flash_api.c | 84 +++++++++++++++---- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c index 459294d045f..9827f94507b 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c +++ b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c @@ -21,14 +21,28 @@ #include "mbed_assert.h" #include "cmsis.h" -#define NUM_PAGES_IN_SECTOR (1U) -#define FLASH_SIZE (uint32_t)(*((uint16_t *)FLASHSIZE_BASE) * 1024U) +#ifndef FLASH_SIZE +#define FLASH_SIZE (uint32_t)(*((uint16_t *)FLASHSIZE_BASE) * 1024U) +#endif + +// Minimum number of bytes to be programmed at a time +#define MIN_PROG_SIZE (4U) +/** 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) { 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) { return 0; @@ -55,6 +69,13 @@ static int32_t flash_lock(void) } } +/** 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 PAGEError = 0; @@ -70,11 +91,12 @@ int32_t flash_erase_sector(flash_t *obj, uint32_t address) } __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR); + /* MBED HAL erases 1 sector at a time */ /* Fill EraseInit structure*/ EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES; EraseInitStruct.PageAddress = address; - EraseInitStruct.NbPages = NUM_PAGES_IN_SECTOR; + 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 @@ -88,9 +110,19 @@ int32_t flash_erase_sector(flash_t *obj, uint32_t address) flash_lock(); return status; - } +/** 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) { @@ -101,8 +133,7 @@ int32_t flash_program_page(flash_t *obj, uint32_t address, return -1; } - if ((size % 4) != 0) { - /* F3 flash devices can only be programmed 32bits/4 bytes at a time */ + if ((size % MIN_PROG_SIZE) != 0) { return -1; } @@ -113,18 +144,18 @@ int32_t flash_program_page(flash_t *obj, uint32_t address, /* Program the user Flash area word by word */ StartAddress = address; - /* HW needs an aligned address to program flash, which data - * parameters doesn't ensure */ + /* HW needs an aligned address to program flash, which data parameter doesn't ensure */ if ((uint32_t) data % 4 != 0) { + volatile uint32_t data32; while (address < (StartAddress + size) && (status == 0)) { - for (uint8_t i =0; i < 4; i++) { + for (uint8_t i = 0; i < MIN_PROG_SIZE; i++) { *(((uint8_t *) &data32) + i) = *(data + i); } if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, data32) == HAL_OK) { - address = address + 4; - data = data + 4; + address = address + MIN_PROG_SIZE; + data = data + MIN_PROG_SIZE; } else { status = -1; } @@ -132,8 +163,8 @@ int32_t flash_program_page(flash_t *obj, uint32_t address, } else { /* case where data is aligned, so let's avoid any copy */ while ((address < (StartAddress + size)) && (status == 0)) { if (HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, *((uint32_t*) data)) == HAL_OK) { - address = address + 4; - data = data + 4; + address = address + MIN_PROG_SIZE; + data = data + MIN_PROG_SIZE; } else { status = -1; } @@ -145,26 +176,47 @@ int32_t flash_program_page(flash_t *obj, uint32_t address, return status; } +/** Get sector size + * + * @param obj The flash object + * @param address The sector starting address + * @return The size of a sector (in our case considering 1 sector = 1 page) + */ uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) { if (!(IS_FLASH_PROGRAM_ADDRESS(address))) { return MBED_FLASH_INVALID_SIZE; } else { - return (NUM_PAGES_IN_SECTOR * FLASH_PAGE_SIZE); + return FLASH_PAGE_SIZE; } } +/** Get page size + * + * @param obj The flash object + * @param address The page starting address + * @return The size of a page (in our case the minimum programmable size) + */ uint32_t flash_get_page_size(const flash_t *obj) { - /* Page size is the minimum programmable size, which is 4 bytes */ - return 4; + return MIN_PROG_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; From 563338ad58df3ec6f81d4724dd0572859efcd0bb Mon Sep 17 00:00:00 2001 From: bcostm Date: Wed, 13 Dec 2017 10:10:30 +0100 Subject: [PATCH 4/5] STM32F3: reset PGERR flash flag --- targets/TARGET_STM/TARGET_STM32F3/flash_api.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c index 9827f94507b..27e42a3c1b1 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c +++ b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c @@ -90,7 +90,8 @@ int32_t flash_erase_sector(flash_t *obj, uint32_t address) return -1; } - __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR); + // Clear Flash status register's flags + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_PGERR); /* MBED HAL erases 1 sector at a time */ /* Fill EraseInit structure*/ From 8203a8ddf5ad661675bba8dfa4b1712c210ddbf3 Mon Sep 17 00:00:00 2001 From: bcostm Date: Mon, 18 Dec 2017 10:21:53 +0100 Subject: [PATCH 5/5] STM32F3: Remove flash functions doc + typos --- targets/TARGET_STM/TARGET_STM32F3/flash_api.c | 81 ++++--------------- 1 file changed, 15 insertions(+), 66 deletions(-) diff --git a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c index 27e42a3c1b1..9a2d7c4c8ef 100644 --- a/targets/TARGET_STM/TARGET_STM32F3/flash_api.c +++ b/targets/TARGET_STM/TARGET_STM32F3/flash_api.c @@ -28,29 +28,9 @@ // Minimum number of bytes to be programmed at a time #define MIN_PROG_SIZE (4U) -/** 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) -{ - 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) -{ - return 0; -} - static int32_t flash_unlock(void) { - /* Allow Access to Flash control registers and user Falsh */ + /* Allow Access to Flash control registers and user Flash */ if (HAL_FLASH_Unlock()) { return -1; } else { @@ -69,13 +49,16 @@ static int32_t flash_lock(void) } } -/** 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_init(flash_t *obj) +{ + return 0; +} + +int32_t flash_free(flash_t *obj) +{ + return 0; +} + int32_t flash_erase_sector(flash_t *obj, uint32_t address) { uint32_t PAGEError = 0; @@ -113,19 +96,7 @@ int32_t flash_erase_sector(flash_t *obj, uint32_t address) return status; } -/** 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) +int32_t flash_program_page(flash_t *obj, uint32_t address, const uint8_t *data, uint32_t size) { uint32_t StartAddress = 0; int32_t status = 0; @@ -177,13 +148,7 @@ int32_t flash_program_page(flash_t *obj, uint32_t address, return status; } -/** Get sector size - * - * @param obj The flash object - * @param address The sector starting address - * @return The size of a sector (in our case considering 1 sector = 1 page) - */ -uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) +uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) { if (!(IS_FLASH_PROGRAM_ADDRESS(address))) { return MBED_FLASH_INVALID_SIZE; @@ -192,33 +157,17 @@ uint32_t flash_get_sector_size(const flash_t *obj, uint32_t address) } } -/** Get page size - * - * @param obj The flash object - * @param address The page starting address - * @return The size of a page (in our case the minimum programmable size) - */ uint32_t flash_get_page_size(const flash_t *obj) { return MIN_PROG_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) +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) +uint32_t flash_get_size(const flash_t *obj) { return FLASH_SIZE; }