Як реалізуються обробники переривань у CMSIS Cortex M0?


9

У мене є комплект LPC1114. Останні кілька днів я розкопував CMSIS реалізацію Cortex M0, щоб дізнатися, як все робиться в ньому. Поки я зрозумів, як окремі регістри відображаються і як я можу отримати доступ до нього. Але все одно я не знаю, як в ньому реалізуються переривання. Все, що я знаю про перебої в CMSIS - це деякі імена обробника переривань, згадані у файлі запуску. І я можу написати власні обробники, просто записавши функцію C з тими ж іменами, згаданими у файлі запуску. Що мене бентежить, що в посібнику користувача сказано, що всі GPIO можуть використовуватися як зовнішні джерела переривання. Але у файлі запуску вказано лише 4 переривання PIO. Так скажіть мені:

  1. Як я можу реалізувати зовнішні обробники переривань для інших GPIO?
  2. Де таблиця переривань відображається в CMSIS?
  3. Які основні відмінності між NVIC та переривним впровадженням в AVR / PIC? .

Відповіді:


14

Наступна інформація є доповненням до чудової відповіді Ігоря.

З точки зору програмування на C, обробники переривань визначаються у файлі cr_startup_xxx.c (наприклад, файл cr_startup_lpc13.c для LPC1343). Усі можливі обробники переривань визначаються там як ПІВДЕННЯ СЛАБОГО. Якщо ви не визначите власний XXX_Handler () для джерела переривання, тоді буде використана функція обробника перерв за замовчуванням, визначена в цьому файлі. Лінкер розбере, яку функцію включити в кінцевий бінарний файл, а також векторну таблицю переривання з cr_startup_xxx.c

Приклад перерв GPIO з портів показаний у демонстраційних файлах у gpio.c. Є один вхід переривання в NVIC на порт GPIO. Кожен окремий біт у порту можна включити / вимкнути, щоб генерувати переривання на цьому порту. Якщо вам потрібні, наприклад, перерви на портах PIO1_4 та PIO1_5, ви б увімкнули окремі біти переривання PIO1_4 та PIO1_5 в GPIO0IE. Коли ваша функція обробника переривань PIOINT0_Handler () спрацьовує, вам належить визначити, які з переривань PIO1_4 або PIO1_5 (або обох) очікуються, прочитавши регістр GPIO0RIS та обробляючи переривання належним чином.


10

(Зверніть увагу, що пункти 1 і 2 - це деталі реалізації, а не архітектурні обмеження.)

  1. У більших NXP-мікросхемах (таких як LPC17xx) є пара виділених штифтів переривання (EINTn), які мають власний обробник переривання. Решта GPIO повинні використовувати один загальний переривання (EINT3). Потім можна запитати реєстр статусу переривання, щоб побачити, які штифти викликали переривання.
  2. Я не дуже знайомий з LPC11xx, але, схоже , він має один перерив на GPIO-порт. Вам знову доведеться перевірити регістр статусу, щоб визначити конкретні штифти. Також є до 12 штифтів, які можуть діяти як джерела пробудження. Я не впевнений, чи зможете ви викрасти їх як загальні переривання (тобто вони, ймовірно, спрацьовують лише тоді, коли вони перебувають у стані сну).
  3. Таблиця обробника за замовчуванням розміщується за адресою 0 (яка знаходиться у спалах). Перший запис - це значення скидання для регістра SP, другий - вектор скидання, а решта - інші винятки та вектори переривання. Пару перших (таких як NMI і HardFault) фіксують ARM, решта - для чіпів. Якщо вам потрібно змінити вектори під час виконання, ви можете перезавантажити його в RAM (спочатку потрібно скопіювати таблицю). У LPC11xx перекомпонування фіксується до початку SRAM (0x10000000), інші мікросхеми можуть бути більш гнучкими.
  4. NVIC оптимізовано для ефективної обробки перерв:
    • програмований рівень пріоритету 0-3 для кожного переривання. Більш пріоритетні переривання перешкоджають тим, які мають нижчий пріоритет (вкладення). Виконання нижчого пріоритету поновлюється після завершення переривання вищого пріоритету.
    • автоматичне укладання стану процесора при вступі переривання; це дозволяє записувати обробники переривань безпосередньо на С та знімає необхідність у складанні обгортки.
    • хвостовий ланцюг: замість того, щоб вискакувати і знову натиснути стан, наступне очікуване переривання обробляється негайно
    • запізнення: якщо надходить перерив більш високого пріоритету під час укладання стану процесора, він виконується негайно замість раніше очікуваного.

Оскільки ви знайомі з PIC, ознайомтеся з цим додатком Примітка: Перехід з мікроконтролерів PIC на Cortex-M3

Мова йде про M3, але більшість пунктів стосується і M0.


8

Відповіді Остіна та Ігоря досить детальні. Однак я хочу відповісти на це іншим способом, можливо, ви вважаєте це корисним.

LPC11xx (Cortex-M0) має 4 рівні для штифтів GPIO, усі штифти від GPIO0.0 до GPIO0.n мають однаковий номер переривання, і всі штифти від GPIO3.0 до GPIO3.m мають однаковий номер переривання.

Існує шість кроків для ініціалізації переривання GPIO у LPC11xx

  1. Налаштуйте контактну функцію, змінивши регістри блоків з'єднання контактів.
  2. Встановіть напрямок штифта, змінивши регістр напрямків даних GPIO (значення за замовчуванням - введення).
  3. Налаштуйте переривання для кожного окремого штифта, вам потрібно перейти до реєстру маски GPIO переривання GPIOnIE і встановити біт (що відповідає штифту) логіки 1.
  4. Встановіть переривання для висхідного або нижнього краю або обох, змінивши регістри почуттів переривання GPIO GPIOnIBE та GPIOnIS.
  5. Увімкніть джерело переривання або PIO_0 / PIO_1 / PIO_2 / PIO_3 у вкладеному векторіальному контролі переривання за допомогою функцій CMSIS.
  6. Встановіть пріоритет переривання за допомогою функцій CMSIS.

Реалізація коду. Вам потрібні дві функції: одна ініціалізує 6 вищезазначених кроків, а друга - обробник переривання, який повинен мати те саме ім'я, що і обробник, визначений у стартових кодах, startup_LPC11xx.sфайлу. Імена з PIOINT0_IRQHandlerдо PIOINT3_IRQHandler. Якщо ви використовуєте інше ім’я, вам потрібно змінити імена у файлі запуску.

/*Init the GPIO pin for interrupt control */
void GPIO_Init(){
    LPC_IOCON-> =..              //Pin configuration register
    LPC_GPIO1->FIODIR = ...      //GPIO Data direction register
    LPC_GPIO1->FIOMASK = ..      //GPIO Data mask register - choose  the right pin
    LPC_GPIO1->GPIOnIE = ..      //Set up falling or rising edge 
    NVIC_EnableIRQ(PIO_1);       //Call API to enable interrupt in NVIC
    NVIC_SetPriority(PriorityN); //Set priority if needed
}


/*Must have the same name as listed in start-up file startup_LPC11xx.s */
void PIOINT1_IRQHandler(void){
   //Do something here
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.