From 205837c47b14cb242d7e75469fe4ecd056dd29ce Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Thu, 11 Feb 2021 12:48:36 +0530 Subject: nvm implementation for rp2040 --- ports/raspberrypi/common-hal/nvm/ByteArray.c | 72 ++++++++++++++++++++++++++++ ports/raspberrypi/common-hal/nvm/ByteArray.h | 38 +++++++++++++++ ports/raspberrypi/common-hal/nvm/__init__.c | 1 + ports/raspberrypi/mpconfigport.h | 9 ++-- ports/raspberrypi/mpconfigport.mk | 2 +- 5 files changed, 117 insertions(+), 5 deletions(-) create mode 100644 ports/raspberrypi/common-hal/nvm/ByteArray.c create mode 100644 ports/raspberrypi/common-hal/nvm/ByteArray.h create mode 100644 ports/raspberrypi/common-hal/nvm/__init__.c diff --git a/ports/raspberrypi/common-hal/nvm/ByteArray.c b/ports/raspberrypi/common-hal/nvm/ByteArray.c new file mode 100644 index 000000000..2aef1a09f --- /dev/null +++ b/ports/raspberrypi/common-hal/nvm/ByteArray.c @@ -0,0 +1,72 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "common-hal/nvm/ByteArray.h" + +#include + +#include "py/runtime.h" +#include "src/rp2_common/hardware_flash/include/hardware/flash.h" + +uint32_t common_hal_nvm_bytearray_get_length(nvm_bytearray_obj_t* self) { + return self->len; +} + +static void write_page(uint32_t page_addr, uint32_t offset, uint32_t len, uint8_t* bytes) { + // Write a whole page to flash, buffering it first and then erasing and rewriting + // it since we can only clear a whole page at a time. + if (offset == 0 && len == FLASH_PAGE_SIZE) { + flash_range_program(page_addr - 0x10000000, bytes, FLASH_PAGE_SIZE); + } else { + uint8_t buffer[FLASH_PAGE_SIZE]; + memcpy(buffer, (uint8_t*) page_addr, FLASH_PAGE_SIZE); + memcpy(buffer + offset, bytes, len); + flash_range_program(page_addr - 0x10000000, buffer, FLASH_PAGE_SIZE); + } +} + +bool common_hal_nvm_bytearray_set_bytes(nvm_bytearray_obj_t* self, + uint32_t start_index, uint8_t* values, uint32_t len) { + uint32_t address = (uint32_t) self->start_address + start_index; + uint32_t offset = address % FLASH_PAGE_SIZE; + uint32_t page_addr = address - offset; + + while (len) { + uint32_t write_len = MIN(len, FLASH_PAGE_SIZE - offset); + write_page(page_addr, offset, write_len, values); + len -= write_len; + values += write_len; + page_addr += FLASH_PAGE_SIZE; + offset = 0; + } + + return true; +} + +void common_hal_nvm_bytearray_get_bytes(nvm_bytearray_obj_t* self, + uint32_t start_index, uint32_t len, uint8_t* values) { + memcpy(values, self->start_address + start_index, len); +} diff --git a/ports/raspberrypi/common-hal/nvm/ByteArray.h b/ports/raspberrypi/common-hal/nvm/ByteArray.h new file mode 100644 index 000000000..a2a904fea --- /dev/null +++ b/ports/raspberrypi/common-hal/nvm/ByteArray.h @@ -0,0 +1,38 @@ +/* + * This file is part of the MicroPython project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2020 microDev + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#ifndef MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_NVM_BYTEARRAY_H +#define MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_NVM_BYTEARRAY_H + +#include "py/obj.h" + +typedef struct { + mp_obj_base_t base; + uint8_t * start_address; + uint32_t len; +} nvm_bytearray_obj_t; + +#endif // MICROPY_INCLUDED_RASPBERRYPI_COMMON_HAL_NVM_BYTEARRAY_H diff --git a/ports/raspberrypi/common-hal/nvm/__init__.c b/ports/raspberrypi/common-hal/nvm/__init__.c new file mode 100644 index 000000000..1b702a158 --- /dev/null +++ b/ports/raspberrypi/common-hal/nvm/__init__.c @@ -0,0 +1 @@ +// No nvm module functions. diff --git a/ports/raspberrypi/mpconfigport.h b/ports/raspberrypi/mpconfigport.h index 77d1ff080..d57f1c575 100644 --- a/ports/raspberrypi/mpconfigport.h +++ b/ports/raspberrypi/mpconfigport.h @@ -27,15 +27,16 @@ #ifndef __INCLUDED_MPCONFIGPORT_H #define __INCLUDED_MPCONFIGPORT_H -#define MICROPY_PY_SYS_PLATFORM "RP2040" +#define MICROPY_PY_SYS_PLATFORM "RP2040" -#define CIRCUITPY_INTERNAL_NVM_SIZE 0 +#define CIRCUITPY_INTERNAL_NVM_SIZE (4*1024) +#define CIRCUITPY_INTERNAL_NVM_START_ADDR (0x100FF000) -#define CIRCUITPY_DEFAULT_STACK_SIZE (24*1024) +#define CIRCUITPY_DEFAULT_STACK_SIZE (24*1024) #define MICROPY_USE_INTERNAL_PRINTF (1) -#define CIRCUITPY_PROCESSOR_COUNT (2) +#define CIRCUITPY_PROCESSOR_COUNT (2) // This also includes mpconfigboard.h. #include "py/circuitpy_mpconfig.h" diff --git a/ports/raspberrypi/mpconfigport.mk b/ports/raspberrypi/mpconfigport.mk index 8681e2994..5477d7f1b 100644 --- a/ports/raspberrypi/mpconfigport.mk +++ b/ports/raspberrypi/mpconfigport.mk @@ -32,7 +32,7 @@ CIRCUITPY_AUDIOMP3 = 0 CIRCUITPY_COUNTIO = 0 # Use PWM interally CIRCUITPY_FREQUENCYIO = 0 # Use PWM interally CIRCUITPY_I2CPERIPHERAL = 0 -CIRCUITPY_NVM = 0 +CIRCUITPY_NVM = 1 CIRCUITPY_PULSEIO = 0 # Use PIO interally CIRCUITPY_ROTARYIO = 0 # Use PIO interally CIRCUITPY_WATCHDOG = 1 -- cgit v1.2.3 From 527b11f99e2d060f48b6485081f2c0618ce72cc5 Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Fri, 12 Feb 2021 18:28:48 +0530 Subject: implement suggested changes - update FLASH_FIRMWARE length - use linker script define value --- ports/raspberrypi/common-hal/nvm/ByteArray.c | 6 ++++-- ports/raspberrypi/link.ld | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ports/raspberrypi/common-hal/nvm/ByteArray.c b/ports/raspberrypi/common-hal/nvm/ByteArray.c index 2aef1a09f..6dbd21351 100644 --- a/ports/raspberrypi/common-hal/nvm/ByteArray.c +++ b/ports/raspberrypi/common-hal/nvm/ByteArray.c @@ -31,6 +31,8 @@ #include "py/runtime.h" #include "src/rp2_common/hardware_flash/include/hardware/flash.h" +extern uint32_t __flash_binary_start; + uint32_t common_hal_nvm_bytearray_get_length(nvm_bytearray_obj_t* self) { return self->len; } @@ -39,12 +41,12 @@ static void write_page(uint32_t page_addr, uint32_t offset, uint32_t len, uint8_ // Write a whole page to flash, buffering it first and then erasing and rewriting // it since we can only clear a whole page at a time. if (offset == 0 && len == FLASH_PAGE_SIZE) { - flash_range_program(page_addr - 0x10000000, bytes, FLASH_PAGE_SIZE); + flash_range_program(page_addr - (uint32_t) &__flash_binary_start, bytes, FLASH_PAGE_SIZE); } else { uint8_t buffer[FLASH_PAGE_SIZE]; memcpy(buffer, (uint8_t*) page_addr, FLASH_PAGE_SIZE); memcpy(buffer + offset, bytes, len); - flash_range_program(page_addr - 0x10000000, buffer, FLASH_PAGE_SIZE); + flash_range_program(page_addr - (uint32_t) &__flash_binary_start, buffer, FLASH_PAGE_SIZE); } } diff --git a/ports/raspberrypi/link.ld b/ports/raspberrypi/link.ld index b83299dee..653408d4e 100644 --- a/ports/raspberrypi/link.ld +++ b/ports/raspberrypi/link.ld @@ -23,7 +23,7 @@ MEMORY { - FLASH_FIRMWARE (rx) : ORIGIN = 0x10000000, LENGTH = 1024k + FLASH_FIRMWARE (rx) : ORIGIN = 0x10000000, LENGTH = 1020k RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 256k SCRATCH_X (rwx) : ORIGIN = 0x20040000, LENGTH = 4k SCRATCH_Y (rwx) : ORIGIN = 0x20041000, LENGTH = 4k -- cgit v1.2.3 From 696d212dc70e01b9b51b7a19f344338ed387d69b Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Thu, 18 Feb 2021 18:42:00 +0530 Subject: fix nvm rewrite --- ports/raspberrypi/common-hal/nvm/ByteArray.c | 41 ++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 9 deletions(-) diff --git a/ports/raspberrypi/common-hal/nvm/ByteArray.c b/ports/raspberrypi/common-hal/nvm/ByteArray.c index 6dbd21351..5d1147425 100644 --- a/ports/raspberrypi/common-hal/nvm/ByteArray.c +++ b/ports/raspberrypi/common-hal/nvm/ByteArray.c @@ -32,26 +32,54 @@ #include "src/rp2_common/hardware_flash/include/hardware/flash.h" extern uint32_t __flash_binary_start; +static const uint32_t flash_binary_start = (uint32_t) &__flash_binary_start; + +#define RMV_OFFSET(addr) addr - flash_binary_start uint32_t common_hal_nvm_bytearray_get_length(nvm_bytearray_obj_t* self) { return self->len; } static void write_page(uint32_t page_addr, uint32_t offset, uint32_t len, uint8_t* bytes) { - // Write a whole page to flash, buffering it first and then erasing and rewriting - // it since we can only clear a whole page at a time. + // Write a whole page to flash, buffering it first and then erasing and rewriting it + // since we can only write a whole page at a time. if (offset == 0 && len == FLASH_PAGE_SIZE) { - flash_range_program(page_addr - (uint32_t) &__flash_binary_start, bytes, FLASH_PAGE_SIZE); + flash_range_program(RMV_OFFSET(page_addr), bytes, FLASH_PAGE_SIZE); } else { uint8_t buffer[FLASH_PAGE_SIZE]; memcpy(buffer, (uint8_t*) page_addr, FLASH_PAGE_SIZE); memcpy(buffer + offset, bytes, len); - flash_range_program(page_addr - (uint32_t) &__flash_binary_start, buffer, FLASH_PAGE_SIZE); + flash_range_program(RMV_OFFSET(page_addr), buffer, FLASH_PAGE_SIZE); } } +static void write_sector(uint32_t address, uint32_t len, uint8_t* bytes) { + // Write a whole sector to flash, buffering it first and then erasing and rewriting it + // since we can only erase a whole sector at a time. + uint8_t buffer[FLASH_SECTOR_SIZE]; + memcpy(buffer, (uint8_t*) CIRCUITPY_INTERNAL_NVM_START_ADDR, FLASH_SECTOR_SIZE); + memcpy(buffer + address, bytes, len); + flash_range_erase(RMV_OFFSET(CIRCUITPY_INTERNAL_NVM_START_ADDR), FLASH_SECTOR_SIZE); + flash_range_program(RMV_OFFSET(CIRCUITPY_INTERNAL_NVM_START_ADDR), buffer, FLASH_SECTOR_SIZE); +} + +void common_hal_nvm_bytearray_get_bytes(nvm_bytearray_obj_t* self, + uint32_t start_index, uint32_t len, uint8_t* values) { + memcpy(values, self->start_address + start_index, len); +} + bool common_hal_nvm_bytearray_set_bytes(nvm_bytearray_obj_t* self, uint32_t start_index, uint8_t* values, uint32_t len) { + uint8_t values_in[len]; + common_hal_nvm_bytearray_get_bytes(self, start_index, len, values_in); + + for (uint32_t i = 0; i < len; i++) { + if (values_in[i] != UINT8_MAX) { + write_sector(start_index, len, values); + return true; + } + } + uint32_t address = (uint32_t) self->start_address + start_index; uint32_t offset = address % FLASH_PAGE_SIZE; uint32_t page_addr = address - offset; @@ -67,8 +95,3 @@ bool common_hal_nvm_bytearray_set_bytes(nvm_bytearray_obj_t* self, return true; } - -void common_hal_nvm_bytearray_get_bytes(nvm_bytearray_obj_t* self, - uint32_t start_index, uint32_t len, uint8_t* values) { - memcpy(values, self->start_address + start_index, len); -} -- cgit v1.2.3 From b02903128679d3ecbe83d19770d2f622b36fe84d Mon Sep 17 00:00:00 2001 From: microDev <70126934+microDev1@users.noreply.github.com> Date: Tue, 2 Mar 2021 14:36:28 +0530 Subject: minor structural modification --- ports/raspberrypi/common-hal/nvm/ByteArray.c | 31 ++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/ports/raspberrypi/common-hal/nvm/ByteArray.c b/ports/raspberrypi/common-hal/nvm/ByteArray.c index 5d1147425..fdc2c6080 100644 --- a/ports/raspberrypi/common-hal/nvm/ByteArray.c +++ b/ports/raspberrypi/common-hal/nvm/ByteArray.c @@ -53,7 +53,7 @@ static void write_page(uint32_t page_addr, uint32_t offset, uint32_t len, uint8_ } } -static void write_sector(uint32_t address, uint32_t len, uint8_t* bytes) { +static void erase_and_write_sector(uint32_t address, uint32_t len, uint8_t* bytes) { // Write a whole sector to flash, buffering it first and then erasing and rewriting it // since we can only erase a whole sector at a time. uint8_t buffer[FLASH_SECTOR_SIZE]; @@ -73,24 +73,29 @@ bool common_hal_nvm_bytearray_set_bytes(nvm_bytearray_obj_t* self, uint8_t values_in[len]; common_hal_nvm_bytearray_get_bytes(self, start_index, len, values_in); + bool all_ones = true; for (uint32_t i = 0; i < len; i++) { if (values_in[i] != UINT8_MAX) { - write_sector(start_index, len, values); - return true; + all_ones = false; + break; } } - uint32_t address = (uint32_t) self->start_address + start_index; - uint32_t offset = address % FLASH_PAGE_SIZE; - uint32_t page_addr = address - offset; + if (all_ones) { + uint32_t address = (uint32_t) self->start_address + start_index; + uint32_t offset = address % FLASH_PAGE_SIZE; + uint32_t page_addr = address - offset; - while (len) { - uint32_t write_len = MIN(len, FLASH_PAGE_SIZE - offset); - write_page(page_addr, offset, write_len, values); - len -= write_len; - values += write_len; - page_addr += FLASH_PAGE_SIZE; - offset = 0; + while (len) { + uint32_t write_len = MIN(len, FLASH_PAGE_SIZE - offset); + write_page(page_addr, offset, write_len, values); + len -= write_len; + values += write_len; + page_addr += FLASH_PAGE_SIZE; + offset = 0; + } + } else { + erase_and_write_sector(start_index, len, values); } return true; -- cgit v1.2.3