CAN Interrupt
Edit this on GitLab
CAN Interrupt
Explanation
About CAN Interrupt Sample Application Code
This sample application demonstrates how to perform an interrupt when a single channel receives a CAN message using North Atlantic Industries' (NAI) System Software Kit (SSK). The code also manages multiple interrupts simultaneously, queries user inputs regarding edge trigger values, and handles offboard interrupts. The program uses various functions from the naibrd
library for these configurations and operations.
File and Library Inclusions
The application includes several libraries:
- Standard Libraries: stdio.h
, stdlib.h
, string.h
, time.h
for standard input/output, memory management, string manipulation, and time functions.
- NAI-Specific Libraries: These libraries provide method calls to interact with the NAI board and CAN modules such as nai_can_int.h
, nai_can_cfg.h
, and other common sample program include files specific to NAI applications.
- NAI Board Library files: These include nai.h
and naibrd.h
, which contain functions specific to NAI boards.
- Module-Specific NAI Board Library files: For CAN functionalities, functions/naibrd_can.h
is included.
Application Configuration
The configuration file used for this application is specified by static const int8_t *CONFIG_FILE = "default_CAN_Interrupt.txt";
.
Function Prototypes
Run_CAN_Interrupt()
is the primary internal function for managing CAN interrupts.
Main Routine
Overview
The main routine facilitates access to the NAI board and configures the CAN module for interrupt handling. It calls several predefined routines from the nai_sys_cfg.c
file for configuration.
Steps
-
Initialization and Configuration:
-
The CAN and interrupt configurations are initialized using
initializeCANConfigurations
andinitializeInterruptConfigurations
. -
The
naiapp_RunBoardMenu
function is used to start the board menu configuration withCONFIG_FILE
.
-
-
User Interaction and Configuration:
-
The user is queried for the card index, and module number through
naiapp_query_CardIndex
andnaiapp_query_ModuleNumber
. -
If a valid module is detected,
Run_CAN_Interrupt()
function is called.
-
-
Running CAN Interrupt:
-
Run_CAN_Interrupt()
manages the full process of configuring and handling CAN interrupts, as elaborated below.
-
-
Exiting Program:
-
After running the main loop, the user is prompted to exit, and all accessed cards are closed using
naiapp_access_CloseAllOpenCards()
.
-
Run_CAN_Interrupt Function
Overview
The Run_CAN_Interrupt
function handles all the major steps required to set up and process CAN interrupts as described in the NAI SSK Quick Guide(Interrupts).
Detailed Steps
-
Query User Inputs:
-
The function queries the user for the channel range, interrupt trigger type (edge level), prompt for clearing interrupts, onboard/offboard interrupts, display data option, and interrupt steering type.
-
-
Set Up Interrupt Handling:
-
An interrupt service routine (ISR) is installed using
naibrd_InstallISR
.
-
-
Enable Module Interrupts:
-
The function configures the CAN module to generate interrupts upon receiving CAN messages using functions like
naibrd_CAN_SetInterruptEdgeLevel
,naibrd_CAN_SetIntVector
,naibrd_CAN_SetInterruptSteering
, andnaibrd_CAN_SetIntEnable
.
-
-
Configure CAN Module:
-
The CAN module is configured to receive messages at the specified Baud rate with functions such as
naibrd_CAN_SetBitTiming
andnaibrd_CAN_SetRxEnable
.
-
-
Interrupt Handling:
-
The function processes interrupts by managing them in a message queue and checking for mailbox status to see if interrupts occurred. Subsequently, it clears the status registers to re-arm the interrupts using
naibrd_CAN_ClearStatus
.
-
-
Clear Configurations:
-
The module configurations are cleared by disabling CAN interrupts and uninstalling the ISR using
naibrd_UninstallISR
.
-
Execution
-
The function loops until the termination condition is met, displaying messages and handling CAN interrupts based on user input and configurations.
Conclusion
This sample application demonstrates the configuration and handling of CAN interrupts using NAI’s hardware and libraries. It uses a combination of user inputs and API calls to manage complex interrupt scenarios effectively.
/**************************************************************************************************************/
/**
<summary>
The CAN_Interrupt program demonstrates how to perform an interrupt when a single channel receives
a can message. The purpose of this program is to demonstrate the method calls in the naibrd library for performing
the interrupt. More information on this process can be found in the naibrd SSK Quick Guide(Interrupts) file.
This application differs from CAN_Interrupt_Basic in that it could handle multiple interrupts at once.
It also queries the user for the edge trigger value and whether the user should be prompted to clear an interrupt.
The application also has support for offboard interrupts.
</summary>
*/
/**************************************************************************************************************/
/************************/
/* Include Declarations */
/************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
/*Common Module Specific Sample Program include files*/
#include "nai_can_int.h"
#include "nai_can_cfg.h"
/* Common Sample Program include files */
#include "include/naiapp_interrupt.h"
#include "include/naiapp_interrupt_ether.h"
#include "include/naiapp_boardaccess_menu.h"
#include "include/naiapp_boardaccess_query.h"
#include "include/naiapp_boardaccess_access.h"
#include "include/naiapp_boardaccess_display.h"
#include "include/naiapp_boardaccess_utils.h"
/* naibrd include files */
#include "nai.h"
#include "naibrd.h"
/* Module Specific NAI Board Library files */
#include "functions/naibrd_can.h"
/********************/
/* Application Name */
/********************/
static const int8_t *CONFIG_FILE = (int8_t *)"default_CAN_Interrupt.txt";
/********************************/
/* Internal Function Prototypes */
/********************************/
static bool_t Run_CAN_Interrupt();
/**************************************************************************************************************/
/***** Main Routine *****/
/**************************************************************************************************************/
/**************************************************************************************************************/
/**
<summary>
The main routine assists in gaining access to the board.
The following routines from the nai_sys_cfg.c file are
called to assist with accessing and configuring the board.
- ConfigDevice
- DisplayDeviceCfg
- GetBoardSNModCfg
- CheckModule
</summary>
*/
/*****************************************************************************/
#if defined (__VXWORKS__)
int32_t CAN_Interrupt(void)
#else
int32_t main(void)
#endif
{
bool_t stop = FALSE;
int32_t cardIndex;
int32_t moduleCnt;
int32_t module;
int8_t inputBuffer[80];
int32_t inputResponseCnt;
initializeCANConfigurations(0, 0, 0, 0, 0, 0, NAI_J1939_MAX_DATA_LEN, 1, NAI_CAN_500K_BAUD);
initializeInterruptConfigurations(FALSE, FALSE, FALSE, 0, 0, 0, 0);
if (naiapp_RunBoardMenu(CONFIG_FILE) == TRUE)
{
while (stop != TRUE)
{
/* Query the user for the card index */
stop = naiapp_query_CardIndex(naiapp_GetBoardCnt(), 0, &cardIndex);
inputCANConfig.cardIndex = cardIndex;
if (stop != TRUE)
{
check_status(naibrd_GetModuleCount(cardIndex, &moduleCnt));
/* Query the user for the module number */
stop = naiapp_query_ModuleNumber(moduleCnt, 1, &module);
inputCANConfig.module = module;
if (stop != TRUE)
{
inputCANConfig.modid = naibrd_GetModuleID(cardIndex, module);
if ((inputCANConfig.modid != 0))
{
Run_CAN_Interrupt();
}
}
}
printf("\nType Q to quit or Enter key to restart application:\n");
stop = naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
}
}
printf("\nType the Enter key to exit the program: ");
naiapp_query_ForQuitResponse(sizeof(inputBuffer), NAI_QUIT_CHAR, inputBuffer, &inputResponseCnt);
naiapp_access_CloseAllOpenCards();
return 0;
}
/**************************************************************************************************************/
/**
<summary>
This function is broken into the following major steps. These steps correspond with the steps provided
in the naibrd SSK Quick Guide(Interrupts) file.
2. Bus Interrupt Handling - Install ISR
API CALLS - naibrd_InstallISR
3. Enable Module Interrupts- Configures module to interrupt when channel receives CAN message.
API CALLS - naibrd_CAN_SetInterruptEdgeLevel, naibrd_CAN_SetIntVector, naibrd_CAN_SetInterruptSteering, naibrd_CAN_SetIntEnable
4. Configure Module to Cause Rx Interrupt - sets the BAUD Rate to 1mbit/s (CAN AB) or 500k bits/s (CAN J1939) as definted in nai_can_utils.h
It also enables the particular channel on the module to receive can messages
API CALLS - naibrd_CAN_SetBitTiming , naibrd_CAN_SetRxEnable
5. Show Interrupt Handling - Check the mailbox to see if any interrupts occurred.
6. Re-arming Interrupts - Clear the status register to allow interrupts to occur again. This is done by writing to the status register.
In this program, we use an API call to do this.
API CALLS - naibrd_CAN_ClearStatus
7. Clear Module Configurations
API CALLS - naibrd_CAN_SetRxEnable
8. Clear Board Configurations
API CALLS - naibrd_UninstallISR
</summary>
*/
/**************************************************************************************************************/
static bool_t Run_CAN_Interrupt()
{
bool_t bQuit = FALSE;
int32_t minChannel;
int32_t maxChannel;
minChannel = 1;
maxChannel = naibrd_CAN_GetChannelCount(inputCANConfig.modid);
/* Query for Channels to Operate on */
bQuit = naiapp_query_ForChannelRange(&inputCANConfig.minChannel,&inputCANConfig.maxChannel,minChannel,maxChannel);
/* Query for Trigger Status of interrupts */
if(!bQuit)
{
bQuit = GetCANLatchStatusTriggerMode(&inputInterruptConfig.interrupt_Edge_Trigger);
}
/* Query user if they'd like to be prompted for clearing interrupts */
if(!bQuit){
bQuit = QueryUserForClearingInterruptPrompts(&inputInterruptConfig.bPromptForInterruptClear);
}
if(!bQuit){
bQuit = QueryUserForOnboardOffboardInterrupts(&inputInterruptConfig.bProcessOnboardInterrupts);
}
/* Query user if they'd like to display fifo data after interrupt */
if(!bQuit)
{
bQuit = QueryUserForDisplayingData(&inputInterruptConfig.displayData);
}
/* Query user for location interrupt will be sent out to */
if(!bQuit)
{
bQuit = GetIntSteeringTypeFromUser(&inputInterruptConfig.steering);
}
if (!bQuit)
{
if(inputInterruptConfig.displayData)
fifoDataFile = stdout;
else
fifoDataFile = fopen("fifoData.txt","w+");
/**** 2. Implement Bus Interrupt Handling ****/
setIRQ(inputInterruptConfig.steering,&inputInterruptConfig.irq);
inputInterruptConfig.cardIndex = inputCANConfig.cardIndex;
if(inputInterruptConfig.bProcessOnboardInterrupts == TRUE)
{
check_status(naibrd_InstallISR(inputInterruptConfig.cardIndex,inputInterruptConfig.irq,(nai_isr_t)IntOnboardIsr,NULL));
}
else
{
check_status(naibrd_InstallISR(inputInterruptConfig.cardIndex,inputInterruptConfig.irq, (nai_isr_t)IntOffboardIsr, (void*)&inputCANConfig.cardIndex));
}
/****3. configure Module to perform interrupts ****/
configureCANToInterruptOnRx(inputInterruptConfig,inputCANConfig);
/****4. Configure Module to cause Interrupts ****/
Cfg_Rx_CAN(inputCANConfig);
/****Initialize Message Queue ****/
InitInterruptAppThread(ONBOARD_INT, 0);
nai_msDelay(10);
UpdateThreadState(RUN);
/****Enable Interrupts****/
enableCANInterrupts(inputCANConfig,TRUE);
/***5. Show Interrupt Handling (contains step 6) ***/
canIntProcessFunc = handleCANInterrupt;
/***Request user triggers interrupt ***/
DisplayMessage_CANInterrupt(MSG_USER_TRIGGER_CAN_INT);
/****Wait on program threads****/
while (!isThreadStateTerminated()){}
bQuit = TRUE;
if(!inputInterruptConfig.displayData)
fclose(fifoDataFile);
/*****7. Clear Module Configurations*****/
enableCANInterrupts(inputCANConfig,FALSE);
/*****8. Clear Board Configurations *****/
check_status(naibrd_UninstallISR(inputInterruptConfig.cardIndex));
}
return bQuit;
}