AD7685 Reading data problem - Page 1
Forum section: electronics / general

author: maxbelyx
author_rank: Newbie
timestamp: September 13, 2019, 12:15:40 pm
content: Good afternoon, dear users.I have a problem reading the AD7685 ADC chip. I am trying to connect this chip to the STM32F411 microcontroller installed on the Nucleo board.The ADC chip is powered by a 5V reference source, REF, Vio, and SDI pins are also connected to 5V.I chose CS 3 wire mode, without a busy indicator and use SPI1 on the microcontroller. The microcontroller operates at 100 MHz, SPI operates at a speed of 1.5625 Mbps (prescaler 64).I generate a pulse on a CNV pin with a duration of 2.625 μs (as I understand it, the duration of this pulse should be more than 2.2 μs with a 5V power supply). After that, I start the function of reading SPI 2 bytes of data, and then I calculate the voltage according to the formula. But for some reason, I get incorrect and unstable data. Data on the ADC comes through the ADA4841 driver, which is enabled in the buffer repeater mode.I apply a constant voltage of 1V to the driver input and get a value of approximately 30,000 (i.e. approximately 2.390V) through SPI.The important thing is that I see that when the input voltage value changes, the value obtained through the SPI changes. When the input is already 1.77V, I get 0V, when the input 2V I get already 900mV, and gradually increasing to 3V, I again run into the limit and get 0. Increasing the input voltage again, I again see an increase in the output of the ADC.Tell me please, what could be my problem?I attached images from the logical analyzer, and the SPI settings.Code:uint16_t AD7980_Conversion(void) {uint16_t receivedData = 0;// CNV HIGHGPIOA->ODR |= GPIO_PIN_8;for(uint8_t i=0;i<50;i++);// CNV LOWGPIOA->ODR &= ~GPIO_PIN_8;HAL_SPI_Receive(&hspi1, (uint8_t*)&receivedData, 1, 0x100);return(receivedData);}Thanks in advance!

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 13, 2019, 01:56:11 pm
content: Quote from: maxbelyx on September 13, 2019, 12:15:40 pmStart with using proper voltage for Vio. Why connect it to 5V? The STM32F411 on the Nucleo is powered at 3.3V. Sure many of its IOs are 5V-tolerant (still would have to check whether the IOs you used for SPI are), but I don't see the point: the AD7685 has a Vio pin for "free" level shifting. Use it! Connect Vio and SDI to the Nucleo's 3.3V power rail. That's your logic interface.What's the potential problem with what you did if the MCU's IOs are 5V-tolerant? Well, the SDO signal (ADC -> MCU) should be properly interpreted by the MCU. But the other direction (MCU -> ADC, ie. SCK and CNV signals)? Not so much. The VIH min for digital inputs of this ADC is 0.7xVio. With what you did (Vio = 5V), that's 3.5V. The digital outputs of the MCU will have a HI level below this threshold. Hence, you're out of spec here.

author: maxbelyx
author_rank: Newbie
timestamp: September 14, 2019, 08:07:17 am
content: Good morning, thank you very much for the answer!Indeed, it is correct to use Vio equal to 3.3V, as in STM32, but I thought that the power from the Nucleo board would be noisy and would affect the ADC, so I thought that 3.3V would be enough for the logic level of the ADC chip.In any case, I changed this, connected the SDI and Vio pins to 3.3V, but nothing changed.I also changed the SPI settings to CPOL = CPHA = 0, the results that I get from the ADC have changed, but they are still extremely incorrect and do not change smoothly (I connected a trimming multi-turn resistor to the IN + input and operate between 0V and 5V).It seems to me that somehow I am fundamentally reading data incorrectly. Any ideas? (also I attached my scheme, maybe it can help)Thanks in advance for your reply,Sincerely.

author: SiliconWizard
author_rank: Super Contributor
timestamp: September 14, 2019, 03:43:59 pm
content: Two things:- I think the correct SPI mode for this ADC should be: CPOL = 0, CPHA = 1.- From the small code snippet you posted, you are using an empty loop to generate a small delay:Code:for(uint8_t i=0;i<50;i++);this is not a correct way of implementing delays. This kind of empty loops do not only yield inaccurate delays, of course depending on the cpu clock and how the compiler compiles it, but have a high probability of getting optimized out by the compiler altogether, because they do nothing, leaving you with NO delay at all.To make sure an empty loop would not get optimized out, you can modify your delay loops like so:Code:for(uint8_t i=0;i<50;i++) __asm volatile ("nop");(The max tCOnv in the ADC datasheet is 2.2µs, so you need to wait for at least as long as that, but you probably got that already.)I don't think STM32's HAL has functions for µs delays (HAL_Delay() is by default in ms), but I've implemented this small routine that works well independently of the system clock frequency:Code:void DWT_Init(void){if (! (CoreDebug->DEMCR & CoreDebug_DEMCR_TRCENA_Msk))CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;DWT->CYCCNT = 0;DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;}void Delay_us(uint32_t nDelay_us){uint32_t nStart = DWT->CYCCNT;nDelay_us *= (HAL_RCC_GetHCLKFreq() / 1000000);while ((DWT->CYCCNT - nStart) < nDelay_us) ;}DWT_Init() should be called only once (for instance at the init. of your program) to be able to use the Delay_us() function.There is a very small overhead in the Delay_us() function, so depending on your system clock, the low values in µs may yield a slightly longer delay, but that's usually more than good enough for this kind of uses. But at 100MHz, the overhead is completely negligible.One thing to note as well is that it will work only for system clocks >= 1MHz and with integer frequencies in MHz (due to the HAL_RCC_GetHCLKFreq() / 1000000 ). Obviously for system clocks < 1MHz, it's absolutely impossible to get delays with 1µs resolution anyway, so this function can be adjusted appropriately depending on your needs for lower frequencies.

author: maxbelyx
author_rank: Newbie
timestamp: September 15, 2019, 08:31:24 am
content: Good afternoon! Thanks for the answer,Yes, I know, of course, that using this kind of delay is stupid, but I just wanted to check the operation with the ADC. And besides, I always control everything through an oscilloscope and logic analyzer.In any case - I changed the delay to "correct" (I set 2.5us) and changed the SPI settings (CPOL=0, CPHA = 1). I got this picture this time. As you can see, it still does not display correctly, at the input of 1 volt.I have a suspicion that SPI reading starts too late after the CNV impulse. Could this be a problem? I mean, did I understand correctly that the ADC chip after the CNV pulse "waits" for the 16 cycles of the CLK from the microcontroller? Or should they be started immediately after a CNV impulse?**UPD**Due to hopelessness, I took Arduino and connected my motherboard with an ADC to it, configured everything exactly the same as on STM32 (but Vio and SDI is connected to 5v) - the result is EXACTLY SAME (although here SPI starts faster after a CNV pulse (heh) than on STM32). I selected all possible SPI modes - the values change, but still, everything is wrong (110mv or 220mV). It seems that I'm still doing something fundamentally wrong. Any ideas?Thanks in advance for your reply,Sincerely.

author: Dave
author_rank: Super Contributor
timestamp: September 15, 2019, 10:24:17 am
content: This might be a kick in the dark, but I've experienced similar problems with a EFM8 microcontroller in a QFN package in the past.The readings would be somewhat correlated to what I was feeding the ADC, but even changing the sample rate would affect the reading.It turned out to be a poorly soldered chip, there was no real connection to the ADC input pin, but a little bit of charge was getting in through the contaminants and giving me weird, unexplainable results.

author: maxbelyx
author_rank: Newbie
timestamp: September 15, 2019, 11:03:09 am
content: Sorry guys, I'm an idiot.Everything, as always, is electrical engineering - the science of contacts. Thanks for all very much, and to you Dave, you pushed me on the right path. I did not connect the "IN-" to the ground, which is why I received incorrect data. I looked at the datasheet and thought that it was connected inside...Thanks again to everyone!Sincerely.

author: Dave
author_rank: Super Contributor
timestamp: September 16, 2019, 09:40:21 am
content: Glad to hear my kick in the dark managed to hit something.

author: nigelwright7557
author_rank: Frequent Contributor
timestamp: September 21, 2019, 12:53:07 am
content: Some of these AD A2D converters do odd things.On my dual channel AD9281 with inputs set to vref/2 I got out 128+16 on one channel and 128+32 on the other !Clearly they should both output 128 ?My vref was good at 1 volt exactly.However the reft and refb were 2.75v and 0,75v which is clearly wrong.They should be 3v and 1v.I alerted AD but had no reply yet as to why ?They have also set /AIN internally to 1/3 of VREF which his pretty useless.For most implementations it should be at half vref.Obviously differential input is another matter.