This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GH6PM: help needed in using TIVAWARE

Part Number: TM4C123GH6PM


Hi everybody, 

I am trying to write simple code that implementing the CAN serial protocol and here is the transmitter launchpad code. 

i observe that when i step over the 

CANIntRegister(CAN0_BASE, CANIntHandler);

function the white led is just turning on (take a look to the handler code) and the execution stops on the following line

I try to register the handler statically in the startup file then, when i step over the 

IntEnable(INT_CAN0) ;  

function it turn on the white led and the execution stops at the following line in the code. 

In both cases i try to continue stepping to see what happen after  CANmsgSet() .. i find out the code is getting stuck in the handler forever (the led blinking continuously)..

could somebody help please ? 

regards, 

Sarea

#pragma diag_push
#pragma CHECK_MISRA("none")

#include <stdint.h>
#include <stdbool.h>
#include "stdlib.h"
//#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_uart.h"
#include "inc/hw_gpio.h"
#include "inc/hw_pwm.h"
#include "inc/hw_types.h"
#include "driverlib/timer.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/udma.h"
#include "driverlib/pwm.h"
#include "driverlib/ssi.h"
#include "driverlib/can.h"
#include "driverlib/systick.h"
#include <string.h>
#include <uartstdio.h>
#include <SysTick_Init.h>
#include <PORTF_Init.h>

#pragma diag_pop

void CANIntHandler(void);
int main(void) ;

int main(void){
        SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_OSC_MAIN|SYSCTL_XTAL_16MHZ);
        PORTF_Init() ;


        // CAN0 and PORTE configurations
	    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE) ;
	    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOE)){}
	    GPIOPinConfigure(GPIO_PE4_CAN0RX) ;
	    GPIOPinConfigure(GPIO_PE5_CAN0TX) ;
	    GPIOPinTypeCAN(GPIO_PORTE_BASE, GPIO_PIN_4|GPIO_PIN_5) ;


	    SysCtlPeripheralEnable(SYSCTL_PERIPH_CAN0) ;
	    while(!SysCtlPeripheralReady(SYSCTL_PERIPH_CAN0)){}
	    CANInit(CAN0_BASE) ;
	    CANBitRateSet(CAN0_BASE, SysCtlClockGet(), 500000) ;
	    CANIntRegister(CAN0_BASE, CANIntHandler);
	    CANIntEnable(CAN0_BASE, CAN_INT_MASTER | CAN_INT_ERROR | CAN_INT_STATUS);
	    IntEnable(INT_CAN0) ;
	    CANEnable(CAN0_BASE) ;


	    // set up the CAN message object

	    tCANMsgObject msg ;
	    uint32_t msgData;
	    uint8_t *msgDataPtr = (uint8_t *) &msgData ;

	    msgData = 0;
	    msg.ui32MsgID = 1;
	    msg.ui32MsgIDMask = 0 ;
	    msg.ui32Flags = MSG_OBJ_TX_INT_ENABLE ;
	    msg.ui32MsgLen = sizeof(msgDataPtr) ;
	    msg.pui8MsgData = msgDataPtr ;





	  while(1){
	      CANMessageSet(CAN0_BASE, 1, &msg, MSG_OBJ_TYPE_TX) ;

	      SysTick80_Delay_10ms(300) ;

	  }
return 0;
}


void CANIntHandler(void){
    GPIO_PORTF_DATA_R ^= 0x0E ; // toggle the white LED
    SysTick80_Delay_10ms(300) ;

    CANIntClear(CAN0_BASE, 1); // clear interrupt

    unsigned long status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE); // read interrupt status

    if(status == CAN_INT_INTID_STATUS) { // controller status interrupt
        status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); // read back error bits, do something with them?
    } else if(status == 1) { // message object 1
        CANIntClear(CAN0_BASE, 1); // clear interrupt

}
}

  • Hello sarea,

    What is this "SysTick80_Delay_10ms" function you have? Can you post the source code for it? I have not seen that in any TivaWare file.
  • Hi sarea,

    Also, can you use a breakpoint or some UART print statement to find out the returned result of the CANIntStatus API?
  • Agree with Ralph, but in addition for and reasonable definition of SysTick80_Delay_10ms this usage:

    sarea hariri said:
    void CANIntHandler(void){ GPIO_PORTF_DATA_R ^= 0x0E ; // toggle the white LED SysTick80_Delay_10ms(300) ;

    can't be good.

    To a good second approximation, there should never be delays or prints in interrupts.

    And a question, have you implemented the example CAN code?

    Robert

  • thanks Ralph,

    here is my definition for the function and edited handler: 

    void SysTick80_Delay_10ms (uint32_t ms){
        int i ;
    
        for (i = 0 ; i<ms ; i++)
        SysTick_Init (800000);
    
    }
    
    void SysTick_Init(uint32_t count){
                NVIC_ST_CTRL_R = 0x00  ; // disable during the setup
                NVIC_ST_RELOAD_R = count -1 ; // the no of count to wait
                NVIC_ST_CURRENT_R = 0 ; // write any value to start counting
                NVIC_ST_CTRL_R = 0x05  ; // 0101 enable system tick with the system clk, no interrupts, enable the Systek
                while ((NVIC_ST_CTRL_R & 0x010000) == 0 ){}
    }


    void CANIntHandler(void){
        GPIO_PORTF_DATA_R ^= 0x0E ; // toggle the white LED
        //SysTick80_Delay_10ms(300) ;
    
        //CANIntClear(CAN0_BASE, 1); // clear interrupt
    
        uint32_t status;
        status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE); // read interrupt status
    
        if(status == CAN_INT_INTID_STATUS) { // controller status interrupt
            status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); // read back error bits, do something with them?
        } else if(status == 1) { // message object 1
            CANIntClear(CAN0_BASE, 1); // clear interrupt
    
    }
    }

    here is what is happening  exactly: 

    1. after executing the  CANIntRegister(CAN0_BASE, CANIntHandler); function .. its go the handler (till now i don't know why?)  

    2. at the start of handler i observe the status variable == 1 .. but after executing the second line in handler .. status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); .. status will be 0 .. so not entering if nor else if statment.

    3. after msg set in while(1) .. it goes to the handler .. at the start of it. I have the status == 0 .. but after executing the 2nd line. status == 32768 .. then entering the if statement and status == 4 which is the return of  CANStatusGet() ;  then it loops in the handler forever ??

    Regards,

    Sarea

  • Robert
    thanks for the advice about delay and prints in handlers.
    i read the TX example in TivaWare and the programming example of the CAN module in driver library user guide.
    but i don't like to copy it and paste. instead i consider it as a guide helps me to write a similar code

    Regards,
    Sarea
  • Robert's point regarding, "Burdening and/or extending time spent w/in an ISR is surely valid."      And - vendor code (often) employs "printf" - which does add time to fully execute.

    Now you NEED to confirm that your code has, "Reached certain key/critical points" - yet that may be achieved - and FAR FASTER - via setting of one (or several) Leds.     I'd suggest potentially dedicating one entire GPIO Port (or at least half of one) and those 4 Leds - may confirm that up to 16 different code blocks have been entered/executed - yet "minus" any "blink or toggle induced," ISR extending delays.

    My firm employs a "dedicated, tiny, pcb Led plug-in" which always attaches to a GPIO Port - which we reserve for such usage - during development.    Driving code is thus "re-usable" and simple - only its "placement" w/in monitored code blocks - changes.

    Monitoring code's progress IS greatly helpful (often mandatory) yet - as the suggestion above reveals - does not have to force "unwanted time expenditures" w/in the ISRs...

  • sarea hariri said:
    void SysTick80_Delay_10ms (uint32_t ms){ int i ; for (i = 0 ; i<ms ; i++) SysTick_Init (800000); } void SysTick_Init(uint32_t count){ NVIC_ST_CTRL_R = 0x00 ; // disable during the setup NVIC_ST_RELOAD_R = count -1 ; // the no of count to wait NVIC_ST_CURRENT_R = 0 ; // write any value to start counting NVIC_ST_CTRL_R = 0x05 ; // 0101 enable system tick with the system clk, no interrupts, enable the Systek while ((NVIC_ST_CTRL_R & 0x010000) == 0 ){} }

    That leads to multiple questions. Why are you initializing the system tick function multiple times? And why are you not using the TIVAWare functions?

    sarea hariri said:
    2. at the start of handler i observe the status variable == 1

    Well, you haven't initialized it yet so it could be anything. Technically it isn't even in scope yet, worse this is only valid for C++ and C99. A lot of compilers don't yet support C99 so my worry is that you may be using C++ in which case this is not a valid interrupt routine.

    sarea hariri said:
    status == 4 which is the return of  CANStatusGet()

    And what does that tell you?

    Robert

    There's a lot to be said for starting with a known good routine. More to be said for reverting to a known good routine when what you have does not work.

  • Robert

    thanks for you. Since i am a new user of TivaWare, i don't know that i can delay using SysCtlDelay. However, here is the new edited handler.

    i still have a trouble. when i execute this

       CANIntRegister(CAN0_BASE, CANIntHandler);

    it goes to the handler(could you tell me why?)!!  and the status variable has assigned to a value of zero.

    after calling this

         CANMessageSet(CAN0_BASE, 1, &msg, MSG_OBJ_TYPE_TX) ;

    it goes to the handler and status == 32768  which means  its a status interrupt .. then entering the if statement and status == 4 which is the return of  CANStatusGet() ;

    but shouldn't this function clear the status interrupt when it is called ?? if So, why did the handler re-execute ?

    if the function should't. could you help me in this point which is how can i clear the flag .. so that we can return from the interrupt handler ?

    one last question, does the can controller trigger a status interrupt if it send a message and there is no other nodes on the  bus ?

    Regards, 

    Sarea

    void CANIntHandler(void){
        GPIO_PORTF_DATA_R ^= 0x0E ; // toggle the white LED
    
        SysCtlDelay(SysCtlClockGet()/3) ; // delay for a second
    
    
    
    
        uint32_t status;
        status = CANIntStatus(CAN0_BASE, CAN_INT_STS_CAUSE); // read interrupt status
    
        if(status == CAN_INT_INTID_STATUS) { // controller status interrupt
            status = CANStatusGet(CAN0_BASE, CAN_STS_CONTROL); // read back error bits, do something with them?
        } else if(status == 1) { // message object 1
            CANIntClear(CAN0_BASE, 1); // clear interrupt
    
    }
    }
    

  • sarea hariri said:

    i still have a trouble. when i execute this

       CANIntRegister(CAN0_BASE, CANIntHandler);

    Have you cleared the interrupts?

    sarea hariri said:
    it goes to the handler and status == 32768  which means  its a status interrupt .. then entering the if statement and status == 4 which is the return of  CANStatusGet() ;

    And what does a return of four mean? Once you've determined that, then we can approach the next question you asked.

    Skipping that for now and looking at your last question.

    sarea hariri said:
    one last question, does the can controller trigger a status interrupt if it send a message and there is no other nodes on the  bus ?

    That will cause an error (and fairly quickly a bus off condition) so depending on your setup you will expect an interrupt.

    You haven't responded as to whether you are compiling as C or C++

    Robert

  • Hello Sarea,

    The CANIntRegister API should only be used if you want to dynamically allocate the vector table. I would not recommend using this for your first application. Try removing that and see if any behavior changes.
  • firstly, i think the CANIntRegisterI(); should't generate interrupt itself.

    for the second question and if i thick properly, a return of 4 in the CAN status register means BIT 1 ERROR according to data sheet (A Bit 1 Error indicates that the device wanted to send a High level (logical 1) but the monitored bus value was Low (logical
    0).) and this maybe occur because noise signals since i didn't connect any wire to the board yet as i test the first board (transmitter).

    lastly, i use the TI compiler in the options of the CCS. i really don't know where can i find if its compiling as c or c++ ?

    Regards,
    Sarea
  • Ralph

    I just pressed "this resolve my issue" wrongly !! 
    I try to allocate the ISR statically in the start up file and remove the CANIntRegister() function. then the same thing exactly happens and the same values for the status variable though the code. the only difference is that instead of going to the handler after executing CANIntRegister() ( now i comment it out) it jumps to the handler after executing IntEnable(INT_CAN0) ;

    Regards,
    Sarea

  • sarea hariri said:
    lastly, i use the TI compiler in the options of the CCS. i really don't know where can i find if its compiling as c or c++ ?

    It should be in your options.

    sarea hariri said:

    for the second question and if i thick properly, a return of 4 in the CAN status register means BIT 1 ERROR according to data sheet (A Bit 1 Error indicates that the device wanted to send a High level (logical 1) but the monitored bus value was Low (logical
    0).) and this maybe occur because noise signals since i didn't connect any wire to the board yet as i test the first board (transmitter).

    Good, but pause and think about whether noise is required to get this result. I assert it is not.

    Next step, what does this then require that you do?

    Robert

  • sarea hariri said:
    I just pressed "this resolve my issue" wrongly !! 

    And the forum continues to degrade, apparently now removing the capability of correcting this mis-click.

    Robert

  • Robert
    Here is good news. i just connect the 2 wires of the can bus and tried many times.
    lastly, i can say it works properly...

    i use loop back technique to test the board by adding this two line in the configuration:

    CAN0_CTL_R |= CAN_CTL_TEST ; // enable test mode
    CAN0_TST_R |= CAN_TST_LBACK ; // enable loop back mode

    by observing the registers and the status variable i could send MSG on the bus .. ignoring the ack by looping back.
    but still i have 2 last questions:

    1. why the execution goes to the handler after this line:
    IntEnable(INT_CAN0) ; ?

    2. when i call CanMessageSet() it goes to the handler as a controller status interrupt and enter the if statement which is calling CanStatusGet()
    and then it re-enters the handler (just after return from it at the first time) and enter the else if block which is calling CanIntClear() then it return to the caller ( the while (1) ) ... the question is why does it enter the handler two times after calling CanMessageSet() ??


    Regards,
    Sarea
  • sarea hariri said:
    Here is good news. i just connect the 2 wires of the can bus and tried many times.
    lastly, i can say it works properly...

    If you mean connecting the Tx and Rx lines then no you do not have it working. Your writing is far from clear here.

    sarea hariri said:
    1. why the execution goes to the handler after this line:
    IntEnable(INT_CAN0) ; ?

    Have you cleared the interrupts?

    sarea hariri said:
    2. when i call CanMessageSet() it goes to the handler as a controller status interrupt and enter the if statement which is calling CanStatusGet()
    and then it re-enters the handler (just after return from it at the first time) and enter the else if block which is calling CanIntClear() then it return to the caller ( the while (1) ) ... the question is why does it enter the handler two times after calling CanMessageSet() ??

    How do you deal with multiple simultaneous interrupts?

    Robert