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.

ADS8638: having issues with reading adc values and configuration

Part Number: ADS8638


hi guys i am having issues with reading from this chip. something is missing. i am sharing my code below. would anyone be able to help and share his code with me. many thanks.

#define ADC_TI_CHANNELS 8 // total number of channels on each ADS8638 ADC
#define MAX_NUMBER_ADC_TI_CHIPS 5 // total number of ADS8638 ADCs

#define ADS8638_INTERNAL_VREF_ON 0xC
#define ADS8638_REG_AUX_CONFIG   0x06
#define ADS8638_REG_MANUAL       0x04
// Reset the corresponding chip select pin on an LTC DAC
// TiAdcChips will hold value and range for each of its channels
struct TiAdcInfo
{
	uint16_t ADC_TI_VALUE[ADC_TI_CHANNELS]; // this holds all DAC values
	uint16_t ADC_TI_RANGE[ADC_TI_CHANNELS]; // this hold all DAC ranges (voltage spans), range can only be changed on the DAC chip, on STM32F7 its always 0-2.5V

};

// initialize all DAC step sizes to zero
// create multiple LTC chips
struct TiAdcInfo TiAdcChips[MAX_NUMBER_ADC_TI_CHIPS];


// this set command can be used to form commands for all those in the cmdCodeDataList above except the commented ones.
char* adc_setCmdGeneric(uint8_t adcNumber, uint8_t channelNumber, uint16_t commandWord)
{
//	ADC_TI_VALUE[channelNumber % ADC_TI_CHANNELS] = value;
	if(adcNumber >= MAX_NUMBER_ADC_TI_CHIPS)return "BAD DAC NUMBER";


//	adc_SPI_Transmit(adcNumber, channelNumber, commandWord);

	return "Ok\n";
}

char* adc_setChannelandRange(uint8_t adcNumber,uint8_t channelNumber, uint8_t range, uint8_t tempretureSelector)
{
	// for the LSB of the command
	uint8_t cmdWord_LSB = 0;
	cmdWord_LSB = (channelNumber << 4) | (range << 1) | tempretureSelector;

	if(adcNumber >= MAX_NUMBER_ADC_TI_CHIPS)return "BAD DAC NUMBER";
	// code for this command
	uint8_t  cmdWord_MSB = ADS8638_REG_MANUAL;

	// form a command and send it
	adc_SPI_Transmit(adcNumber, channelNumber, ADS8638_INTERNAL_VREF_ON, ADS8638_REG_AUX_CONFIG);

	adc_SPI_Transmit(adcNumber, channelNumber, cmdWord_LSB, cmdWord_MSB);

//	adc_setCmdGeneric(adcNumber, commandWord);


    // update ADC range
	TiAdcChips[adcNumber].ADC_TI_RANGE[channelNumber % ADC_TI_CHANNELS] = range;

	return "Ok\n";
}

int adc_getChannel(uint8_t adcNumber,uint8_t channelNumber)
{
	return TiAdcChips[adcNumber].ADC_TI_VALUE[channelNumber % ADC_TI_CHANNELS];
}
// Set the corresponding chip select pin on an ADC
char* adc_nCs_set(uint8_t adcNumber, int value)
{

	GPIO_PinState PinState;

    if(adcNumber > MAX_NUMBER_ADC_TI_CHIPS)return "BAD INDEX";
	if(value != 0 && value != 1) return "Value Must Be Binary";

	switch(value)
	{
	case 0:PinState = GPIO_PIN_RESET;break;
	case 1:PinState = GPIO_PIN_SET;break;
	}
	// add more cases for as many DACS on the board
	switch(adcNumber)
	{
	case 0:HAL_GPIO_WritePin(GPIOG, nCS_ADC0_Pin, PinState);break;
	case 1:HAL_GPIO_WritePin(GPIOG, nCS_ADC1_Pin, PinState);break;
	case 2:HAL_GPIO_WritePin(GPIOG, nCS_ADC2_Pin, PinState);break;
	case 3:HAL_GPIO_WritePin(GPIOG, nCS_ADC3_Pin, PinState);break;
	case 4:HAL_GPIO_WritePin(GPIOG, nCS_ADC4_Pin, PinState);break;
	default:break;
	}

	return "Ok\n";
}

// power up and down an ADC chip
char* adc_powerUp(uint8_t adcNumber, int value)
{
	GPIO_PinState PinState;

    if(adcNumber > MAX_NUMBER_ADC_TI_CHIPS)return "BAD INDEX";
	if(value != 0 && value != 1) return "Value Must Be Binary";

	switch(value)
	{
	case 0:PinState = GPIO_PIN_RESET;break;
	case 1:PinState = GPIO_PIN_SET;break;
	}
	// add more cases for as many DACS on the board
	switch(adcNumber)
	{
	case 0:HAL_GPIO_WritePin(GPIOG, ADC_EN_Pin, PinState);break;
	case 1:HAL_GPIO_WritePin(GPIOG, ADC_EN_Pin, PinState);break;
	case 2:HAL_GPIO_WritePin(GPIOG, ADC_EN_Pin, PinState);break;
	case 3:HAL_GPIO_WritePin(GPIOG, ADC_EN_Pin, PinState);break;
	case 4:HAL_GPIO_WritePin(GPIOG, ADC_EN_Pin, PinState);break;
	default:break;
	}

	return "Ok\n";
}

// transmit on SPI to the selected chip
char* adc_SPI_Transmit(uint8_t adcNumber, uint8_t channelNumber, uint8_t cmdLSB, uint8_t cmdMSB)
{
	 // Four bytes Array the holds the 32 bit command for the DAC
      uint8_t data_array[2]={0};

  	if(adcNumber >= MAX_NUMBER_ADC_TI_CHIPS)return "BAD DAC NUMBER";

  	// power up the chip
  	adc_powerUp(adcNumber,1);


	// pull the corresponding chip select pin nCS to low to start transmission on the selected DAC
    // and then pull low to execute the command
  	// reset nCs on all chips
  	for(int ii = 0;ii<MAX_NUMBER_ADC_TI_CHIPS; ii++)adc_nCs_set(ii,1);
  	adc_nCs_set(adcNumber,0);


////
//		  data_array[0] = cmdMSB << 1;        // Only required for 32 byte readback transaction
//		  data_array[1] = cmdLSB;             // Build command / address byte
		  cmdMSB = cmdMSB << 1;

		  data_array[0] = cmdMSB;                    // MS Byte
		  data_array[1] = cmdLSB;

		// Send the bytes command to the ADC

//		HAL_SPI_Transmit_DMA(&hspi6,&data_array,2);
//			HAL_SPI_Transmit(&hspi6,&cmdMSB,1,1);
//			HAL_SPI_Transmit(&hspi6,&cmdLSB,1,1);
			HAL_SPI_Transmit(&hspi6,&data_array,2,50);
//			HAL_SPI_Transmit_DMA(&hspi6,&cmdLSB,1);
		// Use below for blocking transmission
		// HAL_SPI_Transmit(&hspi4,&data_array,4,10);

//HAL_Delay(10);
		// pull the corresponding chip select pin nCS to high to execute command on the selected DAC
		adc_nCs_set(adcNumber,1);
//		adc_nCs_set(adcNumber,0);
//		adc_nCs_set(adcNumber,1);
//		adc_nCs_set(adcNumber,0);

		// the chip waits 32 clock cycles before it responds back and echo the same command
		// TODO: add a delay here before we call the receive
		if(cmdMSB == 0x8)adc_SPI_receive(adcNumber,channelNumber);


      	return "Ok\n";
}

// transmit on SPI to the selected chip
char* adc_SPI_receive(uint8_t adcNumber, uint8_t channelNumber)
{
	 // Four bytes Array the holds the 32 bit command for the DAC
      uint8_t data_array[2]={0};
      volatile uint16_t adc_readValue = 0;
      uint8_t b0, b1;

  	if(adcNumber >= MAX_NUMBER_ADC_TI_CHIPS)return "BAD DAC NUMBER";

	    adc_nCs_set(adcNumber,0);
	   HAL_SPI_Receive(&hspi6,&b0,1,0);
	   HAL_SPI_Receive(&hspi6,&b1,1,0);
		adc_nCs_set(adcNumber,1);

	    adc_nCs_set(adcNumber,0);
	   HAL_SPI_Receive(&hspi6,&b0,1,0);
	   HAL_SPI_Receive(&hspi6,&b1,1,0);
		adc_nCs_set(adcNumber,1);

//	    adc_nCs_set(adcNumber,0);
//		HAL_SPI_Receive(&hspi6,&data_array,2,10);
//		adc_nCs_set(adcNumber,1);


	    // update ADC value
		adc_readValue = b0 & 0xF;
		adc_readValue = adc_readValue << 8;
		adc_readValue = adc_readValue | b1;

//		adc_readValue1 = data_array[1] & 0x0F;
//		adc_readValue = adc_readValue1 << 8 ;
//		adc_readValue = adc_readValue + data_array[0];

		TiAdcChips[adcNumber].ADC_TI_VALUE[channelNumber % ADC_TI_CHANNELS] = adc_readValue;

      	return "Ok\n";
}

//// if interrupt on reception complete is enabled, the HAL_UART_RxCpltCallback will be called example is shown below
//void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi){
//
//	if (hspi->Instance == SPI6)
//	{
//
//	}
//}

  • Hello Esam,
    Could you provide more detail as to what you are inputting and receiving as an output?
    Also could you provide a scope shot of your digital communications lines: SDI, SCLK, SDO, CS?

    -Cynthia
  • Hi Cynthia,



    Thanks for your reply. I managed to get sensible readings now, which i will mention shortly, but still have a problem. As per the datasheet on page 40, the reading of a conversion is available at n+2. However, that did not work for me!!, what worked is reading from frame n+1. Not only this, in order to use the internal reference as per your datasheet a cap has to be placed between refgnd and reference. That also was giving inaccurate readings until I connected the cap to the analogue ground on my board through a 10 ohm resistor!

    I am confused now. So far I am reading one channel at a time, but when i start switching manually between channels which frame shall i read from?.
  • Another bug I found is with channel 7. I can set the range on all channels but if i set it on channel 7 it does not work and resets the range on channel 6!. not sure whats wrong
  • Esam,

    It sounds like you are having timing issues, a scope shout would really help to debug. what is the SCLK frequency you are using?
    Each frame begins when a falling edge CS occurse.The digital communications depend on SCLK. The 16 bit output data start off with 4 bit channel address, the last 12 its are the converstion result, MSB first, each when a falling edge of SCLK. The output is delivered at the same time as the digital input communications, although DIN is read in the rising edge of SCLK. Figure 84 below shows that changing in frames, and when valid data is available, as well as when digital input commincations are read.  Figure 85 in the datasheet will also be helpful.

    -Cynthia