EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

Dual SCI on 9S12D64 confused Interrupt

Started by WadeA & RebeccaM Smith February 1, 2008
We are working with a proprietary board based on the Elektronikladen
CardS12.D64 using ICC12 and NoICE with the ComPOD12 Pro BDM. The
processor boots up in the TwinPeeks monitor and jumps to the user code
at 0x8000 where all of our code starts (including startup and init).

SCI1 is interrupt driven RS485. SCI0 is polled RS232 half-duplex.

SCI0 set up:
SCI0CR2=TE+RE

SCI1 is outputting a string, so it is set up as:
SCI1CR2=TIE+TE+RE

Initially I did not have any ISR for SCI0, because no interrupts were
to be set. BUT, I found out that I was ALWAYS receiving an interrupt
on SCI0.

So now in BOTH ISR functions I check SR1 and respond accordingly.

I set up NoICE and put
asm(" BGND");
in both ISR functions and let NoICE run it.

Of course, when it stops at SCI0ISR, TDRE+TC are set and nothing else.
I check both SCI0SR1 and SCI1SR1 and deal with both (either putChar
or getChar for each according to the flags).

Why am I getting SCI0 interrupts when none are set and not getting any
SCI1 interrupts?

locations for the TwinPeeks vectors are:

*(int *)0x3FC5 = (int)NETINT; // SCI1 RS485 interrupt driven
*(int *)0x3FC2 = (int)SCIINT; // SCI0 Serial RS232 polled
An assembler "JMP" instruction precedes the address so that TwinPeeks
will jump to the ISR which ends in the "RTI" instruction.
void SCIINT(void)
{
INTU8 dummy;

netSR1 = SCI1SR1; // read SCI 1 Status Register to clear &
analyze it
sciSR1 = SCI0SR1; // read SCI 0 Status Register to clear &
analyze it
asm(" bgnd"); /* ### for DEBUG */
asm(" nop"); /* ### for DEBUG */
asm(" nop"); /* ### for DEBUG */
if (sciSR1 & (OR + NF + FE + PF))
{
/* Receive ERROR */
dummy = SCI0DR; // clear data regi of ?junk?
}
else if (sciSR1 & RDRF)
{
if (SCI_FLG == SCI_RECEIVE)
{
/* do receive */
//cmdRecv();
getCharSCI();
}
else
{
/* clear data register anyway */
dummy = SCI0DRL;
} /* end if else */
}
if (sciSR1 & (TDRE + TC))
{
/* if data availabe for transmission, do transmit */
if (txBusy)
{
//cmdSend();
putCharSCI();
} /* end if */
} /* end if else */
// check the OTHER serial port for interrupts ALSO
if (netSR1 & (OR + NF + FE + PF))
{
/* Receive ERROR */
}
else if (netSR1 & RDRF)
{
/* do receive */
getCharNet();
}
else if (netSR1 & (TDRE + TC))
{
if (ntxBusy)
{
/* do transmit */
putCharNet();
} /* end if */
} /* end if else */
return;
} /* SCIINT() */

/******************************************************************************/
void NETINT(void)
{
INTU8 dummy;

sciSR1 = SCI0SR1; // read SCI Status Register to clear &
analyze it
netSR1 = SCI1SR1; // read SCI Status Register to clear & analyze it
asm(" bgnd"); /* ### for DEBUG */
asm(" nop"); /* ### for DEBUG */
asm(" nop"); /* ### for DEBUG */

if (netSR1 & (RDRF + TDRE + TC))
{
if (netDir_FLG == SCI_RECEIVE)
{
/* do receive */
NET_ID();
}
else
{
/* do transmit */
NET_SEND();
} /* end if else */
} /* end if else */
// check the OTHER serial port for interrupts ALSO
if (sciSR1 & (OR + NF + FE + PF))
{
/* Receive ERROR */
dummy = SCI0DRL; // clear data regi of ?junk?
}
else if (sciSR1 & RDRF)
{
if (SCI_FLG == SCI_RECEIVE)
{
/* do receive */
getCharSCI();
} /* end if else */
} /* end if else */

if (sciSR1 & (TDRE + TC))
{
/* do transmit */
putCharSCI();
} /* end if else */

return;
} /* NETINT() */

If BOTH SCI0 and SCI1 are polled, no problem at all and both ports
output strings just fine. The moment I turn on SCI1CR2 = TIE+TE+RE;
disaster strikes and the processor is hung up doing SCI0ISR. (cuss)

What is going on? Is there any code I can see that properly handles
the dual SCI (polled+interrupt-driven)?

wade
Waouhhh !
Your system seems to me so complicated !!!
But mybe it's not your system ?

Why only SCI1 interrupt driven, and not SCI0 ?
Below the code (simplified) I use with SCI0 and SCI1 ports, all of them
managed under interrupt.
As you can see, I use data structure handling
- buffer
- read and write pointers from and to the buffer

Now your only have to poll by a function examining if "wr" and "rd" pointers
point on the same address (buffer empty) or not (something in the buffer),
and write a function reading the next byte in the buffer (and managing rd
pointer).

I use ICC12 and NoIce, with 9s12dp256 processor.
With that code, I can put breakpoint with NoIce even on interrupt service
routine, exam what the program do...

I hope this help.
Joel

//---------------------------------
// In a file I named Serial.c

#define SCI1_TAILLE_BUFFER_EMISSION 512
#define SCI1_TAILLE_BUFFER_RECEPTION 512

typedef struct TSci1_BufferEmission
{ Byte buffer[SCI1_TAILLE_BUFFER_EMISSION]; // buffer
Byte *wr, *rd; // pointer to read and write buffer
} TSci1_BufferEmission;

typedef struct TSci1_BufferReception
{ Byte buffer[SCI1_TAILLE_BUFFER_RECEPTION]; // buffer
Byte *wr, *rd; // pointers to read and write buffer
} TSci1_BufferReception;

// Variables file seen (buffers xmit and receive) for SCI0 and SCI1
static TSci1_BufferEmission _sci0_emission;
static TSci1_BufferReception _sci0_reception;

static TSci1_BufferEmission _sci1_emission;
static TSci1_BufferReception _sci1_reception;
void SCI1_Init (void)
{ SCI1BDH = ... depend on the speed
SCI1BDL = ... idem

SCI1CR1 = 0x00;
SCI1CR2 = 0x2c; // enable receive and xmit, int on
receive only
_sci1_emission.wr = _sci1_emission.rd = &sci1_emission.buffer[0];
}

// To transmit a char :
void SCI1_Xmit (char c)
{ // Check if there are place for the new char to transmit

*_sci1_emission.wr = c;
_sci1_emission.wr++;
// circulary buffer
if (_sci1_emission.wr > &_sci1_emission.buffer[TAILLE_EMISSION])
_sci1_emission.wr = &sci1_emission.buffer[0];

// Now, I enable interrupt for transmit the char and transmit buffer
if (SCI1SR1 & 0x80) SCI1CR2 |= 0x88;
}

// Interrupt service routine for SCI1
#pragma interrupt_handler ISR_Sci1
void ISR_Sci1 (void)
{ char sci_status;

sci_status = SCI1SR1;
// Interruption received char
if (sci_status & 0x28) // RDRF 0x20 : Receive data reg full
{ *_sci1_reception.wr = SCI1DRL;
_sci1_reception.wr++;
if (_sci1_reception.wr >=

&_sci1_reception.buffer[SCI1_TAILLE_BUFFER_RECEPTION])
_sci1_reception.wr = &_sci1_reception.buffer[0];
}
// Interruption transmit char
if (sci_status & 0x80) // TDRE : 0x80 ; Xmit Data Reg Empty
{ if (_sci1_emission.rd != _sci1_emission.wr)
SCI1DRL = *_sci1_emission.rd; // xmit current char
_sci1_emission.rd++; // prare next char
if (_sci1_emission.rd >=
&_sci1_emission.buffer[TAILLE_EMISSION])
_sci1_emission.rd = &_sci1_emission.buffer[0];
}
else // no more
char to xmit
{ SCI1CR2 &= 0x3f; // inhibe
interruptions
}
}
}

// The same ISR for SCI0
#pragma interrupt_handler ISR_Sci0
void ISR_Sci0 (void)
{ char sci_status;

sci_status = SCI0SR1;
// Same code as SCI1, but with _sci0_emission and _sci0_reception

}
//---------------------------------
// In a file I named Vectors.c :

extern void ISR_Sci0 (void);
extern void ISR_Sci1 (void);

// Processeur 9S12DP256 : vecteurs interruptions en 0xff80
#pragma abs_address:0xFF80
void (*interrupt_vectors[])(void) =
{ .../...
ISR_Sci1, // $FFD4 SCI1
ISR_Sci0, // $FFD6 SCI0
.../...
_start, // $FFFE Reset, vector to entry point for ICC12
};

> -----Message d'origine-----
> De: 6... [mailto:6...] De la part de
> WadeA & RebeccaM Smith
> Envoy samedi 2 frier 2008 00:41
> : 6...
> Objet: [68HC12] Dual SCI on 9S12D64 confused Interrupt
>
> We are working with a proprietary board based on the Elektronikladen
> CardS12.D64 using ICC12 and NoICE with the ComPOD12 Pro BDM. The
> processor boots up in the TwinPeeks monitor and jumps to the user code
> at 0x8000 where all of our code starts (including startup and init).
>
> SCI1 is interrupt driven RS485. SCI0 is polled RS232 half-duplex.
>
> SCI0 set up:
> SCI0CR2=TE+RE
>
> SCI1 is outputting a string, so it is set up as:
> SCI1CR2=TIE+TE+RE
>
> Initially I did not have any ISR for SCI0, because no interrupts were
> to be set. BUT, I found out that I was ALWAYS receiving an interrupt
> on SCI0.
>
> So now in BOTH ISR functions I check SR1 and respond accordingly.
>
> I set up NoICE and put
> asm(" BGND");
> in both ISR functions and let NoICE run it.
>
> Of course, when it stops at SCI0ISR, TDRE+TC are set and nothing else.
> I check both SCI0SR1 and SCI1SR1 and deal with both (either putChar
> or getChar for each according to the flags).
>
> Why am I getting SCI0 interrupts when none are set and not getting any
> SCI1 interrupts?
>
> locations for the TwinPeeks vectors are:
>
> *(int *)0x3FC5 = (int)NETINT; // SCI1 RS485 interrupt driven
> *(int *)0x3FC2 = (int)SCIINT; // SCI0 Serial RS232 polled
> An assembler "JMP" instruction precedes the address so that TwinPeeks
> will jump to the ISR which ends in the "RTI" instruction.
>
>
> void SCIINT(void)
> {
> INTU8 dummy;
>
> netSR1 = SCI1SR1; // read SCI 1 Status Register to clear &
> analyze it
> sciSR1 = SCI0SR1; // read SCI 0 Status Register to clear &
> analyze it
> asm(" bgnd"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
> if (sciSR1 & (OR + NF + FE + PF))
> {
> /* Receive ERROR */
> dummy = SCI0DR; // clear data regi of ?junk?
> }
> else if (sciSR1 & RDRF)
> {
> if (SCI_FLG == SCI_RECEIVE)
> {
> /* do receive */
> //cmdRecv();
> getCharSCI();
> }
> else
> {
> /* clear data register anyway */
> dummy = SCI0DRL;
> } /* end if else */
> }
> if (sciSR1 & (TDRE + TC))
> {
> /* if data availabe for transmission, do transmit */
> if (txBusy)
> {
> //cmdSend();
> putCharSCI();
> } /* end if */
> } /* end if else */
>
>
> // check the OTHER serial port for interrupts ALSO
> if (netSR1 & (OR + NF + FE + PF))
> {
> /* Receive ERROR */
> }
> else if (netSR1 & RDRF)
> {
> /* do receive */
> getCharNet();
> }
> else if (netSR1 & (TDRE + TC))
> {
> if (ntxBusy)
> {
> /* do transmit */
> putCharNet();
> } /* end if */
> } /* end if else */
>
>
> return;
> } /* SCIINT() */
>
> /*************************************************************************
> *****/
> void NETINT(void)
> {
> INTU8 dummy;
>
> sciSR1 = SCI0SR1; // read SCI Status Register to clear &
> analyze it
> netSR1 = SCI1SR1; // read SCI Status Register to clear & analyze it
> asm(" bgnd"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
>
> if (netSR1 & (RDRF + TDRE + TC))
> {
> if (netDir_FLG == SCI_RECEIVE)
> {
> /* do receive */
> NET_ID();
> }
> else
> {
> /* do transmit */
> NET_SEND();
> } /* end if else */
> } /* end if else */
>
>
> // check the OTHER serial port for interrupts ALSO
> if (sciSR1 & (OR + NF + FE + PF))
> {
> /* Receive ERROR */
> dummy = SCI0DRL; // clear data regi of ?junk?
> }
> else if (sciSR1 & RDRF)
> {
> if (SCI_FLG == SCI_RECEIVE)
> {
> /* do receive */
> getCharSCI();
> } /* end if else */
> } /* end if else */
>
> if (sciSR1 & (TDRE + TC))
> {
> /* do transmit */
> putCharSCI();
> } /* end if else */
>
> return;
> } /* NETINT() */
>
>
>
> If BOTH SCI0 and SCI1 are polled, no problem at all and both ports
> output strings just fine. The moment I turn on SCI1CR2 = TIE+TE+RE;
> disaster strikes and the processor is hung up doing SCI0ISR. (cuss)
>
> What is going on? Is there any code I can see that properly handles
> the dual SCI (polled+interrupt-driven)?
>
> wade
>
>
>
>
>
>
--- In 6..., "jpdi" wrote:
>
> Waouhhh !
> Your system seems to me so complicated !!!
> But mybe it's not your system ?

Are you trying to make snide comments about my most excellent code?
Sorry, something caught in my throat when I said that.

I added code to check the "other" SCI port to try to stop the
interrupts. That didn't seem to help.

> Why only SCI1 interrupt driven, and not SCI0 ?

The code was originally written simplisticly using polling. I am in
the process of converting to interrupt driven, but I've hit a brick
wall with this interrupt nonsence. Interrupts worked fine with one
SCI port in assembler...
Talking with a computer on SCI1, using RS485, I am confident with
interrupts. Talking with a human interactively on SCI0 using RS232,
sort of unnerves me (echo, etc)

> Below the code (simplified) I use with SCI0 and SCI1 ports, all of them
> managed under interrupt.

> I use ICC12 and NoIce, with 9s12dp256 processor.

Hmmmm... sounds familiar, so in theory it should work with mine too.

> With that code, I can put breakpoint with NoIce even on interrupt
service
> routine, exam what the program do...

I will plug it in and see what happens. Wait for the KaBoom....

> I hope this help.

Me too!

> Joel

Thanks, Joel.

wade
Can you read TwinPeeks vector table and confirm that SCI0 vector @FFD6
points to 3FC1 and
@FFD8 - to 3FC4?

I don't see where in ISRs you are disabling TIE interrupt. Are you sending
something forewer? If not, then after you sent last byte, you should disable
TIE, because TDRE is "always" set (until you write some data to TDRE). So
you "always" receive interrupt.

This:
> if (sciSR1 & (TDRE + TC))
also looks weird a bit. Here should be a check for TIE set. But maybe indeed
you have foreve Tx data stream, then it's OK to not check TIE here.
Edward

----- Original Message -----
From: "WadeA & RebeccaM Smith"
To: <6...>
Sent: Saturday, February 02, 2008 1:40 AM
Subject: [68HC12] Dual SCI on 9S12D64 confused Interrupt
> We are working with a proprietary board based on the Elektronikladen
> CardS12.D64 using ICC12 and NoICE with the ComPOD12 Pro BDM. The
> processor boots up in the TwinPeeks monitor and jumps to the user code
> at 0x8000 where all of our code starts (including startup and init).
>
> SCI1 is interrupt driven RS485. SCI0 is polled RS232 half-duplex.
>
> SCI0 set up:
> SCI0CR2=TE+RE
>
> SCI1 is outputting a string, so it is set up as:
> SCI1CR2=TIE+TE+RE
>
> Initially I did not have any ISR for SCI0, because no interrupts were
> to be set. BUT, I found out that I was ALWAYS receiving an interrupt
> on SCI0.
>
> So now in BOTH ISR functions I check SR1 and respond accordingly.
>
> I set up NoICE and put
> asm(" BGND");
> in both ISR functions and let NoICE run it.
>
> Of course, when it stops at SCI0ISR, TDRE+TC are set and nothing else.
> I check both SCI0SR1 and SCI1SR1 and deal with both (either putChar
> or getChar for each according to the flags).
>
> Why am I getting SCI0 interrupts when none are set and not getting any
> SCI1 interrupts?
>
> locations for the TwinPeeks vectors are:
>
> *(int *)0x3FC5 = (int)NETINT; // SCI1 RS485 interrupt driven
> *(int *)0x3FC2 = (int)SCIINT; // SCI0 Serial RS232 polled
> An assembler "JMP" instruction precedes the address so that TwinPeeks
> will jump to the ISR which ends in the "RTI" instruction.
> void SCIINT(void)
> {
> INTU8 dummy;
>
> netSR1 = SCI1SR1; // read SCI 1 Status Register to clear &
> analyze it
> sciSR1 = SCI0SR1; // read SCI 0 Status Register to clear &
> analyze it
> asm(" bgnd"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
> if (sciSR1 & (OR + NF + FE + PF))
> {
> /* Receive ERROR */
> dummy = SCI0DR; // clear data regi of ?junk?
> }
> else if (sciSR1 & RDRF)
> {
> if (SCI_FLG == SCI_RECEIVE)
> {
> /* do receive */
> //cmdRecv();
> getCharSCI();
> }
> else
> {
> /* clear data register anyway */
> dummy = SCI0DRL;
> } /* end if else */
> }
> if (sciSR1 & (TDRE + TC))
> {
> /* if data availabe for transmission, do transmit */
> if (txBusy)
> {
> //cmdSend();
> putCharSCI();
> } /* end if */
> } /* end if else */
> // check the OTHER serial port for interrupts ALSO
> if (netSR1 & (OR + NF + FE + PF))
> {
> /* Receive ERROR */
> }
> else if (netSR1 & RDRF)
> {
> /* do receive */
> getCharNet();
> }
> else if (netSR1 & (TDRE + TC))
> {
> if (ntxBusy)
> {
> /* do transmit */
> putCharNet();
> } /* end if */
> } /* end if else */
> return;
> } /* SCIINT() */
>
> /******************************************************************************/
> void NETINT(void)
> {
> INTU8 dummy;
>
> sciSR1 = SCI0SR1; // read SCI Status Register to clear &
> analyze it
> netSR1 = SCI1SR1; // read SCI Status Register to clear & analyze it
> asm(" bgnd"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
> asm(" nop"); /* ### for DEBUG */
>
> if (netSR1 & (RDRF + TDRE + TC))
> {
> if (netDir_FLG == SCI_RECEIVE)
> {
> /* do receive */
> NET_ID();
> }
> else
> {
> /* do transmit */
> NET_SEND();
> } /* end if else */
> } /* end if else */
> // check the OTHER serial port for interrupts ALSO
> if (sciSR1 & (OR + NF + FE + PF))
> {
> /* Receive ERROR */
> dummy = SCI0DRL; // clear data regi of ?junk?
> }
> else if (sciSR1 & RDRF)
> {
> if (SCI_FLG == SCI_RECEIVE)
> {
> /* do receive */
> getCharSCI();
> } /* end if else */
> } /* end if else */
>
> if (sciSR1 & (TDRE + TC))
> {
> /* do transmit */
> putCharSCI();
> } /* end if else */
>
> return;
> } /* NETINT() */
>
> If BOTH SCI0 and SCI1 are polled, no problem at all and both ports
> output strings just fine. The moment I turn on SCI1CR2 = TIE+TE+RE;
> disaster strikes and the processor is hung up doing SCI0ISR. (cuss)
>
> What is going on? Is there any code I can see that properly handles
> the dual SCI (polled+interrupt-driven)?
>
> wade
--- In 6..., "Edward Karpicz" wrote:
>
> Can you read TwinPeeks vector table and confirm that SCI0 vector @FFD6
> points to 3FC1 and
> @FFD8 - to 3FC4?

AHA! That IS the problem! Originally SCI0 was the RS485 and SCI1 was
the RS232. I swapped them in the RAM table because the EEs has
swapped the usage of the SCI ports. Everything else in the table goes
in assending address except SCI0 and SCI1.

D'OH!

> I don't see where in ISRs you are disabling TIE interrupt. Are you
sending
> something forewer? If not, then after you sent last byte, you should
disable
> TIE, because TDRE is "always" set (until you write some data to
TDRE). So
> you "always" receive interrupt.

SCI0 never has TIE set. SCI1 has it set until EndOfMessage has been
sent out and then it reverts back to RIE+TE+RE and a PortH bit is
set/clr to RECEIVE485.
The SCI1 Send function handles that decision.

> This:
> > if (sciSR1 & (TDRE + TC))
> also looks weird a bit. Here should be a check for TIE set. But
maybe indeed
> you have foreve Tx data stream, then it's OK to not check TIE here.

For RS485 I must absolutely know when the last character has finished
transmitting (sent out the shift register). So when the EndOfMessage
character is put into the TransmitDataRegister, the Send function
changes the SCI1CR2 = TCIE+TE+RE (it was TIE+TE+RE) so that I know
when it is time to switch to RECEIVE485 from TRANSMIT485. TDRE will
not be indicated, but TC will and then it is time to switch.

activity SCI1CR2 setting
--------------------- ---------------
normal mode RIE+TE+RE
response built
Switch to transmit TIE+TE+RE
loag character into TDR loop here for message
normal message character TIE+TE+RE loop here for message
TDRE fires loop here for message
load EndOfMessage into TDR TCIE+TE+RE
TC fires
Switch to receive RIE+TE+RE

Thanks for the second pair of eyes on the TwinPEEKS RAM vectors!

wade
I'm so sorry !
It was not my goal to make "snide comments" (sorry, my English is not so
good to understand all the words) !
But it seems to me you smiled about that ?

Anyway, I hope you find a solution for your problem !

Joel
> -----Message d'origine-----
> De: 6... [mailto:6...] De la part de
> WadeA & RebeccaM Smith
> Envoy samedi 2 frier 2008 17:43
> : 6...
> Objet: [68HC12] Re: Dual SCI on 9S12D64 confused Interrupt
>
> --- In 6..., "jpdi" wrote:
> >
> > Waouhhh !
> > Your system seems to me so complicated !!!
> > But mybe it's not your system ?
>
> Are you trying to make snide comments about my most excellent code?
> Sorry, something caught in my throat when I said that.
>
> I added code to check the "other" SCI port to try to stop the
> interrupts. That didn't seem to help.
>
> > Why only SCI1 interrupt driven, and not SCI0 ?
>
> The code was originally written simplisticly using polling. I am in
> the process of converting to interrupt driven, but I've hit a brick
> wall with this interrupt nonsence. Interrupts worked fine with one
> SCI port in assembler...
> Talking with a computer on SCI1, using RS485, I am confident with
> interrupts. Talking with a human interactively on SCI0 using RS232,
> sort of unnerves me (echo, etc)
>
> > Below the code (simplified) I use with SCI0 and SCI1 ports, all of them
> > managed under interrupt.
>
> > I use ICC12 and NoIce, with 9s12dp256 processor.
>
> Hmmmm... sounds familiar, so in theory it should work with mine too.
>
> > With that code, I can put breakpoint with NoIce even on interrupt
> service
> > routine, exam what the program do...
>
> I will plug it in and see what happens. Wait for the KaBoom....
>
> > I hope this help.
>
> Me too!
>
> > Joel
>
> Thanks, Joel.
>
> wade
>




The 2024 Embedded Online Conference