Проблема с таблицей векторов прерываний

32-разрядные микроконтроллеры разработки АО "НИИЭТ"

Модераторы: dav, bkolbov, pip, _sva_

Degrees
Сообщения: 9
Зарегистрирован: 05 сен 2018, 16:02
Предприятие: АО ПО "Север"

Проблема с таблицей векторов прерываний

Сообщение Degrees » 16 июл 2019, 13:11

Здравствуйте.
Есть проблема с вызовом обработчика прерывания при изменении смещения таблицы векторов.
Оборудование:
Микроконтроллер К1921ВК01Т (стартеркит от НИИЭТ)
Микроконтроллер 1921ВК01Т1 с ромбиком (своя разработка)
Среда разработки:
Keil 5.24.2 Lite (32K ограничение кода)
NIIET.K1921VK01T_DFP.2.0.5 (и DFP.2.0.4 пробовал)
Отладчик:
ST-LINK/V2 ISOL
Работающая ситуация:

Код: Выделить всё

// назначение обработчика прерывания от PWM3.
IRQ_HandlerInit (PWM3_IRQn, Interrupt_PWM3_Event_CheckSystem);
Под отладчиком видим в массиве :

Код: Выделить всё

Vectors[79]    0x00001881 Interrupt_PWM3_Event_CheckSystem
В файле Project.map(рабочий) находим положение таблицы векторов прерываний в ОЗУ МК:

Код: Выделить всё

    vtable                                   0x20000080   Section      600  niietcm4_irq.o(vtable)
    Vectors                                  0x20000080   Data         600  niietcm4_irq.o(vtable)
НЕ Работающая ситуация:
Немного добавил кода, глобальных и статических переменных .
Под отладчиком видим в массиве :

Код: Выделить всё

Vectors[79]    0x00001881 Interrupt_PWM3_Event_CheckSystem
Всё как положено !!! ;)
После разрешения прерывания:

Код: Выделить всё

	__Энвик_EnableIRQ(PWM3_IRQn);	
Контроллер зависает в startup_K1921VK01T.s

Код: Выделить всё

SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
 >>             B       .
                ENDP
:?
В файле Project.map(не рабочий) находим положение таблицы векторов прерываний в ОЗУ МК:

Код: Выделить всё

    vtable                                   0x20000100   Section      600  niietcm4_irq.o(vtable)
    Vectors                                  0x20000100   Data         600  niietcm4_irq.o(vtable)
При добавлении куска кода в файле «main.c» жизнь налаживается !!!

Код: Выделить всё

void SysTick_Handler(void){
	PWM_ET_StatusClear(NT_PWM3, PWM_ET_Status_A);
	PWM_ITStatusClear(NT_PWM3);
	PWM_ITPendClear(NT_PWM3);
}
:!:
В файле Project.map(жизнь наладилась) находим положение таблицы векторов прерываний:

Код: Выделить всё

    vtable                                   0x20000100   Section      600  niietcm4_irq.o(vtable)
    Vectors                                  0x20000100   Data         600  niietcm4_irq.o(vtable)
При остановке в теле обработчика прерываний SysTick_Handler открываем Энвик и видим:

Код: Выделить всё

15   System Tick Timer		SYSTICK		Enable		--------		--------
...
79   ExtIRQ63			ExtIRQ63	Enable		--------		Active
79 – 15 = 64 ???
Похоже ошибка в железе или при инициализации оного… Да и инициализация вроде верна… Может я чего-то не понимаю?
Вложения
Project.map(рабочий).txt
(122.88 КБ) 9 скачиваний
Project.map(не рабочий).txt
(129.47 КБ) 6 скачиваний
Project.map(жизнь наладилась).txt
(130.04 КБ) 6 скачиваний

редактор
Сообщения: 8
Зарегистрирован: 08 ноя 2016, 09:10

Re: Проблема с таблицей векторов прерываний

Сообщение редактор » 17 июл 2019, 11:02

Немного добавил кода, глобальных и статических переменных. Контроллер зависает в startup_K1921VK01T.s
Судя по всему контроллер зависает при возникновении прерывания от SysTick_Timer.
То есть вы запустили таймер, разрешили от него прерывание но не указали обработчик, поэтому линкер подставил обработчик по умолчанию, в котором вы и зависли.
При добавлении куска кода в файле «main.c» жизнь налаживается !!!
Жизнь налаживается, потому что вы описали СВОЙ обработчик прерывания от SysTick_Timer.
Может я чего-то не понимаю?
Не нужно разрешать прерывания от перефирии если не указываете свой обработчик прерывания.

prostoRoman
Сообщения: 47
Зарегистрирован: 11 июл 2014, 15:06

Re: Проблема с таблицей векторов прерываний

Сообщение prostoRoman » 17 июл 2019, 14:03

А что содержит регистр SCB->VTOR?
Он должен содержать указатель на таблицу векторов, а он, если я правильно понимаю, у Вас меняется то 0x20000080, то 0x20000100.
Кроме того, на выравнивание таблицы тоже есть требование! Исходя из кол-ва векторов у этого МК выравнивание должно бы быть 0x400.

Degrees
Сообщения: 9
Зарегистрирован: 05 сен 2018, 16:02
Предприятие: АО ПО "Север"

Re: Проблема с таблицей векторов прерываний

Сообщение Degrees » 17 июл 2019, 14:51

Судя по всему контроллер зависает при возникновении прерывания от SysTick_Timer.
То есть вы запустили таймер, разрешили от него прерывание но не указали обработчик, поэтому линкер подставил обработчик по умолчанию, в котором вы и зависли.
1. Насколько мне известно SysTick_Timer имеет не маскируемое прерывание.
То есть запретить я его не могу.
2. SysTick_Timer не запущен.
3. открыв Энвик при остановке в теле обработчика SysTick_Handler убеждаемся, что происходит обработка ExtIRQ63.

Код: Выделить всё

15   System Tick Timer	SYSTICK		Enable	-------	-------
...
79   ExtIRQ63		ExtIRQ63	Enable	-------	Active
Не нужно разрешать прерывания от перефирии если не указываете свой обработчик прерывания.
Об этом было известно пару десятилетий назад :) , но с кортекс'ом знакомство только началось.

bkolbov
Сообщения: 227
Зарегистрирован: 14 дек 2015, 11:37
Предприятие: АО НИИЭТ
Откуда: Воронеж

Re: Проблема с таблицей векторов прерываний

Сообщение bkolbov » 17 июл 2019, 15:26

Degrees писал(а):
16 июл 2019, 13:11
Здравствуйте.
Есть проблема с вызовом обработчика прерывания при изменении смещения таблицы векторов.
Добрый день!

Судя по мап-файлу вы используете функции из niietcm4_irq.c.
Там похоже ошибка в выравнивании, должно быть 256:

Код: Выделить всё

void (*Vectors[IRQ_TOTAL])(void) __attribute__((aligned(256)));
Попробуйте исправить.

prostoRoman
Сообщения: 47
Зарегистрирован: 11 июл 2014, 15:06

Re: Проблема с таблицей векторов прерываний

Сообщение prostoRoman » 17 июл 2019, 18:02

Degrees писал(а):
17 июл 2019, 14:51
1. Насколько мне известно SysTick_Timer имеет не маскируемое прерывание.
То есть запретить я его не могу.
Прерывание от SysTick_Timer ни чем не отличается от всех остальных (кроме Reset, NMI, HardFault), т.е. его нужно включить для того, чтобы обработчик вызывался.

Degrees
Сообщения: 9
Зарегистрирован: 05 сен 2018, 16:02
Предприятие: АО ПО "Север"

Re: Проблема с таблицей векторов прерываний

Сообщение Degrees » 18 июл 2019, 09:30

Изменил выравнивание в "niietcm4_irq.c" (было 128)

Код: Выделить всё

#if defined (__ICCARM__)
    #pragma data_alignment=256
    static __no_init void (*Vectors[IRQ_TOTAL])(void) @ "VTABLE";
#elif defined (__GNUC__)
    static __attribute__((section("vtable")))
    void (*Vectors[IRQ_TOTAL])(void) __attribute__((aligned(256)));
#elif defined (__CC_арм)
    static __attribute__((section("vtable")))
    void (*Vectors[IRQ_TOTAL])(void) __attribute__((aligned(256)));
#else
    #error "Нет реализации под данный компилятор"
#endif
Все осталось как прежде. Вызывается

Код: Выделить всё

void SysTick_Handler(void){
	PWM_ET_StatusClear(NT_PWM3, PWM_ET_Status_A); // сброс запуска АЦП
	PWM_ITStatusClear(NT_PWM3);
	PWM_ITPendClear(NT_PWM3);
}
Нужный мне обработчик не вызывается.

Код: Выделить всё

void  Interrupt_PWM_Event_CheckSystem(void){
	PWM_ET_StatusClear(NT_PWM3, PWM_ET_Status_A); // сброс запуска АЦП
	PWM_ITStatusClear(NT_PWM3);
	PWM_ITPendClear(NT_PWM3);
}

Попробовал запускать прерывания от PWM4_IRQn

Код: Выделить всё

	IRQ_HandlerInit (PWM4_IRQn, Interrupt_PWM_Event_CheckSystem); // назначение
	__Энвик_EnableIRQ(PWM4_IRQn); // разрешение
Теперь виснет в обработчике прерывания по умолчанию. Default_Handler
Адрес таблицы векторов прерываний (VTOR) 0x20000100.
Поднимаемся по таблице векторов прерываний вверх на 64 строчки и натыкаемся на

Код: Выделить всё

I2C1_IRQHandler
Добавляю свой обработчик в файле "main.c":

Код: Выделить всё

void I2C1_IRQHandler(void){
	PWM_ET_StatusClear(NT_PWM3, PWM_ET_Status_A); // сброс запуска АЦП
	PWM_ITStatusClear(NT_PWM4);
	PWM_ITPendClear(NT_PWM4);
}
И жизнь налаживается опять!!!

Код: Выделить всё

void SysTick_Handler(void){	// пока повременит.
	while(1){}		// а вдруг поймает чего…
}
Висеть перестает.
При этом, нужный мне (ПРАВИЛЬНЫЙ) обработчик

Код: Выделить всё

void  Interrupt_PWM_Event_CheckSystem(void){
	PWM_ET_StatusClear(NT_PWM3, PWM_ET_Status_A); // сброс запуска АЦП
	PWM_ITStatusClear(NT_PWM4);
	PWM_ITPendClear(NT_PWM4);
}
НЕ ЗАПУСКАЕТСЯ !!!
При остановке в теле обработчика прерываний I2C1_IRQHandler открываем Энвик и видим:

Код: Выделить всё

18   ExtIRQ 2	ExtIRQ 2	-------	-------	-------
...
82   ExtIRQ 66	ExtIRQ66	Enable	-------	Active
ВЫПОЛНЯЕТСЯ ExtIRQ 66 от PWM4 !!!
То есть

Код: Выделить всё

void  Interrupt_PWM_Event_CheckSystem(void);
==========================================================
Выход есть. В "niietcm4_irq.c" меняем строчку

Код: Выделить всё

//    Vectors[IRQ_NUM(IRQn)] = pfnHandler;		// Было
    Vectors[IRQ_NUM(IRQn)-64] = pfnHandler;		// Стало
и вызывается нужный мне обработчик. Но это как-то неправильно. Не с каждым вектором такое прокатит.

bkolbov
Сообщения: 227
Зарегистрирован: 14 дек 2015, 11:37
Предприятие: АО НИИЭТ
Откуда: Воронеж

Re: Проблема с таблицей векторов прерываний

Сообщение bkolbov » 18 июл 2019, 10:11

Извиняюсь, я похоже ввёл вас в заблуждение.

prostoRoman выше правильно написал
Кроме того, на выравнивание таблицы тоже есть требование! Исходя из кол-ва векторов у этого МК выравнивание должно бы быть 0x400.
Выравнивание вычисляется как следующая степень двойки от размера(!) таблицы прерываний в байтах, а не от общего количества векторов.
Попробуйте выравнивание 1024 - должно заработать.

prostoRoman
Сообщения: 47
Зарегистрирован: 11 июл 2014, 15:06

Re: Проблема с таблицей векторов прерываний

Сообщение prostoRoman » 18 июл 2019, 10:33

Degrees писал(а):
18 июл 2019, 09:30
Изменил выравнивание в "niietcm4_irq.c" (было 128)

Код: Выделить всё

#if defined (__ICCARM__)
    #pragma data_alignment=256
    static __no_init void (*Vectors[IRQ_TOTAL])(void) @ "VTABLE";
#elif defined (__GNUC__)
    static __attribute__((section("vtable")))
    void (*Vectors[IRQ_TOTAL])(void) __attribute__((aligned(256)));
#elif defined (__CC_арм)
    static __attribute__((section("vtable")))
    void (*Vectors[IRQ_TOTAL])(void) __attribute__((aligned(256)));
#else
    #error "Нет реализации под данный компилятор"
#endif
Все осталось как прежде. ...
Зря вы не прислушиваетесесь. Я догадываюсь так, что хитрые арм'овцы, создавая Энвик, произвели грамотную оптимизацию: определяют адрес функции обработчика прерывания (ISR) как объединение бит смещения таблицы прерывания (TBLOFF из SCB->VTOR) и номера прерывания (сдвинутого на 2 разряда влево, ибо указатель имеет размерность слова - 32 бит).
Поэтому, что выравнивание 128 байт (как было, это вообще минимальное значение), что 256 байт (было бы в словах - было бы правильно) - оба не верно.
Производитель прямо пишет: http://infocenter.арм.com/help/topic/co ... eijba.html
арм DUI 0552A писал(а):When setting TBLOFF, you must align the offset to the number of exception entries in the vector table. The minimum alignment is 32 words, enough for up to 16 interrupts. For more interrupts, adjust the alignment by rounding up to the next power of two. For example, if you require 21 interrupts, the alignment must be on a 64-word boundary because the required table size is 37 words, and the next power of two is 64. See your vendor documentation for the alignment details for your device.
гугл перевод писал(а):При установке TBLOFF вы должны выровнять смещение по количеству записей об исключениях в таблице векторов. Минимальное выравнивание составляет 32 слова, достаточно для 16 прерываний. Для большего количества прерываний отрегулируйте выравнивание, округляя до следующей степени двух. Например, если вам требуется 21 прерывание, выравнивание должно быть на границе из 64 слов, поскольку требуемый размер таблицы составляет 37 слов, а следующая степень двух - 64. Информацию о выравнивании для вашего устройства см. В документации вашего поставщика.
"В документации вашего поставщика" прямо, видимо, не сказано, но векторов там более двухсот, соответственно выравниваться нужно по 256 слов, что равно 1024 байт.
__attribute__((aligned)) выравнивает по байтам, а не по словам:
9.62 __attribute__((aligned)) variable attribute
The aligned variable attribute specifies a minimum alignment for the variable or structure field, measured in bytes.
Поэтому правильно будет сделать

Код: Выделить всё

#elif defined (__CC_арм)
    static __attribute__((section("vtable")))
    void (*Vectors[IRQ_TOTAL])(void) __attribute__((aligned(1024)));
#else
Убкдиться во всём этом Вы сможете самостоятельно, если посчитаете в двоичном виде как определяет Энвик адрес ISR и как таблица векторов ложится на это.
UPD: да, на ответ потратил полчаса.

bkolbov
Сообщения: 227
Зарегистрирован: 14 дек 2015, 11:37
Предприятие: АО НИИЭТ
Откуда: Воронеж

Re: Проблема с таблицей векторов прерываний

Сообщение bkolbov » 18 июл 2019, 10:41

prostoRoman писал(а):
18 июл 2019, 10:33
...
Убкдиться во всём этом Вы сможете самостоятельно, если посчитаете в двоичном виде как определяет Энвик адрес ISR и как таблица векторов ложится на это.
UPD: да, на ответ потратил полчаса.
Благодарю за такой подробный пост! Внесу в FAQ.

Ответить

Вернуться в «32-разрядные микроконтроллеры»

Пользователи онлайн

Сейчас этот форум просматривают: нет зарегистрированных пользователей и 4 гостя