EmbeddedRelated.com
Forums
The 2024 Embedded Online Conference

ADS1255 (24-bit ADC) Initialisation command sequence

Started by kishor March 5, 2010
Hi friends,
I am working on 16 - channel data acquisition project, Silab C8051F310
+ ADS1255 + external multiplexer.

ADC crystal is 7.643 MHz.
SPI clock freq is 1.58 MHz

Hardware interface-
	CS -->  permanently tied to ground
	3 wire SPI (SCK, MOSI, MISO)
	DRDY as external interrupt source

When I debug the code by step by step it works most of the time.
But in normal case it does not.

Whether my command sequence or delay between command is wrong.
Or something else i am missing.


Source code


/**
 * @brief	Write data to ADS1255 registers at specified address \a
lbAddress
 *		of specified length \a lbLength from pointer \a lpSource.
 *
 * @param	lbLength - Specifies the number of Bytes to write
 * @param	lbAddress - Specifies the destination ADS1255 register
address
 * @param	lpSource - Byte pointer to write data to ADS1255
 *
 */
void Wr_ADS1255_Reg ( Byte lbLength, Byte lbAddress, Byte * lpSource )
{
	SELECT_ADS1255();				// Select ADS1255

	SPI_Write ( 0x50 | lbAddress );			// Address with Write command
	SPI_Write ( lbLength - 1 );			// No of registers to write

	do
	{
		SPI_Write ( *lpSource++ );		// Write the data
	}
	while ( --lbLength );

	Wait_Clk ( 16 );					// Wait for 16 clock
}

/**
 * @brief	Read data from ADS1255 registers from specified address \a
lbAddress
 * 		of specified length \a lbLength to pointer \a lpDest
 *
 * @param	lbLength - Specifies the number of Bytes to read
 * @param	lbAddress - Specifies the address of ADS1255 register
 * @param	lpDest - Byte pointer to store data from ADS1255
 *
 */
void Rd_ADS1255_Reg ( Byte lbLength, Byte lbAddress, Byte * lpDest )
{
	SELECT_ADS1255();			// Select ADS1255

	SPI_Write ( lbAddress | 0x10 );		// Write Address with read command

	SPI_Write ( lbLength - 1 );		// No of registers to read

	Wait_Clk ( 80 );				// Wait for 80 clock

	do
	{
		*lpDest++ = SPI_Read();		// Read data from ADS1255
	}
	while ( --lbLength );

	Wait_Clk ( 16 );				// Wait for 16 clock

}


void Init_ADS1255 ( void)
{

	SELECT_ADS1255();

	Send_SPI ( enWAKEUP );		// Wakeup the Ads1255.
	Wait_Clk ( 48 );				// Wait for 48 clocks

	Send_SPI ( enRESET );			// Reset the ADS1255.
 	Wait_Clk ( 48 );				// Wait for 48 clocks

	// Read the registers to verify the communication
	Rd_ADS1255_Reg ( sizeof ( stRdReg ), 0, ( Byte * ) &stRdReg );

	stWrReg.Status 	= 0x04;		// Auto calibration is enabled
	stWrReg.MUX 		= 0x08;		// Single ended channel 0
	stWrReg.ADCON 		= 0;
	stWrReg.IO  		= 0xE0;		// IO register
	stWrReg.DRate 		= 0xF0;		// 30K SPS

	Wr_ADS1255_Reg ( 5, 0, ( Byte * ) &stWrReg );

	SPI_Write ( enSYNC );				// Syncronize the ADC

	SPI_Write ( enWAKEUP );			// Wakeup the Adc


	Rd_ADS1255_Reg ( sizeof ( stRdReg ), 0, ( Byte * ) &stRdReg );


	SPI_Write ( enSELFCAL );		// perform Self calibration

}

On Fri, 5 Mar 2010 03:41:28 -0800 (PST), kishor <kiishor@gmail.com> wrote:
> Hi friends, > I am working on 16 - channel data acquisition project, Silab C8051F310 > + ADS1255 + external multiplexer. > > ADC crystal is 7.643 MHz. > SPI clock freq is 1.58 MHz > > Hardware interface- > CS --> permanently tied to ground > 3 wire SPI (SCK, MOSI, MISO) > DRDY as external interrupt source > > When I debug the code by step by step it works most of the time. > But in normal case it does not. > > Whether my command sequence or delay between command is wrong. > Or something else i am missing.
First, without more detail on what you mean when you say "works" or "doesn't work", it will be hard for anyone to offer any specific recommendations. What do you expect to happen when it works? What do you observe that leads you to conclude that it isn't working? Based on your report that it works (mostly) when you step through the code with your debugger, it sounds like a timing issue to me. These can be extremely difficult to diagnose because you are attempting to examine in seconds or tens of seconds events that occur in microseconds. At this point I'd suggest that you re-read the ADC datasheet carefully with special attention to minimum and maximum timings. Your debugger slows down the CPU's actions relative to the ADC, so I'd start with the minimum timings and check them against your hand-calculated instruction timings for your '8051 code. Good luck! Frank McKenney -- Youth is much more capable of amusing itself than is now supposed, and in much less mortal need of being amused. The only real warning against solitude and stagnation which needs to be uttered is that you really need to be rather young and strong in order to get the fun out of them. -- G.K. Chesterton: On the Thrills of Boredom (1932) -- Frank McKenney, McKenney Associates Richmond, Virginia / (804) 320-4887 Munged E-mail: frank uscore mckenney ayut mined spring dawt cahm (y'all)
kishor wrote:
> Hi friends, > I am working on 16 - channel data acquisition project, Silab C8051F310 > + ADS1255 + external multiplexer. > > ADC crystal is 7.643 MHz. > SPI clock freq is 1.58 MHz > > Hardware interface- > CS --> permanently tied to ground
That's _wrong_. SPI uses edges of the CS line to signal the beginning of a transaction. It can't work without it.
"Hans-Bernhard Br&#4294967295;ker" <HBBroeker@t-online.de> wrote in message 
news:hmrmg1$qbh$00$1@news.t-online.com...
> kishor wrote: >> Hi friends, >> I am working on 16 - channel data acquisition project, Silab C8051F310 >> + ADS1255 + external multiplexer. >> >> ADC crystal is 7.643 MHz. >> SPI clock freq is 1.58 MHz >> >> Hardware interface- >> CS --> permanently tied to ground > > That's _wrong_. SPI uses edges of the CS line to signal the beginning of > a transaction. It can't work without it. >
The OP needs to re-visit the data sheet. TI do offer a mode of operation for this part with CS tied to ground but of course it's not SPI - it's a two wire mode with DataIn and DataOut on th same pin and not all the chip functions are supported. Since the Silab part has proper SPI why not use it ? Michael Kellett
On Mar 5, 4:41=A0pm, kishor <kiis...@gmail.com> wrote:
> Hi friends, > I am working on 16 - channel data acquisition project, Silab C8051F310 > + ADS1255 + external multiplexer. > > ADC crystal is 7.643 MHz. > SPI clock freq is 1.58 MHz > > Hardware interface- > =A0 =A0 =A0 =A0 CS --> =A0permanently tied to ground > =A0 =A0 =A0 =A0 3 wire SPI (SCK, MOSI, MISO) > =A0 =A0 =A0 =A0 DRDY as external interrupt source > > When I debug the code by step by step it works most of the time. > But in normal case it does not. > > Whether my command sequence or delay between command is wrong. > Or something else i am missing. > > Source code > > /** > =A0* @brief =A0 =A0 =A0 Write data to ADS1255 registers at specified addr=
ess \a
> lbAddress > =A0* =A0 =A0 =A0 =A0 =A0 =A0 =A0of specified length \a lbLength from poin=
ter \a lpSource.
> =A0* > =A0* @param =A0 =A0 =A0 lbLength - Specifies the number of Bytes to write > =A0* @param =A0 =A0 =A0 lbAddress - Specifies the destination ADS1255 reg=
ister
> address > =A0* @param =A0 =A0 =A0 lpSource - Byte pointer to write data to ADS1255 > =A0* > =A0*/ > void Wr_ADS1255_Reg ( Byte lbLength, Byte lbAddress, Byte * lpSource ) > { > =A0 =A0 =A0 =A0 SELECT_ADS1255(); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 =A0 // Select ADS1255
> > =A0 =A0 =A0 =A0 SPI_Write ( 0x50 | lbAddress ); =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 // Address with Write command
> =A0 =A0 =A0 =A0 SPI_Write ( lbLength - 1 ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 // No of registers to write
> > =A0 =A0 =A0 =A0 do > =A0 =A0 =A0 =A0 { > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 SPI_Write ( *lpSource++ ); =A0 =A0 =A0 =
=A0 =A0 =A0 =A0// Write the data
> =A0 =A0 =A0 =A0 } > =A0 =A0 =A0 =A0 while ( --lbLength ); > > =A0 =A0 =A0 =A0 Wait_Clk ( 16 ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0// Wait for 16 clock
> > } > > /** > =A0* @brief =A0 =A0 =A0 Read data from ADS1255 registers from specified a=
ddress \a
> lbAddress > =A0* =A0 =A0 =A0 =A0 =A0 =A0 =A0of specified length \a lbLength to pointe=
r \a lpDest
> =A0* > =A0* @param =A0 =A0 =A0 lbLength - Specifies the number of Bytes to read > =A0* @param =A0 =A0 =A0 lbAddress - Specifies the address of ADS1255 regi=
ster
> =A0* @param =A0 =A0 =A0 lpDest - Byte pointer to store data from ADS1255 > =A0* > =A0*/ > void Rd_ADS1255_Reg ( Byte lbLength, Byte lbAddress, Byte * lpDest ) > { > =A0 =A0 =A0 =A0 SELECT_ADS1255(); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 // Select ADS1255
> > =A0 =A0 =A0 =A0 SPI_Write ( lbAddress | 0x10 ); =A0 =A0 =A0 =A0 // Write =
Address with read command
> > =A0 =A0 =A0 =A0 SPI_Write ( lbLength - 1 ); =A0 =A0 =A0 =A0 =A0 =A0 // No=
of registers to read
> > =A0 =A0 =A0 =A0 Wait_Clk ( 80 ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0// Wait for 80 clock
> > =A0 =A0 =A0 =A0 do > =A0 =A0 =A0 =A0 { > =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 *lpDest++ =3D SPI_Read(); =A0 =A0 =A0 =A0=
// Read data from ADS1255
> =A0 =A0 =A0 =A0 } > =A0 =A0 =A0 =A0 while ( --lbLength ); > > =A0 =A0 =A0 =A0 Wait_Clk ( 16 ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0// Wait for 16 clock
> > } > > void Init_ADS1255 ( void) > { > > =A0 =A0 =A0 =A0 SELECT_ADS1255(); > > =A0 =A0 =A0 =A0 Send_SPI ( enWAKEUP ); =A0 =A0 =A0 =A0 =A0// Wakeup the A=
ds1255.
> =A0 =A0 =A0 =A0 Wait_Clk ( 48 ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0// Wait for 48 clocks
> > =A0 =A0 =A0 =A0 Send_SPI ( enRESET ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
// Reset the ADS1255.
> =A0 =A0 =A0 =A0 Wait_Clk ( 48 ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0// Wait for 48 clocks
> > =A0 =A0 =A0 =A0 // Read the registers to verify the communication > =A0 =A0 =A0 =A0 Rd_ADS1255_Reg ( sizeof ( stRdReg ), 0, ( Byte * ) &stRdR=
eg );
> > =A0 =A0 =A0 =A0 stWrReg.Status =A0=3D 0x04; =A0 =A0 =A0 =A0 // Auto calib=
ration is enabled
> =A0 =A0 =A0 =A0 stWrReg.MUX =A0 =A0 =A0 =A0 =A0 =A0 =3D 0x08; =A0 =A0 =A0=
=A0 // Single ended channel 0
> =A0 =A0 =A0 =A0 stWrReg.ADCON =A0 =A0 =A0 =A0 =A0 =3D 0; > =A0 =A0 =A0 =A0 stWrReg.IO =A0 =A0 =A0 =A0 =A0 =A0 =A0=3D 0xE0; =A0 =A0 =
=A0 =A0 // IO register
> =A0 =A0 =A0 =A0 stWrReg.DRate =A0 =A0 =A0 =A0 =A0 =3D 0xF0; =A0 =A0 =A0 =
=A0 // 30K SPS
> > =A0 =A0 =A0 =A0 Wr_ADS1255_Reg ( 5, 0, ( Byte * ) &stWrReg ); > > =A0 =A0 =A0 =A0 SPI_Write ( enSYNC ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0=
=A0 =A0 =A0 =A0 // Syncronize the ADC
> > =A0 =A0 =A0 =A0 SPI_Write ( enWAKEUP ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 /=
/ Wakeup the Adc
> > =A0 =A0 =A0 =A0 Rd_ADS1255_Reg ( sizeof ( stRdReg ), 0, ( Byte * ) &stRdR=
eg );
> > =A0 =A0 =A0 =A0 SPI_Write ( enSELFCAL ); =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0/=
/ perform Self calibration
> > > > }- Hide quoted text - > > - Show quoted text -
Since it works while you go in slowly, it should be a delay factor that is affecting the operation. Just as other pointed out, it would be better if you are clear of the operation from the datasheet. BR, Karthik Balaguru
"MK" <mk@nospam.please> wrote in message 
news:T7CdnQSTcKTE8A_WnZ2dnUVZ7qudnZ2d@bt.com...
> > "Hans-Bernhard Br&#4294967295;ker" <HBBroeker@t-online.de> wrote in message > news:hmrmg1$qbh$00$1@news.t-online.com... >> kishor wrote: >>> Hi friends, >>> I am working on 16 - channel data acquisition project, Silab C8051F310 >>> + ADS1255 + external multiplexer. >>> >>> ADC crystal is 7.643 MHz. >>> SPI clock freq is 1.58 MHz >>> >>> Hardware interface- >>> CS --> permanently tied to ground >> >> That's _wrong_. SPI uses edges of the CS line to signal the beginning of >> a transaction. It can't work without it. >> > > The OP needs to re-visit the data sheet. TI do offer a mode of operation > for this part with CS tied to ground but of course it's not SPI - it's a > two wire mode with DataIn and DataOut on th same pin and not all the chip > functions are supported. > > Since the Silab part has proper SPI why not use it ? > > Michael Kellett >
I would just mention I had trouble using the 'F064 SPI in 4 wire master mode using NSSMD0, but all worked well using three wire mode and another port pin for CS.
Hi friends,

As all of u mentioned, I concentrated on "timing issues".
I set the delay of 500 micro-seconds before "Read register command".

This works, I got the valid readings.

But still this is strange......, cause according to data sheet delay
should be 4 micro-seconds.

As the initialization is performed in once only (at starting),
It will not affect my ADC data scanning rate.

all other commands are working properly.

Thanks & regards,
Kishore.
Hello, Kishore.

On Sun, 7 Mar 2010 22:43:07 -0800 (PST), kishor <kiishor@gmail.com> wrote:
> Hi friends, > > As all of u mentioned, I concentrated on "timing issues". I set > the delay of 500 micro-seconds before "Read register command".
That's a _long_ time, even in "microcontroller years". <grin> But "working" is always better than "non-working".
> This works, I got the valid readings.
Always a desirable outcome.
> But still this is strange......, cause according to data sheet > delay should be 4 micro-seconds.
This sounded very fast for a complex chip startup, so I checked The Datasheet. Under POWER-UP we see this: "... A self-calibration is then performed automatically. For best performance, it is strongly recommended to perform an additional self-calibrarion by issuing the SELFCAL command after the power supplies and voltage reference have had time to settle to their final value." Then, under SELFCAL: "/DRDY goes high at the beginning of the calibration. It goes low after the calibration completes and settled data is ready. Do not send additional commands after issuing this command until /DRDY goes low indicating that the calibration is complete." It is not clear whether the "automatic" calibration is exactly the same as SELFCAL, but it should raise a red (warning) flag as you read it, especially when you noice from Table 21 that SELFCAL takes 600usec-1227msec to complete. That's 1227000usec; we're talking microcontroller _centuries_ here. <grin> It's also not stated in the datasheet (or I missed it) whether /DRDY can be used to check whether the _automatic_ RESET/power-up self-calibration has completed, but if I were writing the code I'd give it a try. Using fixed timing to work around an unknown problem would make me uncomfortable; your 500usec seems marginal (per Table 21); timings can change, and changing them is one of "Murphy's" favorite pastimes. <grin>
> As the initialization is performed in once only (at starting), It > will not affect my ADC data scanning rate. > > all other commands are working properly.
Good signs. Best of luck. Frank -- Of all tyrannies, a tyranny sincerely exercised for the good of its victims may be the most oppressive. It may be better to live under robber barons than under omnipotent moral busybodies. The robber baron's cruelty may sometimes sleep, his cupidity may at some point be satiated: but those who torment us for our own good will torment us without end, for they do so with the approval of their own conscience. -- C. S. Lewis -- Frank McKenney, McKenney Associates Richmond, Virginia / (804) 320-4887 Munged E-mail: frank uscore mckenney ayut mined spring dawt cahm (y'all)
Hi Frank,

> > =A0 =A0"... =A0A self-calibration is then performed automatically. =A0For > =A0 =A0 best performance, it is strongly recommended to perform an > =A0 =A0 additional self-calibrarion by issuing the SELFCAL command after > =A0 =A0 the power supplies and voltage reference have had time to settle > =A0 =A0 to their final value." > > Then, under SELFCAL: > > =A0 =A0"/DRDY goes high at the beginning of the calibration. =A0It goes > =A0 =A0 low after the calibration completes and settled data is ready. > =A0 =A0 Do not send additional commands after issuing this command until > =A0 =A0 /DRDY goes low indicating that the calibration is complete." > > It is not clear whether the "automatic" calibration is exactly the > same as SELFCAL, but it should raise a red (warning) flag as you > read it, especially when you noice from Table 21 that SELFCAL takes > 600usec-1227msec to complete. =A0That's 1227000usec; we're talking > microcontroller _centuries_ here. =A0<grin> > > It's also not stated in the datasheet (or I missed it) whether /DRDY > can be used to check whether the _automatic_ RESET/power-up > self-calibration has completed, but if I were writing the code I'd > give it a try. =A0Using fixed timing to work around an unknown problem > would make me uncomfortable; your 500usec seems marginal (per Table > 21); timings can change, and changing them is one of "Murphy's" > favorite pastimes. =A0<grin> >
Thanks, you pointed out very important thing. Now Instead of blind "500 micro-seconds" delay I am monitoring DRDY line, after "RESET" & "Write reg" command. This approach will make my code more "Reliable" & "Predictable". Thanks & regards, Kishore.

The 2024 Embedded Online Conference