реклама на сайте
подробности

 
 
2 страниц V   1 2 >  
Reply to this topicStart new topic
> Перенос векторов прерываний в nRF51822
sevstels
сообщение Mar 19 2018, 13:55
Сообщение #1


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



Подскажите если есть идеи, где мог сделать ошибкy.

Недавно подключить к готовому проекту Cortex M0 bootloader. Перенес вектора прерываний приложения из начала флеш в середину, сделал ремап векторов. scmRTOS запускается успешно но стал вылетать в HardFault_Handler после вызова channel.push() в прерывании UART.

Вылет происходит когда накладываюя 2 прерывания.
От системного таймера и вызова метода push().

Поиск выхода в точку падения по методу Сергей Борщ, в дизассемблере по шагам на выход из обработчика стабильно приводит к позиции scmRTOS: while(CurProcPriority != SchedProcPriority);

Размер стека я менял - не помогает.
Если медленно шагать по щагам в дизасме, найти точку вылета не получается. Все работает.

Я знаю, что каналы в прерываниях использовать не рекомендовано. Но программа отлично и долго работала в этом варианте. И только сдвиг векторов из начала flash порушил работоспособность.

Неделя борьбы с багом ни к чему не привела, может у кого есть свежая идея. Спасибо.


--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 19 2018, 14:52
Сообщение #2


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (sevstels @ Mar 19 2018, 15:55) *
Подскажите если есть идеи, где мог сделать ошибкy.

1) Вы перед запихиванием в канал проверяете наличие в нем свободного места?
2) Какая ассемблерная инструкция вызывает падение, какие значения имеют используемые в ней регистры?



--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
sevstels
сообщение Mar 19 2018, 15:52
Сообщение #3


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



1. Свободное место проверяется, канал никогда не переполняется.

2. Не могу точно посмотреть. После выхода из обработчика и ввода в дебагер адреса из sp, оказываюсь на адресе в ram где лежит os_kernel. Никаких асм инструкций ..


--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 19 2018, 18:45
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (sevstels @ Mar 19 2018, 17:52) *
2. Не могу точно посмотреть. После выхода из обработчика и ввода в дебагер адреса из sp, оказываюсь на адресе в ram где лежит os_kernel. Никаких асм инструкций ..
Недопонял. Вы же писали, что исключение происходит при выполнении кода "while(CurProcPriority != SchedProcPriority);". Посмотрите конкретную инструкцию в окне дизассемблера. И что за шаманство с вводом адреса из sp?

Вопрос третий - вылетает при первом же обращении к push()? Не может такого быть, что у вас прерывание возникает раньше, чем запустилась ОС?


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
sevstels
сообщение Mar 20 2018, 05:14
Сообщение #5


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



>> что за шаманство с вводом адреса из 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.

Сообщение отредактировал sevstels - Mar 20 2018, 07:04


--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post
sevstels
сообщение Mar 20 2018, 06:45
Сообщение #6


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



All pictures by one zip

На мой взгляд целесообразно ввести в port раздельное заполнение тестовым паттерном.
#define scmRTOS_STACK_PATTERN 0xAAAAAAAAUL
#define scmRTOS_PROCESS_PATTERN 0xBBBBBBBBUL

Сообщение отредактировал sevstels - Mar 20 2018, 07:56


--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 20 2018, 14:13
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (sevstels @ Mar 20 2018, 07:14) *
Нашел данную методику но она не помогает.
По данной методике результат можно посмотреть на картинке.
На всех ваших картинках SP_main имет значения порядка 0x2000043x, то есть стек прерываний расположен где-то в начале ОЗУ и, судя по всему, довольно небольшого размера. Такое ощущение, что этот стек переполняется и затирает объект OS::Kernel, а дальше, при перепланировке, происходит унос черт знает куда из-за загрузки мусора в PC.

На картинке test-3 в архиве (по прямой ссылке другая картинка) отладчик показывает адрес OS:TKernel равный 0x0000122B, но этого не может быть - в этих адресах нет ОЗУ.


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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Baser
сообщение Mar 20 2018, 17:46
Сообщение #8


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(sevstels @ Mar 19 2018, 15:55) *
Недавно подключить к готовому проекту Cortex M0 bootloader. Перенес вектора прерываний приложения из начала флеш в середину, сделал ремап векторов. scmRTOS запускается успешно но стал вылетать в HardFault_Handler после вызова channel.push() в прерывании UART.

Немного не вяжется: у вас Cortex M0 или Cortex M0+ ?
У Cortex M0 нет регистра VTOR, соответственно нельзя перенести таблицу векторов в середину флеш.
Можно только в начало ОЗУ.
Может дело в этом?
Тогда при первом прерывании программа и будет улетать неизвестно куда.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Mar 20 2018, 18:47
Сообщение #9


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (Baser @ Mar 20 2018, 19:46) *
Немного не вяжется: у вас Cortex M0 или Cortex M0+ ?
У Cortex M0 нет регистра VTOR, соответственно нельзя перенести таблицу векторов в середину флеш.
У M0+ вроде тоже нет. Но у них есть процедура отражения ОЗУ на начало памяти (remap), таким образом можно скопировать вектора в начало ОЗУ откуда угодно.
QUOTE (Baser @ Mar 20 2018, 19:46) *
Можно только в начало ОЗУ.
Собственно, да.

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


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Baser
сообщение Mar 20 2018, 22:00
Сообщение #10


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(Сергей Борщ @ Mar 20 2018, 20:47) *
У M0+ вроде тоже нет.

У STM Cortex-m0+ это семейство STM32L0, в нем есть VTOR
Go to the top of the page
 
+Quote Post
sevstels
сообщение Mar 21 2018, 11:21
Сообщение #11


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



Цитата(Baser @ Mar 21 2018, 02:46) *
Немного не вяжется: у вас 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% работает sm.gif

>> Меня очень смущает расположение основного стека близко к началу ОЗУ. Обычно его располагают в самом конце.
Пока не могу преодолеть. Усилия перенести стек в конец 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 вызывает выдачу моря ошибок линковки.


--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post
Baser
сообщение Mar 21 2018, 12:20
Сообщение #12


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(sevstels @ Mar 21 2018, 13:21) *
Помогите исправить и проверить идею Практически на 90% работает sm.gif

Не слишком углублялся в вашу идею, уж больно она нестандартная laughing.gif
А чем вам не угодил стандартный способ ремапа векторов прерываний с копированием в начало ОЗУ?
При этом создаются два независимых проекта, можно отлаживаться как отдельно, так и вместе (в ИАРе).
Ссылки на примеры на STM32, но принципы то одинаковы:
Bootloader on STM32F0
Interrupt vector table relocation on cortex M0

з.ы. зря вы закинули свой вопрос в эту тему, судя по всему, ваши проблемы никак не касаются scmRTOS...
Go to the top of the page
 
+Quote Post
sevstels
сообщение Mar 21 2018, 13:40
Сообщение #13


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



>> чем не угодил стандартный способ ремапа
Не нашел функцию SYSCFG_MemoryRemapConfig.



--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post
Baser
сообщение Mar 21 2018, 13:59
Сообщение #14


Просто Che
*****

Группа: Свой
Сообщений: 1 567
Регистрация: 22-05-07
Из: ExUSSR
Пользователь №: 27 881



Цитата(sevstels @ Mar 21 2018, 15:40) *
>> чем не угодил стандартный способ ремапа
Не нашел функцию SYSCFG_MemoryRemapConfig.

Похоже вы правы - глянул, System configuration controller (SYSCFG) это периферия STM32F0, она не входит в ядро Cortex-M0. Так что в вашем nRF51822 его может и не быть. А что производитель рекомендует для ремапа? Тот метод, что вы применили?
Go to the top of the page
 
+Quote Post
sevstels
сообщение Mar 21 2018, 14:35
Сообщение #15


Знающий
****

Группа: Участник
Сообщений: 626
Регистрация: 3-12-07
Пользователь №: 32 910



Производитель еще тот крендель. Они ничего не рекомендуют кроме своих сборок. Обойти их безумный индуский код стороной - было лучшее решение в данном случае.

Вероятно они поленились и в их 'авторско горяче-финской' модификации ядра никак не предусмотрен перенос векторов. Теперь каждый спасется как может...


--------------------
Herz - дятел.
Go to the top of the page
 
+Quote Post

2 страниц V   1 2 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 6th July 2025 - 01:27
Рейтинг@Mail.ru


Страница сгенерированна за 0.01473 секунд с 7
ELECTRONIX ©2004-2016