S12ga48 code hangs in for(;;) loop.

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

S12ga48 code hangs in for(;;) loop.

1,115 Views
nandulalgavali
Contributor II

Hello All,

I am designing the data acquisition system on S12GA48 (LQFP48 pin). In my system, I have to display data on 20x4 char LCD. I am taking data from other 27 modules on CAN bus @37ms rate every-time. Also, I am sending data to GSM modem every 1 second. I have 1 timer compare ISR for 35ms. In that ISR, I am getting data on CAN from other modules. Apart from it, I have I2C based RTC, SPI based EEPROM , I2C based Humidity sensor and using MODBUS protocol on RS485. My LCD operating is 4 bit mode. I am doing I2C and SPI based PORT bit banging. I am using Codeworrior 5.2 version. My infinite loop look like,

 

for(;;)
{


Task_LCD_Refresh();

Task_RTC_Update();

Task_Humidity_Temp_Update();

}

 

Timer ISR is,

 

void HeartBit_ISR (void)
{
static uCHAR cntDecodeMODBUS = 0;
static uCHAR cntADCrefresh = 0;
static uCHAR cntSlaveRead = 0;
volatile uINT batPackVolt = 0;

// Get the errors
generateErrorCode();

 


if(++cntADCrefresh > timeADCrefresh) // Excution - 100us
{
cntADCrefresh = 0;
flagADCsample = TRUE;

// Add all the voltages to create the Pack voltage
readAllADCs(); // Sample ADC for 100 ms time
}

// TimeOut for the MODBUS if no communication in 150ms then clear Buffer
if((++comTimeOut > 5) && (flagSerialReceive)) // Code takes 100uS time
{
comTimeOut = 0;
messageSize = MODBUS_MESSAGE_SIZE_MAX;
clearMODBUSmessage();
flagDecodeMODBUSFrame = 0;
flagSerialReceive = 0;
}

// Slave Sample after every 37ms So, All slave can update data in 1sec
flagCANsendCmd = TRUE;
Task_CAN_Send();
HEARTBIT_LED = ~HEARTBIT_LED;
}
//***************************************************************************************

 

I am using isolated USBDM (based on pgo design) for the debugging and programming which I have created and is working fine.

 

My LCD paging code is,

 

void LCDdisplayRefresh (void)
{

// Select different Displays @4sec rate

// Increase display counter
dispCounter = (dispCounter + 1);

// Total Five display pages
if(dispCounter > (MAX_LCD_PAGES-1))
{
dispCounter = START_LCD_PAGE;
}

if(dispCounter == 0)
displayVolt1PAGE(); // display page 1

if(dispCounter == 1)
displayVolt2PAGE(); // display page 2

if(dispCounter == 2)
displayVolt3PAGE(); // display page 3

if(dispCounter == 3)
displayVolt4PAGE(); // display page 4

if(dispCounter == 4)
displayVolt5PAGE(); // display page 5

if(dispCounter == 5)
displayVolt6PAGE(); // display page 6

if(dispCounter == 6)
displayCurrPAGE(); // display page 7

if(dispCounter == 7)
displayCurr2PAGE(); // display page 8

if(dispCounter == 8)
displayErrAlramPAGE(); // display page 9 
}

 

Initially, I used 'switch case loop' but shifted on 'if loop' to check whether loop is doing some malfunction. I found that somehow my code going either out of infinite loop or stuck to somewhere in the other function and it stops LCD refreshing and hold any of the LCD page. I also tried to hot sync USBDM to find out the issue.

 

But whenever I connect USBDM, the code recovers and started again. I do not understand how I can check what is happening there. I have assigned the stack to 0x150  bytes and found that only half of this value being used during continuous operation. So, this is not looking as a stack failure issue.

 

Also, I found that all my interrupts are working fine at all times. I have disable all optimization in standard setting. I cannot share all my code due to security reqasons. Can anyone suggests me what can I do to check what is happening there?

 

Regards

N.K. Gavali

Labels (1)
9 Replies

885 Views
nandulalgavali
Contributor II

Hello Radek,

System is working from last 33 hours. :smileyhappy: with the above  "just for sure” solution.

Regards

Nandu

0 Kudos

885 Views
RadekS
NXP Employee
NXP Employee

Hi Nandu,

Thank you for your update.

I am glad that it works now.

Regards,
Radek

0 Kudos

885 Views
nandulalgavali
Contributor II

Hello Radek,

It is again hang after 29 hours. :smileysad:. After connecting debugger, I found that all RDRF/IDLE/OR/NF flags of SCI1SR1 were SET. The stack pointer was showing 300 bytes less than first Global variable location and I have assigned  2KB RAM for STACK.

So, now It is confirmed that this issue is not related with STACK. As discussed in  previous post, the other SCI flags are not clearing so the code might be locked in Serial ISR. When I ran the code from debugger, it started working again as usual. which is logical from earlier discussion.

I have set the only RIE bit in SCI1CR2 reg and expecting Serial Receive Full ISR only. So, I don't understand why code is staying in Serial ISR when OR bit is set. Can you plz explain?

FYI, I am using both SCIs. They are working on 57.6 kbps. and almost 100 bytes are sending after 200ms duration. The bytes receiving to uC are not more than 15 bytes in every 200ms. So, the code is not violating any timings.

Now, I have written the serial ISR code as,

__interrupt void Serial1_ISR (void)

{

   volatile uCHAR dataReg, i, tmpSR1;

  

   tmpSR1 = SCI1SR1

  if(tmpSR1 & SCI1SR1_RDRF_MASK)

  {

    dataReg = SCI1DRL;

    Serial_Fun(dataReg);

  }

  // Clear Remaining Flags -  As I am not interested into them.  

  for(i=0; i<20; i++)

  {

     tmpSR1 = SCI1SR1;

     dataReg = SCI1DRL;

     

    if(tmpSR1 == 0)

       break;

  } 

   asm NOP;  // dummy NOP

}

I am hoping that this code will clear all flags of SCI1SR1 even if  SCI1SR1_RDRF is cleared first.

Plz check and Suggest.

Have a nice day.

Regards,

Nandu 

0 Kudos

885 Views
RadekS
NXP Employee
NXP Employee

Hi Nandu,

Thank you for new details. So, it seems that we found a root cause.

Please let us know the result after SCI ISR fix.

 

There is just one shared interrupt for whole SCI module and various number of SCI interrupt sources which should/must be handled.

SCI Interrupt Sources.png

The exact number of interrupt sources and their handling will depend on you SCI configuration and application requirements.

 

The for loop in your ISR is a quite interesting solution (“just for sure” solution). Maybe just else branch may be enough in such case.

For example:

if(tmpSR1 & SCI1SR1_RDRF_MASK)

  {

    dataReg = SCI1DRL;

    Serial_Fun(dataReg);

  }

else  // Clear Remaining Flags

    {

     (void)SCI1DRL; //The SCI1SR1 is already read by tmpSR1 = SCI1SR1; command

    }

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

885 Views
nandulalgavali
Contributor II

Hello Radek,

Thanks for further suggestions. As I told you on yesterday that I have set stack value to 2KB. and glad to update you that the system is running since last 24 hours without any issue. :smileyhappy:.

Apart from it, I had changed the Serial ISR flag clear method. which is like,

void Serial_ISR(void) 

{

   volatile uCHAR temp = 0, dataReg = 0;

   if(SCI_RECV_FLAG)

   {

      temp = SCI0SR1;

     dataReg = SCI0_DATA_REG;

     MODBUS_Fun(dataReg);

   }

   temp      = SCI0SR1;   

}

Here my thinking is that if any flag other than serial receive is set, then it will be cleared by last two lines. I also checked and confirmed that there is no spurious interrupt occurs. In my code the compiler setting is -DPPAGE_ADDR=0x15 which I think similar what you suggest in earlier post. 

Can you plz share recommended code snippet for the Serial ISR? So, that I will take care in future.

Have a good day :smileyhappy:

Thanks and Regards

Nandu

0 Kudos

885 Views
RadekS
NXP Employee
NXP Employee

Hi Nandu,

In the case of your routine, the problem may happen when OR/NF/FE/PF is set while RDRF flag is cleared.

Note from RM: OR flag may read back as set when RDRF flag is clear. This may happen if the following sequence of events occurs:

  1. After the first frame is received, read status register SCISR1 (returns RDRF set and OR flag clear);
  2. Receive second frame without reading the first frame in the data register (the second frame is not

received and OR flag is set);

  1. Read data register SCIDRL (returns first frame and clears RDRF flag in the status register);
  2. Read status register SCISR1 (returns RDRF clear and OR set).

Event 3 may be at exactly the same time as event 2 or any time after. When this happens, a dummy

SCIDRL read following event 4 will be required to clear the OR flag if further frames are to be received.

 

Please use rather something like:

void Serial_ISR(void)

{

   volatile uCHAR temp = 0, dataReg = 0;

   temp      = SCI0SR1;  

   if( temp & SCI0SR1_RXDF_MASK )

   {

     dataReg = SCI0_DATA_REG;

     MODBUS_Fun(dataReg);

   }

   if( temp & SCI0SR1_OR_MASK )

   {

//…

   }

//…

}

When bodies of these branches will be the same/similar, you may use combination for flag testing.

Example of S12G SCI ISR:

#pragma CODE_SEG NON_BANKED

interrupt 20 void SCI0_Isr(void)

{  

 unsigned char scicr2,scisr1;

 scisr1 = SCI0SR1;                          // save status register actual status

 scicr2 = SCI0CR2;                          // save control register actual status

 

 //if receiver interrupt is enabled and corresponding interrupt flag is set

 if((scicr2 & SCI0CR2_RIE_MASK) && ((scisr1 & (SCI0SR1_OR_MASK | SCI0SR1_RDRF_MASK))))

  {

    if(scisr1 & SCI0SR1_OR_MASK)            // if overrun error do nothing/something

      {

        (void)SCI0DRL;                      // clear interrupt flag

        // do something

      }

    else

      {

     

        sc0_data_in = SCI0DRL;              // read received character + clear interrupt flag                       

        //do something with received data   

      }

  }

}

#pragma CODE_SEG DEFAULT

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

885 Views
nandulalgavali
Contributor II

Hello Radek,

Thanks for the reply. I have done the further testing and found that when code hangs that time following ISRs condition are

1. Timer ISR (TC3) - 37ms ---- working OK

2. Timer ISR (TC1) - 50ms --- Working OK

3. SCI0 Receive ISR --- Not working

4. SCI1 Receive ISR --- Not Working

5. CAN Receive ISR --- Not Working

Also, code is not in for(;;) loop. I found that many Global variables are corrupted. When I stopped USBDM on

break-point @Timer ISR. It stops as usual and when I re-run the code from debugger, everything starts working as it (without RESET).

I am also suspecting this issue as a Stack Overflow. So, now, I have assigned maximum possible stack size (around 2KB) and unit is kept on testing. It was my experience that the issue repeats within 24 hours working. So, I will update the result tomorrow evening (India Time).

For your info, I am using SSTACK in the prm file. It means that stack is started just before the first global variable. I will also try to allocate small RAM section between the global variable and start of STACK. So that the chances of SP corruption can be reduced.

 

I will also implement PPAGE suggestion given by you.

Thanks and Regards

Nandulal Gavali

0 Kudos

885 Views
RadekS
NXP Employee
NXP Employee

Hi Nandulal,

Thank you for more details.

 

It is strange that only half of your ISR works. That may point us to some problem with priority.

The S12G do not offer tools for selection interrupt priority per single interrupt source (in compare with S12X/Z derivatives). Therefore, the interrupt priority is given by position in vector table (higher vector address = higher priority).

The timer interrupts are relatively high in the vector table. So, I guess that there may be some active interrupt between timer TC3 channel and SCI0 which is not handled correctly (you didn’t erase correct flag) and that interrupt routine try to start again and again. Since priority of this ISR is higher than others, it effectively blocks part of interrupts and the main loop.

 

It is possible that when you connect a debugger, the flag disappears. That is the typical issue when we debug SCI, where the flags are cleared by reading SCISC1 register followed by reading SCIDR register. That reading may be caused also by the debugger.

As the solution, we typically store SCISR1 register content into some variable at beginning of SCI ISR and later in ISR we work only with that variable value. When we place breakpoint behind that reading, we may simple debug SCI interrupt. Please look at OR/NF/FE/PF flags handling in your SCI0 ISR.

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------

0 Kudos

885 Views
RadekS
NXP Employee
NXP Employee

Hi Nandulal,

It is hard to say what may happen in your project.

Unfortunately, my experience with USBDM are limited, therefore I am not sure whether is possible attach to MCU (HotSync) without reset with that BDM interface.

 

The typical reasons for code walk away are:

1. Stack overflow.

2. Unexpected interrupt. You wrote that your ISRs working fine, but you didn’t mention whether you manage also unexpected interrupts (like Spurious Interrupt). Please look at Interrupt Catcher example code https://community.nxp.com/docs/DOC-93792 at for your inspiration.

3. Some incorrect operation with a pointer to the function.

4. PPAGE modification – for banked memory model. Please check whether your code directly modifies PPAGE or not. By default, the PPAGE value is not stacked at ISR enter.

If you want to save/restore PPAGE in ISR, please use -CpPPAGE=0x15 as the compiler option.

You may also try to -CpPPAGE=RUNTIME. In that case, the routines from datapage.c will be used for access to far data.

 

Note: You may share un-public data with us through NXP Support Ticket:

https://community.nxp.com/docs/DOC-329745

I hope it helps you.

Have a great day,
Radek

-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------