Tutorial: User Interrupts with Processor Expert

I have been asked this question several times:

“How can I define my own interrupt vector with Processor Expert?”

So I think it deserves a short tutorial, if more than one person is asking this ;-).

My user interrupt in the vector table

My user interrupt in the vector table

Interrupts in Processor Expert: Vectors.c

If you are using an interrupt device (SPI, I2C, USB, etc), then Processor Expert cares about it. Processor Expert maintains the vector table But if I want to hook into an interrupt vector myself, I need to tell Processor Expert that. The interrupt vector table is generated as ‘vectors.c’ in the Generated_Code folder.

❗ I’m using in this post screenshots from the newly released Processor Expert V10.4 version, but things apply to earlier versions too. I’m using here an ARM project (Kinetis KL02Z), but things are pretty the same for any other architecture supported by Processor Expert. Additionally, I’m *not* using the Kinetis SDK here, as the way how the SDK deals with interrupts is a different thing, and only would apply to Kinetis.

Vectors.c in Generated_Code Folder

Vectors.c in Generated_Code Folder

InterruptVector Component

There is a component in the Components Library where I can hook my interrupt into the vector table:

InterruptVector Component in Components Library

InterruptVector Component in Components Library

That component does nothing else than let me overwrite the interrupt vector in the vector table. So if I add that component, I can configure it to use my interrupt routine. For example if I want to map the Interrupts on port B to my handler, I only need to specify the interrupt and my function name:

InterruptVector Component Properties

InterruptVector Component Properties

Then I only need to add that interrupt handler (MyIRQ() in my example) and that’s it.

Oh, wait: how to define other properties for that interrupt? I mean I usually can configure to create an interrupt on PortB pin 7 on a falling edge, etc?

The answer is: either I configure all these settings in my code (setting the ‘trigger on’ flags, …), or I use a different component: the Init_GPIO one.

Init_GPIO Component

If I want to configure a pin to create an interrupt on a specific event, I can use the Init_GPIO component found in the Components Library:

Init_GPIO Component in Components Library

Init_GPIO Component in Components Library

Once I have added this component to my project, I specify the port and pin to be enabled and initialized:

PTB7 Interrupt on Falling Edge

PTB7 Interrupt on Falling Edge

💡 Here I can configure other properties like direction and pull resistor of the pin.

To enable the interrupt and to give my user interrupt function name, I do this in the ‘Interrupts’ section:

Port Interrupt Settings

Port Interrupt Settings

Interrupt Code

What is missing is now my interrupt function in my application. An (empty) example would be like this:

void MyIRQ(void) {
  /* my interrupt code here */
}

ExtInt Component

Another way is to use the ExtInt Component for external interrupts:

ExtInt Component in Components Library View

ExtInt Component in Components Library View

The ExtInt component offers methods and events I can use in my application:

ExtInt Component Methods and Events

ExtInt Component Methods and Events

In the properties, I configure the interrupt pin and on which edge/level it shall generate an interrupt:

ExtInt Component Poperites

ExtInt Component Poperites

The interrupt itself gets handled in the component itself: all what I need to do is to fill out my user code in the Events.c module:

ExtInt OnInterrupt Callback

ExtInt OnInterrupt Callback

Summary

Processor Expert takes care about the interrupt vectors and vector table. To define my own interrupts, I can use the InterruptVector component which allows me to add my function name to the vector table. If I want to use interrupts with general purpose I/O pins and want to configure properties like pull-resistors, then the preferred way is to use the Init_GPIO component. The ExtInt component on the other side is a convenient way to act on external interrupt and to configure the interrupt properties.

Happy Vectoring 🙂

 

Advertisements

49 thoughts on “Tutorial: User Interrupts with Processor Expert

  1. Hi Erich,

    I am using the same version of processor expert than you with codewarrior for the frdm kl25z, however in the componente library not appear the InterruptVector component. But, the ExtInt appears!
    I’ve updated the software!

    Like

    • Hi Matheus,
      yes, that depends on the CPU/architecture. There is the InterruptVector component which allows you to hook into any interrupt vector. There is the ExtInt component which allows you to use any interrupt pin (so this is a subset of all interrupts).

      Erich

      Like

  2. I use a KL15. On my project only pins on PTA and PTD are available for EInt component. Why? I would like to also use PTB, PTC or PTE. Is that possible? How do I configure it?
    Thank you!
    Gil

    Like

  3. Hi again,

    I’m doing a project where I get data from an accelerometer with kl25z. The sampling rate of the accelerometer is 640 hz. I’m using FreeRTOS, where there is a specific task to receive data from the accelerometer. There are other tasks, but do not seem to affect anything, because the problem happens in the job itself.
    There is only one task with higher priority than the task that reads the accelerometer. The accelerometer generates a high signal on an interrupt pin when data is sampled, and low when the data are read. Basically, the task reads the samples of accelerometer for 2 seconds and then waits for 3 seconds, parallel with other tasks. In an oscilloscope, it can be seen that in the interrupt pin during 2 seconds, a square wave of approximately 640 Hz occurs. In the 3 seconds should read a low value. Observing the oscilloscope, it almost happens … But at a random moment, the value of this pin goes high during the 3 seconds. When this occurs, the program gets stuck at the task awaiting the flag that is set in ISR interrupt. It seems that interrupt dont recognized the rising edge at some point! this can be a hardware issue?

    Like

      • I am not using the RTOS API in the ISRs, I am testing another aplication that send a ramp function to pc via UART, Assynchronous Serial component. The firmware waits for a character from pc to begin send data! But a weird thing happens and I think it’s related with the another problem. One task waits the pc response with that:

        while (res != ‘a’)
        UART0_RecvChar(&res);

        Setting the Interrupt RXD priority with 2 (medium) with ARM priority scheme and the task with priority of 2, FreeRTOS scheme, the program awaits a flag that never comes. But, when I set the task priority to 1, the program receive the char!

        How I know the relantionship beetween the ARM priorities and the FreeRTOS tasks priorites?

        Like

      • The RTOS (and the tasks) run with the configLIBRARY_LOWEST_INTERRUPT_PRIORITY (‘RTOS Interrupt Priority’ in the component settings). Usually this should be the lowest (hardware) interrupt priority of your system. On ARM cores: the higher the number, the lower the interrupt priority. If you are using an Freescale Kinetis M4, then this would be 15, for a M0+ this would be 3. The SysTick interrupt runs with this lowest priority, and therefore the tasks too. Inside that, the RTOS has its own task priorities: and here the higher the numbers, the higher the priority.
        I hope this helps.

        Like

      • It helps! I think that configLIBRARY_LOWEST_INTERRUPT_PRIORITY is just for define what task can set a priority! I think that the kernel priority was defined in configKERNEL_INTERRUPT_PRIORITY!
        I will continue in my task!!! 😛
        Thanks very much!

        Like

      • Hi again Erich!

        Sorry for bothering you again, but I need to solve the accelerometer problem.
        I will be more precise in my explanation now!
        The interrupt generated by the accelerometer is connected to pin PTD4 with maximum priority (0), active on rising edge. In this ISR interrupt, a flag is set one!
        The kernel was configured with the lower priority (3). A task kernel compares if the value of the flag is set to be able to continue!
        However, the task gets stuck in that sentence!
        What would be the reason for a higher priority, external interrupt does not occur?

        Thanks

        Like

  4. Erich,

    The way I understand it, I can set one single ISR for a whole port – which is, one function for all pins in that port. Assuming I have multiple pins in that port, and I want interrupts raised for each of them, how can I find out which one triggered my ISR?

    Thanks,
    Cristian.

    Like

  5. Hi Erich,

    I’m new to Processor Expert, and this is probably a stupid question, but I’m not sure where to put my Interrupt Code, if I enable the Interrupt on a GPIO Pin.

    Thanks,
    Jamin

    Like

    • Hi Jamin,
      well, that depends what component you are using. If using the ExtInt component, then this component has a method OnInterrupt(). Code for it gets created into Events.c, and there you can add your code. Processor Expert will set up the vector table for you, it will call the interrupt service routine inside the ExtInt component and will call your OnInterrupt() method in Events.c.

      I hope that makes sense and helps,
      Erich

      Like

      • Thank you!
        If I use the ExtInt everything works fine 🙂

        But if I’m trying to use the Init_GPIO Component from the Components Library, Processor Expert will set up the vector table as well, but I’ve to call the interrupt service routine and create a MyIRQ methode, (correct?)
        And I don’t know where I’ve to call the IRS and put that methode.

        Like

      • Hi Jamin,
        if using the Init_GPIO component, enable the interrupts for the port (Interrupts > Port interrupt > Enable). There specify an ISR name (e.g. MyPORTA_ISR). If you generate code, it will add that MyPORTA_ISR entry into the vector table. All what you have to do is now to implement that function MyPORTA_ISR in your application code.

        Like

      • Hi Erich,
        Sorry for bothering you again!
        If I implement a MyPORTA_ISR Function in the main.c or in the Events.c it isn’t called correctly.
        Maybe you could send me an example, on how to implement the MyPORTA_ISR?

        Like

      • What do you mean with ‘not called correctly’? Is it called or not?
        The implemenation might look like this:
        void MyPORTA_ISR(void) {
        /* reset interrupt flag here */
        /* do whatever you need to do */
        }

        Like

    • Hy Erich,
      It is not called.
      But for now the ExtInt component is doing the job.
      Thank you for this tutorial and your support.
      Jamin

      Like

      • Hi Jamin,
        then problably some of the settings to trigger the interrupt are maybe not correct. Anyway, you have a working solution now 🙂
        Erich

        Like

  6. Hi Eric! Good tutorial. I’m to do the but to USB CDC. I noted that this olect doens’t work with USB because the FSL_USB_STACK should manage the interrupt. But it’s not working to me.
    Could you give some tips about usb interrupt?

    Like

      • Thanks Erich, I khow this tutorial (excellent too). But in this tutorial you aren’t using interrupt but pooling. You call de the rotine in the code. Does is it right?
        I would like manage the USB by interrupt.

        Like

      • Hi Julio,
        the FSL_USB_Stack is using interrupts. The interrupt will place the data into a ring buffer where data can be read from the application code (outside of the interrupt context).
        Othwerwise you should have a look at the SDK v2.0 USB stack code.
        Erich

        Like

  7. Erich,

    I wanted to issue a strong word of warning for anyone using the EXTINT component.

    In my project I did not select the “Enabled in init. code” because I did not want the interrupt to fire until after some data structures had been initialized. Later when I tried to use the Enable() function to enable the interrupt it didn’t work. But it did work if I used that init checkbox. This seemed odd so I looked at the generated code. It turns out that PE ignores the “Generate interrupt on” setting if you don’t check the init checkbox. When you call Enable() it doesn’t actually enable the interrupt. In order to get it to work you have to first call SetEdge(). The big problem here is that SetEdge() actually enables the interrupt all on its own BUT it doesn’t set the UserEnabled flag to true. This means that the interrupt is allowed to fire but the component ISR ignores it and thus doesn’t clear the interrupt. Now your system is stuck. Very very bad.

    The SetEdge function needs to be modified to verify that UserEnabled is true before configuring/enabling the interrupt. Otherwise it should only update the private IrqConfig variable with the new setting. Then the Enable() function can subsequently be called to update the UserEnabled flag and configure/enable the interrupt.

    This leads me to another concern. In the Enable() function, the UserEnabled flag is set AFTER the interrupt is enabled. Since interrupts aren’t forced to be globally disabled, this can potentially lead to the same lockup situation described above.

    Eric

    Like

    • Hi Eric,
      I think I have used that component always with ‘enabled in init’, so I was lucky not to see what you describe. I have checked the implementation on a K64F, but here in the ExtIntLdd1_Enable() it *does* configure the edge:
      PORT_PDD_SetPinInterruptConfiguration(PORTC_BASE_PTR,
      ExtIntLdd1_PIN_INDEX, PORT_PDD_INTERRUPT_ON_RISING);
      So it might be a difference with the microcontroller or Processor Expert version you are using. However, I see the same problem with the UserEnabled flag which can lead to a problem ;-(.

      As for what you want to accomplish: I did something similar what you wanted, but this way:
      – Enabled in Init code is turned on
      – In the CPU settings, I have interrupts turned off. So that the PE_Low_Level_Init() does not enable interrupts before jumping to main().
      – in main then I have interrupts disabled. Here I could disable as well the ExtInt interrupts if I like to have them turned on later on.
      – then turn on interrupts (EnableInt() of CPU component)

      that might be a better approach for you too?

      Erich

      Like

      • Erich,

        It’s intriguing that the two implementations are different. I’m using KDS 3.2 to design for a MKL16 on a custom board.

        In ExtIntLdd4_Enable() I see this:
        PORT_PDD_SetPinInterruptConfiguration(PORTC_BASE_PTR, ExtIntLdd4_PIN_INDEX, DeviceDataPrv->IrqConfig);

        The problem is that ExtIntLdd4_Init() does this:
        DeviceDataPrv->IrqConfig = PORT_PDD_INTERRUPT_DMA_DISABLED;

        Thanks for you suggestion. I wasn’t able to find an explicit setting in the CPU component to globally disable interrupts. Are you accomplishing this by inserting code into “Build Options->User Initialization->User code before PE initialization”?

        Thanks!
        Eric

        Like

      • Eric,

        I tried using the search you referenced. Interestingly it does not work in KDS 3.2.0. I click on the search result and it does not jump to the component setting. It seems to work fine in my old Kepler-based IDE I built using your guide. I tested this using “?LL” query in your post.

        That being said, even in my old IDE, the “Initialization priority” does not seem to have a result and I can’t find it it in the list. I even tried creating a K64F project (to match you) and still didn’t have any success. I did make sure I’m using the “Advanced” filter.

        I can work around it without this setting but I find it intriguing that there seems to be a discrepancy in settings we both have available.

        Eric

        Like

      • Erich,

        Well I feel sheepish now. I’m using tabs view but you have to click the “All” option at the top of the properties box to see this setting. It isn’t called out explicitly like the other settings. In classic view is very prominent.

        Thanks for your help!
        Eric

        Like

  8. Hello Erich,

    I am working with some asynchronous interrupts and one of them is the uart interrupt which has the smaller prioriy, so I am worried about not receving any message from the uart. Also I am worried about the lecture of the ADC. Is there any way to control this asynchronous interruption events?

    Thanks for all,
    Iñaki

    Like

    • Hi Iñaki,
      I assume you are working with an ARM Cortex type microcontroller? In that case, you need to make sure that the priority of the UART (and ADC) are high enough soe they are not blocked (too much interrupt latency). For the UART (AsynchroSerial) there is in the component a ring buffer (send and receive buffer size): they are ring buffers, filled by the interrupt. So if your UART interrupt is high engough, it will fill in the Rx characters regardless what other things are running, up to the buffer size. Usually I have the buffer size say 64 characters long.
      About the ARM Cortex-M interrupt system: I wrote a series of articles about it (towards FreeRTOS), but the same applies if you just using the hardware (and no RTOS): https://mcuoneclipse.com/2016/08/14/arm-cortex-m-interrupts-and-freertos-part-1/
      I hope this helps,
      Erich

      Like

      • Hi Erich,

        I am using the KL25Z128. The problem is that I have three interrupts to measure the cadence (r.p.m.) that have the highest priority (asynchronous interrupts). The priority is to have a good measure of the cadence (the interrupts are activated in a few ms all the time). So I am a little bit worried about not taking other interrupts like Uart, ADC, buttons of control,… How I can manage this?

        Thanks for all,
        Iñaki

        Like

      • Hi Iñaki,
        that should not be a problem:
        make your cadence interrupt(s) the highest priority. Keep these interrupt service routines as fast and small as possible.
        So if they do not block the interrupts for longer than the time for the UART to receive a character, there is no problem.
        Keep in mind that the interrupt controller on the ARM Cortex-M supports interrupt nesting (as outlined in the above article(s)), so if your UART interrupt is running with lower priority, it can be interrupted by the higher urgency ones (which is a good thing).

        Erich

        Like

      • Hi Erich,

        I was speaking with a coworker and he says the same us you are telling me. The cadence interrupts have to be as fast and small as possible, the doubt we have is that if we have an interrupt of cadence running and another interrupt (button) is activated during the interrupt of cadence is going on, that interrupt is lost? or ones the interrupt of the cadence is finished the other interrupt is done? we have to manage some interrupt flag in order to check if it is activated? I am using the Extint component for the interrupts in KL25Z.

        Thanks for all your expert help,
        Iñaki
        P.D.: My coworker is a big fan of you. He recommended my this amazing blog.

        Like

      • Hi Iñaki,
        I appologize for my late response.
        If you run a higher urgency interrupt, it will mask any lower urgent interrupts. Masking means that the masked interrupt will interrupt the already running interrupt service routine, e.g. your button interrupt. But this does not mean that the event is lost. The button interrupt hardware will set a ‘pending’ bit in the interrupt hardware for that button. And as soon as the higher urgency interrupt service routine has finished its work, it will be able to trigger the interrupt for the button. So it is not lost. However, typically there is just one bit for for each interrupt event (button, USB, UART, etc): so if there would be two button events during the higher urgency interrupt execution, then only one event/bit would be stored. So you only would have an interrupt for the first button press, but not for any more unless your interrupt service routine for the button is able to handle that first event and to set back that bit.
        I wish you could attend my lectures around nested interrupts :-).
        I hope this helps,
        Erich
        PS: Say ‘thank you to your coworker’. I will be at Embedded World in Nürnberg 14.-16. March 2017 🙂

        Like

    • Hi Erich,

      Don´t apologize, you are always so fast!
      What you have commented is very interesting i will continue reading here the nesting interrupts articles. Now I am reading the FreeRTOS but i think that we don´t needed for our application, but it is also very interesting 🙂
      I would like to go to the Embedded World in Nürnberg and speak with you (also i wish if i had had a teacher like you in the university), but i think that my boss has another point of view 🙂

      My coworker and I thanks you for this brilliant Embedded world blog 🙂
      Iñaki

      Like

  9. Hi Erich,

    I have implemented interrupt base key detection on kinetis K10 series microcontroller.
    I am facing a problem. On pressing a key, sometime device hangs and resets after watch dog timer reset.
    In ISR , semaphore is released (posted).

    Just for testing, I commented semaphore post statement and made ISR empty. Still I am facing device hang issue.

    Any guess? why this is happening?.

    Thanks and Regards,
    Rohit Khele

    Like

    • Hi Rohit,
      are you using the _FromISR() version from that ISR?
      You are only allowed to use FreeRTOS API calls with _FromISR() in the name from interrupt service routines.
      Erich

      Like

      • Hi Erich,
        Thanks for reply.

        I am using Micrium OS III.
        ISR for external interrupt PX_WEST_OnInterrupt() is call by four level fuction call as below.
        PE_ISR(PX_CPU_ivINT_PORTA) -> ExtIntLdd3_Interrupt() -> ExtIntLdd3_OnInterrupt(DeviceDataPrv->UserData) -> PX_WEST_OnInterrupt() -> PX_WEST_OnInterrupt()
        All these functions are from PE drivers for external interrupt.

        If I skip function call by 2 level and do the following way then device didn’t hang
        PE_ISR(PX_CPU_ivINT_PORTA) -> ExtIntLdd3_Interrupt() -> PX_WEST_OnInterrupt()

        Thanks,
        Rohit K

        Like

      • Hi Rohit,
        I have not used Micrium OS for a long time, and I only have used the version II (not the version III). I guess it has something to do with how Micrium OS is dealing with interrupts, but this is out of my knowledge for version III.

        Like

  10. This was pretty helpful, I’m trying to use the SPI0 in slave mode and the automatic generated code was put in Events.c as well, which was not apparent at first. Now I understand the typical usage in the help file a bit better.

    Like

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s