Jump to content

    

_Desh_

Участник
  • Content Count

    54
  • Joined

  • Last visited

Everything posted by _Desh_


  1. Если она обратится к библиотечным функциям, у которых исходные коды недоступны, у меня будут проблемы. Но наверняка они тоже решаемы, просто я пока не знаю как (оно мне сейчас не надо). Последний раз я пользовался Keil 4 с ARMCC и там можно было прямо в свойствах исходника мышкой указать размещение в конкретной области памяти. Либо так же с помощью атрибута, аналогичного GCC, если для отдельной функции или переменной. Но там еще можно было явно адрес указывать, например, __attribute__((at(0x20002000))). А в GCC так нельзя, только через линкер и секции.
  2. Знает. Я даже могу обратиться к переменным, указанным в скрипте линкера, в исходном коде, собственно, я это и делаю, когда копирую код функции - именно из скрипта я беру начальный и конечный адреса нужного участка кода. Нет, не допустимо. Я даже цитату из документации по компилятору для этого привел - он разместит мой код там, где ему указывает атрибут. Не останется, если я точно так же скопирую весь код и переменные, к которым идет обращение, туда же, при необходимости. Это неудобно, не спорю. В документации на линкер написано, что можно даже целиком объектный файл указывать для размещения в данной секции, но с этим я пока не разобрался. Копирование специально сделано перед вызовом функций, которые работают с периферией, как мне и посоветовали здесь. Я включил оптимизацию Os, затем O2, обычная функция и функция-обработчик прерывания работают из ОЗУ, поведение программы соответствует ожидаемому. Я не использую IAR, используемую среду разработки я указал в первом же посте первой же строкой.
  3. https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes __attribute__((section(".RAMFUNC"))) void systick_config(void) { ... } Размещение секции указано здесь: RAMFUNC (rx) : ORIGIN = 0x20000000, LENGTH = 8K и здесь: .ramfunc : { ... *(.RAMFUNC.ISR) *(.RAMFUNC) *(.RAMFUNC*) ... } >RAMFUNC AT> FLASH
  4. Из атрибута, в котором указано, в какой области памяти находится код функции.
  5. Я обязательно разберусь. Просто я на STM32F4 с Миландровского 1986ВЕ1Т пересел. Там обязательно было код записи/стирания флэш-памяти в ОЗУ размещать. Перемещаемой таблицы там не было, потому что Cortex-M0/M1, это я уже сам затеял. Опыта у меня с STM32 мало.
  6. Нет, только страницу с основной программой. Я так и понял, что именно программист должен это гарантировать, вручную разместив все данные и функции, к которым будут обращения, в нужной области памяти.
  7. Я указал секцию, где будет размещена функция, при помощи линкера. В исходнике функции указал, что она размещается именно в этой секции. Затем самостоятельно скопировал код этой функции по соответствующему адресу RAM в стартапе. Что еще я должен сделать, чтобы эта функция разместилась там, где мне нужно?
  8. Верно, сейчас попробовал сделать как посоветовал АНТОХА, и все получилось. Просто вчера я свой вариант успел сделать и протестировать раньше, чем увидел его пост. Спасибо, что обратили мое внимание на это.
  9. Предполагаю стирать/писать флэш-память без запрета прерываний. Раньше я загрузку прошивки на лету ни разу не делал, опыта у меня мало. Сейчас я увидел неудобства, связанные с этим (начинал с Кейла, там гораздо проще делается размещение функций в ОЗУ), возможно в конце концов обойдусь простым запретом прерываний на время стирания/записи. Ну и сами-то функции стирания/записи по-любому придется в ОЗУ размещать. Так что осваивать все равно пришлось бы, пусть и не на примере обработчика.
  10. Нагуглил и сделал следующее (пусть это наверное всем кроме меня известный баян, напишу хотя бы для упорядочивания в своей голове). Объявил новую секцию RAMFUNC для размещения кода нужных мне функций в скрипте линкера. Пока выбрал 8 Кб, отрезав столько же от остальной RAM. MEMORY { CCMRAM (xrw) : ORIGIN = 0x10000000, LENGTH = 64K RAMFUNC (rx) : ORIGIN = 0x20000000, LENGTH = 8K RAM (xrw) : ORIGIN = 0x20002000, LENGTH = 120K FLASH (rx) : ORIGIN = 0x08020000, LENGTH = 128K } Описание секции между секциями .data и .bss: _siramfunc = LOADADDR(.ramfunc); .ramfunc : { . = ALIGN(4); _sramfunc = .; /* для копирования кода в startup-файле */ *(.RAMFUNC.ISR) *(.RAMFUNC) *(.RAMFUNC*) . = ALIGN(4); _eramfunc = .; /* для копирования кода в startup-файле */ } >RAMFUNC AT> FLASH В startup-файле вписал объявленные ранее переменные и добавил копирование кода по аналогии с уже имеющимся копированием данных .data и .bss. Как уже указывал уважаемый Forger, копировать код функций надо до вызова основной программы: .word _siramfunc .word _sramfunc .word _eramfunc ... CopyCodeRamFunc: ldr r3, =_siramfunc ldr r3, [r3, r1] str r3, [r0, r1] adds r1, r1, #4 LoopCopyCodeRamFunc: ldr r0, =_sramfunc ldr r3, =_eramfunc adds r2, r0, r1 cmp r2, r3 bcc CopyCodeRamFunc bl SystemInit bl main ... После этого осталось только объявить соответствующий атрибут для нужных мне функций. Для целей тестирования я сделал для одной обычной функции (инициализация Systick) и одного обработчика прерывания (того же Systick): __attribute__((section(".RAMFUNC"))) void systick_config(void) { ... } __attribute__((interrupt)) __attribute__((section(".RAMFUNC.ISR"))) void systick_handler_ram(void) { ... } Теперь обработчик работает корректно. Обычная функция тоже. Извините за простыню. Всем спасибо за подсказки.
  11. Подскажите пожалуйста хотя бы название. Что за мануал - на МК, на среду разработки, на сам GCC?
  12. Поведение остается прежним и при пустом обработчике. sp = 0x1000ffd0 (я разместил стек в области CCMRAM) lr = 0xfffffff9 Также наблюдал такую картину: содержимое окна дизассемблера кардинально различается в двух вариантах программы - с обработчиком во FLASH и с обработчиком в RAM. Для пустого обработчика во FLASH всего лишь: 080202ec: push {r7} 080202ee: add r7, sp, #0 А вот для обработчика в RAM полная белиберда, ничего похожего, просто непонятный набор инструкций. Как будто никакого копирования кода функции в ОЗУ не произошло. Разве для этого недостаточно просто указать рядом с объявлением/определением функции соответствующий атрибут?
  13. Попробовал перенести весь код в main с запретом прерываний на время инициализации - не помогло. Спасибо, но дело похоже не в этом. Первый-то раз в обработчик программа заходит как положено. Сбой при выходе из него. Порядок вызова в startup-файле - System_Init->__libc_init_array->main. Копирование всего, кроме таблицы, происходит до вызова System_Init. Для успокоения совести убирал вызов __libc_init_array - результат прежний.
  14. Разрабатываю в STM32CubeIDE. Контроллер STM32F407V. Так я копирую таблицу векторов в ОЗУ: #define VECTOR_EXCEPTION_NUM (16) /* Ссылка на таблицу векторов, размещенную в памяти Flash. Взята из файла * startup.s */ extern uint32_t g_pfnVectors[]; /* Массив для хранения адресов обработчиков прерываний, размещенных в RAM. */ static uint32_t vector_table_ram[94] __attribute__((section(".RAM"))) __attribute__((aligned(512))); void SystemInit(void) { uint32_t i = 0; /* Копируем таблицу векторов. */ for (i = 0; i < 94; i++) { vector_table_ram[i] = g_pfnVectors[i]; } /* Регистрация нового обработчика. */ vector_table_ram[VECTOR_EXCEPTION_NUM + SysTick_IRQn] = (uint32_t)&systick_handler_ram; /* VTOR. */ SCB->VTOR = (uint32_t)vector_table_ram; } Правильность копирования проверял в отладчике. Сама таблица разместилась по адресу 0x20000600, содержимое регистра VTOR соответствует. Обработчик прерывания, который я хочу разместить в ОЗУ: void systick_handler_ram(void) __attribute__((section(".RAM"))); void systick_handler_ram(void) { systick_inc_tick_1ms(); systick_flag = 1; } Обработчик успешно размещается по адресу 0х20000200, в новую таблицу векторов это значение вносится. Программа один раз заходит в обработчик, прошагивает инструкции до конца, а при выходе из него вылетает в HardFault. Если убрать из объявления systick_handler_ram атрибут размещения в секции RAM, обработчик размещается во FLASH, и прерывание работает - по прерыванию я завел счетчик и моргалку. Пробовал добавлять __attribute__((interrupt)) или __attribute__((interrupt("IRQ"))) - программа перестала даже заходить в обработчик - сразу в HardFault. Подскажите, пожалуйста, что я делаю не так? P.S. Пробовал делать так: vector_table_ram[VECTOR_EXCEPTION_NUM + SysTick_IRQn] = ((uint32_t)&systick_handler_ram) | 1UL; Ничего не меняется, компилятор добавляет единицу в младший разряд самостоятельно.
  15. Серия, поставщик подтвердил официально, периодика. На ближайшее будущее вопрос решен, продавили военных.
  16. Тогда, если я правильно понимаю, изделие верхнего уровня должно пройти испытания на свои ВВФ, на которых необходимо подтвердить эти требования. В этом случае, если испытания прошли успешно, к составной части вообще вопросов быть не должно.
  17. Нет, если микросхемы являются изделиями межотраслевого применения (входят в перечень МОП/ЭКБ). Импортные микросхемы таковыми не являются, хотя существуют некоторые типы ЭКБ ИП, которые имеют соответствующие утвержденные методики сертификационных испытаний, проводимые в специальных аттестованных испытательных организациях, и имеют даже какое-то подобие ТУ. Видел лично такие ТУ на некоторые ПЛИС Xilinx, например. Вообще, я не понял, как изделие, прошедшее испытания на свои ВВФ может без дополнительного подтверждения применяться в вышестоящем изделии с более жесткими ВВФ? Кто это пропустил?
  18. У меня претензий к реальной надежности нет (кроме того, что предприятия-изготовители ЭКБ порой умудряются гнать брак с приемкой ВП, а иногда даже и ОС/ОСМ). Претензии к стандартам. Сейчас начальство решает, надо ли писать в 22ЦНИИ (или как он там сейчас называется), видимо не хотят подставляться, я попробую все-таки продавить и написать.
  19. Отказ электромагнитного реле. Произошел на механике, которая по программе испытаний шла после климатики. Климатику изделие выдержало. Отказы ПКИ иногда бывали и раньше, на других этапах. Просто до чтения ТУ вояками дошло впервые. В данном конкретном случае (на мой взгляд) надо победить в первую очередь нормативы. Я прекрасно понимаю, что теоретически причиной может быть все, что угодно, например, снижение надежности электрического контакта обмотки реле на минусе и последующее окончательное разрушение на механике, но на моей практике ни один элемент на минус 65 не умирал. Умирали одиночные контакты в соединителях, умирала некачественная пайка, умирала некачественная металлизация переходных отверстий. Даже обычные буржуйские микросхемы в пластике работали и не жужжали (бывало, ставили эксперименты). Согласен, что в принципе это ничего не гарантирует. Просто хотел познакомиться с опытом других людей, которые делают аппаратуру на честные минус 65 - как они обосновывают применение ЭРИ или какие конструктивные решения им приходится использовать (и приходится ли). Лично на мой взгляд (не претендую на истину), в нормативах имеется конкретное неустранимое противоречие - если мой прибор должен в выключенном состоянии выдерживать минус 65, почему подавляющее большинство отечественных ЭРИ категории качества ВП по своим нормативам должны обеспечивать только минус 60? Как я буду обеспечивать термостатирование средствами самого прибора, если он выключен и выдерживается в течение нескольких суток, например?
  20. Предельная температура при более вдумчивом чтении документации обнаружилась в ОТУ. Она совпадает с рабочей пониженной и, в соответствии с этими же ОТУ, при совпадении температур испытания допускается проводить только на рабочую. Так-то буржуи тоже на industrial в пластиковых корпусах дают температуру хранения минус 55 или даже минус 65 при рабочей минус 40.
  21. Да. Иногда наши заказчики пишут в ТТЗ "температура хранения и транспортирования". По ГОСТ РВ 20.57.306 предельная - это фактически температура, при которой изделие находится в выключенном состоянии. Производитель разрешает применить ЭРИ в данном режиме и вместе со своей приемкой сообщил нам об этом официальным письмом. Только нашей приемке это побоку.
  22. Тут я должен извиниться и поправить вводную. Рабочая на компонент равна предельной на компонент и равна минус 60. Рабочая на прибор равна минус 50. Предельная на прибор равна минус 65. Не проходит по цифрам на предельной.
  23. Осталось только изобрести такой элемент питания, который проработает 100 лет, чтобы в нужный момент прибор проснулся, и дело в шляпе.