Jump to content

    

_Desh_

Участник
  • Content Count

    54
  • Joined

  • Last visited

Community Reputation

0 Обычный

About _Desh_

  • Rank
    Участник
  • Birthday 07/19/1988

Контакты

  • Сайт
    Array
  • ICQ
    Array
  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; Ничего не меняется, компилятор добавляет единицу в младший разряд самостоятельно.