PDA

View Full Version : SPI - The basics



rnuke77
- 29th August 2010, 14:18
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

rnuke77
- 30th August 2010, 18:02
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???????

Bruce
- 30th August 2010, 19:43
For SPI use SHIFTOUT. Something like this should work;


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

rnuke77
- 30th August 2010, 23:47
Thanks Bruce. I will give this a go in the next day or two and let you know if I had some success!

rnuke77
- 1st September 2010, 15:10
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 ...

Bruce
- 1st September 2010, 15:50
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.

rnuke77
- 5th September 2010, 11:17
Thanks Bruce-
All the seperate components came together and everything is working great. Your help above was great!!!

HankMcSpank
- 7th September 2010, 01:32
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/imported-files/data_sheets/AD5204_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....




@ __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

Bruce
- 8th September 2010, 08:20
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.

HankMcSpank
- 8th September 2010, 10:39
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?

Bruce
- 8th September 2010, 17:12
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.

HankMcSpank
- 9th September 2010, 12:08
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?

boroko
- 4th July 2011, 09:34
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 (http://www.vti.fi/midcom-serveattachmentguid-53b766f2850a127b88947edbf1de536f/SCA61T_inclinometer_datasheet_8261900A.pdf) 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

mister_e
- 4th July 2011, 18:05
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/en/devicedoc/21298c.pdf

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

boroko
- 5th July 2011, 01:38
Thanks Steve!

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

Bo

boroko
- 5th July 2011, 02:15
Interesting, that explanation doesn't show up in either the MCP4821 or MCP4921 datasheets.

Thanks again for the heads up

Bo

boroko
- 8th July 2011, 12:13
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.

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

HenrikOlsson
- 8th July 2011, 13:10
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.

boroko
- 9th July 2011, 22:35
After banging around for a while, I was able to get this to give me good data from the inclinometer:

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