diff --git a/cpu/efm32/Makefile.features b/cpu/efm32/Makefile.features index 8ea9c65488..71e0b814c2 100644 --- a/cpu/efm32/Makefile.features +++ b/cpu/efm32/Makefile.features @@ -2,6 +2,7 @@ include $(RIOTCPU)/efm32/efm32-features.mk FEATURES_PROVIDED += periph_cpuid FEATURES_PROVIDED += periph_flashpage +FEATURES_PROVIDED += periph_flashpage_raw FEATURES_CONFLICT += periph_rtc:periph_rtt FEATURES_CONFLICT_MSG += "On the EFM32, the RTC and RTT map to the same hardware peripheral." diff --git a/cpu/efm32/include/cpu_conf.h b/cpu/efm32/include/cpu_conf.h index 1c8d4748e9..61f2f967d5 100644 --- a/cpu/efm32/include/cpu_conf.h +++ b/cpu/efm32/include/cpu_conf.h @@ -45,6 +45,12 @@ extern "C" { */ #define FLASHPAGE_SIZE (FLASH_PAGE_SIZE) #define FLASHPAGE_NUMOF (FLASH_SIZE / FLASH_PAGE_SIZE) +/* The minimum block size which can be written is 4B. However, the erase + * block is always FLASHPAGE_SIZE. + */ +#define FLASHPAGE_RAW_BLOCKSIZE (4U) +/* Writing should be always 4 bytes aligned */ +#define FLASHPAGE_RAW_ALIGNMENT (4U) /** @} */ #ifdef __cplusplus diff --git a/cpu/efm32/periph/flashpage.c b/cpu/efm32/periph/flashpage.c index fdce123ded..ed3ac4590f 100644 --- a/cpu/efm32/periph/flashpage.c +++ b/cpu/efm32/periph/flashpage.c @@ -26,19 +26,41 @@ #include "em_msc.h" +void flashpage_write_raw(void *target_addr, const void *data, size_t len) +{ + /* assert multiples of FLASHPAGE_RAW_BLOCKSIZE are written and no less of + that length. */ + assert(!(len % FLASHPAGE_RAW_BLOCKSIZE)); + + /* ensure writes are aligned */ + assert(!(((unsigned)target_addr % FLASHPAGE_RAW_ALIGNMENT) || + ((unsigned)data % FLASHPAGE_RAW_ALIGNMENT))); + + /* ensure the length doesn't exceed the actual flash size */ + assert(((unsigned)target_addr + len) < + (CPU_FLASH_BASE + (FLASHPAGE_SIZE * FLASHPAGE_NUMOF)) + 1); + + uint32_t *page_addr = target_addr; + const uint32_t *data_addr = data; + + MSC_Init(); + MSC_WriteWord(page_addr, data_addr, len); + MSC_Deinit(); +} + void flashpage_write(int page, const void *data) { assert(page < (int)FLASHPAGE_NUMOF); uint32_t *page_addr = (uint32_t *)flashpage_addr(page); - const uint32_t *data_addr = data; + /* erase given page */ MSC_Init(); MSC_ErasePage(page_addr); - - if (data != NULL) { - MSC_WriteWord(page_addr, data_addr, FLASHPAGE_SIZE); - } - MSC_Deinit(); + + /* write data to page */ + if (data != NULL) { + flashpage_write_raw(page_addr, data, FLASHPAGE_SIZE); + } }