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

_Desh_

Участник
  • Постов

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

  • Посещение

Сообщения, опубликованные _Desh_


  1. Методом проб и ошибок выяснил, что перезаписать данные по некоторому адресу можно, сначала исключив этот адрес:

    srec_cat.exe test_file_source.bin -binary -exclude 0x1C 0x20 -length-l-e 0x1C -o test_file.bin -binary

    Теперь по адресу 0x1C корректно записывается длина файла.

    Но теперь проблема записать по адресу 0x20 значение CRC. Если исключить диапазон 0x20-0x24, то в расчете CRC он не участвует, выдается предупреждение о том, что в данных есть прореха. В принципе, при сверке CRC программно внутри контроллера можно это учесть, но получается как-то некрасиво.

     

    Есть ли более элегантный способ прописать CRC в нужный адрес?

  2. 6 hours ago, jcxz said:

    Писать CRC не в конец, а внутрь прошивки.

    Вопрос немного не об этом, но допустим.

    При попытке писать длину прошивки и CRC вместо неиспользуемых (несуществующих) векторов по заранее известному фиксированному адресу:

    srec_cat.exe test_file_source.bin -binary -length-l-e 0x1C -crc32-b-e 0x20 -o test_file.bin -binary

    srec_cat.exe выводит следующее сообщение об ошибке:

    srec_cat: test_file_source.bin: 0x0400: multiple 0x0000001C values (previous = 0x0C, this one = 0x00)

    Что это означает и как это исправить? Из документации ни черта не понятно, там есть почти такой же пример, и видимо он должен работать.

     

    P.S. Что означает ошибка примерно понял. Он мне хочет сказать, что я хочу какое-то ненулевое значение перезаписать новым значением (нулевым). Ну и что? Мне это и надо.

  3. Прошерстил форум и Интернет на предмет использования утилиты srec_cat.exe, но остались вопросы и непонятки.

    Мне надо добавить в конец прошивки ее CRC, с этим я справился:

    srec_cat.exe test_file_source.bin -binary -crc32-l-e -maximum-address test_file_source.bin -binary -o test_file.bin -binary

    Также хотелось бы перед формированием конечного файла прошивки увидеть в выводе IDE полученную CRC (или даже записать ее в отдельный файл). Это тоже можно сделать, например, так:

    srec_cat.exe test_file_source.bin -binary -fill 0xFF 0 0x400 -crop 0 0x400 -crc32-b-e 0x400 -crop 0x400 0x404 -o - -hex-dump

    Но как быть, если размер прошивки заранее неизвестен? Чтобы встроить вызов утилиты в IDE и полностью автоматизировать процесс, не вводя ручками каждый раз разные адреса.

    Во втором случае, если использовать, например,

    -crop -maximum-address test_file_source.bin -binary -maximum-address test_file_source.bin -binary -offset 4

    вместо

    -crop 0x400 0x404

    В консоль выводится полный дамп прошивки, а не 4 последние байта, как мне надо.

    Есть ли способ для утилиты srec_cat.exe указывать в качестве параметров, например, реальную длину файла, а не забивать магические константы?

  4. 31 minutes ago, Arlleex said:

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

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

    31 minutes ago, Arlleex said:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  6. 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

     

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

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

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

  8. 2 minutes ago, Arlleex said:

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

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

  9. 19 minutes ago, MasterElectric said:

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

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

     

    8 minutes ago, amaora said:

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

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

  10. 9 minutes ago, jcxz said:

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

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

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

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

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

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

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

  12. 2 hours ago, haker_fox said:

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

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

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

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

  13. Нагуглил и сделал следующее (пусть это наверное всем кроме меня известный баян, напишу хотя бы для упорядочивания в своей голове).

    Объявил новую секцию 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)
    {
      ...
    }

    Теперь обработчик работает корректно. Обычная функция тоже.

    Извините за простыню. Всем спасибо за подсказки.

  14. Поведение остается прежним и при пустом обработчике.

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

    lr = 0xfffffff9

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

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

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

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

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

  15. 14 minutes ago, Forger said:

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

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

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

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

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

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

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

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

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

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

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

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

     

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

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

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

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

     

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

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

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

     

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

     

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

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

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

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

     

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

×
×
  • Создать...