How to use interrupts on kinetis?

cancel
Showing results for 
Search instead for 
Did you mean: 

How to use interrupts on kinetis?

6,269 Views
GerasinIvan
Contributor II

Hi all!

I'm trying to understand how to use interrupts (k60), but unsucsessful :smileyhappy:

So, i want to use RTC interupt. and i should use "enable_irq(66)", but what should i include? And how to handle this INT, i mean, where can i write code, that will be execute on this INT?

So, questions is:

1)What headers should i include

2)How to enable INT?

3)Where is body of INT function?

Thx for help!

Tags (2)
11 Replies

538 Views
Monica
Senior Contributor III

Gerasin, was this helpful?

How is the project going? We'd like to know!

Regards!

0 Kudos

538 Views
GerasinIvan
Contributor II

I'm sorry for delay, unfortunatly i'm always forget yhat i have a questions on community.

I'm using Device Initializator in my project, and using interrupts with it are really simple. I should only wirite an interrupt code in already declareted function. But I'm still intresting how to do it without DI. Sample with rtc works, but if i'm doing the same in my project, i don't know what headers i should include.

0 Kudos

538 Views
mehdikarimibiuk
Contributor V

I have a same question.

I want to know how to activate NVIC to use spi0 interrupt.

I have a bareboard project created. I added SPI0 module. I know that PE creates "Events.c", which in it there are interrupt handlers. But I don't want to use those since using those limit me to use their generated functions only!

I just need to see how to activate NVIC interrupt and use the interrupt that corresponds to SPI0.

for example, could there be something like:

interrupt_spi0_data_received()

{

     read_data_and_put_it_in_the_queue_to_process;

}

0 Kudos

538 Views
mjbcswitzerland
Specialist V

Hi

Here is a compact answer for a bare-metal solution.

1. Enter the interrupt (place interrupt handler address in SRAM, set interrupt priority, enable interrupt in NVIC) using

fnEnterInterrupt(26, 11, interrupt_spi0_data_received);

2. Enable SPI interrupt (in peripheral so that it is asserted to the NVIC input) as well as configuring SPI peripheral generally

3. Send SPI data and handle the interrupts generated in the process. Reading the received data will clear the interrupt in your case.

The hander routine should be declared as a standard subroutine [void function(void)]

Details about fnEnterInterrupt():

- assumes interrupt table is in RAM, set by VECTOR_TABLE_OFFSET_REG = RAM_START_ADDRESS, for example to set table to start of SRAM.

- the routine accepts the ID of the interrupt in question (26 is SPI0 for K60, for example, but can change between derivates), an interrupt priority (0..15, where 0 is highest), plus a prointer to the handler.

- the code is (translate to register names in your headers if needed)

// Function used to enter processor interrupts

//

static void fnEnterInterrupt(int iInterruptID, unsigned char ucPriority, void (*InterruptFunc)(void))

{

    unsigned long *ptrIntSet = IRQ0_31_SER_ADD;

    unsigned char *ptrPriority = IRQ0_3_PRIORITY_REGISTER_ADD;

    VECTOR_TABLE *ptrVect;

    void ( **processor_ints )( void );

    ptrVect = (VECTOR_TABLE *)(RAM_START_ADDRESS);

    processor_ints = (void (**)(void))&ptrVect->processor_interrupts;

    processor_ints += iInterruptID;

    *processor_ints = InterruptFunc;

    ptrIntSet += (iInterruptID/32);

    *ptrIntSet = (0x01 << (iInterruptID%32)); // enable the interrupt

    ptrPriority += iInterruptID;

    *ptrPriority = (ucPriority << 4); // define the interrupt's priority

}

VECTOR_TABLE is defined as

typedef struct stVECTOR_TABLE

{

    RESET_VECTOR  reset_vect;

    void  (*ptrNMI)(void);

    void  (*ptrHardFault)(void);

    void  (*ptrMemManagement)(void);

    void  (*ptrBusFault)(void);

    void  (*ptrUsageFault)(void);

    unsigned long ptrReserved1[4];

    void  (*ptrSVCall)(void);

    void  (*ptrDebugMonitor)(void);

    unsigned long ptrReserved2;

    void  (*ptrPendSV)(void);

    void  (*ptrSysTick)(void);

    PROCESSOR_IRQ processor_interrupts;                                  // length is processor specific

} VECTOR_TABLE;

with

typedef struct stRESET_VECTOR

{

    void  *ptrResetSP;                                                   // initial stack pointer

    void  (*ptrResetPC)(void);                                           // initial program counter

} RESET_VECTOR;

and

// Kinetis interrupts

//

typedef struct stPROCESSOR_IRQ

{

    void  (*irq_DMA0)(void);                                             // 0

    void  (*irq_DMA1)(void);                                             // 1

    void  (*irq_DMA2)(void);                                             // 2

    void  (*irq_DMA3)(void);                                             // 3

    void  (*irq_DMA4)(void);                                             // 4

    void  (*irq_DMA5)(void);                                             // 5

    void  (*irq_DMA6)(void);                                             // 6

    void  (*irq_DMA7)(void);                                             // 7

    void  (*irq_DMA8)(void);                                             // 8

    void  (*irq_DMA9)(void);                                             // 9

    void  (*irq_DMA10)(void);                                            // 10

    void  (*irq_DMA11)(void);                                            // 11

    void  (*irq_DMA12)(void);                                            // 12

    void  (*irq_DMA13)(void);                                            // 13

    void  (*irq_DMA14)(void);                                            // 14

    void  (*irq_DMA15)(void);                                            // 15

    void  (*irq_DMA_ERROR)(void);                                        // 16

    void  (*irq_MCM)(void);                                              // 17

    void  (*irq_FLASH_CC)(void);                                         // 18

    void  (*irq_FLASH_RC)(void);                                         // 19

    void  (*irq_LOW_VOLTAGE)(void);                                      // 20

    void  (*irq_LL_wakeup)(void);                                        // 21

    void  (*irq_WDOG)(void);                                             // 22

    void  (*irq_RNGB)(void);                                             // 23

    void  (*irq_I2C0)(void);                                             // 24

    void  (*irq_I2C1)(void);                                             // 25

    void  (*irq_SPI0)(void);                                             // 26

    void  (*irq_SPI1)(void);                                             // 27

    void  (*irq_SPI2)(void);                                             // 28

    void  (*irq_CAN0_MESSAGE)(void);                                     // 29

    void  (*irq_CAN0_BUS_OFF)(void);                                     // 30

    void  (*irq_CAN0_ERROR)(void);                                       // 31

    void  (*irq_CAN0_TX)(void);                                          // 32

    void  (*irq_CAN0_RX)(void);                                          // 33

    void  (*irq_CAN0_WAKE_UP)(void);                                     // 34

    void  (*irq_CAN0_IMEU)(void);                                        // 35

    void  (*irq_CAN0_LOST_RX)(void);                                     // 36

    void  (*irq_CAN1_MESSAGE)(void);                                     // 37

    void  (*irq_CAN1_BUS_OFF)(void);                                     // 38

    void  (*irq_CAN1_ERROR)(void);                                       // 39

    void  (*irq_CAN1_TX)(void);                                          // 40

    void  (*irq_CAN1_RX)(void);                                          // 41

    void  (*irq_CAN1_WAKE_UP)(void);                                     // 42

    void  (*irq_CAN1_IMEU)(void);                                        // 43

    void  (*irq_CAN1_LOST_RX)(void);                                     // 44

    void  (*irq_UART0)(void);                                            // 45

    void  (*irq_UART0_ERROR)(void);                                      // 46

    void  (*irq_UART1)(void);                                            // 47

    void  (*irq_UART1_ERROR)(void);                                      // 48

    void  (*irq_UART2)(void);                                            // 49

    void  (*irq_UART2_ERROR)(void);                                      // 50

    void  (*irq_UART3)(void);                                            // 51

    void  (*irq_UART3_ERROR)(void);                                      // 52

    void  (*irq_UART4)(void);                                            // 53

    void  (*irq_UART4_ERROR)(void);                                      // 54

    void  (*irq_UART5)(void);                                            // 55

    void  (*irq_UART5_ERROR)(void);                                      // 56

    void  (*irq_ADC0)(void);                                             // 57

    void  (*irq_ADC1)(void);                                             // 58

    void  (*irq_CMP0)(void);                                             // 59

    void  (*irq_CMP1)(void);                                             // 60

    void  (*irq_CMP2)(void);                                             // 61

    void  (*irq_FTM0)(void);                                             // 62

    void  (*irq_FTP1)(void);                                             // 63

    void  (*irq_FTP2)(void);                                             // 64

    void  (*irq_CMT)(void);                                              // 65

    void  (*irq_RTC_ALARM)(void);                                        // 66

    void  (*reserved0)(void);                                            // 67

    void  (*irq_PIT0)(void);                                             // 68

    void  (*irq_PIT1)(void);                                             // 69

    void  (*irq_PIT2)(void);                                             // 70

    void  (*irq_PIT3)(void);                                             // 71

    void  (*irq_PDB)(void);                                              // 72

    void  (*irq_USB_OTG)(void);                                          // 73

    void  (*irq_USB_CD)(void);                                           // 74

    void  (*irq_ETH_IEEE1588)(void);                                     // 75

    void  (*irq_ETH_TX)(void);                                           // 76

    void  (*irq_ETH_RX)(void);                                           // 77

    void  (*irq_ETH_ERR_MISC)(void);                                     // 78

    void  (*irq_I2S)(void);                                              // 79

    void  (*irq_SDHC)(void);                                             // 80

    void  (*irq_DAC0)(void);                                             // 81

    void  (*irq_DAC1)(void);                                             // 82

    void  (*irq_TSI)(void);                                              // 83

    void  (*irq_MCG)(void);                                              // 84

    void  (*irq_LPT)(void);                                              // 85

    void  (*reserved1)(void);                                            // 86

    void  (*irq_PORTA)(void);                                            // 87

    void  (*irq_PORTB)(void);                                            // 88

    void  (*irq_PORTC)(void);                                            // 89

    void  (*irq_PORTD)(void);                                            // 90

    void  (*irq_PORTE)(void);                                            // 91

} PROCESSOR_IRQ;

This is valid for K60 (for example) but the exact content is not actually important for just entering interrupts.

Regards

Mark

538 Views
marciol_carleto
Contributor I

Hi Mark,

I know this is not exaclty the topic for this but I couldn´t avoid to ask for your help to solve my problem concerning Freemaster (not) communicating with a S9KEAZ128AVLH custom board of mine. I´m using S32 (no PEx), Freemaster SDK and already made it work, but only using polling method when I want (need) to use Freemaster short interrupt. Reading AN4752, page 13 says:

3. FMSTR_Isr() must be assigned to the UART3 interrupt vector. The kinetis_sysinit.c file contains
the vector table definition. Here, we can define the called FreeMASTER:
(tIsrFunc) FMSTR_Isr, /* 67 (0x0000010C) (prior: -) UART 3 status sources */
(tIsrFunc) FMSTR_Isr, /* 68 (0x00000110) (prior: -) UART 3 error sources */

In my case I´m using UART1 (thru RS232). The thing is: I don´t have the kinetis_sysinit.c file generated and don´t know where is my vector table neither how to "assign" FMSTR_Isr()  to UART1 (my case). I have searched all the community, google, etc. and didn´t find anywhere something to solve this problem. Can you help me on that?

0 Kudos

538 Views
mjbcswitzerland
Specialist V

Hi Marcio

UART1 interrupt ID is 13 (on the KEA128) so I assume you need to find the (usually hard-coded in the KDSs) vector table and insert the interrupt handler there (where there is probably a default handler at the moment).
I assume that the UART driver will then support interrupts if you set some appropriate define(?)

Below is the view of the KEA128 vectors when I simulate it after inserting a UART1 handler called SCI1_Interrupt.

pastedImage_1.png

If you have continued problems see the following for a service to quickly help you solve it
http://www.utasker.com/services.html

The uTasker project for KEA128 (also with S32 project) includes Freemaster support by setting the define FREEMASTER_UART and choosing the UART to be used with
#define FREEMASTER_UART_CH   1                                       // user UART 1 for FreeMaster via UART
and always works in interrupt driven mode, or optionally DMA mode when the processor supports DMA. It can be used with the original KDS or as native uTasker version with a few feature enhancements (such as monitoring external SPI based memory and writing to internal / external flash).
Most is included in the free open source version on Github and it allows simulating complete Freemaster operation in Visual Studio on an emulated KEA128.
Unfortunately Freescale/NXP doesn't point out that ports to (almost) all devices are available since it would save a lot of porting/development time in many projects where the same exercises in the more basic environments are (unnecessarily) repeated over and over again (costing their customers unnecessary time and money).

Regards

Mark

Kinetis: http://www.utasker.com/kinetis.html
Kinetis KEA128:
- http://www.utasker.com/kinetis/TRK-KEA128.html
- http://www.utasker.com/kinetis/FRDM-KEAZ128Q80.html
S32 Design Studio: http://www.utasker.com/kinetis/compilers.html#S32

0 Kudos

538 Views
mehdikarimibiuk
Contributor V

n/a

0 Kudos

538 Views
mjbcswitzerland
Specialist V

Hi

As I wrote you would need to translate any defines to the ones used in your environment. You will also probably find that there is a similar function for entering interrupts in the environment that you use which could be used instead.

My example is an bare-metal example of how it can be done (and is done in the uTasker environment).

Regards

Mark

0 Kudos

538 Views
mehdikarimibiuk
Contributor V

I used PE to generate the Event.c file where these events get called when their interrupt:

in Event.c:

/*

** ===================================================================

**     Event       :  SS1_OnBlockSent (module Events)

**

**     Component   :  SS1 [SPISlave_LDD]

*/

/*!

**     @brief

**         This event is called after the last character from the

**         output buffer is moved to the transmitter. This event is

**         available only if the SendBlock method is enabled.

**     @param

**         UserDataPtr     - Pointer to the user or

**                           RTOS specific data. The pointer is passed

**                           as the parameter of Init method.

*/

/* ===================================================================*/

void SS1_OnBlockSent(LDD_TUserData *UserDataPtr)

{

  printf("==========ISR event: SPI0 sent a block=========\n");

}

/*

** ===================================================================

**     Event       :  SS1_OnBlockReceived (module Events)

**

**     Component   :  SS1 [SPISlave_LDD]

*/

/*!

**     @brief

**         This event is called when the requested number of data is

**         moved to the input buffer. This method is available only if

**         the ReceiveBlock method is enabled.

**     @param

**         UserDataPtr     - Pointer to the user or

**                           RTOS specific data. The pointer is passed

**                           as the parameter of Init method.

*/

/* ===================================================================*/

void SS1_OnBlockReceived(LDD_TUserData *UserDataPtr)

{

  printf("event===========\n");

}

but as I said and as it says there, these functions are triggered only when we enable and use their ReceiveBlock and SentBlock methods.

I am not using those functions and so it is expected that I do not see those printf above. That made me to want to access NVIC directly.

Ok, I try your function and see if I can make it work.

Thanks!

0 Kudos

538 Views
JimDon
Senior Contributor III

- Include the normal headers for your part as generated by the IDE.

- You may need to enable the NVIC as well as interrupts for the module you are using. The function enable_irq ONLY enables the NVIC.

- You put the body of the interrupt handler in any file you wish. For ARM, a plain "C" function is all you need.

- For the K60, you need to place the vector into the vector table. Look in kinetis_sysinit.c there is a table where you put the address of the handler function.

0 Kudos

538 Views
santiago_gonzal
NXP Employee
NXP Employee

Hello,

You have an example of exactly what you want in:

[CodeWarrior Install Folder]\MCU\CodeWarrior_Examples\Kinetis_Examples\k60\rtc

Also the Reference Manual is a good start point to understand what registers you should set.

0 Kudos