stm32 NVIC_EnableIRQ() голый металлический эквивалент?

#stm32 #interrupt #bare-metal

#stm32 #прерывание #голый металл

Вопрос:

Я использую синюю таблетку и пытаюсь разобраться с прерываниями. У меня есть обработчик прерываний:

 void __attribute__ ((interrupt ("TIM4_IRQHandler"))) myhandler()
{
    puts("hi");
    TIM4->EGR |= TIM_EGR_UG; // send an update even to reset timer and apply settings
    TIM4->SR amp;= ~0x01; // clear UIF
    TIM4->DIER |= 0x01; // UIE
}
  

Я установил таймер:

     RCC_APB1ENR |= RCC_APB1ENR_TIM4EN;
    TIM4->PSC=7999;
    TIM4->ARR=1000;
    TIM4->EGR |= TIM_EGR_UG; // send an update even to reset timer and apply settings
    TIM4->EGR |= (TIM_EGR_TG | TIM_EGR_UG);
    TIM4->DIER |= 0x01; // UIE enable interrupt
    TIM4->CR1 |= TIM_CR1_CEN;
   
  

Похоже, мой таймер не активируется. Я не думаю, что я на самом деле включил его. Есть ли у меня??

Я вижу во многих примерах команд кода, таких как:

 NVIC_EnableIRQ(USART1_IRQn);
  

Что на самом деле происходит в NVIC_EnableIRQ()?

Я погуглил, но не могу найти реальный голый металлический код, который делает что-то похожее на мой.

Кажется, я пропускаю важный шаг.

Обновление 2020-09-23 Спасибо респондентам на этот вопрос. Хитрость заключается в том, чтобы установить бит для номера прерывания в регистре NVIC_ISER. Как я указал ниже, это, похоже, не упоминается в справочном руководстве STM32F101xx, поэтому я, вероятно, никогда бы не смог разобраться в этом самостоятельно; не то чтобы у меня были какие-либо реальные навыки чтения таблиц данных.

В любом случае, о радость, мне удалось заставить прерывания работать! Вы можете увидеть код здесь: https://github.com/blippy/rpi/tree/master/stm32/bare/04-timer-interrupt

Комментарии:

1. Детали, связанные с ядром Cortex, обычно упоминаются в «Руководстве по программированию», а не в «Справочном руководстве».

2. Нашел описание регистров NVIC здесь: booksite.elsevier.com/9780124080829/downloads/APP-06.pdf

Ответ №1:

Даже если вы используете голый металл, вы все равно можете захотеть использовать заголовочные файлы CMSIS, которые предоставляют объявления и встроенную версию очень простых элементов ARM Cortex, таких NVIC_EnableIRQ как .

Вы можете найти NVIC_EnableIRQ на https://github.com/ARM-software/CMSIS_5/blob/develop/CMSIS/Core/Include/core_cm3.h#L1508

Оно определяется как:

 
#define NVIC_EnableIRQ __NVIC_EnableIRQ

__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn)
{
  if ((int32_t)(IRQn) >= 0)
  {
    __COMPILER_BARRIER();
    NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) amp; 0x1FUL));
    __COMPILER_BARRIER();
  }
}
  

Если вы хотите, вы можете игнорировать __COMPILER_BARRIER() . Предыдущие версии его не использовали.

Определение применимо к чипам Cortex M-3. Это отличается для других версий Cortex.

Ответ №2:

С библиотеками все еще считается голым металлом. Без операционной системы, но в любом случае, хорошо, что у вас есть желание учиться на этом уровне. Кто-то должен писать библиотеки для других.

Я собирался привести здесь полный пример (для этого действительно требуется очень мало кода), но возьму из своего кода для этой платы, которая использует timer1.

Вам, очевидно, нужна документация ARM (техническое справочное руководство для cortex-m3 и справочное руководство по архитектуре для armv7-m), а также спецификация и справочное руководство для этой части st (нет необходимости в руководстве для программистов от любой компании).).

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

Я предпочитаю, чтобы uart работал, а затем использовал его для просмотра регистров таймера при перевороте, подсчете и т. Д. Затем посмотрите / подтвердите запуск регистра состояния, узнайте / подтвердите, как его очистить (иногда это просто очистка при чтении).

Затем включите его в NVIC и путем опроса убедитесь, что NVIC его видит, и что вы можете его очистить.

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

 08000000 <_start>:
 8000000:   20005000
 8000004:   080000b9
 8000008:   080000bf
 800000c:   080000bf
...
 80000a0:   080000bf
 80000a4:   080000d1
 80000a8:   080000bf
...
080000b8 <reset>:
 80000b8:   f000 f818   bl  80000ec <notmain>
 80000bc:   e7ff        b.n 80000be <hang>
...
080000be <hang>:
 80000be:   e7fe        b.n 80000be <hang>
...
080000d0 <tim1_handler>:
  

Первое слово загружает указатель стека, остальные — векторы, адрес обработчика или один (я дам вам посмотреть).

В этом случае в справочном руководстве st показано, что прерывание 25 является TIM1_UP по адресу 0x000000A4. Который отражает 0x080000A4, и именно там находится обработчик в моем двоичном файле, если ваш не соответствует двум вещам, во-первых, вы можете использовать VTOR, чтобы найти выровненное пространство, иногда sram или какое-либо другое флэш-пространство, которое вы создаете для этого, и указать там, но ваш обработчик векторной таблицы должен иметь правильноеуказатель или обработчик прерывания не будут запускаться.

 volatile unsigned int counter;
void tim1_handler ( void )
{
    counter  ;
    PUT32(TIM1_SR,0);
}
  

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

 ra=GET32(RCC_APB2ENR);
ra|=1<<11;  //TIM1
PUT32(RCC_APB2ENR,ra);

...

counter=0;
PUT32(TIM1_CR1,0x00001);
PUT32(TIM1_DIER,0x00001);
PUT32(NVIC_ISER0,0x02000000);
for(rc=0;rc<10;)
{
    if(counter>=1221)
    {
        counter=0;
        toggle_led();
        rc  ;
    }
}
PUT32(TIM1_CR1,0x00000);
PUT32(TIM1_DIER,0x00000);
  

Минимальная инициализация и время выполнения для tim1.

Обратите внимание, что NVIC_ISER0 имеет бит 25, который установлен для включения прерывания с 25 по.

Задолго до того, как попробовать этот код, я опросил регистр состояния таймера, чтобы посмотреть, как это работает, сравнить с документами, очистить прерывание в соответствии с документами. Затем с этим знанием, подтвержденным регистрами NVIC_ICPR0,1,2, что это было прерывание 25. А также отсутствие других вентилей между периферийным устройством и NVIC, как это может быть у некоторых чипов некоторых производителей.

Затем выпустил его в ядро с помощью NVIC_ISER0.

Если вы не предпримете эти маленькие шаги, и, возможно, вы уже это сделали, это только усложнит задачу и займет больше времени (да, иногда вам везет).).

TIM4 выглядит как прерывание 30, смещение / адрес 0x000000B8, в векторной таблице. NVIC_ISER0 (0xE000E100) покрывает первые 32 прерывания, поэтому в этом регистре будет 30. Если вы разбираете код, который вы создаете с помощью библиотеки, мы можем увидеть, что происходит, и или посмотреть его в исходном коде библиотеки (как кто-то уже сделал для вас).

И тогда, конечно, ваш код timer 4 должен правильно инициализировать таймер и вызвать прерывание, которое я не проверял.

Есть примеры, вам нужно просто продолжать искать.

Минимум равен

  1. вектор в таблице
  2. установите бит в регистре включения набора прерываний
  3. разрешить прерыванию покинуть периферийное устройство
  4. запуск прерывания

Не обязательно в таком порядке.

Комментарии:

1. Ага! Хорошо, это дало мне достаточно подсказок, чтобы заставить его работать. Я не вижу NVIC_ISER0 в таблицах данных, поэтому я немного смущен. Тем не менее, кажется, что адрес равен 0xE000E100, который я получил из поиска в Google. Мне просто нужно установить бит с номером прерывания, который я пытаюсь установить. Я обновлю свой первоначальный вопрос. Большое спасибо.