Недавно мне нужно было использовать в сборке NVRAM / EEPROM AT32UC3L0256 для хранения некоторых данных конфигурации. Наконец, мне удалось использовать NVRAM пользовательской страницы MCU (после нескольких дней проб и ошибок и проклятия G CC игнорирования директив 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
не находится на каком-либо адресе, устройство больше не будет сбрасываться в обычном режиме (но все равно, пока сброс не будет выполнен нормально). При СБРОСЕ без загрузчика он запускает код прошивки, но через несколько [ms]
он снова сбрасывается, и это продолжается вечно. Для ясности, СБРОС происходит в этой части кода (в моем случае):
for (U8 i=0;i<4;i++)
{
gpio_tgl_gpio_pin(_LED);
wait_ms(200);
}
его простое мигание светодиода после настройки системы (частота процессора PLL, настроенные таймеры и ISR, но прерывания все еще отключены) . Светодиод мигнет как следует несколько раз (ФАПЧ работает с правильной скоростью), но до завершения l oop происходит сброс. Ожидание простое:
//------------------------------------------------------------------------------------------------
#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;
}
}
}
//------------------------------------------------------------------------------------------------
Еще более странно то, что если я загружаюсь в загрузчик, а затем снова перезагружаюсь, устройство сбрасывается правильно, и прошивка снова работает (без стирания / программирования), однако, если я снова перезагружаюсь в обычном режиме, сброс l oop происходит снова ...
Если я перепрограммирую .userpage
NVRAM обратно в исходное состояние с помощью BatchISP (перевернуть), чип снова будет работать нормально.
Итак, наконец вопросы:
Какие адреса на странице пользователя NVRAM вызывают это или их следует зарезервировать / избегать изменения?
Я знаю последние 8 байтов - это конфигурация загрузчика. Я подозреваю, что адреса c - это первые 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, T C, GPIO, PWMA, AD C, однако сброс происходит перед использованием ISR и / или AD C, PWMA, T C.
[Edit1] Watchdog
согласно this первое слово в .userpage
NVRAM - это предохранитель для сторожевого таймера, который объясняет сброс после нескольких ms
однократных восстановлений данных до исходных значений и отключения WDT
сброса останавливается. Однако теперь вместо загрузки программы запускается загрузчик, так что все еще есть что-то подозрительное. Выбор пина загрузчика находится в последних 8 байтах
Также я просмотрел источник USART Bootloader ver: 1.0.2 и обнаружил, что они используют FLASHC
вместо FLASHCDW
и принудительную загрузку с помощью сторожевого таймера (который может сбросить его состояние и разрешить моей программе запускаться снова).
Ошибка [Edit2] изолирована
Я наконец обнаружил, что проблема вызвана записью в последнее 32-битное слово из 512 байт .userpage
:
U32 btldr[2]={0x929E0B79,0xE11EFFD7};
flashcdw_memcpy(&nvram_adr[127],(U32*)&btldr[1] ,4,false);
, что является огромной проблемой, поскольку для правильного хранения данных я должен использовать стирание, которое стирает всю страницу независимо от того, что и для того, чтобы все еще иметь возможность правильно загружаться to Bootloader или My firmware. Мне нужно восстановить данные конфигурации загрузчика:
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);
Мне нужно найти обходной путь, как восстановить чип в рабочее состояние. Возможно, продублируйте сброс сторожевого таймера из загрузчика (но это было бы очень проблематично c и даже рискованно в моем приложении), поскольку он восстанавливает чип даже без перепрошивки ...
так что сопоставьте сейчас:
: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] обходной путь
Мне удалось успешно записать / прочитать программную память FLA SH (проверено с помощью BatchISP и MCU), она также загружается нормально.
Вот код, который я тестирую с помощью:
// **** 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);
}
, где flash_adr
- это найденный адрес, содержимое которого соответствует подписи buf[]
... (я распечатываю его на ЖК-дисплее, чтобы проверить, соответствует тому, что я ожидал), и, наконец, это так :). Поэтому я буду использовать это вместо .userpage
.
Однако исправление проблемы с загрузкой .userpage
все еще остается открытым вопросом