HCS08SG16/32 port reads wrong value

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

HCS08SG16/32 port reads wrong value

Jump to solution
1,809 Views
ttom
Contributor I

Hello again,

I have a problem when communicating with a device via SPI. 

I have to start the spi communication and wait for a port of the slave device to be set, but it seems, that the microcontroller reads the port as set when it is not set at this moment.

 

I am the SPI - master, the other device is SPI slave.

I have to send the adress byte and the length byte first. Then I have to wait, until the slave device pulls up its MISO output, then I can proceed with communication and read the data.

 

I use the USB Multilink interface to debug my target hardware (it runs at 3,3 V).

 

When I manually step the code, it seems, that it always work. When I let it run without breakpoints, then I sometimes get a wrong value (wrong value: always 0) back. I "debugged" it by hardware and I have seen, that in case of getting a wrong value, my routine does not wait until the slave device pulls its MISO output high.

 

I don't know, whats wrong with my code. There are no pullup or pulldown resistors activated.

 

#define CHECK_MISO_LINE   (PTBD_PTBD4>0?0:1)

 

 

void SPIread (CS_t cs, uint8_t addr, uint8_t len, uint8_t * d)
{
  uint8_t i, j;

  delay_us (PREDELAY);  // minimum delay, if we have subsequent calls

  spi_setcs (cs);          // set chipselect
  delay_us (DEVICE_PREPARE); // minimum delay for device to get ready after beeing selected

 

  j = 1;

  while (j)  // check the MISO line of the slave

  {
    j = CHECK_MISO_LINE;  

  }


  spi_SendByte (addr);  // send adress and length and wait for MISO line going high

  spi_SendByte (len);
  j = 1;
  while (j)
  {
    j = CHECK_MISO_LINE;
  }

  for (i = 0; i < len; i++)  // do the read access to the slave

  {
    *d = spi_TransferByte (0);
    d++;
  }


  delay_us (DEVICE_PREPARE); // delay again...

  j = 1;
  while (j)
  {
    j = CHECK_MISO_LINE;
  }

  spi_resetcs (cs);   // reset the chipselect to stop this access
}

 

The functions spi_setcs() and spi_resetcs() are setting and resetting the chipselect pins. 

 

In case of error, I can see at the oscilloskope, that the routine spi_read() is continuing with the  spi_Transferbyte() - calls, while the MISO - line is not set.

 

I don't know, if this is important: The SPI - clock is very slow, because the device is very slow and only allows a maximum SPI - clock of 75 kHz. I have tested it with a bus clock of about 70 and in a further step with 8 kBit. It seems, that it is independent from the clock.

 

If I restart the debug session with strg - shift - F5, I get sometimes an error out of the code warrior, that it is not possible to set a breakpoint at a certain adress. If I restart the Emulator window, it works agian for a while.  Maybe this is a second problem?

 

Many thanks in advance,

Thomas

Labels (1)
0 Kudos
1 Solution
562 Views
bigmac
Specialist III

Hello Thomas,

 

With your present code, when the SendByte() function exits, the SPI transfer will not have been completed, and this is the probable cause of your problem.  In addition, because the SPRF flag has not been cleared, an overrun condition is likely to be present when the first data byte is returned.

 

As I said in my previous post, SPI operation is a two-way process.  The master will always read a return byte at MISO simultaneously with sending a byte from MOSI. Therefore, I would tend to use a common function for master SPI communications that waits until each SPI transfer is complete, and then clears the SPRF flag.  There is no need to explicitly clear the SPTEF flag.

 

byte SPI_transfer( byte val)

{

   while (!SPIS_SPTEF);

   SPID = val;

   while (!SPIS_SPRF);  // Wait for transfer complete

   return SPID;         // Also clears flag

}

 

 

delay_us( PREDELAY);
spi_setcs(cs);
delay_us(
DEVICE_PREPARE);
while (!
CHECK_MISO_LINE) ;

(void)SPI_transfer( addr);
(void)SPI_transfer( len);
while (!
CHECK_MISO_LINE);

for (i = 0; i < len; i++) {
   *d =
SPI_transfer(0);
   d++;
}
delay_us(
DEVICE_PREPARE);
while (!
CHECK_MISO_LINE);
spi_resetcs(cs);

 

The use of the casts will prevent compiler warnings when return data is ignored.

 

Regards,

Mac

View solution in original post

0 Kudos
6 Replies
562 Views
bigmac
Specialist III

Hello Thomas,

 

It would seem that the SPI slave device has special requirements that are outside of normal SPI communication.  You appear to be attempting to read the MISO line as a GPIO input, which is not possible whilst the SPI module is enabled.  Whilst waiting for the slave to set the MISO line high, the SPI module would need to be disabled.  The SPI module can then be enabled just prior to sending the address byte, etc.

 

I assume that your spi_SendByte() function does clear the SPRF flag by waiting until the flag is set, and  then reading the SPID register.  I do not see your need for the function spi_TransferByte().  SPI operation is always a two-way process, so a single communications function to send and receive will usually suffice.

 

Note that your use of the macro  PTBD_PTBD4 is based on the use of a bit field, so will already have the value 0 or 1 only.  The test of the line might therefore be simplified to the following:

 

#define MISO_LINE  PTBD_PTBD4

 

while (!MISO_LINE);  // Wait for MISO line high 

 

Regards,

Mac

0 Kudos
562 Views
ttom
Contributor I

Hello,

thank you for your explanations.

According to your hints, i tried the following:

first try:

I send the adress and the length byte to the slave.

Then I wait for the SPI transfer to become ready (polling the SPRF - flag to become 1)

and then disabling the SPI interface by clearing the SPE flag

polling the MISO pin until it goes high

enabling spi again

going on with data transfer (result from spi slave)

 

With this setup the transfer does not stop after sending the length field as it should but goes on immediately with the transfer. 

So, I tried with a hardware modification:

 

second try:

I added a wire from the MISO pin to a free GPIO (Port A, Pin 2) and poll this GPIO without disabling the SPI - interface between.

 

It seems, (in both cases), that the first polling is ignored, but the second polling is done correctly (the polling, before releasing the chipselect). I see it on the oszilloskope, that if I want to read 1 Byte, I get a transfer of 3 (adress, length and immideately the data byte) Bytes, but the 3rd Byte is immediately read. The function does not wait until the MISO / PTA2 pin goes high. With the second polling of this pin (before reset the chipselect line) it seems to runs correctly.

 

Here is my code with the second variant:

 

#define CHECK_MISO_LINE PTAD_PTAD2

 

void
SPIreadCP (CS_t cs, uint8_t addr, uint8_t len, uint8_t * d)
{
  uint8_t i;

  delay_us (PREDELAY);
  spi_setcs (cs);
  delay_us (
DEVICE_PREPARE);

  while (!
CHECK_MISO_LINE) ;

  spi_SendByte (addr);
  spi_SendByte (len);

  while (!
CHECK_MISO_LINE);

  for (i = 0; i < len; i++)
  {
    *d = spi_TransferByte (0);
    d++;
  }
  delay_us (
DEVICE_PREPARE);

  while (!
CHECK_MISO_LINE);

  spi_resetcs (cs);
}


The Port A, Pin 2 is initialized as input (at startup):

 


  PTADD = 0x03;
  PTAD = 0;
  PTADS = 0x03;                 // drive strength high for PTA0 and PTA1 (debug LEDs)

 

 

I had a look at the assembly output, at the code line

  while (!CHECK_MISO_LINE);

The according assembly istruction is (I got it from the Debugger):

BRCLR 2,0x00, *+0

 

I think, this is right (PTAD is at adress 0x0000).

 

It seems, that the port read command does not work correctly or I am doing something else wrong? 

 

I use a digital Oszilloskope to watch the signals. To be sure, that the line levels are ok, I had additionally a look with the analog channel to the MISO - line. But the signal is good and meets the electrical requirements of the micro.

 

Is there another need in configuration of a port to do a successful read (than in my example above)?

 

 

 

 

 

0 Kudos
562 Views
bigmac
Specialist III

Hello,

 

Perhaps you should also post the code for the SendByte() and TransferByte() functions.  I notice that in two other places you have implemented a delay before testing the MISO state, but you do not do this immediately after sending the length byte.  If the delay is necessary in the other places, maybe it is also necessary here (depending on the timing specifications for the slave device).

 

Regards,

Mac

 

0 Kudos
562 Views
ttom
Contributor I

Hello,

I think it is quite easier to explain with screenshots. In the attachment, you find a spi_ok and a spi_not_ok screenshot. In both screens the Reset line is not connected.

In the spi_ok attachment you see the following:

First, chipselect goes low.

Then  I start communication by sending adress (0x00) and length (0x01). Then I wait until the MISO line goes high. Then I continue the communication by doing a additional transfer of the desired 1 Byte. When the MISO line goes high after the transmitted byte, the transfer is complete and the chipselect is going high.

In the second screen spi_not_ok.tif, you see, that the 3rd Byte transfer is without any break after the second transfer (length field). So I get the wrong value.

 

The difference in the two screens in software is a delay of 1 us after sending the length byte. The spi slave needs about 250 us after sending the length byte to it, until it is ready to continue (see spi_ok.tif). 

 

Here are my transfer functions:

 

void spi_SendByte (uint8_t data)
{
  while (!SPIS_SPTEF);

  SPID = data;
}

 

 

uint8_t spi_TransferByte (uint8_t data)
{
  uint8_t i;

 

  if (SPIS_SPRF)                // if there is a byte received
    i = SPID;                   // clear rx buffer

  while (SPIS_SPTEF == 0);
  i = SPIS;                     // clear SPTEF flag
  SPID = data;

  while (!SPIS_SPRF);

  return SPID;
}
 

Do you see a mistake in my functions?

 

spi_not_ok.jpg

spi_ok.jpg

Message Edited by t.dowe on 2009-11-10 09:07 AM
0 Kudos
563 Views
bigmac
Specialist III

Hello Thomas,

 

With your present code, when the SendByte() function exits, the SPI transfer will not have been completed, and this is the probable cause of your problem.  In addition, because the SPRF flag has not been cleared, an overrun condition is likely to be present when the first data byte is returned.

 

As I said in my previous post, SPI operation is a two-way process.  The master will always read a return byte at MISO simultaneously with sending a byte from MOSI. Therefore, I would tend to use a common function for master SPI communications that waits until each SPI transfer is complete, and then clears the SPRF flag.  There is no need to explicitly clear the SPTEF flag.

 

byte SPI_transfer( byte val)

{

   while (!SPIS_SPTEF);

   SPID = val;

   while (!SPIS_SPRF);  // Wait for transfer complete

   return SPID;         // Also clears flag

}

 

 

delay_us( PREDELAY);
spi_setcs(cs);
delay_us(
DEVICE_PREPARE);
while (!
CHECK_MISO_LINE) ;

(void)SPI_transfer( addr);
(void)SPI_transfer( len);
while (!
CHECK_MISO_LINE);

for (i = 0; i < len; i++) {
   *d =
SPI_transfer(0);
   d++;
}
delay_us(
DEVICE_PREPARE);
while (!
CHECK_MISO_LINE);
spi_resetcs(cs);

 

The use of the casts will prevent compiler warnings when return data is ignored.

 

Regards,

Mac

0 Kudos
562 Views
ttom
Contributor I

Hello bigmac,

many thanks to you for your help.

The problem is solved now.

I want to explain, what the error was:

Have a look at the two screenshots, please. The second screenshot is the zoomed range of the first (in the first screen you only see one vertical line, in the second, this part is zoomed).

 

The screenshots are taken with the sendByte() implementation from the beginning of my tests:

 

void spi_SendByte (uint8_t data)

{

while (!SPIS_SPTEF);

SPID = data;

}

 

 

The two spi_transferbyte() were replaced by the spi_SendByte() calls. In the screenshot, the line D0 is set, when I normally sample the MISO line.

You will see, that the two spi_SendByte() calls where finished 2,4 us _before_ the MISO line goes low, so I sampled already the MISO line, before it went low. This was my problem.

I now use the spi_TransferByte() function in every situation, so the transfer is complete when return from the function. So I can disable SPI and sample the MISO line and activate SPI again afterwards to go on.

 

Again, many thanks to you (I hope I can help you anytime, too)

 

Thomas

 

short_SendByte.jpg

short_SendByte_zoom.jpg

Message Edited by t.dowe on 2009-11-12 11:21 AM
0 Kudos