View previous topic :: View next topic |
Author |
Message |
Barney
Joined: 18 Oct 2004 Posts: 41 Location: Newark, CA
|
MCP3208 driver vs SPI Library functions |
Posted: Mon Apr 10, 2006 2:05 pm |
|
|
I have to revisit my old nemesis, SPI, and last time it whipped me. (I wimped out with I2C). No choice now as I need an 8 channel 12 bit ADC (MCP3208). This time around I found the MCP3208.c driver (thank you forum) and am wondering why I need to use it and bang bits instead of the built in SPI library functions?
Thanks |
|
![](templates/subSilver/images/spacer.gif) |
Charlie U
Joined: 09 Sep 2003 Posts: 183 Location: Somewhere under water in the Great Lakes
|
|
Posted: Mon Apr 10, 2006 2:22 pm |
|
|
Barney,
I've been using multiple MCP3208's in a design for a couple of years and never had any trouble with it. I have some functions that I can post later this evening that should get you started. The biggest problem is setting up the SPI hardware correctly. I'll include that, too. In the mean time, tell us which processor you are using and the version of your compiler. |
|
![](templates/subSilver/images/spacer.gif) |
Barney
Joined: 18 Oct 2004 Posts: 41 Location: Newark, CA
|
|
Posted: Tue Apr 11, 2006 12:20 pm |
|
|
Thanks, a more generous offer than what I was looking for, but I won't look a gift horse in the mouth. I am using the 16F87 & PCM 3.212
I had tried using the built in SPI functions about a year ago and it didn't work. I didn't have time to really get into the assemby code and verify how the hardware was being setup by the SPI commands and I got some really weird clock/data signals that didn't make sense so I went back to the tried & true I2C. I can't find a 12 bit 8 channel I2C ADC, so I have to get SPI working.
The "C" drivers is new information for me and may be the solution. Haven't had a chance to try them out on the hardware yet.
My real question is this, Why were the drivers were written given the built in SPI functions?
Thanks
Barney |
|
![](templates/subSilver/images/spacer.gif) |
dr Guest
|
OT:Gift Horse |
Posted: Tue Apr 11, 2006 2:13 pm |
|
|
Barney wrote: | Quote: | Thanks, a more generous offer than what I was looking for, but I won't look a gift horse in the mouth. | I am using the 16F87 & PCM 3.212
I had tried using the built in SPI functions about a year ago and it didn't work. I didn't have time to really get into the assemby code and verify how the hardware was being setup by the SPI commands and I got some really weird clock/data signals that didn't make sense so I went back to the tried & true I2C. I can't find a 12 bit 8 channel I2C ADC, so I have to get SPI working.
The "C" drivers is new information for me and may be the solution. Haven't had a chance to try them out on the hardware yet.
My real question is this, Why were the drivers were written given the built in SPI functions?
Thanks
Barney |
I think you would use the Gift Horse saying if he had offered you less than what you were looking for.............. |
|
![](templates/subSilver/images/spacer.gif) |
Charlie U
Joined: 09 Sep 2003 Posts: 183 Location: Somewhere under water in the Great Lakes
|
|
Posted: Tue Apr 11, 2006 4:40 pm |
|
|
Well, time flies when you are having fun????
I got caught up in the real world of production problems.
Here we go:
spi definitions header file:
Code: | // Defines for new spi mode parameters
//
#define SPI_MODE_0_0 0x4000
#define SPI_MODE_0_1 0x0000
#define SPI_MODE_1_0 0x0010
#define SPI_MODE_1_1 0x4010
|
Version 3 of the compiler sets up the spi in a non-standard mode with the basic parameters. Insert the following line in you initialization section:
Code: | setup_spi(SPI_MASTER|SPI_MODE_0_0|SPI_CLK_DIV_16); |
You can change the clock part for your system clock, etc.
Here's my adc_io.h file:
Code: | // Header file for adc_io.c file
// Contains function prototypes for adc_io.c
int adc_address_temp, adc_cs_temp;
long read_ext_adc (int ext_adc_channel);
long const start_ext_adc [8] =
{
0x0600, 0x0640, 0x0680, 0x06C0,
0x0700, 0x0740, 0x0780, 0x07C0
};
struct s_long
{
int l;
int h;
};
union u_long
{
long int l_temp;
struct s_long s_temp;
} long_temp0, long_temp1, long_temp2;
|
And here's my acd_io.c file:
Code: | // Code file for ADC access functions
// Also add adc_io.h file
/*
ADC I/O functions:
read_ext_adc(int ext_adc_channel)
*/
long read_ext_adc (int ext_adc_channel)
{
adc_address_temp = ext_adc_channel & 0x07;
// select the proper adc start sequence for our channel
long_temp0.l_temp = start_ext_adc[adc_address_temp];
adc1_cs = 0;
// then start the adc reading by sending the start sequence
// and reading the data
spi_write (long_temp0.s_temp.h);
long_temp1.s_temp.h = spi_read();
spi_write (long_temp0.s_temp.l);
long_temp1.s_temp.h = spi_read();
spi_write (long_temp0.s_temp.l);
long_temp1.s_temp.l = spi_read();
adc1_cs = 1;
long_temp1.l_temp = 0x0FFF & long_temp1.l_temp;
return (long_temp1.l_temp);
}
|
You will need to sort out your chip select and define a pin for it. Just use the read_ext_adc(channel); as you would any other function.
Code: | MyLongInt = read_ext_adc(channel); // channel is 0-7 |
Try this out and let us know if it works for you. I had to edit the functions a bit because my system has 2 of these and the chip selects are controlled by external latches.
edited to correct the set up parameters. Thanks PCM! |
|
![](templates/subSilver/images/spacer.gif) |
Barney
Joined: 18 Oct 2004 Posts: 41 Location: Newark, CA
|
Gift Horse |
Posted: Tue Apr 11, 2006 8:50 pm |
|
|
DR,
Nope, I got much more than I asked for. Muchos.
"You are looking a gift horse in the mouth when you receive a gift and then you question the value of that gift. Like a person who has been given a horse as a gift (a gift-horse) and you are looking into the horse's mouth to see if it is in good health." |
|
![](templates/subSilver/images/spacer.gif) |
magnoedu
Joined: 29 May 2009 Posts: 11
|
y need to driver for the multiples mcp3208 can you help-me? |
Posted: Sat Sep 25, 2010 4:55 am |
|
|
I need an driver for ccs to work with multiples mcp3208, I search by the all net but not find, I read one post you use multiples mcp3208, I trying to make changes to ex_ad12 by the ccs but not have success.
please help-me
sorry my bad english I live in Brazil |
|
![](templates/subSilver/images/spacer.gif) |
krugger
Joined: 12 Jul 2011 Posts: 18 Location: El Salvador
|
Suggested Changes |
Posted: Tue Jul 19, 2011 10:19 am |
|
|
Hello Charlie U,
I've been using your functions and they've been very helpfull to me. However I think I've found a bug in your code. My english is not very good but I'll try to make myself understood.
I was using your library to sequentially measure 6 consecutive ADC channels with MCP3208 Proteus Model. I realized that I obtained correct measures only in some channles, having wrong measures in some others.
Looking at the chronogram in the datasheet we observe that there is a bit that is slightly wider than the others in the address word (as they use 7 leading zeroes before the strat bit the wider bit is the SGL/DIFF bit in this example).
http://imageshack.us/photo/my-images/855/mcp3008driverbug.jpg/
Meanwhile, as you're using 5 leading zeroes in your code, the wider bit is exactly the most significant bit of the Channel selection field (D2). I've found that because of this bit D1 is ¿overlapped? by D2 and thus it always take the same value than D2, making it impossible to select channels 2,3,4 and 5 properly, as they have D2 != D1.
So, my suggestion (it has worked for my application) is to change the contents of start_ext_adc array, i.e.:
Code: | long const start_ext_adc [8] =
{
0x0600, 0x0640, 0x0680, 0x06C0,
0x0700, 0x0740, 0x0780, 0x07C0
}; |
changed as:
Code: | long const start_ext_adc [8] =
{
0x0180, 0x0190, 0x01A0, 0x01B0,
0x01C0, 0x01D0, 0x01E0, 0x01F0
}; |
Maybe I'm wrong but it has worked for me. I'll be glad of hearing comments or corrections if what I've said is wrong.
Thank you again for your work Charlie.
Regards,
Pablo |
|
![](templates/subSilver/images/spacer.gif) |
Charlie U
Joined: 09 Sep 2003 Posts: 183 Location: Somewhere under water in the Great Lakes
|
|
Posted: Tue Jul 19, 2011 5:28 pm |
|
|
Hello Pablo,
Thanks for the suggestion, but you are using a different ADC chip. Yours is the MCP3004/8 which is a 10 bit part. Your start array will work correctly for it. However, my driver is for an MCP3208 which is a 12 bit part. My original start array is correct for this part. It has been used in many production test systems for many years quite successfully.
Charlie |
|
![](templates/subSilver/images/spacer.gif) |
krugger
Joined: 12 Jul 2011 Posts: 18 Location: El Salvador
|
|
Posted: Tue Jul 19, 2011 8:53 pm |
|
|
Thank you again! |
|
![](templates/subSilver/images/spacer.gif) |
nuclear__
Joined: 24 Jan 2015 Posts: 63
|
3V7 operation |
Posted: Sun Mar 28, 2021 12:45 pm |
|
|
Hi. It's being too long since this thread was created.
I use mcp3208 with 3.7v supply (reference too).
I have an external power supply ( common ground with pic etc) and i test the digital output by adding 0.1v each time.
It looks working up to 1.0V . Then when i go to 1.1V my digital reading goes from around 1000(for 1Volt) to 1600(for 1.1Volt) then it keeps growing but not linear. It stops growing at 2 Volts.
I tried that on more than one channel and i get the same result.
I guess i get corrupted reading . Any idea how to check it more?
Here are variable readings after each command, as shown in file adc_io.c
Code: | spi_write (long_temp0.s_temp.h);
long_temp1.s_temp.h = spi_read();
printf(usb_cdc_putc,"\r\ntemp.h:%u ",long_temp1.s_temp.h);
spi_write (long_temp0.s_temp.l);
long_temp1.s_temp.h = spi_read();
printf(usb_cdc_putc," temp.h:%u ",long_temp1.s_temp.h);
spi_write (long_temp0.s_temp.l);
long_temp1.s_temp.l = spi_read();
printf(usb_cdc_putc," temp.l:%u ",long_temp1.s_temp.l); |
Voltage 0.9Volt :
temp.h:0 temp.h:3 temp.l:219 adc1:976
Voltage 1.0Volt :
temp.h:0 temp.h:3 temp.l:251 adc1:1008
Voltage 1.1Volt :
temp.h:0 temp.h:6 temp.l:111 adc1:1648
Voltage 1.2Volt :
temp.h:0 temp.h:6 temp.l:247 adc1:1776 |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 28, 2021 3:05 pm |
|
|
To display long ints with printf in CCS, you need to use "%lu". |
|
![](templates/subSilver/images/spacer.gif) |
nuclear__
Joined: 24 Jan 2015 Posts: 63
|
|
Posted: Sun Mar 28, 2021 3:31 pm |
|
|
h and l are int.
It doesn't compile with lu .
actualy you can see adc1 variable which is shown with %lu and is over 255. This is the output .
I just added the rest variables in a destructive way to help me find out the problem . But i cant |
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Mar 28, 2021 3:40 pm |
|
|
OK, well what happens if you use the CCS driver, mcp3208.c ? |
|
![](templates/subSilver/images/spacer.gif) |
temtronic
Joined: 01 Jul 2010 Posts: 9170 Location: Greensville,Ontario
|
|
Posted: Sun Mar 28, 2021 6:59 pm |
|
|
You don't post HOW you convert the 2 ADC bytes into the 'voltage' ! That is important for us to see.
Also, you say that Vref is 3.7 volts, same as VDD of the PIC. Is it the SAME power supply ? If so Vref will vary depending on what the PIC is doing !
The ADc Vref needs to be from a 'voltage reference' chip, well filtered Vin, bypassed, and laidout according to mfr's specs !
As a 10 bit ADC, you need a LOT of GREAt PCB design/layout/ components before you can get ANY reliable, accurate readings |
|
![](templates/subSilver/images/spacer.gif) |
|