|
Команда "STM r0!, {r1}" на Cortex M3, При невыровненном адресе возникает Hard Fault. |
|
|
|
Sep 6 2011, 13:37
|

Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 21-09-10
Из: г.Зеленоград
Пользователь №: 59 631

|
Добрый день! Железо - STM32F105VC rev.Z. ПО - Keil 4.21, компилятор armcc 4.1.0.644 Случилось вот что. Понадобилось мне одну 32битную сохранить в буфер, и адрес поменять на следующую ячейку буфера: Код *((u32*)pPDU) = __REV16_W(*((u32*)( MB_HoldRegs + Address))); //да хоть просто число туда записывать pPDU += 4; Ситуация стандартная. Но на мою голову компилятор засовывает инструкцию " STM": Код 0x080018A0 F7FEFC70 BL.W __REV16_W (0x08000184) 0x080018A4 C601 STM r6!,{r0} тем самым пытаясь выполнить запись+инкремент за раз, но при выполнении которой происходит ошибка (HardFault). Пока выяснял почему, начитался всякого. Вплоть до того, что вставленная 16битная инструкция STM является устаревшей и не используется для ядер ARMv6 и выше. А в другом месте (в ссылке про STM) вообще написано, что 16битная STM не поддерживается в Thumb-2EE, который для ARMv7, т.е. нашего Cortex-M3. Но тогда почему именно эта инструкция была вставлена? Неужели косяк компилятора? Или же все-таки эта инструкция поддерживается Cortex-M3, но есть ограничения для ревизиии Z? Все эти вопросы я себе задавал, а между этим провел эксперимент. Написал на ассемблере функцию, в которой с помощью этой инструкции заполняю массив 32битных элементов. Результат экспериментов: инструкция работает, но если адрес массива не кратен 4, то вылетаем в Hard Fault. Люди добрые, прокомментируйте случившееся. Помогите подвести итог.
Сообщение отредактировал ISK2010 - Sep 6 2011, 13:39
|
|
|
|
2 страниц
1 2 >
|
 |
Ответов
(1 - 20)
|
Sep 6 2011, 15:55
|

Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 21-09-10
Из: г.Зеленоград
Пользователь №: 59 631

|
To ViKo:
pPDU - указатель на байт, поэтому прибавляю 4. Fault Status завтра гляну, все железо на работе.
To KRS:
Да, ошибка возникала при не выровненном доступе. Но я не нашел где написано, что нельзя с не выровненными использовать. Подскажите в каком доке? Кто знает, может там для меня еще что-нибудь найдется.
Да, приведение корректно до некорректности. Как бы это обойти. Есть буфер, и в него пишутся разные вещи, в том числе 32битные. А структуры этих вещей выровнять не могу, т.к. этот буфер для связи с внешним устройством. Тут точно надо избавляться от "STM", но как бы это компилятору объяснить.
|
|
|
|
|
Sep 6 2011, 17:32
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Процитирую помощь к Кейлу, правда, не уверен, что если указатель определен на байтовую переменную, а потом приводится к указателю на целое, то будет работать.
Unaligned pointers By default, the ARM compiler expects conventional C pointers to point to an aligned word in memory, because this enables the compiler to generate more efficient code.
If you want to define a pointer that can point to a word at any address, then you must specify this using the __packed qualifier when defining the pointer. For example:
__packed int *pi; // pointer to unaligned int When a pointer is declared as __packed, the ARM compiler generates code that correctly accesses the dereferenced value of the pointer, regardless of its alignment. The generated code consists of a sequence of byte accesses, or variable alignment-dependent shifting and masking instructions, rather than a simple LDR instruction. Consequently, declaring a pointer as __packed incurs a performance and code size penalty.
|
|
|
|
|
Sep 7 2011, 06:21
|

Местный
  
Группа: Участник
Сообщений: 205
Регистрация: 21-09-10
Из: г.Зеленоград
Пользователь №: 59 631

|
Цитата А что это за макрос __REV16_W? Эта функция меняет местами байты в каждом полуслове и выдает результат. В CMSIS есть такое: Код __ASM uint32_t __REV16(uint16_t value) { rev16 r0, r0 bx lr } Но,как видите, они зачем-то аргумент сделали 16-битным. Поэтому я сделал тоже, только с 32-битным: Код __ASM u32 __REV16_W(u32 value) { rev16 r0, r0 bx lr }
|
|
|
|
|
Sep 7 2011, 08:04
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Получается, что фолт на cm3 может произойти лишь при адресации не выравненных объектов больших байта? А указатели на байт в принципе не нуждаются в атрибуте packed. Я правильно мыслю? Цитата(ViKo @ Sep 7 2011, 11:02)  Реверсируется-то порядок байтов в обоих полусловах, и в младшем, и в старшем.  Поэтому аргумент и 16-ти битный в старшем полуслове будут всегда нули. Баги в CMSIS я не вижу. Кстати, в литературе есть мнение, что Код b = ((a & 0x00ff) << 8) | ((a & 0xff00) >> 8); // This should generate the REV16 instruction.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Sep 7 2011, 08:57
|

Универсальный солдатик
     
Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362

|
Цитата(demiurg_spb @ Sep 7 2011, 11:04)  Поэтому аргумент и 16-ти битный в старшем полуслове будут всегда нули. Баги в CMSIS я не вижу. Кстати, в литературе есть мнение, что Код b = ((a & 0x00ff) << 8) | ((a & 0xff00) >> 8); // This should generate the REV16 instruction. Понятно, что при 16-битовом аргументе будет работать. А если нужно проинвертировать порядок в обоих полусловах, придется писать свою функцию, как сделал ISK2010. Хотя команда та же. А можно было задать в функции REV16 32-битовый аргумент. Если кому-то нужно было проинвертировать порядок байтов в 16-битовой переменной, то эту 32-битовую функцию можно было бы использовать без переделок. Кстати, в приведенной вами литературе есть пример, показывающий неэффективность использования в функциях переменныхс размерностью, меньше, чем int32. То же относится и к аргументам функций и возвращаемому результату.
|
|
|
|
|
Sep 7 2011, 09:42
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(ViKo @ Sep 7 2011, 12:57)  А можно было задать в функции REV16 32-битовый аргумент. Если кому-то нужно было проинвертировать порядок байтов в 16-битовой переменной, то эту 32-битовую функцию можно было бы использовать без переделок. Это да. Цитата Кстати, в приведенной вами литературе есть пример, показывающий неэффективность использования в функциях переменныхс размерностью, меньше, чем int32. То же относится и к аргументам функций и возвращаемому результату. Разумеется. Цитата(ViKo @ Sep 7 2011, 12:57)  Понятно, что при 16-битовом аргументе будет работать. А если нужно проинвертировать порядок в обоих полусловах, придется писать свою функцию, как сделал ISK2010. Вопрос зачем ему это? Какой-то middle-endian формат получается. Ведь для смены эндианизма есть инструкции REV и REVSH. Как я понял речь идёт в контексте формирования PDU одного из протоколов (modbus?), где используется не нативный для cm3 сетевой порядок следования байт. ИМХО расширять функционал CMSIS - крайняя мера...
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|