|
Прошу помощи с STM32F051, Периодическое сваливание в HardFault |
|
|
|
Aug 8 2014, 18:41
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Отлаживаю дивайс на STM32F051. интенсивно используется DMA - все каналы. Периодически (1 раз в 1- 4 часа) происходит HardFault.Ввел обработчик ХардФаулт из Definitive Guide, получил листинг регистров. Не могу полноценно осознать результаты. Судя по содержимому PC, инструкция, вызвавшая HardFault была расположена в RAM. Непонятно. Указатели на функции не использую. Во вложении кусочек скриншота с регистрами.
Эскизы прикрепленных изображений
|
|
|
|
|
 |
Ответов
(1 - 68)
|
Aug 8 2014, 19:25
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(adnega @ Aug 9 2014, 01:22)  Стека точно хватает? Вопрос интересный... Яровские установки = default
|
|
|
|
|
Aug 9 2014, 10:18
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(ViKo @ Aug 9 2014, 16:06)  Причина HardFault описана в Fault регистрах. В той же книге они описаны. Я всегда сначала там роюсь, а потом адрес, с которого улетел, смотрю. Если Вы имеете в виду регистры CFSR и HFSR то в M0 их нет, только в M3/M4. А адрес с которого улетело, есть адрес в области RAM. Программа же расположена во FLASH, и не использует никаких трюков с выполнением из RAM и указателей на функции. Отсюда мой ступор.
|
|
|
|
|
Aug 9 2014, 11:17
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(nanorobot @ Aug 8 2014, 20:41)  Отлаживаю дивайс на STM32F051. интенсивно используется DMA - все каналы. Периодически (1 раз в 1- 4 часа) происходит HardFault.Ввел обработчик ХардФаулт из Definitive Guide, получил листинг регистров. Не могу полноценно осознать результаты. Судя по содержимому PC, инструкция, вызвавшая HardFault была расположена в RAM. Непонятно. Указатели на функции не использую. Во вложении кусочек скриншота с регистрами. Явно в какой-то процедуре затирается стек (LR странный), и при возврате из нее процессор попадает в никуда. Стек затирается видимо ввиду нарушения границ какой-то локальной переменной (массива), объявленной в процедуре. Почему так редко? Ну может наступает некое условие раз в час, например, особое время суток в часах реального времени. А может происходит неверная инициализация DMA, который влазит на чужую область памяти. Например, принимается пакет извне (через UART и т.п.), пакет содержит поле длины, эта длина оказывается изредка неправильной, проверка границ не происходит, DMA грузится слишком "длинно" и влазит в чужой огород. Если глянуть на регистры R1 и R2, можно также увидеть, что они указывают в RAM. Возможно по их значениям и карте памяти для секции RAM можно определить, какие переменные там есть, и, таким образом, по имени переменных и по тексту кода "вычислить" процедуру, которая ломает стек. Да и R3 содержит 0x4B0 = 1200 - больно круглое число, чтобы быть случайным. Это указывает на какой-то счетчик (например, из for ()). Вот гляньте, нет ли в коде процедуры, которая чего-то там прописывает с этой длиной. Если используется динамическое размещение памяти, то в результате длительной работы может возникнуть сильная фрагментация кучи, с которой менеджер не справляется (кто сказал, что не бывает ошибок в библиотеках?) и выделяет память ошибочно. Попробуйте кучу увеличить. Кстати, если куча в собственном коде явно и не используется, возможно она используется библиотеками. Например, для стандарта --C99 локальная переменная-массив может быть переменной длины, зависимой от параметра функции. Это реализуется, к сожалению, не смещением указателя стека, чтобы разместить такой массив в нем, а вызовом malloc/free.
Сообщение отредактировал KnightIgor - Aug 9 2014, 11:21
|
|
|
|
|
Aug 9 2014, 11:23
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(KnightIgor @ Aug 9 2014, 17:17)  ... Благодарю за развернутый ответ. Буду копать в указанных направлениях.
Сообщение отредактировал IgorKossak - Aug 9 2014, 18:29
Причина редактирования: избыточное цитирование
|
|
|
|
|
Aug 9 2014, 15:25
|
Гуру
     
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713

|
Цитата(nanorobot @ Aug 9 2014, 16:18)  Если Вы имеете в виду регистры CFSR и HFSR то в M0 их нет, только в M3/M4. А адрес с которого улетело, есть адрес в области RAM. Программа же расположена во FLASH, и не использует никаких трюков с выполнением из RAM и указателей на функции. Отсюда мой ступор. Это и не обязательно. Cortex может сохранять адреса возврата из функций на стеке. Если Вы его каким-либо образом разрушаете, то при попытке возврата выполнение может улететь куда угодно (или сразу в fault). Цитата(KnightIgor @ Aug 9 2014, 17:17)  Явно в какой-то процедуре затирается стек (LR странный) Там не только LR странный, но и PSR к примеру. Сдаётся мне, что это никакое не содержимое регистров в момент fault-a, а просто ТС привёл нам мусор.  Вот например, что выдаёт мой обработчик критических ошибок при возникновении BUS FAULT: неточная ошибка при обращении к данным (imprecise data bus error) (ловушка 123):
Всё чётко видно где произошло, при каких регистрах и стеке.
|
|
|
|
|
Aug 9 2014, 16:44
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(jcxz @ Aug 9 2014, 21:25)  ... Если быть точным, это не регистры, а их копии лежащие в верхушке стека, т.е. их состояния на момент HardFault. Если я намеренно привожу ситуацию к HardFault - все регистры (их копии в стеке) выглядят вполне пристойно.
Сообщение отредактировал IgorKossak - Aug 9 2014, 18:30
Причина редактирования: избыточное цитирование
|
|
|
|
|
Aug 9 2014, 18:35
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(jcxz @ Aug 10 2014, 00:22)  Пристойно? И 24й бит PSR тоже? То что Вы приводите не имеет никакого отношения к регистрам либо "их копиям в верхушке стека". Извините, если что не так. Вы меня неправильно поняли. "Пристойно" они выглядят не в приведенном случае, а в том, когда я программно создаю ситуацию HardFault от кнопки. а текущий случай не укладывается ни в какие рамки. Возможно ситуация осложнена модификацией стека, или чем либо еще, но она именно такова.
|
|
|
|
|
Aug 9 2014, 19:21
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(jcxz @ Aug 10 2014, 00:50)  Тогда эта модификация стека произошла в вашем обработчике HardFault. Вы же вроде пытаетесь привести результат стекинга на входе в HardFault? Вот как раз такого результата быть не может, как я вам выше уже показал. Скорей всего Вы неправильно определили положение верхушки стека прерванной программы. Осознавая недостаток собственной компетенции обработчик взял из Definitive Guide CODE // Hard Fault handler in C, with stack frame location and LR value // extracted from the assembly wrapper as input parameters void HardFault_Handler(unsigned int * hardfault_args, unsigned lr_value) { static volatile unsigned int stacked_r0; static volatile unsigned int stacked_r1; static volatile unsigned int stacked_r2; static volatile unsigned int stacked_r3; static volatile unsigned int stacked_r12; static volatile unsigned int stacked_lr; static volatile unsigned int stacked_pc; static volatile unsigned int stacked_psr; stacked_r0 = ((unsigned long) hardfault_args[0]); stacked_r1 = ((unsigned long) hardfault_args[1]); stacked_r2 = ((unsigned long) hardfault_args[2]); stacked_r3 = ((unsigned long) hardfault_args[3]); stacked_r12 = ((unsigned long) hardfault_args[4]); stacked_lr = ((unsigned long) hardfault_args[5]); stacked_pc = ((unsigned long) hardfault_args[6]); stacked_psr = ((unsigned long) hardfault_args[7]); printf ("[Hard fault handler]\n"); printf ("R0 = %x\n", stacked_r0); printf ("R1 = %x\n", stacked_r1); printf ("R2 = %x\n", stacked_r2); printf ("R3 = %x\n", stacked_r3); printf ("R12 = %x\n", stacked_r12); printf ("Stacked LR = %x\n", stacked_lr); printf ("Stacked PC = %x\n", stacked_pc); printf ("Stacked PSR = %x\n", stacked_psr); printf ("Current LR = %x\n", lr_value); while(1); // endless loop
|
|
|
|
|
Aug 10 2014, 12:21
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(nanorobot @ Aug 9 2014, 22:47)  Точка - chSemSignal(&semAdc) - использование сервиса RTOS Nil(ChibiOs) от Jiovanni di Sirio. Гляньте, выровнена ли переменная/структура (и ее поля) semAdc: для M0 это критично. Если M3 скушает структуру типа: __packed { U8 a; void *p; }, и не подавится (то есть, когда указатель p явно по нечетному адресу), то в M0 попытка обратиться через *p вызывает hard fault. На это я наткнулся, когда переносил библиотеку с M3 на M0. Т.к. структура у меня должна была оставаться __packed, пришлось перетасовать поля, чтобы указатели были по четным адресам.
|
|
|
|
|
Aug 10 2014, 15:14
|
Местный
  
Группа: Участник
Сообщений: 244
Регистрация: 29-02-08
Пользователь №: 35 503

|
Цитата(KnightIgor @ Aug 10 2014, 18:21)  Гляньте, выровнена ли переменная/структура (и ее поля) semAdc: для M0 это критично. Если M3 скушает структуру типа: __packed { U8 a; void *p; }, и не подавится (то есть, когда указатель p явно по нечетному адресу), то в M0 попытка обратиться через *p вызывает hard fault. На это я наткнулся, когда переносил библиотеку с M3 на M0. Т.к. структура у меня должна была оставаться __packed, пришлось перетасовать поля, чтобы указатели были по четным адресам. данная инструкция выполняется сотни раз в секунду а HF случается раз в часы. т.е. дело видимо не в не в выравнивании, а в стечении неких обстоятельств. Проблему решил, правда, не "в лоб" а обходным маневром - отказался от использования семафора, и вот уже более полусуток проблема не проявляет себя. Хотя желание разобраться в сути проблемы до конца есть.
|
|
|
|
|
Aug 10 2014, 16:49
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 10 2014, 16:57)  Если структура __packed, то выравнивание полей значения не имеет - компилятор собирает каждое поле побайтово. У меня указатель был расположен после U8. В то время как вся структура была размещена с выравниванием 4, поле указателя имело адрес 4*n+1. Инструкция LDR R0, [Rx,#5] вешала систему. Фактически структура была что-то типа: void * U8 void * .. Я сделал void * void * U8 .. после чего все заработало. P.S. KEIL 5.x
Сообщение отредактировал KnightIgor - Aug 10 2014, 16:50
|
|
|
|
|
Aug 11 2014, 08:43
|

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

|
Цитата(KnightIgor @ Aug 10 2014, 19:49)  У меня указатель был расположен после U8. В то время как вся структура была размещена с выравниванием 4, поле указателя имело адрес 4*n+1. Инструкция LDR R0, [Rx,#5] вешала систему. Полагаю, вы чего-то недоговариваете. Если структура была обявлена без квалификатора packed, то компиляор был обязан выровнять указатель на его размер, т.е. на 4 байта, пропустив перед ним необходимое количество байтов. Если структура объявлена с packed, то компилятор пропускать байты не будет, но если процессор не умеет невыровненный доступ (как в случае с Cortex-M0) - компилятор обязан каждое многобайтовое поле считать побайтно и собрать целиком уже в регистрах. То есть он не имел права использовать в этом месте LDR R0, [Rx,#5]. Значит это либо ошибка компилятора (что маловероятно), либо вы использовали явное приведение типа, приведя (void *) к чему-то другому, но забыв packed в приводимом типе. Попробуйте воспроизвести ситуацию еще раз, попытаемся докопаться до причины.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 11 2014, 09:59
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
вроде как-то уже такое обсуждали, но так и не смогли придумать примера когда это произойдет, однако уже 2 свидетельство косяка по этой причине... Интересно правда поглядеть какой код все таки рушит такие доступы. я вот только такой пример знаю Код char Array[8]; int *P = (int *)&Array[2]; *p = 10; в некоторых процах такой маневр приводил к замене не 2, 3, 4, 5 байтов, а все равно к замене 0, 1, 2, 3. Допускаю что такой же ход в кортексе М0 должен взывать падение, я прав?
|
|
|
|
|
Aug 12 2014, 10:08
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 11 2014, 10:43)  Полагаю, вы чего-то недоговариваете. Попробуйте воспроизвести ситуацию еще раз, попытаемся докопаться до причины. Я попытался откатить код. Слетает. Конечно, не в момент заполнения структуры как таковой: в некую процедуру передается указатель на поле структуры типа (void *), а внутри есть инструкция: LDR R0, [R0, #0], при этом R0 = 0x20000035, т.к. R0 это и есть входной параметр процедуры и указывает на поле типа (void *), которая размещена после поля U8, почему и такой нечетный адрес. Эта инструкция загрузки с нечетного адреса и вызывает исключение в -M0, в то время как -M3 все кушает без проблем.
|
|
|
|
|
Aug 12 2014, 12:33
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 12 2014, 13:39)  Так вот это оно и есть. Против лома компилятор бессилен. Попробуйте передавать указатель типа (void * __packed), если компилятор такое позволяет. Я переразместил поля структуры, чтобы было выровнено. Была такая возможность. Конечно, у компилятора против лома нет приема, но и передать в процедуру в качестве параметра поле структуры тоже легитимно. Надеюсь, что для топикстартера описаное мной поведение может помочь найти подобные навороты.
|
|
|
|
|
Aug 17 2014, 11:18
|

Гуру
     
Группа: Свой
Сообщений: 2 015
Регистрация: 23-01-07
Из: Москва
Пользователь №: 24 702

|
Очень интересная тема ! Подскажите, нет ли в интернете какой-нибудь статьи, где разжёваны все отладочные возможности, которые есть после попадания в Hardfault ? И ещё вопрос . Вот тут, что именно произойдёт неправильно? Цитата(KnightIgor @ Aug 10 2014, 16:21)  __packed { U8 a; void *p; }, , то в M0 попытка обратиться через *p вызывает hard fault. Я верно понимаю, что не получится прочитать из памяти 32х битную переменную, не выровненную в памяти на 32 бита ? То есть, ядре М0 вот в этом случае значение b будет всё время некорректным ? __packed { U8 a; U32 b; },
--------------------
Если у Вас нет практического опыта в данной теме- не вступайте в дискуссию и не пишите никаких теоретических рассуждений! Заранее спасибо !
|
|
|
|
|
Aug 17 2014, 13:46
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(MiklPolikov @ Aug 17 2014, 15:54)  А почему компилятор не сможет это сделать, если невыровненное поле это указатель void *p; , как в примере выше ? void * p он обработает без ошибок и HF. Но если p будет указывать на невыровненные данные и будет обращение к этим данным, то в этот момент возникнет HF. Как заставить обработать эту ситуацию? Не знаю, я забочусь, чтоб p всегда указывал на выровненные данные.
|
|
|
|
|
Aug 17 2014, 14:36
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Golikov A. @ Aug 17 2014, 18:07)  ну типа Код char Array[10]; int *p = (int *)&Array[2]; *p = 10; //пипец %) но при этом к полям пакованной структуры компилятор будет обращаться правильно, понимая что они могут быть не выровнены. Но передав это поле в функцию просто указателем будет опять обломс.... Вы же согласитесь, что выстрел в ногу произошел во второй строчке кода?
|
|
|
|
|
Aug 17 2014, 20:45
|
Гуру
     
Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702

|
Цитата(Golikov A. @ Aug 17 2014, 21:11)  это же условно...
может же быть входной байтовый буфер через который идет структура, который при декодировании вот так сделает. Ну или прям стандарт, протокол вида: преамбула - байт, код команды - байт, данные - 32 бита, как раз приводит к таким строчкам... В этом случае неоценимая помощь будет оказана компилятору, если структура будет должным образом описана, а начало буфера будет выровнено на границу слова. Код привести? CODE typedef struct s_test { DWORD dw1; BYTE b1; BYTE b2; DWORD dw2; } __attribute((packed)) s_test;
BYTE b_test[10];
void f_test(void) { s_test *p; p = (s_test *)b_test; p->dw1 = p->dw2; }
Листинг
void f_test(void) { 8000f18: b510 push {r4, lr} s_test *p; p = (s_test *)b_test; p->dw1 = p->dw2; 8000f1a: 4c0a ldr r4, [pc, #40] ; (8000f44 <f_test+0x2c>) 8000f1c: 79e2 ldrb r2, [r4, #7] 8000f1e: 79a0 ldrb r0, [r4, #6] 8000f20: 7a23 ldrb r3, [r4, #8] 8000f22: 0212 lsls r2, r2, #8 8000f24: 4302 orrs r2, r0 8000f26: 041b lsls r3, r3, #16 8000f28: 4313 orrs r3, r2 8000f2a: 1c1a adds r2, r3, #0 8000f2c: 7a63 ldrb r3, [r4, #9] 8000f2e: 061b lsls r3, r3, #24 8000f30: 4313 orrs r3, r2 8000f32: 0a1a lsrs r2, r3, #8 8000f34: 7023 strb r3, [r4, #0] 8000f36: 7062 strb r2, [r4, #1] 8000f38: 0c1a lsrs r2, r3, #16 8000f3a: 0e1b lsrs r3, r3, #24 8000f3c: 70a2 strb r2, [r4, #2] 8000f3e: 70e3 strb r3, [r4, #3] } 8000f40: bd10 pop {r4, pc} 8000f42: 46c0 nop ; (mov r8, r8) ; прикольно. это выравнивание?)) 8000f44: 2000063c .word 0x2000063c - адрес буфера
Не стреляет)) Даже осторожничает с dw1
|
|
|
|
|
Aug 18 2014, 07:50
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 18 2014, 00:22)  Вот тут вы и стреляете себе в ногу - пытясь передать указатель на упакованное поле как обычный указатель. Передавайте его честно, как указатель на упакованные данные - и обломса не будет. Как правильно заметил Golikov A., обломс наступает при переносе библиотек. У меня есть обработчик SVC, код которого базируется на широко цитируемых в сети примерах от ARM. Там, чтобы получить номер SVC из кода инструкции, есть выражение LDRB R0,[R0, #-2], где в R0 загружен сохраненный PC, который, очевидно, указывает на следующую за SVC инструкцию. Так вот, M0 НЕ ДОПУСКАЕТ отрицательные смещения. Хорошо, что ругня идет еще на этапе трансляции... Чтобы код был универсальным, пришлось сделать SUBS R0, R0, #2 LDRB R0,[R0]
Сообщение отредактировал KnightIgor - Aug 18 2014, 07:51
|
|
|
|
|
Aug 18 2014, 09:56
|

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

|
Цитата(KnightIgor @ Aug 18 2014, 10:50)  Как правильно заметил Golikov A., обломс наступает при переносе библиотек. Почему вы упорно валите с больной головы на здоровую? Если библиотека написана правильно, то указатель на упакованные данные будет описан именно как указатель на упакованные данные, без всяких допущений - умеет процессор сам работать с неупакованными данными или нет. Это работа компилятора - он знает целевой процессор лучше нас с вами и если досуп к упакованным данным на целевом процессоре возможен одной командой - он так и сделает. Но если такой доступ невозможен - он сгенерит честный побайтовый доступ. Если же автор библиотеки попытался обмануть компилятор и вместо указателя на упакованные данные подсунул обычный указатель, то виноват в этом писатель библиотеки и более никто. Эта попытка обмануть компилятор и есть выстрел в ногу. Цитата(KnightIgor @ Aug 18 2014, 10:50)  У меня есть обработчик SVC, код которого базируется на широко цитируемых в сети примерах от ARM. То есть вас удивляет, что ассемблерный код для одного ядра не ассемблируется для другого??? А почему вас тогда не удивляет, что код для Пентиума не ассемблируется под 8086? Простите, но это напоминает анекдот: - У меня на телефоне фотографии нечеткими получаются. - Да ладно? Прикинь, а у меня с фотоаппарата вообще звонить нельзя!
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 18 2014, 11:39
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Цитата Почему вы упорно валите с больной головы на здоровую? да я вроде без претензий. Это для меня не столько "ё мое ну нафига так сделали?", сколько объяснение почему бездумное копирование и использование в нормальной работе халявных примеров ведет к неприятным последствиям. в качестве легбеза: получается лучше все указатели что void* передавать как указатели на пакованный тип? А лучше вообще все так передавать? Потому что сейчас выравнивание 32 бита, а завтра будет 64 и проблема старых библиотек и реюз кода вылезет заново? Или же это чем-то плохо? почему по умолчанию то не пакед, если компилятор сам разберется? И работает ли магическое слово пакед, если мы передаем не структуру или ее поле, а кусок байтового массива? или компилятору все равно и это просто указание следить за выравниванием и не более? А че он сам зараза не следит по умолчанию?
|
|
|
|
|
Aug 18 2014, 12:31
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 18 2014, 11:56)  Почему вы упорно валите с больной головы на здоровую? Я не валю, тем более упорно. Я подцепил вброс Golikov A. (перенос библиотек), который простекает из двух основных проблем программирования: нельзя видеть будущее (и написать библиотеку на все случаи жизни), и нужно обеспечивать совместимость с предыдущей версией. Это хорошо проснуться десятилетием позже и охватить все варианты мудрым взором. Но Вы ведь помните, что сначала был M3, а лишь много позже ARM замутил M0, который вдруг не понимает отрицательных смещений и невыровненного доступа. И куда податься крестьянину? Ответ: перепахать огород. Я, кстати, совершенно с Вами согласен, что строгое программирование (в обсуждаемом случае __packed) может избавить от косяков. Но только честно: пусть в нас кинет камень тот, чей код соответствует MISRA. Цитата То есть вас удивляет, что ассемблерный код для одного ядра не ассемблируется для другого??? А почему вас тогда не удивляет, что код для Пентиума не ассемблируется под 8086? Простите, но это напоминает анекдот: - У меня на телефоне фотографии нечеткими получаются. - Да ладно? Прикинь, а у меня с фотоаппарата вообще звонить нельзя! По поводу 8086 и Пентиума - я изложил в первом абзаце. Если пофилосовствовать же, то меня ничто не удивляет в мире диалектики. Ясно одно: чтобы понять настоящее, надо знать предысторию. Правда, один немецкий филосов сказал, что главный урок состоит истории в том, что никто не извлекает из нее уроков. Кстати, Ваш анекдот в части телефона никто бы не понял еще лет 20 назад. На Ваш анекдот отвечу другим: - Почему Богу удалось создать мир всего да 6 дней? - Не нужно было обеспечивать совместимость с предыдущей версией.
|
|
|
|
|
Aug 18 2014, 13:13
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (KnightIgor @ Aug 18 2014, 16:31)  Я не валю, тем более упорно. Я подцепил вброс Golikov A. (перенос библиотек), который простекает из двух основных проблем программирования: нельзя видеть будущее (и написать библиотеку на все случаи жизни), и нужно обеспечивать совместимость с предыдущей версией. Написать вполне можно. Достаточно следовать простым правилам. В данном случае нарушено простенькое правило: нельзя приводить указатель от меньшего типа к большему. Из указателя на int делать указатель на char можно. А наоборот - нельзя. QUOTE (KnightIgor @ Aug 18 2014, 16:31)  Но Вы ведь помните, что сначала был M3, а лишь много позже ARM замутил M0, который вдруг не понимает отрицательных смещений и невыровненного доступа. До Cortex-M3 был ARM7TDMI. Вполне логично ожидать, что ассемблерный код для одной архитектуры не будет переносим на другую архитектуру. На то он и ассемблерный код.
|
|
|
|
|
Aug 18 2014, 14:45
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(LightElf @ Aug 18 2014, 15:13)  До Cortex-M3 был ARM7TDMI. Вполне логично ожидать, что ассемблерный код для одной архитектуры не будет переносим на другую архитектуру. На то он и ассемблерный код. "Логично ожидать?" Тогда вопросы. Когда был ARM7TDMI, было уже известно, что будет Cortex-M3? Когда появился Cortex-M3, и инструкция с отрицательным смещением была допустима, было известно, что появится M0? Если ARM приводит в 2009 пример для Cortex-M3, а именно на ассемблере (речь идет о SVC, и ARM прямо говорит, что без ассемблерной вставки никак), можно ли верить ARM и использовать код? Что будем делать с time_t после 19.01.2038?
|
|
|
|
|
Aug 18 2014, 16:31
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 18 2014, 17:09)  Использовать для Cortex-M3 - можно. Этот же код для Cortex-M0 - чаще всего нет. Сергей, Вы правы. В 2014 году. Для 2009-2010 высказывание смысла не имеет. Как никто бы лет 20 назад не понял, почему смешно, что телефон фотографировать может, а фотоаппарат не может звонить. Кстати, уже и фотоаппарат почти может, коль WiFi в нем уже есть. А лет 30 назад никто бы не понял фразу: "забыл трубу дома". Подумали бы, что музыкант. П.С. Не удержусь, расскажу случай с собственным ребенком в садике. Дело было 2 года назад. В стране, где я живу, в саду проводят тесты, насколько хорошо дети владеют языком, чтобы вовремя отправить к логопеду, например, или позаниматься дополнительно в группе. Для этого им показывают картинки, просят назвать предмет, эмоции лица, и т.п. Родители могут молча присутствовать. И вот показывают моему мальцу картинку, на которой изображено что-то закругленно кубическое, красное, с кругом посередине и точками. Он смотрит долго, хмыкает и говорит: "божья коровка". Тетка начинает ставить наводящие вопросы. Реакция та же - жук, и все. Тогда тетка раскрывает ребенку глаза на этот удивительный мир и утверждает, что изображен телефон (для меня было очевидно: телефон с тубкой сверху, наборной диск с дырочками). На что мой малец говорит: "это не телефон, телефон - с кнопочками и картинкой". Вот так. Что скажут его дети на нынешние смартфоны, имея вживленные сети с приемом прямо в мозг?
Сообщение отредактировал KnightIgor - Aug 18 2014, 16:49
|
|
|
|
|
Aug 19 2014, 03:16
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(Golikov A. @ Aug 18 2014, 15:39)  получается лучше все указатели что void* передавать как указатели на пакованный тип? А лучше вообще все так передавать? Получается (с), что в голове у программера надо навести порядок. Что программеру предоставлен такой инструмент, как типизация. Что этот инструмент помогает избежать ошибок. Что используя void, программер отказывается от этого инструмента, а значит, всю ответственность, по части контроля за ошибками, программер берет на себя. Из чего следует, что очень желательно избегать void, где это только возможно. А если по каким-то причинам пришлось отказаться от типизации, то худшее место, где это можно сделать - "пограничная застава". ИМХО, серьезный повод пересмотреть стиль программирования.
|
|
|
|
|
Aug 19 2014, 06:10
|

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

|
Цитата(KnightIgor @ Aug 18 2014, 19:31)  Сергей, Вы правы. В 2014 году. Для 2009-2010 высказывание смысла не имеет. Похоже, я окончательно потерял нить ваших рассуждений. Если вы работаете с CM-0 - используйте документацию и примеры от CM-0. Причем тут CM-3 независимо от года его рождения? Цитата(Golikov A. @ Aug 19 2014, 08:05)  В большинстве случаев void * может быть прекрасно заменен на char * без какого либо ущерба для функционала или производительности. Это глубокое заблуждение. Будет ущерб производительности программиста. В подавляющем большинстве случаев void * используется в параметрах функций, подобных memcpy(), read(), write(). Это позволяет существенно разгрузить исходник от явных приведений типа при вызове таких функций (приведение в этом случае делается один раз внутри функции). При замене на char * возможность неявного приведения теряется, исходник загромождается явными приведениями. А загроможденный исходник - это совершенно ненужные потери времени на написание и сопровождение.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Aug 19 2014, 07:30
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (KnightIgor @ Aug 18 2014, 18:45)  Когда был ARM7TDMI, было уже известно, что будет Cortex-M3? Нет, известно не было. Но ARM7TDMI (как и нынешний CM0) не поддерживает невыровненные обращения к памяти. П ишете переносимый код - пиш ите его правильно. Ассемблерный код не переносим между архитектурами. QUOTE (KnightIgor @ Aug 18 2014, 18:45)  Когда появился Cortex-M3, и инструкция с отрицательным смещением была допустима, было известно, что появится M0? Если ARM приводит в 2009 пример для Cortex-M3, а именно на ассемблере (речь идет о SVC, и ARM прямо говорит, что без ассемблерной вставки никак), можно ли верить ARM и использовать код? А от PDP-11 ассемблерный код не пробовали Cortex-у скормить? CM0 и CM3 - разные процессоры, с разной системой команд. QUOTE (KnightIgor @ Aug 18 2014, 18:45)  Что будем делать с time_t после 19.01.2038? используйте time_t именно как time_t, не приводите его к другому типу. QUOTE (Golikov A. @ Aug 18 2014, 19:37)  ох... и как жить? почти любой парсер входящих сообщений занимается разбором символьных массивов в нечто большее... И в чем проблема написать CODE char * y; int x = y[0] | (y[1] << 8) | (y[2] << 16) | (y[3]<<24); ? Получите более переносимый результат. QUOTE (Golikov A. @ Aug 18 2014, 19:37)  следить надо читать и помнить. Тем профик и отличается от не пойми кого, у него есть опыт  Приведение указателя от большего типа к меньшему переносимо всегда. В обратную сторону - непереносимо. Пляски с __packet (__attribute, #pragma pack и т.д.) зависят от компилятора. Использовать их можно (и иногда нужно), но переносимости ожидать нельзя.
|
|
|
|
|
Aug 19 2014, 08:21
|
Знающий
   
Группа: Участник
Сообщений: 643
Регистрация: 29-05-09
Из: Германия
Пользователь №: 49 725

|
Цитата(Сергей Борщ @ Aug 19 2014, 08:10)  Похоже, я окончательно потерял нить ваших рассуждений. Если вы работаете с CM-0 - используйте документацию и примеры от CM-0. Причем тут CM-3 независимо от года его рождения? Я о том, что нельзя предвидеть будущее с одной стороны, и легко умничать (не упрек Вам, а общее рассуждение) и тыкать НЫНЕ носом в код, несовместимый с процессором, которого не было и в помине в период написания библиотеки. И о том, что несмотря на стремление и утверждение ARM "забыть" ассемблер при работе с Cortex (это же их рекламный слоган был!), есть навороты, когда без этого самого ассемблера (смотри тот же ARM для SVC) ну никак. Я не спорю, что -M0 это иное, чем -M3, и надо учитывать СЕЙЧАС особенности -M0, но учесть их 4-5 лет назад было невозможно по определению. И так будет всегда. И допахивать код придется всегда - тот же time_t. Тут один советчик опустился до вопроса, не пробовал ли я код с PDP-11 на Cortex перенести. Он, видимо, предполагал, что я не знаю, что такое PDP-11. Но в отличие от него, я еще помню НАИЗУСТЬ многие бинарные коды инструкций PDP-11: в советское время CM-1420 и "Электроника". Кстати, MSP430 - это тот самый PDP-11 по идее.
Сообщение отредактировал KnightIgor - Aug 19 2014, 08:52
|
|
|
|
|
Aug 19 2014, 10:29
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (KnightIgor @ Aug 19 2014, 12:21)  Я о том, что нельзя предвидеть будущее с одной стороны, и легко умничать (не упрек Вам, а общее рассуждение) и тыкать НЫНЕ носом в код, несовместимый с процессором, которого не было и в помине в период написания библиотеки. Задолго до появления CM3 были процессоры, требовавшие правильного выравнивания данных. Более того, таких процессорных архитектур и тогда и сейчас - большинство. Вы заложились на редкую фишку и теперь на что-то жалуетесь. QUOTE (KnightIgor @ Aug 19 2014, 12:21)  И о том, что несмотря на стремление и утверждение ARM "забыть" ассемблер при работе с Cortex (это же их рекламный слоган был!), есть навороты, когда без этого самого ассемблера (смотри тот же ARM для SVC) ну никак. Вот что-то не уверен я, что там не обойтись без ассемблера. С другой стороны, низкоуровневый обработчик исключения по определению не может быть переносимым. QUOTE (KnightIgor @ Aug 19 2014, 12:21)  И допахивать код придется всегда - тот же time_t. В _одном_ месте переопределите time_t как long long - и все остальное поедет без переделок. Конечно если вы не преобразовываете time_t в void-указатель. QUOTE (KnightIgor @ Aug 19 2014, 12:21)  Тут один советчик опустился до вопроса, не пробовал ли я код с PDP-11 на Cortex перенести. Он, видимо, предполагал, что я не знаю, что такое PDP-11. Но в отличие от него, я еще помню НАИЗУСТЬ многие бинарные коды инструкций PDP-11: в советское время CM-1420 и "Электроника". Кстати, MSP430 - это тот самый PDP-11 по идее. Я тоже прекрасно помню коды PDP-11, не стоит со мной мериться известным предметом. И придумывать за меня, что я предполагал, тоже не надо.
|
|
|
|
|
Aug 20 2014, 05:39
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(Golikov A. @ Aug 19 2014, 09:05)  В большинстве случаев void * может быть прекрасно заменен на char * без какого либо ущерба для функционала или производительности. Void нужен больше стилистически, что-ли, для понятности кода. Перевожу на русский язык: в большинстве случаев "грузовик" может быть заменен на "автомобиль". У меня только один вопрос, стоит ли при таком подходе удивляться, что вместо контейнеровоза, прислали Форд Фиеста? А в качестве такси, к подъезду подали Камаз?  Цитата(KnightIgor @ Aug 18 2014, 18:45)  Что будем делать с time_t после 19.01.2038? Стесняюсь спросить, а какая связь, между ТИПОМ time_t и неким ЗНАЧЕНИЕМ? Подобный вопрос говорит лишь о непонимании, что есть тип/типизация. Цитата(KnightIgor @ Aug 19 2014, 12:21)  нельзя предвидеть будущее Вот именно поэтому, надо научиться мыслить абстрактно. Надо научиться простой вещи, забыть сами понятия "сколько бит", "какой адрес". Если, не дай Б-г, в голове у программера всплывает вопрос "а сколько бит char?", он должен тут же себе ответить - не твое собачье дело.  Аналогично с адресом. Надо вбить себе в голову, что у переменных есть только один адрес - "где-то". Сколько это "в граммах" - не программерова ума дело. И, предвосхищая следующий вопрос, сразу отвечу, что понятия "адрес" и "область памяти"/"тип памяти" означают совершенно разные вещи. Вот так, легко и непринужденно, раскрывается тема сисек написания переносимого кода.  Цитата(Golikov A. @ Aug 19 2014, 23:40)  явно привожу их к типу void *, тем самым убивая полученную выгоду, но мне кажется что так код понятнее в некоторых местах Ну включаем логику. Как может стать понятнее, если табличку "Иванов, 28 лет, пневмония, лечащий врач Сидоров" заменить на табличку "очередной больной"?
|
|
|
|
|
Aug 20 2014, 07:28
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
А вы по специальности работали?  ... мне вот очень важно сколько бит int, потому что когда вы его массивами на компьютер шлете и обратно принимаете хорошо бы знать сколько переменных пошло. Так же я напомню что есть big endian и little endian, хорошо про них не знать, но в железе редко имеем дело с одним процессором, а если еще ПЛИС, а в ней удобнее big endian, а между процом и ПЛИС тоже интерфейсы и передача данных. также мы вспоминаем о структурах и их преобразовании в байтовый массив и обратно, где так же важно знать типы, размеры полей, их последовательность и прочее... И тут в полный рост встает архитектура, по посылайте на компьютер не пакованные структуры с какого-нить СМ0, и попробуйте их с позиции "не програмерово собачье дело" их преобразовать. Ну и пример про грузовик: void - это не просто машина, это такая машина, которая может все, и потому если запросили void машину, то она сто пудово подойдет, только надо с пониманием к ней отнестись, и найти где вход  , а все остальное она сделает, и груз перевезет и на работу по пробкам доставит. И продолжая этот пример, трудности на себя берет водитель, чтобы клиенты не парились! Цитата Ну включаем логику. Как может стать понятнее, если табличку "Иванов, 28 лет, пневмония, лечащий врач Сидоров" заменить на табличку "очередной больной"? не такая замена как вы говорите, а такая: "Иванов, 28 лет, пневмония, лечащий врач Сидоров" меняем на (очередной больной) "Иванов, 28 лет, пневмония, лечащий врач Сидоров" согласитесь что во 2 случае информации чуть больше, как минимум что мы именно хотели включить этого человека как нашего очередного больного. Иногда в поисках ошибок находятся разные места кода, и смотрите на них и думаете а нет ли тут ошибки, и иногда с таким явным уточнением вы понимаете что тут все верно. Особенно это часто это происходит когда идут двойные указатели и всякие их разименования...
|
|
|
|
|
Aug 20 2014, 08:30
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(Golikov A. @ Aug 20 2014, 11:28)  мне вот очень важно сколько бит int Это очень плохо. Потому что все, что должен знать программер о типе int, что это тип, _удобный_ для процессора. Цитата(Golikov A. @ Aug 20 2014, 11:28)  потому что когда вы его массивами на компьютер шлете и обратно принимаете хорошо бы знать сколько переменных пошло указатели и всякие их разименования... Пересылка int между машинами, это тоже очень плохо, говорит о низкой квалификации программера. Обмен между машинами должен идти в каких-либо data_t, а не int. И пусть не вводит в заблуждение тот факт, что по каким-то причинам, в т.ч. из-за совпадения кол-ва разрядов, данные представляют все тем же int. Повторюсь, int, это некоторый тип, удобный для процессора и ничего более. Любые совпадения - случайны, все персонажи - вымышлены. (с) Цитата(Golikov A. @ Aug 20 2014, 11:28)  Так же я напомню что есть big endian и little endian, хорошо про них не знать, но в железе редко имеем дело с одним процессором А причем здесь железо? Мы говорим о том, насколько программер понимает/чувствует инструмент, которым пользуется. В общем случае, программа должна быть написана так, что бы было плевать, на каком endian работает процессор. Вот мы снова вернулись к переносимости кода. Если писать так, то будет зависимость от endian: Код union { uint16_t d; struct { uint8_t l; uint8_t h; } } А если написать так, то исполняться будет одинаково, при любом endian: l = d >> 0; h = d >> 8; Цитата(Golikov A. @ Aug 20 2014, 11:28)  а если еще ПЛИС, а в ней удобнее big endian Какой любопытный постулат. Можно с этого места попобробнее. А то моим ПЛИС всегда было по-барабану, с каким endian работать. - грузины, лучше чем армяне - чем лучше? - чем армяне! (с)  Цитата(Golikov A. @ Aug 20 2014, 11:28)  также мы вспоминаем о структурах и их преобразовании в байтовый массив и обратно, где так же важно знать типы, размеры полей, их последовательность и прочее... И тут в полный рост встает архитектура ... и тут в полный рост встает умение правильно структурировать программу. Выносится небольшой кусочек, в котором есть подобные зависимости. Не надо сразу лезть копаться в частностях, не разобравшись с главным. Цитата(Golikov A. @ Aug 20 2014, 11:28)  Ну и пример про грузовик: void - это не просто машина, это такая машина, которая может Ну вот не надо фантазировать, а? Здесь void, это то же, что и просто машина. Без уточнений, что она там может, а что не может. Цитата(Golikov A. @ Aug 20 2014, 11:28)  если запросили void машину, то она сто пудово подойдет Вот опять, выдаем желаемое за действительное. Если запросили void машину, это не значит, что она подойдет. Это значит, что клиент ничего не сообщил о том, какая машина ему нужна. Подойдет или нет - никто не знает. Собсно, в обсуждении выше это и произошло - на каком-то ядре void * работало корректно, но в один прекрасный день, случилось то, что и должно было случиться. Цитата(Golikov A. @ Aug 20 2014, 11:28)  И продолжая этот пример, трудности на себя берет водитель, чтобы клиенты не парились! Да-да. Я прям представил себе, как на погрузку 2т сахара, приехало такси и водитель "взял на себя все трудности". На своем горбу, видимо, перетаскал, от склада до магазина. Главное, что клиенты не парились.  Цитата(Golikov A. @ Aug 20 2014, 11:28)  не такая замена как вы говорите, а такая: "Иванов, 28 лет, пневмония, лечащий врач Сидоров" меняем на (очередной больной) "Иванов, 28 лет, пневмония, лечащий врач Сидоров" Сдаюсь. Видимо, умение программировать дано не каждому.
|
|
|
|
|
Aug 20 2014, 08:44
|
Гуру
     
Группа: Свой
Сообщений: 4 256
Регистрация: 17-02-06
Пользователь №: 14 454

|
Цитата Сдаюсь. Видимо, умение программировать дано не каждому. последние вы верно заметили. Точно не каждому%)... из наводящих вопросов, если с big и little проблем нет, то нафига функция смены порядка байт иногда(напишем осторожно) поддержана на железном уровне? И еще спрошу известна ли вам разница между SPI и UART? не очевидная в синхронизации, а другая, что в битах лежит? Кстати, насколько удобен int для 8051? Мне правда интересно каких приемов я не знаю. Вот мне дают описание что с компьютера придет структура struct { int32_t OverLoadFlags; int32_t SpeedX; int32_t SpeedY; int32_t SpeedZ; int32_t SpeedRx; int32_t SpeedRy; } вот как вы это оформляете в вашей программе, приемную часть? При условии что вы не заботитесь о битности? Приведите пример?
|
|
|
|
|
Aug 20 2014, 10:46
|
Местный
  
Группа: Свой
Сообщений: 459
Регистрация: 30-03-06
Из: Москва
Пользователь №: 15 600

|
Цитата(Golikov A. @ Aug 20 2014, 12:44)  последние вы верно заметили. Точно не каждому%)... Конечно. В 2/3 случаев, мне попадается не программирование, а г*внокод(с). Главное, не путать эти два понятия.  Цитата(Golikov A. @ Aug 20 2014, 12:44)  с компьютера придет структура Новое слово в интерфесах. Про ПЛИС ответа не дождался. Но может хоть про это дождусь. Шо, вот прям структура приходит?  Там, поди, шина специальная, на каждого члена структуры - своя subbus?
|
|
|
|
|
Aug 21 2014, 11:51
|
Частый гость
 
Группа: Участник
Сообщений: 180
Регистрация: 5-04-09
Пользователь №: 47 205

|
QUOTE (KnightIgor @ Aug 19 2014, 12:21)  Тут один советчик опустился до вопроса, не пробовал ли я код с PDP-11 на Cortex перенести. Он, видимо, предполагал, что я не знаю, что такое PDP-11. Но в отличие от него, я еще помню НАИЗУСТЬ многие бинарные коды инструкций PDP-11: в советское время CM-1420 и "Электроника". Кстати, MSP430 - это тот самый PDP-11 по идее. Раз уж коды инструкций на наизусть помните, может и требования к выравниванию переменных не забыли? На всякий случай: ваш код и на PDP-11 работать не будет.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|