Reply by Mike Elphick January 24, 20052005-01-24
Wade,

Just to add that you should read the errata: -

http://www.freescale.com/files/microcontrollers/doc/errata/MSE9S12D64_1L86D.pdf

Where is states: -

"[When the SPI is enabled in master mode, with the CPHA bit set] After the SPTEF flag is set, a delay of half an SCK period has to be added before storing data into the SPI Data Registers." (Page 5)

I can't see this delay in your code!

Of course you don't have to use an SPI port. Since you are not relying on interrupts and you are already toggling bits, why don't you go all the way and 'bit bang' the complete procedure? You may find you have more control this way.

Hope this helps.

Mike From Edward Karpicz (in reply to Wade A Smith), Saturday, January 22, 2005 7:19 PM: -

> Hi

> > To all you HC12 guru types,

> > I sent an email to freescale because I am having strange things happening
> > with
> > SPI. All he could see is that I toggled a bit in PortK and he fussed
> > about
> > setting and clearing flags using BCLR/BSET. I wish he took the time to
> > read.


> SPI flags aren't cleared by writing one to. But he was partly right. Problem
> lies in clearing of flags. See below.


> > I'm working with a numeric LCD that takes a pulse, SPI data, a pulse for
> > each digit (location + BCD 0-9 and 'HELP -' for 0xA-0xF using maxim
> > 7232B).

> > Assumptions:
> > - if SPI0CR1 has SPIE=off SPE=ON SPTIE=off MSTR=ON CPOL=ON CPHA=ON
> > SSOE=ON LSBFE=off, then the SPIF and SPTEF flags will be set in SPI0SR
> > but no interrupts will occur.
> > - when the 8th data bit is clocked out, the SPIF flag will become a 1
> > until the next read of the SPI0SR

> .. followed by read of SPI0DR!

> > - the SPTEF flag is set when the data register is moved to the shift
> > register

> > What the 'scope shows is that after 2-3 SPI clocks, the second toggle
> > occurs and
> > the digit is lost. However, if I generously supply some delays
> > (basically ignoring the
> > SPIF -- since interrupts are turned off for SPI), the code works. But if
> > I depend on
> > the SPIF, the code is broken. The loc+digit takes 16 microsec to
> > transmit, so
> > giving it 30 microsec delays allows it to work.

> > This does NOT work:

> > STAB BUFFER2 ; save loc+digit
> > BCLR PORTK #$20 ; toggle
> > JSR DELAY10U ; make sure it is seen
> > BSET PORTK #$20 ; toggle
> > JSR DELAY10U ; make sure it is seen
> > LDAA DPFLAG
> > BEQ NUM_C4 ; branch around other stuff
> > <snip> ; do some other stuff
> > NUM_C4 LDAB BUFFER2 ; ready for the loc+digit now
> > LDAA SPI0SR ; this *should* clear Status Register
> > BRCLR SPI0SR,#SPTEF,* ; make sure the Tx is empty


> Reading of SPISR *shouldn't* clear SPISR. To clear SPIF you have to read
> SPI0SR then read SPI0DR. Your read of SPI0DR comes after while(!(SPI0SR &
> 0x80)).

<---- Add a delay here

> > STAB SPI0DR ; transmit a loc+digit
> > NUM_C5 LDAA SPI0SR ; check the Status Register
> > BPL NUM_C5 ; loop until SPIF is set
> > LDAB SPI0DR ; make sure I clear DR
> > BCLR PORTK #$20 ; toggle
> > JSR DELAY10U ; make sure it is seen
> > BSET PORTK #$20 ; toggle
> > RTS

> > This DOES work:

> > STAB BUFFER2 ; save loc+digit
> > BCLR PORTK #$20 ; toggle
> > JSR DELAY10U ; make sure it is seen
> > BSET PORTK #$20 ; toggle
> > JSR DELAY10U
> > LDAA DPFLAG
> > BEQ NUM_C4
> > <snip> ; do some other stuff
> > NUM_C4 LDAB BUFFER2 ; ready for the loc+digit now
> > LDAA SPI0SR ; this *should* clear Status Register
> > BRCLR SPI0SR,#SPTEF,* ; make sure the Tx is empty

<---- Add a delay here

> > STAB SPI0DR ; transmit a loc+digit
> > JSR DELAY10U ; WORKS WITH THIS IN ;
> > JSR DELAY10U ; WORKS WITH THIS IN ;
> > NUM_C5 LDAA SPI0SR ; check the Status Register
> > BPL NUM_C5 ; loop until SPIF is set
> > LDAB SPI0DR ; make sure I clear DR
> > JSR DELAY10U ; WORKS WITH THIS IN ;
> > BCLR PORTK #$20 ; toggle
> > JSR DELAY10U ; make sure it is seen
> > BSET PORTK #$20 ; toggle
> > RTS

> > The primary question was and is "why is the SPIF already ON after
> > we 1) read the SPI0SR (I've already done the read SPI0DR earlier
> > to make sure the DataRegister is empty) 2) write to the SPI0DR
> > such that the 'BPL NUM_C5' instruction never takes the branch
> > and always drops through?"

> To clear SPIF you have to read SPI0SR then read SPI0DR. Reading of SPI0DR
> followed by reading of SPI0SR doesn't work too.

> > There are 3 "JSR DELAY10U" (delay 10 micro sec) instructions
> > that allows the code to work, if those are removed, the code
> > does not work SINCE THE SPIF DOES NOT WORK as

> It works.


> > advertised. I say that because the code drops right through
> > to the toggle, which causes the device to stop accepting data

> > We read the SPI0DR; we read the SPI0SR then we start looking
> > for SPTEF to be ON so we can write SPI0DR; then we try
> > to look for the SPIF, but it is already ON. WHY?

> Calm down, make a break. Weekend isn't gone.

> > IF there is a problem with the code then PLEASE do point
> > it out. All I know is that according to the code the I execute
> > and the 'scope, the SPIF DOES NOT WORK AS ADVERTISED.

> > I will be GLAD to fix my code if you can point out some
> > valid misconceptions that I am using. Otherwise this is
> > a bug in the SPI.

> > BTW, the HC11E20 code this is based upon works
> > wonderfully well -- buit the HC9S12D64 is disappointing.

> Maybe I forgot HC11 completely, but HC11 SPI flags were cleared same way.

> Good luck,
> Edward
> > wade




Reply by Edward Karpicz January 22, 20052005-01-22
Hi

> To all you HC12 guru types,
>
> I sent an email to freescale because I am having strange things happening
> with
> SPI. All he could see is that I toggled a bit in PortK and he fussed
> about
> setting and clearing flags using BCLR/BSET. I wish he took the time to
> read.


SPI flags aren't cleared by writing one to. But he was partly right. Problem
lies in clearing of flags. See below. > I'm working with a numeric LCD that takes a pulse, SPI data, a pulse for
> each digit (location + BCD 0-9 and 'HELP -' for 0xA-0xF using maxim
> 7232B).
>
> Assumptions:
> - if SPI0CR1 has SPIE=off SPE=ON SPTIE=off MSTR=ON CPOL=ON CPHA=ON
> SSOE=ON LSBFE=off, then the SPIF and SPTEF flags will be set in SPI0SR
> but no interrupts will occur.
> - when the 8th data bit is clocked out, the SPIF flag will become a 1
> until the next read of the SPI0SR


... followed by read of SPI0DR!
> - the SPTEF flag is set when the data register is moved to the shift
> register
>
> What the 'scope shows is that after 2-3 SPI clocks, the second toggle
> occurs and
> the digit is lost. However, if I generously supply some delays
> (basically ignoring the
> SPIF -- since interrupts are turned off for SPI), the code works. But if
> I depend on
> the SPIF, the code is broken. The loc+digit takes 16 microsec to
> transmit, so
> giving it 30 microsec delays allows it to work.
>
> This does NOT work:
>
> STAB BUFFER2 ; save loc+digit
> BCLR PORTK #$20 ; toggle
> JSR DELAY10U ; make sure it is seen
> BSET PORTK #$20 ; toggle
> JSR DELAY10U ; make sure it is seen
> LDAA DPFLAG
> BEQ NUM_C4 ; branch around other stuff
> <snip> ; do some other stuff
> NUM_C4 LDAB BUFFER2 ; ready for the loc+digit now
> LDAA SPI0SR ; this *should* clear Status Register
> BRCLR SPI0SR,#SPTEF,* ; make sure the Tx is empty


Reading of SPISR *shouldn't* clear SPISR. To clear SPIF you have to read
SPI0SR then read SPI0DR. Your read of SPI0DR comes after while(!(SPI0SR &
0x80)). > STAB SPI0DR ; transmit a loc+digit
> NUM_C5 LDAA SPI0SR ; check the Status Register
> BPL NUM_C5 ; loop until SPIF is set
> LDAB SPI0DR ; make sure I clear DR
> BCLR PORTK #$20 ; toggle
> JSR DELAY10U ; make sure it is seen
> BSET PORTK #$20 ; toggle
> RTS
>
> This DOES work:
>
> STAB BUFFER2 ; save loc+digit
> BCLR PORTK #$20 ; toggle
> JSR DELAY10U ; make sure it is seen
> BSET PORTK #$20 ; toggle
> JSR DELAY10U
> LDAA DPFLAG
> BEQ NUM_C4
> <snip> ; do some other stuff
> NUM_C4 LDAB BUFFER2 ; ready for the loc+digit now
> LDAA SPI0SR ; this *should* clear Status Register
> BRCLR SPI0SR,#SPTEF,* ; make sure the Tx is empty
> STAB SPI0DR ; transmit a loc+digit
> JSR DELAY10U ; WORKS WITH THIS IN ;
> JSR DELAY10U ; WORKS WITH THIS IN ;
> NUM_C5 LDAA SPI0SR ; check the Status Register
> BPL NUM_C5 ; loop until SPIF is set
> LDAB SPI0DR ; make sure I clear DR
> JSR DELAY10U ; WORKS WITH THIS IN ;
> BCLR PORTK #$20 ; toggle
> JSR DELAY10U ; make sure it is seen
> BSET PORTK #$20 ; toggle
> RTS > The primary question was and is "why is the SPIF already ON after
> we 1) read the SPI0SR (I've already done the read SPI0DR earlier
> to make sure the DataRegister is empty) 2) write to the SPI0DR
> such that the 'BPL NUM_C5' instruction never takes the branch
> and always drops through?"

To clear SPIF you have to read SPI0SR then read SPI0DR. Reading of SPI0DR
followed by reading of SPI0SR doesn't work too. >
> There are 3 "JSR DELAY10U" (delay 10 micro sec) instructions
> that allows the code to work, if those are removed, the code
> does not work SINCE THE SPIF DOES NOT WORK as

It works. > advertised. I say that because the code drops right through
> to the toggle, which causes the device to stop accepting data
>
> We read the SPI0DR; we read the SPI0SR then we start looking
> for SPTEF to be ON so we can write SPI0DR; then we try
> to look for the SPIF, but it is already ON. WHY?

Calm down, make a break. Weekend isn't gone. >
> IF there is a problem with the code then PLEASE do point
> it out. All I know is that according to the code the I execute
> and the 'scope, the SPIF DOES NOT WORK AS ADVERTISED.
>
> I will be GLAD to fix my code if you can point out some
> valid misconceptions that I am using. Otherwise this is
> a bug in the SPI.
>
> BTW, the HC11E20 code this is based upon works
> wonderfully well -- buit the HC9S12D64 is disappointing.

Maybe I forgot HC11 completely, but HC11 SPI flags were cleared same way.

Good luck,
Edward

>
>
> wade




Reply by Wade A Smith January 22, 20052005-01-22
To all you HC12 guru types,

I sent an email to freescale because I am having strange things happening
with
SPI. All he could see is that I toggled a bit in PortK and he fussed
about
setting and clearing flags using BCLR/BSET. I wish he took the time to
read.

I'm working with a numeric LCD that takes a pulse, SPI data, a pulse for
each digit (location + BCD 0-9 and 'HELP -' for 0xA-0xF using maxim
7232B).

Assumptions:
- if SPI0CR1 has SPIE=off SPE=ON SPTIE=off MSTR=ON CPOL=ON CPHA=ON
SSOE=ON LSBFE=off, then the SPIF and SPTEF flags will be set in SPI0SR
but no interrupts will occur.
- when the 8th data bit is clocked out, the SPIF flag will become a 1
until the next read of the SPI0SR
- the SPTEF flag is set when the data register is moved to the shift
register

What the 'scope shows is that after 2-3 SPI clocks, the second toggle
occurs and
the digit is lost. However, if I generously supply some delays
(basically ignoring the
SPIF -- since interrupts are turned off for SPI), the code works. But if
I depend on
the SPIF, the code is broken. The loc+digit takes 16 microsec to
transmit, so
giving it 30 microsec delays allows it to work.

This does NOT work:

STAB BUFFER2 ; save loc+digit
BCLR PORTK #$20 ; toggle
JSR DELAY10U ; make sure it is seen
BSET PORTK #$20 ; toggle
JSR DELAY10U ; make sure it is seen
LDAA DPFLAG
BEQ NUM_C4 ; branch around other stuff
<snip> ; do some other stuff
NUM_C4 LDAB BUFFER2 ; ready for the loc+digit now
LDAA SPI0SR ; this *should* clear Status Register
BRCLR SPI0SR,#SPTEF,* ; make sure the Tx is empty
STAB SPI0DR ; transmit a loc+digit
NUM_C5 LDAA SPI0SR ; check the Status Register
BPL NUM_C5 ; loop until SPIF is set
LDAB SPI0DR ; make sure I clear DR
BCLR PORTK #$20 ; toggle
JSR DELAY10U ; make sure it is seen
BSET PORTK #$20 ; toggle
RTS

This DOES work:

STAB BUFFER2 ; save loc+digit
BCLR PORTK #$20 ; toggle
JSR DELAY10U ; make sure it is seen
BSET PORTK #$20 ; toggle
JSR DELAY10U
LDAA DPFLAG
BEQ NUM_C4
<snip> ; do some other stuff
NUM_C4 LDAB BUFFER2 ; ready for the loc+digit now
LDAA SPI0SR ; this *should* clear Status Register
BRCLR SPI0SR,#SPTEF,* ; make sure the Tx is empty
STAB SPI0DR ; transmit a loc+digit
JSR DELAY10U ; WORKS WITH THIS IN ;
JSR DELAY10U ; WORKS WITH THIS IN ;
NUM_C5 LDAA SPI0SR ; check the Status Register
BPL NUM_C5 ; loop until SPIF is set
LDAB SPI0DR ; make sure I clear DR
JSR DELAY10U ; WORKS WITH THIS IN ;
BCLR PORTK #$20 ; toggle
JSR DELAY10U ; make sure it is seen
BSET PORTK #$20 ; toggle
RTS The primary question was and is "why is the SPIF already ON after
we 1) read the SPI0SR (I've already done the read SPI0DR earlier
to make sure the DataRegister is empty) 2) write to the SPI0DR
such that the 'BPL NUM_C5' instruction never takes the branch
and always drops through?"

There are 3 "JSR DELAY10U" (delay 10 micro sec) instructions
that allows the code to work, if those are removed, the code
does not work SINCE THE SPIF DOES NOT WORK as
advertised. I say that because the code drops right through
to the toggle, which causes the device to stop accepting data

We read the SPI0DR; we read the SPI0SR then we start looking
for SPTEF to be ON so we can write SPI0DR; then we try
to look for the SPIF, but it is already ON. WHY?

IF there is a problem with the code then PLEASE do point
it out. All I know is that according to the code the I execute
and the 'scope, the SPIF DOES NOT WORK AS ADVERTISED.

I will be GLAD to fix my code if you can point out some
valid misconceptions that I am using. Otherwise this is
a bug in the SPI.

BTW, the HC11E20 code this is based upon works
wonderfully well -- buit the HC9S12D64 is disappointing. wade