Перейти к содержанию
    

LPC4337, свой загрузчик. Не получается запустить приложение.

Загрузка в стек должна производиться инструкцией MSR

LDR R1, [R0]
MSR MSP, R0

, а загрузка в PC - банальным переходом

LDR R1, [R0, 4]
BX  R1

, но можно и LDR-ами грузить. Каково значение бита 0 (nPRIV) в регистре CONTROL у CPU? В непривилегированном режиме грузить LDR-ами в SP и PC запрещено.

Судя по названиям файлов проекта, в нем крутится какая-то RTOS, а значит она, скорее всего, "сделала все правильно" и установила непривилегированный режим.

Насколько я помню (лень открывать мануал), из режима потока его снять обратно не получится, только через обработчик прерывания. Сделайте это, например, через синхронный SVC.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

50 минут назад, arm-user сказал:

При попытке это выполнить происходит Hard Fault.

Тут я уже ничего не понимаю.

Вам обработчик HF рассказывает о том, что у вас произошло:

Undefined instruction UsageFault:
0 = no undefined instruction UsageFault
1 = the processor has attempted to execute an undefined instruction.
When this bit is set to 1, the PC value stacked for the exception return points to the undefined instruction.
An undefined instruction is an instruction that the processor cannot decode.

Т.е. - попытка выполнения неправильной команды CPU. Сделайте расшифровку причины HF.

А потом, по адресу PC, посмотрите на эту команду.

25 минут назад, Arlleex сказал:

Загрузка в стек должна производиться инструкцией MSR

Почему обязательно MSR? Чем банальная MOV SP, Rx плоха?

StartWorkFw:   LDR      R0, =PFLASH_BEGIN_C + FW_WORK_BEGIN
               LDMIA    R0!, {R1, R2}
               MOV      SP, R1
               BX       R2

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 минуты назад, jcxz сказал:

Почему обязательно MSR? Чем банальная MOV SP, Rx плоха?

Ничем. Не обязательно MSR. Это я поспешил.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

32 минуты назад, Arlleex сказал:

Судя по названиям файлов проекта, в нем крутится какая-то RTOS, а значит она, скорее всего, "сделала все правильно" и установила непривилегированный режим.

Если это так, то передавать управление в другое приложение таким образом - чревато. Ибо оно не знает, что конфигурация процессора не соответствует послесбросовой (режим CPU, его управляющие регистры и активный SP). И поэтому уже оно может работать неверно. Если использовалась ОС, то перед передачей управления в другое приложение, нужно сперва привести CPU в исходное состояние. И периферию - тоже.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как я понял, у ТС RTOS уже во весь ход запущена к моменту вызова функции перехода на приложение. Так что да, чревато.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, arm-user said:

Может быть, что изменение стека запрещено по умолчанию

Читайте про эту команду)

Upd. Немного поспешил. Оказывается в теме уже были ответы)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 минуты назад, haker_fox сказал:

Читайте про эту команду)

Да не, выше jcxz дал, по идее, универсальный вариант, который не зависит от состояния CPU. Должно работать.

Но, как уже было замечено, все инициализированное/измененное железо должно быть приведено в исходное состояние.

Я бы банально сбросился через NVIC (разумеется, первыми командами проверив, что сброс вызван точкой перехода на приложение).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 hours ago, Arlleex said:

Как я понял, у ТС RTOS уже во весь ход запущена к моменту вызова функции перехода на приложение. Так что да, чревато.

Спасибо за отклики, попробую ответить.

 

- scmRTOS была в этом коде. Для загрузчика отскреб ее насколько мог. Для выдачи в UART используются очереди сообщений от RTOS. Чтобы не тратить время на переделку их оставил и оставлены инклюды от scmRTOS. Но процессы и запуск самой RTOS отсутствуют. Все сейчас крутится в поллинге. А также есть прерывания от Ethernet и таймера. Но в момент перехода мы находимся в основном цикле и прерывания отключаются перед переходом. Есть ли тут какие-то еще подводные камни, которые я не знаю?

- В ассемблерных процедурах перехода ничего не понимаю. Взял код, найденный на этом форуме в соседней ветке. Код на С также не заработал. Попробую предложенный выше.

- Переход на приложение и планировлся через NVIC_Reset, но я не знаю, получится ли его отлаживать в таком режиме. Подхватит ли отладчик точки останова после ресета. Я почему-то решил, что нет, и убрал пока Ресет для теста.

- Стек удалось изменить встроенной функцией __set_MSP(user_stack);

Переход, похоже, тоже работает и сейчас проблема в том, что код приложения лежит где задумано, но сам "не знает" что он начинается с 0x1a008000. Буду с этим разбираться.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Поправил код приложения, адреса встали на место, но проблема осталась.

Попробовал код перехода, предложеннный выше (на скриншоте 1). Все равно на переходе уходит на ошибку.

Чтобы понять на каком шаге происходит ошибка, разбил asm вставку на 2 - по одной строке в каждой. И в таком виде оно заработало.

Есть ли объяснение почему?

 

image.thumb.png.ca8f741bfc75cd59259ba370edf12ddb.png

 

И второй вопрос - адрес перехода (R1) вычитывается 0x1A00C095 (в бинарнике, соответственно, также).

Но дизассемблер говорит, что адрес Reset_Handler на единицу меньше 0x1A00C094.

Почему так происходит и не надо ли подправить что-нибудь в процедуре перехода на эту тему?

Подскажите, пожалуйста.

 

image.thumb.png.82fb4aceb7111931f260bbb7c25a74d0.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 минут назад, arm-user сказал:

Чтобы понять на каком шаге происходит ошибка, разбил asm вставку на 2 - по одной строке в каждой. И в таком виде оно заработало.

Есть ли объяснение почему?

Потому что в "асм-вставке" написан полный бред.

С чего вдруг чтение от R0 делаете? У вас же адрес объявлен как "r"(address).

Естественно, что читать нужно не с R0, а с соответствующего аргумента.

И вообще к регистрам напрямую лучше не обращаться.

  u32 i;
  asm(                                            
    " LDR %0, [%1, #4] \n"        
    " BX  %0"
    : "=&r"(i)
    : "r"(address)
    : "memory");                            
  i = i;

как-то так. Кроме того - ещё про SP забыли.

 

PS: И в отладчике смотреть нужно не на исходный код, а в окно дизассемблера.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

arm-user, Вы лучше в асм-листинг функций перехода смотрите, а то этот inline asm - та еще могучая кучка со своим мусор..ом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, jcxz said:

Потому что в "асм-вставке" написан полный бред.

С чего вдруг чтение от R0 делаете? У вас же адрес объявлен как "r"(address).

Естественно, что читать нужно не с R0, а с соответствующего аргумента.

И вообще к регистрам напрямую лучше не обращаться.

  u32 i;
  asm(                                            
    " LDR %0, [%1, #4] \n"        
    " BX  %0"
    : "=&r"(i)
    : "r"(address)
    : "memory");                            
  i = i;

как-то так. Кроме того - ещё про SP забыли.

 

PS: И в отладчике смотреть нужно не на исходный код, а в окно дизассемблера.

Окно дизассемблера не показывало текущую информацию. Разобрался, нашел галку прилинковать текущий debug контекст.

SP не забыл, говорил, что для него заработала штатная функция __set_MSP(user_stack);

С новым вариантом ассемблерной вставки стало существенно хуже, адрес перехода лежит в регистре R0, а операции производятся с другими регистрами

image.thumb.png.51926c76ab82f8e38efe5fecd841b02d.png

 

38 minutes ago, Arlleex said:

Интереса ради: зачем нужен i = i в конце?

наверное, это компилятору, чтобы не решил "оптимизировать" пустую функцию?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Arlleex сказал:

Интереса ради: зачем нужен i = i в конце?

Иначе IAR ругается на "неиспользуемую переменную".

53 минуты назад, arm-user сказал:

С новым вариантом ассемблерной вставки стало существенно хуже, адрес перехода лежит в регистре R0, а операции производятся с другими регистрами

А если ещё раз подумать? И почитать какой-нить учебник по системе команд используемого CPU. И затем - ещё раз внимательно посмотреть на результат компиляции?

Всё там ok.

PS: Чтобы было в R0 (более-менее вероятно), достаточно включить оптимизацию.

53 минуты назад, arm-user сказал:

наверное, это компилятору, чтобы не решил "оптимизировать" пустую функцию?

Ответ неверный. Как же он её оптимизирует, если у вас оптимизация выключена?  :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

И второй вопрос - адрес перехода (R1) вычитывается 0x1A00C095 (в бинарнике, соответственно, также).
Но дизассемблер говорит, что адрес Reset_Handler на единицу меньше 0x1A00C094.
Почему так происходит и не надо ли подправить что-нибудь в процедуре перехода на эту тему?

Ядро использует набор команд Thumb-2 (впрочем, других и не умеет), а признак его (набора) - "1" в младшем разряде того, что находится или будет находиться в счётчике команд (PC).
Править ничего не надо: адрес в памяти 0x1A00C094, в должно PC загрузиться 0x1A00C094|0x00000001.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...