在主要功能中早期禁用wdt
wdt_disable();
我最近需要在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重新编程回原始状态,则芯片将再次正常工作。
最后是问题:
NVRAM用户页面中的哪些地址正在引起这种情况,或者应该保留/避免更改?
我知道最后8个字节是Bootloader配置。我怀疑有问题的地址是前16个字节。 .userpage
应该用于用户数据,并且不包含保险丝。
发生了什么?
它是某种看门狗还是什么?我以为那些是存放在别处的保险丝。我在数据表中看不到任何内容。
原始.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; }
在主要功能中早期禁用wdt
wdt_disable();