From e3c342c5dd11271f2d4c16c977502fb7f3175a75 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Wed, 6 May 2020 23:52:48 +0300 Subject: [PATCH 1/5] add DUE definitions (interim commit) --- src/InternalStorage.cpp | 4 ++++ src/OTAStorage.cpp | 7 ++++++- src/OTAStorage.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/InternalStorage.cpp b/src/InternalStorage.cpp index e71a09a..09a96c5 100644 --- a/src/InternalStorage.cpp +++ b/src/InternalStorage.cpp @@ -45,6 +45,8 @@ extern "C" { while (!NVMCTRL->INTFLAG.bit.READY); #elif defined(ARDUINO_ARCH_NRF5) while (NRF_NVMC->READY == NVMC_READY_READY_Busy); +#elif defined(__SAM3X8E__) +/////////// while ... #endif } @@ -75,6 +77,8 @@ extern "C" { waitForReady(); NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; waitForReady(); +#elif defined(__SAM3X8E__) +///////////////// #endif } diff --git a/src/OTAStorage.cpp b/src/OTAStorage.cpp index 7451004..b55b219 100644 --- a/src/OTAStorage.cpp +++ b/src/OTAStorage.cpp @@ -18,10 +18,15 @@ char * __isr_vector(); #endif OTAStorage::OTAStorage() : -#if defined(ARDUINO_ARCH_SAMD) +#if defined(ARDUINO_ARCH_SAMD) SKETCH_START_ADDRESS((uint32_t) __text_start__), PAGE_SIZE(pageSizes[NVMCTRL->PARAM.bit.PSZ]), MAX_FLASH(PAGE_SIZE * NVMCTRL->PARAM.bit.NVMP - eepromSizes[EEPROM_EMULATION_RESERVATION]) +#elif defined(__SAM3X8E__) + SKETCH_START_ADDRESS((uint32_t) 0), //// + PAGE_SIZE(16),/// + MAX_FLASH(1024)/// + #elif defined(ARDUINO_ARCH_NRF5) SKETCH_START_ADDRESS((uint32_t) __isr_vector), PAGE_SIZE((size_t) NRF_FICR->CODEPAGESIZE), diff --git a/src/OTAStorage.h b/src/OTAStorage.h index ca65394..2786d93 100644 --- a/src/OTAStorage.h +++ b/src/OTAStorage.h @@ -26,6 +26,7 @@ #include + class OTAStorage { public: From 403534c7ec1f698e1b8f2d7c6662031d993546f1 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sun, 24 May 2020 21:18:05 +0300 Subject: [PATCH 2/5] DUE OTA added --- src/ArduinoOTA.h | 12 ++++++- src/InternalStorage.cpp | 71 +++++++++++++++++++++++++++++++++++++++-- src/OTAStorage.cpp | 8 +++-- 3 files changed, 85 insertions(+), 6 deletions(-) diff --git a/src/ArduinoOTA.h b/src/ArduinoOTA.h index 20a921f..534c787 100644 --- a/src/ArduinoOTA.h +++ b/src/ArduinoOTA.h @@ -44,17 +44,23 @@ template class ArduinoOTAClass : public WiFiOTAClass { private: +// bool init; NetServer server; public: - ArduinoOTAClass() : server(OTA_PORT) {}; + ArduinoOTAClass() : server(OTA_PORT) + { + //init=false; + }; void begin(IPAddress localIP, const char* name, const char* password, OTAStorage& storage) { WiFiOTAClass::begin(localIP, name, password, storage); server.begin(); + //init=true; } void end() { + //init=false; #if defined(ESP8266) || defined(ESP32) server.stop(); #elif defined(_WIFI_ESP_AT_H_) @@ -65,8 +71,12 @@ class ArduinoOTAClass : public WiFiOTAClass { } void poll() { + //if (init) + //{ NetClient client = server.available(); pollServer(client); + // } + // else Serial.write("."); } void handle() { // alias diff --git a/src/InternalStorage.cpp b/src/InternalStorage.cpp index 09a96c5..b6d5d78 100644 --- a/src/InternalStorage.cpp +++ b/src/InternalStorage.cpp @@ -27,12 +27,29 @@ #include "InternalStorage.h" +#if defined(__SAM3X8E__) +#include "flash_efc.h" +#include "efc.h" +#endif + + InternalStorageClass::InternalStorageClass() : + +#if defined(__SAM3X8E__) + MAX_PARTIONED_SKETCH_SIZE(256*1024), + STORAGE_START_ADDRESS(IFLASH1_ADDR) +#else MAX_PARTIONED_SKETCH_SIZE((MAX_FLASH - SKETCH_START_ADDRESS) / 2), STORAGE_START_ADDRESS(SKETCH_START_ADDRESS + MAX_PARTIONED_SKETCH_SIZE) +#endif { _writeIndex = 0; _writeAddress = nullptr; + +#if defined(__SAM3X8E__) + flash_init(FLASH_ACCESS_MODE_128, 6); + //if (retCode != FLASH_RC_OK) +#endif } extern "C" { @@ -106,12 +123,23 @@ int InternalStorageClass::open(int length) _writeIndex = 0; _writeAddress = (uint32_t*)STORAGE_START_ADDRESS; +Serial.println("Open flash for write\n"); + #ifdef ARDUINO_ARCH_SAMD // enable auto page writes NVMCTRL->CTRLB.bit.MANW = 0; #endif +#if defined(__SAM3X8E__) + int retCode = flash_unlock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) MAX_PARTIONED_SKETCH_SIZE, 0, 0); + if (retCode != FLASH_RC_OK) { + Serial.println("Failed to unlock flash for write\n"); + } +#else eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); +#endif + + return 1; } @@ -124,11 +152,19 @@ size_t InternalStorageClass::write(uint8_t b) if (_writeIndex == 4) { _writeIndex = 0; - *_writeAddress = _addressData.u32; +#if defined(__SAM3X8E__) + int retCode = flash_write((uint32_t) _writeAddress, &_addressData.u32, 4, 1); + if (retCode != FLASH_RC_OK) + Serial.println("Flash write failed\n"); _writeAddress++; +#else + *_writeAddress = _addressData.u32; + _writeAddress++; waitForReady(); +#endif + } return 1; @@ -136,21 +172,52 @@ size_t InternalStorageClass::write(uint8_t b) void InternalStorageClass::close() { +Serial.println("Closing flash\n"); + while ((int)_writeAddress % PAGE_SIZE) { write(0xff); - } + } +#if defined(__SAM3X8E__) + int retCode = flash_lock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) MAX_PARTIONED_SKETCH_SIZE, 0, 0); + if (retCode != FLASH_RC_OK) + Serial.println("Failed to lock flash for write\n"); +#endif + } void InternalStorageClass::clear() { } + void InternalStorageClass::apply() { +#if defined(__SAM3X8E__) +if (flash_is_gpnvm_set(2)) // BANK1 is active +{ +Serial.println("Switching to BANK0"); +flash_clear_gpnvm(2); + +} + +else +{ +Serial.println("Switching to BANK1"); +flash_set_gpnvm(2); +} + +flash_set_gpnvm(1); //Booting from FLASH + +Serial.println("Restarting"); +delay(500); + +RSTC->RSTC_CR = 0xA5000005; +#else // disable interrupts, as vector table will be erase during flash sequence noInterrupts(); copyFlashAndReset(SKETCH_START_ADDRESS, STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); +#endif } long InternalStorageClass::maxSize() diff --git a/src/OTAStorage.cpp b/src/OTAStorage.cpp index b55b219..282bbed 100644 --- a/src/OTAStorage.cpp +++ b/src/OTAStorage.cpp @@ -22,10 +22,12 @@ OTAStorage::OTAStorage() : SKETCH_START_ADDRESS((uint32_t) __text_start__), PAGE_SIZE(pageSizes[NVMCTRL->PARAM.bit.PSZ]), MAX_FLASH(PAGE_SIZE * NVMCTRL->PARAM.bit.NVMP - eepromSizes[EEPROM_EMULATION_RESERVATION]) + #elif defined(__SAM3X8E__) - SKETCH_START_ADDRESS((uint32_t) 0), //// - PAGE_SIZE(16),/// - MAX_FLASH(1024)/// + + SKETCH_START_ADDRESS((uint32_t) IFLASH0_ADDR), + PAGE_SIZE(IFLASH0_PAGE_SIZE), + MAX_FLASH(256*1024) #elif defined(ARDUINO_ARCH_NRF5) SKETCH_START_ADDRESS((uint32_t) __isr_vector), From 8ad7461b692b5a2689a41c43d2cd2a5b532dcc04 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Mon, 25 May 2020 05:30:25 +0300 Subject: [PATCH 3/5] OTA for DUE start working --- examples/OTA_Flashing/hello.bin | Bin 0 -> 24416 bytes examples/OTA_Flashing/upload.sh | 1 + src/InternalStorage.cpp | 212 +++++++++++++++++++++++++------- src/InternalStorage.h | 12 +- src/OTAStorage.cpp | 2 +- 5 files changed, 182 insertions(+), 45 deletions(-) create mode 100755 examples/OTA_Flashing/hello.bin create mode 100755 examples/OTA_Flashing/upload.sh diff --git a/examples/OTA_Flashing/hello.bin b/examples/OTA_Flashing/hello.bin new file mode 100755 index 0000000000000000000000000000000000000000..61b353c3ff27b4780df3b0ccbbe5619f4c8edd22 GIT binary patch literal 24416 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
  • 7sHdU(vY;uOeF25c)Sjs3oi!1JK`jrN2WXK zlB5$Fsorh6B;gQw$2J2v__D*zWB8F4#QX$KeMg)mBZtH@NiU&oOw*5T%5NHz%ArW1s7V}Cc{Kx`7aWWo>*bAY-b821&GoM1pw6BCq%i;j&rLjcV*yM63jsKQA^>bq zOaKmm768n9OoRiV1t6=~{-k}wqnfAfPx6{4p3HypsV6i^tM65!FeTcMzX91dtVNIi zb}eq{`rkXD40=Qf-x-GVQ2-mjc7U%`47vvCOn@8z?pA&p{MOu!z-zGG&vHnvhK* z2!ftO%4L(}h)~E%C^b@t&@c`qw5gDhqzNabIQdUo08()akXR6wuR?R{pK*Fx`iz

    RkV_tqi;p#P#Fq1bt_1I%m0C&ru*Z}tfk1@yo1Ut?5QWz9R053=e zEr;KZd3`Jczl-oAegHHt_Iv*(%({&q%57D=3x54gmb-$h;#=W24yj!H3jy#ebnqL8 zDgvzlef|rA-$X(o4@fp7O@q*V_an3xChywmn9@7{VY$Nh(%}#84Bt>>6{XO83Xlr1 zxf`epTW{-;cu|Nnzs{BKkL%Ypypz+E_iZDi&W z%e;Aa!Q<@FIf|e0z1Qn^U*Xvqgf>VqbOzxvq!@%Ch>&7HvH&oUVo(Pm7E%nFAS6SI z!5D-LNHLg#kOL`(g+W*bDF!YGJfs+kf=~=821gLKLW-e02$hgxs1Cw@NHNp~;RvJ{ zT7vL7q!^q*XoD0(XAmw!ia`j12q^|64*&xx26Yf(A;q8xLNcTnj6ukN6oV-UIgnyl z7=&ezV&HLBcg6hmzgjzEf`B?zBGioqF#Hb^ma z2H`TK7=$2*kYYfJ05FhZPzNCvQVg0PBtwe97=#Q+F_?mo11W}uL0ASU1}+FZq!@~V zPz)&sM-a9`ilICRm5^en4#Iv&G1La(2&5QVg77({7@R?9gA_w&5H3TCK?s5fDFy`R zm>8HKs3FA=8w6mA219ZXjF4i;2!aVx3^_qq2q}hTLEs?8zz3lSQVhjGa6pP-YY@sI d#ZVc9YDh8c4?-=Z7>)!1JIvVMaAh*+{{g!WcmeREADY == NVMC_READY_READY_Busy); #elif defined(__SAM3X8E__) -/////////// while ... +// Not used #endif } @@ -95,24 +95,82 @@ extern "C" { NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos; waitForReady(); #elif defined(__SAM3X8E__) -///////////////// + + //Erase secondary bank; + Serial.println("Erase flash"); + flash_erase_all(address); #endif } __attribute__ ((long_call, noinline, section (".data#"))) static void copyFlashAndReset(int dest, int src, int length, int pageSize) { + +#if defined(__SAM3X8E__) +// Not actual copy, just switch banks +flash_set_gpnvm(1); //Booting from FLASH + +/* + +HMM not working - starting & hung +if (FLASH_RC_YES == flash_is_gpnvm_set(2)) // BANK1 is active +{ +Serial.println("Switching to BANK0"); +delay(500); +noInterrupts(); +flash_clear_gpnvm(2); +} + +else +{ +Serial.println("Switching to BANK1"); +delay(500); +noInterrupts(); +flash_set_gpnvm(2); +} +*/ + +//TODO - less bytes +Serial.print("Copying bytes:"); +Serial.println(length); +delay(300); + +noInterrupts(); + +//NOt working +//eraseFlash(dest, length, pageSize); +//flash_erase_all(dest); + +while (length>=256) + { + flash_write(dest,(void*) src,256,1); + dest+=256; + src+=256; + length-=256; + watchdogReset(); + } +flash_write(dest,(void*) src,length,1); + +// TODO - lock flash +//Todo - clean STORAGE (not working) +//flash_erase_all(src); + +RSTC->RSTC_CR = 0xA5000005; + +#else uint32_t* d = (uint32_t*)dest; uint32_t* s = (uint32_t*)src; + + noInterrupts(); eraseFlash(dest, length, pageSize); for (int i = 0; i < length; i += 4) { *d++ = *s++; - + waitForReady(); } - +#endif NVIC_SystemReset(); } } @@ -121,7 +179,7 @@ int InternalStorageClass::open(int length) { (void)length; _writeIndex = 0; - _writeAddress = (uint32_t*)STORAGE_START_ADDRESS; + _writeAddress = (addressData*)STORAGE_START_ADDRESS; Serial.println("Open flash for write\n"); @@ -131,36 +189,123 @@ Serial.println("Open flash for write\n"); #endif #if defined(__SAM3X8E__) - int retCode = flash_unlock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) MAX_PARTIONED_SKETCH_SIZE, 0, 0); +//TODO - remove + int retCode = flash_unlock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) STORAGE_START_ADDRESS + MAX_PARTIONED_SKETCH_SIZE - 1, 0, 0); if (retCode != FLASH_RC_OK) { Serial.println("Failed to unlock flash for write\n"); } -#else - eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); #endif - +eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); return 1; } + + + +/* + +uint32_t flash_write(uint32_t ul_address, const void *p_buffer, + uint32_t ul_size, uint32_t ul_erase_flag) +{ + Efc *p_efc; + uint32_t ul_fws_temp; + uint16_t us_page; + uint16_t us_offset; + uint32_t writeSize; + uint32_t ul_page_addr; + uint16_t us_padding; + uint32_t ul_error; + uint32_t ul_idx; + uint32_t *p_aligned_dest; + uint8_t *puc_page_buffer = (uint8_t *) gs_ul_page_buffer; + + translate_address(&p_efc, ul_address, &us_page, &us_offset); + + /// According to the errata, set the wait state value to 6. + ul_fws_temp = efc_get_wait_state(p_efc); + efc_set_wait_state(p_efc, 6); + + // Write all pages + while (ul_size > 0) { + // Copy data in temporary buffer to avoid alignment problems. + writeSize = Min((uint32_t) IFLASH_PAGE_SIZE - us_offset, + ul_size); + compute_address(p_efc, us_page, 0, &ul_page_addr); + us_padding = IFLASH_PAGE_SIZE - us_offset - writeSize; + + // Pre-buffer data + memcpy(puc_page_buffer, (void *)ul_page_addr, us_offset); + + // Buffer data + memcpy(puc_page_buffer + us_offset, p_buffer, writeSize); + + // Post-buffer data + memcpy(puc_page_buffer + us_offset + + writeSize, + (void *)(ul_page_addr + us_offset + writeSize), + us_padding); + + // Write page. + // Writing 8-bit and 16-bit data is not allowed and may lead to + // unpredictable data corruption. + // + p_aligned_dest = (uint32_t *) ul_page_addr; + for (ul_idx = 0; ul_idx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); + ++ul_idx) { + *p_aligned_dest++ = gs_ul_page_buffer[ul_idx]; + } + + if (ul_erase_flag) { + ul_error = efc_perform_command(p_efc, EFC_FCMD_EWP, + us_page); + } else { + ul_error = efc_perform_command(p_efc, EFC_FCMD_WP, + us_page); + } + + if (ul_error) { + return ul_error; + } + + // Progression + p_buffer = (void *)((uint32_t) p_buffer + writeSize); + ul_size -= writeSize; + us_page++; + us_offset = 0; + } + + // According to the errata, restore the wait state value. + efc_set_wait_state(p_efc, ul_fws_temp); + + return FLASH_RC_OK; +} + +*/ + + size_t InternalStorageClass::write(uint8_t b) { _addressData.u8[_writeIndex] = b; _writeIndex++; - if (_writeIndex == 4) { + if (_writeIndex == sizeof(addressData)) { _writeIndex = 0; #if defined(__SAM3X8E__) - int retCode = flash_write((uint32_t) _writeAddress, &_addressData.u32, 4, 1); + watchdogReset(); + Serial.print("="); + int retCode = flash_write((uint32_t) _writeAddress, &_addressData.u32, sizeof(addressData), 0); if (retCode != FLASH_RC_OK) + { Serial.println("Flash write failed\n"); - + return 0; + } _writeAddress++; #else - *_writeAddress = _addressData.u32; + _writeAddress->u32 = _addressData.u32; _writeAddress++; waitForReady(); #endif @@ -172,13 +317,19 @@ size_t InternalStorageClass::write(uint8_t b) void InternalStorageClass::close() { -Serial.println("Closing flash\n"); - while ((int)_writeAddress % PAGE_SIZE) { - write(0xff); - } + write(0xff); + } #if defined(__SAM3X8E__) - int retCode = flash_lock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) MAX_PARTIONED_SKETCH_SIZE, 0, 0); +Serial.println("\nClosing flash"); +Serial.println((uint32_t)_writeAddress-STORAGE_START_ADDRESS+_writeIndex); + + while (_writeIndex) { + write(0xff); + } + +//TODO move lock up + int retCode = flash_lock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) STORAGE_START_ADDRESS+MAX_PARTIONED_SKETCH_SIZE-1, 0, 0); if (retCode != FLASH_RC_OK) Serial.println("Failed to lock flash for write\n"); #endif @@ -192,32 +343,9 @@ void InternalStorageClass::clear() void InternalStorageClass::apply() { -#if defined(__SAM3X8E__) -if (flash_is_gpnvm_set(2)) // BANK1 is active -{ -Serial.println("Switching to BANK0"); -flash_clear_gpnvm(2); - -} - -else -{ -Serial.println("Switching to BANK1"); -flash_set_gpnvm(2); -} - -flash_set_gpnvm(1); //Booting from FLASH - -Serial.println("Restarting"); -delay(500); - -RSTC->RSTC_CR = 0xA5000005; -#else // disable interrupts, as vector table will be erase during flash sequence - noInterrupts(); - + //noInterrupts(); copyFlashAndReset(SKETCH_START_ADDRESS, STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); -#endif } long InternalStorageClass::maxSize() diff --git a/src/InternalStorage.h b/src/InternalStorage.h index 1e055de..75af9e0 100644 --- a/src/InternalStorage.h +++ b/src/InternalStorage.h @@ -41,13 +41,21 @@ class InternalStorageClass : public OTAStorage { private: const uint32_t MAX_PARTIONED_SKETCH_SIZE, STORAGE_START_ADDRESS; - union { + +#if defined(__SAM3X8E__) + union addressData { + uint32_t u32; + uint8_t u8[256]; + } _addressData; +#else + union addressData{ uint32_t u32; uint8_t u8[4]; } _addressData; +#endif int _writeIndex; - uint32_t* _writeAddress; + addressData * _writeAddress; }; extern InternalStorageClass InternalStorage; diff --git a/src/OTAStorage.cpp b/src/OTAStorage.cpp index 282bbed..390e58e 100644 --- a/src/OTAStorage.cpp +++ b/src/OTAStorage.cpp @@ -26,7 +26,7 @@ OTAStorage::OTAStorage() : #elif defined(__SAM3X8E__) SKETCH_START_ADDRESS((uint32_t) IFLASH0_ADDR), - PAGE_SIZE(IFLASH0_PAGE_SIZE), + PAGE_SIZE(256), MAX_FLASH(256*1024) #elif defined(ARDUINO_ARCH_NRF5) From 65874b528c2f9c1a4d90131ba6de3a1d694cf9b4 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sun, 14 Jun 2020 06:19:08 +0300 Subject: [PATCH 4/5] DUE flash unlock fixed --- src/InternalStorage.cpp | 115 +---- src/InternalStorage.h | 3 +- src/efc.cpp | 340 +++++++++++++++ src/efc.h | 139 ++++++ src/flash_efc.cpp | 916 ++++++++++++++++++++++++++++++++++++++++ src/flash_efc.h | 151 +++++++ 6 files changed, 1568 insertions(+), 96 deletions(-) create mode 100644 src/efc.cpp create mode 100644 src/efc.h create mode 100644 src/flash_efc.cpp create mode 100644 src/flash_efc.h diff --git a/src/InternalStorage.cpp b/src/InternalStorage.cpp index 713536c..ac51f9a 100644 --- a/src/InternalStorage.cpp +++ b/src/InternalStorage.cpp @@ -107,12 +107,12 @@ extern "C" { { #if defined(__SAM3X8E__) -// Not actual copy, just switch banks flash_set_gpnvm(1); //Booting from FLASH /* - HMM not working - starting & hung +// Not actual copy, just switch banks + if (FLASH_RC_YES == flash_is_gpnvm_set(2)) // BANK1 is active { Serial.println("Switching to BANK0"); @@ -130,8 +130,13 @@ flash_set_gpnvm(2); } */ -//TODO - less bytes -Serial.print("Copying bytes:"); +// Since bank swithing is not working - just copy to bank0 from bank1 +int retCode = flash_unlock((uint32_t)dest, (uint32_t) src-1, 0, 0); + if (retCode != FLASH_RC_OK) { + Serial.println("Failed to unlock bank0 for write\n"); + } + +Serial.print("Flashing bytes:"); Serial.println(length); delay(300); @@ -151,7 +156,9 @@ while (length>=256) } flash_write(dest,(void*) src,length,1); -// TODO - lock flash +// Locking flash +retCode = flash_lock((uint32_t)dest, (uint32_t) src-1, 0, 0); + //Todo - clean STORAGE (not working) //flash_erase_all(src); @@ -189,7 +196,7 @@ Serial.println("Open flash for write\n"); #endif #if defined(__SAM3X8E__) -//TODO - remove + int retCode = flash_unlock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) STORAGE_START_ADDRESS + MAX_PARTIONED_SKETCH_SIZE - 1, 0, 0); if (retCode != FLASH_RC_OK) { Serial.println("Failed to unlock flash for write\n"); @@ -203,88 +210,6 @@ eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); - -/* - -uint32_t flash_write(uint32_t ul_address, const void *p_buffer, - uint32_t ul_size, uint32_t ul_erase_flag) -{ - Efc *p_efc; - uint32_t ul_fws_temp; - uint16_t us_page; - uint16_t us_offset; - uint32_t writeSize; - uint32_t ul_page_addr; - uint16_t us_padding; - uint32_t ul_error; - uint32_t ul_idx; - uint32_t *p_aligned_dest; - uint8_t *puc_page_buffer = (uint8_t *) gs_ul_page_buffer; - - translate_address(&p_efc, ul_address, &us_page, &us_offset); - - /// According to the errata, set the wait state value to 6. - ul_fws_temp = efc_get_wait_state(p_efc); - efc_set_wait_state(p_efc, 6); - - // Write all pages - while (ul_size > 0) { - // Copy data in temporary buffer to avoid alignment problems. - writeSize = Min((uint32_t) IFLASH_PAGE_SIZE - us_offset, - ul_size); - compute_address(p_efc, us_page, 0, &ul_page_addr); - us_padding = IFLASH_PAGE_SIZE - us_offset - writeSize; - - // Pre-buffer data - memcpy(puc_page_buffer, (void *)ul_page_addr, us_offset); - - // Buffer data - memcpy(puc_page_buffer + us_offset, p_buffer, writeSize); - - // Post-buffer data - memcpy(puc_page_buffer + us_offset + - writeSize, - (void *)(ul_page_addr + us_offset + writeSize), - us_padding); - - // Write page. - // Writing 8-bit and 16-bit data is not allowed and may lead to - // unpredictable data corruption. - // - p_aligned_dest = (uint32_t *) ul_page_addr; - for (ul_idx = 0; ul_idx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); - ++ul_idx) { - *p_aligned_dest++ = gs_ul_page_buffer[ul_idx]; - } - - if (ul_erase_flag) { - ul_error = efc_perform_command(p_efc, EFC_FCMD_EWP, - us_page); - } else { - ul_error = efc_perform_command(p_efc, EFC_FCMD_WP, - us_page); - } - - if (ul_error) { - return ul_error; - } - - // Progression - p_buffer = (void *)((uint32_t) p_buffer + writeSize); - ul_size -= writeSize; - us_page++; - us_offset = 0; - } - - // According to the errata, restore the wait state value. - efc_set_wait_state(p_efc, ul_fws_temp); - - return FLASH_RC_OK; -} - -*/ - - size_t InternalStorageClass::write(uint8_t b) { _addressData.u8[_writeIndex] = b; @@ -296,7 +221,7 @@ size_t InternalStorageClass::write(uint8_t b) #if defined(__SAM3X8E__) watchdogReset(); Serial.print("="); - int retCode = flash_write((uint32_t) _writeAddress, &_addressData.u32, sizeof(addressData), 0); + int retCode = flash_write((uint32_t) _writeAddress, &_addressData.u32, sizeof(addressData), 1); if (retCode != FLASH_RC_OK) { Serial.println("Flash write failed\n"); @@ -322,16 +247,16 @@ void InternalStorageClass::close() } #if defined(__SAM3X8E__) Serial.println("\nClosing flash"); -Serial.println((uint32_t)_writeAddress-STORAGE_START_ADDRESS+_writeIndex); +Serial.println(MAX_PARTIONED_SKETCH_SIZE = (uint32_t)_writeAddress-STORAGE_START_ADDRESS+_writeIndex); while (_writeIndex) { write(0xff); } -//TODO move lock up - int retCode = flash_lock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) STORAGE_START_ADDRESS+MAX_PARTIONED_SKETCH_SIZE-1, 0, 0); - if (retCode != FLASH_RC_OK) - Serial.println("Failed to lock flash for write\n"); +//TODO not sure need to lock bank1 (storage) +// int retCode = flash_lock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) STORAGE_START_ADDRESS+MAX_PARTIONED_SKETCH_SIZE-1, 0, 0); +// if (retCode != FLASH_RC_OK) +// Serial.println("Failed to lock flash for write\n"); #endif } @@ -344,7 +269,7 @@ void InternalStorageClass::clear() void InternalStorageClass::apply() { // disable interrupts, as vector table will be erase during flash sequence - //noInterrupts(); + //noInterrupts(); moved inside routine copyFlashAndReset(SKETCH_START_ADDRESS, STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); } diff --git a/src/InternalStorage.h b/src/InternalStorage.h index 75af9e0..f39271b 100644 --- a/src/InternalStorage.h +++ b/src/InternalStorage.h @@ -39,7 +39,8 @@ class InternalStorageClass : public OTAStorage { virtual long maxSize(); private: - const uint32_t MAX_PARTIONED_SKETCH_SIZE, STORAGE_START_ADDRESS; + //const + uint32_t MAX_PARTIONED_SKETCH_SIZE, STORAGE_START_ADDRESS; #if defined(__SAM3X8E__) diff --git a/src/efc.cpp b/src/efc.cpp new file mode 100644 index 0000000..74f0c8a --- /dev/null +++ b/src/efc.cpp @@ -0,0 +1,340 @@ +/** + * \file + * + * \brief Enhanced Embedded Flash Controller (EEFC) driver for SAM. + * + * Copyright (c) 2011-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include "efc.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/** + * \defgroup sam_drivers_efc_group Enhanced Embedded Flash Controller (EEFC) + * + * The Enhanced Embedded Flash Controller ensures the interface of the Flash + * block with the 32-bit internal bus. + * + * @{ + */ + +/* Address definition for read operation */ +# define READ_BUFF_ADDR0 IFLASH0_ADDR +# define READ_BUFF_ADDR1 IFLASH1_ADDR + +/* Flash Writing Protection Key */ +#define FWP_KEY 0x5Au + +#if (SAM4S || SAM4E) +#define EEFC_FCR_FCMD(value) \ + ((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos))) +#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR) +#else +#define EEFC_ERROR_FLAGS (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE) +#endif + + + +/* + * Local function declaration. + * Because they are RAM functions, they need 'extern' declaration. + */ +extern void efc_write_fmr(Efc *p_efc, uint32_t ul_fmr); +extern uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr); + +/** + * \brief Initialize the EFC controller. + * + * \param ul_access_mode 0 for 128-bit, EEFC_FMR_FAM for 64-bit. + * \param ul_fws The number of wait states in cycle (no shift). + * + * \return 0 if successful. + */ +uint32_t efc_init(Efc *p_efc, uint32_t ul_access_mode, uint32_t ul_fws) +{ + efc_write_fmr(p_efc, ul_access_mode | EEFC_FMR_FWS(ul_fws)); + return EFC_RC_OK; +} + +/** + * \brief Enable the flash ready interrupt. + * + * \param p_efc Pointer to an EFC instance. + */ +void efc_enable_frdy_interrupt(Efc *p_efc) +{ + uint32_t ul_fmr = p_efc->EEFC_FMR; + + efc_write_fmr(p_efc, ul_fmr | EEFC_FMR_FRDY); +} + +/** + * \brief Disable the flash ready interrupt. + * + * \param p_efc Pointer to an EFC instance. + */ +void efc_disable_frdy_interrupt(Efc *p_efc) +{ + uint32_t ul_fmr = p_efc->EEFC_FMR; + + efc_write_fmr(p_efc, ul_fmr & (~EEFC_FMR_FRDY)); +} + +/** + * \brief Set flash access mode. + * + * \param p_efc Pointer to an EFC instance. + * \param ul_mode 0 for 128-bit, EEFC_FMR_FAM for 64-bit. + */ +void efc_set_flash_access_mode(Efc *p_efc, uint32_t ul_mode) +{ + uint32_t ul_fmr = p_efc->EEFC_FMR & (~EEFC_FMR_FAM); + + efc_write_fmr(p_efc, ul_fmr | ul_mode); +} + +/** + * \brief Get flash access mode. + * + * \param p_efc Pointer to an EFC instance. + * + * \return 0 for 128-bit or EEFC_FMR_FAM for 64-bit. + */ +uint32_t efc_get_flash_access_mode(Efc *p_efc) +{ + return (p_efc->EEFC_FMR & EEFC_FMR_FAM); +} + +/** + * \brief Set flash wait state. + * + * \param p_efc Pointer to an EFC instance. + * \param ul_fws The number of wait states in cycle (no shift). + */ +void efc_set_wait_state(Efc *p_efc, uint32_t ul_fws) +{ + uint32_t ul_fmr = p_efc->EEFC_FMR & (~EEFC_FMR_FWS_Msk); + + efc_write_fmr(p_efc, ul_fmr | EEFC_FMR_FWS(ul_fws)); +} + +/** + * \brief Get flash wait state. + * + * \param p_efc Pointer to an EFC instance. + * + * \return The number of wait states in cycle (no shift). + */ +uint32_t efc_get_wait_state(Efc *p_efc) +{ + return ((p_efc->EEFC_FMR & EEFC_FMR_FWS_Msk) >> EEFC_FMR_FWS_Pos); +} + +/** + * \brief Perform the given command and wait until its completion (or an error). + * + * \note Unique ID commands are not supported, use efc_read_unique_id. + * + * \param p_efc Pointer to an EFC instance. + * \param ul_command Command to perform. + * \param ul_argument Optional command argument. + * + * \note This function will automatically choose to use IAP function. + * + * \return 0 if successful, otherwise returns an error code. + */ +uint32_t efc_perform_command(Efc *p_efc, uint32_t ul_command, + uint32_t ul_argument) +{ + /* Unique ID commands are not supported. */ + if (ul_command == EFC_FCMD_STUI || ul_command == EFC_FCMD_SPUI) { + return EFC_RC_NOT_SUPPORT; + } + + /* Use IAP function with 2 parameters in ROM. */ + static uint32_t(*iap_perform_command) (uint32_t, uint32_t); + uint32_t ul_efc_nb = (p_efc == EFC0) ? 0 : 1; + + iap_perform_command = + (uint32_t(*)(uint32_t, uint32_t)) + *((uint32_t *) CHIP_FLASH_IAP_ADDRESS); + iap_perform_command(ul_efc_nb, + EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(ul_argument) | + EEFC_FCR_FCMD(ul_command)); + return (p_efc->EEFC_FSR & EEFC_ERROR_FLAGS); +} + +/** + * \brief Get the current status of the EEFC. + * + * \note This function clears the value of some status bits (FLOCKE, FCMDE). + * + * \param p_efc Pointer to an EFC instance. + * + * \return The current status. + */ +uint32_t efc_get_status(Efc *p_efc) +{ + return p_efc->EEFC_FSR; +} + +/** + * \brief Get the result of the last executed command. + * + * \param p_efc Pointer to an EFC instance. + * + * \return The result of the last executed command. + */ +uint32_t efc_get_result(Efc *p_efc) +{ + return p_efc->EEFC_FRR; +} + +/** + * \brief Perform read sequence. Supported sequences are read Unique ID and + * read User Signature + * + * \param p_efc Pointer to an EFC instance. + * \param ul_cmd_st Start command to perform. + * \param ul_cmd_sp Stop command to perform. + * \param p_ul_buf Pointer to an data buffer. + * \param ul_size Buffer size. + * + * \return 0 if successful, otherwise returns an error code. + */ +RAMFUNC +uint32_t efc_perform_read_sequence(Efc *p_efc, + uint32_t ul_cmd_st, uint32_t ul_cmd_sp, + uint32_t *p_ul_buf, uint32_t ul_size) +{ + volatile uint32_t ul_status; + uint32_t ul_cnt; + + uint32_t *p_ul_data = + (uint32_t *) ((p_efc == EFC0) ? + READ_BUFF_ADDR0 : READ_BUFF_ADDR1); + + if (p_ul_buf == NULL) { + return EFC_RC_INVALID; + } + + p_efc->EEFC_FMR |= (0x1u << 16); + + /* Send the Start Read command */ + + p_efc->EEFC_FCR = EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0) + | EEFC_FCR_FCMD(ul_cmd_st); + /* Wait for the FRDY bit in the Flash Programming Status Register + * (EEFC_FSR) falls. + */ + do { + ul_status = p_efc->EEFC_FSR; + } while ((ul_status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY); + + /* The data is located in the first address of the Flash + * memory mapping. + */ + for (ul_cnt = 0; ul_cnt < ul_size; ul_cnt++) { + p_ul_buf[ul_cnt] = p_ul_data[ul_cnt]; + } + + /* To stop the read mode */ + p_efc->EEFC_FCR = + EEFC_FCR_FKEY(FWP_KEY) | EEFC_FCR_FARG(0) | + EEFC_FCR_FCMD(ul_cmd_sp); + /* Wait for the FRDY bit in the Flash Programming Status Register (EEFC_FSR) + * rises. + */ + do { + ul_status = p_efc->EEFC_FSR; + } while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY); + + p_efc->EEFC_FMR &= ~(0x1u << 16); + + return EFC_RC_OK; +} + +/** + * \brief Set mode register. + * + * \param p_efc Pointer to an EFC instance. + * \param ul_fmr Value of mode register + */ +RAMFUNC +void efc_write_fmr(Efc *p_efc, uint32_t ul_fmr) +{ + p_efc->EEFC_FMR = ul_fmr; +} + +/** + * \brief Perform command. + * + * \param p_efc Pointer to an EFC instance. + * \param ul_fcr Flash command. + * + * \return The current status. + */ +RAMFUNC +uint32_t efc_perform_fcr(Efc *p_efc, uint32_t ul_fcr) +{ + volatile uint32_t ul_status; + + p_efc->EEFC_FCR = ul_fcr; + do { + ul_status = p_efc->EEFC_FSR; + } while ((ul_status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY); + + return (ul_status & EEFC_ERROR_FLAGS); +} + +//@} + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond diff --git a/src/efc.h b/src/efc.h new file mode 100644 index 0000000..4481b98 --- /dev/null +++ b/src/efc.h @@ -0,0 +1,139 @@ +/** + * \file + * + * \brief Embedded Flash Controller (EFC) driver for SAM. + * + * Copyright (c) 2011-2012 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef EFC_H_INCLUDED +#define EFC_H_INCLUDED + +#include +#include + +#define SAM3XA +#define RAMFUNC __attribute__ ((section(".ramfunc"))) + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/*! \name EFC return codes */ +//! @{ +typedef enum efc_rc { + EFC_RC_OK = 0, //!< Operation OK + EFC_RC_YES = 0, //!< Yes + EFC_RC_NO = 1, //!< No + EFC_RC_ERROR = 1, //!< General error + EFC_RC_INVALID, //!< Invalid argument input + EFC_RC_NOT_SUPPORT = 0xFFFFFFFF //!< Operation is not supported +} efc_rc_t; +//! @} + +/*! \name EFC command */ +//! @{ +#define EFC_FCMD_GETD 0x00 //!< Get Flash Descriptor +#define EFC_FCMD_WP 0x01 //!< Write page +#define EFC_FCMD_WPL 0x02 //!< Write page and lock +#define EFC_FCMD_EWP 0x03 //!< Erase page and write page +#define EFC_FCMD_EWPL 0x04 //!< Erase page and write page then lock +#define EFC_FCMD_EA 0x05 //!< Erase all +#if (SAM3SD8) +#define EFC_FCMD_EPL 0x06 //!< Erase plane +#endif +#if (SAM4S || SAM4E) +#define EFC_FCMD_EPA 0x07 //!< Erase pages +#endif +#define EFC_FCMD_SLB 0x08 //!< Set Lock Bit +#define EFC_FCMD_CLB 0x09 //!< Clear Lock Bit +#define EFC_FCMD_GLB 0x0A //!< Get Lock Bit +#define EFC_FCMD_SGPB 0x0B //!< Set GPNVM Bit +#define EFC_FCMD_CGPB 0x0C //!< Clear GPNVM Bit +#define EFC_FCMD_GGPB 0x0D //!< Get GPNVM Bit +#define EFC_FCMD_STUI 0x0E //!< Start unique ID +#define EFC_FCMD_SPUI 0x0F //!< Stop unique ID +#if (!SAM3U && !SAM3SD8 && !SAM3S8) +#define EFC_FCMD_GCALB 0x10 //!< Get CALIB Bit +#endif +#if (SAM4S || SAM4E) +#define EFC_FCMD_ES 0x11 //!< Erase sector +#define EFC_FCMD_WUS 0x12 //!< Write user signature +#define EFC_FCMD_EUS 0x13 //!< Erase user signature +#define EFC_FCMD_STUS 0x14 //!< Start read user signature +#define EFC_FCMD_SPUS 0x15 //!< Stop read user signature +#endif +//! @} + +/*! The IAP function entry address */ +#define CHIP_FLASH_IAP_ADDRESS (IROM_ADDR + 8) + +/*! \name EFC access mode */ +//! @{ +#define EFC_ACCESS_MODE_128 0 +#define EFC_ACCESS_MODE_64 EEFC_FMR_FAM +//! @} + +uint32_t efc_init(Efc *p_efc, uint32_t ul_access_mode, uint32_t ul_fws); +void efc_enable_frdy_interrupt(Efc *p_efc); +void efc_disable_frdy_interrupt(Efc *p_efc); +void efc_set_flash_access_mode(Efc *p_efc, uint32_t ul_mode); +uint32_t efc_get_flash_access_mode(Efc *p_efc); +void efc_set_wait_state(Efc *p_efc, uint32_t ul_fws); +uint32_t efc_get_wait_state(Efc *p_efc); +uint32_t efc_perform_command(Efc *p_efc, uint32_t ul_command, + uint32_t ul_argument); +uint32_t efc_get_status(Efc *p_efc); +uint32_t efc_get_result(Efc *p_efc); +uint32_t efc_perform_read_sequence(Efc *p_efc, + uint32_t ul_cmd_st, uint32_t ul_cmd_sp, + uint32_t *p_ul_buf, uint32_t ul_size); + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +#endif /* EFC_H_INCLUDED */ diff --git a/src/flash_efc.cpp b/src/flash_efc.cpp new file mode 100644 index 0000000..c7b3aa8 --- /dev/null +++ b/src/flash_efc.cpp @@ -0,0 +1,916 @@ +/** + * \file + * + * \brief Embedded Flash service for SAM. + * + * Copyright (c) 2011-2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#include +#include +#include "flash_efc.h" + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/** + * \defgroup sam_services_flash_efc_group Embedded Flash Service + * + * The Embedded Flash service provides functions for internal flash operations. + * + * @{ + */ + +#if SAM4E +/* User signature size */ +# define FLASH_USER_SIG_SIZE (512) +#endif + +#if SAM4S +/* Internal Flash Controller 0. */ +# define EFC EFC0 +/* User signature size */ +# define FLASH_USER_SIG_SIZE (512) +/* Internal Flash 0 base address. */ +# define IFLASH_ADDR IFLASH0_ADDR +/* Internal flash page size. */ +# define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE +/* Internal flash lock region size. */ +# define IFLASH_LOCK_REGION_SIZE IFLASH0_LOCK_REGION_SIZE +#endif + +/* Internal Flash Controller 0. */ +# define EFC EFC0 +/* The max GPNVM number. */ +# define GPNVM_NUM_MAX 3 +/* Internal Flash 0 base address. */ +# define IFLASH_ADDR IFLASH0_ADDR +/* Internal flash page size. */ +# define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE +/* Internal flash lock region size. */ +# define IFLASH_LOCK_REGION_SIZE IFLASH0_LOCK_REGION_SIZE + +/* Flash page buffer for alignment */ +static uint32_t gs_ul_page_buffer[IFLASH_PAGE_SIZE / sizeof(uint32_t)]; + +/** + * \brief Translate the given flash address to page and offset values. + * \note pus_page and pus_offset must not be null in order to store the + * corresponding values. + * + * \param pp_efc Pointer to an EFC pointer. + * \param ul_addr Address to translate. + * \param pus_page The first page accessed. + * \param pus_offset Byte offset in the first page. + */ +static void translate_address(Efc **pp_efc, uint32_t ul_addr, + uint16_t *pus_page, uint16_t *pus_offset) +{ + Efc *p_efc; + uint16_t us_page; + uint16_t us_offset; + + if (ul_addr >= IFLASH1_ADDR) { + p_efc = EFC1; + us_page = (ul_addr - IFLASH1_ADDR) / IFLASH1_PAGE_SIZE; + us_offset = (ul_addr - IFLASH1_ADDR) % IFLASH1_PAGE_SIZE; + } else { + p_efc = EFC0; + us_page = (ul_addr - IFLASH0_ADDR) / IFLASH0_PAGE_SIZE; + us_offset = (ul_addr - IFLASH0_ADDR) % IFLASH0_PAGE_SIZE; + } + + /* Store values */ + if (pp_efc) { + *pp_efc = p_efc; + } + + if (pus_page) { + *pus_page = us_page; + } + + if (pus_offset) { + *pus_offset = us_offset; + } +} + +/** + * \brief Compute the address of a flash by the given page and offset. + * + * \param p_efc Pointer to an EFC instance. + * \param us_page Page number. + * \param us_offset Byte offset inside page. + * \param pul_addr Computed address (optional). + */ +static void compute_address(Efc *p_efc, uint16_t us_page, uint16_t us_offset, + uint32_t *pul_addr) +{ + uint32_t ul_addr; + +/* Dual bank flash */ +#ifdef EFC1 + /* Compute address */ + ul_addr = (p_efc == EFC0) ? + IFLASH0_ADDR + us_page * IFLASH_PAGE_SIZE + us_offset : + IFLASH1_ADDR + us_page * IFLASH_PAGE_SIZE + us_offset; + +/* One bank flash */ +#else + /* avoid Cppcheck Warning */ + UNUSED(p_efc); + /* Compute address */ + ul_addr = IFLASH_ADDR + us_page * IFLASH_PAGE_SIZE + us_offset; +#endif + + /* Store result */ + if (pul_addr != NULL) { + *pul_addr = ul_addr; + } +} + +/** + * \brief Compute the lock range associated with the given address range. + * + * \param ul_start Start address of lock range. + * \param ul_end End address of lock range. + * \param pul_actual_start Actual start address of lock range. + * \param pul_actual_end Actual end address of lock range. + */ +static void compute_lock_range(uint32_t ul_start, uint32_t ul_end, + uint32_t *pul_actual_start, uint32_t *pul_actual_end) +{ + uint32_t ul_actual_start, ul_actual_end; + + ul_actual_start = ul_start - (ul_start % IFLASH_LOCK_REGION_SIZE); + ul_actual_end = ul_end - (ul_end % IFLASH_LOCK_REGION_SIZE) + + IFLASH_LOCK_REGION_SIZE - 1; + + if (pul_actual_start) { + *pul_actual_start = ul_actual_start; + } + + if (pul_actual_end) { + *pul_actual_end = ul_actual_end; + } +} + +/** + * \brief Initialize the flash service. + * + * \param ul_mode FLASH_ACCESS_MODE_128 or FLASH_ACCESS_MODE_64. + * \param ul_fws The number of wait states in cycle (no shift). + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_init(uint32_t ul_mode, uint32_t ul_fws) +{ + efc_init(EFC, ul_mode, ul_fws); + +#ifdef EFC1 + efc_init(EFC1, ul_mode, ul_fws); +#endif + + return FLASH_RC_OK; +} + +/** + * \brief Set flash wait state. + * + * \param ul_address Flash bank start address. + * \param ul_fws The number of wait states in cycle (no shift). + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_set_wait_state(uint32_t ul_address, uint32_t ul_fws) +{ + Efc *p_efc; + + translate_address(&p_efc, ul_address, NULL, NULL); + efc_set_wait_state(p_efc, ul_fws); + + return FLASH_RC_OK; +} + +/** + * \brief Set flash wait state. + * + * \param ul_address Flash bank start address. + * \param ul_fws The number of wait states in cycle (no shift). + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_set_wait_state_adaptively(uint32_t ul_address) +{ + Efc *p_efc; + uint32_t clock = SystemCoreClock; + + translate_address(&p_efc, ul_address, NULL, NULL); + + /* Set FWS for embedded Flash access according to operating frequency */ + if (clock < CHIP_FREQ_FWS_0) { + efc_set_wait_state(p_efc, 0); + } else if (clock < CHIP_FREQ_FWS_1) { + efc_set_wait_state(p_efc, 1); + } else if (clock < CHIP_FREQ_FWS_2) { + efc_set_wait_state(p_efc, 2); + } else if (clock < CHIP_FREQ_FWS_3) { + efc_set_wait_state(p_efc, 3); + } else { + efc_set_wait_state(p_efc, 4); + } + return FLASH_RC_OK; +} + +/** + * \brief Get flash wait state. + * + * \param ul_address Flash bank start address. + * + * \return The number of wait states in cycle (no shift). + */ +uint32_t flash_get_wait_state(uint32_t ul_address) +{ + Efc *p_efc; + + translate_address(&p_efc, ul_address, NULL, NULL); + return efc_get_wait_state(p_efc); +} + +/** + * \brief Get flash descriptor. + * + * \param ul_address Flash bank start address. + * \param pul_flash_descriptor Pointer to a data buffer to store flash descriptor. + * \param ul_size Data buffer size in DWORD. + * + * \return The actual descriptor length. + */ +uint32_t flash_get_descriptor(uint32_t ul_address, + uint32_t *pul_flash_descriptor, uint32_t ul_size) +{ + Efc *p_efc; + uint32_t ul_tmp; + uint32_t ul_cnt; + + translate_address(&p_efc, ul_address, NULL, NULL); + + /* Command fails */ + if (FLASH_RC_OK != efc_perform_command(p_efc, EFC_FCMD_GETD, 0)) { + return 0; + } else { + /* Read until no result */ + for (ul_cnt = 0;; ul_cnt++) { + ul_tmp = efc_get_result(p_efc); + if ((ul_size > ul_cnt) && (ul_tmp != 0)) { + *pul_flash_descriptor++ = ul_tmp; + } else { + break; + } + } + } + + return ul_cnt; +} + +/** + * \brief Get flash total page count for the specified bank. + * + * \note The flash descriptor must be fetched from flash_get_descriptor + * function first. + * + * \param pul_flash_descriptor Pointer to a flash descriptor. + * + * \return The flash total page count. + */ +uint32_t flash_get_page_count(const uint32_t *pul_flash_descriptor) +{ + return (pul_flash_descriptor[1] / pul_flash_descriptor[2]); +} + +/** + * \brief Get flash page count per region (plane) for the specified bank. + * + * \note The flash descriptor must be fetched from flash_get_descriptor + * function first. + * + * \param pul_flash_descriptor Pointer to a flash descriptor. + * + * \return The flash page count per region (plane). + */ +uint32_t flash_get_page_count_per_region(const uint32_t *pul_flash_descriptor) +{ + return (pul_flash_descriptor[4] / pul_flash_descriptor[2]); +} + +/** + * \brief Get flash region (plane) count for the specified bank. + * + * \note The flash descriptor must be fetched from flash_get_descriptor + * function first. + * + * \param pul_flash_descriptor Pointer to a flash descriptor. + * + * \return The flash region (plane) count. + */ +uint32_t flash_get_region_count(const uint32_t *pul_flash_descriptor) +{ + return (pul_flash_descriptor[3]); +} + +/** + * \brief Erase the entire flash. + * + * \note Only the flash bank including ul_address will be erased. If there are + * two flash banks, we need to call this function twice with each bank start + * address. + * + * \param ul_address Flash bank start address. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_erase_all(uint32_t ul_address) +{ + Efc *p_efc; + + translate_address(&p_efc, ul_address, NULL, NULL); + + if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EA, 0)) { + return FLASH_RC_ERROR; + } + + return FLASH_RC_OK; +} + +#if SAM3SD8 +/** + * \brief Erase the flash by plane. + * + * \param ul_address Flash plane start address. + * + * \note Erase plane command needs a page number parameter which belongs to + * the plane to be erased. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_erase_plane(uint32_t ul_address) +{ + Efc *p_efc; + uint16_t us_page; + + translate_address(&p_efc, ul_address, &us_page, NULL); + + if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EPL, us_page)) { + return FLASH_RC_ERROR; + } + + return FLASH_RC_OK; +} +#endif + +#if (SAM4S || SAM4E) +/** + * \brief Erase the specified pages of flash. + * + * \param ul_address Flash bank start address. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num) +{ + Efc *p_efc; + uint16_t us_page; + + if (uc_page_num >= IFLASH_ERASE_PAGES_INVALID) { + return FLASH_RC_INVALID; + } + + if (ul_address & (IFLASH_PAGE_SIZE - 1)) { + return FLASH_RC_INVALID; + } + + translate_address(&p_efc, ul_address, &us_page, NULL); + + if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_EPA, + (us_page | uc_page_num))) { + return FLASH_RC_ERROR; + } + + return FLASH_RC_OK; +} + +/** + * \brief Erase the flash sector. + * + * \note Erase sector command needs a page number parameter which belongs to + * the sector to be erased. + * + * \param ul_address Flash sector start address. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_erase_sector(uint32_t ul_address) +{ + Efc *p_efc; + uint16_t us_page; + + translate_address(&p_efc, ul_address, &us_page, NULL); + + if (EFC_RC_OK != efc_perform_command(p_efc, EFC_FCMD_ES, us_page)) { + return FLASH_RC_ERROR; + } + + return FLASH_RC_OK; +} +#endif + +/** + * \brief Write a data buffer on flash. + * + * \note This function works in polling mode, and thus only returns when the + * data has been effectively written. + * \note For dual bank flash, this function doesn't support cross write from + * bank 0 to bank 1. In this case, flash_write must be called twice (ie for + * each bank). + * + * \param ul_address Write address. + * \param p_buffer Data buffer. + * \param ul_size Size of data buffer in bytes. + * \param ul_erase_flag Flag to set if erase first. + * + * \return 0 if successful, otherwise returns an error code. + */ +uint32_t flash_write(uint32_t ul_address, const void *p_buffer, + uint32_t ul_size, uint32_t ul_erase_flag) +{ + Efc *p_efc; + uint32_t ul_fws_temp; + uint16_t us_page; + uint16_t us_offset; + uint32_t writeSize; + uint32_t ul_page_addr; + uint16_t us_padding; + uint32_t ul_error; + uint32_t ul_idx; + uint32_t *p_aligned_dest; + uint8_t *puc_page_buffer = (uint8_t *) gs_ul_page_buffer; + + translate_address(&p_efc, ul_address, &us_page, &us_offset); + + /* According to the errata, set the wait state value to 6. */ + ul_fws_temp = efc_get_wait_state(p_efc); + efc_set_wait_state(p_efc, 6); + + /* Write all pages */ + while (ul_size > 0) { + /* Copy data in temporary buffer to avoid alignment problems. */ + writeSize = Min((uint32_t) IFLASH_PAGE_SIZE - us_offset, + ul_size); + compute_address(p_efc, us_page, 0, &ul_page_addr); + us_padding = IFLASH_PAGE_SIZE - us_offset - writeSize; + + /* Pre-buffer data */ + memcpy(puc_page_buffer, (void *)ul_page_addr, us_offset); + + /* Buffer data */ + memcpy(puc_page_buffer + us_offset, p_buffer, writeSize); + + /* Post-buffer data */ + memcpy(puc_page_buffer + us_offset + writeSize, + (void *)(ul_page_addr + us_offset + writeSize), + us_padding); + + /* Write page. + * Writing 8-bit and 16-bit data is not allowed and may lead to + * unpredictable data corruption. + */ + p_aligned_dest = (uint32_t *) ul_page_addr; + for (ul_idx = 0; ul_idx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); + ++ul_idx) { + *p_aligned_dest++ = gs_ul_page_buffer[ul_idx]; + } + + if (ul_erase_flag) { + ul_error = efc_perform_command(p_efc, EFC_FCMD_EWP, + us_page); + } else { + ul_error = efc_perform_command(p_efc, EFC_FCMD_WP, + us_page); + } + + if (ul_error) { + return ul_error; + } + + /* Progression */ + p_buffer = (void *)((uint32_t) p_buffer + writeSize); + ul_size -= writeSize; + us_page++; + us_offset = 0; + } + + /* According to the errata, restore the wait state value. */ + efc_set_wait_state(p_efc, ul_fws_temp); + + return FLASH_RC_OK; +} + + +/** + * \brief Lock all the regions in the given address range. The actual lock + * range is reported through two output parameters. + * + * \param ul_start Start address of lock range. + * \param ul_end End address of lock range. + * \param pul_actual_start Start address of the actual lock range (optional). + * \param pul_actual_end End address of the actual lock range (optional). + * + * \return 0 if successful, otherwise returns an error code. + */ +uint32_t flash_lock(uint32_t ul_start, uint32_t ul_end, + uint32_t *pul_actual_start, uint32_t *pul_actual_end) +{ + Efc *p_efc; + uint32_t ul_actual_start, ul_actual_end; + uint16_t us_start_page, us_end_page; + uint32_t ul_error; + uint16_t us_num_pages_in_region = + IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; + + /* Compute actual lock range and store it */ + compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end); + + if (pul_actual_start != NULL) { + *pul_actual_start = ul_actual_start; + } + + if (pul_actual_end != NULL) { + *pul_actual_end = ul_actual_end; + } + + /* Compute page numbers */ + translate_address(&p_efc, ul_actual_start, &us_start_page, 0); + translate_address(0, ul_actual_end, &us_end_page, 0); + + /* Lock all pages */ + while (us_start_page < us_end_page) { + ul_error = efc_perform_command(p_efc, EFC_FCMD_SLB, us_start_page); + + if (ul_error) { + return ul_error; + } + us_start_page += us_num_pages_in_region; + } + + return FLASH_RC_OK; +} + +/** + * \brief Unlock all the regions in the given address range. The actual unlock + * range is reported through two output parameters. + * + * \param ul_start Start address of unlock range. + * \param ul_end End address of unlock range. + * \param pul_actual_start Start address of the actual unlock range (optional). + * \param pul_actual_end End address of the actual unlock range (optional). + * + * \return 0 if successful, otherwise returns an error code. + */ +uint32_t flash_unlock(uint32_t ul_start, uint32_t ul_end, + uint32_t *pul_actual_start, uint32_t *pul_actual_end) +{ + Efc *p_efc; + uint32_t ul_actual_start, ul_actual_end; + uint16_t us_start_page, us_end_page; + uint32_t ul_error; + uint16_t us_num_pages_in_region = + IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; + + /* Compute actual unlock range and store it */ + compute_lock_range(ul_start, ul_end, &ul_actual_start, &ul_actual_end); + if (pul_actual_start != NULL) { + *pul_actual_start = ul_actual_start; + } + if (pul_actual_end != NULL) { + *pul_actual_end = ul_actual_end; + } + + /* Compute page numbers */ + translate_address(&p_efc, ul_actual_start, &us_start_page, 0); + translate_address(0, ul_actual_end, &us_end_page, 0); + + /* Unlock all pages */ + while (us_start_page < us_end_page) { + ul_error = efc_perform_command(p_efc, EFC_FCMD_CLB, + us_start_page); + if (ul_error) { + return ul_error; + } + us_start_page += us_num_pages_in_region; + } + + return FLASH_RC_OK; +} + +/** + * \brief Get the number of locked regions inside the given address range. + * + * \param ul_start Start address of range + * \param ul_end End address of range. + * + * \return The number of locked regions inside the given address range. + */ +uint32_t flash_is_locked(uint32_t ul_start, uint32_t ul_end) +{ + Efc *p_efc; + uint16_t us_start_page, us_end_page; + uint8_t uc_start_region, uc_end_region; + uint16_t us_num_pages_in_region; + uint32_t ul_status; + uint32_t ul_error; + uint32_t ul_num_locked_regions = 0; + uint32_t ul_count = 0; + uint32_t ul_bit = 0; + + /* Compute page numbers */ + translate_address(&p_efc, ul_start, &us_start_page, 0); + translate_address(0, ul_end, &us_end_page, 0); + + /* Compute region numbers */ + us_num_pages_in_region = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE; + uc_start_region = us_start_page / us_num_pages_in_region; + uc_end_region = us_end_page / us_num_pages_in_region; + + /* Retrieve lock status */ + ul_error = efc_perform_command(p_efc, EFC_FCMD_GLB, 0); + + /* Skip unrequested regions (if necessary) */ + ul_status = efc_get_result(p_efc); + while (!(ul_count <= uc_start_region && + uc_start_region < (ul_count + 32))) { + ul_status = efc_get_result(p_efc); + ul_count += 32; + } + + /* Check status of each involved region */ + ul_bit = uc_start_region - ul_count; + + /* Number of region to check (must be > 0) */ + ul_count = uc_end_region - uc_start_region + 1; + + while (ul_count > 0) { + if (ul_status & (1 << (ul_bit))) { + ul_num_locked_regions++; + } + + ul_count -= 1; + ul_bit += 1; + if (ul_bit == 32) { + ul_status = efc_get_result(p_efc); + ul_bit = 0; + } + } + + return ul_num_locked_regions; +} + +/** + * \brief Set the given GPNVM bit. + * + * \param ul_gpnvm GPNVM bit index. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_set_gpnvm(uint32_t ul_gpnvm) +{ + if (ul_gpnvm >= GPNVM_NUM_MAX) { + return FLASH_RC_INVALID; + } + + if (FLASH_RC_YES == flash_is_gpnvm_set(ul_gpnvm)) { + return FLASH_RC_OK; + } + + if (EFC_RC_OK == efc_perform_command(EFC, EFC_FCMD_SGPB, ul_gpnvm)) { + return FLASH_RC_OK; + } + + return FLASH_RC_ERROR; +} + +/** + * \brief Clear the given GPNVM bit. + * + * \param ul_gpnvm GPNVM bit index. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_clear_gpnvm(uint32_t ul_gpnvm) +{ + if (ul_gpnvm >= GPNVM_NUM_MAX) { + return FLASH_RC_INVALID; + } + + if (FLASH_RC_NO == flash_is_gpnvm_set(ul_gpnvm)) { + return FLASH_RC_OK; + } + + if (EFC_RC_OK == efc_perform_command(EFC, EFC_FCMD_CGPB, ul_gpnvm)) { + return FLASH_RC_OK; + } + + return FLASH_RC_ERROR; +} + +/** + * \brief Check if the given GPNVM bit is set or not. + * + * \param ul_gpnvm GPNVM bit index. + * + * \retval 1 If the given GPNVM bit is currently set. + * \retval 0 If the given GPNVM bit is currently cleared. + */ +uint32_t flash_is_gpnvm_set(uint32_t ul_gpnvm) +{ + uint32_t ul_gpnvm_bits; + + if (ul_gpnvm >= GPNVM_NUM_MAX) { + return FLASH_RC_INVALID; + } + + if (EFC_RC_OK != efc_perform_command(EFC, EFC_FCMD_GGPB, 0)) { + return FLASH_RC_ERROR; + } + + ul_gpnvm_bits = efc_get_result(EFC); + if (ul_gpnvm_bits & (1 << ul_gpnvm)) { + return FLASH_RC_YES; + } + + return FLASH_RC_NO; +} + +/** + * \brief Set security bit. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_enable_security_bit(void) +{ + return flash_set_gpnvm(0); +} + +/** + * \brief Check if the security bit is set or not. + * + * \retval 1 If the security bit is currently set. + * \retval 0 If the security bit is currently cleared. + */ +uint32_t flash_is_security_bit_enabled(void) +{ + return flash_is_gpnvm_set(0); +} + +/** + * \brief Read the flash unique ID. + * + * \param pul_data Pointer to a data buffer to store 128-bit unique ID. + * \param ul_size Data buffer size in DWORD. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_read_unique_id(uint32_t *pul_data, uint32_t ul_size) +{ + uint32_t uid_buf[4]; + uint32_t ul_idx; + + if (FLASH_RC_OK != efc_perform_read_sequence(EFC, EFC_FCMD_STUI, + EFC_FCMD_SPUI, uid_buf, 4)) { + return FLASH_RC_ERROR; + } + + if (ul_size > 4) { + /* Only 4 dword to store unique ID */ + ul_size = 4; + } + + for (ul_idx = 0; ul_idx < ul_size; ul_idx++) { + pul_data[ul_idx] = uid_buf[ul_idx]; + } + + return FLASH_RC_OK; +} + +#if (SAM4S || SAM4E) +/** + * \brief Read the flash user signature. + * + * \param p_data Pointer to a data buffer to store 512 bytes of user signature. + * \param ul_size Data buffer size. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size) +{ + if (ul_size > FLASH_USER_SIG_SIZE) { + /* Only 512 byte to store unique ID */ + ul_size = FLASH_USER_SIG_SIZE; + } + + /* Send the read user signature commands */ + if (FLASH_RC_OK != efc_perform_read_sequence(EFC, EFC_FCMD_STUS, + EFC_FCMD_SPUS, p_data, ul_size)) { + return FLASH_RC_ERROR; + } + + return FLASH_RC_OK; +} + +/** + * \brief Write the flash user signature. + * + * \param ul_address Write address. + * \param p_data Pointer to a data buffer to store 512 bytes of user signature. + * \param ul_size Data buffer size. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_write_user_signature(uint32_t ul_address, const void *p_buffer, + uint32_t ul_size) +{ + /* The user signature should be no longer than 512 bytes */ + if (ul_size > FLASH_USER_SIG_SIZE) { + return FLASH_RC_INVALID; + } + + /* Write the full page */ + flash_write(ul_address, p_buffer, ul_size, 0); + + /* Send the write signature command */ + if (FLASH_RC_OK != efc_perform_command(EFC, EFC_FCMD_WUS, 0)) { + return FLASH_RC_ERROR; + } + + return FLASH_RC_OK; +} + +/** + * \brief Erase the flash user signature. + * + * \return 0 if successful; otherwise returns an error code. + */ +uint32_t flash_erase_user_signature(void) +{ + /* Perform the erase user signature command */ + return efc_perform_command(EFC, EFC_FCMD_EUS, 0); +} +#endif + +//@} + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond diff --git a/src/flash_efc.h b/src/flash_efc.h new file mode 100644 index 0000000..bd52033 --- /dev/null +++ b/src/flash_efc.h @@ -0,0 +1,151 @@ +/** + * \file + * + * \brief Embedded Flash service for SAM. + * + * Copyright (c) 2011-2013 Atmel Corporation. All rights reserved. + * + * \asf_license_start + * + * \page License + * + * 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. The name of Atmel may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * 4. This software may only be redistributed and used in connection with an + * Atmel microcontroller product. + * + * THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE + * EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL 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. + * + * \asf_license_stop + * + */ + +#ifndef FLASH_H_INCLUDED +#define FLASH_H_INCLUDED + +#include +#include "efc.h" + +/* Internal Flash 0 base address. */ +#define IFLASH_ADDR IFLASH0_ADDR + /* Internal flash page size. */ +#define IFLASH_PAGE_SIZE IFLASH0_PAGE_SIZE + +/* Last page start address. */ +#define IFLASH_LAST_PAGE_ADDRESS (IFLASH1_ADDR + IFLASH1_SIZE - IFLASH1_PAGE_SIZE) + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus + extern "C" { +#endif +/**INDENT-ON**/ +/// @endcond + +/*! \name Flash driver return codes */ +//! @{ +typedef enum flash_rc { + FLASH_RC_OK = 0, //!< Operation OK + FLASH_RC_YES = 0, //!< Yes + FLASH_RC_NO = 1, //!< No + FLASH_RC_ERROR = 0x10, //!< General error + FLASH_RC_INVALID, //!< Invalid argument input + FLASH_RC_NOT_SUPPORT = 0xFFFFFFFF //!< Operation is not supported +} flash_rc_t; +//! @} + +/*! \name Flash erase page num in FARG[1:0] + \note The erase page commands should be cautiouly used as EPA4/EPA32 will not + take effect according to errata and EPA8/EPA16 must module 8/16 page addresses.*/ +//! @{ +typedef enum flash_farg_page_num { + /* 4 of pages to be erased with EPA command*/ + IFLASH_ERASE_PAGES_4=0, + /* 8 of pages to be erased with EPA command*/ + IFLASH_ERASE_PAGES_8, + /* 16 of pages to be erased with EPA command*/ + IFLASH_ERASE_PAGES_16, + /* 32 of pages to be erased with EPA command*/ + IFLASH_ERASE_PAGES_32, + /* Parameter is not support */ + IFLASH_ERASE_PAGES_INVALID, +}flash_farg_page_num_t; +//! @} + +/*! \name Flash access mode */ +//! @{ +#define FLASH_ACCESS_MODE_128 EFC_ACCESS_MODE_128 +#define FLASH_ACCESS_MODE_64 EFC_ACCESS_MODE_64 +//! @} + +uint32_t flash_init(uint32_t ul_mode, uint32_t ul_fws); +uint32_t flash_set_wait_state(uint32_t ul_address, uint32_t ul_fws); +uint32_t flash_set_wait_state_adaptively(uint32_t ul_address); +uint32_t flash_get_wait_state(uint32_t ul_address); +uint32_t flash_get_descriptor(uint32_t ul_address, + uint32_t *pul_flash_descriptor, uint32_t ul_size); +uint32_t flash_get_page_count(const uint32_t *pul_flash_descriptor); +uint32_t flash_get_page_count_per_region(const uint32_t *pul_flash_descriptor); +uint32_t flash_get_region_count(const uint32_t *pul_flash_descriptor); +uint32_t flash_erase_all(uint32_t ul_address); + +#if SAM3SD8 +uint32_t flash_erase_plane(uint32_t ul_address); +#endif + +#if (SAM4S || SAM4E) +uint32_t flash_erase_page(uint32_t ul_address, uint8_t uc_page_num); +uint32_t flash_erase_sector(uint32_t ul_address); +#endif + +uint32_t flash_write(uint32_t ul_address, const void *p_buffer, + uint32_t ul_size, uint32_t ul_erase_flag); +uint32_t flash_lock(uint32_t ul_start, uint32_t ul_end, + uint32_t *pul_actual_start, uint32_t *pul_actual_end); +uint32_t flash_unlock(uint32_t ul_start, uint32_t ul_end, + uint32_t *pul_actual_start, uint32_t *pul_actual_end); +uint32_t flash_is_locked(uint32_t ul_start, uint32_t ul_end); +uint32_t flash_set_gpnvm(uint32_t ul_gpnvm); +uint32_t flash_clear_gpnvm(uint32_t ul_gpnvm); +uint32_t flash_is_gpnvm_set(uint32_t ul_gpnvm); +uint32_t flash_enable_security_bit(void); +uint32_t flash_is_security_bit_enabled(void); +uint32_t flash_read_unique_id(uint32_t *pul_data, uint32_t ul_size); + +#if (SAM4S || SAM4E) +uint32_t flash_read_user_signature(uint32_t *p_data, uint32_t ul_size); +uint32_t flash_write_user_signature(uint32_t ul_address, const void *p_buffer, + uint32_t ul_size); +uint32_t flash_erase_user_signature(void); +#endif + +/// @cond 0 +/**INDENT-OFF**/ +#ifdef __cplusplus +} +#endif +/**INDENT-ON**/ +/// @endcond + +#endif /* FLASH_H_INCLUDED */ From 7b82b0a5089a26a582efe73431586b31215a7f85 Mon Sep 17 00:00:00 2001 From: Andrey Klimov Date: Sun, 14 Jun 2020 16:52:00 +0300 Subject: [PATCH 5/5] finally fix DUE OTA --- src/ArduinoOTA.h | 8 -- src/InternalStorage.cpp | 213 +++++++++++++++++++++++++++------------- src/InternalStorage.h | 11 +-- src/OTAStorage.cpp | 7 +- 4 files changed, 154 insertions(+), 85 deletions(-) diff --git a/src/ArduinoOTA.h b/src/ArduinoOTA.h index 534c787..f0d3a45 100644 --- a/src/ArduinoOTA.h +++ b/src/ArduinoOTA.h @@ -44,23 +44,19 @@ template class ArduinoOTAClass : public WiFiOTAClass { private: -// bool init; NetServer server; public: ArduinoOTAClass() : server(OTA_PORT) { - //init=false; }; void begin(IPAddress localIP, const char* name, const char* password, OTAStorage& storage) { WiFiOTAClass::begin(localIP, name, password, storage); server.begin(); - //init=true; } void end() { - //init=false; #if defined(ESP8266) || defined(ESP32) server.stop(); #elif defined(_WIFI_ESP_AT_H_) @@ -71,12 +67,8 @@ class ArduinoOTAClass : public WiFiOTAClass { } void poll() { - //if (init) - //{ NetClient client = server.available(); pollServer(client); - // } - // else Serial.write("."); } void handle() { // alias diff --git a/src/InternalStorage.cpp b/src/InternalStorage.cpp index ac51f9a..e1ddce2 100644 --- a/src/InternalStorage.cpp +++ b/src/InternalStorage.cpp @@ -35,20 +35,14 @@ InternalStorageClass::InternalStorageClass() : -#if defined(__SAM3X8E__) - MAX_PARTIONED_SKETCH_SIZE(256*1024), - STORAGE_START_ADDRESS(IFLASH1_ADDR) -#else MAX_PARTIONED_SKETCH_SIZE((MAX_FLASH - SKETCH_START_ADDRESS) / 2), STORAGE_START_ADDRESS(SKETCH_START_ADDRESS + MAX_PARTIONED_SKETCH_SIZE) -#endif -{ +{ _writeIndex = 0; _writeAddress = nullptr; - + _sketchSize = 0; #if defined(__SAM3X8E__) flash_init(FLASH_ACCESS_MODE_128, 6); - //if (retCode != FLASH_RC_OK) #endif } @@ -102,23 +96,38 @@ extern "C" { #endif } - __attribute__ ((long_call, noinline, section (".data#"))) - static void copyFlashAndReset(int dest, int src, int length, int pageSize) - { + #if defined(__SAM3X8E__) -flash_set_gpnvm(1); //Booting from FLASH +#define us_num_pages_in_region (IFLASH0_LOCK_REGION_SIZE / IFLASH0_PAGE_SIZE) +#define RAMFUNC __attribute__ ((section(".ramfunc"))) +extern void copyFlashAndReset(int dest, int src, int length, int pageSize); +RAMFUNC void copyFlashAndReset(int dest, int src, int length, int pageSize) + +{ +static uint32_t(*iap_perform_command) (uint32_t, uint32_t); +uint32_t ul_efc_nb; +/* Use IAP function with 2 parameters in ROM. */ +iap_perform_command = (uint32_t(*)(uint32_t, uint32_t)) *((uint32_t *) CHIP_FLASH_IAP_ADDRESS); +ul_efc_nb = 0; + + + +//Bank swithch forction not working on SAM with firmware>64K - see Errata /* -HMM not working - starting & hung // Not actual copy, just switch banks +flash_set_gpnvm(1); //Booting from FLASH + if (FLASH_RC_YES == flash_is_gpnvm_set(2)) // BANK1 is active { Serial.println("Switching to BANK0"); delay(500); noInterrupts(); -flash_clear_gpnvm(2); +//flash_clear_gpnvm(2); +iap_perform_command(ul_efc_nb, EEFC_FCR_FKEY(0x5Au) | EEFC_FCR_FARG(2) | + EEFC_FCR_FCMD(EFC_FCMD_CGPB)); } else @@ -126,48 +135,109 @@ else Serial.println("Switching to BANK1"); delay(500); noInterrupts(); -flash_set_gpnvm(2); +//flash_set_gpnvm(2); +iap_perform_command(ul_efc_nb, EEFC_FCR_FKEY(0x5Au) | EEFC_FCR_FARG(2) | + EEFC_FCR_FCMD(EFC_FCMD_SGPB)); } -*/ +RSTC->RSTC_CR = 0xA5000005; +*/ // Since bank swithing is not working - just copy to bank0 from bank1 -int retCode = flash_unlock((uint32_t)dest, (uint32_t) src-1, 0, 0); - if (retCode != FLASH_RC_OK) { - Serial.println("Failed to unlock bank0 for write\n"); - } +Efc *p_efc; +uint16_t us_page; +uint32_t *p_src; +uint32_t *p_dest; +int32_t left; + + Serial.print("Flashing bytes:"); Serial.println(length); +Serial.print("From:"); +Serial.println(src,HEX); +Serial.print("To:"); +Serial.println(dest,HEX); +Serial.print("PageSize:"); +Serial.println(pageSize); + + delay(300); +watchdogReset(); -noInterrupts(); -//NOt working -//eraseFlash(dest, length, pageSize); -//flash_erase_all(dest); +flash_set_gpnvm(1); //Booting from FLASH + +// Preparing to flashing + +p_efc = EFC0; +us_page = 0; -while (length>=256) +efc_set_wait_state(p_efc, 6); +p_dest = (uint32_t *) dest; +p_src = (uint32_t *) src; +left = length; + +noInterrupts(); + +while (left>0) { - flash_write(dest,(void*) src,256,1); - dest+=256; - src+=256; - length-=256; - watchdogReset(); + // Dangerous zone - no exterlal flash based routines allowed below + + // Unlock range + if (! (us_page % us_num_pages_in_region)) + iap_perform_command(ul_efc_nb, + EEFC_FCR_FKEY(0x5Au) | EEFC_FCR_FARG(us_page) | + EEFC_FCR_FCMD(EFC_FCMD_CLB)); + + // Copy page + for (int ul_idx = 0; ul_idx < (IFLASH0_PAGE_SIZE / sizeof(uint32_t)); ++ul_idx) + { + *p_dest++ = *p_src++; + } + + + if ((us_page+1) % us_num_pages_in_region) + + // Erase & write page + iap_perform_command(ul_efc_nb, + EEFC_FCR_FKEY(0x5Au) | EEFC_FCR_FARG(us_page) | + EEFC_FCR_FCMD(EFC_FCMD_EWP)); + // result at (p_efc->EEFC_FSR & EEFC_ERROR_FLAGS); + + else // last page in the lock region + // Erase, write, lock page + iap_perform_command(ul_efc_nb, + EEFC_FCR_FKEY(0x5Au) | EEFC_FCR_FARG(us_page) | + EEFC_FCR_FCMD(EFC_FCMD_EWPL)); + // result at (p_efc->EEFC_FSR & EEFC_ERROR_FLAGS); + + + + + us_page++; + left -= IFLASH0_PAGE_SIZE; + //watchdogReset(); + } -flash_write(dest,(void*) src,length,1); +// End low-level flashing code + -// Locking flash -retCode = flash_lock((uint32_t)dest, (uint32_t) src-1, 0, 0); - -//Todo - clean STORAGE (not working) -//flash_erase_all(src); +//Restart RSTC->RSTC_CR = 0xA5000005; +} + + #else + + __attribute__ ((long_call, noinline, section (".data#"))) + static void copyFlashAndReset(int dest, int src, int length, int pageSize) + { uint32_t* d = (uint32_t*)dest; uint32_t* s = (uint32_t*)src; - + + // disable interrupts, as vector table will be erase during flash sequence noInterrupts(); eraseFlash(dest, length, pageSize); @@ -177,11 +247,15 @@ RSTC->RSTC_CR = 0xA5000005; waitForReady(); } -#endif + NVIC_SystemReset(); - } } +#endif + +} //extern C + + int InternalStorageClass::open(int length) { (void)length; @@ -212,51 +286,53 @@ eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); size_t InternalStorageClass::write(uint8_t b) { - _addressData.u8[_writeIndex] = b; - _writeIndex++; + +#if defined(__SAM3X8E__) + _addressData[_writeIndex] = b; + _writeIndex++; - if (_writeIndex == sizeof(addressData)) { + if ( _writeIndex == IFLASH0_PAGE_SIZE ) { _writeIndex = 0; - -#if defined(__SAM3X8E__) + watchdogReset(); Serial.print("="); - int retCode = flash_write((uint32_t) _writeAddress, &_addressData.u32, sizeof(addressData), 1); + int retCode = flash_write((uint32_t) _writeAddress, &_addressData, IFLASH0_PAGE_SIZE, 0); //1? if (retCode != FLASH_RC_OK) { Serial.println("Flash write failed\n"); return 0; } _writeAddress++; - + } #else - _writeAddress->u32 = _addressData.u32; - _writeAddress++; - waitForReady(); -#endif + _addressData.u8[_writeIndex] = b; + _writeIndex++; - } + if (_writeIndex == sizeof(addressData)) { + _writeIndex = 0; + _writeAddress->u32 = _addressData.u32; + _writeAddress++; + waitForReady(); + } +#endif - return 1; +return 1; } -void InternalStorageClass::close() +void InternalStorageClass::close() { - while ((int)_writeAddress % PAGE_SIZE) { - write(0xff); - } #if defined(__SAM3X8E__) -Serial.println("\nClosing flash"); -Serial.println(MAX_PARTIONED_SKETCH_SIZE = (uint32_t)_writeAddress-STORAGE_START_ADDRESS+_writeIndex); +_sketchSize = (uint32_t)_writeAddress-STORAGE_START_ADDRESS+_writeIndex; + +while (_writeIndex) write(0xff); //Finish block - while (_writeIndex) { - write(0xff); - } +Serial.print("\nReceived bytes:"); +Serial.println(_sketchSize); +#else -//TODO not sure need to lock bank1 (storage) -// int retCode = flash_lock((uint32_t)STORAGE_START_ADDRESS, (uint32_t) STORAGE_START_ADDRESS+MAX_PARTIONED_SKETCH_SIZE-1, 0, 0); -// if (retCode != FLASH_RC_OK) -// Serial.println("Failed to lock flash for write\n"); + while ((int)_writeAddress % PAGE_SIZE) { + write(0xff); + } #endif } @@ -268,9 +344,14 @@ void InternalStorageClass::clear() void InternalStorageClass::apply() { - // disable interrupts, as vector table will be erase during flash sequence //noInterrupts(); moved inside routine + +#if defined(__SAM3X8E__) + copyFlashAndReset(SKETCH_START_ADDRESS, STORAGE_START_ADDRESS, _sketchSize, PAGE_SIZE); +#else copyFlashAndReset(SKETCH_START_ADDRESS, STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE); +#endif + } long InternalStorageClass::maxSize() diff --git a/src/InternalStorage.h b/src/InternalStorage.h index f39271b..4d3d98f 100644 --- a/src/InternalStorage.h +++ b/src/InternalStorage.h @@ -39,15 +39,14 @@ class InternalStorageClass : public OTAStorage { virtual long maxSize(); private: - //const - uint32_t MAX_PARTIONED_SKETCH_SIZE, STORAGE_START_ADDRESS; + const uint32_t MAX_PARTIONED_SKETCH_SIZE, STORAGE_START_ADDRESS; + uint32_t _sketchSize; #if defined(__SAM3X8E__) - union addressData { - uint32_t u32; - uint8_t u8[256]; - } _addressData; +// Buffer for page + typedef uint8_t addressData[256]; + addressData _addressData; #else union addressData{ uint32_t u32; diff --git a/src/OTAStorage.cpp b/src/OTAStorage.cpp index 390e58e..989a0b8 100644 --- a/src/OTAStorage.cpp +++ b/src/OTAStorage.cpp @@ -22,13 +22,10 @@ OTAStorage::OTAStorage() : SKETCH_START_ADDRESS((uint32_t) __text_start__), PAGE_SIZE(pageSizes[NVMCTRL->PARAM.bit.PSZ]), MAX_FLASH(PAGE_SIZE * NVMCTRL->PARAM.bit.NVMP - eepromSizes[EEPROM_EMULATION_RESERVATION]) - #elif defined(__SAM3X8E__) - SKETCH_START_ADDRESS((uint32_t) IFLASH0_ADDR), - PAGE_SIZE(256), - MAX_FLASH(256*1024) - + PAGE_SIZE(IFLASH0_PAGE_SIZE), + MAX_FLASH((uint32_t) IFLASH0_ADDR+512*1024) #elif defined(ARDUINO_ARCH_NRF5) SKETCH_START_ADDRESS((uint32_t) __isr_vector), PAGE_SIZE((size_t) NRF_FICR->CODEPAGESIZE),