Gradient 1 19 марта, 2018 Опубликовано 19 марта, 2018 · Жалоба Подскажите если есть идеи, где мог сделать ошибкy. Недавно подключить к готовому проекту Cortex M0 bootloader. Перенес вектора прерываний приложения из начала флеш в середину, сделал ремап векторов. scmRTOS запускается успешно но стал вылетать в HardFault_Handler после вызова channel.push() в прерывании UART. Вылет происходит когда накладываюя 2 прерывания. От системного таймера и вызова метода push(). Поиск выхода в точку падения по методу Сергей Борщ, в дизассемблере по шагам на выход из обработчика стабильно приводит к позиции scmRTOS: while(CurProcPriority != SchedProcPriority); Размер стека я менял - не помогает. Если медленно шагать по щагам в дизасме, найти точку вылета не получается. Все работает. Я знаю, что каналы в прерываниях использовать не рекомендовано. Но программа отлично и долго работала в этом варианте. И только сдвиг векторов из начала flash порушил работоспособность. Неделя борьбы с багом ни к чему не привела, может у кого есть свежая идея. Спасибо. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 19 марта, 2018 Опубликовано 19 марта, 2018 · Жалоба Подскажите если есть идеи, где мог сделать ошибкy. 1) Вы перед запихиванием в канал проверяете наличие в нем свободного места? 2) Какая ассемблерная инструкция вызывает падение, какие значения имеют используемые в ней регистры? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gradient 1 19 марта, 2018 Опубликовано 19 марта, 2018 · Жалоба 1. Свободное место проверяется, канал никогда не переполняется. 2. Не могу точно посмотреть. После выхода из обработчика и ввода в дебагер адреса из sp, оказываюсь на адресе в ram где лежит os_kernel. Никаких асм инструкций .. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 19 марта, 2018 Опубликовано 19 марта, 2018 · Жалоба 2. Не могу точно посмотреть. После выхода из обработчика и ввода в дебагер адреса из sp, оказываюсь на адресе в ram где лежит os_kernel. Никаких асм инструкций ..Недопонял. Вы же писали, что исключение происходит при выполнении кода "while(CurProcPriority != SchedProcPriority);". Посмотрите конкретную инструкцию в окне дизассемблера. И что за шаманство с вводом адреса из sp? Вопрос третий - вылетает при первом же обращении к push()? Не может такого быть, что у вас прерывание возникает раньше, чем запустилась ОС? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gradient 1 20 марта, 2018 Опубликовано 20 марта, 2018 (изменено) · Жалоба >> что за шаманство с вводом адреса из sp? Нашел данную методику но она не помогает. 1. Первым важным для нас регистром является счетчик команд. Переменная pc содержит значение счетчика команд где содержится адрес инструкции, которая выполнялась, когда произошла Hard Fault ошибка (или другая ошибка). Чтобы найти инструкцию по адресу, содержащемуся в переменной pc, откройте окно Disassembly (IAR) в отладчике и вручную введите адрес в окно Go to для просмотра asm инструкций по этому адресу. 2. Далее вручную установите точку останова в Disassembly отладчике или точку прерывания выполнения или доступа по этому адресу. С установленной точкой останова перезапустите приложение, чтобы увидеть, к какой строке C/C++ кода относится инструкция. 3. Код обработчика HardFault_Handler() #pragma section = "CSTACK" #pragma optimize=none extern "C" void HardFault_Handler(void) { volatile uint32_t r0; volatile uint32_t r1; volatile uint32_t r2; volatile uint32_t r3; volatile uint32_t r12; volatile uint32_t lr; volatile uint32_t pc; volatile uint32_t psr; uint32_t *pStackAddress = (uint32_t*)__section_begin("CSTACK"); r0 = pStackAddress++; r1 = pStackAddress++; r2 = pStackAddress++; r3 = pStackAddress++; r12 = pStackAddress++; lr = pStackAddress++; //Link register pc = pStackAddress++; //Program counter psr = pStackAddress; //Program status register //When the following line is hit, the variables contain the register values volatile int i = 0; while(i==0); //Stop here } По данной методике результат можно посмотреть на картинке. Методика 2. Шагаем в Disassembly из обработчика. Момент останова в обработчике > картинка Момент выхода из обработчика > картинка >>Вопрос третий - вылетает при первом же обращении к push()? Обычно после первого же, но иногда со второго. >>прерывание возникает раньше, чем запустилась ОС? Исключено. Прерывания запрещены до старта OS. Прерывание UART приходит с компа по моей команде, когда уже программа запущена. Если метод push() закомментировать, то все работает, но нет связи по UART. Изменено 20 марта, 2018 пользователем sevstels Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gradient 1 20 марта, 2018 Опубликовано 20 марта, 2018 (изменено) · Жалоба All pictures by one zip На мой взгляд целесообразно ввести в port раздельное заполнение тестовым паттерном. #define scmRTOS_STACK_PATTERN 0xAAAAAAAAUL #define scmRTOS_PROCESS_PATTERN 0xBBBBBBBBUL Изменено 20 марта, 2018 пользователем sevstels Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 марта, 2018 Опубликовано 20 марта, 2018 · Жалоба Нашел данную методику но она не помогает. По данной методике результат можно посмотреть на картинке. На всех ваших картинках SP_main имет значения порядка 0x2000043x, то есть стек прерываний расположен где-то в начале ОЗУ и, судя по всему, довольно небольшого размера. Такое ощущение, что этот стек переполняется и затирает объект OS::Kernel, а дальше, при перепланировке, происходит унос черт знает куда из-за загрузки мусора в PC. На картинке test-3 в архиве (по прямой ссылке другая картинка) отладчик показывает адрес OS:TKernel равный 0x0000122B, но этого не может быть - в этих адресах нет ОЗУ. Расскажите более подробно о ремапе векторов. Возможно вы в нем затираете какие-то данные. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 20 марта, 2018 Опубликовано 20 марта, 2018 · Жалоба Недавно подключить к готовому проекту Cortex M0 bootloader. Перенес вектора прерываний приложения из начала флеш в середину, сделал ремап векторов. scmRTOS запускается успешно но стал вылетать в HardFault_Handler после вызова channel.push() в прерывании UART. Немного не вяжется: у вас Cortex M0 или Cortex M0+ ? У Cortex M0 нет регистра VTOR, соответственно нельзя перенести таблицу векторов в середину флеш. Можно только в начало ОЗУ. Может дело в этом? Тогда при первом прерывании программа и будет улетать неизвестно куда. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Сергей Борщ 119 20 марта, 2018 Опубликовано 20 марта, 2018 · Жалоба Немного не вяжется: у вас Cortex M0 или Cortex M0+ ? У Cortex M0 нет регистра VTOR, соответственно нельзя перенести таблицу векторов в середину флеш. У M0+ вроде тоже нет. Но у них есть процедура отражения ОЗУ на начало памяти (remap), таким образом можно скопировать вектора в начало ОЗУ откуда угодно. Можно только в начало ОЗУ.Собственно, да. Меня очень смущает расположение основного стека близко к началу ОЗУ. Обычно его располагают в самом конце, чтобы он мог расти максимально далеко. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 20 марта, 2018 Опубликовано 20 марта, 2018 · Жалоба У M0+ вроде тоже нет. У STM Cortex-m0+ это семейство STM32L0, в нем есть VTOR Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gradient 1 21 марта, 2018 Опубликовано 21 марта, 2018 · Жалоба Немного не вяжется: у вас Cortex M0 или Cortex M0+ ? У Cortex M0 нет регистра VTOR, соответственно нельзя перенести таблицу векторов в середину флеш. Можно только в начало ОЗУ. Проект базируется на nRF51822, а это Cortex M0, VTOR нет. Но на мой взгляд, таблицу перенести можно. Для этого в стандартный (нулевой) адрес FLASH следует записать таблицу общую для bootloader и для application. Bootloader: *iar_startup.s file В этой таблице заменить все вектора на адрес функции обработчика прерывания. Address from 0x0000 SECTION .main_intvec __vector_table_main DCD sfe(CSTACK) DCD Reset_Handler DCD irq_forwarder DCD irq_forwarder DCD 0; Reserved DCD 0; Reserved DCD 0; Reserved DCD 0; Reserved ....... Далее собственная таблица векторов bootloader. Она может располагаться где угодно в пространстве FLASH, задается в настройках линкера. Any FLASH address SECTION .boot_intvec __vector_table DCD sfe(CSTACK) DCD Reset_Handler DCD NMI_Handler DCD HardFault_Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD 0 ; Reserved DCD SVC_Handler DCD 0 ; Reserved DCD 0 ; Reserved DCD PendSV_Handler DCD SysTick_Handler Далее за основной таблицей прерываний располагаем функцию форварда адресов: Linker file: place at address mem: 0xc8 {readonly section .irq_forwarder}; keep { section .irq_forwarder }; Code file: Переменная irq_table_offset может указывать смещение как во FLASH так и в RAM. irq_table_offset @ 0x20000000 = (unsigned long) __section_begin(".boot_intvec"); typedef void (*irq_handler_t)(void); __root void irq_forwarder(void) { //Read the number of the currently executing interrupt handler from IPSR. //See the Cortex-M0 user guide for details. uint32_t irq_interrupt_number = __get_IPSR(); //Find the address offset in the vector table //for the currently running interrupt, irq_interrupt_number * 4 uint32_t vector_table_offset = irq_interrupt_number << 2; //Get the address of the vector in the offset vector table uint32_t offset_vector_address = vector_table_offset + irq_table_offset; ///uint32_t offset_vector_address = vector_table_offset + (uint32_t)&irq_ram_table[0]; //Read the address of the IRQ handler to branch to from the offset vector irq_handler_t irq_handler=(irq_handler_t)(*(uint32_t*)offset_vector_address); //Branch to the irq_handler irq_handler(); } При запуске bootloader инициализация: irq_table_offset = (unsigned long) __section_begin(".boot_intvec"); При запуске application from bootloader инициализация: typedef void (*application_main_t)(void); apl_base_addr = find_application(); launch_application(apl_base_addr); void launch_application(unsigned long base_addr) { unsigned long *pData; unsigned long appl_cstack_pointer; application_main_t appl_reset_handler; //Get application CSTACK value pData = (unsigned long*)base_addr; appl_cstack_pointer = *pData++; //+4 bytes //Get Reset_Handler vector value from application intvec table appl_reset_handler = *(application_main_t*)(pData); //Set mode flag NRF_POWER->GPREGRET = DEV_APPLICATION_MODE; //Set application CStack pointer __set_SP(appl_cstack_pointer); //Jump to application Reset_Handler appl_reset_handler(); } Траблы происходят из за использования форвардера Я не смог его обьявить как __task, компилятор воспротивился, чтоб запретить сохранять на стеке адрес возврата. Видимо проблема в этой точке кода. Помогите исправить и проверить идею Практически на 90% работает :) >> Меня очень смущает расположение основного стека близко к началу ОЗУ. Обычно его располагают в самом конце. Пока не могу преодолеть. Усилия перенести стек в конец RAM, яростно отвергаются линкером. place at address mem:__ICFEDIT_intvec_start__ { readonly section .intvec }; place in ROM_region { readonly }; place in RAM_region { readwrite, block CSTACK, block HEAP }; //place at end of RAM_region {readwrite}; Строка place at end of RAM_region вызывает выдачу моря ошибок линковки. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 21 марта, 2018 Опубликовано 21 марта, 2018 · Жалоба Помогите исправить и проверить идею Практически на 90% работает :) Не слишком углублялся в вашу идею, уж больно она нестандартная :laughing: А чем вам не угодил стандартный способ ремапа векторов прерываний с копированием в начало ОЗУ? При этом создаются два независимых проекта, можно отлаживаться как отдельно, так и вместе (в ИАРе). Ссылки на примеры на STM32, но принципы то одинаковы: Bootloader on STM32F0 Interrupt vector table relocation on cortex M0 з.ы. зря вы закинули свой вопрос в эту тему, судя по всему, ваши проблемы никак не касаются scmRTOS... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gradient 1 21 марта, 2018 Опубликовано 21 марта, 2018 · Жалоба >> чем не угодил стандартный способ ремапа Не нашел функцию SYSCFG_MemoryRemapConfig. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Baser 5 21 марта, 2018 Опубликовано 21 марта, 2018 · Жалоба >> чем не угодил стандартный способ ремапа Не нашел функцию SYSCFG_MemoryRemapConfig. Похоже вы правы - глянул, System configuration controller (SYSCFG) это периферия STM32F0, она не входит в ядро Cortex-M0. Так что в вашем nRF51822 его может и не быть. А что производитель рекомендует для ремапа? Тот метод, что вы применили? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Gradient 1 21 марта, 2018 Опубликовано 21 марта, 2018 · Жалоба Производитель еще тот крендель. Они ничего не рекомендуют кроме своих сборок. Обойти их безумный индуский код стороной - было лучшее решение в данном случае. Вероятно они поленились и в их 'авторско горяче-финской' модификации ядра никак не предусмотрен перенос векторов. Теперь каждый спасется как может... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться