Methods of setting a MISO pin to be high impedance or ignored via SPI block

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
jatoc_3265626
Level 1
Level 1
First like given

I'll start off with what I'm trying to do: I have a MAX11200 ADC that I'm interfacing with via a SPI Master in full duplex mode (using a CY8C3866PVI-021) and am attempting to get readings from. The ADC has a !RDY/DOUT line which is configured as high impedance when it is not selected via !CS. When the device is selected via !CS, the line drives high if no data is ready, and low if data is ready. Data is clocked out on the !RDY/DOUT line on each falling clock edge. This can be seen in the following image, from page 13 of the manual: max11200_read.PNG

My issue occurs when I perform a register read from the ADC. When I select the device via !CS, the !RDY/DOUT line goes high to indicate that data is not ready to be sent from the device. However, because my SPI master sees a logic high signal on MISO while !CS is low and clock pulses are being sent out, it sees this as a valid transaction and stores the byte. This means that every time I send an address/command and read data back, I receive two bytes of data- 0xFF (or 0x00 if data is already ready), and then my actual data. See below for an example of this where my SPI RX buffer would contain 0xFF 0x02 instead of the desired 0x02:

max11200_spi2.png

What I'd like to do is either disable the MISO line on my SPI block when I'm not actually trying to read data, or find a way to set it to high impedance so that my SPI block doesn't see anything on the line. I could throw away the first byte of data that I read when parsing results, but I'd prefer to find a more robust way of handling the issue. The only buffer I can find with an enable signal is bufoe, which is meant to be used to drive output pins. I suppose I could pass the MISO pin to a bufoe, feed it out on another pin, then feed it back in on another pin which actually goes to my SPI block, but this seems roundabout and wasteful. If I do something like AND the MISO line with a control signal, I'm still stuck at either logic 1/0, which the SPI block will see as valid data.

Can anybody suggest a more sane/simple solution to ignoring the ADC's output line until I'm actually trying to read data from it? Thanks!

0 Likes
1 Solution

Hi,

Can you try something like this :

1. Set data bits to 8 is master component

2. Use firmware controlled slave select

3. Disable the input buffer of the MISO pin when the command byte is send using PRT[0..11]_INP_DIS (Input buffer disable override) register.

Code similar to :

for(;;)

    { 

      sendcommand(cmd);

      resullt = receivedata();  

    }

void sendcommand(uint8 value)

{

    uint8 temp;

    SPIM_ClearTxBuffer();

    temp = SPIM_ReadTxStatus();

    SlaveSelect_Write(0);  /*CS pin pulled low */

   CY_SET_REG8(MISO__INP_DIS,0x08); /* Disable the input buffer of the MISO pin */

   

     if(temp & (SPIM_STS_SPI_DONE | SPIM_STS_SPI_IDLE))

        {

            SPIM_WriteTxData(value); /*Write the command to the slave*/

        }

         while(0u ==(SPIM_ReadTxStatus()& SPIM_STS_SPI_DONE ))

         {}

   ans =  SPIM_ReadRxData(); /*You should not be receiving any data*/

   CY_SET_REG8(MISO__INP_DIS,0x00);  /*Enable the input buffer again before receiving the 2nd byte of data*/

}

uint8 receivedata()

{

    uint8 dummy = 0xFF;

  

    SPIM_WriteTxData(dummy); /*Send the next byte of data. Note: The CS is still low*/

  

    while(SPIM_GetRxBufferSize()!=1u)

    {}

    SPIM_ClearTxBuffer(); /*Clear Dummy data in buffer*/

    SlaveSelect_Write(1);  /*Make the CS high again*/

 

return(SPIM_ReadRxData());

}

(or)

The simpler solution is to simply clear the RxBuffer when the first byte of data is received. The modified code for that would be:

(Note: 8 bits packet)

for(;;)

    { 

      sendcommand(cmd);

      result = receivedata();  

    }

void sendcommand(uint8 value)

{

    uint8 temp;

    SPIM_ClearTxBuffer();

    temp = SPIM_ReadTxStatus();

    SlaveSelect_Write(0);  /*CS pin pulled low */

   

     if(temp & (SPIM_STS_SPI_DONE | SPIM_STS_SPI_IDLE))

        {

            SPIM_WriteTxData(value); /*Write the command to the slave*/

        }

         while(0u ==(SPIM_ReadTxStatus()& SPIM_STS_SPI_DONE ))

         {}

  SPIM_ClearRxBuffer();   /* Clears the junk data received*/

 

}

uint8 receivedata()

{

    uint8 dummy = 0xFF;

  

    SPIM_WriteTxData(dummy); /*Send the next byte of data. Note: The CS is still low*/

  

    while(SPIM_GetRxBufferSize()!=1u)

    {}

    SPIM_ClearTxBuffer(); /*Clear Dummy data in buffer*/

    SlaveSelect_Write(1);  /*Make the CS high again*/

 

return(SPIM_ReadRxData()); /*This will have only the correct data*/

}

But for this you need be careful of the inter-byte timing requirements of the slave.

If you want only 16 bits packet, the most simple solution would just be :

data = SPIM_ReadRxData() & 0x00FF

I think all the other methods would be just using additional system resources, execution time, memory and power consumption for this application.

Please let us know in case you have any stringent requirements also.

Regards,

Bragadeesh

Regards,
Bragadeesh

View solution in original post

8 Replies
BragadeeshV
Moderator
Moderator
Moderator
First question asked 1000 replies posted 750 replies posted

Hi,

I referred to the ADC's datasheet. When the conversion is in progress, you will get high in the RDY/ DOUT pin. So this means the conversion is in progress and you have to send one more master read request. The data is valid only when the RDY/DOUT pin is low. The best way to handle this is in your firmware. Discard the entire packet when it has first byte as 0xFF. Consider only the packets that has 0x00 Data in it. I think that is how the ADC's SPI is designed to work.

Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes

Hey Bragadeesh, thanks for your response. I'm aware of the ADC's handling of the MISO line when busy/ready, but I'm more interested in finding a way around this and either disabling the SPI's RX capabilities, or finding a way to set the MISO line high z to avoid the SPI master seeing a high/low signal from this pin. I'd prefer to be able to enable/disable these features as needed, so that I can simply enable them after requesting a read, grab the data, and then disable until I'm ready to grab data again. As you can see in my last screenshot, I was just reading a register value, not performing a conversion, and still ended up with junk data.

I supposed I could have two SPI masters in my device, and dedicate one to TX and one to RX, and then simple enable/disable the RX SPI master as needed.

0 Likes

You could do that, or you could simply put some digital logic on the lines (and/or gate) and force the signal to be either 0 or 1 via a control register.  Or you could mux to a different IO set to high impedance digital.

Note: there may be timing implications to these changes that may not make the possible, depending on your system.

0 Likes

Hi,

Can you try something like this :

1. Set data bits to 8 is master component

2. Use firmware controlled slave select

3. Disable the input buffer of the MISO pin when the command byte is send using PRT[0..11]_INP_DIS (Input buffer disable override) register.

Code similar to :

for(;;)

    { 

      sendcommand(cmd);

      resullt = receivedata();  

    }

void sendcommand(uint8 value)

{

    uint8 temp;

    SPIM_ClearTxBuffer();

    temp = SPIM_ReadTxStatus();

    SlaveSelect_Write(0);  /*CS pin pulled low */

   CY_SET_REG8(MISO__INP_DIS,0x08); /* Disable the input buffer of the MISO pin */

   

     if(temp & (SPIM_STS_SPI_DONE | SPIM_STS_SPI_IDLE))

        {

            SPIM_WriteTxData(value); /*Write the command to the slave*/

        }

         while(0u ==(SPIM_ReadTxStatus()& SPIM_STS_SPI_DONE ))

         {}

   ans =  SPIM_ReadRxData(); /*You should not be receiving any data*/

   CY_SET_REG8(MISO__INP_DIS,0x00);  /*Enable the input buffer again before receiving the 2nd byte of data*/

}

uint8 receivedata()

{

    uint8 dummy = 0xFF;

  

    SPIM_WriteTxData(dummy); /*Send the next byte of data. Note: The CS is still low*/

  

    while(SPIM_GetRxBufferSize()!=1u)

    {}

    SPIM_ClearTxBuffer(); /*Clear Dummy data in buffer*/

    SlaveSelect_Write(1);  /*Make the CS high again*/

 

return(SPIM_ReadRxData());

}

(or)

The simpler solution is to simply clear the RxBuffer when the first byte of data is received. The modified code for that would be:

(Note: 8 bits packet)

for(;;)

    { 

      sendcommand(cmd);

      result = receivedata();  

    }

void sendcommand(uint8 value)

{

    uint8 temp;

    SPIM_ClearTxBuffer();

    temp = SPIM_ReadTxStatus();

    SlaveSelect_Write(0);  /*CS pin pulled low */

   

     if(temp & (SPIM_STS_SPI_DONE | SPIM_STS_SPI_IDLE))

        {

            SPIM_WriteTxData(value); /*Write the command to the slave*/

        }

         while(0u ==(SPIM_ReadTxStatus()& SPIM_STS_SPI_DONE ))

         {}

  SPIM_ClearRxBuffer();   /* Clears the junk data received*/

 

}

uint8 receivedata()

{

    uint8 dummy = 0xFF;

  

    SPIM_WriteTxData(dummy); /*Send the next byte of data. Note: The CS is still low*/

  

    while(SPIM_GetRxBufferSize()!=1u)

    {}

    SPIM_ClearTxBuffer(); /*Clear Dummy data in buffer*/

    SlaveSelect_Write(1);  /*Make the CS high again*/

 

return(SPIM_ReadRxData()); /*This will have only the correct data*/

}

But for this you need be careful of the inter-byte timing requirements of the slave.

If you want only 16 bits packet, the most simple solution would just be :

data = SPIM_ReadRxData() & 0x00FF

I think all the other methods would be just using additional system resources, execution time, memory and power consumption for this application.

Please let us know in case you have any stringent requirements also.

Regards,

Bragadeesh

Regards,
Bragadeesh

That PRT*_INP_DIS example looks like it might be what I need. Can you point me towards more information on the port register settings? I've looked through the PSoC 3 TRM but the only reference I'm seeing is a short description on page 165 that says "The Port Input buffer disable allows the user to over-ride the input buffer default drive mode settings". I'm not having any lucking finding other references to the macro on Google or in the rest of the PSoC documentation. Thanks!

0 Likes

You can refer to the PSoC 3 arch TRM IO section for more details on Port registers.  This register will basically turn off the input buffer in the GPIO. 

https://www.cypress.com/file/124706/download

Is that what you were asking?

Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes

I was looking for a description of register values and their effect (e.g. 0x08 to disable the input buffer and 0x00 to re-enable it). The only info I found in the TRM was that short description on page 165

0 Likes

Hi jtobin_3265626​,

Each bit in the register corresponds to each pin in the port.

For example, in the code we shared, we were using Port 5 Pin 4 [P5.3] for the MISO line.

For Port 5 -> Register 0x5158

For pin 4 -> 0x00001000 (Set 4th bit) -> 0x08

For PSoC 3, the corresponding macro for this register is <Pin_name>_INP_DIS . This is defined in the <Pin_name>.h file

Please let us know in case of further clarifications.

Regards,

Bragadeesh

Regards,
Bragadeesh
0 Likes