Help needed with SCI interrupts (HC12)

Started by June 27, 2007
Hello.
I'm writing a program for an NE64 board, which reads a series of data
over the SCI1 port, and then transmits them over the Ethernet port.
Pretty much it's done and works, but due to the amount of data
collected on every reading, I have to send out 10-15 packets every
time.
My problem is that, when the function for UDP transmission is
executed, some of the data received on the serial port are skipped and
lost.
I understand that in order to overcome this I need to implement an
Interrupt function for the SCI1 port.
I've tried this, but my code gets stuck in an infinite loop when the
SCI reading in functions takes place ( SCI1in(); ).

<TR>
<TH>main.c</TH>
//***********************************
#include "RXFIFO.H"
#include "sci.h"
#include "MC9S12NE64.h"
//...and all other required files/libraries

extern void SCI1_isr_handler (void);

#pragma CODE_SEG BANKED
interrupt void SCI1Interrupt (void)
{
  SCI1_isr_handler();
}
#pragma CODE_SEG DEFAULT

....

<TR>

<TR>
<TH>RxFifo.c</TH>
//************************************
#include "RxFifo.h"
/* Number of characters in the Fifo
     the FIFO is full when it has FifoSize-1 characters */
char static volatile *RxPutPt;    /* Pointer of where to put next */
char static volatile *RxGetPt;    /* Pointer of where to get next */
                  /* FIFO is empty if PutPt=GetPt */
                  /* FIFO is full  if PutPt+1=GetPt */
char static RxFifo[RXFIFOSIZE];     /* The statically allocated fifo
data */

/*----------RxFifo_Init
  Initialize fifo to be empty
  Inputs: none
  Outputs: none */
void RxFifo_Init(void){unsigned char SaveCCR;
/* save previous interrupt enable */
asm  tpa
asm  staa SaveCCR
asm  sei          /* make atomic */
  RxPutPt=RxGetPt=&RxFifo[0];   /* Empty when PutPt=GetPt */
asm  ldaa SaveCCR
asm  tap          /* end critical section */
}

/*---------RxFifo_Put
  Enter one character into the fifo
  Inputs: 8-bit data
  Outputs: true if data is properly saved
  Since this is called by interrupt handlers no sei,cli*/
int RxFifo_Put(char data){
char volatile *tempPt;
  tempPt = RxPutPt;
  *(tempPt) = data;              /* try to Put data into fifo */
  tempPt++;
  if(tempPt == &RxFifo[RXFIFOSIZE]){ /* need to wrap?*/
    tempPt = &RxFifo[0];
  }
  if(tempPt == RxGetPt){
    return(0);             /* Failed, fifo was full */
  }
  else{
    RxPutPt = tempPt;      /* Success, so update pointer */
    return(1);
  }
}

/*-----------------------RxFifo_Get----------------------------
  Remove one character from the fifo
  Inputs: pointer to place to save 8-bit data
  Outputs: true if data is valid */
int RxFifo_Get(char *datapt){
  if(RxPutPt == RxGetPt){
    return(0);     /* Empty if PutPt=GetPt */
  }
  else{
    *datapt = *(RxGetPt);
    RxGetPt++;
    if(RxGetPt == &RxFifo[RXFIFOSIZE]){
      RxGetPt = &RxFifo[0];
    }
    return(1);
  }
}

</TR>


<TR>
<TH>sci.c</TH>
//************************************
#include <stdio.h>
#include "ne64debug.h"
#include "MC9S12NE64.h"
#include "sci.h"
#include "RXFIFO.H"

unsigned short RxHistogram[RXFIFOSIZE]; // collected before put

void SCI1Init(void){
  //Debugt("Initializing my SCI1 function\r\n");
  #define ECLK 25000000 //< this is BUSCLK
  #define BAUD_RATE    9600
  PTG_PTG2 = 0;
  #define BAUD_DIV     ECLK/16/BAUD_RATE

  SCI1BD= BAUD_DIV;
  SCI1CR1= 0;
  SCI1CR2= SCI1CR2_TE_MASK | SCI1CR2_RE_MASK | SCI1CR2_RIE;
  RxFifo_Init();
  asm cli
}



//------SCI1 interrupt handler
interrupt void SCI1_isr_handler(void){
  if(SCI1SR1 & SCI1SR1_RDRF_MASK){
    RxHistogram[RxFifo_Size()]++;
    RxFifo_Put(SCI1DRL); // clears RDRF
  }
}


//-----Start of SCI1In
// Wait for new serial port input, return ASCII code for key typed
char SCI1In(void){

  char letter;
  while (RxFifo_Get(&letter) == 0){
    PTG_PTG0 = 0; //<FONT FACE="Times New Roman" SIZE="+2"
COLOR="#FF0000"> Where my code stucks</FONT>
  };
  PTG_PTG0 = 1;
  return(letter);
}
</TR>

My program is based on the Freescale's Connector_App, so similar
initilizations take place.
I'm new at this, and I had a really hard time finding information and
examples using SCI Rx interrupts. Can somebody indicate me what i'm
doing wrong please?
Your help will be trully appreciated.

Thank you

On Jun 27, 1:23 pm, ryufr...@hotmail.com wrote:

> I understand that in order to overcome this I need to implement an > Interrupt function for the SCI1 port. > I've tried this, but my code gets stuck in an infinite loop when the > SCI reading in functions takes place ( SCI1in(); ).
So which exact instructions is it looping on? Are there actually characters in the RF fifo? If you put a breakpoint in the ISR, is it triggering and storing characters to the FIFO? One general note: your memory section pragmas look a little suspicious. You need to be sure that everything that runs as a result of the interrupt is in the non-banked memory section - both the ISR routine, and anything it calls . If you don't it will likely work fine until your program grows to the size where bank switching is required, at which point it will start failing in very odd ways.
> RxFifo_Put(SCI1DRL); // clears RDRF
I'd be tempted to copy SCI1DRL into a volatile temporary variable so I could see with the debugger that it's actually getting read, and then call the routine using that.
Hi, and thank you for your quick reply.
I attempted to write in HTML formatting, to indicate some problems,
but I forgot that this is not supported here.
Anyway here is my feedback to your help:

> > I understand that in order to overcome this I need to implement an > > Interrupt function for the SCI1 port. > > I've tried this, but my code gets stuck in an infinite loop when the > > SCI reading in functions takes place ( SCI1in(); ). > > So which exact instructions is it looping on?
I inspected closer my code by adding some Debugging checkpoints, and my code loops 3-4 times in the SCI1in() function at the " while (RxFifo_Get(&letter) == 0){ };" loop when SCI1in is manually called. Then it just crashes or something.
> Are there actually characters in the RF fifo? > > If you put a breakpoint in the ISR, is it triggering and storing > characters to the FIFO?
I checked and it appears that the ISR is not reached before program crashes (SCI1In reached). So i guess my mistake is at a lower level, something to do with my interrupt implimentation mayb.e
> One general note: your memory section pragmas look a little > suspicious. You need to be sure that everything that runs as a result > of the interrupt is in the non-banked memory section - both the ISR > routine, and anything it calls . If you don't it will likely work > fine until your program grows to the size where bank switching is > required, at which point it will start failing in very odd ways.
I`m not really sure what to do with this. Any suggestions are more than welcome
> > RxFifo_Put(SCI1DRL); // clears RDRF > > I'd be tempted to copy SCI1DRL into a volatile temporary variable so I > could see with the debugger that it's actually getting read, and then > call the routine using that.
The 3-4 readings taken before the program crashes show SCI1DRL as 0, even though I`m transmitting to the board`s SCI1 port. I googled around a lot the past days to find SCI communication examples with interrupts to familiarize with. But I didn`t have much luck with it. If you have anything in mind please let me know. Thank you
On Jun 28, 5:11 am, ryufr...@hotmail.com wrote:

> I checked and it appears that the ISR is not reached before program > crashes (SCI1In reached). So i guess my mistake is at a lower level, > something to do with my interrupt implimentation mayb.e
Please describe what you mean by crashes. For example, does it jump to an arbitrary address outside of the program and thus trigger the software trap debugging interrupt? What is your debuger and target connection?
> > One general note: your memory section pragmas look a little > > suspicious. You need to be sure that everything that runs as a result > > of the interrupt is in the non-banked memory section - both the ISR > > routine, and anything it calls . If you don't it will likely work > > fine until your program grows to the size where bank switching is > > required, at which point it will start failing in very odd ways. > > I`m not really sure what to do with this. Any suggestions are more > than welcome
You need to have a non-banked memory section in your linker .prm file (assuming codewarrior) which will not be banked switch and thus always reliably there when an interrupt occurs, and you need to put your interrupt service routine and anything that it might call in that section. If you are using the .prm from the connector app, this section is called NON_BANKED so you would precede your ISR and anything it uses with a #pragma CODE_SEG NON_BANKED and follow it with a #pragma CODE_SEG DEFAULT Also make sure that you are getting the address of the ISR correctly loaded into the vector table. In the connector app, vectors.c does that and would need to reference your ISR.
On Jun 28, 2:58 pm, cs_post...@hotmail.com wrote:
> Please describe what you mean by crashes. For example, does it jump > to an arbitrary address outside of the program and thus trigger the > software trap debugging interrupt?
I`m sorry for my ignorance, but how can I check this?
> What is your debuger and target connection?
I`m using Serial Monitor debugger, and Monitor as Target in Codewarrior IDE 5.7. Sorry for not referring to these information earlier.
> You need to have a non-banked memory section in your linker .prm file > (assuming codewarrior) which will not be banked switch and thus always > reliably there when an interrupt occurs, and you need to put your > interrupt service routine and anything that it might call in that > section. > > If you are using the .prm from the connector app, this section is > called NON_BANKED > so you would precede your ISR and anything it uses with a > > #pragma CODE_SEG NON_BANKED > > and follow it with a > > #pragma CODE_SEG DEFAULT
This is my case.. #pragma CODE_SEG NON_BANKED interrupt void SCI1Interrupt (void) { SCI1_isr_handler(); } #pragma CODE_SEG DEFAULT
> Also make sure that you are getting the address of the ISR correctly > loaded into the vector table. In the connector app, vectors.c does > that and would need to reference your ISR.
in Vectors.c ------------------------- ... SCI1Interrupt, /* 38 Default (unused) interrupt */ .... I believe SCI1 is supposed to be Interrupt Vector No. 21. But how do I clarify that my specific interrupt is triggered by that? Thank you for your support so far.
On Jun 28, 10:43 am, ryufr...@hotmail.com wrote:

> > Please describe what you mean by crashes. For example, does it jump > > to an arbitrary address outside of the program and thus trigger the > > software trap debugging interrupt? > > > I`m sorry for my ignorance, but how can I check this?
How is it that you determine that the program has "crashed"? What exactly do you mean by "crashed" ?
> I believe SCI1 is supposed to be Interrupt Vector No. 21. But how do I > clarify that my specific interrupt is triggered by that?
- Put a breakpoint in the ISR to see if it is ever reached - Examine memory at location 0xFF80 and you should see the vector table. Check that the address of your handler appears at the right location in it. (You may want to examine the linker map file too, it shows you a lot)
On Jun 28, 4:54 pm, cs_post...@hotmail.com wrote:
> On Jun 28, 10:43 am, ryufr...@hotmail.com wrote: > > > > Please describe what you mean by crashes. For example, does it jump > > > to an arbitrary address outside of the program and thus trigger the > > > software trap debugging interrupt? > > > I`m sorry for my ignorance, but how can I check this? > > How is it that you determine that the program has "crashed"? > What exactly do you mean by "crashed" ?
When the board reaches the point to call the SCI1in function to read in data over the RS232 link, any further functions taking place at that time freeze (Ethernet protocols` initialization etc).
> > I believe SCI1 is supposed to be Interrupt Vector No. 21. But how do I > > clarify that my specific interrupt is triggered by that? > > - Put a breakpoint in the ISR to see if it is ever reached
I tried to set various checkpoint to see where the code reaches... and the ISR doesn`t appear to be called
> - Examine memory at location 0xFF80 and you should see the vector > table. Check that the address of your handler appears at the right > location in it. (You may want to examine the linker map file too, it > shows you a lot)
In the linker map file i found that my interrupt is on the wrong address i think. Name Addr hSize dSize Ref Section SCI1Interrupt 506D 5 5 1 NON_BANKED
>From the MC9S12NE64`s datasheets:
Vector No Vector Address Name Source 21 $FFD4, $FFD5 Vsci1 SCI1 This is getting more confusing to me minute by minute :/ Thanks again for your help
On Jun 28, 11:49 am, ryufr...@hotmail.com wrote:
> On Jun 28, 4:54 pm, cs_post...@hotmail.com wrote: > > > On Jun 28, 10:43 am, ryufr...@hotmail.com wrote:
> > What exactly do you mean by "crashed" ? > > When the board reaches the point to call the SCI1in function to read > in data over the RS232 link, any further functions taking place at > that time freeze (Ethernet protocols` initialization etc).
But what is the processor doing? Frozen? Executing from unprogrammed memory? Or stuck in a loop within your program? If it's stuck in a loop, determine which instructions are actually being executed - I think you posted something before that included a function call within the loop.
> > - Examine memory at location 0xFF80 and you should see the vector > > table. Check that the address of your handler appears at the right > > location in it. (You may want to examine the linker map file too, it > > shows you a lot) > > In the linker map file i found that my interrupt is on the wrong > address i think. > > Name Addr hSize dSize Ref Section > SCI1Interrupt 506D 5 5 1 NON_BANKED > > >From the MC9S12NE64`s datasheets: > > Vector No Vector Address Name Source > 21 $FFD4, $FFD5 Vsci1 SCI1
The 16 bit value at $FFD4 should contain the address of your ISR, which according to the map file would be $506D. Use the memory window in the debugger to examine it. But it's probably okay. You should also make sure that interrupts are enable (assembler instructions SEI and CLI or whatever, can't remember which is which), that the SCI RX interrupt bit is enabled (use the debugger to examine the memory mapped SCI register), and that the port module is leaving the relevant IO pins for SCI and not making GPIO's out of them. Another thing you could try: make your program periodically call the ISR, so that in effect you are polling the serial port (and leave out the time consuming UDP calls). Does it work then?
Hi.
Sorry for the late reply.
I took some time to play around with my code and discover various
flaws thanks to your help.
My biggest mistake was that my ISR function was in the wrong place in
vectors.c. Using the file MC9S12NE64.h and the board`s manual i
figured out the correct position.
Now everything in the program appears to function as it should...
apart from the SCI1 interrupt that skips several readings.
For example I'm inputting to SCI1 "1234567890" and it reads "1470".
The SCI1 status register 1 returns OverRun bit as 1. (I'm checking the
value of SCI1DRL right after the ISR occurs).
So this means that for some reason it misses those characters.
Tomorrow I will sit down and struggle to find what can be wrong with
it.
If you have any more suggestions they are more than welcome :)
Thank you for all your help so far.

Yeyyy!!!
Who said that "Information is power"?
My problem was caused by the various DEBUGOUT functions I set in my
code in order to monitor its progress in hyperterminal and locate
where it stops etc. As long as it works fine, there is no need anymore
to know the details within ;)
They were causing delays to everything else! I never tought of that,
and I didn`t expect the board to be so sensitive with such delays :/
Anyway, now the initial part is ok. I can receive some basic
information over the serial port, and trying to make the whole thing
work together (UDP sending and interrupted SCI1). When this works more
or less my objective will be met.
So far I can notice that various other interrupts take place while
SCI1 interrupt is active, coming from broadcast packets on the
Ethernet port. I haven`t done much testing yet of the whole program,
but in case this causes me any problems, is there a way to increase
the SCI1 interrupt`s priority over the others?
Thanks