реклама на сайте
подробности

 
 
2 страниц V  < 1 2  
Reply to this topicStart new topic
> Чтение внутренних регистров STM32
jcxz
сообщение May 17 2016, 02:00
Сообщение #16


Гуру
******

Группа: Свой
Сообщений: 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().
От регистров почти никакого толку - в каком месте кода произошёл сбой? Зато по стеку можно легко проследить цепочку вызовов. Уже сколько так багов нашли.
Go to the top of the page
 
+Quote Post
Alechek
сообщение May 17 2016, 05:22
Сообщение #17


Профессионал
*****

Группа: Свой
Сообщений: 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, мало что скажет. Главное состояние планировщика, текущая задача(последняя в случае переключения контекста) и свободное место в стеке задачи.
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 17 2016, 08:48
Сообщение #18


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Alechek @ May 17 2016, 11:22) *
__stackless void FaultHandler(void * p_base, unsigned long EXC_RETURN)
{
SaveContext(p_base, EXC_RETURN);
...
Для CORTEX ядра все получается и без ASM функций.

Ещё раз: Где гарантия, что компилятор не вставит перед Вашей SaveContext() например создание стекового фрейма с занесением указателя на него в любой из R4-R11?
Типа:
PUSH {R7, LR}
ADD R7, SP, #N
...

или ещё чего, чего ему вздумается.
Go to the top of the page
 
+Quote Post
scifi
сообщение May 17 2016, 09:01
Сообщение #19


Гуру
******

Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136



Цитата(jcxz @ May 17 2016, 11:48) *
Ещё раз: Где гарантия, что компилятор не вставит перед Вашей SaveContext() например создание стекового фрейма с занесением указателя на него в любой из R4-R11?

Как где? __stackless же. У gcc есть аналогичная штука - naked.
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 17 2016, 10:33
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(scifi @ May 17 2016, 15:01) *
Как где? __stackless же. У gcc есть аналогичная штука - naked.

А это обязательное или только рекомендуемое как inline? А функции, которые из FaultHandler() вызываются тоже все __stackless?
И стек - это для примера. Что угодно, например - в какой-либо регистр может заранее положить указатель на секцию данных, либо какие-то другие данные.
Использование регистров внутри си-функции - по усмотрению компилятора, любые домыслы по их содержимому - потенциальные грабли.
Go to the top of the page
 
+Quote Post
Alechek
сообщение May 17 2016, 11:00
Сообщение #21


Профессионал
*****

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



jcxz, если делать что-то бездумно - то возможны любые грабли.
А если подумать - компилятор пытается лишь сделать то, что от него просят. И не больше.
Головой думать надо, прежде что-то делать.
Go to the top of the page
 
+Quote Post
adnega
сообщение May 17 2016, 11:10
Сообщение #22


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(Alechek @ May 17 2016, 14:00) *
И не больше.

Ну, ну. Я как-то на Си осмелился пописать под AVR. На меге8 килобайты флеш закончились настолько быстро, что захотелось узнать куда.
Листинг показал, что компилятор сохраняет в стек все регистры при вызове функций, даже неиспользуемые.
Отдельным приключением было сделать программный UART на Си - по тактам реализация очень неустойчива - на том краю планеты бабочка
махнет рукой (добавим, например, переменную в проект), а у нас пару лишних тактов в цикле задержки.
Что касается регистров, тактов и байтов - компилятор очень непредсказуемая штука.
Go to the top of the page
 
+Quote Post
Копейкин
сообщение May 17 2016, 11:34
Сообщение #23


Частый гость
**

Группа: Участник
Сообщений: 190
Регистрация: 7-11-07
Из: С-Петербург
Пользователь №: 32 134



Цитата(adnega @ May 17 2016, 14:10) *
Листинг показал, что компилятор сохраняет в стек все регистры при вызове функций, даже неиспользуемые.

Компилятор IAR так поступает при выключенной оптимизации (или невысоком уровне).
Go to the top of the page
 
+Quote Post
Alechek
сообщение May 17 2016, 11:40
Сообщение #24


Профессионал
*****

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



adnega, речь немного не про такой случай.
Использование стека еще как компиляторозависимо. От того, как он будет оптимизировать код, и какую оптимизацию ему разрешено использовать.
Уверен, и Вашему случаю нашлось бы объяснение в мануалах.

Здесь о том, что __stackless говорит компилятору, что стека НЕТ! То есть только регистры. И ничего он в них выделять не будет, пока не попросишь.

Да, и определитесь, что у вас закончилось, стек или флеш.... не вяжется как-то.
Go to the top of the page
 
+Quote Post
adnega
сообщение May 17 2016, 11:51
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 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-функционала на С закончился флеш.
Go to the top of the page
 
+Quote Post
Alechek
сообщение May 17 2016, 11:57
Сообщение #26


Профессионал
*****

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



Цитата(adnega @ May 17 2016, 16:41) *
Зачем неиспользуемые регистры складывать в стек??

Затем что оптимизации НЕТ. Делаем так, чтобы 110% все работало и отладка была удобной.
Определитесь для начала, какой результат хотите: быстрый, мало памяти занимал, или для отладки.
Программа не работала? Так какие претензии к компилятору?


Цитата(adnega @ May 17 2016, 16:51) *
Прошу без эмоций определить, что быстрее заканчивается при таком подходе

Так да. Закончится и то, и другое.

На AVR почти не писал. А в ARM,как тут уже приводили, - одна инструкция хооть для всех регистров.
Go to the top of the page
 
+Quote Post
jcxz
сообщение May 18 2016, 05:05
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(Alechek @ May 17 2016, 17:00) *
jcxz, если делать что-то бездумно - то возможны любые грабли.
А если подумать - компилятор пытается лишь сделать то, что от него просят. И не больше.
Головой думать надо, прежде что-то делать.

Ну-ну. И что же он пытается сделать? Расскажите-ка нам какие именно регистры задействуют все возможные компиляторы во всех возможных режимах оптимизации.
К Вашему сведению: компилятор имеет право использовать внутри функции любые регистры как ему заблагорассудится если это не противоречит соглашениям вызова.
Если думать именно головой, то как раз не надо делать никаких гаданий как именно будет построен код внутри си-функции.
Go to the top of the page
 
+Quote Post
Alechek
сообщение May 18 2016, 06:00
Сообщение #28


Профессионал
*****

Группа: Свой
Сообщений: 1 241
Регистрация: 15-11-05
Из: Челябинск
Пользователь №: 10 882



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

И когда я говорю про компилятор, я имею ввиду конкретный, а не абстрактную сущность всех компиляторов.
К слову, ASM файлы тоже в большинстве случаев не переносимы.
Go to the top of the page
 
+Quote Post

2 страниц V  < 1 2
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th June 2025 - 14:22
Рейтинг@Mail.ru


Страница сгенерированна за 0.0148 секунд с 7
ELECTRONIX ©2004-2016