![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
18f4520 SPI AD7376 |
Posted: Fri Mar 29, 2013 9:11 am |
|
|
Hello! I'm new here and beginner in PIC uC
I need help with a problem I have no idea how to solve.
I'm trying to control a digipot AD7376 via SPI from PIC 18F4520.
the signals seem correct in SPI pins, according to AD7376 datasheet (shown below)
but the digipot only works ok when sending odd decimal data (binary final 1)
AD7376 uses a 7-bit serial input data. Extra MSB bits are ignored.
spi_write (x);
231 or 11100111 works
232 or 11101000 not
233 or 11101001 works
234 or 11101010 not
235 or 11101011 works
236 or 11101100 not
...
Code: | #include <18F4520.h>
#use delay(clock=10000000)
#FUSES NOWDT, HS, NOPROTECT, NOBROWNOUT, NOPUT, NOCPD, STVREN, NODEBUG, NOLVP,
NOWRT, NOWRTD, NOIESO, NOFCMEN, NOPBADEN, NOWRTC, NOWRTB, NOEBTR, NOEBTRB,
NOCPB, NOMCLR, NOXINST
VOID main (VOID)
{
setup_spi ( SPI_MASTER | SPI_H_TO_L | SPI_XMIT_L_TO_H | SPI_CLK_DIV_64 ); //mode 3
output_high (pin_b0); //chip select
delay_ms (1000);
WHILE (1)
{
output_low (pin_b0); //chip select
spi_write (3);
output_high (pin_b0); //chip select
delay_ms (5000); //time for measure
}
} |
any idea what might be happening?
thanks all.
Regards.
-- CCS C ver 4.065 |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Fri Mar 29, 2013 9:41 am |
|
|
Wrong SPI mode.....
Look at the manufacturers data. They show the clock idle _low_. Yours is idling high....
Much better to use SPI mode numbers. The data sheet for the pot shows mode0. Now if you add:
Code: |
#define SPI_MODE_0 (SPI_L_TO_H | SPI_XMIT_L_TO_H)
#define SPI_MODE_1 (SPI_L_TO_H)
#define SPI_MODE_2 (SPI_H_TO_L)
#define SPI_MODE_3 (SPI_H_TO_L | SPI_XMIT_L_TO_H)
|
and change your setup to:
Code: |
setup_spi ( SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_64 ); //mode0
|
Your timings should be better.
You are transmitting on the right edge, but starting from the wrong beginning....
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Fri Mar 29, 2013 11:56 am |
|
|
Hello Ttelmah,
first, very thanks!
I was using the same #defines you showed, but with SPI_MODE_3 in setup_spi. only modified to be more objective here.
testing here now, in SPI_MODE_0 nothing works.
only odd decimal in SPI_MODE_3 again.
with this guy seems to work:
http://www.instructables.com/id/Using-an-Arduino-to-Control-or-Test-an-SPI-electro/
looks like my timings. he used mode3.
according to the datasheet of ad7376:
"The 7-bit serial word must be loaded MSB first. The
format of the word is shown in Figure 2. The positive edge
-sensitive CLK input requires clean transitions to avoid clocking
incorrect data into the serial input register. Standard logic
families work well. When CS is low, the clock loads data into
the serial register upon each positive clock edge."
I d'ont understand the problem.
thanks thanks thanks |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Fri Mar 29, 2013 12:15 pm |
|
|
You may be raising CS too soon.
It should be mode0 from the data sheet, though the example you show is using 3. Some chips don't care and will use either mode.
SPI is MSB first.
Try:
Code: |
VOID main (VOID)
{
int8 dummy;
setup_spi ( SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_64 );
output_high (pin_b0); //chip select
delay_ms (1000);
WHILE (1)
{
output_low (pin_b0); //chip select
dummy=spi_read (3);
output_high (pin_b0); //chip select
delay_ms (5000); //time for measure
}
}
|
Using spi_read, makes the function wait till the transfer is finished (since it waits to clock the non-existent return byte in).
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Fri Mar 29, 2013 1:00 pm |
|
|
the same
results:
setup_spi ( SPI_MASTER | SPI_MODE_0 | SPI_CLK_DIV_64 );
spi_write (3); = none
spi_write (4); = none
setup_spi ( SPI_MASTER | SPI_MODE_1 | SPI_CLK_DIV_64 );
spi_write (3); //103k = OK
spi_write (4); = none
setup_spi ( SPI_MASTER | SPI_MODE_2 | SPI_CLK_DIV_64 );
spi_write (3); = none
spi_write (4); = none
setup_spi ( SPI_MASTER | SPI_MODE_3 | SPI_CLK_DIV_64 );
spi_write (3); //103k = OK
spi_write (4); = none |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Fri Mar 29, 2013 1:53 pm |
|
|
If you look at it the data sheet picture again, it shows an eighth data bit after the seven bits are sent.
To send '3' to the chip, you need to rotate this by one, and send '6'.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Fri Mar 29, 2013 3:08 pm |
|
|
also try adding a 47 ohm resistor in series with the control lines to both SDI and your clock line between the pic and digipot . helps enormously to prevent glitching with HS switching . |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Fri Mar 29, 2013 5:45 pm |
|
|
Ttelmah wrote: | If you look at it the data sheet picture again, it shows an eighth data bit after the seven bits are sent.
To send '3' to the chip, you need to rotate this by one, and send '6'.
|
asmboy wrote: | also try adding a 47 ohm resistor in series with the control lines to both SDI and your clock line between the pic and digipot . helps enormously to prevent glitching with HS switching . |
very thanks! but it not work I changed the digipot, same result.
I'll try via software spi... |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Fri Mar 29, 2013 10:28 pm |
|
|
trying with software spi:
Code: | #include <18F4520.h>
#use delay(clock=10000000)
#FUSES NOWDT, HS, NOPROTECT, NOBROWNOUT, NOPUT, NOCPD, STVREN, NODEBUG, NOLVP,
NOWRT, NOWRTD, NOIESO, NOFCMEN, NOPBADEN, NOWRTC, NOWRTB, NOEBTR, NOEBTRB,
NOCPB, NOMCLR, NOXINST
#USE SPI (MASTER, CLK=PIN_C3, DI=PIN_C4, DO=PIN_C5, MODE=3, BITS=8, STREAM=SPI_1, MSB_FIRST)
VOID main (VOID)
{
output_high (pin_b4); //chip select
delay_ms (1000);
WHILE (1)
{
output_low (pin_b4); //chip select
spi_xfer(124);
output_high (pin_b4); //chip select
delay_ms (5000); //time for measure
}
} |
with MODE=0 not work,
in MODE=3 works exactly on hardware spi
but if i remove the delay_ms (5000); works some odd values: 126, 124, 122
![Shocked](images/smiles/icon_eek.gif) |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Sun Mar 31, 2013 5:09 pm |
|
|
tested in another pic I have here,
18f4431 with internal osc,
same result. ![Sad](images/smiles/icon_sad.gif) |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 31, 2013 5:15 pm |
|
|
What do you mean by "not work" ?
How are you testing it ?
What do you observe to see if it works or does not work ?
The circuit schematic that you posted is very minimal.
What are the connections to the other pins, such as Vdd, Vss, A, B, W,
\RS and \SHDN ? |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Sun Mar 31, 2013 6:12 pm |
|
|
hello PCM programmer,
first, very thanks!
I'm testing with a resistance meter, between W and A, between W and B.
when I say working, I have a resistence value equivalent to the decimal value sent.
sending "1", read the values on meter: 101k between W-A, and 0.1k between W-B,
sending "127," read values: 0.1K between W-A and 102k between W-B, like a "real" pot.
when I say "not work", I have no reading between WA and WB, seems fully open.
the pins on the AD7376:
Vdd: +15Vdc
Vss: -15Vdc
GND: GND
A, B, W: resistance meter
\RS: nothing
\SHDR: nothing
SDO: nothing
I also did tests with Vdd:+5Vdc, Vss:GND, \RS: +5vdc, \SHDR: +5vdc
in both tests, was a "traditional" power supply: transformer, 4700u cap, 7815, 7915, 7805 regulators, protection diodes etc ... clean. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah
Joined: 11 Mar 2010 Posts: 19359
|
|
Posted: Mon Apr 01, 2013 1:07 am |
|
|
I must admit, I think I'd drive this using software, rather than trying to use the SPI.
If you study the data sheet, the behaviour of the shift register suggests that it really should have CS raised after the seventh bit rather than the eighth to work ideally.
However their illustration shows a sequence that SPI should manage fine.
Table 7, tells you that in fact the starting level of the clock doesn't matter (x) in the row. and what happens at each state. Bits are latched at each rising edge in the clock, but the word is transferred at the rising edge of CS.
Using eight bits, the top bit should have shifted out the top of the register when this happens, so shouldn't matter at all. The data sheet confirms this with "Extra MSB bits are ignored".
However it sounds as if the chip doesn't really behave like this...
So trying seven bits instead:
Code: |
#include <18F4520.h>
#use delay(clock=10000000)
#FUSES NOWDT, HS, NOPROTECT, NOBROWNOUT, PUT, NOCPD, STVREN, NODEBUG, NOLVP,
NOWRT, NOWRTD, NOIESO, NOFCMEN, NOPBADEN, NOWRTC, NOWRTB, NOEBTR, NOEBTRB,
NOCPB, NOMCLR, NOXINST
//as a comment, always have PUT with a crystal...
#define CS PIN_C0
#define SDO PIN_C5
#define SCL PIN_C3
void load_byte(int8 val)
{
int8 mask=0x40; //start with the seventh bit
int8 count;
output_low(SCL);
output_low(CS); //select the register
//clock out seven bits
for (count=0;count<7;count++)
{
if ((val ^ mask)!=0)
output_high(SDO);
else
output_low(SDO);
output_high(SCL); //latch the bit
mask/=2; //next bit
output_low(SCL);
}
output_high(CS); //load the byte to the pot
}
VOID main (VOID)
{
int8 val;
output_high (CS); //chip select
output_low(CLK);
delay_ms (1000);
WHILE (TRUE)
{
for (val=0;val<128;val++)
{
load_byte(val);
delay_us(50);
}
}
}
|
Should give a sawtooth output, at about 150Hz.
I must say the data sheet is a "curate's egg", with some really noticeable contradictions in what it says/shows.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Mon Apr 01, 2013 4:55 pm |
|
|
thanks Ttelmah,
but in your code, I did not understand where the value is to be sent.
sorry, I'm beginner.
trying manually, I wrote a code that is looped off and on PIN_C3 with delays of 3us between them, to generate the clock, etc ... can laugh of me! rssss looks good in scope.
and it works! (decimal "8")
Code: | #define CS PIN_C0
#define SDO PIN_C5
#define SCL PIN_C3
#define time (3)
VOID main (VOID)
{
WHILE (TRUE)
{
output_high(CS);
output_high(SDO);
output_high(SCL);
delay_ms (5000);
// start
output_low(CS);
delay_us (1);
//------bit 7 - MSB //00001000
// ^
output_low(SCL);
output_low(SDO);
delay_us (time);
output_high(SCL);
delay_us (time);
//------bit 6 - //00001000
// ^
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
//------bit 5 - //00001000
// ^
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
//------bit 4 - //00001000
// ^
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
//------bit 3 - //00001000
// ^
output_high(SDO); //UP
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
output_low(SDO); //DOWN
//------bit 2 - //00001000
// ^
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
//------bit 1 - //00001000
// ^
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
//------bit 0 - //00001000
// ^
output_low(SCL);
delay_us (time);
output_high(SCL);
delay_us (time);
//--------------------------------------------
delay_us (time);
output_high(CS);
}
} |
and now? |
|
![](templates/subSilver/images/spacer.gif) |
ouch_
Joined: 27 Mar 2013 Posts: 12
|
|
Posted: Mon Apr 01, 2013 8:48 pm |
|
|
Working:
Code: | #USE SPI (MASTER, CLK=PIN_C3, DI=PIN_C2, DO=PIN_C5, MODE=3, BITS=8, STREAM=SPI_1, MSB_FIRST)
VOID main (VOID)
{
WHILE (TRUE)
{
output_low (PIN_C0);
spi_xfer(254);
output_high (PIN_C0);
}
} |
Not Working:
Code: | #USE SPI (MASTER, CLK=PIN_C3, DI=PIN_C2, DO=PIN_C5, MODE=3, BITS=8, STREAM=SPI_1, MSB_FIRST)
VOID main (VOID)
{
WHILE (TRUE)
{
output_low (PIN_C0);
spi_xfer(254);
output_high (PIN_C0);
delay_ms (5000); // <<<< diference
}
} |
why?
any delay cause the problem! |
|
![](templates/subSilver/images/spacer.gif) |
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|