This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS1256: SPI Communication issue with DSP F28335

Part Number: ADS1256


Hello,

I need some help with some issues when communicating via SPI between DSP F28335 and ADS1256. The ADS1256 was not responding to any command, and MISO always return FF whenever I read register or data. I doubt it that the command sent to ADC was not recognized, so it had no response. Data Ready was connected to a GPIO, when powering up, data ready signal is with 33us period, namely around 2.4 us high, then around 30.6 us low,

The F28335 SPI SCLK is set at 1.25 MHz, with sending out data on rising edge and receiving data on falling edge, no phase delay, idle low.

I have attached the wave form showing SCLK, CS and MOSI. The timing between SCLK, CS and MOSI meets the timing specification shown below. And the consecutive MOSI bytes also meets timing requirements. The MISO was not shown, but in the test, it always stayed high.

The following figure showed when writing a single byte. Blue line -- CS, Yellow line -- SCLK, Purple line -- MOSI.

The following figure shows when writing multiple bytes. Green line -- CS, Purple line -- SCLK, Blue line -- MOSI

I have also attached the configuration code. This is ADC set up.

// adc_spi.c

#include "adc_spi.h"
#include "DSP28x_Project.h"
#include "spi.h"

enum
{

	REG_STATUS = 0x0000,	// x1H
	REG_MUX    = 0x0100, // 01H
	REG_ADCON  = 0x0200, // 20H
	REG_DRATE  = 0x0300, // F0H
	REG_IO     = 0x0400, // E0H
	REG_OFC0   = 0x0500, // xxH
	REG_OFC1   = 0x0600, // xxH
	REG_OFC2   = 0x0700, // xxH
	REG_FSC0   = 0x0800, // xxH
	REG_FSC1   = 0x0900, // xxH
	REG_FSC2   = 0x0A00, // xxH
};


// Command Table

enum
{
	CMD_WAKEUP  = 0x0000,	// Completes SYNC and Exits Standby Mode 0000  0000 (00h)
	CMD_RDATA   = 0x0100, // Read Data 0000  0001 (01h)
	CMD_RDATAC  = 0x0300, // Read Data Continuously 0000   0011 (03h)
	CMD_SDATAC  = 0x0F00, // Stop Read Data Continuously 0000   1111 (0Fh)
	CMD_RREG    = 0x1000, // Read from REG rrr 0001 rrrr (1xh)
	CMD_WREG    = 0x5000, // Write to REG rrr 0101 rrrr (5xh)
	CMD_SELFCAL = 0xF000, // Offset and Gain Self-Calibration 1111    0000 (F0h)
	CMD_SELFOCAL= 0xF100, // Offset Self-Calibration 1111    0001 (F1h)
	CMD_SELFGCAL= 0xF200, // Gain Self-Calibration 1111    0010 (F2h)
	CMD_SYSOCAL = 0xF300, // System Offset Calibration 1111   0011 (F3h)
	CMD_SYSGCAL = 0xF400, // System Gain Calibration 1111    0100 (F4h)
	CMD_SYNC    = 0xFC00, // Synchronize the A/D Conversion 1111   1100 (FCh)
	CMD_STANDBY = 0xFD00, // Begin Standby Mode 1111   1101 (FDh)
	CMD_RESET   = 0xFE00, // Reset to Power-Up Values 1111   1110 (FEh)
	//CMD_WAKEUP  = 0xFF, // Completes SYNC and Exits Standby Mode (FFh)
};

static void bsp_DelayMS(Uint16 nms);
static void bsp_DelayUS(Uint16 nus);

static void ADS1256_WaitDRDY(void);
static void ADS1256_ResetHard(void);
static void ADS1256_DelaySCLK(void);
static void ADS1256_DelayDATA(void);
static void ADS1256_DelayCS(void);
static void ADS1256_DelaySYNC(void);

static void ADS1256_WriteCmd(Uint16 _cmd);
//static void ADS1256_WriteReg(Uint16 _RegID, Uint16 _RegValue);
//static Uint16 ADS1256_ReadReg(Uint16 _RegID);
static Uint32 ADS1256_ReadData(void);
static void ADS1256_SetChannal(Uint16 _ch);
//static void ADS1256_StopScan(void);

ADS1256_VAR_T g_tADS1256;
static const Uint16 s_tabDataRate[ADS1256_DRATE_MAX] =
{
	0xF000,		// 30K SPS 
	0xE000,		// 15K
	0xD000,		// 7.5K
	0xC000,		// 3750
	0xB000,		// 2000
	0xA100,		// 1000
	0x9200,		// 500
	0x8200,		// 100
	0x7200,		// 60
	0x6300,		// 50
	0x5300,		// 30
	0x4300,		// 25
	0x3300,		// 15
	0x2300,		// 10
	0x1300,		// 5
	0x0300		// 2.5
};


void bsp_DelayUS(Uint16 nus)
{
	DELAY_US(nus);
}


void ADS1256_Init(){
    EALLOW;
	
	// CS
	GpioCtrlRegs.GPAMUX1.bit.GPIO6=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO6=0; // Enable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO6=1; // Output 

	//RST
    GpioCtrlRegs.GPAMUX1.bit.GPIO7=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO7=0; // Enable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO7=1; // Output 

	//SYNC
    GpioCtrlRegs.GPAMUX1.bit.GPIO8=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO8=0;  // Enable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO8=1;  // Output 
	
	//DATA READY
	SysCtrlRegs.PCLKCR3.bit.GPIOINENCLK = 1; // GPIO input clock
    GpioCtrlRegs.GPAMUX1.bit.GPIO9=0; // GPIO
    GpioCtrlRegs.GPAPUD.bit.GPIO9=1;  // Disable internal pullup
    GpioCtrlRegs.GPADIR.bit.GPIO9=0;  // Input
	GpioCtrlRegs.GPAQSEL1.bit.GPIO9= 0;
	

	GpioDataRegs.GPASET.bit.GPIO6=1; // Set value
    GpioDataRegs.GPASET.bit.GPIO7=1; // Set value
    GpioDataRegs.GPASET.bit.GPIO8=1; // Set value
	
	
	
	EDIS;
};

// t11 -> min 1/7.68M * 4 = 0.52 us Delay for final SCLK falling edge to first
// rising edge of next command, WREG, RREG, RDATA
// RESET and SYNC must be low for at least 0.52 us to be effective
static void ADS1256_DelaySCLK(void)
{
	bsp_DelayUS(1);
}

// t11 -> min 1/7.68M * 24 = 3.12 us Delay for final SCLK falling edge to first
// rising edge of next command, RDATAC, SYNC

static void ADS1256_DelaySYNC(void)
{
	bsp_DelayUS(5);
}

// t8 -> min 1/7.68M * 8 = 1.04 us Delay for final SCLK falling edge to first
// CS goes high

static void ADS1256_DelayCS(void)
{
	bsp_DelayUS(3);
}

// t6 -> min  50 * 0.13uS = 6.5uS
// Delay from last SCLK edge for DIN to first SCLK rising edge for 
// DOUT: RDATA, RDATAC,RREG Commands

static void ADS1256_DelayDATA(void)
{
	bsp_DelayUS(10);	
}

// SCLK period 37.5 M / 60 = 625K
// 1/625k = 1.6 us

// Data ready time 

static void ADS1256_WaitDRDY(void)
{
	Uint32 i;

	for (i = 0; i < 40000000; i++)
	{
		if (DRDY_IS_LOW())
		{
			break;
		}
	}
}

// Write register

void ADS1256_WriteReg(Uint16 _RegID, Uint16 _RegValue)
{
	ADS1256_WaitDRDY();

	spi_xmit(CMD_WREG | _RegID);	

	DELAY_US(10);
	ADS1256_WaitDRDY();
	spi_xmit(0x0000);	

	DELAY_US(10);
	ADS1256_WaitDRDY();
	spi_xmit(_RegValue);	
	
}

// Send command

static void ADS1256_WriteCmd(Uint16 _cmd)
{

	DELAY_US(10);
	spi_xmit(_cmd);
	DELAY_US(10);

}


void ADS1256_CfgADC(ADS1256_GAIN_E _gain, ADS1256_DRATE_E _drate)
{
	g_tADS1256.Gain = _gain;
	g_tADS1256.DataRate = _drate;

	ADS1256_StopScan();			

	ADS1256_ResetHard();
	
 	ADS1256_WriteCmd(CMD_RESET);
 	DELAY_US(60);
 	ADS1256_WriteCmd(CMD_SDATAC);
 	DELAY_US(60);

	{
		Uint16 buf[4];	
		buf[0] = (((0 << 3) | (1 << 2) | (0 << 1))<<8);
		// write 00000100, MSB, auto-calibration, buffer disable
		buf[1] = 0x0800;
		// output mux 00001000
		buf[2] = (((0 << 5) | (0 << 3) | (_gain << 0))<<8);
		// no clock out, sensor detect off, gain 1
		buf[3] = s_tabDataRate[_drate];

		//ADS1256_DelaySCLK();
		DELAY_US(20);
		spi_xmit(CMD_WREG | 0);

		DELAY_US(20);
		spi_xmit(0x0303);			

		DELAY_US(20);
		spi_xmit(buf[0]);	

		DELAY_US(20);
		spi_xmit(buf[1]);	

		DELAY_US(20);
		spi_xmit(buf[2]);	
        DELAY_US(20);

		spi_xmit(buf[3]);	
		DELAY_US(20);
	}


	DELAY_US(50);
		
	ADS1256_WriteCmd(CMD_SYNC);
	DELAY_US(20);
	ADS1256_WriteCmd(CMD_WAKEUP);
	DELAY_US(800);
	
}		


static void ADS1256_ResetHard(void)
{
	RST(0);
	DELAY_US(10);
	RST(1);
	
	SYNC(0);
	bsp_DelayUS(2);
	DELAY_US(10);
	SYNC(1);
	DELAY_US(800);

	ADS1256_WaitDRDY();	/* Ready time 630us */
}

Uint16 ADS1256_ReadReg(Uint16 _RegID)
{
	Uint16 read;
	read = 0;
	ADS1256_WaitDRDY();

	DELAY_US(20);
	spi_xmit(CMD_RREG | _RegID);	 
	DELAY_US(20);
	spi_xmit(0x0000);	

	DELAY_US(20);
	spi_xmit(0xEEEE);

	read = SpiaRegs.SPIRXBUF;

	DELAY_US(10);

	
	return read;
}

Uint16 ADS1256_ReadChipID(void)
{
	Uint16 id;
	
	id = ADS1256_ReadReg(REG_STATUS);

	return (id >> 4);
}

This is SPI set up.

#include "spi.h"
#include "SCI.h"
#include "adc.h"

//SPI send out data
void spi_xmit(Uint16 a){
	SpiaRegs.SPISTS.bit.INT_FLAG = 1;
    SpiaRegs.SPITXBUF = a;
    while(!SpiaRegs.SPISTS.bit.INT_FLAG){}
    //DELAY_US(20);
}

void spi_init(){
    // Initialize spigpio:16--SIMO, 17--SOMI, 18--CLK, 19--STEA
	
    EALLOW;
    
    GpioCtrlRegs.GPAPUD.bit.GPIO16 = 0;   //Enable pull-up on GPIO16 (SPISIMOA)
    GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0;   //Enable pull-up on GPIO17 (SPISOMIA)
    GpioCtrlRegs.GPAPUD.bit.GPIO18 = 0;   //Enable pull-up on GPIO18 (SPICLKA)
    GpioCtrlRegs.GPAPUD.bit.GPIO19 = 0;   //Enable pull-up on GPIO19 (SPISTEA)

    //
    // Set qualification for selected pins to asynch only
    // This will select asynch (no qualification) for the selected pins.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAQSEL2.bit.GPIO16 = 3; // Asynch input GPIO16 (SPISIMOA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch input GPIO17 (SPISOMIA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO18 = 3; // Asynch input GPIO18 (SPICLKA)
    GpioCtrlRegs.GPAQSEL2.bit.GPIO19 = 3; // Asynch input GPIO19 (SPISTEA)

    //
    // Configure SPI-A pins using GPIO regs
    // This specifies which of the possible GPIO pins will be SPI 
    // functional pins.
    // Comment out other unwanted lines.
    //
    GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 1; // Configure GPIO16 as SPISIMOA
    GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 1; // Configure GPIO17 as SPISOMIA
    GpioCtrlRegs.GPAMUX2.bit.GPIO18 = 1; // Configure GPIO18 as SPICLKA
    GpioCtrlRegs.GPAMUX2.bit.GPIO19 = 1; // Configure GPIO19 as SPISTEA

    EDIS;
	
   
	SpiaRegs.SPICCR.all = 0x0008;  // Reset SPI, send out on rising edge, receive on falling edge, 8 bit
 
    SpiaRegs.SPICTL.all = 0x0006;   //no phase delay master mode

    SpiaRegs.SPIBRR = 0x001D;   // SPICLK(SPICLK 37.5M/(29+1))

    SpiaRegs.SPIPRI.bit.FREE = 1;   // Free run
    //SPI FIFO
    SpiaRegs.SPIFFTX.all = 0xE040;  //enable SPI TX interrupt

	SpiaRegs.SPICCR.all= 0x0088; // Renable SPI

}

interrupt void spi_rx_isr(void){

    SpiaRegs.SPIFFRX.bit.RXFFINTCLR = 1; //Clear inerrupt
    PieCtrlRegs.PIEACK.bit.ACK6 = 1; //
}

interrupt void spi_tx_isr(void){
    SpiaRegs.SPIFFTX.bit.TXFFINTCLR = 1; // Clear interrupt
    PieCtrlRegs.PIEACK.bit.ACK6 = 1; //
}

Look forward for your help.

Thanks

Chad

  • Hi Chad,

    Do you have a schematic to share?

    The DRDY signal is a good sign since this appears to be toggling at the default data rate (30kSPS). This means the ADC is working in some capacity.

    Are you toggling CS between bytes? The first image you show has CS going low at the beginning of the byte and CS going high at the end. The command you are sending appears to be 0101 0011, which is a WREG beginning at register 3 (DRATE). However, pulling CS high after this byte resets the SPI interface, so the command never gets executed. I cannot really tell what us going on in the second image with all of the different signals, but CS appears to go high after each byte. This is acceptable for some commands, but not for RREG and WREG.

    You will also need to keep CS low when clocking out data (sending the RDATA command, wait time t6, then issue 24 SCLKs).

    Let me know if changing any of this behavior improves your results.

    -Bryan

  • Hi, Bryan:

    Thank you very much for your prompt response. This helps me a lot, and I will give a try.

    I am using an ADS1256 module off-the-shelf, so I don't have a schematics to show here. I am using a DSP F28335 as the SPI master, and ADS1256 is interfacing with original 28335 SPI interface. F28335 SPI CS is connected to ADC's CS, and F28335 is sending out 8 bit each time, so that's why CS was pulled low first and then pulled high. I guess I need to use a GPIO to act as the CS line.

    Besides, I do have two follow up questions.

    1. What is the timing interval requirements between the consecutive bytes for the WREG and RREG command? Is it t11 (1/CLKIN * 4)? For instance, the interval between "0001 rrrr" and "0000 nnnn"?

    2. When sending out WREG and RREG command, do I need to wait for Data Ready to go low first?

    Thanks

    Chad

  • Hi Chad,

    If you have two separate boards, make sure that there is a strong, solid ground connection between them. Any variation in the ground potentials in the two boards can lead to noise and undefined communication behavior.

    To answer your questions:

    1. There is no timing delay required between bytes when sending a WREG or RREG command. This is stated in the Command Definition section on page 34 in the ADS1256 datasheet
    2. WREG and RREG can be issued at any time, you do not need to wait until DRDY goes low. However, keep in mind that if you change the ADC settings you should restart the conversion process, as the conversion in progress may get corrupted by the change in settings.
  • Hi, Bryan:

    Now I use a GPIO as the CS line, it stays low during the entire period when I send out command bytes. When I read registers, it returned values as "00". Do you have any suggestions for this issue?

    Besides, I doubt if it will be harmful for inserting some delay between consecutive bytes when sending out WREG or RREG. Since F28335 data is 16 bit width, I noticed that sometimes when I sent out consecutive bytes without delay, some SCLK waveform will collapse.

    Thanks

    Chad 

  • Hi Chad,

    Do you have a strong ground connection between the two (or more?) boards? Since the SCLK signal is driven by the MCU, I don't know why it would be collapsing unless there is some sort of noise or voltage difference present. In other words, this would not be an issue with the ADC.

    Also, how are the RESET and PWDN pins controlled on your board? Are they left floating, are they controlled by the MCU, or are they tied to DVDD?

    -Bryan

  • Hi, Bryan:

    I revised my code, and made some progress today. Now the ADC was able to receive single byte command, and respond to RREG command. However, I still have some other issues. 

    First, the ADC was not able to respond to WREG command. As shown in the following waveform, I was trying to send out WREG command. Since I am using DSP F28335, which only supports 16 bits width data. The command bytes were placed on the higher two bytes. 

    5000 // write from address 0x00

    0300 // write four bytes

    0400 // address 0x00 write 04

    0800 // address 0x01 write 08

    0000 // address 0x02 write 00

    D000 // address 0x03 write D0, 7500 SPS

    However, the WREG command was not successful. After performing the WREG command, the data ready period is still around 33 us (1/30K). Besides, when I read register 0x00, it returned "81", which should be "85" if WREG successful,  

    Yellow -- CS, Blue -- SCLK, Purple -- MOSI, Green -- Data ready

    The following figure showed the details of the figure above.

    Second, after I send out SDATAC command, would it be normal for the Data Ready still comes at the period of 33 us (30K SPS)?

    Third, when I read the register 0x00, it constantly returned DD81.Since I was using DSP F28335, which only supports 16 bits width data, the returned value showed on the lower two bytes, and it was normal. However, when I read register 0x03, the returned value jumped among the following values:

    DC07

    DD87

    DC07

    DC2F

    I sent out the RREG command as

    1300

    0000

    EEEE

    Here is the waveform.

    Last, when I performed a single channel read. The returned value jumped among 0, 1024 and 65535. 

    Look forward to hearing from you,

    Thanks

    Chad

  • Hi Chad,

    I still have not received answers to the question in my last post:

    1. Do you have a strong ground connection between the two (or more?) boards? Since the SCLK signal is driven by the MCU, I don't know why it would be collapsing unless there is some sort of noise or voltage difference present. In other words, this would not be an issue with the ADC.
    2. How are the RESET and PWDN pins controlled on your board? Are they left floating, are they controlled by GPIOs from the MCU, or are they tied to DVDD?

    Also, it is hard to tell in the images you sent, but it looks like there are 9 SCLKs issued in each frame instead of 8. This means you are clocking in/out one extra bit each time, which will not be read correctly by the ADC.

    -Bryan

  • Hi, Bryan:

    Sorry for my late response. 

    1. The MCU and ADC are connected via dupont wire, and they do have a strong ground connection.

    2. The RESET and PWDN pins are connected to MCU GPIO, and they are pulled high.

    The following image shows a detailed waveform when MCU sends out 8 bits. There are actually 8.5 SCLK period, and MCU is sending out 8 dummy bits (EE) to ready 8 bits of data. Is this the correct wave form?

    As before, Yellow line -- CS, Blue line -- SCLK, Purple line - MOSI, Green line -- MISO

    Look forward to hearing from you.

    Thanks

    Chad

  • Hi, Bryan:

    Actually, this post has solved my problem. I checked my SPI setup, and realized that my SPI data width was actually set up as 9 bit, and that's why I saw eight and half clocks in the waveform. After I corrected this mistake, everything worked.

    Besides, by referring to SCLK collapsed, I meant the following waveform. I was trying to write register 0x00, and my command was:

    0500

    0000

    8400

    Without inserting some delays when sending out these three bytes, the middle byte somehow disappeared. This issue was resolved by inserting some delays between consecutive bytes.

    All in all, thank you very much for your help.

    Chad

  • Hi Chad,

    Glad we could help!

    -Bryan