Help needed with SCI interrupts (HC12)

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(); ).

main.c //*********************************** #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

....

RxFifo.c //************************************ #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); } }

sci.c //************************************ #include #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; // Where my code stucks }; PTG_PTG0 = 1; return(letter); }

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

Reply to
ryufrank
Loading thread data ...

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.

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.

Reply to
cs_posting

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 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.

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

I`m not really sure what to do with this. Any suggestions are more than welcome

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

Reply to
ryufrank

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?

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.

Reply to
cs_posting

I`m sorry for my ignorance, but how can I check this?

I`m using Serial Monitor debugger, and Monitor as Target in Codewarrior IDE 5.7. Sorry for not referring to these information earlier.

This is my case..

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

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.

Reply to
ryufrank

How is it that you determine that the program has "crashed"?

What exactly do you mean by "crashed" ?

- 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)

Reply to
cs_posting

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 tried to set various checkpoint to see where the code reaches... and the ISR doesn`t appear to be called

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

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

Reply to
ryufrank

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.

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?

Reply to
cs_posting

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.

Reply to
ryufrank

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

Reply to
ryufrank

First, congratulations on getting it working.

Yeah, that would do it. Unless the debug connection is at a baud rate an order of magnitude faster than the data connection, I'd expect you to lose characters. Strongly suggest getting a BDM pod... best $100 you will spend.

I don't know if it actually makes a difference, but I often due the ISR as a while loop contingent on the character available flag; that way if somehow I'm running far enough behind that reception of another character completes while I'm storing the first, I can actually get two characters from one interrupt.

I'm not sure that I'd agree that the SCI should have priority over the ethernet. 10 MB/s is nearly 100 times 115200 baud, so at first glance it looks like entire short packets could come in between serial characters. Anyway, I've seen no problems with 115200 baud serial, and ethernet.

As for priorities, disabling the interrupts during the ISR (if that's not happening automatically), consult the data sheet. It's long, but informative even if you only read the applicable section to your problem-of-the-day.

Reply to
cs_posting

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.