Can't get spi to read data

General discussion relating to the library modules supplied with the compiler

Moderators: David Barker, Jerry Messina

Post Reply
garryp4
Posts: 78
Joined: Mon May 21, 2007 7:18 am
Location: Loveland, CO USA

Can't get spi to read data

Post by garryp4 » Sun Apr 26, 2020 5:23 pm

I am having a problem getting SPI data from a radio. A paired circuit with the same circuit uses the same radio and works so I know the logic is good. the other circuit has an 18F47J13 and uses SPI2 and Jerry M's PPS module (great code!). This circuit uses an 18F14K22. I use the exact same settings for the SPI as the SPI2. I also see good updated radio register data returning on the scope, but just get 0's when display the value on hyperterm. The radio has a config chip select and a data chip select

Code: Select all

'****************************************************************************
Public Sub OPEN_SPI1()
  SPI1.SetClock(spiIdleLow,spiRisingEdge)           ' spiRisingEdge  spiFallingEdge
  SPI1.Open(SPI_MODE_1,spiOscDiv64,spiSampleEnd)    ' spiSampleEnd, spiSampleMiddle 
  DelayUS(5)
End Sub
'****************************************************************************
Public Sub RADIO_RESET()
  High(r_reset)
  DelayUS(110)
  Input(r_reset)
End Sub  
'****************************************************************************
Private Sub RADIO_CONFIG_SPI()
  OPEN_SPI1
  High(r_csdata)
  Low(r_cscon)
  DelayUS(100)
  
'  TRISB.4 = 1
'  b1 = SSPSTAT
'  b2 = SSPCON1
'  b3 = TRISB
'  
'  USART.Write("SSPSTAT = ",BinToStr(b1,8),"  SSPCON1 = ",BinToStr(b2,8),"  TRISB = ",BinToStr(b3,8),10,13)
'  DelayMS(2)

(gives "SSPSTAT = 10000000  SSPCON1 = 00100010  TRISB = 10110000")
  
End Sub
'****************************************************************************
Private Sub RADIO_DATA_SPI()
  OPEN_SPI1
  High(r_cscon)
  Low(r_csdata)
  DelayUS(100)
    
End Sub
'****************************************************************************
Private Sub DISABLE_RADIO_SPI()
  High(r_cscon)
  High(r_csdata)
'  DelayUS(2)
  SPI1.Close
End Sub  
'****************************************************************************
Public Sub RADIO_INIT()

  RADIO_RESET
  OPEN_SPI1

End Sub
'****************************************************************************
'****************************************************************************
Public Sub READ_REG()

  RADIO_INIT
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)           ' $40
  b1 = SPI1.ReadByte
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)

  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_w)                        ' Register address write
  SPI1.Transfer($68)                                ' Register data write
  DISABLE_RADIO_SPI
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)
  b1 = SPI1.ReadByte
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)  

  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_w)                        ' Register address write
  SPI1.Transfer($28)                                ' Register data write
  DISABLE_RADIO_SPI
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)
  b1 = SPI1.ReadByte
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)  

  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_w)                        ' Register address write
  SPI1.Transfer($88)                                ' Register data write
  DISABLE_RADIO_SPI
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)
  b1 = SPI1.ReadByte
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)  
  
End Sub
'****************************************************************************
Any help is greatly appreciated.
Thanks

Jerry Messina
Swordfish Developer
Posts: 1140
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Can't get spi to read data

Post by Jerry Messina » Mon Apr 27, 2020 10:04 am

Here are a few things to look out for...

- on the 14K22, SPI pins are also analog so be sure to add a SetAllDigital() call in your main routine

- you can change OPEN_SPI1 to remove the SetClock() call since this is done by Open()

Code: Select all

Public Sub OPEN_SPI1()
// remove SetClock since Open does this
//  SPI1.SetClock(spiIdleLow,spiRisingEdge)           ' spiRisingEdge  spiFallingEdge
  SPI1.Open(SPI_MODE_1,spiOscDiv64,spiSampleEnd)    ' spiSampleEnd, spiSampleMiddle 
  DelayUS(5)
End Sub
- In READ_REG I'd recommend just using Transfer() instead of ReadByte() since Transfer() will take care of dealing with the SSPBUF and flags.
Calling Transfer() with no argument will send a dummy byte (set via '#option SPI_DEFAULT_TRANSFER') and read the result.
Change

Code: Select all

  SPI1.Transfer(gcon_addr_r)           ' $40
  b1 = SPI1.ReadByte
to

Code: Select all

  SPI1.Transfer(gcon_addr_r)           ' $40
  b1 = SPI1.Transfer()
And finally, I never tested this on a 14K22, so if it still doesn't work let me know and I'll get some samples to test it with.

garryp4
Posts: 78
Joined: Mon May 21, 2007 7:18 am
Location: Loveland, CO USA

Re: Can't get spi to read data

Post by garryp4 » Mon May 04, 2020 7:27 pm

Jerry:

Thanks for the reply and hope all is well in these crazy times.

I have changed the SPI1.ReadByte to SPI1.Transfer(). I have also put a statement to show that TRISB.4, the SDI pin, is an input. This should satisfy the SetAllDigital() call requirement. In the parent routine only AN2 is enabled with:

ADCON0 = $09 ' AN2
ADCON1 = $00 ' Vref = Vcc

Because I can see the data sent from the radio registers changing on the scope and matching what the it should be, I know the PIC SDO and CLK are good. The SDI data is getting to B.4.


Here is the current code:

Code: Select all

'****************************************************************************
Public Sub OPEN_SPI1()
  SPI1.Open(SPI_MODE_1,spiOscDiv64,spiSampleEnd)    ' spiSampleEnd, spiSampleMiddle 
  DelayUS(5)
End Sub
'****************************************************************************
Public Sub RADIO_RESET()
  High(r_reset)
  DelayUS(110)
  Input(r_reset)
End Sub  
'****************************************************************************
Private Sub RADIO_CONFIG_SPI()
  OPEN_SPI1
  High(r_csdata)
  Low(r_cscon)
  DelayUS(100)
  
End Sub
'****************************************************************************
Private Sub RADIO_DATA_SPI()
  OPEN_SPI1
  High(r_cscon)
  Low(r_csdata)
  DelayUS(100)
    
End Sub
'****************************************************************************
Private Sub DISABLE_RADIO_SPI()
  High(r_cscon)
  High(r_csdata)
  SPI1.Close
End Sub  
'****************************************************************************
Public Sub RADIO_INIT()

  RADIO_RESET
  OPEN_SPI1

End Sub
'****************************************************************************
Public Sub READ_REG()

  RADIO_INIT
  
  RADIO_CONFIG_SPI
  
  b3 = TRISB
  USART.Write("TRISB = ",BinToStr(b3,8),".  B.4 is SDI",10,13)
  DelayMS(2)
    
  SPI1.Transfer(gcon_addr_r)           ' $40
'  b1 = SPI1.ReadByte
  b1 = SPI1.Transfer()
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)

  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_w)                        ' Register address write
  SPI1.Transfer($68)                                ' Register data write
  DISABLE_RADIO_SPI
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)
  b1 = SPI1.Transfer()
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)  

  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_w)                        ' Register address write
  SPI1.Transfer($28)                                ' Register data write
  DISABLE_RADIO_SPI
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)
  b1 = SPI1.Transfer()
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)  

  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_w)                        ' Register address write
  SPI1.Transfer($88)                                ' Register data write
  DISABLE_RADIO_SPI
  
  RADIO_CONFIG_SPI  
  SPI1.Transfer(gcon_addr_r)
  b1 = SPI1.Transfer()
  DISABLE_RADIO_SPI
  USART.Write("GCON = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)

  b1 = SSPBUF
  USART.Write("SSPBUF = ",BinToStr(b1,8),"  ",HexToStr(b1),10,13)
  DelayMS(2)  
  
End Sub
This is the hyperterm display:

TRISB = 10110000. B.4 is SDI
GCON = 00000000 0
GCON = 00000000 0
GCON = 00000000 0
GCON = 00000000 0
SSPBUF = 00000000 0

Still not getting any SDI data.


Thanks a lot for your time.

Garry

Jerry Messina
Swordfish Developer
Posts: 1140
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Can't get spi to read data

Post by Jerry Messina » Tue May 05, 2020 10:39 am

I assume you're using the SPI.bas library module from the latest version (2.2.3.2) and have copied it and renamed the module to SPI1.

I have also put a statement to show that TRISB.4, the SDI pin, is an input. This should satisfy the SetAllDigital() call requirement. In the parent routine only AN2 is enabled with:

ADCON0 = $09 ' AN2
ADCON1 = $00 ' Vref = Vcc
Just so we're clear, ADCON0 doesn't change the analog/digital function of the ports... that's done using ANSEL/ANSELH on the 14K22.
A PORT pin that's in analog mode will always read '0' no matter what the TRIS setting for that bit is.

Humor me. Try adding this to your main program:

Code: Select all

include "setdigitalio.bas"

SetAllDigital()
SetAnalogPort(AN2, ANA)   // set AN2 (RA2) to analog mode
That should set all IO to digital mode and then AN2 back to analog.
It will also setup registers like slew-rate control for you.

If that doesn't work then I'll have to get some samples and figure out what's up.

garryp4
Posts: 78
Joined: Mon May 21, 2007 7:18 am
Location: Loveland, CO USA

Re: Can't get spi to read data

Post by garryp4 » Tue May 05, 2020 1:37 pm

Jerry:

That definitely did make a difference! I now get:

GCON = 01000111 47
GCON = 01000111 47
GCON = 01000111 47
GCON = 01000111 47
SSPBUF = 01000111 47

I should be writing then reading a hex 68, 28, then 88. I will put the scope on it tonight and see what is happening.

Also, I did not look far into the A/D section of the data sheet as have been using the ADCON0 to disable successfully for years. Thanks for that.

And, I am running version 2.2.2.5. Are you able to send me a new code to get the latest or does that have to come from David?

Thanks

Jerry Messina
Swordfish Developer
Posts: 1140
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Can't get spi to read data

Post by Jerry Messina » Tue May 05, 2020 2:34 pm

Great.

The ADCON/ANSEL/XXXXX varies from device to device. That's why it's best to use SetAllDigital
Are you able to send me a new code to get the latest or does that have to come from David?
There's a "check for updates" button in the IDE Help | About window.

If you need your registration number you'll have to get that from David.

Jerry Messina
Swordfish Developer
Posts: 1140
Joined: Fri Jan 30, 2009 6:27 pm
Location: US

Re: Can't get spi to read data

Post by Jerry Messina » Wed May 06, 2020 9:50 am

If you're using an older version of spi.bas you should check the transfer() routines.

Some versions of the function returned the value in the SSPBUF register.
They were declared something like this...

Code: Select all

public inline function transfer(b as WREG) as SSPBUF
Note the 'as SSPBUF' as the return value. The problem with that is if you don't assign the function to a value ie 'b = spi.transfer($55)' then it doesn't read the SSPBUF register and you get overrun errors.

The simplest way to fix that is to always assign the return value to something, even if you're doing a write and don't need the value

Code: Select all

  b1 = SPI1.Transfer(gcon_addr_r)           'write  $40, read dummy return
  b1 = SPI1.Transfer()
You can always assign the return value to WREG if not needed

Code: Select all

  WREG = SPI1.Transfer(gcon_addr_r)           'write  $40, read dummy return
This was changed in later versions to always read the SSPBUF and return a byte value instead of the SSPBUF directly.

Post Reply