SPI, how to know when CS can be returned high, Processor Expert beans

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

SPI, how to know when CS can be returned high, Processor Expert beans

1,960 Views
AndersJ
Contributor IV

HCS12XEP100, CW 4,7 and Processor Expert Synchromaster bean.

 

Q1.

===

I need to send more than one byte while CS is active low.

I use a port to generate CS.

How do I detect that all SPI clocks have been generated, allowing me to return CS high?

 

Q2.

===

I use a MCP2515 CAN controller.

It needs 3 SPI bytes to read a register on the MCP

Byte 1: "Read command"

Byte 2; "Register selection"

Byte 3: "Dummy byte" to generate the clocks needed to output the register content

 

For some reason I seem to need to use the bean function RecvChar twice,

with a slight delay between them, in order to read the register back.

The delay is also related to the clock setting used.

The faster the clock the less delay needed.

 

How do I determine when the clocking is done, allowing me to read the data received?

Will data received while clocking the first 2 bytes need reading/clearing,

or is it always the data clocked in last that is available?

 

Q3:

===

When the MCP generates a interrupt I need to acknowledge it in the ISR,

to release the interrupt line.

Are there any limitations in how the Processor Expert bean(s) can be used in a ISR?

 

Thanks for any comments,

Anders J

Labels (1)
0 Kudos
Reply
7 Replies

876 Views
Lundin
Senior Contributor IV

> How do I detect that all SPI clocks have been generated, allowing me to return CS high?

 

When programming, you would check the SPTEF flag. I have no idea how to do it with beans.

 

> For some reason I seem to need to use the bean function RecvChar twice, with a slight delay between them, in order to read the register back.

 

SPI is not standardized. Any device is free to implement their own mystical delays and dependencies, and flank trigging (bits CPHA and CPOL is the Freescale MCU). It is very common that you get so-called "clock skew" when working with SPI, ie the master and slave are clocking data differently. This issue smells like it. You will need to read the data sheet of the device in detail, hoping that they specified their SPI needs.

 

> How do I determine when the clocking is done, allowing me to read the data received?

 

SPRF, once per received byte.

 

> Will data received while clocking the first 2 bytes need reading/clearing, or is it always the data clocked in last that is available?

The latest data is indeed always clocked into the data buffer when you send something (assuming MCU = master). The best implementation is to clear the SPRF flag for each data received, by reading it, followed by a read to the data register. Otherwise there is no way for you to be certain when the actual data arrives.

 

Since you are probably master and determines the send pace, you could of course make a qualified guess of when it is available. But that's more of a quick & dirty solution, and not acceptable when designing realtime systems.

 

How Mr. Bean implements this, I have no idea.

 

> Are there any limitations in how the Processor Expert bean(s) can be used in a ISR?

 

Certainly. I would not trust any automatically generated code inside an ISR as the code there should be kept to a minimum. And no matter whether you are C programming or beaning, you will want to check the generated disassembly, to ensure that the flags are properly cleared.

 

Incorrect flag clearing in ISRs is one of the most frequent bugs in embedded systems, and every darn MCU clears their flags differently. Especially Freescale, who has managed the remarkable feat of having literally every interrupt in every peripheral cleared in an unique way.

 

So when you disassemble the ISR, you can check if PE is doing anything resouce-heavy there at the same time.

0 Kudos
Reply

876 Views
AndersJ
Contributor IV

Lundin, thanks for valuable input.

 

I have stripped the problem to a minimum, and issues remain:

* Polling SPIF sems to not work. SPIF is always 1

* SPIDRL needs to be read twice to return the rx'd byte

 

I must be making a stupid mistake, but I cannot figure it out.

See code below.

Anders J

 

static unsigned char ReadStatus(void)
{
  unsigned char RxChar;
    
  Set_CS_Lo(); // Assert CS

  SPI2DRL = cMCPInstruction_ReadStatus; // Request data from device

  while ((SPI2SR & 0x20) == 0); // Vait for empty SPI tx buffer
    
  App_Driver_Debug_SetDebug(2, TRUE);  
  RxChar = (SPI2SR | SPI2DRL); // Clear SPI Rx received data flag

                               //  by reading both regs


  SPI2DRL = 0;                 // 8 clocks to read SPI data

  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx while SPIF = 0
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
  while ((SPI2SR & 0x80) == 0); // Wait for SPI rx
                                // End of clocking

                                // due to exe time,

                                // not due to SPIF

                                // SPIF loop does not work

                                // SPIF is always 1  

                             
  App_Driver_Debug_SetDebug(2, FALSE);  
  RxChar = SPI2DRL; // Read SPI rx - Reads back 0x00
  RxChar = SPI2DRL; // Read SPI rx - Reads back correctly
                    // The data IS physically available.

                    // Verified by scoping hardware.
                    
  App_Driver_Debug_SetDebug(2, TRUE);  
  App_Driver_Debug_SetDebug(2, FALSE);  

  Set_CS_Hi();  // Negate CS
  return RxChar;
}



 

0 Kudos
Reply

876 Views
kef
Specialist I

Is this working the same also in normal mode (without debugger)? Because write to data register should not work properly without leading read from status register.

SPI on S12X is fully double buffered. It means you can send two bytes from master and read both received bytes from data register after both trransfers are complete.

Try using this routine for all transfers. It won't exit until byte transfer is complete. Use returned byte when relevant.

 

char puspi(char c)

{

   while( !(SPI2SR & SPI2SR_SPTEF_MASK) )

   {

   }

 

   SPI2DR = c;

 

   while( !(SPI2SR & SPI2SR_SPIF_MASK) )

   {

   }

 

   return SPI2DR;

}

 

0 Kudos
Reply

876 Views
AndersJ
Contributor IV

Normal mode, no debugger.

 

I am tempted so say I am doing exactly what you suggest,

but at this point, I dare not be sure of anything.

 

But, and here is where I believe the big difference is,

I don't think your code will work if called in rapid succession with CS asserted during

the entire procedure, IF your code execution speed is "fast" related to SPI baudrate.

 

What I think happens is this:

 

SPIF must be clear before sending a byte, IF you need to read rx data after ALL clocks are generated.

If you do not clear SPIF first, it may already be set before loading SPI2DR for transmission.

In that case the while(SPIF) loop falls through immediately even if clock pulses still remain to be generated.

 

In addition to the above, if you send the next character

(remember I need to send a "READ-Instruction first, THEN a dummy byte to sample the rx data)

as soon as the transmit register is empty (SPTEF=1) right after clearing SPIF,

there will be clocks remaining to be generated (if baudrate is low compared to exec time).

These remaing clocks, perhaps only 1 or 2, will then affect when SPIF is set,

(not sure about SPI internal details, perhaps something else goes on)

and this will happen earlier than wanted, while the last byte (dummy byte in my case)

is being clocked out. That is when I incorrectly read SPI2DRL which has not yet been

loaded with the incoming character, because clocking has not yet ended.

 

My hypothesis is:

When needing to read data back in a multibyte protocol,

do not send data back to back when SPTEF=1.

Instead, clear SPIF, send, wait for SPIF=1, THEN send the next byte, or read incoming data.

 

For send only, SPTEF will work.

End of hypothesis.

 

There may be flaws in my reasoning and verbosity,

but I'm relatively sure that this is more or less what is happening.

If nothing else my problems seem to be gone.

 

Comments are extremely appreciated,

Anders J

0 Kudos
Reply

876 Views
kef
Specialist I
  • Normal mode, no debugger.

Then your code shouldn't send at all. Maybe yet another "silent" and "unimportant" modification to SPI in S12XE made it working. To send you need to clear SPTEF flasg. This is done by reading status, then writing data register.

 

 

  • I am tempted so say I am doing exactly what you suggest,

No.

  

  • But, and here is where I believe the big difference is,
  • I don't think your code will work if called in rapid succession with CS asserted during
  • the entire procedure, IF your code execution speed is "fast" related to SPI baudrate.

It should work, unless you are interfacfing some odd hardware, that requires back to back transfers with uninterrupted SPI clock. Make compiler inlining this function and you should be fine.

 

 

  • SPIF must be clear before sending a byte, IF you need to read rx data after ALL clocks are generated.
  • If you do not clear SPIF first, it may already be set before loading SPI2DR for transmission.
  • In that case the while(SPIF) loop falls through immediately even if clock pulses still remain to be generated.

Yes, you should clear SPIF for every TX-ed byte,  else you won't be able to determine the end of transfer, and may toggle CS too early. Since SPI on new S12X is fully double buffered, you may queue up to two TX bytes each time (wait for SPTEF, write SPDR, wait for SPTEF, write SPDR), then up to two times wait for SPIF and read SPDR.

 

  • In addition to the above, if you send the next character
  • (remember I need to send a "READ-Instruction first, THEN a dummy byte to sample the rx data)
  • as soon as the transmit register is empty (SPTEF=1) right after clearing SPIF,
  • there will be clocks remaining to be generated (if baudrate is low compared to exec time).
  • These remaing clocks, perhaps only 1 or 2, will then affect when SPIF is set,
  • (not sure about SPI internal details, perhaps something else goes on)
  • and this will happen earlier than wanted, while the last byte (dummy byte in my case)
  • is being clocked out. That is when I incorrectly read SPI2DRL which has not yet been
  • loaded with the incoming character, because clocking has not yet ended.

SPIF is set when data transfer is fully completed, all 8 clocks. But you need to clear SPIF after each byte, else you won't be able to determine the end of multibyte transfer, because SPIF will remain set from previous transfers and won't indicate the end of transfer.

 

Double buffered SPI on new S12X allows you to send bytes back to back, but you need to handle every SPIF=1 to determine the end of transfer.

0 Kudos
Reply

876 Views
AndersJ
Contributor IV

Please define "Normal mode"

I run my sw in real hardware, code in flash, etc. MODC=1, MODB = MODA=0. Isn't this Normal mode?

Why should my code not send at all?

 

"wait for SPTEF, write SPDR"

Why is this necessary?

Is it not safe to assume that SPTEF = 1 when SPIF=1, after data has been received?

 

 

 

0 Kudos
Reply

876 Views
kef
Specialist I

Yes, this is normal singlechip mode, but debuggers usually pull MODC=0 and reset MCU into special  singlechip mode. Debuggers use special singlechip mode.

 

S12XD SPTEF bit description:

If set, this bit indicates that the transmit data register is empty. To clear this bit and place data into the transmit data register, SPISR must be read with SPTEF = 1, followed by a write to SPIDR.

 

S12XE datasheet is in principle the same, but after adding table 21-9, it got bit fuzzy about necessity of clearing SPTEF flag. No must anymore. I believe this is wrong.

0 Kudos
Reply