View previous topic :: View next topic |
Author |
Message |
kongfu1
Joined: 26 Apr 2010 Posts: 56
|
ads8331 - help |
Posted: Fri Dec 07, 2012 10:17 pm |
|
|
Hi,
Any one has experience or driver code of ads8331 ADC converter with 24EP512GU810 or any PIC?
This is chip is not easy to nail down.
Thanks,
Howard |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Dec 08, 2012 4:53 am |
|
|
Quote: | This is chip is not easy to nail down. |
Which chip?
Google took me straight to the TI ADS8331, and its data sheet.
A search on microchip's web site yielded the appropriate PIC data sheet.
What more do you need?
Mike |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19516
|
|
Posted: Sat Dec 08, 2012 8:40 am |
|
|
The interface is standard SPI. Like many other TI chips, they use a format that only requires less than a multiple of eight clocks, but then accept extra clocks to allow standard 8bit formats to be used. So if you study table 7, you have the clocks required for one mode as >=19, with up to five trailing zeros, allowing 24 clocks to be used and normal SPI.
Like many chips driving is not going to be 'generic', is has several different modes, dependant on whether you have acquisition continuous, or only when you read, which channel(s) you want to. read, whether you want sleep, etc. etc.. Draw a table of which features you want to use, then what commands you think are needed. Then try to code these. When you find this works, cheer, or if it doesn't, then post this here, and we will try to help. Keep the test 'environment' in the code simple. Just read values for the channels you want, don't try to attach this to your main code, till this is working.
Best Wishes |
|
|
kongfu1
Joined: 26 Apr 2010 Posts: 56
|
ads8331 - help |
Posted: Sat Dec 08, 2012 1:42 pm |
|
|
Hi,
Thanks for everyone's help. This project was done long time ago when a controller board is available but sensors circuit not.
Now everything is here. The problem is that, the ads8331 does not switch between two channels in a manual mode. CFR is set with manual channel select mode and everything else - 0x7fd. See SetFRC(), SetCh1() and SetCh2(). Testing code is attached below. Thanks.
Howard
Code: |
#include <24EP512GU810.h>
#device *=16
#fuses NOWDT, NOIESO, NODEBUG, NOJTAG
#use delay(crystal=8Mhz, clock=120Mhz, AUX:clock=48Mhz)
#pin_select SDI3 = PIN_D14
#pin_select SDO3 = PIN_D15
#pin_select SCK3IN = PIN_B13
#pin_select SS3IN = PIN_B14
#use spi(SLAVE, FORCE_HW, DI=PIN_D14, DO=PIN_D15, CLK=PIN_B13, BITS=8, SPI3, stream=SPI_RCB)
#define CCB_CHANNEL_ONE 1
#define CCB_CHANNEL_TWO 2
void SetCFR(void)
{
output_low(ADC_SPI_CS);
spi_write2(0xe7);
spi_write2(0xfd);
output_high(ADC_SPI_CS);
}
void SetCh1(void)
{
output_low(ADC_SPI_CS);
spi_write2(0x00); //select INT0 input
spi_write2(0x00);
output_high(ADC_SPI_CS);
}
void SetCh2(void)
{
output_low(ADC_SPI_CS);
spi_write2(0x01); //select INT1 input
spi_write2(0x00);
output_high(ADC_SPI_CS);
}
void ResetADC(void)
{
output_low(ADC_SPI_CS);
spi_write2(0xf0);
spi_write2(0x00);
output_high(ADC_SPI_CS);
}
//----------------------------------------------
void initADC(void)
//----------------------------------------------
{
output_high(ADC_SPI_CS);
setup_spi2(SPI_MASTER | SPI_H_TO_L | SPI_CLK_DIV_512);
delay_us(30);
ResetADC();
delay_ms(500);
SetCFR();
delay_ms(10);
SetCh1(); //set to next channel
SW_ON(ADC_START);
}
//use spi call to set and read data back from adc
unsigned int16 readPhotoCh(void)
{
unsigned int16 adcResult = 0, theInt16 = 0;
unsigned int8 i = 0, theInt0 = 0, theInt1 = 0;
while(!input(ADC_READY) && i < 1000)
{
delay_us(10);
i++;
}
if(i < 10)
{
delay_us(1);
output_low(ADC_SPI_CS);
delay_us(1);
theInt0 = spi_read2(0);
theInt1 = spi_read2(0);
output_high(ADC_SPI_CS);
theInt16 = theInt0;
theInt16 = theInt16 << 8;
adcResult = theInt16 | theInt1;
}
return adcResult;
}
void enableADC1(void)
{
SW_OFF(ADC_START); //convert analog to ADC SPI chip
spi_write2(0xd0); //read command 0x0d
spi_write2(0x00);
}
void enableADC2(void)
{
SW_OFF(ADC_START); //convert analog to ADC SPI chip
spi_write2(0xd0); ////read command 0x0d
spi_write2(0x00);
}
int16 ReadCh1(void)
{
uint16 volA;
enableADC1(); //convert analog to ADC SPI chip
volA = readPhotoCh();
SW_ON(ADC_START);
SetCh2(); //set to next channel
return volA;
}
int16 ReadCh2(void)
{
uint16 volA;
enableADC2(); //convert analog to ADC SPI chip
volA = readPhotoCh();
SW_ON(ADC_START);
SetCh1(); //set to next channel
return volA;
}
int16 ReadCh(void)
{
if(currentChannel == CCB_CHANNEL_ONE)
return ReadCh1();
else
return ReadCh2();
}
void main(void)
{
int16 theValue;
initADC();
currentChannel = CCB_CHANNEL_ONE;
theValue = ReadCh();
currentChannel = CCB_CHANNEL_TWO;
theValue = ReadCh();
}
|
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Dec 08, 2012 1:58 pm |
|
|
Quote: | unsigned int8 i = 0, theInt0 = 0, theInt1 = 0;
while(!input(ADC_READY) && i < 1000)
|
Your data type is too small.
Also, some of these variable names are not very good. You should
use better names like 'lsb' and 'msb'. The first byte to come out is
the msb, and the next byte is the lsb. Much better names than "theInt". |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Sat Dec 08, 2012 1:59 pm |
|
|
Are you're telling us the only problem is selecting the channel ? That everything else works fine ?
What were the ADC values tested and the results ?
Your 'main' program isn't complete and runs off......
It initalizes the ADC then captures 2 readings but nowhere does it display the results to us humans, then stops.well sleeps actually...
at least no that I can see.
Perhaps others see it differently ? |
|
|
kongfu1
Joined: 26 Apr 2010 Posts: 56
|
|
Posted: Sat Dec 08, 2012 2:19 pm |
|
|
temtronic wrote: | Are you're telling us the only problem is selecting the channel ? That everything else works fine ?
What were the ADC values tested and the results ?
Your 'main' program isn't complete and runs off......
It initalizes the ADC then captures 2 readings but nowhere does it display the results to us humans, then stops.well sleeps actually...
at least no that I can see.
Perhaps others see it differently ? |
Yes. the value was read back from ads8331 with sensor attached. The reading from ads8331 matches with sensor output. But it is always same value from channel 1 regardless SetCh1/SetCh2 were called or not.
USB communication was used with the board here. It is going to be too long to add USB driver with the testing code.
In debug mode, it shall be OK to test and see the problem.
Thanks.
Howard |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Dec 08, 2012 2:52 pm |
|
|
How do you KNOW the ADC values?
Mike |
|
|
kongfu1
Joined: 26 Apr 2010 Posts: 56
|
|
Posted: Sat Dec 08, 2012 3:20 pm |
|
|
Mike Walne wrote: | How do you KNOW the ADC values?
Mike |
The ADC values were measured from pin IN0 (channel 1) and IN1 (channel2) of ads8331. Also sensor output could be set in a rough range such as 0, 1,2..6V. For a testing purpose, have channel 1 set on 0 or 3 and channel 2 on 5V, readings from ads8331 are always same on both channels that matches with channel 1 settings.
Thanks,
Howard |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sat Dec 08, 2012 6:02 pm |
|
|
Code: | void enableADC1(void)
{
SW_OFF(ADC_START); //convert analog to ADC SPI chip
spi_write2(0xd0); //read command 0x0d
spi_write2(0x00);
}
void enableADC2(void)
{
SW_OFF(ADC_START); //convert analog to ADC SPI chip
spi_write2(0xd0); ////read command 0x0d
spi_write2(0x00);
} |
I don't find your code easy to analyse.
I can't see much difference between your two functions 'void enableADC2(void)' and 'void enableADC1(void)'.
Is this significant?
Mike
EDIT And I still don't see how KNOW what your ADC output is. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9228 Location: Greensville,Ontario
|
|
Posted: Sat Dec 08, 2012 6:22 pm |
|
|
I have to agree with Mike.
You should start with simple linear coding. Get ONE channel working correctly (showing the result either on and LCD or to a PC terminal program). Currently there is NO way to see the ADC results.
MANUALLY change the ADC channel and observe the results.
Once this is working, duplicate the 'read adc and display' code segment and add to 'main', with a small delay(say 500ms), so that you can observe the results, again on either LCD or PC, looping between the channels.
Once ALL this works, then, you can 'make it fancy', if you want. Really though, unless you're working on a very, very tight memory budget, it's NOT worth the effort to make it overly complicated.
hth
jay |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Dec 10, 2012 3:57 pm |
|
|
Quote: | void SetCh1(void)
{
output_low(ADC_SPI_CS);
spi_write2(0x00); //select INT0 input
spi_write2(0x00);
output_high(ADC_SPI_CS);
}
void SetCh2(void)
{
output_low(ADC_SPI_CS);
spi_write2(0x01); //select INT1 input
spi_write2(0x00);
output_high(ADC_SPI_CS);
}
The ADC values were measured from pin IN0 (channel 1) and IN1 (channel2) of ads8331
But it is always same value from channel 1 regardless SetCh1/SetCh2 were called or not. |
1. The channel numbers for IN0 and IN1 are not ch 1 and ch 2.
They are ch 0 and ch 1. They are the same as the INx number.
It's just a naming convention, but you shouldn't mentally rename the
channels to something different than the data sheet says.
2. Your method of selecting the channels is wrong. Look on page 27
of the ads8331 data sheet:
http://www.ti.com/lit/ds/symlink/ads8331.pdf
It has a table which shows the CMR values required to select channels
0 and 1. It shows clearly that the 4-bit CMR value is in bits 15:12 of
the of the 16-bit word. But your code, shown above, doesn't do that.
You have the channel in bits 11:8. That's not correct.
Download the sample C code from TI for interfacing to the ads8331.
http://www.ti.com/litv/zip/slaa551
Look in the main.c file. I have posted their channel select routine below.
Notice how they left-shift the channel into the upper 4 bits (bits 15:12).
This is a confirmation of the ads8331 data sheet.
Quote: |
// Write CMR register to select channel if Manual channel select is enabled
void ADS833x_Channel_Select(Uint16 Data)
{
Data = Data << 12;
while(SpiaRegs.SPISTS.bit.BUFFULL_FLAG !=0) { } // Wait until SPITXBUF is free
SpiaRegs.SPITXBUF = Data;
}
|
So your channel select code should be changed as shown in bold below:
Quote: |
void SetCh1(void)
{
output_low(ADC_SPI_CS);
spi_write2(0x00); //select INT0 input
spi_write2(0x00);
output_high(ADC_SPI_CS);
}
void SetCh2(void)
{
output_low(ADC_SPI_CS);
spi_write2(0x10); //select INT1 input
spi_write2(0x00);
output_high(ADC_SPI_CS);
} |
Please see bkamen's comments in the PIC101 thread:
http://www.ccsinfo.com/forum/viewtopic.php?t=47549&start=1 |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Mon Dec 10, 2012 7:49 pm |
|
|
BTW: whats the reason for the 24EP512GU810
in your post. ? |
|
|
|