|
|
View previous topic :: View next topic |
Author |
Message |
zeeshan ahmed
Joined: 02 Dec 2010 Posts: 22
|
Problem in reading two channels in MAX1416 adc |
Posted: Sat Dec 31, 2011 2:06 am |
|
|
Hi all, Happy new year,
In continuation of previous thread
http://www.ccsinfo.com/forum/viewtopic.php?t=46768
Now i am able to read Channel 1 data successfully,
I am using the following code
Code: |
#include <18f26k22.h>
#fuses intrc,NOLVP,noWDT,pllen
#use delay (clock=32M)
#USE RS232(BAUD=19200, XMIT=PIN_c6, RCV=PIN_c7)
#use spi(FORCE_HW, spi2, master)
#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)
#define ch_s pin_b4
#define rst pin_b5
#define drdy pin_b0
int1 d=0;
int8 bdta[2];
#int_ext
void ext_isr(void)
{
output_toggle(pin_c0);
d=1;
output_low(ch_s);
delay_us(1);
spi_write2(0x38);
bdta[0]=spi_read2(0x00);
bdta[1]=spi_read2(0x00);
delay_us(1);
output_high(ch_s);
}
void main(void)
{
float data=0;
ext_int_edge (0,l_to_h);
setup_spi2(SPI_MASTER | spi_mode_3 | SPI_CLK_DIV_16);
enable_interrupts( INT_EXT_l2h );
enable_interrupts(GLOBAL);
output_low(rst); // Reset ADC for a while
output_low(ch_s);
delay_ms(500);
output_high(ch_s);
output_high(rst);
delay_ms(100);
//-----------------------------------------------------------------------------
output_low(ch_s); // Chip Select low
delay_us(1);
spi_write2(0x20); // Com Regs Chan 1, clk reg selected
spi_write2(0xa5); // Clk Regs, 60 HZ notch
spi_write2(0x10); // Com Regs chan 1, Setup reg selected
spi_write2(0x44); // Setup Regs
delay_us(1);
output_high(ch_s); // Chip Select High
//-----------------------------------------------------------------------------
delay_ms(1000);
while(true)
{
if(d==1)
{
d=0;
data=make16(bdta[0],bdta[1]);
printf("\rWord is %f",data);
}
}
}
|
Up till now the code is working properly.
But when i modified above program to read channel 1 and 2, problem occurs, i get wrong values.
The modified program to read 2 channels is:
Code: |
#include <18f26k22.h>
#fuses intrc,NOLVP,noWDT,pllen
#use delay (clock=32M)
#USE RS232(BAUD=19200, XMIT=PIN_c6, RCV=PIN_c7)
#use spi(FORCE_HW, spi2, master)
#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)
#define ch_s pin_b4
#define rst pin_b5
#define drdy pin_b0
int1 d=0,t=0;
int8 bdta[2];
#int_ext
void ext_isr(void)
{
int ad_data=0;
output_toggle(pin_c0);
d=1;
if (t==0) ad_data=0x38;
else if (t==1) ad_data=0x39;
output_low(ch_s);
delay_us(1);
spi_write2(ad_data);
bdta[0]=spi_read2(0x00);
bdta[1]=spi_read2(0x00);
delay_us(1);
output_high(ch_s);
}
void main(void)
{
float data=0;
ext_int_edge (0,l_to_h);
setup_spi2(SPI_MASTER | spi_mode_3 | SPI_CLK_DIV_16);
enable_interrupts( INT_EXT_l2h );
enable_interrupts(GLOBAL);
output_low(rst);
output_low(ch_s);
delay_ms(500);
output_high(ch_s);
output_high(rst);
delay_ms(100);
//-----------------------------------------------------------------------------
output_low(ch_s);
delay_us(1);
spi_write2(0x21); // com regs chan 2, clk reg selected
spi_write2(0xa5); // clk regs
spi_write2(0x11); // com regs chan 2, setup reg selected
spi_write2(0x44); // setup regs
spi_write2(0x10); // com regs chan 1, setup reg selected
spi_write2(0x44); // setup regs
delay_us(1);
output_high(ch_s);
//-----------------------------------------------------------------------------
delay_ms(1000);
t=0;
while(true)
{
if(d==1)
{
d=0;
data=make16(bdta[0],bdta[1]);
if(t==0)
{
printf("ch1\r\n");
}
else
{
printf("ch2\r\n");
}
printf("Word is %f\r\n",data);
if(t==0) t=1;
else if(t==1) t=0;
}
}
}
|
I think there is some thing wrong with setup or clock register setting.
Please help me and guide me if I am doing something WRONG. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Dec 31, 2011 3:51 pm |
|
|
I would get rid of the interrupt routine. It makes the program be
needlessly complex. You could move all that code into a driver function.
You could poll the DRDY line with an input() statement in a while() loop
until it goes ready. (Possibly with a timeout counter).
I think it would be much easier to modify and to maintain and to
understand your driver, if you re-write it and get rid of the interrupt
routine. Then you wouldn't need all those flags in the isr to synchronize
it to your main code. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Sun Jan 01, 2012 6:37 am |
|
|
I agree with PCM..trash the ISR just have code in Main.
Make a simple loop
Code: |
main(){
configure to read channel one
read channel one
display data channel one.
}
|
when that works
Code: |
main(){
configure to read channel one
read channel one
save channel one data
configure to read channel two
read channel two
save channel two data
display data channel one and two
} |
display data channel one.
If that doesn't read channel 2, then you've miscoded the setup 'config' for channel 2 as you know channel 1 works correctly.
Once you have it 'up and running', then create an ISR IF you can justify WHY ( speed ? code space ?so..ISR overhead is huge compared to 6-10 lines of 2nd channel 'inline')
You don't always need to use ISRs ! |
|
|
zeeshan ahmed
Joined: 02 Dec 2010 Posts: 22
|
Problem is still there |
Posted: Tue Jan 03, 2012 2:19 am |
|
|
Thank U PCM Programmer and Temtronic,
here is the datasheet of adc
http://datasheets.maxim-ic.com/en/ds/MAX1415-MAX1416.pdf
I have modified the program, i just removed the ISR, below is the simple program, but problem is still there, i am getting wrong data. I think there is a problem with data rate selection settings.
Code: |
#include <18f26k22.h>
#fuses intrc,NOLVP,noWDT,pllen
#use delay (clock=16M)
#USE RS232(BAUD=19200, XMIT=PIN_c6, RCV=PIN_c7)
#use spi(FORCE_HW, spi2, master)
#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)
#define ch_s pin_b4 // chipselect
#define rst pin_b5 // reset
#define drdy pin_b0 // data ready
int1 d=0,t=0;
int8 bdta[2];
float data=0;
int adr=0;
void main(void)
{
setup_spi2(SPI_MASTER | spi_mode_3 | SPI_CLK_DIV_4);
output_low(rst); // reset ADC for a while
output_low(ch_s);
delay_ms(500);
output_high(ch_s);
output_high(rst);
//----------------------------------------------------------------------------A
output_low(ch_s); // Select chip
delay_us(1);
spi_write2(0x20); // com regs chan 1
spi_write2(0xa4); // clk regs, 50 hz data rate
spi_write2(0x21); // com regs chan 2
spi_write2(0xa4); // clk regs, 50 hz data rate
spi_write2(0x10); // com regs chan 1
spi_write2(0x44); // setup regs
spi_write2(0x11); // com regs chan 2
spi_write2(0x44); // setup regs
delay_us(1);
output_high(ch_s);
//----------------------------------------------------------------------------A
while(true)
{
if(!input(drdy)) // data register read routine
{
if(t==0) adr=0x38; // chan 1
else if (t==0) adr=0x39; // chan 2
output_low(ch_s);
spi_write2(adr); // channel address
bdta[0]=spi_read2(0xff);
bdta[1]=spi_read2(0xff);
output_high(ch_s);
data=make16(bdta[0],bdta[1]);
d=1;
}
if(d==1) // new data avaiable ?
{
if(t==0) // data from chan 1
{
printf("ch1 data is %f\r\n",data);
}
else if(t==1)
{
printf("ch2 data is %f\r\n",data);
}
if(t==0) t=1; // alternate the channels
else if (t==1) t=0;
}
}
} |
Please guide me, whats wrong with above code.
Thank you very much for your time.
Best Reagrds. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9243 Location: Greensville,Ontario
|
|
Posted: Tue Jan 03, 2012 6:59 am |
|
|
First , I'd make a simple loop like below.
No conditions, no 'if's, just 'hard' coding ..select channel0, read, display, select channel1, read, display, loop.
This is a test program to see if the chip is working right, not a test in 'logic' or 'main program coding'.
Second, the lines with **. It appears you're sending FF or all ones to the chip, do you really want to send this data to it ?? I admit I haven't looked at the SPI driver commands but to me these lines say 'while receiving data from the SPI device, send 0xff to it at the same time' Am I right, wrong or just confused?
Code: |
while(true)
{
if(!input(drdy)) // data register read routine ,ready !
{
//read channel 1 and display data..
output_low(ch_s);
spi_write2(0x38); // channel address 0
** bdta[0]=spi_read2(0xff);
** bdta[1]=spi_read2(0xff);
output_high(ch_s);
data=make16(bdta[0],bdta[1]);
printf("ch1 data is %f\r\n",data);
delay_ms(100); //delay between channels for testing...
//read channel 2 and display data...
output_low(ch_s);
spi_write2(0x39); // channel address 1
** bdta[0]=spi_read2(0xff);
** bdta[1]=spi_read2(0xff);
output_high(ch_s);
data=make16(bdta[0],bdta[1]);
printf("ch1 data is %f\r\n",data);
delay_ms(100); // delay after displaying channel 2 data
}
|
Third.
I'd make a 'reset_ADC' function. the datasheet says how, sending a lot of 1's. It is important! You have to be able to 'synchronize' the PIC and ADC as ANY bad data on the SPI bus could/will corrupt the data stream. While 'overkill' I'd send it everytime I call the 'read channels' function just to be sure. At the very least , upon powerup and before 'main' is executed.
For test purposes I'd have fixed voltages on the channels. Say 1 volt and 4 volts. Not 0 and 5, that way you can tell if you're readings are correct. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Tue Jan 03, 2012 3:29 pm |
|
|
Quote: |
if(!input(drdy)) // data register read routine
{
if(t==0) adr=0x38; // chan 1
else if (t==0) adr=0x39; // chan 2
|
This test is wrong.
Your whole 2nd program could still be written in a much more simple way,
including the above section. |
|
|
zeeshan ahmed
Joined: 02 Dec 2010 Posts: 22
|
Wrong data |
Posted: Wed Jan 04, 2012 11:40 pm |
|
|
Thanks alot PCM Programmer and Temtronic for the reply.
I modified the above program as you suggested, but still the result is not correct, e.g. if Voltage on channel1 analog pin is 3.3 V, then ADC shows 4.5V, sometimes 2.3 V etc. This problem arises only when I want to use 2 channels, while with one channel ADC works perfect. I think there is a problem with output data rate and filter notch setting in setup register, Because when I change the data rate(from 50 to 60 Hz), ADC values also changes.
Code: |
void main(void)
{
setup_spi2(SPI_MASTER | spi_mode_3 | SPI_CLK_DIV_4);
output_low(rst); // reset ADC for a while
output_low(ch_s);
delay_ms(500);
output_high(ch_s);
output_high(rst);
//----------------------------------------------------------------------------A
output_low(ch_s); // Select chip
delay_us(1);
spi_write2(0x20); // com regs chan 1
spi_write2(0xa4); // clk regs, 50 hz data rate
spi_write2(0x10); // com regs chan 1
spi_write2(0x44); // setup regs
spi_write2(0x21); // com regs chan 2
spi_write2(0xa4); // clk regs, 50 hz data rate
spi_write2(0x11); // com regs chan 2
spi_write2(0x44); // setup regs
delay_us(1);
output_high(ch_s);
//----------------------------------------------------------------------------A
printf("ON\r\n");
while(true)
{
if(!input(drdy))
{
//read channel 1 and display data..
output_low(ch_s);
spi_write2(0x38); // channel address 0
bdta[0]=spi_read2(0xff);
bdta[1]=spi_read2(0xff);
output_high(ch_s);
data=make16(bdta[0], bdta[1]);
printf("ch1 data is %.2f\r\n", (data/65535)*4.96);
//read channel 2 and display data...
output_low(ch_s);
spi_write2(0x39); // channel address 1
bdta[0]=spi_read2(0xff);
bdta[1]=spi_read2(0xff);
output_high(ch_s);
data=make16(bdta[0], bdta[1]);
printf("ch2 data is %.2f\r\n", (data/65535)*4.96);
//delay_ms(100); // delay after displaying channel 2 data
}
}
}
|
Temtronic said:
Quote: |
Second, the lines with **. It appears you're sending FF or all ones to the chip, do you really want to send this data to it ?? I admit I haven't looked at the SPI driver commands but to me these lines say 'while receiving data from the SPI device, send 0xff to it at the same time' Am I right, wrong or just confused?
|
We can send any data while reading the ADC data register. I checked it with different values, it doesn't affect ADC values. |
|
|
RF_Developer
Joined: 07 Feb 2011 Posts: 839
|
|
Posted: Thu Jan 05, 2012 3:35 am |
|
|
This is a convertor with multiplexed input, it is not a pair of convertors side by side in the same chip. This mean you cannot select one channel, read it and then immediately read the other channel. You have to set up the first channel, wait for data ready, read it then select the second channel, wait for data ready then read.
Delta-sigma convertors work by filtering over time. They are primarily intended for continuous high resolution conversion, and have a high level of noise rejection, and the filtration is optimised to reject the line/mains frequencies, i.e. 50 or 60Hz. They are especially useful to measure slowly changing small signals in the presence of mains derived noise, such as strain gauge signals. They are of limited use as single shot general purpose convertors, which is what you are trying to do. Basically every time you change anything you must wait for the convertor to go through a full acquisition cycle. So in pseudo-code its always:
Code: |
while (true)
{
set up channel or filtering settings or anything
while (settings don't change)
{
wait for data ready
read data
do something with data just read
}
}
|
RF Developer |
|
|
|
|
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
|