|
LPC1768 uart bootloader, не получается |
|
|
|
Dec 8 2011, 21:00
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Всем привет! Помогите победить проблему. Пробую сделать загрузчик по юарту. Позже планируется 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); } Успешно попадаем в 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; } В таком виде работает, светодиод на P1.1 моргает. Но стоит раскомментировать задержку в вечном цикле и закомментировать "инлайновую" задержку (так она в теле цикла, а станет функцией) - всё, получаем HardFault Precise Error (скачок на адрес 0x40F6 где лежит обработчик HardFault-ов). Тоже самое и с юартом и системинитом. Можно предположить косяк со стеком при вызове функции, но фактически стек работает верно. Например, если убрать системинит, но оставить юарт, то хардфолтов не будет, он исправно пробежит uart_sendstring("YES\n"); но ничего не отправит. Та же программа зашитая в 0 сектор как обычно (с соответсвующей правкой скрипта линкера) работает абсолютно верно. Оно мне уже мозг вынесло. Подскажите плз, что я делаю не так?
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Dec 9 2011, 07:30
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Точно-точно. По крайней мере скрипты линкера верные, в map-файле адреса тоже верные. Вчера уже в полу-сонном состоянии решил добавить задержку (for на 10000) перед переходом на адрес программы из загрузчика и оно заработало! юарт начал печатать, функции вызываться, диод моргать.Но радость была не долгой  Попробовал залить реальную программу где уже 70кб набыдлокодено и в ней получаю похожие симптомы: то Imprecise Error прямо в ResetISR, то после срабатывания 2-го прерывания от таймера, то ещё что-то, глючит по-полной в общем. Опять же адрес начала верный MFlash512 (rx) : ORIGIN = 0x4000, LENGTH = 0x7C000 в map файле адреса верные. Эти симптомы с этой программой похожи на те, с которыми я столкнулся пытаясь разместить загрузчик в коде основной программы, но по специальному адресу. Там тоже сначала ни в какую не получалось, потом помогли на форуме lpcxpresso чтобы заработал тестовый проект, а когда те же скрипты линкера перенёс в реальный проект то получил такие глюки. Вот эта тема http://knowledgebase.nxp.com/showthread.php?t=2670 . Но если проблема в моём быдлокоде, то почему он стабильно работает из 0 сектора?! Продолжаю мучиться...
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Dec 9 2011, 13:04
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Поступило предложение использовать барьеры памяти и сбросить конвейер перед "прыжком в другую реальность". Почитал что это и как, не особо хорошо понял этот механизм, но всё же добавил: Код __asm ( "dmb\n" "dsb\n" "isb\n" ); Прямо перед вызовом функции, изменяющей PC в загрузчике. А так же в моей программе в ResetISR прямо в самом начале. Вот что происходит в этом случае: Загрузчик всё так же успешно отрабатывает, обновляет SP и PC, прыгаем в ResetISR моей программы и на этапе инициализации data/bss происходит сразу 3 пакости: Access Violation, Stack Error, Precise Error. Но что интересно они происходят не без причины. SP внезапно изменяется на 3FE т.е. какой-то код в загрузчике, поскольку в моей программе эта область не отмечена вообще никак - происходит Access Violation. Но кто мог так надругаться над стеком?? Затрейсить выполнение нечем, но в отладчике отображаются красным цветом с градиентом последние 4 команды и это всё тот же цикл в инициализации секторов data/bss, т.е. дальше этого места она никак не могла выпрыгнуть. Есть вариант что кончается память и "куча" дорастает до стека, но этого не может быть т.к. у меня нет столько глобальных переменных, есть парочка статических буферов, один на 4k, другой на 256 и ещё по мелочи, но это никак не переползёт до 32k если только не произойдёт какой-то бяки и цикл инициализации не "взбесится". Но какого лешего тогда оно работает из 0 сектора? Вот что интересно, если не добавлять барьеры и сброс конвейера в начале ResetISR, то поведение будет другое. SP уже так не изменяется, остаётся на 10007ED8 (начальная верхушка 10008000) во время хардфолта, и ошибка - Bus Error. Тут не удаётся увидеть что было перед этим (видимо отладчик глючит), но судя по такому отрастанию стека там уже какие-то функции успели вызваться. Если же убрать барьеры и из загрузчика, то будет примерно также, но ошибка Imprecise Error и тот же хардфолт. Кошмар
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Dec 9 2011, 20:26
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Всё намного проще Ну почему люди такие идиоты? Это я про себя. Банальнейшая ошибка в загрузчике из-за которой блоки записывались неверно но проверялись верно, настолько банальная, что признаться стыдно. Вот так ищем ошибку там где её нет, и не замечаем на самом видном месте. А заметил вот как: в LPCXpresso можно прошивать бинарник со смещением на любой адрес. Ради интереса пошил так свою программу, загрузчик там тоже был и вот оно побежало как положено. Спасибо всем за отклики! Что примечательно до этого 3 суток загара перед монитором и никакого толку, а тут отвлёкся с друзьями в баре по пиву, вернулся домой и почти сразу "попёрло"  Зато поближе с архитектурой проца познакомился. Остались несколько белых пятен насчёт задержек перед прыжком, переключения тактовых частот и барьеров, но это уже по ходу дела разберусь.
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Dec 10 2011, 10:45
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Cosmojam @ Dec 10 2011, 00:05)  На это нужно перепрыгнуть обратно в загрузчик, но при этом знать что сейчас будет обновление прошивки и не нужно проверять суммы и стартовать программу. То есть нужен ровно 1 бит информации. Делаете программный ресет и в загрузчике проверяете его флаг. Убиваете сразу двух кроликов: 1) попадаете в загрузчик без лишних теодвижений 2) Сбрасываете всю периферию, в том числе и настроенный приложением WDT, в известное и четко определенное состояние. QUOTE (Cosmojam @ Dec 10 2011, 00:05)  Обычно это делают с помощью кнопки или небольшой задержки при старте загрузчика чтобы попытки соединения уже шли во время его старта. Чушь. Так делают студенты. Кнопка - еще куда ни шло как средство аварийного запуска загрузчика, помогает на этапе разработки после заливки мертвой прошивки. А в общем случае устройство должно перешиваться без участия человека, по команде через штатный интерфейс.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 10 2011, 17:54
|
Местный
  
Группа: Свой
Сообщений: 311
Регистрация: 12-01-11
Из: Калининград (Koenigsberg)
Пользователь №: 62 182

|
Цитата(toweroff @ Dec 10 2011, 11:25)  Жестко прописанная переменная в Non-ZI сегменте Так ведь глобальные переменные инициируются в 0, т.е. нужно править стартап чтобы эту переменную не потёрли в ResetISR. Цитата(Dron_Gus @ Dec 10 2011, 12:45)  SVC? Можно сдвинуть таблицу векторов обратно на бутлоадер и вызвать. А можно просто взять адрес из таблицы векторов бутлоадера и вызвать напрямую. Да, только бутлодырь должен уметь отличать вызвали его программно, или по POR. Цитата(Сергей Борщ @ Dec 10 2011, 13:45)  То есть нужен ровно 1 бит информации. Делаете программный ресет и в загрузчике проверяете его флаг. Убиваете сразу двух кроликов: 1) попадаете в загрузчик без лишних теодвижений 2) Сбрасываете всю периферию, в том числе и настроенный приложением WDT, в известное и четко определенное состояние. Чушь. Так делают студенты. Кнопка - еще куда ни шло как средство аварийного запуска загрузчика, помогает на этапе разработки после заливки мертвой прошивки. А в общем случае устройство должно перешиваться без участия человека, по команде через штатный интерфейс. Вы имеете в виду програмный ресет от вочдога и проверку флага WDTR в регистре RSID ?
--------------------
typedef enum { no, yes, maybe } bool; | блог тут
|
|
|
|
|
Dec 11 2011, 00:47
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
QUOTE (Cosmojam @ Dec 10 2011, 19:54)  Вы имеете в виду програмный ресет от вочдога и проверку флага WDTR в регистре RSID ? Нет, я имел ввиду сброс через SYSRESETREQ. К сожалению, QUOTE Note: support for SYSRESETREQ is not included in LPC17xx devices. Значит, такой вариант отпадает.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|