Статьи

Пользовательское прерывание на выводе NMI с компонентом Kinetis и ExtInt

Пока моя говяжья грудинка (см. « Моя первая домашняя копченая говяжья грудинка : день 1 ») курит ;-), у меня есть время для изучения проблемы, с которой я столкнулся в своей лекции в пятницу: щит Джойстика (см. « JoyStick»). Щит с платой FRDM “) на плате FRDM-KL25Z, я хотел использовать прерывание, если я нажимаю зеленую кнопку:

Нет прерываний для кнопки C

Нет прерываний для кнопки C

Однако это не сработало :-(.

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

Смена контактов кнопки C

Смена контактов кнопки C

Но нет прерывания для кнопки C :-(. И это работало для всех остальных контактов, которые имеют возможность прерывания. Так что может быть не так?

Во-первых, я должен отметить, что этот вывод находится на PTA4 на плате Freescale FRDM-KL25Z. PTA4 используется по умолчанию как NMI (вывод без прерывания). Я настроил его в Processor Expert с компонентом ExtInt (Внешнее прерывание):

ExtInt на PTA4

ExtInt на PTA4

Поскольку PTA4 по умолчанию настроен на прерывание NMI, я правильно отключил NMI в компоненте CPU:

Функция NMI отключена в компоненте ЦП

Функция NMI отключена в компоненте ЦП

У меня есть компоненты ExtInt для нескольких выводов порта A (PTA12, PTA4, PTA5 и PTA13), и все они правильно подключены к подпрограмме обслуживания прерываний Cpu_ivINT_PORTA и вектору прерываний:

PE_ISR(Cpu_ivINT_PORTA)
{
  ExtIntLdd2_Interrupt();              /* Call the service routine */
  ExtIntLdd3_Interrupt();              /* Call the service routine */
  ExtIntLdd4_Interrupt();              /* Call the service routine */
  ExtIntLdd5_Interrupt();              /* Call the service routine */
}

Таким образом, я полагаю, что, возможно, обнаружил ошибку Processor Expert? Каким-то образом мой компонент PTA4 ExtInt вступает в конфликт с настройками вектора внутреннего прерывания NMI. В результате мое пользовательское прерывание PTA4 не срабатывает :-(.

Я нашел хотя бы способ, как заставить его работать. Для этого я добавляю компонент Init_GPIO в свой проект и настраиваю его для создания прерывания для PTA4:

Init_GPIO Настройки для включения прерывания на PTA4

Init_GPIO Настройки для включения прерывания на PTA4

Теперь, когда мой вектор PORTA_OnInterrupt () используется для вектора прерывания, мне нужно направить его в обработчик в Cpu.c:

void PORTA_OnInterrupt(void) {
  void Cpu_ivINT_PORTA(void); /* prototype of ISR in Cpu.c */
 
  Cpu_ivINT_PORTA(); /* call interrupt handler created by the ExtInt components */
}

Cpu_ivINT_PORTA (), сгенерированный процессором Expert в Cpu.c:

PE_ISR(Cpu_ivINT_PORTA)
{
  ExtIntLdd2_Interrupt();              /* Call the service routine */
  ExtIntLdd3_Interrupt();              /* Call the service routine */
  ExtIntLdd4_Interrupt();              /* Call the service routine */
  ExtIntLdd5_Interrupt();              /* Call the service routine */
}

Это вызывает прерывание NMI, как это

void ExtIntLdd3_Interrupt(void)
{
  /* {Default RTOS Adapter} ISR parameter is passed through the global variable */
  ExtIntLdd3_TDeviceDataPtr DeviceDataPrv = INT_PORTA__DEFAULT_RTOS_ISRPARAM;
 
  /* Check if the component is disabled */
  if (!DeviceDataPrv->UserEnabled) {
    return;
  }
  /* Call OnInterrupt event */
  ExtIntLdd3_OnInterrupt(DeviceDataPrv->UserData);
}

Обратите внимание, что этот код * не * подтверждает флаг ISR. Затем он вызывает следующий обработчик:

void ExtIntLdd3_OnInterrupt(LDD_TUserData *UserDataPtr)
{
  (void)UserDataPtr;                   /* Parameter is not used, suppress unused argument warning */
  SW3_OnInterrupt();                   /* Invoke OnInterrupt event */
}

При этом мне нужно обработать подтверждение флага прерывания в моем SW3_OnInterrupt ():

void SW3_OnInterrupt(void)
{
#if PL_HAS_KBI
#if 1 /* Problem with Processor Expert and sharing PTA4/NMI interrupt: code below is missing in ExtIntLdd3_OnInterrupt() */
  /* Check the pin interrupt flag of the shared interrupt */
  if (PORT_PDD_GetPinInterruptFlag(PORTA_BASE_PTR, ExtIntLdd3_PIN_INDEX)) {
    /* Clear the interrupt flag */
    PORT_PDD_ClearPinInterruptFlag(PORTA_BASE_PTR, ExtIntLdd3_PIN_INDEX);
    /* call user event */
    KEY_OnInterrupt(KEY_BTN3);
  }
#else
  if (KEY3_Get()) {
    KEY_OnInterrupt(KEY_BTN3);
  }
#endif
#endif
}

С этим все работает 🙂

Резюме

Можно отключить и предопределенные прерывания, такие как NMI для Kinetis. Однако это может конфликтовать с настройками ЦП по умолчанию (или является ошибкой в ​​Processor Expert). В любом случае, я нашел решение, чтобы оно заработало:

  1. Используйте компонент Init_GPIO, чтобы разрешить прерывания в PORTA с пользовательским обработчиком.
  2. Направьте прерывания из пользовательского обработчика в обработчик компонента ЦП.

Счастливое прерывание 🙂