0

I recently need to use in build NVRAM/EEPROM of AT32UC3L0256 to store some configuration data. I finally managed to use the user page NVRAM of the MCU (after days of trial and error and cursing on GCC ignoring noinit directives and fixing and workarounding bugs in ASF as usual) to something like this:

typedef struct
    {
    int writes;                 // write cycles counter
    int irc_pot;                // IRC_POT_IN position state
    } _cfg;
volatile static int *nvram_adr=(int*)(void*)0x80800000;     // user page NVRAM
volatile static _cfg    ram_cfg;                            // RAM copy of cfg

void cfg_load() // nvram_cfg -> ram_cfg
    {
    ram_cfg.writes =nvram_adr[8];
    ram_cfg.irc_pot=nvram_adr[9];
    }
void cfg_save() // nvram_cfg <- ram_cfg
    {
    int i;
    U32 buf[128];
    // blank
    for (i=0;i<128;i++) buf[i]=0xFFFFFFFF;
    // cfg
    buf[8]=ram_cfg.writes;
    buf[9]=ram_cfg.irc_pot;
    // Bootloader default cfg
    buf[126]=0x929E0B79;
    buf[127]=0xE11EFFD7;
    flashcdw_memcpy(nvram_adr   ,buf   ,256,true);  // write data -> nvram_cfg with erase
    flashcdw_memcpy(nvram_adr+64,buf+64,256,false); // write data -> nvram_cfg without erase (fucking ASF cant write more than 256Bytes at once but erases whole page !!!)
    }

I had to update flashcdw.c,flashcdw.h from ASF 3.48.0.98 in order to be able to write the full 512 Bytes as old ASF did program just up to 256 BYTES but erases whole page making a mess. I also had to store the full page (instead of just 8 bytes due to erase) and as usual due ASF bugs I needed to do it as is instead of just calling flashcdw_memcpy just once...

Its working now but I found out that some addresses are causing weird behavior. When 0xFF is not on some address the device will no longer RESET normally (but still until reset runs OK). On non Bootloader RESET it start the firmware code but after few [ms] it resets again and this goes on forever. To be clear the RESET occurs in this part of code (in my case):

for (U8 i=0;i<4;i++)
    {
    gpio_tgl_gpio_pin(_LED);
    wait_ms(200);
    }

its simple blink of LED after the system is configured (PLL CPU clock, configured timers and ISRs but interrupts still disabled). The LED blinks as should few times (PLL works on correct speed) but before loop is finished reset occurs. The wait is simple:

//------------------------------------------------------------------------------------------------
#define clk_cpu 50000000
#define RDTSC_mask 0x0FFFFFFF
void wait_ms(U32 dt)
    {
    U32 t0,t1;
    t0=Get_system_register(AVR32_COUNT);
    static const U32 ms=(clk_cpu+999)/1000;
    t0&=RDTSC_mask;
    for (;dt>0;)
        {
        t1=Get_system_register(AVR32_COUNT);
        t1&=RDTSC_mask;
        if (t0>t1)  t1+=RDTSC_mask+1;
        if ((t1-t0)>=ms)
            {
            dt--;
            t0+=ms;
            t0&=RDTSC_mask;
            continue;
            }
        }
    }
//------------------------------------------------------------------------------------------------

Even weirder is that if I boot into Bootloader and then reset normally again device is resetting properly and firmware works again (without any erasing/programing) however if I reset normally again the resetting loop occurs again ...

If I reprogram the .userpage NVRAM back to original state using BatchISP (flip) the chip works again normally.

So finally the questions:

  1. What addresses in userpage of NVRAM are causing this or should be reserved/avoided to change?

    I know the last 8 Bytes are Bootloader configuration. I suspect the problematic addresses are first 16 bytes. The .userpage should be for user data and does not contain fuses.

  2. What is happening?

    its some kind of watchdog or something? I thought those are inside fuses which are stored elsewhere. I do not see anything in datasheet.

Here hex of original .userpage:

:020000048080FA
:10000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00
:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90
:10008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
:10009000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70
:1000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:1000B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50
:1000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
:1000D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30
:1000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20
:1000F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10
:10010000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
:10011000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF
:10012000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF
:10013000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF
:10014000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF
:10015000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF
:10016000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F
:10017000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F
:10018000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F
:10019000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F
:1001A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F
:1001B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F
:1001C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F
:1001D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F
:1001E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F
:1001F000FFFFFFFFFFFFFFFF929E0B79E11EFFD77E
:00000001FF

I use these (Flip commands) to obtain and restore it:

Batchisp -device AT32UC3L0256 -hardware RS232 -port COM1 -baudrate 115200 -operation memory user read savebuffer cfg_userpage.hex hex386 start reset 0
Batchisp -device AT32UC3L0256 -hardware RS232 -port COM1 -baudrate 115200 -operation onfail abort memory user loadbuffer cfg_userpage.hex program start reset 0

The Bootloader in question is USART version: 1.0.2 And the firmware with this behavior uses PLL,TC,GPIO,PWMA,ADC modules however reset occurs before any ISR and or ADC,PWMA,TC usage.

[Edit1] Watchdog

according to this the first word in .userpage of NVRAM is a fuse for the watchdog which explains the reset after few ms once repairing the data to original values and disabling the WDT the reseting stops. However now instead of booting program the Bootloader is started instead so there is still something fishy. The Bootloader pin selection is in last 8 Bytes

Also I looked into USART Bootloader ver: 1.0.2 source and found out they are using FLASHC instead of FLASHCDW and forcing boot with watchdog (which might reset its state and enable my program to run again somehow).

[Edit2] bug isolated

I finally found out that the problem is caused by writing to last 32bit word of the 512 Byte .userpage:

U32 btldr[2]={0x929E0B79,0xE11EFFD7};
flashcdw_memcpy(&nvram_adr[127],(U32*)&btldr[1]       ,4,false);

which is a huge problem as in order to store data correctly I must use erase which erases whole page no matter what and in order to still be able to boot correctly to Bootloader or My firmware I have to restore the Bootloader configuration data:

U32 btldr[2]={0x929E0B79,0xE11EFFD7};
flashcdw_memcpy(&nvram_adr[126],(U32*)&btldr[0]       ,4,false);
flashcdw_memcpy(&nvram_adr[127],(U32*)&btldr[1]       ,4,false);

I need to find a workaround how to restore the chip to functional state. Maybe duplicate the watchdog reset from Bootloader (but that would be very problematic and even risky in my application) as it restores the chip even without any flashing...

so map for now:

:020000048080FA
:10000000---WDT--FFFFFFFFFFFFFFFFFFFFFFFF00
:10001000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0
:10002000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE0
:10003000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD0
:10004000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0
:10005000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFB0
:10006000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA0
:10007000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF90
:10008000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80
:10009000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF70
:1000A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60
:1000B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF50
:1000C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF40
:1000D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF30
:1000E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF20
:1000F000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF10
:10010000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
:10011000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF
:10012000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDF
:10013000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFCF
:10014000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBF
:10015000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFAF
:10016000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF9F
:10017000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F
:10018000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7F
:10019000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF6F
:1001A000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5F
:1001B000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F
:1001C000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F
:1001D000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF2F
:1001E000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF1F
:1001F000FFFFFFFFFFFFFFFF------BTLDR-----7E
:00000001FF

[Edit3] workaround

I managed to successfully write/read program memory FLASH (checked with BatchISP and MCU itself) it also boots OK.

Here code I test this with:

// **** test ****
volatile static U32 *flash_adr=(U32*)(void*)0x00000000;
const U32 buf[4]=
    {
    0xDEADBEEF,0x00112233,
    0xDEADBEEF,0x44556677,
    };
volatile static U32 *adr=(U32*)(void*)0x80030000;
flashcdw_memcpy(&adr[0],(U32*)buf,4*4,true ); // erase

flash_adr=(U32*)(void*)0x80000000;
for (U32 i=0;i<0x08000000;i++,flash_adr++)
    {
    if (flash_adr!=buf)
     if (flash_adr[0]==buf[0])
      if (flash_adr[1]==buf[1])
       if (flash_adr[2]==buf[2])
        if (flash_adr[3]==buf[3])
         { break; }
    if ((i&0xFFF)==0) gpio_tgl_gpio_pin(_LED);
    }

where flash_adr is the found address which contents matches the buf[] signature... (I print it on LCD so I see if it matches what I expect) and it finally does :). So I will use this instead of .userpage.

However the .userpage booting problem fix is still open question

Community
  • 1
  • 1
Spektre
  • 49,595
  • 11
  • 110
  • 380

2 Answers2

1

disable wdt early in main function

wdt_disable();

Also I think you not need to write the full page each time. flashc_memcpy takes bytes length to write while preserving other data unchanged.

unsigned char buf[AVR32_FLASHCDW_PAGE_SIZE];
void* flash_addr = AVR32_FLASHCDW_USER_PAGE;
memcpy(buf, flash_addr, 512);
// modify data in buf
flashcdw_memcpy(flash_addr, buf,AVR32_FLASHCDW_PAGE_SIZE,TRUE);

or just use

int mydata = 123;
int *nvmydata=AVR32_FLASHCDW_USER_PAGE + 16 // offset
flashcdw_memcyp(nvmydata,&mydata,sizeof(mydata),TRUE);

flashcdw_memcpy

 volatile void* flashcdw_memcpy(volatile void* dst, const void* src, size_t nbytes, Bool erase)
{
  // Use aggregated pointers to have several alignments available for a same address.
  UnionCVPtr flash_array_end;
  UnionVPtr dest;
  UnionCPtr source;
  StructCVPtr dest_end;
  UnionCVPtr flash_page_source_end;
  Bool incomplete_flash_page_end;
  Union64 flash_dword;
  Bool flash_dword_pending = FALSE;
  UnionVPtr tmp;
  unsigned int error_status = 0;
  unsigned int i, j;

  // Reformat arguments.
  flash_array_end.u8ptr = AVR32_FLASH + flashcdw_get_flash_size();
  dest.u8ptr = dst;
  source.u8ptr = src;
  dest_end.u8ptr = dest.u8ptr + nbytes;

  // If destination is outside flash, go to next flash page if any.
  if (dest.u8ptr < AVR32_FLASH)
  {
    source.u8ptr += AVR32_FLASH - dest.u8ptr;
    dest.u8ptr = AVR32_FLASH;
  }
  else if (flash_array_end.u8ptr <= dest.u8ptr && dest.u8ptr < AVR32_FLASHCDW_USER_PAGE)
  {
    source.u8ptr += AVR32_FLASHCDW_USER_PAGE - dest.u8ptr;
    dest.u8ptr = AVR32_FLASHCDW_USER_PAGE;
  }

  // If end of destination is outside flash, move it to the end of the previous flash page if any.
  if (dest_end.u8ptr > AVR32_FLASHCDW_USER_PAGE + AVR32_FLASHCDW_USER_PAGE_SIZE)
  {
    dest_end.u8ptr = AVR32_FLASHCDW_USER_PAGE + AVR32_FLASHCDW_USER_PAGE_SIZE;
  }
  else if (AVR32_FLASHCDW_USER_PAGE >= dest_end.u8ptr && dest_end.u8ptr > flash_array_end.u8ptr)
  {
    dest_end.u8ptr = flash_array_end.u8ptr;
  }

  // Align each end of destination pointer with its natural boundary.
  dest_end.u16ptr = (U16*)Align_down((U32)dest_end.u8ptr, sizeof(U16));
  dest_end.u32ptr = (U32*)Align_down((U32)dest_end.u16ptr, sizeof(U32));
  dest_end.u64ptr = (U64*)Align_down((U32)dest_end.u32ptr, sizeof(U64));

  // While end of destination is not reached...
  while (dest.u8ptr < dest_end.u8ptr)
  {
    // Clear the page buffer in order to prepare data for a flash page write.
    flashcdw_clear_page_buffer();
    error_status |= flashcdw_error_status;

    // Determine where the source data will end in the current flash page.
    flash_page_source_end.u64ptr =
      (U64*)min((U32)dest_end.u64ptr,
                 Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE) + AVR32_FLASHCDW_PAGE_SIZE);

    // Determine if the current destination page has an incomplete end.
    incomplete_flash_page_end = (Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE) >=
                                 Align_down((U32)dest_end.u8ptr, AVR32_FLASHCDW_PAGE_SIZE));

    // If destination does not point to the beginning of the current flash page...
    if (!Test_align((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE))
    {
      // Fill the beginning of the page buffer with the current flash page data.
      // This is required by the hardware, even if page erase is not requested,
      // in order to be able to write successfully to erased parts of flash
      // pages that have already been written to.
      for (tmp.u8ptr = (U8*)Align_down((U32)dest.u8ptr, AVR32_FLASHCDW_PAGE_SIZE);
           tmp.u64ptr < (U64*)Align_down((U32)dest.u8ptr, sizeof(U64));
           tmp.u64ptr++)
      {
        * tmp.u32ptr = *tmp.u32ptr;
        * (tmp.u32ptr + 1) = *(tmp.u32ptr + 1);
      }

      // If destination is not 64-bit aligned...
      if (!Test_align((U32)dest.u8ptr, sizeof(U64)))
      {
        // Fill the beginning of the flash double-word buffer with the current
        // flash page data.
        // This is required by the hardware, even if page erase is not
        // requested, in order to be able to write successfully to erased parts
        // of flash pages that have already been written to.
        for (i = 0; i < Get_align((U32)dest.u8ptr, sizeof(U64)); i++)
          flash_dword.u8[i] = *tmp.u8ptr++;

        // Fill the end of the flash double-word buffer with the source data.
        for (; i < sizeof(U64); i++)
          flash_dword.u8[i] = *source.u8ptr++;

        // Align the destination pointer with its 64-bit boundary.
        dest.u64ptr = (U64*)Align_down((U32)dest.u8ptr, sizeof(U64));

        // If the current destination double-word is not the last one...
        if (dest.u64ptr < dest_end.u64ptr)
        {
          // Write the flash double-word buffer to the page buffer.
            *dest.u32ptr++ = flash_dword.u32[0];
            *dest.u32ptr++ = flash_dword.u32[1];
        }
        // If the current destination double-word is the last one, the flash
        // double-word buffer must be kept for later.
        else flash_dword_pending = TRUE;
      }
    }

    // Read the source data with the maximal possible alignment and write it to
    // the page buffer with 64-bit alignment.
    switch (Get_align((U32)source.u8ptr, sizeof(U32)))
    {
    case 0:
      for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
      {
        *dest.u32ptr++ = *source.u32ptr++;
        *dest.u32ptr++ = *source.u32ptr++;
      }
      break;

    case sizeof(U16) :
      for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
      {
        for (j = 0; j < sizeof(U64) / sizeof(U16); j++) flash_dword.u16[j] = *source.u16ptr++;
* dest.u32ptr++ = flash_dword.u32[0];
* dest.u32ptr++ = flash_dword.u32[1];
      }
      break;

    default:
      for (i = flash_page_source_end.u64ptr - dest.u64ptr; i; i--)
      {
        for (j = 0; j < sizeof(U64); j++) flash_dword.u8[j] = *source.u8ptr++;
 dest.u32ptr++ = flash_dword.u32[0];
 dest.u32ptr++ = flash_dword.u32[1];
      }
    }

    // If the current destination page has an incomplete end...
    if (incomplete_flash_page_end)
    {
      // If the flash double-word buffer is in use, do not initialize it.
      if (flash_dword_pending) i = Get_align((U32)dest_end.u8ptr, sizeof(U64));
      // If the flash double-word buffer is free...
      else
      {
        // Fill the beginning of the flash double-word buffer with the source data.
        for (i = 0; i < Get_align((U32)dest_end.u8ptr, sizeof(U64)); i++)
          flash_dword.u8[i] = *source.u8ptr++;
      }

      // This is required by the hardware, even if page erase is not requested,
      // in order to be able to write successfully to erased parts of flash
      // pages that have already been written to.
      {
        tmp.u8ptr = (volatile U8*)dest_end.u8ptr;

        // If end of destination is not 64-bit aligned...
        if (!Test_align((U32)dest_end.u8ptr, sizeof(U64)))
        {
          // Fill the end of the flash double-word buffer with the current flash page data.
          for (; i < sizeof(U64); i++)
            flash_dword.u8[i] = *tmp.u8ptr++;

          // Write the flash double-word buffer to the page buffer.
* dest.u32ptr++ = flash_dword.u32[0];
* dest.u32ptr++ = flash_dword.u32[1];
        }

        // Fill the end of the page buffer with the current flash page data.
        for (; !Test_align((U32)tmp.u64ptr, AVR32_FLASHCDW_PAGE_SIZE); tmp.u64ptr++)
        {
 tmp.u32ptr = *tmp.u32ptr;
* (tmp.u32ptr + 1) = *(tmp.u32ptr + 1);
        }
      }
    }

    // If the current flash page is in the flash array...
    if (dest.u8ptr <= AVR32_FLASHCDW_USER_PAGE)
    {
      // Erase the current page if requested and write it from the page buffer.
      if (erase)
      {
        flashcdw_erase_page(-1, FALSE);
        error_status |= flashcdw_error_status;
      }
      flashcdw_write_page(-1);
      error_status |= flashcdw_error_status;

      // If the end of the flash array is reached, go to the User page.
      if (dest.u8ptr >= flash_array_end.u8ptr)
      {
        source.u8ptr += AVR32_FLASHCDW_USER_PAGE - dest.u8ptr;
        dest.u8ptr = AVR32_FLASHCDW_USER_PAGE;
      }
    }
    // If the current flash page is the User page...
    else
    {
      // Erase the User page if requested and write it from the page buffer.
      if (erase)
      {
        flashcdw_erase_user_page(FALSE);
        error_status |= flashcdw_error_status;
      }
      flashcdw_write_user_page();
      error_status |= flashcdw_error_status;
    }
  }

  // Update the FLASHC error status.
  flashcdw_error_status = error_status;

  // Return the initial destination pointer as the standard memcpy function does.
  return dst;
}
Ahmed Anter
  • 650
  • 4
  • 13
  • `flashc_memcpy` is buggy and will not write/erase what you think ... the only way around this I found is to write full page. Even that cant be done at once... otherwise `flashc_memcpy` corrupt the content related to Bootloader. After more trial I start to suspect it does not matter what is in the other addresses of page and the problem is solely in `flashc_memcpy` function leaving some weird state set that is reseted only by Bootloader + BatchISP (even Power down does not help). There is no mention about this in datasheet errata known chip bugs but the chip is still relatively new ... – Spektre May 26 '20 at 12:13
  • 1
    I worked with this version on uc3b0256 and developed custom boolloader which writes to both system flash and user flash and it works fine with me. the problem when I use wdt_reset cuses the cpu to enter reset and never exit because it uses 0delay time and the dfu bootloader doesn't disable the wdt. – Ahmed Anter May 26 '20 at 12:18
  • Ok you're right WDT was the reason for repeated reset after few ms (+1). However after remedy that (repairing 1st word of `.userpage` back to 0xFFFFFFFF) the firmware always boots into Bootloader even if the Bootloader config is correct). Reflashing firmware remedies this (without changing `.userpage`) and on any erase+write to flash the problem resurface again. I try to check if its the flashc_memcpy or erase – Spektre May 27 '20 at 09:24
  • I isolated the problem see edits in my question... Any ideas? – Spektre May 27 '20 at 10:02
  • How much data you want to store in user flash page? – Ahmed Anter May 27 '20 at 14:55
  • right now 2x32bit but it would be enough even 32bit ... or even 8bit (its just state of single IRC for RPM tuning and number of writes for debug which I can dismiss) the problem is I need to erase the page and that erases all ... and the Bootloader config is at the address which access corrupts the Reseting ... was thinking about using flash for program for this instead however I do not know if I can erase just single page ... never used flashing in code before this – Spektre May 27 '20 at 18:03
  • another option would be mask the Bootloader config areas as protected but not sure if that protecs from erase or not, nor how to do it yet... – Spektre May 27 '20 at 18:05
  • if you look at the code snippet from ASF to flashc_memcpy you will see that it loads data from flash page into buffer first then put your data after then it erase the page and write buffer back to the flash. so all you need is to provide the actual length for your data not the whole page size – Ahmed Anter May 28 '20 at 09:51
  • UC3L does not have FLASHC it has FLASHCDW instead and I did follow the example for it in ASF to the letter ... This might be related to fact that the 128,256 versions are new and they have still bugs either in ASF or even on chip itself. The UC3L0 series is the buggiest MCU I ever work with (even the old 32,64) but I need to use it as it has other advantages others have not... I usually use UC3A and those are superb – Spektre May 28 '20 at 09:57
  • check this edit. I looked inside flashcdw it do the same it fills the buffer with original flash data the load your data and write it back after erasing the page. – Ahmed Anter May 28 '20 at 10:25
  • asf version 1.6.0 – Ahmed Anter May 28 '20 at 10:34
  • I have updated my question with workaround I will use. However `.userpage` usage boot corruption is still open Question... PS `1.6.0` is too old (have many bugs and does not support newer chips) I use `3.1.0` as base ASF and have updated some drivers and some of them have recoded completely as they where coded poorly ... The most problems I had with USB there where huge bugs causing weird stuff so I ended up writing my own... – Spektre Jun 01 '20 at 09:25
  • I created new answer with the current Atmel/Microchip resolution for the issue (I created back then) – Spektre May 13 '21 at 07:40
0

OK here is official resolution from Atmel/Microchip:

Proposed Resolution:
Looks like the DFU word being restored doesn't have the boot flag + CRC change. For the customer's application where userpage data is not constant, it's preferable to flash instead for non-volatile storage.

So my understanding its a HW bug (on the newer chips like AT32UC3L0256) and can not be work-around-ed ... other than using different non volatile memory like Flash for program (just like I ended up doing in the first place).

[edit1] Atmel/Microchip just confirmed its definately HW bug

Spektre
  • 49,595
  • 11
  • 110
  • 380