Помогите победить проблему.
Пробую сделать загрузчик по юарту. Позже планируется usb, но пока с этим ничего не получается.
За основу взят usb bootloader от NXP AN10866 http://www.nxp.com/documents/other/LPC1700..._bootloader.zip
В аттаче архив с 2 проектами для LPCXpresso. UART_bootloader - собственно бутлодырь, точнее только его скелет с самым самым минимумом. test - светодиодная моргалка, которую надо загружать для теста.
Проблема такова:
Загрузчик работает верно, бинарный файл с прошивкой тестового проекта сохраняет как нужно (файл не выравнен по 512байт, то чего не хватает для записи последнего блока дописываю ручками, временно так). Проверки при записи проходят т.е. неверно залитый файл исключается.
При старте он проверяет контрольную сумму прошивки в секторе 4 (туда по умолчанию загружаем). Сумма есть в бинарнике.
Сумма сошлась, надо переходить к исполнению программы с 4 сектора.
Указываем новое местоположение таблицы векторов прерываний, смещаем программный счётчик и верхушку стека (всё как в NXP-шном примере, только там для Keil, а у меня gcc с другим синтаксисом ассемблера):
Код
void boot(uint32_t a)
{
asm(
"LDR SP, [R0]\n"
"LDR PC, [R0, #4]\n"
);
}
void execute_user_code(void)
{
uint32_t addr=(uint32_t)sector_start_adress[USERCODE_SECTOR_START];
SCB->VTOR = (addr & 0x1FFFFF80);
boot(addr);
}
{
asm(
"LDR SP, [R0]\n"
"LDR PC, [R0, #4]\n"
);
}
void execute_user_code(void)
{
uint32_t addr=(uint32_t)sector_start_adress[USERCODE_SECTOR_START];
SCB->VTOR = (addr & 0x1FFFFF80);
boot(addr);
}
Успешно попадаем в ResetISR загруженной программы (смотрю пошагово в отладчике и сверяю адреса инструкций с адресами в .map файле)
Дальше самое интересное:
Тестовая программа:
Код
volatile uint32_t del;
void _delay(uint32_t delay)
{
uint32_t i;
for(i = 0; i < delay; i++ )
del = i; // do this so that the compiler does not optimize away the loop.
}
int main(void)
{
// SystemInit();
// init_uart(57600);
LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO
LPC_GPIO0->FIODIR |= 1 << 1;
LPC_GPIO0->FIOPIN = 1<<1;
// uart_sendstring("YES\n");
uint32_t i;
const uint32_t delay=1<<22;
while(1)
{
// _delay(1<<22);
for(i = 0; i < delay; i++ )
del = i;
LPC_GPIO0->FIOPIN ^= 1 << 1;
}
return 0;
}
void _delay(uint32_t delay)
{
uint32_t i;
for(i = 0; i < delay; i++ )
del = i; // do this so that the compiler does not optimize away the loop.
}
int main(void)
{
// SystemInit();
// init_uart(57600);
LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO
LPC_GPIO0->FIODIR |= 1 << 1;
LPC_GPIO0->FIOPIN = 1<<1;
// uart_sendstring("YES\n");
uint32_t i;
const uint32_t delay=1<<22;
while(1)
{
// _delay(1<<22);
for(i = 0; i < delay; i++ )
del = i;
LPC_GPIO0->FIOPIN ^= 1 << 1;
}
return 0;
}
В таком виде работает, светодиод на P1.1 моргает. Но стоит раскомментировать задержку в вечном цикле и закомментировать "инлайновую" задержку (так она в теле цикла, а станет функцией) - всё, получаем HardFault Precise Error (скачок на адрес 0x40F6 где лежит обработчик HardFault-ов). Тоже самое и с юартом и системинитом. Можно предположить косяк со стеком при вызове функции, но фактически стек работает верно. Например, если убрать системинит, но оставить юарт, то хардфолтов не будет, он исправно пробежит uart_sendstring("YES\n"); но ничего не отправит. Та же программа зашитая в 0 сектор как обычно (с соответсвующей правкой скрипта линкера) работает абсолютно верно.
Оно мне уже мозг вынесло. Подскажите плз, что я делаю не так?