BobW

Active Member
My project of the week (if I'm lucky) involves interfacing a PIC16F1703 to an Analog Devices ADIS16203 digital inclinometer. Both are SPI capable. However, the ADIS16203 works strictly in 16 bit words, and the PIC16F1703 SPI documentation only discusses 8 bit byte transfer. I assume that I just need to read two successive bytes over SPI to get the full 16 bit word from the inclinometer, but I can also see where things could easily go awry (given my past experience with odd serial protocols). In past projects, when things were a bit non-standard, I would just bit bang the data, rather than try to figure out how to set up all of the config registers and config bits. That's what I'd do here (and probably will bit bang it for initial testing), but eventually I want to get this working in an interrupt routine, so I'll have to use the actual SPI port.

Does anyone here have experience with 16 bit SPI, and tips or example code to share?

Edit: I should mention that this will be programmed in assembly language.

jpanhalt

Well-Known Member
Hi Bob,

I have done it only a few times. Just like you suggest, you exchange 8 bits at a time. One chip I used was the AK8963 e-compass with a 16F1783. That did a sequential read of several 8-bit registers. Probably closest to what you are doing was reading the AS5048A rotary encoder from AMS. I used a 16F1519 for that. Here's a snippet of the read code. If more will help, let me know, and I will clean up the rest. I typically write a lot of comments to myself, which maybe shouldn't be put in public. Note, bits 15 and 14 were for parity and error, respectively, and had to be stripped off before calculating the encoder result. Here's a link to the datasheet: http://ams.com/eng/Products/Magnetic-Position-Sensors/Angle-Position-On-Axis/AS5048A (Can't link directly to the DS. Just click on the link there.)

Code:
;setup serial port
MOVLB     4              ;SPI controls in Bank4                       |B4
CLRF      SSPSTAT        ;CKE=0, SMP=0 (sample at middle)                                       |B4
MOVLW     b'00100000'    ;
MOVWF     SSPCON1        ;CKP=0,master clk =Fosc/x (see below),
;SPEN <5> enabled
;04.25.15 tried all 3 settings for <3,0>, Fosc/64 did not work, others did,
;hung up on waiting for the BF flag bit. 0001=Fosc/16 should work wtih
;all Fosc up to 32 MHz.  0000=Fosc/4. AS5048 internal clock is ca. 5 MHz. ˜˜

GetSPI
MOVLB     2              ;                                            |B2
BCF       CSn            ;!CS                                         |B2
MOVLB     4              ;                                            |B4
MOVLW     0xFF           ;alternative to zeros                        |B4                    |B4
MOVWF     SSPBUF         ;                                            |B4
;    CLRF      SSPBUF         ;initiates duplex communication              |B4

GetBUFF
;NB:Polling SSPSTAT,BF seems to work as well as polling PIR1,SSPIF and
;doesn't require bank switching.
btfss     SSPSTAT,BF
goto      $-1 movf SSPBUF,w movwf SPI_H CLRF SSPBUF btfss SSPSTAT,BF goto$-1
movf      SSPBUF,w
movwf     SPI_L
movlb     2              ;                                           |B2
bsf       CSn            ;set !SS(CSn)high                           |B2
;    movlb    4                                                           |B4
;    BCF       SSPCON1,SSPEN  ;disable SPI port leave running             |B4

ErrTest
BTFSC     SPI_H,6        ;checks error bit and returns if set
GOTO      Test0
BCF       SPI_H,7        ;clears parity bit so print not effected 08.01.15
BSF       SPI_H,7
;SET BIT<7> TO FLAG HIGH (MSB) BYTE WHEN SENDING EUSART TO STEPPER
;insert save data steps here
nop
;     DelayCy   (150*msecs)
;     DelayCy   (150*msecs)
call      RegPrnt
goto      GetSPI
John

EDIT: Just noticed the last 2 steps in the error test section. Ignore one or both. I was using that particular draft of the whole code to drive a stepper motor synchronously to the movement of the encoder input.

Last edited:

BobW

Active Member
Thanks John. Much appreciated. I'm completely brain dead tonight, so I'll give your code a good looking over tomorrow.
BTW, there's no such thing as too many comments.

fourtytwo

Member
Not much help but to drive a 16bit DAC fast I had to resort to a PIC24F with a 16 bit SPI controller, beware not all 16 bit mcu's have 16 bit SPI only those with fifo buffers!

Ian Rogers

User Extraordinaire
Forum Supporter
Not much help but to drive a 16bit DAC fast I had to resort to a PIC24F with a 16 bit SPI controller, beware not all 16 bit mcu's have 16 bit SPI only those with fifo buffers!
I use MCP's 12bit DAC... Same protocol as the 16bit.. I use two 8bit SPI transfers with no issue at all using pic16 and pic18...

SPI has 4 modes.... You just need to make sure the correct mode is selected or you can loose a bit in the middle..

Nigel Goodwin

Super Moderator
Yes, it's perfectly fine to send two 8 bit bytes, it's the way it's most often done - there seems little advantage in using 16 bit mode on the 24F series, so I don't bother.

Even if you do, it leaves the identical 'problem' of how do you do 32 bit transfers

Ian Rogers

User Extraordinaire
Forum Supporter
Well I did use the word FAST!!
True... The speed will come from the abilities of the pic24 over the pic16 and pic18.

To run at 8MHz on a small pic, you have to run at top speed, but the pic32 and pic24 can have different peripheral speeds.. I am testing a small SPI screen on a pic18... I can't achieve max speed ( 10MHz) only 8 or 16MHz..

Between 8 and 10 there is little difference I know, but it doesn't work at 16!!

Nigel Goodwin

Super Moderator
True... The speed will come from the abilities of the pic24 over the pic16 and pic18.

To run at 8MHz on a small pic, you have to run at top speed, but the pic32 and pic24 can have different peripheral speeds.. I am testing a small SPI screen on a pic18... I can't achieve max speed ( 10MHz) only 8 or 16MHz..

Between 8 and 10 there is little difference I know, but it doesn't work at 16!!