EmbeddedRelated.com
Forums

RCM3000 and A/D using SPI

Started by "argy.tzak" August 7, 2007
Hi,

I need to use an ADC for my application, so I went for an LTC1294. I
haven't even noticed that there is a sample code for this chip inside
the SPI folder. I expected things to be easier for this reason, but
they're not.

According to the sample program, serial port B is used, as well as PD0
for the CS line.

>From the RCM3200 manual, I can see that the pins that I have to use are
pin PC4 for TXB
pin PC5 for RXB
PD0 for Chip Select (CS) and
PB0 (CLKB) for the clock signal

Using this configuration, I run the program and always get a value of
4.999V.

What strikes me most is that the PD0 (which is supposed to be used for
CS) is at around 1.5V (it floats), when it should be going low each
time a conversion is to be performed.

Is there something wrong with the configuration that I describe? And
since I am going to use port B for the RS-232 communication with
another device, which pins should I use if I define
#define SPI_SER_C (instead of #define SPI_SER_B (which pins for CS,
TX, RX and CLK).

Thx
Argy
--- In r..., "argy.tzak" wrote:
>
> Hi,
>
> I need to use an ADC for my application, so I went for an LTC1294. I
> haven't even noticed that there is a sample code for this chip
inside
> the SPI folder. I expected things to be easier for this reason, but
> they're not.
>
> According to the sample program, serial port B is used, as well as
PD0
> for the CS line.
>
> From the RCM3200 manual, I can see that the pins that I have to use
are
> pin PC4 for TXB
> pin PC5 for RXB
> PD0 for Chip Select (CS) and
> PB0 (CLKB) for the clock signal
>
> Using this configuration, I run the program and always get a value
of
> 4.999V.
>
> What strikes me most is that the PD0 (which is supposed to be used
for
> CS) is at around 1.5V (it floats), when it should be going low each
> time a conversion is to be performed.
>
> Is there something wrong with the configuration that I describe? And
> since I am going to use port B for the RS-232 communication with
> another device, which pins should I use if I define
> #define SPI_SER_C (instead of #define SPI_SER_B (which pins for CS,
> TX, RX and CLK).
>
> Thx
> Argy
>

Alternate thought: I looked at using the serial ports in the past,
but didn't like the libraries. I wound up just using the pins in
regular i/o fashion, and bit-banging the SPI port through my own
code. That way, I could do also support "odd" devices that may
require non-8 bit or non-16 bit words (say, it requires an extra
clock cycle to make a conversion). I don't know the SPI part you
have, but I'm thinking that most SPI devices are fine with bit-
banging. It's worth a shot anyhow.

Shawn
You haven't properly configured your I/O pins.
Your chip select is still set as an input.
----- Original Message ----
From: argy.tzak
To: r...
Sent: Tuesday, August 7, 2007 11:21:40 AM
Subject: [rabbit-semi] RCM3000 and A/D using SPI

Hi,

I need to use an ADC for my application, so I went for an LTC1294. I

haven't even noticed that there is a sample code for this chip inside

the SPI folder. I expected things to be easier for this reason, but

they're not.

According to the sample program, serial port B is used, as well as PD0

for the CS line.

>From the RCM3200 manual, I can see that the pins that I have to use are

pin PC4 for TXB

pin PC5 for RXB

PD0 for Chip Select (CS) and

PB0 (CLKB) for the clock signal

Using this configuration, I run the program and always get a value of

4.999V.

What strikes me most is that the PD0 (which is supposed to be used for

CS) is at around 1.5V (it floats), when it should be going low each

time a conversion is to be performed.

Is there something wrong with the configuration that I describe? And

since I am going to use port B for the RS-232 communication with

another device, which pins should I use if I define

#define SPI_SER_C (instead of #define SPI_SER_B (which pins for CS,

TX, RX and CLK).

Thx

Argy

Thx for the replies,

I read about bit banging and it seems that many prefer this solution.
I hate to admit it, but since my project also involves other stuff
besides configuring the hardware, I am trying to go for the shortest
way, using the available libraries. I do realize that this might get
me into trouble (and if it does, I won't be able to tell what's wrong).

Today I didn't have the time to work on my project, but I did find out
that pin PD0 (which is used in the code) is actually used by the
Ethernet chip on the RCM3200. That should be the reason why the code
doesn't work.

Argy

--- In r..., Steve Trigero wrote:
>
> You haven't properly configured your I/O pins.
> Your chip select is still set as an input.
> ----- Original Message ----
> From: argy.tzak
> To: r...
> Sent: Tuesday, August 7, 2007 11:21:40 AM
> Subject: [rabbit-semi] RCM3000 and A/D using SPI
>
>
>
> Hi,
>
> I need to use an ADC for my application, so I went for an LTC1294. I
>
> haven't even noticed that there is a sample code for this chip inside
>
> the SPI folder. I expected things to be easier for this reason, but
>
> they're not.
>
> According to the sample program, serial port B is used, as well as PD0
>
> for the CS line.
>
> From the RCM3200 manual, I can see that the pins that I have to use are
>
> pin PC4 for TXB
>
> pin PC5 for RXB
>
> PD0 for Chip Select (CS) and
>
> PB0 (CLKB) for the clock signal
>
> Using this configuration, I run the program and always get a value of
>
> 4.999V.
>
> What strikes me most is that the PD0 (which is supposed to be used for
>
> CS) is at around 1.5V (it floats), when it should be going low each
>
> time a conversion is to be performed.
>
> Is there something wrong with the configuration that I describe? And
>
> since I am going to use port B for the RS-232 communication with
>
> another device, which pins should I use if I define
>
> #define SPI_SER_C (instead of #define SPI_SER_B (which pins for CS,
>
> TX, RX and CLK).
>
> Thx
>
> Argy
>
>
>
>
>
>
>
--- In r..., "argy.tzak" wrote:
>
> Thx for the replies,
>
> I read about bit banging and it seems that many prefer this
solution.
> I hate to admit it, but since my project also involves other stuff
> besides configuring the hardware, I am trying to go for the shortest
> way, using the available libraries. I do realize that this might get
> me into trouble (and if it does, I won't be able to tell what's
wrong).
>
> Today I didn't have the time to work on my project, but I did find
out
> that pin PD0 (which is used in the code) is actually used by the
> Ethernet chip on the RCM3200. That should be the reason why the code
> doesn't work.
>
> Argy
FWIW, I've found bit-banging to be pretty easy. If you're not too
strapped on time, you can do a really dirty method: use no loops, and
bit check each position in the word to be sent. Bit set each
position in the word that is sent back. Tedious, but if you do this
in a function, you can always go back and fix at a later date.

The ones that I have do use a loop, and usually rotate the word being
sent, just bit checking the LSB to determine if the DO line is set or
not.

Here is some code that I have for an MCP3208 (4/8 channel 12bit
ADC). I'm sure that anybody else could do a better job, but it
works. _ADC_Clk_Pulse() just sets and clears the SPI clock bit; I
really need go back and change that to a macro... The first 4 bits
sent to the ADC are control bits, then a bit for conversion, then
send 12 clocks for the result (if I'm remembering correctly). "val"
is the channel to be sampled.

int _ADC(char val)
{
int retval;
char i;
retval=0;

#ifdef ADC_Debug
printf("Inside _ADC(); recieved val=%d\n\r",val);
#endif

// make sure bits are in proper state prior to proceeding
ADC_DI(FALSE);
ADC_CLK(FALSE);
ADC_CS(TRUE);

//initiate conversion, by sending first bit of the control word
ADC_DI(TRUE);
_ADC_Clk_Pulse();

//all conversions are differential, so set this bit to zero and
send
ADC_DI(FALSE);
_ADC_Clk_Pulse();

// send rest of control word with channel information
for (i=0;i<3;i++)
{
if (val&0x4)
{ADC_DI(TRUE);}
_ADC_Clk_Pulse();
ADC_DI(FALSE);
val = val*2; // left shift 1 bit to get next outgoing bit
}

// MCP3208 is sampling at this point in time, give it a moment to
settle
Delay(ms1delay);
// 1ms is longer than required, but this is not critical

// send two dummy bits, as required for conversion (see datasheet)
for (i=0;i<2;i++)
{ _ADC_Clk_Pulse(); }

// now read in conversion result, MSB is first
for (i=0;i<12;i++)
{
retval = retval * 2; // left shift value
retval = retval + ADC_DO; // add in next bit
_ADC_Clk_Pulse();
}

// done
ADC_CS(FALSE);

#ifdef ADC_Debug
printf("Recieved val=%d\n\r",retval);
#endif

// re-enable over current monitor
_OvrCurrentMonitor();
return retval;
}

For the MCP4922 dual DAC, I didn't need the data back, so I used
this. This has some error checking in it, and some calibration
gain/offset applied. The input is a float, which gets cast back to
int and stripped down into 12bits (the LSB was 1mV, so nice to do
that!). As I'm reading back over this, I noticed a distinct lack of
comments, but I think it's relatively straight forward to follow.

void DAC_Write(float val, int chan)
{
byte DAC_Write_i;
int value;

// make sure chan isn't too big
if (chan<0)
{ chan = 0;}
if (chan>1)
{ chan = 1;}

if (chan==0)
{
// first do check for range
if (val<0)
{val=0;}
if (val>P)
{valP;}
// now adjust value to proper DAC set level
val = (val - ISense_OFFSET) / ISense_GAIN;
// Set value to DAC to be low 12 bits
value = (int)val & 0x0fff;
// Add in control bits: A channel, buffer reference, no gain,
no shutdown
value = value + 0x7000;
}
if (chan==1)
{
// first do check for range
if (val<0)
{val=0;}
if (val>=4)
{val=4;}
val=val*1000;
// no calibration is used on DAC1
// Set value to DAC to be low 12 bits
value = (int)val & 0x0fff;
// Add in control bits: B channel, buffer reference, no gain,
no shutdown
value = value + 0xf000;
}

//send MSB first!
DAC_CS(TRUE);
DAC_Write_i = 16; // need 16 bits to go out!
//Send value
while(DAC_Write_i)
{
if (value&0x8000)
{ DAC_DI(TRUE);}
DAC_CLK(TRUE);
DAC_CLK(FALSE);
DAC_DI(FALSE);
DAC_Write_i = DAC_Write_i - 1;
value = value<<1; // right shift to get
next bit
}
DAC_CS(FALSE);
return;
}
Shawn