Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added examples/OTA_Flashing/hello.bin
Binary file not shown.
1 change: 1 addition & 0 deletions examples/OTA_Flashing/upload.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
./arduinoOTA -address 192.168.88.34 -port 65280 -username arduino -password password -sketch hello.bin -b -upload /sketch
4 changes: 3 additions & 1 deletion src/ArduinoOTA.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@ class ArduinoOTAClass : public WiFiOTAClass {
NetServer server;

public:
ArduinoOTAClass() : server(OTA_PORT) {};
ArduinoOTAClass() : server(OTA_PORT)
{
};

void begin(IPAddress localIP, const char* name, const char* password, OTAStorage& storage) {
WiFiOTAClass::begin(localIP, name, password, storage);
Expand Down
245 changes: 225 additions & 20 deletions src/InternalStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,23 @@

#include "InternalStorage.h"

#if defined(__SAM3X8E__)
#include "flash_efc.h"
#include "efc.h"
#endif


InternalStorageClass::InternalStorageClass() :

MAX_PARTIONED_SKETCH_SIZE((MAX_FLASH - SKETCH_START_ADDRESS) / 2),
STORAGE_START_ADDRESS(SKETCH_START_ADDRESS + MAX_PARTIONED_SKETCH_SIZE)
{
{
_writeIndex = 0;
_writeAddress = nullptr;
_sketchSize = 0;
#if defined(__SAM3X8E__)
flash_init(FLASH_ACCESS_MODE_128, 6);
#endif
}

extern "C" {
Expand All @@ -45,6 +56,8 @@ extern "C" {
while (!NVMCTRL->INTFLAG.bit.READY);
#elif defined(ARDUINO_ARCH_NRF5)
while (NRF_NVMC->READY == NVMC_READY_READY_Busy);
#elif defined(__SAM3X8E__)
// Not used
#endif
}

Expand Down Expand Up @@ -75,78 +88,270 @@ extern "C" {
waitForReady();
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
}



#if defined(__SAM3X8E__)
#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
/*
// 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);
iap_perform_command(ul_efc_nb, EEFC_FCR_FKEY(0x5Au) | EEFC_FCR_FARG(2) |
EEFC_FCR_FCMD(EFC_FCMD_CGPB));
}

else
{
Serial.println("Switching to BANK1");
delay(500);
noInterrupts();
//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

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();


flash_set_gpnvm(1); //Booting from FLASH

// Preparing to flashing

p_efc = EFC0;
us_page = 0;

efc_set_wait_state(p_efc, 6);
p_dest = (uint32_t *) dest;
p_src = (uint32_t *) src;
left = length;

noInterrupts();

while (left>0)
{
// 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();

}
// End low-level flashing code



//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);

for (int i = 0; i < length; i += 4) {
*d++ = *s++;

waitForReady();
}

NVIC_SystemReset();
}
}

#endif

} //extern C


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");

#ifdef ARDUINO_ARCH_SAMD
// enable auto page writes
NVMCTRL->CTRLB.bit.MANW = 0;
#endif

eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE);
#if defined(__SAM3X8E__)

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");
}
#endif

eraseFlash(STORAGE_START_ADDRESS, MAX_PARTIONED_SKETCH_SIZE, PAGE_SIZE);

return 1;
}



size_t InternalStorageClass::write(uint8_t b)
{
_addressData.u8[_writeIndex] = b;
_writeIndex++;

#if defined(__SAM3X8E__)
_addressData[_writeIndex] = b;
_writeIndex++;

if (_writeIndex == 4) {
if ( _writeIndex == IFLASH0_PAGE_SIZE ) {
_writeIndex = 0;

*_writeAddress = _addressData.u32;


watchdogReset();
Serial.print("=");
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
_addressData.u8[_writeIndex] = b;
_writeIndex++;

if (_writeIndex == sizeof(addressData)) {
_writeIndex = 0;
_writeAddress->u32 = _addressData.u32;
_writeAddress++;
waitForReady();
}
#endif

waitForReady();
}

return 1;
return 1;
}

void InternalStorageClass::close()
void InternalStorageClass::close()
{
#if defined(__SAM3X8E__)
_sketchSize = (uint32_t)_writeAddress-STORAGE_START_ADDRESS+_writeIndex;

while (_writeIndex) write(0xff); //Finish block

Serial.print("\nReceived bytes:");
Serial.println(_sketchSize);
#else

while ((int)_writeAddress % PAGE_SIZE) {
write(0xff);
}
write(0xff);
}
#endif

}

void InternalStorageClass::clear()
{
}


void InternalStorageClass::apply()
{
// disable interrupts, as vector table will be erase during flash sequence
noInterrupts();
//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()
Expand Down
12 changes: 10 additions & 2 deletions src/InternalStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,14 +40,22 @@ class InternalStorageClass : public OTAStorage {

private:
const uint32_t MAX_PARTIONED_SKETCH_SIZE, STORAGE_START_ADDRESS;
uint32_t _sketchSize;

union {

#if defined(__SAM3X8E__)
// Buffer for page
typedef uint8_t addressData[256];
addressData _addressData;
#else
union addressData{
uint32_t u32;
uint8_t u8[4];
} _addressData;
#endif

int _writeIndex;
uint32_t* _writeAddress;
addressData * _writeAddress;
};

extern InternalStorageClass InternalStorage;
Expand Down
6 changes: 5 additions & 1 deletion src/OTAStorage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ 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) IFLASH0_ADDR),
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),
Expand Down
1 change: 1 addition & 0 deletions src/OTAStorage.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <Arduino.h>


class OTAStorage {
public:

Expand Down
Loading