SPI Communications

Started by rickpres22 May 18, 2005
Are there any application notes around showing how to use the SPI
communication commands on the BX-24. I am thinking about interfacing
an Analog Devices AD5235 digital potentiometer, which uses SPI
communications, and was wondering how complicated that would be.



> ... how to use the SPI communication commands on the BX-24...

SPI is easy. Look at file EasyOpenSPI.bas in the group's file section.
Much of what's there, already simple, is fluff.

OpenSPI defines the SPI channel (pick one), the CS pin and SPI mode (for
me, always a 0). SPICmd does the CS pin work and shifts the commands
and data for you; it writes to and immediately reads from the bus. I
believe you must write at least one byte, a command to your device, but
the read count can be zero.

You need only dim a few bytes for output commands and data, a few for
input data, open the SPI channel, call SPICmd (pointing at the right
things) and, poof, you write commands and read data. Tom
Tom Becker
--... ...--
GTBecker@GTBe... www.RighTime.com
The RighTime Clock Company, Inc., Cape Coral, Florida USA
+1239 540 5700


--- In basicx@basi..., "rickpres22" <rickpres22@y...> wrote:
> Are there any application notes around showing how to use the SPI
> communication commands on the BX-24.

I haven't seen an application note but the built-in SPI is easy to
use. The most difficult aspects of it are that you need to solder
some wires to your BX-24 and you need to understand the command
protocol of the selected device. Each SPI device has it's own command
set that you'll need to understand.

If you don't want to solder wires onto the BX-24, you can use Tom
Handley's bit-banged SPI routines. They can use any set of three pins
for SCK, MOSI, MISO plus an additional one for the device's chip
select. See the link below:

http://home.comcast.net/~tomhandley/rs/rs.html


rickpres22, I have moved general BX-24 suff to another directory to
separate the RoboSapien specific examples. In the case of my SPI
module, they are the same but you will want to check the following
link [SPI.zip]:

http://home.comcast.net/~tomhandley/bx-24/bx-24.html

My example uses pins 25, 26, and 27 with an additional pin for chip
select. You can easily change that to any regular pin. I had problems
talking to some SPI devices using the hardware SPI and built-in
functions so I wrote a Bit-banged version. What I do now days is try
the Bit-banged version first to verify the interface to a given
device and then try the hardware routines. Peter Anderson has a good
discussion of using the built-in SPICmd() at:

http://www.phanderson.com/bx24/spicommand.html

- Tom

--- In basicx@basi..., "Don Kinzer" <dkinzer@e...> wrote:
> --- In basicx@basi..., "rickpres22" <rickpres22@y...> wrote:
> > Are there any application notes around showing how to use the SPI
> > communication commands on the BX-24.
>
> I haven't seen an application note but the built-in SPI is easy to
> use. The most difficult aspects of it are that you need to solder
> some wires to your BX-24 and you need to understand the command
> protocol of the selected device. Each SPI device has it's own
command
> set that you'll need to understand.
>
> If you don't want to solder wires onto the BX-24, you can use Tom
> Handley's bit-banged SPI routines. They can use any set of three
pins
> for SCK, MOSI, MISO plus an additional one for the device's chip
> select. See the link below:
>
> http://home.comcast.net/~tomhandley/rs/rs.html


--- In basicx@basi..., "tombhandley" <gr13tbs@c...> wrote:
> [...]Peter Anderson has a good discussion of using the built-in
> SPICmd() at:
> http://www.phanderson.com/bx24/spicommand.html

I read through the discussion and was confused. With regard to the
example below he says that "four bytes are sent beginning at the
address of A(1)".

Call SPICmd(1, 3, A(1), 1, Dummy)

Later, with regard to the next example below he says "4 bytes are
sent beginning at A(1)".

Call SPICommand(1, 0, A(1), 4, A(1))

These statements seem to be conflicting. My research suggests that
the second statement is, in fact, the correct one but the actual
goings on still are not clearly explained.

Here's what really happens: If the 'PutCount' parameter is non-
zero, bytes are written in succession beginning at the address of
the 'PutData' parameter and the data returned for each byte written
is discarded. Then, if the 'GetCount' parameter is non-zero,
existing bytes beginning at the address of the 'GetData' are written
and the data returned is written to 'GetData'.

An example may help clarify this. Assume that a byte
array 'outData' has the following values: 21, 22, 23, 24 and that a
byte array 'inData' has the following values: 99, 98. Then, the
call below is executed:

Call SPICmd(chan, 3, outData(1), 2, inData(1))

This will result in the following data being written and stored.
The first column is the data byte written, the second column
indicates where the returned data byte ends up.

Data written and read:
21 discarded
22 discarded
23 discarded
99 indata(1)
98 indata(2)

Just to be clear, here's a second example call using the same
initial data as above:

Call SPICmd(chan, 0, outData(1), 2, inData(1))

Data written and read:
99 indata(1)
98 indata(2)

Depending on the device that you've connected, the ability to write
existing data from the input array may or may not be useful.

Caveat: This is how it works on a BX-24P. I suspect that the same
is true of the older version but I haven't confirmed it.

Don



I don't see an SPICmd mystery, guys.

SPICmd writes a number of bytes, simultaneously overwriting the outgoing
RAM data with incoming SPI data (zeros, in my case), then reads a number
of SPI bytes. The outgoing data (the command and 2-byte address, for
instance) is overwritten in the midst of SPICmd, and consequently must
be set each time SPICmd is called.

This is extracted from my FRAM code, more or less, and should work: const SPIChannel as byte = 1
const bPin as integer = 10 'CS for FRAM

dim bGetCount as byte
dim bPutCount as byte

dim bPutData0 as byte 'SPI command
dim bPutData1 as byte 'FRAM AddrL
dim bPutData2 as byte 'FRAM AddrH
dim iPutData34 as integer
dim iPutData56 as integer

dim iIncomingInteger0 as integer
dim iIncomingInteger2 as integer

call OpenSPI(SPIChannel, 0, bPin) '0= mode and speed;
might differ for your part 'read two consecutive integers
bPutData0 = 3 'read command
bPutData1 = cbyte(iFRAMAddress \ i256)
bPutData2 = cbyte(iFRAMAddress mod i256)
bPutCount = 3 'send command, integer address
bGetCount = 4 'get 2 integers
call SPIcmd(SPIChannel, bPutCount, bPutData0, bGetCount,
iIncomingInteger0) 'write two consecutive integers
bPutData0 = 6 'wren command
bPutData1 = cbyte(iFRAMAddress \ i256)
bPutData2 = cbyte(iFRAMAddress mod i256)
bPutCount = 1 'command
bGetCount = 0 'no return data
call SPIcmd(SPIChannel, bPutCount, bPutData0, bGetCount, 0)
'0 is dummy read address
iPutData34 = iFirstIntegerToWrite
iPutData56 = iSecondIntegerToWrite
bPutData0 = 2 'write command
bPutCount = 7 'put command, integer address, 2 integers
bGetCount = 0 'no return data
call SPIcmd(SPIChannel, bPutCount, bPutData0, bGetCount, 0) Tom
Tom Becker
--... ...--
GTBecker@GTBe... www.RighTime.com
The RighTime Clock Company, Inc., Cape Coral, Florida USA
+1239 540 5700



Don, Peter's notes also confused me as does NetMedia's docs... I had
similar results as yours with a standard BX-24. At the time I was
testing the PNI V2Xe compass which has a complex SPI interface. I had
assumed I was doing something wrong. After a 'marathon' call with
their application engineer, I decided to write the Bit-banged
routines and they work fine.

- Tom

--- In basicx@basi..., "Don Kinzer" <dkinzer@e...> wrote:
> --- In basicx@basi..., "tombhandley" <gr13tbs@c...> wrote:
> > [...]Peter Anderson has a good discussion of using the built-in
> > SPICmd() at:
> > http://www.phanderson.com/bx24/spicommand.html
>
> I read through the discussion and was confused. With regard to the
> example below he says that "four bytes are sent beginning at the
> address of A(1)".
>
> Call SPICmd(1, 3, A(1), 1, Dummy)
>
> Later, with regard to the next example below he says "4 bytes are
> sent beginning at A(1)".
>
> Call SPICommand(1, 0, A(1), 4, A(1))
>
> These statements seem to be conflicting. My research suggests that
> the second statement is, in fact, the correct one but the actual
> goings on still are not clearly explained.
>
> Here's what really happens: If the 'PutCount' parameter is non-
> zero, bytes are written in succession beginning at the address of
> the 'PutData' parameter and the data returned for each byte written
> is discarded. Then, if the 'GetCount' parameter is non-zero,
> existing bytes beginning at the address of the 'GetData' are
written
> and the data returned is written to 'GetData'.
>
> An example may help clarify this. Assume that a byte
> array 'outData' has the following values: 21, 22, 23, 24 and that a
> byte array 'inData' has the following values: 99, 98. Then, the
> call below is executed:
>
> Call SPICmd(chan, 3, outData(1), 2, inData(1))
>
> This will result in the following data being written and stored.
> The first column is the data byte written, the second column
> indicates where the returned data byte ends up.
>
> Data written and read:
> 21 discarded
> 22 discarded
> 23 discarded
> 99 indata(1)
> 98 indata(2)
>
> Just to be clear, here's a second example call using the same
> initial data as above:
>
> Call SPICmd(chan, 0, outData(1), 2, inData(1))
>
> Data written and read:
> 99 indata(1)
> 98 indata(2)
>
> Depending on the device that you've connected, the ability to write
> existing data from the input array may or may not be useful.
>
> Caveat: This is how it works on a BX-24P. I suspect that the same
> is true of the older version but I haven't confirmed it.
>
> Don


Tom, this is interesting. I've only tested it using Byte arrays.

- Tom

--- In basicx@basi..., "Tom Becker" <gtbecker@r...> wrote:
> I don't see an SPICmd mystery, guys.
>
> SPICmd writes a number of bytes, simultaneously overwriting the
outgoing
> RAM data with incoming SPI data (zeros, in my case), then reads a
number
> of SPI bytes. The outgoing data (the command and 2-byte address,
for
> instance) is overwritten in the midst of SPICmd, and consequently
must
> be set each time SPICmd is called.
>
> This is extracted from my FRAM code, more or less, and should work: > const SPIChannel as byte = 1
> const bPin as integer = 10 'CS for FRAM
>
> dim bGetCount as byte
> dim bPutCount as byte
>
> dim bPutData0 as byte 'SPI command
> dim bPutData1 as byte 'FRAM AddrL
> dim bPutData2 as byte 'FRAM AddrH
> dim iPutData34 as integer
> dim iPutData56 as integer
>
> dim iIncomingInteger0 as integer
> dim iIncomingInteger2 as integer
>
> call OpenSPI(SPIChannel, 0, bPin) '0= mode and speed;
> might differ for your part > 'read two consecutive integers
> bPutData0 = 3 'read command
> bPutData1 = cbyte(iFRAMAddress \ i256)
> bPutData2 = cbyte(iFRAMAddress mod i256)
> bPutCount = 3 'send command, integer address
> bGetCount = 4 'get 2 integers
> call SPIcmd(SPIChannel, bPutCount, bPutData0, bGetCount,
> iIncomingInteger0) > 'write two consecutive integers
> bPutData0 = 6 'wren command
> bPutData1 = cbyte(iFRAMAddress \ i256)
> bPutData2 = cbyte(iFRAMAddress mod i256)
> bPutCount = 1 'command
> bGetCount = 0 'no return data
> call SPIcmd(SPIChannel, bPutCount, bPutData0, bGetCount, 0)
> '0 is dummy read address
> iPutData34 = iFirstIntegerToWrite
> iPutData56 = iSecondIntegerToWrite
> bPutData0 = 2 'write command
> bPutCount = 7 'put command, integer address, 2 integers
> bGetCount = 0 'no return data
> call SPIcmd(SPIChannel, bPutCount, bPutData0, bGetCount, 0) > Tom >
> Tom Becker
> --... ...--
> GTBecker@R... www.RighTime.com
> The RighTime Clock Company, Inc., Cape Coral, Florida USA
> +1239 540 5700


--- In basicx@basi..., "Tom Becker" <gtbecker@r...> wrote:
> I don't see an SPICmd mystery, guys.

The only mystery is that the BasicX documentation does not mention
that the content of the receive buffer prior to the call is written to
the device. Depending on the device, not being aware of this may
produce unexpected or unreliable results.

In reviewing the documentation again there is a subtle hint that the
data in the receive buffer is used. In the "Direction" column,
the "GetData" parameter is listed as "Input/Output". However, the
description of the parameter is "Data to be received".


> ... In the "Direction" column...

I've been unsuccessful in trying to read the FRAM by placing a read
command and address in the incoming buffer with a bGetCount of four
(command, integer address and room for a return byte), using zero in
bPutCount. All I can determine so far is that those data are changed to
255 in RAM after SPICmd. Tom
Tom Becker
--... ...--
GTBecker@GTBe... www.RighTime.com
The RighTime Clock Company, Inc., Cape Coral, Florida USA
+1239 540 5700