|
Чтение внутренних регистров STM32 |
|
|
|
May 17 2016, 02:00
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Alechek @ May 16 2016, 22:09)  Единственное, для чего мне это понадобилось, это скинуть дамп регистров при возникновении Fault. Пришлось написать вставку на ASM для копирования регистров в память (структуру). Остальная работа на C. И где гарантия, что компилятор при очередной перекомпиляции, не разместит какие-то переменные в регистрах которые Вы хотели сохранить до вашей вставки? Такое надо делать целиком в asm-функциях. Напишите ISR fault-ов полностью на asm, там всё элементарно. Цитата(adnega @ May 17 2016, 01:59)  Реально, по значениям LR, PC, R0-R4 в подавляющем большинстве случаев можно найти причину фэйла. Не знаю не знаю... У меня сохраняются все регистры + дамп стека. И то часто не хватает. Цитата(aaarrr @ May 17 2016, 02:27)  У меня алгоритм такой: Исключение -> запись контекста исключения в RAM -> перезапуск -> сохранение контекста на внешнем носителе или передача на отладочный сервер -> возобновление работы У меня все fault-ы примерно так же обрабатываются, только кроме дампа регистров сохраняю ещё и дамп текущего стека. Отличия: Для release-сборки: всё так же, кроме передачи на отладочный сервер. Для debug-сборки: вместо перезапуска - переинициализация железа в минимальный дефолт-конфиг trap-режима и зацикливание в цикле периодического вывода инфы о событии в лог (UART). Чтобы не пропускать такие ошибки, а исправлять сразу. Этот-же механизм используется для обработки программных критических ошибок (через SVC). Цитата(aaarrr @ May 17 2016, 03:24)  На удаленном оборудовании пару раз выручало. Всех подробностей не вспомню, но потребовалось Помогает очень часто в обнаружении редко проявляющихся ошибок. Когда тестируем сразу несколько десятков (а то и сотни) устройств в течение длительного времени (дни/недели непрерывной работы). С JTAG-ом тут не посидишь, а вот устройства защёлкнувшиеся в trap-цикле сразу видны. А потом - по регистрам-стеку ищем причину. И если такие ошибки проявились уже на объектах заказчика - тут другого выбора нет, очень помогает. Без дампа стека вообще мало когда эта инфа помогает. Типичная ситуация: срабатывание исключения MPU защиты памяти при попытке обращения к недопустимой памяти изнутри memcpy(). От регистров почти никакого толку - в каком месте кода произошёл сбой? Зато по стеку можно легко проследить цепочку вызовов. Уже сколько так багов нашли.
|
|
|
|
|
May 17 2016, 05:22
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(jcxz @ May 17 2016, 07:00)  И где гарантия, что компилятор при очередной перекомпиляции, не разместит какие-то переменные в регистрах которые Вы хотели сохранить до вашей вставки? Такое надо делать целиком в asm-функциях. Напишите ISR fault-ов полностью на asm, там всё элементарно. С легкой руки (для IAR) CODE __stackless void FaultHandler(void * p_base, unsigned long EXC_RETURN) { SaveContext(p_base, EXC_RETURN); EXPT.VERSION = APP_Get_FwVersion(); gMarker = EXCEPTION_MARKER; #ifdef NDEBUG SYS_Reset(); #else while (1); #endif }
__stackless __irq void HardFaultHandler(void) { if (SCB->HFSR & SCB_HFSR_DEBUGEVT_Pos) return; FaultHandler((void*)( (__get_LR() & BIT(2)) ? __get_PSP() : __get_MSP()), __get_LR()); }
__stackless __irq void MemoryFaultHandler(void) { FaultHandler((void*)( (__get_LR() & BIT(2)) ? __get_PSP() : __get_MSP()), __get_LR()); }
__stackless __irq void BusFaultHandler(void) { FaultHandler((void*)( (__get_LR() & BIT(2)) ? __get_PSP() : __get_MSP()), __get_LR());
}
__stackless __irq void UsageFaultHandler(void) { FaultHandler((void*)( (__get_LR() & BIT(2)) ? __get_PSP() : __get_MSP()), __get_LR());
// while(1); }
void SaveContext(void * p_base, unsigned long EXC_RETURN) { EXPT.Registers = *(struct exception_saved_context * )p_base; EXPT.SP = (DWORD)p_base + sizeof(struct exception_saved_context);
EXPT.Status.dwRaw = SCB->CFSR; EXPT.Exception = (int_source_t)(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk); EXPT.EXC_RETURN = ( EXPT.Status.BFSR.BFARVALID) ? SCB->BFAR : EXC_RETURN; SCB->CFSR = 0;
EXPT.HeapFree = OS_MEMORY_AVAILABLE(); EXPT.ShedulerState = OS_GET_SHEDULER_STATE(); EXPT.Context.StackFree = OS_GET_TASK_STACK_WATERMARK(OS_GET_CURRENT_TASK_HANDLE()); strncpy(EXPT.Context.Name, (char*)OS_GET_CURRENT_TASK_NAME() , sizeof(EXPT.Context.Name)); EXPT.Context.Name[sizeof(EXPT.Context.Name)-1] = '\0'; Для CORTEX ядра все получается и без ASM функций. А вот для ARM делал вставку на ASM с обработчиками исключений и функцией сохранения регистров. В большинстве случаев эта информация помогает на столе. В основном в исключения валимся при переполнении стека. Поэтому место возникновения исключения, при наличии RTOS, мало что скажет. Главное состояние планировщика, текущая задача(последняя в случае переключения контекста) и свободное место в стеке задачи.
|
|
|
|
|
May 17 2016, 10:33
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(scifi @ May 17 2016, 15:01)  Как где? __stackless же. У gcc есть аналогичная штука - naked. А это обязательное или только рекомендуемое как inline? А функции, которые из FaultHandler() вызываются тоже все __stackless? И стек - это для примера. Что угодно, например - в какой-либо регистр может заранее положить указатель на секцию данных, либо какие-то другие данные. Использование регистров внутри си-функции - по усмотрению компилятора, любые домыслы по их содержимому - потенциальные грабли.
|
|
|
|
|
May 17 2016, 11:10
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Alechek @ May 17 2016, 14:00)  И не больше. Ну, ну. Я как-то на Си осмелился пописать под AVR. На меге8 килобайты флеш закончились настолько быстро, что захотелось узнать куда. Листинг показал, что компилятор сохраняет в стек все регистры при вызове функций, даже неиспользуемые. Отдельным приключением было сделать программный UART на Си - по тактам реализация очень неустойчива - на том краю планеты бабочка махнет рукой (добавим, например, переменную в проект), а у нас пару лишних тактов в цикле задержки. Что касается регистров, тактов и байтов - компилятор очень непредсказуемая штука.
|
|
|
|
|
May 17 2016, 11:34
|
Частый гость
 
Группа: Участник
Сообщений: 190
Регистрация: 7-11-07
Из: С-Петербург
Пользователь №: 32 134

|
Цитата(adnega @ May 17 2016, 14:10)  Листинг показал, что компилятор сохраняет в стек все регистры при вызове функций, даже неиспользуемые. Компилятор IAR так поступает при выключенной оптимизации (или невысоком уровне).
|
|
|
|
|
May 17 2016, 11:40
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
adnega, речь немного не про такой случай. Использование стека еще как компиляторозависимо. От того, как он будет оптимизировать код, и какую оптимизацию ему разрешено использовать. Уверен, и Вашему случаю нашлось бы объяснение в мануалах.
Здесь о том, что __stackless говорит компилятору, что стека НЕТ! То есть только регистры. И ничего он в них выделять не будет, пока не попросишь.
Да, и определитесь, что у вас закончилось, стек или флеш.... не вяжется как-то.
|
|
|
|
|
May 17 2016, 11:51
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Копейкин @ May 17 2016, 14:34)  Компилятор IAR так поступает при выключенной оптимизации (или невысоком уровне). Тут советовали головой думать, но моя не может придумать - "зачем"? Зачем неиспользуемые регистры складывать в стек?? Хотелось, чтобы основные "просьбы" к компилятору были в исходнике, а не различных ключах. Именно поэтому есть задачки, не решаемые на С гарантированно, рассчитывать на здравый смысл компилятора я бы не стал. Цитата(Alechek @ May 17 2016, 14:40)  Да, и определитесь, что у вас закончилось, стек или флеш.... не вяжется как-то. Прошу без эмоций определить, что быстрее заканчивается при таком подходе Код 11e: 1f 92 push r1 120: 0f 92 push r0 122: 0f b6 in r0, 0x3f; 63 124: 0f 92 push r0 126: 11 24 eor r1, r1 128: 2f 93 push r18 12a: 3f 93 push r19 12c: 4f 93 push r20 12e: 5f 93 push r21 130: 6f 93 push r22 132: 7f 93 push r23 134: 8f 93 push r24 136: 9f 93 push r25 138: af 93 push r26 13a: bf 93 push r27 13c: ef 93 push r30 13e: ff 93 push r31 Это еще годный код, т.к. не все регистры убираются в стек, а только используемые. Я описывал ситуацию, когда банальная установка переменной оборачивалась push-ами и pop-ами для всех регистров. В моем случае резко закончилась флеш, хотя и к глубине стека требования резко возрастают. Перед использованием С этот же проект был реализован на asm. При 10% asm-функционала на С закончился флеш.
|
|
|
|
|
May 17 2016, 11:57
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
Цитата(adnega @ May 17 2016, 16:41)  Зачем неиспользуемые регистры складывать в стек?? Затем что оптимизации НЕТ. Делаем так, чтобы 110% все работало и отладка была удобной. Определитесь для начала, какой результат хотите: быстрый, мало памяти занимал, или для отладки. Программа не работала? Так какие претензии к компилятору? Цитата(adnega @ May 17 2016, 16:51)  Прошу без эмоций определить, что быстрее заканчивается при таком подходе Так да. Закончится и то, и другое. На AVR почти не писал. А в ARM,как тут уже приводили, - одна инструкция хооть для всех регистров.
|
|
|
|
|
May 18 2016, 05:05
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(Alechek @ May 17 2016, 17:00)  jcxz, если делать что-то бездумно - то возможны любые грабли. А если подумать - компилятор пытается лишь сделать то, что от него просят. И не больше. Головой думать надо, прежде что-то делать. Ну-ну. И что же он пытается сделать? Расскажите-ка нам какие именно регистры задействуют все возможные компиляторы во всех возможных режимах оптимизации. К Вашему сведению: компилятор имеет право использовать внутри функции любые регистры как ему заблагорассудится если это не противоречит соглашениям вызова. Если думать именно головой, то как раз не надо делать никаких гаданий как именно будет построен код внутри си-функции.
|
|
|
|
|
May 18 2016, 06:00
|
Профессионал
    
Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882

|
jcxz, сравнивать неопределеность, исходящую от компилятора с определенностью, полученой от ручного кодирования машинных кодов (ASM) бессмысленно. ASM в выигрыше однозначно. Но, вероятность получить "пасхальное яйцо" от компилятора примерно равна вероятности получить неработоспособный код со вполне работоспособных исходников. Выбор всегда есть: - хочешь сложное кодирование но 110% результат - пиши в машинных кодах, - хочешь более легкое программирование и 100% результат - попытайся думать так, как думает компилятор.
И когда я говорю про компилятор, я имею ввиду конкретный, а не абстрактную сущность всех компиляторов. К слову, ASM файлы тоже в большинстве случаев не переносимы.
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|