SPI - The basics


Closed Thread
Results 1 to 19 of 19
  1. #1
    Join Date
    Aug 2010
    Posts
    11

    Default SPI - The basics

    Greetings to all and thanks for a very thorough user forum. I am very new to pics, picbasic and microcontrollers. I won't pretend to understand 1/2 of what I have read but some of it must have sunk in as I am 1/2 way through a project. I am building a PID controller and can successfully read in 2 AI channels, display their values on an LCD and create the output value for the PID.
    Now for control I realize I can use PWM or a DAC chip. I have (regretfully??) chosen the later of the two and am now stuck. I cant really find sufficient documentation and code examples. I am using a 16F877A and need to get the DAC conversion through a MCP4812.
    So before a I beg for any direct answers - I would love some pointers as to where to get the relevant code/ pinout/ examples to learn from.

    I do have one other anomaly that has no caused me too much grief yet, but I fear it is coming as I might need it to get through this DAC section. When I try to use the ASM ... ENDASM within my code - it will not compile!!!!

    Thanks to any whom might be able to give some guidance

  2. #2
    Join Date
    Aug 2010
    Posts
    11

    Default

    Okay, maybe I can focus this on where exactly I am getting lost. The MCP4812 needs the data brought in a specific format. That is bits 15:12 are formatting information for the data and bits 11:0 are the 12 bit digital (or 10 bit ...) information that is being transfered.
    As I understand it, the SEROUT command will send 8 bit packets and I am not sure how to get the cofiguration data combined with the actual data??????? and, combine this as 1 - 16 bit packet???????

  3. #3
    Join Date
    Jul 2003
    Posts
    2,405

    Default

    For SPI use SHIFTOUT. Something like this should work;
    Code:
    A VAR WORD
    B VAR WORD
     
    CS VAR PORTB.0  ' chip select
    SCK VAR PORTB.1 ' clock
    SDI VAR PORTB.2 ' data
    LDAC VAR PORTB.3 ' load DAC
     
    HIGH CS   
    LOW SCK
    HIGH LDAC
     
    A = %0001111111111100 ' channel A, 2x, active, max output
    B = %1001111111111100 ' channel B, 2x, active, max output
     
    Main:
      LOW CS ' enable writes
      SHIFTOUT SDI,SCK,0,[A\16]
      HIGH CS 
      PAUSE 5
     
      LOW CS
      SHIFTOUT SDI,SCK,0,[B\16]
      HIGH CS
     
      LOW LDAC ' load both DAC outputs
      PAUSE 5
      HIGH LDAC
     
      PAUSE 5000
      GOTO Main
      END
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  4. #4
    Join Date
    Aug 2010
    Posts
    11

    Default

    Thanks Bruce. I will give this a go in the next day or two and let you know if I had some success!

  5. #5
    Join Date
    Aug 2010
    Posts
    11

    Default

    Thanks Bruce - I now have some level of success !??!

    I was stuck for a while with only getting a Vref output from the 4812 - no matter what 10 bit information I loaded it was the same. I just had to change the mode on the SHIFTOUT command to a 1 or MSB first and it fell in line.

    For this example, you are predefining the 10 bits for conversion in A and B. How would I load up 'A' with the same first 4 bits but then the next 12 (10) bits varying, based on my PID loop output?

    Thanks again ...

  6. #6
    Join Date
    Jul 2003
    Posts
    2,405

    Default

    There are several ways to do it, but I would probably go for something like this;

    The upper 4-bits for DAC channel A, with 2x gain, with A active, will remain constant. So create a constant like ASel CON 4096. This would be the following in 16-bit binary: %0001000000000000.

    The lower 12-bits, with the 2 least significant bits ignored, + ASel would be your value to send to the DAC to adjust the channel A output.

    Just use a word variable. Load your word variable with any value from 0 to 1023, then shift this left x 2 so the 2 LSBs are 0, then add the ASel constant for the value to shiftout.

    Say your word var is ChanA, and it's = 501. ChanA = (ChanA << 2) + ASel.

    501d = %0000000111110101. Shifted left x 2 it's %0000011111010100. When you add the ASel constant, it ends up being %0001011111010100.
    Last edited by Bruce; - 1st September 2010 at 18:00.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  7. #7
    Join Date
    Aug 2010
    Posts
    11

    Default

    Thanks Bruce-
    All the seperate components came together and everything is working great. Your help above was great!!!

  8. #8
    Join Date
    Mar 2009
    Posts
    653

    Default

    Just had my first attempt dabbling with SPI this evening - fail!

    I'm trying to control a AD5206 (six digital pots in the one IC package - http://www.analog.com/static/importe...D5204_5206.pdf)

    To test that the wiper on the nominated pot moves I've put 5V on the High side of the internal pot6 pin, & 0V on the low side of pot6 pin. I'm trying to set pot 6's wiper to the midway point (it's a 256 position pot, so I'm sending a value of 127) - but the wiper is not going to 2.5V ....it just sits at 5V.

    I've try to join all the 'SPI' elements together (as taken from several threads!). The only bit I'm not totally sure about (& it's pretty fundamental!) is how to send just 11 bits to the AD5206 (the format is three bits to select which of the 6 internal digital pots you want the wiper to move, then send the data to actually control the wiper (3 'variable resistor select' bits + 8 databits so 11 bits in total).

    Any ideas....

    Code:
    @ __CONFIG _FCMEN_OFF & _INTRC_OSC_NOCLKOUT & _WDT_OFF & _MCLRE_OFF & _CP_OFF & _IESO_OFF & _BOR_OFF & _PWRTE_OFF
    
    '16F690 Pin Connections....
    ' PIN# NAME     USE & CONNECTION
    '  1   Vdd      +5VDC power supply   
    '  9   RC7      SDO (serial Data out)
    '  10  RB7      HSEROUT pIN
    '  11  RB6      SPI Clock out
    '  13  RB4      SDI (serial Data In)
    '  16  RCO      CS Chip Select (to pin 3 on AD5206)   output           
    '  20  Vss      Ground
    '*************************************************************************************
    DEFINE  OSC 8          ' set Oscillator at 8Mhz.
    DEFINE  NO_CLRWDT 1   ' PBP doesn't clear WDT automatically
    DEFINE HSER_SPBRG 25   'HSEROUT Stuff.
    DEFINE HSER_TXSTA 24h  'HSEROUT Stuff.
    DEFINE HSER_CLROERR 1  'HSEROUT Stuff.
    
    txsta = %10100100       'setup the tx register
    RCSTA.7 = 1             'Enable RB7 for TX USART
    INTCON.0 = 0            'clears the RABIF Flag (to 0), COULD be 1 on reset (unique to F690)
    ANSEL      = 0          'disable AtoD.
    ANSELH     = 0          'disable AtoD.
    
    OPTION_REG = %00000111  'enable weak pullups.
    WPUB     = %00010000   'enable weak pullups on the SDI RB4 (input from digital pot)
    
    '------SPI setup
    SSPEN VAR SSPCON.5   ' SSP Enable bit
    CKP   VAR SSPCON.4   ' Clock Polarity Select
    SMP   VAR SSPSTAT.7  ' Data input sample phase
    CKE   VAR SSPSTAT.6  ' Clock Edge Select bit
    SSPIF VAR PIR1.3     ' SPI interrupt flag
    
    SSPCON.5=1 'enable SSP 
    SSPCON.4=1 'Clock idles high bit name CKP
    SSPCON.3=0 ' bit 3 to 0 indicate clock speed. bit 0 set means clock = OSC/16 = 1.25 MHz
    SSPCON.2=0
    SSPCON.1=0
    SSPCON.0=1
    SSPSTAT.7=1 ' SPI Master mode 
    SSPSTAT.6=0 ' data transmitted on rising edge of SCK
    
    SCK     var PortB.6  'clock pin
    CS      var PORTC.0     'chip select
    SDI     var PortB.4    'data in
    SDO     var PortC.7      'data out
    AD5206  var word    'word used to send 3 control bits  + 8 data bits
    
    TrisC.0 = 0    'Chip Select (CS) 
    TrisB.6 = 0    'SPI Clock Out
    TrisB.7 = 0    'Debug Out
    
    ' AD5206 Variable resistor select 'Control' bits as as follows....
    '000 Select Variable resistor1
    '001 Select Variable resistor2
    '010 Select Variable resistor3
    '011 Select Variable resistor4
    '100 Select Variable resistor5
    '101 Select Variable resistor6
    
    AD5206 = %00001010111111   'upper byte = select Variable Resistor 6 (ref the table above) , lower byte = set VR6 wiper value to midway
    
    high CS 
    
    ' CODE TO CONTROL SPI POTENTIOMETER AD5206
    
    Main:
        gosub WriteSPI
        pause 1000
        goto Main
    
    WriteSPI:
        LOW CS                            
        Shiftout SDO, SCk, 1, [AD5206 \11] ' not sure about this bit!!
        high cs
        RETURN                       
    
    end

  9. #9
    Join Date
    Jul 2003
    Posts
    2,405

    Default

    SHIFTOUT is a software SPI communications routine. If you use it, don't enable the PICs hardware SPI. If you do, then the hardware SPI takes control of these pins, and SHIFTOUT won't work.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  10. #10
    Join Date
    Mar 2009
    Posts
    653

    Default

    Quote Originally Posted by Bruce View Post
    SHIFTOUT is a software SPI communications routine. If you use it, don't enable the PICs hardware SPI. If you do, then the hardware SPI takes control of these pins, and SHIFTOUT won't work.
    Thanks for the heads up.

    Ok....struggling here! (being completely new to SPI!)

    I'd assumed the reason that SPI hw being available on the PIC was to assist in ease of comms with SPI devices....but now youre saying that h/w should not be used when shiftout is used? So (n00b hat on again!).... Why use shiftout wrt SPI then?

    How does shiftout 'marry' up with the SPI master clock (when using h/w presumably there's tight correlation between the SPI buffers being read out at the right time etc)

    If not using shiftout (as in my above code), how would getting an 11 bit control stream out the SDO pin (the least 3 significant bits of an upper byte + a complete lower byte) be approached in hw?

  11. #11
    Join Date
    Jul 2003
    Posts
    2,405

    Default

    It's pretty much the same for any built-in hardware peripheral.

    Once you enable a peripheral, it takes control of the pins. With PBP SHIFTIN & SHIFTOUT you can use most any pin. With the hardware peripheral you're stuck using whatever pins are used for the hardware peripheral.

    Melabs has a few examples for using hardware SPI here http://melabs.com/resources/samples-pbp-general.htm but I would stick with SHIFTOUT & SHIFTIN unless you just want to learn how the hardware works.
    Regards,

    -Bruce
    tech at rentron.com
    http://www.rentron.com

  12. #12
    Join Date
    Mar 2009
    Posts
    653

    Default

    Thank (as ever) Bruce....I managed to get the hardware working (while testing I was sending a data byte of zeros to the digipot ....which ahem, being zeros don't show up on the PIC's SDO pin...doh, lol. Also, I was clocking data out of the pic on the wrong edge of the clock, which meant the least significant of the data byte was going awol from the digipot's perspective)

    So, while I'm what's the pros and cons of s/w SPI vs hw SPI?

    From the top of my head (and some assumptions)...

    sw SPI ...
    pros - flexibility of pin assignments, bit centric.
    cons - slower? can't use interrupts in the same program (this is an assumption on my part as I know serout/debug get corrupted when interrupts are used in the same program)

    hw SPI ...

    pros - can use interrupts in the same program?, faster?
    cons - tied to using the allocated SPI pins. byte centric?
    Last edited by HankMcSpank; - 9th September 2010 at 13:11.

  13. #13
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231

    Default Re: SPI - The basics

    Something seems weird about this interface.

    The datasheets that I have looked at seem to say that the hardware SPI is only capable of communicating in 8 bit bytes. So even if you were able to write a program that handled the HWSPI, you would be locked into devices that used 8 bits.
    I seems that so many of the desired devices that use SPI require more than that.

    The above D/A is one example. An SCA61T inclinometer that I'm playing with is using 11 bit data.

    I'm going to read the inclinometer and output to the D/A so it looks like a software SPI is the ONLY solution. I intent to try a variation on Bruce's multi-bit write above to do similar with the read so we'll see how that goes.

    Sure seems odd that is the case if I understand it correctly.

    Bo

  14. #14
    Join Date
    Sep 2004
    Location
    montreal, canada
    Posts
    6,898

    Default Re: SPI - The basics

    It's just a matter of playing with it. If you need to send 11 Bits with the MSSP, then you just need to send 2 byte (2x8 bits) BUT mask/set the extra bits with 1 or 0.

    Have a look at MCP3204/3208 section 6
    http://ww1.microchip.com/downloads/e...doc/21298c.pdf

    If you really need speed, you want to use the MSSP port, case not, SHIFTIN/SHIFTOUT handle it.
    Steve

    It's not a bug, it's a random feature.
    There's no problem, only learning opportunities.

  15. #15
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231

    Default Re: SPI - The basics

    Thanks Steve!

    I appreciate that you took the time to give me the reference. Very helpful.

    Bo

  16. #16
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231

    Default Re: SPI - The basics

    Interesting, that explanation doesn't show up in either the MCP4821 or MCP4921 datasheets.

    Thanks again for the heads up

    Bo

  17. #17
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231

    Default Re: SPI - The basics

    After studying this for a few nights, the fog is beginning to clear a bit, but not completely.
    On the above mentioned inclinometer (sca61t, pages 11 &12), you send a command and then concurrently it sends back a reply with the data. I think I can see how to send the command, and extend the transmission to 19 clocks so that it can fit in the response by leaving CS low with the [var\19] in SEROUT. What I don't see how to grab those reply bits using SEROUT and SERIN. Each one would execute in order and not catch the response as both share the clock.
    Code:
    I VAR WORD
    D VAR WORD 
    CS_I      VAR           PORTC.2  ' chip select Inclinomteter
    CS_D      VAR           PORTC.3  ' chip select D/A
    SCK       VAR           PORTC.5 ' clock
    SDI       VAR           PORTC.4 ' data OUT
    SDO       VAR           PORTC.7 ' data IN
    IncIn     var           word 
    HIGH CS_I   
    HIGH CS_D
    LOW SCK
    I = %0001000000000000     'send RDAX & fill to get 11 bits of data 
    D = %0001111111111111        '2x, active, max output for test
    
    '*** Inclinometer Commands ***********
    'MEAS         00000000           'Measure (Exit self test)
    'RWTR         00001000           'R/W Temp     
    'RDSR         00001010           'Read Status register
    'RLOAD        00001011           'relaod NV to o/p
    'STX          00001110           'activate self test
    'RDAX         00010000           'read acceleration
    
    Main:
         GOSUB IncRdg
         GOSUB DACout
    goto main
    '**** Subs *********************************
    ;---- Sub to read the inclinometer ------------------
    IncRdg:
      LOW CS_i                       ' enable writes to Inclinometer
      SHIFTOUT SDI,SCK,0,[I\19]      'sends command to READ
    ' SHIFTIN SDO,SDK,0,[IncIn\11]  ' I don't see this working
      HIGH CS_I 
      PAUSE 5
      RETURN
    
    ''---- Sub to output to the D/A converter ----- 
    'DACout:
    '  LOW CS_D                       ' enable writes to D/A converter
    '  SHIFTOUT SDI,SCK,0,[D\16]
    '  HIGH CS_D 
    '  PAUSE 5
    '  return
    Will test further, but I suspect that I might have to resort to the hardware SPI.

    Any thoughts?
    Bo

  18. #18
    Join Date
    Oct 2005
    Location
    Sweden
    Posts
    3,516

    Default Re: SPI - The basics

    Hi,
    I just took a quick look at this but as far as I can see the commands are 8 bits and the response from the device is 11 bits starting at the 9th clock pulse. So, if reading the acceleration you first SHIFTOUT the 8 bit RDAX command, then you SHIFTIN 11 bits for a total of 19bits.

  19. #19
    Join Date
    Feb 2008
    Location
    Michigan, USA
    Posts
    231

    Default Re: SPI - The basics

    After banging around for a while, I was able to get this to give me good data from the inclinometer:
    Code:
    CS_I      VAR           PORTD.0  ' chip select Inclinomteter
    CS_D      VAR           PORTC.3  ' chip select D/A
    SCK       VAR           PORTD.3 ' clock
    SDI       VAR           PORTD.2 ' data IN , MISO
    SDO       VAR           PORTD.1 ' data OUT, MOSI
    IncIn     var           word
    HIGH CS_I   
    HIGH CS_D
    LOW SCK
    HIGH CS_I
    'I = %00001000      'send TeMP command
    I = %00010000     'send RDAX 
    
    Main:
         GOSUB iNCrDG
         hserout ["IncRdg ",bin IncIn," ",DEC IncIn," ",10,13]
         PAUSE 100
    goto main
    '**** Subs *********************************
    ;---- Sub to read the inclinometer ------------------
    IncRdg:
      LOW CS_I                       ' enable writes to Inclinometer
      SHIFTOUT SDO,SCK,1,[I]      'sends command to READ
      SHIFTIN SDI,SCK,0,[IncIn\11]  
      HIGH CS_I 
      RETURN
    My LOGIC pod had a bit of a rough time trying to make sense of the unusual length of data and that threw me for a bit, but the HSEROUT showed that all was good. .

    Hope that help someone.

    Bo

Members who have read this thread : 2

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts