Перейти к содержанию
    

SII

Свой
  • Постов

    898
  • Зарегистрирован

  • Посещение

Репутация

0 Обычный

2 Подписчика

Информация о SII

  • Звание
    Знающий
    Знающий
  • День рождения 22.12.1972

Информация

  • Город
    Array

Посетители профиля

5 979 просмотров профиля
  1. Насколько помню, в STM32H745, чтоб работать на 480 МГц, надо должным образом подавать питание на МК, из-за чего на СТМовской плате (DISCO которая) требовалось перепаять пару перемычек.
  2. А ещё лучше -- разобраться, как это делается в реальном железе, на логических элементах, триггерах и прочая. Если подходить к HDL как к языку программирования, хорошего результата не будет (даже если что-то и будет работать).
  3. STM32H7, SPI, прием с DMA

    А ещё при использовании DMA возможны проблемы из-за того, что у Cortex-M7 есть кэш -- соответственно, перед запуском передачи по DMA надо убедиться, что данные физически лежат в памяти (а не только в кэше), ну а после завершения приёма -- очистить кэш, чтоб добраться до данных в памяти.
  4. Пакеты в keil

    Или собственно ARMовский пакет, где только ядра и указаны. Но обычно лучше пакет под свой МК -- хотя б из-за возможности простого просмотра регистров периферии в процессе отладки.
  5. Ну, судя по вопросу, нужно указать компилятору, в каких секциях что размещать -- он и сгенерит соответствующий код и управляющую информацию. Затем можно, например, все объектники собрать компоновщиком в один объектник (кейловский компоновщик такое умеет -- если память не изменяет, partial linking это обзывается), который скармливать при сборке полного приложения у заказчика. Как секции указывать, зависит от компилятора, так как стандарт это не регламентирует. В ARM Clang кейловском можно, в GCC можно (насколько помню), в мелкомягком компиляторе можно -- так что и в ИАРовском наверняка сие поддерживается.
  6. Ошибка в ArmClang?

    А почему тогда в delete не выбрасывает? Действия-то принципиально одинаковые выполняются...
  7. Ошибка в ArmClang?

    Проверил union. Не работает. Заодно проверил, достаточно ли объявить как volatile только First, но не Last. Тоже недостаточно: ER_IROM1:0000202A STRH R7, [R0,#8] ER_IROM1:0000202C STR R5, [R0,#0xC] ER_IROM1:0000202E STRB R2, [R0,#0x10] ER_IROM1:00002030 STRD.W R2, R6, [R0] ER_IROM1:00002034 LDR R1, [R4,#4] ER_IROM1:00002036 LDR R3, [R4,#8] ER_IROM1:00002038 CMP R1, R0 ER_IROM1:0000203A STR R0, [R3] ER_IROM1:0000203C ADD.W R3, R8, #1 ER_IROM1:00002040 STR R0, [R4,#8] ER_IROM1:00002042 STRB.W R3, [R4,#0x40] ER_IROM1:00002046 BNE loc_20A2 Загрузка First и Last выполняется двумя отдельными командами (2034 и 2036), однако выборка First опять произошла до записи по Last. Фактически -- да. First всегда указывает на первый элемент очереди (FIFO_LNK) или содержит нуль, если очередь пуста. А вот Last указывает либо на последний элемент очереди (FIFO_LNK), либо на поле First самого заголовка (или, если угодно, на сам заголовок -- FIFO_HDR). Эм... Почему? Выборка из Last идёт по адресу 2080 (самая первая LDR), запись по Last -- в 208E, а выборка First -- в 2090. В 2092 идёт запись в Last. Похоже на то. В общем, не глюк компилятора, а оптимизация. Правда, остаётся непонятным, почему именно он выкидывал кусок кода в моём самом первом сообщении этой темы (в операции new): вроде б не должен столь своевольно обращаться с кодом, тем более, что в delete он уже не умничал.
  8. Ошибка в ArmClang?

    Эта опция в данном случае помогла. С ней такой код нагенерило: ER_IROM1:00002080 LDR R2, [R4,#8] ER_IROM1:00002082 MOVS R1, #0 ER_IROM1:00002084 STRH R7, [R0,#8] ER_IROM1:00002086 STR R6, [R0,#0xC] ER_IROM1:00002088 STRB R1, [R0,#0x10] ER_IROM1:0000208A STR R1, [R0] ER_IROM1:0000208C STR R5, [R0,#4] ER_IROM1:0000208E STR R0, [R2] ER_IROM1:00002090 LDR R2, [R4,#4] ER_IROM1:00002092 STR R0, [R4,#8] ER_IROM1:00002094 CMP R2, R0 Первая LDR -- это загрузка указателя Last, а последняя LDR -- это загрузка First; запись по адресу в Last, как видим, происходит непосредственно перед загрузкой First, поэтому всё будет корректно. Ну а без этой опции код такой: ER_IROM1:00002006 LDRD.W R3, R1, [R4,#4] ER_IROM1:0000200A MOVS R2, #0 ER_IROM1:0000200C STRB R2, [R0,#0x10] ER_IROM1:0000200E STRD.W R2, R8, [R0] ER_IROM1:00002012 STR R0, [R1] ER_IROM1:00002014 ADDS R1, R6, #1 ER_IROM1:00002016 CMP R3, R0 ER_IROM1:00002018 STRH R5, [R0,#8] ER_IROM1:0000201A STR R7, [R0,#0xC] ER_IROM1:0000201C STR R0, [R4,#8] ER_IROM1:0000201E STRB.W R1, [R4,#0x40] ER_IROM1:00002022 BNE loc_207C Переупорядочило, как видим, куда агрессивней -- и некорректно для этого случая. Ну а с volatile (и без опции) код такой: ER_IROM1:00002022 MOVS R2, #0 ER_IROM1:00002024 STR R7, [R0,#4] ER_IROM1:00002026 STRH R6, [R0,#8] ER_IROM1:00002028 STR.W R8, [R0,#0xC] ER_IROM1:0000202C STRB R2, [R0,#0x10] ER_IROM1:0000202E STR R2, [R0] ER_IROM1:00002030 LDR R1, [R4,#8] ER_IROM1:00002032 STR R0, [R1] ER_IROM1:00002034 ADDS R1, R5, #1 ER_IROM1:00002036 STR R0, [R4,#8] ER_IROM1:00002038 STRB.W R1, [R4,#0x40] ER_IROM1:0000203C LDR R1, [R4,#4] ER_IROM1:0000203E CMP R1, R0 ER_IROM1:00002040 BNE loc_209C А вот эта статейка навела меня на мысль, как сие исправить и без -fno-strict-aliasing, и без volatile: использовать объединение для поля First (одно поле -- указатель на сам заголовок, другое -- на первый элемент очереди). На досуге проверю.
  9. Ошибка в ArmClang?

    О, спасибо. Похоже, то, что нужно. Жаль, конечно, что это не стандартное средство языка, а расширение компилятора, но жрём, что дают 🙂 ADD. Правда, ссылка -- не для ARM Clang, а для старого компилятора 5-й версии, но в ARM Clang тоже есть. ADD2. Увы, не помогло. Похоже, эти вещи срабатывают лишь для операций, которые, с точки зрения компилятора, имеют побочные эффекты, и не препятствуют ему производить предзагрузку из ячейки, явного обращения на запись к которой нет. Так что только volatile.
  10. Ошибка в ArmClang?

    Он чисто сишный, вроде как, а в це++ не поддерживается. А в данном случае она inline -- для эффективности.
  11. Ошибка в ArmClang?

    Да решил я уже проблему, решил. И не жалуюсь я, а просто констатирую, что без костылей и/или потери эффективности в современной версии языка, похоже, не обойтись.
  12. Ошибка в ArmClang?

    Ну, во-первых, он не решает данную проблему, как понимаете. А во-вторых, он специфичен для конкретного компилятора, что не шибко хорошо. Ну, в моём представлении, барьер памяти влияет на работу процессора, а не компилятора (применительно к ARM -- команды DMB, DSB, ISB). А мне нужно именно на компилятор повлиять, чтоб не переносил код, куда ему вздумается. Или речь о чём-то другом?
  13. Ошибка в ArmClang?

    Стандартный? Или конкретного компилятора? В числе стандартных я не находил. Ну, выше я указывал проблему с моей функцией Append, добавляющей новый элемент в хвост очереди: inline void FIFO_HDR::Append(FIFO_LNK *Entry) { Entry->Next = nullptr; Last->Next = Entry; Last = Entry; } Когда очередь пуста, поле First заголовка очереди содержит нуль, а поле Last -- адрес поля First. Поле Next всегда является самым первым полем элемента очереди, поэтому такой "трюк" благополучно работает. Собственно, это очень распространённый способ организации очереди, который я встречал миллион раз (в частности, в Винде, но далеко не только в ней). Проблема возникла из-за того, что компилятор не способен увидеть, что вызов Append может поменять поле First заголовка очереди (что происходит, когда перед вызовом очередь пуста), он видит изменение только Last. В моём случае он выполнил предвыборку полей First и Last одной командой LDRD, затем сгенерировал вызов Append, а потом воспользовался предвыбранным, а не обновлённым значением поля First -- что дало неверный результат. Если бы была возможность атрибутировать эту функцию как имеющую побочные эффекты, запрещающие перемещение кода мимо неё, проблема бы не возникала. Конечно, это в какой-то мере ограничило бы оптимизатор, но не слишком сильно, думается. Запросто. Це++ необъятен.
  14. Ошибка в ArmClang?

    А ещё это -- загромождение текста лишними объявлениями. Мне не нравится то, что, кроме volatile, нет других атрибутов для переменных, которые могли бы указать, в частности, что данную переменную нельзя выкинуть из программы по желанию компилятора. Если бы был такой атрибут, его пришлось бы указать ровно один раз -- в объявлении самой переменной. Нет и атрибутов для функций, чтобы можно было, скажем, указать, что функция может вызывать побочные эффекты, поэтому нельзя перемещать код до и после вызова этой функции. Ну и т.д. и т.п. Да, бывают случаи, когда действительно не обойтись. Однако мне не нравится, что нужно постоянно применять костыли просто из-за того, что в языке отсутствуют средства, которые позволили бы объяснить компилятору, что можно делать, а что нельзя. Как человек выше указал, существуют же барьеры памяти -- так почему нельзя указать, что некая функция является барьером для оптимизации?
  15. Ошибка в ArmClang?

    Это уже костыль. Прямым решением был бы атрибут, объясняющий компилятору правила обращения с переменной.
×
×
  • Создать...