Jump to content

    

_Desh_

Участник
  • Content Count

    54
  • Joined

  • Last visited

Posts posted by _Desh_


  1. 31 minutes ago, Arlleex said:

    А она может явными и неявными зависимостями обратиться за пределы этого куска ОЗУ.

    Если она обратится к библиотечным функциям, у которых исходные коды недоступны, у меня будут проблемы. Но наверняка они тоже решаемы, просто я пока не знаю как (оно мне сейчас не надо).

    31 minutes ago, Arlleex said:

    На Keil с ARM CLang v6 я, почему-то, ключевого слова наподобие __ramfunc не встретил

    Последний раз я пользовался Keil 4 с ARMCC и там можно было прямо в свойствах исходника мышкой указать размещение в конкретной области памяти. Либо так же с помощью атрибута, аналогичного GCC, если для отдельной функции или переменной. Но там еще можно было явно адрес указывать, например, __attribute__((at(0x20002000))). А в GCC так нельзя, только через линкер и секции.

  2.  38 минут назад, jcxz сказал:

    про который компилятор ничего не знает.

    Знает. Я даже могу обратиться к переменным, указанным в скрипте линкера, в исходном коде, собственно, я это и делаю, когда копирую код функции - именно из скрипта я беру начальный и конечный адреса нужного участка кода.

    42 минуты назад, jcxz сказал:

    А значит вполне допустимо часть кода (или данных) вынести за пределы этой секции. Так как нет никаких указаний от вас, что этого делать нельзя.

    Нет, не допустимо. Я даже цитату из документации по компилятору для этого привел - он разместит мой код там, где ему указывает атрибут.

    43 минуты назад, jcxz сказал:

    А значит - код секции вы скопируете в ОЗУ, а то что изнутри этого кода идут обращения во флешь - так и останется во флешь.

    Не останется, если я точно так же скопирую весь код и переменные, к которым идет обращение, туда же, при необходимости. Это неудобно, не спорю. В документации на линкер написано, что можно даже целиком объектный файл указывать для размещения в данной секции, но с этим я пока не разобрался.

    45 минут назад, jcxz сказал:

    если изнутри другого (флешевого) кода, будут обращения в область .RAMFUNC когда вы ещё не скопировали туда код

    Копирование специально сделано перед вызовом функций, которые работают с периферией, как мне и посоветовали здесь.

    57 минут назад, jcxz сказал:

    Есть конечно ещё 3-й путь, колхозный: Выключить полностью оптимизацию

    Я включил оптимизацию Os, затем O2, обычная функция и функция-обработчик прерывания работают из ОЗУ, поведение программы соответствует ожидаемому.

    Я не использую IAR, используемую среду разработки я указал в первом же посте первой же строкой.

  3. 1 hour ago, jcxz said:

    Никакого атрибута, который бы указывал "в какой области памяти находится код функции", там нет.

    https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#Common-Function-Attributes

    Quote

    Normally, the compiler places the code it generates in the text section. Sometimes, however, you need additional sections, or you need certain particular functions to appear in special sections. The section attribute specifies that a function lives in a particular section. For example, the declaration:

    
    extern void foobar (void) __attribute__ ((section ("bar")));

    puts the function foobar in the bar section.

    __attribute__((section(".RAMFUNC")))
    void
    systick_config(void)
    {
      ...
    }

    Размещение секции указано здесь:

    RAMFUNC (rx)  : ORIGIN = 0x20000000, LENGTH = 8K

    и здесь:

    .ramfunc :
    {
      ...
      *(.RAMFUNC.ISR)
      *(.RAMFUNC)
      *(.RAMFUNC*)
      ...
    } >RAMFUNC AT> FLASH

     

  4. On 9/1/2020 at 2:04 PM, jcxz said:

    И откуда тогда компилятор узнает, что функция будет выполняться из ОЗУ?

    Из атрибута, в котором указано, в какой области памяти находится код функции.

  5. 2 minutes ago, Arlleex said:

    но не в STM32, вроде бы

    Я обязательно разберусь. Просто я на STM32F4 с Миландровского 1986ВЕ1Т пересел. Там обязательно было код записи/стирания флэш-памяти в ОЗУ размещать. Перемещаемой таблицы там не было, потому что Cortex-M0/M1, это я уже сам затеял. Опыта у меня с STM32 мало.

  6. 19 minutes ago, MasterElectric said:

    Вы собираетесь что затирать весь флешь и бутлоадер тоже?

    Нет, только страницу с основной программой.

     

    8 minutes ago, amaora said:

    Но в любом случае компилятор не сможет гарантировать отсутсвие обращений к flash.

    Я так и понял, что именно программист должен это гарантировать, вручную разместив все данные и функции, к которым будут обращения, в нужной области памяти.

  7. 9 minutes ago, jcxz said:

    Вижу атрибут размещения кода функции в конкретной секции (section(".RAMFUNC")), но не вижу задания этому коду спец.атрибута "функция в ОЗУ".

    Я указал секцию, где будет размещена функция, при помощи линкера. В исходнике функции указал, что она размещается именно в этой секции. Затем самостоятельно скопировал код этой функции по соответствующему адресу RAM в стартапе. Что еще я должен сделать, чтобы эта функция разместилась там, где мне нужно?

  8. 30 minutes ago, Сергей Борщ said:

    AHTOXA давал вам более простой совет:

    Верно, сейчас попробовал сделать как посоветовал АНТОХА, и все получилось.

    Просто вчера я свой вариант успел сделать и протестировать раньше, чем увидел его пост.

    Спасибо, что обратили мое внимание на это.

  9. 2 hours ago, haker_fox said:

    А для чего вы размещаете сам обработчик в ОЗУ? Пока не могу придумать, зачем это нужно) Мне хватает разместить в ОЗУ только таблицу.

    Предполагаю стирать/писать флэш-память без запрета прерываний. Раньше я загрузку прошивки на лету ни разу не делал, опыта у меня мало.

    Сейчас я увидел неудобства, связанные с этим (начинал с Кейла, там гораздо проще делается размещение функций в ОЗУ), возможно в конце концов обойдусь простым запретом прерываний на время стирания/записи.

    Ну и сами-то функции стирания/записи по-любому придется в ОЗУ размещать. Так что осваивать все равно пришлось бы, пусть и не на примере обработчика.

  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. Поведение остается прежним и при пустом обработчике.

    sp = 0x1000ffd0 (я разместил стек в области CCMRAM)

    lr = 0xfffffff9

    Также наблюдал такую картину: содержимое окна дизассемблера кардинально различается в двух вариантах программы - с обработчиком во FLASH и с обработчиком в RAM.

    Для пустого обработчика во FLASH всего лишь:

    080202ec:   push    {r7}
    080202ee:   add     r7, sp, #0

    А вот для обработчика в RAM полная белиберда, ничего похожего, просто непонятный набор инструкций.

    Как будто никакого копирования кода функции в ОЗУ не произошло. Разве для этого недостаточно просто указать рядом с объявлением/определением функции соответствующий атрибут?

  12. 14 minutes ago, Forger said:

    Скорее всего в вашем случае сначала вызывается system_init, а уже потом копируются сами обработчики прерываний из flash в озу

    Попробовал перенести весь код в main с запретом прерываний на время инициализации - не помогло.

    Спасибо, но дело похоже не в этом.

    Первый-то раз в обработчик программа заходит как положено. Сбой при выходе из него.

    Порядок вызова в startup-файле -  System_Init->__libc_init_array->main. Копирование всего, кроме таблицы, происходит до вызова System_Init.

    Для успокоения совести убирал вызов __libc_init_array - результат прежний.

  13. Разрабатываю в 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;

    Ничего не меняется, компилятор добавляет единицу в младший разряд самостоятельно.

  14. А если изделие более верхнего уровня обеспечивает защиту?

    Тогда, если я правильно понимаю, изделие верхнего уровня должно пройти испытания на свои ВВФ, на которых необходимо подтвердить эти требования. В этом случае, если испытания прошли успешно, к составной части вообще вопросов быть не должно.

  15. Если, например, предприятие выпускает какие-нибудь микросхемы, которые выдерживают 15 g, а кто-то применит их на 150 g, то ВП должен остановить приёмку микросхем?

    Нет, если микросхемы являются изделиями межотраслевого применения (входят в перечень МОП/ЭКБ). Импортные микросхемы таковыми не являются, хотя существуют некоторые типы ЭКБ ИП, которые имеют соответствующие утвержденные методики сертификационных испытаний, проводимые в специальных аттестованных испытательных организациях, и имеют даже какое-то подобие ТУ. Видел лично такие ТУ на некоторые ПЛИС Xilinx, например.

     

    Вообще, я не понял, как изделие, прошедшее испытания на свои ВВФ может без дополнительного подтверждения применяться в вышестоящем изделии с более жесткими ВВФ? Кто это пропустил?

  16. добрый вечер,

    мне кажется что Вы все же пытаетесь каким-то образом "связать" нормативы и надежность изделия....

    У меня претензий к реальной надежности нет (кроме того, что предприятия-изготовители ЭКБ порой умудряются гнать брак с приемкой ВП, а иногда даже и ОС/ОСМ). Претензии к стандартам.

     

    Сейчас начальство решает, надо ли писать в 22ЦНИИ (или как он там сейчас называется), видимо не хотят подставляться, я попробую все-таки продавить и написать.

  17. м.б. я чего-то не понимаю....

    Отказ электромагнитного реле. Произошел на механике, которая по программе испытаний шла после климатики. Климатику изделие выдержало. Отказы ПКИ иногда бывали и раньше, на других этапах. Просто до чтения ТУ вояками дошло впервые. В данном конкретном случае (на мой взгляд) надо победить в первую очередь нормативы.

     

    Я прекрасно понимаю, что теоретически причиной может быть все, что угодно, например, снижение надежности электрического контакта обмотки реле на минусе и последующее окончательное разрушение на механике, но на моей практике ни один элемент на минус 65 не умирал. Умирали одиночные контакты в соединителях, умирала некачественная пайка, умирала некачественная металлизация переходных отверстий. Даже обычные буржуйские микросхемы в пластике работали и не жужжали (бывало, ставили эксперименты). Согласен, что в принципе это ничего не гарантирует.

     

    Просто хотел познакомиться с опытом других людей, которые делают аппаратуру на честные минус 65 - как они обосновывают применение ЭРИ или какие конструктивные решения им приходится использовать (и приходится ли). Лично на мой взгляд (не претендую на истину), в нормативах имеется конкретное неустранимое противоречие - если мой прибор должен в выключенном состоянии выдерживать минус 65, почему подавляющее большинство отечественных ЭРИ категории качества ВП по своим нормативам должны обеспечивать только минус 60? Как я буду обеспечивать термостатирование средствами самого прибора, если он выключен и выдерживается в течение нескольких суток, например?

  18. А вам завод изготовитель официально дал ответ что -60 предельная температура?

    Странно что у ширпотреба от интеграла температурах хранения -65. А у спец я не помню что бы упоминалось

    Предельная температура при более вдумчивом чтении документации обнаружилась в ОТУ. Она совпадает с рабочей пониженной и, в соответствии с этими же ОТУ, при совпадении температур испытания допускается проводить только на рабочую.

     

    Так-то буржуи тоже на industrial в пластиковых корпусах дают температуру хранения минус 55 или даже минус 65 при рабочей минус 40.

  19. Предельная это температура хранения?

    Да. Иногда наши заказчики пишут в ТТЗ "температура хранения и транспортирования". По ГОСТ РВ 20.57.306 предельная - это фактически температура, при которой изделие находится в выключенном состоянии.

     

    3. Возможно провести испытания и двухсторонним актом с производителем и их и Вашей приемками согласовать использование в данном режиме (если производитель пойдет на это, конечно).

    Производитель разрешает применить ЭРИ в данном режиме и вместе со своей приемкой сообщил нам об этом официальным письмом. Только нашей приемке это побоку.

     

  20. Рабочая -50, предельная -65.

    У вас по оту рабочая -60 и по длкументам на компоненты тоже. А в чем нестыковка?

     

    Тут я должен извиниться и поправить вводную. Рабочая на компонент равна предельной на компонент и равна минус 60.

    Рабочая на прибор равна минус 50. Предельная на прибор равна минус 65. Не проходит по цифрам на предельной.

     

     

  21. Можно раз в 100 лет просыпаться, и перезаписывать инфу в резервную микросхему + ECC.

    Осталось только изобрести такой элемент питания, который проработает 100 лет, чтобы в нужный момент прибор проснулся, и дело в шляпе.