用户页面NVRAM使用后,奇怪的UC3重置行为

问题描述 投票:0回答:1

我最近需要在AT32UC3L0256]的构建NVRAM / EEPROM中使用>存储一些配置数据。我终于设法使用了MCU的用户页面NVRAM(经过数天的反复试验,对GCC进行诅咒,忽略了noinit指令,并像往常一样修复和解决ASF中的错误):

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 !!!)
    }

我必须从flashcdw.c,flashcdw.h更新ASF 3.48.0.98,以便能够写入完整的512字节,因为旧的ASF最多只能编写256个字节,但是会擦除整个页面,使情况变得一团糟。我还必须存储整个页面(由于擦除而不是仅存储8个字节),并且照例,由于ASF错误,我需要按原样进行操作,而不是只调用一次flashcdw_memcpy ...

现在可以正常工作,但我发现某些地址引起了奇怪的行为。当0xFF不在某个地址上时,该设备将不再能正常复位(但直到复位运行OK为止)。在非Bootloader RESET上,它将启动固件代码,但是在几次[ms]之后,它将再次重置,并且此过程将永远持续下去。为了清楚起见,RESET在此部分代码中发生(对我而言):

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

配置系统后,其简单的LED闪烁(PLL CPU时钟,已配置的定时器和ISR,但仍然禁用了中断)。 LED闪烁几次(PLL以正确的速度工作),但要在回路完成之前复位。等待很简单:

//------------------------------------------------------------------------------------------------
#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;
            }
        }
    }
//------------------------------------------------------------------------------------------------

甚至更奇怪的是,如果我启动到引导加载程序,然后再次正常复位,则设备将正确复位并且固件可以再次工作(不进行任何擦除/编程),但是如果我再次正常复位,则复位循环会再次发生...

如果我使用BatchISP(翻转)将.userpage NVRAM重新编程回原始状态,则芯片将再次正常工作。

最后是问题:

  1. NVRAM用户页面中的哪些地址正在引起这种情况,或者应该保留/避免更改?

    我知道最后8个字节是Bootloader配置。我怀疑有问题的地址是前16个字节。 .userpage应该用于用户数据,并且不包含保险丝。

  2. 发生了什么?

  3. 它是某种看门狗还是什么?我以为那些是存放在别处的保险丝。我在数据表中看不到任何内容。

    原始.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
    

我使用这些(翻转命令)获取并还原它:

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

所涉及的引导程序是USART版本:1.0.2具有此行为的固件使用PLL,TC,GPIO,PWMA,ADC

模块,但是在使用任何ISR和/或ADC,PWMA,TC之前都会发生复位。

[[Edit1]看门狗

根据this,NVRAM的.userpage中的第一个字是看门狗的保险丝,它解释了在将数据恢复为原始值并禁用ms后停止几次复位WDT后的复位。但是,现在不是启动程序,而是启动了Bootloader,因此仍然有些麻烦。 Bootloader引脚选择位于最后8个字节中

[我也查看了USART Bootloader版本1.0.2的源,发现他们使用的是FLASHC而不是FLASHCDW,并强制使用看门狗启动(这可能会重置其状态并使我的程序以某种方式再次运行)。] >

[Edit2]错误已隔离

我终于发现问题是由于写入512字节.userpage的最后32位字引起的:

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

这是一个很大的问题,为了正确存储数据,无论如何我都必须使用擦除来擦除整个页面,并且为了仍然能够正确引导到Bootloader或我的固件,我必须恢复Bootloader配置数据:] >

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

我需要找到一种解决方法,如何将芯片恢复到正常状态。也许重复了从Bootloader重置看门狗的过程(但这在我的应用程序中将是非常有问题的,甚至是有风险的),因为即使没有任何闪烁,它也可以恢复芯片...

所以现在地图:

: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

我最近需要在AT32UC3L0256的构建NVRAM / EEPROM中使用以存储一些配置数据。我终于设法使用了MCU的用户页面NVRAM(经过数天的反复试验和在GCC上的诅咒...

在主要功能中早期禁用wdt

wdt_disable();

而且我认为您不必每次都写整页。flashc_memcpy需要字节长度来写,同时保留其他数据不变。

volatile void *flashc_memcpy(volatile void *dst, const void *src, size_t nbytes, bool erase)
{
    uint16_t page_pos;
    Union64 flash_dword;
    uint8_t i;
    bool b_user_page;
    unsigned int error_status = 0;
    uint8_t* flash_add;
    uint8_t* dest_add=(uint8_t*)dst;
    const uint8_t* src_buf=(const uint8_t*)src;

    // Copy area must be in flash array or flash user page
    Assert( (((uint8_t *)dst >= AVR32_FLASH)
            && (((uint8_t *)dst + nbytes) <= (AVR32_FLASH + flashc_get_flash_size())))
            || (((uint8_t *)dst >= AVR32_FLASHC_USER_PAGE)
            && (((uint8_t *)dst + nbytes) <= (AVR32_FLASHC_USER_PAGE + AVR32_FLASHC_USER_PAGE_SIZE))) );

    b_user_page = (volatile uint8_t *)dst >= AVR32_FLASHC_USER_PAGE;

    flash_add = (uint8_t*)((uint32_t)dest_add - ((uint32_t)dest_add % AVR32_FLASHC_PAGE_SIZE));

    while (nbytes) {
        // Clear the page buffer in order to prepare data for a flash page write.
        flashc_clear_page_buffer();
        error_status |= flashc_error_status;

        // Loop in the page
        for (page_pos=0; page_pos<AVR32_FLASHC_PAGE_SIZE; page_pos+=sizeof(uint64_t) ) {
            // Read the flash double-word buffer
            flash_dword.u64 = *(volatile uint64_t*)flash_add;

            // Update double-word if necessary
            for (i = 0; i < sizeof(uint64_t); i++) {
                if (nbytes && (flash_add == dest_add)) {
                    // Update page with data source
                    flash_dword.u8[i] = *src_buf++;
                    dest_add++;
                    nbytes--;
                }
                flash_add++;
            }

            // Write the flash double-word buffer to the page buffer.
            *(volatile uint64_t*)((uint32_t)flash_add - sizeof(uint64_t))= flash_dword.u64;
        }

        // Erase the current page if requested and write it from the page buffer.
        if (erase) {
            (b_user_page)? flashc_erase_user_page(false) : flashc_erase_page(-1, false);
            error_status |= flashc_error_status;
        }

        // Write the page
        (b_user_page)? flashc_write_user_page() : flashc_write_page(-1);
        error_status |= flashc_error_status;
    }
    // Update the FLASHC error status.
    flashc_error_status = error_status;

    // Return the initial destination pointer as the standard memcpy function does.
    return dst;
}
c++ reset bootloader avr32 atmel-uc3
1个回答
1
投票

在主要功能中早期禁用wdt

wdt_disable();
© www.soinside.com 2019 - 2024. All rights reserved.