[Źródło: https://www.nxp.com]
Program:
Na samym początku należy uruchomić port wraz z przyporządkowanym do niego przerwaniem. Przykład zawiera obsługę 10 pinów wejściowych. Przerwania uruchomione na zbocze opadające oraz rosnące.
- void UstawWejscia()
- {
- NVIC_DisableIRQ(EINT3_IRQn);
- F_PORT_WE_01->FIODIR &= ~F_PIN_WE_01;
- F_PORT_WE_02->FIODIR &= ~F_PIN_WE_02;
- F_PORT_WE_03->FIODIR &= ~F_PIN_WE_03;
- F_PORT_WE_04->FIODIR &= ~F_PIN_WE_04;
- F_PORT_WE_05->FIODIR &= ~F_PIN_WE_05;
- F_PORT_WE_06->FIODIR &= ~F_PIN_WE_06;
- F_PORT_WE_07->FIODIR &= ~F_PIN_WE_07;
- F_PORT_WE_05->FIODIR &= ~F_PIN_WE_05;
- F_PORT_WE_06->FIODIR &= ~F_PIN_WE_06;
- F_PORT_WE_07->FIODIR &= ~F_PIN_WE_07;
- F_PORT_WE_08->FIODIR &= ~F_PIN_WE_08;
- F_PORT_WE_09->FIODIR &= ~F_PIN_WE_09;
- F_PORT_WE_10->FIODIR &= ~F_PIN_WE_10;
- PINSEL_CFG_Type PinCfg;
- // Inicjalizacja przerwania HID OBECNOŚĆ KARTY
- PinCfg.Funcnum = PINSEL_FUNC_0;
- PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
- PinCfg.Pinmode = 0;
- PinCfg.Portnum = F_PORT_WEJSC_0_NR;
- PinCfg.Pinnum = F_PIN_WE_01_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = F_PIN_WE_02_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = F_PIN_WE_07_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = F_PIN_WE_08_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = F_PIN_WE_09_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Pinnum = F_PIN_WE_10_NR;
- PINSEL_ConfigPin(&PinCfg);
- LPC_GPIOINT->IO0IntEnF &= ~0x3F0;
- LPC_GPIOINT->IO0IntEnR &= ~0x3F0;
- LPC_GPIOINT->IO0IntEnR |= F_PIN_WE_01;
- LPC_GPIOINT->IO0IntEnF |= F_PIN_WE_01;
- LPC_GPIOINT->IO0IntEnR |= F_PIN_WE_02;
- LPC_GPIOINT->IO0IntEnF |= F_PIN_WE_02;
- LPC_GPIOINT->IO0IntEnR |= F_PIN_WE_07;
- LPC_GPIOINT->IO0IntEnF |= F_PIN_WE_07;
- LPC_GPIOINT->IO0IntEnR |= F_PIN_WE_08;
- LPC_GPIOINT->IO0IntEnF |= F_PIN_WE_08;
- LPC_GPIOINT->IO0IntEnR |= F_PIN_WE_09;
- LPC_GPIOINT->IO0IntEnF |= F_PIN_WE_09;
- LPC_GPIOINT->IO0IntEnR |= F_PIN_WE_10;
- LPC_GPIOINT->IO0IntEnF |= F_PIN_WE_10;
- LPC_GPIOINT->IO0IntClr |= F_PIN_WE_01 | F_PIN_WE_02 | F_PIN_WE_07| F_PIN_WE_08 | F_PIN_WE_09 | F_PIN_WE_10;
- //---------------------------------------------
- PinCfg.Funcnum = PINSEL_FUNC_0;
- PinCfg.OpenDrain = PINSEL_PINMODE_NORMAL;
- PinCfg.Pinmode = 0;
- PinCfg.Portnum = F_PORT_WEJSC_2_NR;
- PinCfg.Pinnum = F_PIN_WE_03_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Portnum = F_PORT_WEJSC_2_NR;
- PinCfg.Pinnum = F_PIN_WE_04_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Portnum = F_PORT_WEJSC_2_NR;
- PinCfg.Pinnum = F_PIN_WE_05_NR;
- PINSEL_ConfigPin(&PinCfg);
- PinCfg.Portnum = F_PORT_WEJSC_2_NR;
- PinCfg.Pinnum = F_PIN_WE_06_NR;
- PINSEL_ConfigPin(&PinCfg);
- LPC_GPIOINT->IO2IntEnF |= F_PIN_WE_03 | F_PIN_WE_04 | F_PIN_WE_05 | F_PIN_WE_06;
- LPC_GPIOINT->IO2IntEnR |= F_PIN_WE_03 | F_PIN_WE_04 | F_PIN_WE_05 | F_PIN_WE_06;
- LPC_GPIOINT->IO2IntClr |= F_PIN_WE_03 | F_PIN_WE_04 | F_PIN_WE_05 | F_PIN_WE_06;
- NVIC_SetPriority(EINT3_IRQn, 0);
- NVIC_EnableIRQ(EINT3_IRQn);
- }
Teraz należy stworzyć nowe zadanie, które będzie wyzwalane po wygenerowaniu przerwania:
- static xTaskHandle inputInterTaskHandle = NULL;
- //...
- xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( unsigned long ) );
- if( xQueue != NULL )
- {
- xTaskCreate( prvQueueInputInterruptTask,( signed char * )"INTERRUPT_TASK", configMINIMAL_STACK_SIZE, NULL ,configQUEUE_ISR_TASK_PRIORITY, &inputInterTaskHandle);
- vTaskStartScheduler();
- }
Do zadania przypisujemy między-innymi funkcję wykonywaną po otrzymaniu przerwania oraz zmienną przechowującą parametry tego zadania.
Teraz funkcja IRQ Handler:
- void EINT3_IRQHandler(void)
- {
- checkPinEnterInterrupt_Port_0(LPC_GPIOINT, F_PIN_WE_01);
- checkPinEnterInterrupt_Port_0(LPC_GPIOINT, F_PIN_WE_02);
- checkPinEnterInterrupt_Port_0(LPC_GPIOINT, F_PIN_WE_07);
- checkPinEnterInterrupt_Port_0(LPC_GPIOINT, F_PIN_WE_08);
- checkPinEnterInterrupt_Port_0(LPC_GPIOINT, F_PIN_WE_09);
- checkPinEnterInterrupt_Port_0(LPC_GPIOINT, F_PIN_WE_10);
- checkPinEnterInterrupt_Port_2(LPC_GPIOINT, F_PIN_WE_03);
- checkPinEnterInterrupt_Port_2(LPC_GPIOINT, F_PIN_WE_04);
- checkPinEnterInterrupt_Port_2(LPC_GPIOINT, F_PIN_WE_05);
- checkPinEnterInterrupt_Port_2(LPC_GPIOINT, F_PIN_WE_06);
- LPC_GPIOINT->IO0IntClr |= F_PIN_WE_01 | F_PIN_WE_02 | F_PIN_WE_07| F_PIN_WE_08 | F_PIN_WE_09 | F_PIN_WE_10;
- LPC_GPIOINT->IO2IntClr |= F_PIN_WE_03 | F_PIN_WE_04 | F_PIN_WE_05 | F_PIN_WE_06;
- portBASE_TYPE checkIfFieldRequired = xTaskResumeFromISR(inputInterTaskHandle);
- portCLEAR_INTERRUPT_MASK_FROM_ISR(checkIfFieldRequired);
- }
Na początku sprawdzam, który pin wygenerował przerwanie po czym czyszczę flagi informujące o jego wygenerowaniu.
Główne zadanie sprawdzające przerwanie zostaje wyprowadzone ze stanu zawieszania za pomocą funkcji xTaskResumeFromISR. Po czym następuje wyczyszczenie wygenerowanego przerwania dla FreeRtos.
- static void prvQueueInputInterruptTask(void *pvParameters)
- {
- (void)pvParameters;
- while(1)
- {
- vTaskSuspend(NULL);
- PrepareActionsForSpecificInput();
- }
- }
W głównej funkcji vTaskSuspend(NULL); utrzymuje funkcje w stanie zawieszenia do momentu jej wybudzenia. Dojście do funkcji głównej PrepareActionsForSpecificInput następuje dopiero wyzwoleniu zadania w funkcji przerwania.