Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Команда "STM r0!, {r1}" на Cortex M3
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
ISK2010
Добрый день!

Железо - 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.

Люди добрые, прокомментируйте случившееся. Помогите подвести итог.
ViKo
А почему вы не определили pPDU как указатель на 32-битовую переменную, а увеличиваете его на 4?
По состоянию битов в xxx Fault Status регистрах можно определить причину вылета. Их можно увидеть в Keil - посмотреть соответствующий диапазон памяти (0xE000ED28 и др.).
KRS
Цитата(ISK2010 @ Sep 6 2011, 17:37) *
Пока выяснял почему, начитался всякого. Вплоть до того, что вставленная 16битная инструкция STM является устаревшей и не используется для ядер ARMv6 и выше. А в другом месте (в ссылке про STM) вообще написано, что 16битная STM не поддерживается в Thumb-2EE, который для ARMv7, т.е. нашего Cortex-M3.

Есть 16 битное кодирование, в ARMv7M reference manual называется Encoding T1 - тут все ок!

А в Hard Fault скорее всего вылетает из-за не выравненного доступа! STM нельзя так использовать. Если это так то в исходнике некорректное приведение типов, надо приводить к не выравненному типу или писать макрос.
ISK2010
To ViKo:

pPDU - указатель на байт, поэтому прибавляю 4. Fault Status завтра гляну, все железо на работе.

To KRS:

Да, ошибка возникала при не выровненном доступе. Но я не нашел где написано, что нельзя с не выровненными использовать. Подскажите в каком доке? Кто знает, может там для меня еще что-нибудь найдется.

Да, приведение корректно до некорректности. Как бы это обойти. Есть буфер, и в него пишутся разные вещи, в том числе 32битные. А структуры этих вещей выровнять не могу, т.к. этот буфер для связи с внешним устройством. Тут точно надо избавляться от "STM", но как бы это компилятору объяснить.




aaarrr
Цитата(ISK2010 @ Sep 6 2011, 19:55) *
как бы это компилятору объяснить.

__packed
ViKo
Процитирую помощь к Кейлу, правда, не уверен, что если указатель определен на байтовую переменную, а потом приводится к указателю на целое, то будет работать.

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.
KRS
Цитата(ISK2010 @ Sep 6 2011, 19:55) *
Подскажите в каком доке? Кто знает, может там для меня еще что-нибудь найдется.

arm architecture v7m reference manual
так же полезно будет
Cortex™-M3 Technical Reference Manual
ISK2010
Огромное СПАСИБО! Использовал _packed для структур, а применительно к указателям не знал)
И мануальчики почитаю.


Наверное, топик надо в раздел "помощь начинающим/программирование". Скандалы, интриги, расследования закончены. Их просто нет, все банально просто.
777777
Цитата(ISK2010 @ Sep 6 2011, 17:37) *
Код
*((u32*)pPDU) = __REV16_W(*((u32*)( MB_HoldRegs + Address))); //да хоть просто число туда записывать

А что это за макрос __REV16_W?
ISK2010
Цитата
А что это за макрос __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
  }


ViKo
Цитата(ISK2010 @ Sep 7 2011, 09:21) *
Но,как видите, они зачем-то аргумент сделали 16-битным.

Похоже на косяк в CMSIS?
ISK2010
Может у них так и было задумано)
ViKo
Цитата(ISK2010 @ Sep 7 2011, 09:51) *
Может у них так и было задумано)

Реверсируется-то порядок байтов в обоих полусловах, и в младшем, и в старшем. wacko.gif
demiurg_spb
Получается, что фолт на cm3 может произойти лишь при адресации не выравненных объектов больших байта?
А указатели на байт в принципе не нуждаются в атрибуте packed.
Я правильно мыслю?

Цитата(ViKo @ Sep 7 2011, 11:02) *
Реверсируется-то порядок байтов в обоих полусловах, и в младшем, и в старшем. wacko.gif
Поэтому аргумент и 16-ти битный в старшем полуслове будут всегда нули. Баги в CMSIS я не вижу.

Кстати, в литературе есть мнение, что
Код
b = ((a & 0x00ff) << 8) | ((a & 0xff00) >> 8); // This should generate the REV16 instruction.
ViKo
Цитата(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. То же относится и к аргументам функций и возвращаемому результату.
demiurg_spb
Цитата(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 - крайняя мера...
ISK2010
Да, ModBus) Решил оптимизировать функции обработки запросов. Например, сразу по 2 регистра читаю-записываю. Адрес региста+количество тоже за раз обрабатываю.
demiurg_spb
Ой не там экономите. Завтра нужно будет для 8-ми битника modbus ваять, после завтра...
За такой оптимизацией теряется прозрачность идеи.
Опять же ИМХО.
ISK2010
Везде по чуть-чуть. Еще с расчета CRC немного высвободил. На данный момент загрузка ~70%.
aaarrr
Цитата(ISK2010 @ Sep 7 2011, 20:47) *
На данный момент загрузка ~70%.

От одного модбаса?
ISK2010
От всего
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.