Interfacing TI ADS9224R ADC with STM32H7 MCU

October 30, 2024 — Written by Haris Turkmanovic

Share this article

#stm32h7#adc#noise#ads9224r
Interfacing TI ADS9224R ADC with STM32H7 MCU

As you may be aware, the first version of the hardware prototype for OpenEPT is currently undergoing testing, with a primary focus on evaluating the signal quality of the internal ADC in the selected STM32H7 MCU. Unfortunately, the test results revealed significant noise levels from the internal ADC that cannot be ignored. Filtering this noise through software would require considerable performance overhead, making it impractical. As a result, we decided to switch to the external ADS9224R ADC [1], which meets the project's original requirements. Testing has demonstrated that the ADS9224R offers a significant improvement in noise performance over the internal ADC. In this blog, we will delve into these findings and outline the integration process for connecting the ADS9224R with the STM32. Since there is no example source code available to illustrate the program flow required to establish communication between the ADS9224R and an MCU-based platform, we have documented our approach for connecting the ADS9224R with the STM32 and are sharing our experience with the community, which we believe will be valuable for other designers.

Although the external ADC is now being used, the internal ADC has not been discarded. The current software integrates both ADCs, utilizing each for specific tasks to optimize overall system performance.

Why do we decide to use an external ADC and select the ADS9224R?

At the start of this project, the key reasons for choosing the STM32 were its dual CPU cores (with the CM4 core planned for future upgrades) and, most importantly, its high-speed ADC converters, a crucial feature for our hardware. However, after developing the initial hardware prototype, the first test results revealed substantial noise (several hundred MSB) on the ADC inputs. When applying a DC voltage of 1V to the ADC input, the samples collected over a 60-second interval are shown in Figure 1, and the main signal characteristics are summarized in Table 1.

Internal ADC TimeFigure 1. 1V DC voltage acquired by Internal ADC over a 60-second interval

Table 1. Characteristics of 1V DC voltage acquired by internal ADC

Table 1As shown in Figure 1, a voltage deviation of 0.1V, representing a 10% variance for battery-powered applications (where single-cell LiPo battery voltage ranges from 3.2 to 4.2V), is unacceptable. After reviewing the hardware and applying various filtering techniques on both hardware and software levels, we found that averaging the ADC samples at a ratio of 1024 reduced the input noise. Unfortunately, this approach severely impacted performance, dropping the sampling rate from 1MSps to 1KSps. While denoising techniques in the frequency domain yielded promising noise reduction, they also required additional computational resources.

Despite these efforts to reduce noise, the core issue remained: What was causing the high input noise? To investigate further, we explored various hardware solutions, such as applying different filters at the ADC input, switching between ADC3 and ADC1, and testing both fast and slow inputs. However, the noise persisted. Reviewing posts from the STM32 community, we discovered that other developers had encountered similar problems. A particularly helpful discussion can be found here [2]. According to the discussion, the issue wasn't with the STM32 itself, but rather with the Nucleo board supporting Ethernet connectivity. The suggested workaround was to disable Ethernet, which might produce acceptable results. However, since Ethernet is a critical requirement for our project [insert hyperlink here], this solution was not viable.

An alternative would have been to design a custom PCB instead of using the Nucleo board, but due to project deadlines, this was not feasible. Consequently, we opted to use an external ADC.

The main criteria for selecting an external ADC included:

  • Simultaneous sampling of two channels

  • A sampling rate of at least 1MSps per channel

  • Standard communication interfaces like SPI or I2C

  • Availability of a development board for easier performance testing

After evaluating several options, we selected the ADS9224R, which met all these criteria and offered comprehensive documentation. However, upon reviewing the documentation, we realized that interfacing the ADS9224R with the STM32 posed a challenge, as the STM32 does not natively support dual slave output lines. This limitation required more advanced programming to achieve the desired integration. Furthermore, since no example source code was available for any platform, we decided to document our approach for connecting the ADS9224R with the STM32 and share our experience with the community.

Interfacing ADS9224R with STM32H7 MCU

This part will describe the approach that we utilized to connect ADS9224R with STM32H7 MCU. One of the main requests during this was to establish a connection in a such way that streaming started to minimally interrupt software. It is important to mention that the approach presented within this blog is not only and sue not the most efficient way from a resource perspective, but because we were limited with time, at the development point it seems to us as the most reasonable solution.

This blog will describe the main principle used to establish communication between STM32H7 MCU and ADS9224R while relevant code is available within the following path on our official GitHub repo:

Firmware/ADFirmware/CM7/Core/Drivers/Platform/AnalogIN/ADS9224R

ADS9224R communication topology

ADS9224R supports different connection topologies. Our system utilizes topology with minimum pins required to establish communication with the device and continuously stream samples. Figure 2 illustrates the connection topology used within OpenEPT hardware. A detailed description of the ADS9224R pins is available within the official ADS9224R documentation [1].

Main topologyFigure 2. Selected communication topology between STM32 and ADS9224R

 The presented topology is used for two operations: device configuration and simultaneous streaming samples acquired from channels A and B. To support these two operations, within a developed ADS9224R driver are implemented two operational modes: Configuration mode and Acquisition mode.

After ADS9224R is powered up, and firmware is run on the STM32 MCU platform, it is important to check that ADS9224R is ready to be configured. The function inside the ADS9224R driver, in charge of properly configuring ADS9224R, is named ADS9224R_Init. One of the first steps performed within this function is to “ping” the device to check if ADS9224R is present and if it is ready to be configured. This “ping” operation considers powering down and then powering up the device to force ADS9224R to generate a ready signal pulse. The device is power-down by pulling the #PD/RST pin and holding it minimum tWL_PD period defined within a datasheet which is in our case about 1 ms. After this, the device is powered up by pulling the #PD/RST pin high. When ADS9224R detects a rising edge, if it is ready and present within a system, consequently it will generate a READY signal to high, and the duration of the high level will be TPU = 0.9ms. This is illustrated in Figure 3. 

PowerUpSequenceFigure 3. Power-up device sequence

Configuration mode

After the device is responded to by a rising Ready signal, it is ready to be configured and the ADS9224R driver is moved to Configuration mode by calling private function prvADS9224R_CONF_SetState. In Configuration mode is mainly performed writing and reading device registers over standard SPI protocol. On the STM32 side is used SPI3 instance of SPI that is configured to operate in Master mode and few GPIO pins. Lines between ADS9224R and STM32 used within Configuration mode are illustrated in Figure 4.

Configuration Mode LInesFigure 4. Lines used in configuration mode

SPI3 instance on the STM32 side is configured to operate in Master mode. Pin 12 of GPIOD is configured as output and it is used as Chip Select signal for SPI while Pin 10 of GPIOG is configured as input and is used for reading operations. Pin 3 of GPIOA is used to keep the CONVST input of ADS9224R high during the configuration stage.

Different types of operations over ADS9224R registers are supported within ADS9224R. Operations are performed by sending the corresponding commands to the ADS9224R device over SPI. Even if there are multiple supported commands, within a current firmware version, two commands are extensively used: Register write, and Register read.

To perform register, and write operations, the standard procedure of sending two bytes over SPI is performed. This procedure is described in official documentation [1]. However, there are a few important notices related to the reading operations. When the register content wants to be read, two bytes are sent from MCU where the first 4 bits indicate the read command. After these two bytes are sent to the device, the device raises a READY pin which indicates that the requested register content is ready to be sent to MCU. After the Ready pin is set high, STM32 can perform an SPI read of one byte. This sequence is illustrated in Figure 5.

Configuration Mode Time DiagramFigure 5. Read the sequence timing diagram

Acquisition mode

As it is required by project definitions, it is important to enable a sampling rate of at least 1MSps which is followed by a relatively huge data bandwidth for MCU platforms. To enable high bandwidth, software architecture is designed based on the guidelines mentioned here [3]. To enable a sampling rate of 1MSps on a selected MCU-based platform it was required to enable streaming from ADS9224R ADC to STM32 MCU with minimal software intervention.

There are two possible conversion control and data transfer frame modes supported by ADS9224R: Zone 1 and Zone 2. These two modes are detailed and described in official ADC documentation [1] and their described protocol between ADC and MCU. For our project, Zone 1 is more suitable even if it requires a few more hardware resources.

To enable streaming from ADC to MCU, the following peripherals are used:

  • Timer instance No 5 (TIM5) – Configured in master mode and it used to Periodically trigger conversion

  • Timer instance No 4 (TIM4) – Configured in slave mode and it is used to control Chip select (CS) signal

  • Timer instance No 8 (TIM8) – Configured in slave mode and it is used to generate a Clock for data transfer

  • SPI instance No 5 (SPI5) – Configured in slave mode and it is used to receive data from channel A

  • SPI instance No 4 (SPI4) – Configured in slave mode and it is used to receive data from channel B

Schematic which illustrated details related to the connections between STM32 and ADS9224R is presented in Figure 6.

Acquisition Mode ConnectionsFigure 6. Lines used in acquisition mode

TIM5 is utilized to periodically trigger the conversion process by generating short high-level pulses on the CONVST input of the ADS9224R ADC. The timer is configured in master mode, with channel 4 operating in PWM mode. TIM5 is connected to STM32's internal APB bus, with its input clock frequency set to the maximum of 200 MHz. To achieve the desired sampling rate, the timer's prescaler and PWM duty cycle are adjusted based on the sampling rate defined through the OpenEPT GUI [4]. All timer configurations related to this process are encapsulated within the prvADS9224R_TIMER_CONVST_Init function, while the sampling rate can be configured using the ADS9224R_SetSamplingRate function.

TIM4 is responsible for controlling the SPI Chip Select (CS) input of the ADS9224R ADC. It is set to operate in slave mode as a One Pulse timer, triggered by the rising edge of the READY signal generated by the ADS9224R. Channel 1 of the timer is configured in PWM mode, with its active level set to zero. Like TIM5, TIM4 is also connected to the STM32’s internal APB bus, with its input clock frequency set to 200 MHz. The total high- and low-level duration of the signal remains constant across all sampling periods. All configurations related to this timer are handled within the prvADS9224R_TIMER_CS_Init function.

TIM8 is used to generate the clock signal for SPI communication. Like TIM4, TIM8 is configured to operate in slave mode, triggered by the falling edge of the READY signal. Channel 4 is set to PWM mode, with a 50% duty cycle, and the repetition counter is set to 16 (corresponding to one clock period per data bit). The clock frequency remains constant regardless of the sampling period. As with TIM5 and TIM4, TIM8 is also connected to the STM32’s internal APB bus, with its input clock frequency set to the maximum of 200 MHz. All timer configurations for this process are encapsulated within the prvADS9224R_TIMER_SCLK_Init function.

An overview of Timers’ configurations is presented in Table 2

Table 2. Timers’ configurations overview

Table 2After we are presented with the timer’s configuration it is important to explain the way they are synchronized to achieve timing for Zone 1. This synchronization is presented in Figure 7.

Zone 1 transferFigure 7. Zone 1 timing diagram

Once the ADS9224R configuration is complete, the device is ready to transmit the acquired samples from channels A and B. The conversion process is initiated by the rising edge of the CONVST signal (1). The minimum high-level duration of this signal is defined by the switching characteristics outlined in [1]. As previously mentioned, this signal is controlled by TIM5, which is configured in master mode to generate a PWM signal with the pre-configured period TS. When the rising edge of the CONVST signal is detected, after a delay of TR (which, according to [1], does not exceed 315ns), the READY signal is generated. This signal plays a key role as it triggers TIM4 and TIM8, which are responsible for the CS and SCLK signals, respectively. The rising edge of the READY signal (2) starts TIM4, which pulls the CS signal low to activate all SPI slaves. The low-level duration of the CS signal, denoted as TT, corresponds to the time needed to transfer all 16 bits of data. The falling edge of the READY (3) signal then triggers TIM8, which generates 16 clock cycles to facilitate data transfer.

It is important to highlight three critical timing parameters:

  • TR: The time interval between the rising edge of the CONVST signal and the rising edge of the READY signal, controlled by the ADS9224R, which is specified in [1] and does not exceed 315ns.

  • TS: The sampling period, is determined by the value set by the user through the GUI application.

  • TT: The time interval during which data transfer is active, which must be less than TS - TR.

In the current software version, 16 clock cycles are generated during each TT interval. To ensure high-speed data transfer, the TT interval remains constant, regardless of the sampling period. This setup allows the transmission of the 16-bit sampled value from the corresponding ADC channel, even when the sampling rate is 1MSps.

To manage data acquisition, three timers generate the CS, SCLK, and CONVST signals for Zone 1, while SPI instances 4 and 5 are used to receive data and store it in local memory. These SPI peripherals are connected to DMA controllers, which offload the CPU by handling data transfer. The DMA retrieves one byte at a time from the SPI and continues until N samples have been received. Unlike the internal ADC setup in the Analog IN software block, where data from both channels is stored sequentially in a single buffer, in case the software utilizes the external ADC, each buffer is divided into two equal parts, with each part storing N samples from one channel. Since the DMA operates in double-buffer mode, when one buffer fills with N samples, the DMA automatically switches the data stream to the second buffer. These buffers, declared as non-cacheable within the AIN software block, store the data. Once both buffer sections are full, an interrupt service routine (ISR) notifies the software to read and transmit the data over Ethernet, while the DMA continues to fill the alternate buffer. This process is illustrated in Figure 8.

DataTransferFigure 8. Data streaming mechanism

When the "START ACQUISITION" command is received by the MCU from the GUI, the acquisition process using the external ADC begins with a call to the ADS9224R_StartAcquisition function. The function first checks whether the ADS9224R driver is already in acquisition mode; if not, it configures the driver for acquisition by calling prvADS9224R_ACQ_SetState. An important modification made to the STM32 HAL library ensures that the DMA operates in double-buffer mode. This modification involves replacing the HAL_DMA_Start_IT function with HAL_DMAEx_MultiBufferStart_IT inside the HAL_SPI_Receive_DMA function. This change is illustrated in Figure 9.

Code 2Figure 9. Part of the STM32 HAL library that is modified to support DMA double buffer mode

Once it is confirmed that the driver is in acquisition mode, the PWM channels are enabled in the following order: TIM4 (CS), TIM8 (SCLK), and TIM5 (CONVST). When the TIM5 timer is activated, it generates pulses that initiate the conversion process, starting the data transfer cycles on the SPI bus.

Testing setup

In the previous sections, we presented the key principles and mechanisms for establishing communication with the ADS9224R, which were achieved through extensive testing and software development. However, the integration process was not straightforward. The STM32H7 platform does not provide a direct interface for easily connecting the STM32H7 MCU to the ADS9224R, which added to the complexity. This meant the integration required systematic investigation and debugging. During the early stages of development, we used tools such as a Digilent logic analyzer, a protoboard, and a voltage and signal generator to test various concepts and verify communication. This setup involved numerous cables to connect the STM32H7 MCU, the ADS9224R ADC, and the logic analyzer, as illustrated in Figure 10.

SystemFigure 10. Initial testing setup

As shown in Figure, a variety of cables were required to establish communication and verify data accuracy. This setup was sufficient for testing the core working principles related to Configuration and Acquisition modes. However, to move forward with system testing on the OpenEPT board developed in Milestone 5, we decided to create an adapter to simplify the connection between the Nucleo board (featuring the STM32H755ZIQ MCU) and the ADS9224R development board. The new setup is illustrated in Figure 11.

System2Figure 11. Final testing setup

The connection between the ADS9224R evaluation kit and the STM32H7 Nucleo development board is established via a custom-made Adapter 1, which routes the test points from the ADS9224R board to the corresponding pins on the STM32H7 board. This setup greatly reduces the cable clutter that was an issue in the early stages of testing and development. Furthermore, it provides an ideal configuration for testing the noise performance, which will be discussed in the next section.

Noise performance

To test the performance in improving noise level reduction, both AD converters were driven by a DC voltage of 1V. Samples obtained from the internal AD converter are shown in Figure 12, while samples obtained from the external AD converter are displayed in Figure 13. The acquisition duration for both channels is 60 seconds.

Internal TimeFigure 12. 1V DC voltage acquired by Internal ADC over a 60 seconds interval

External TimeFigure 13. 1V DC voltage acquired by External ADC over a 60 seconds interval

Table 3 summarizes the key characteristics of the obtained signals, such as mean value, standard deviation, and maximum deviation.

Table 3. Summary of Key Characteristics of Obtained Signals

Table 3From Figures 12 and 13 and the values shown in Table 3, it is clear that the time domain noise level is significantly higher when using the internal ADC. With the external ADC, the noise level is approximately 50 times lower, which greatly enhances the measurement performance of the ADC without requiring additional software intervention.

Figures 14 and 15 display the frequency spectrum of signal amplitudes captured by the internal and external ADC, respectively. It is clear from these figures that both spectra contain significant amplitude components in the lower frequency range, with slightly higher values in the internal ADC spectrum compared to the external ADC. These components, however, are unrelated to ADC noise and instead originate from the DC voltage generator used in the setup.

Internal FrequencyFigure 14. The frequency spectrum of the 1V DC voltage acquired by internal ADC over a 60 seconds interval

External FrequencyFigure 15. The frequency spectrum of the 1V DC voltage acquired by external ADC over a 60 seconds interval

Rephrase this: From Figures 14 and 15 it is noticeable the internal ADC spectrum shows higher amplitude components across all frequency ranges compared to the external ADC spectrum. This could be the primary source of noise introduced by the internal ADC. This phenomenon is illustrated in Figures 16 and 17.

Internal Maximal FrequencyFigure 16. Low-Level Amplitudes of the Frequency Spectrum for a 1V DC Voltage Signal Captured by the Internal ADC

External Maximal FrequencyFigure 17. Low-Level Amplitudes of the Frequency Spectrum for a 1V DC Voltage Signal Captured by the External ADC

Figures 16 and 17 show that the low-level amplitude values across the entire frequency spectrum are 100 times smaller when obtained with the external ADC compared to the internal ADC. The exact reason why the amplitudes within the spectrum obtained by the internal ADC are 100 times higher is not currently known. As mentioned in this discussion, a possible explanation could be that Ethernet communication introduces significant noise. A thorough investigation into the source of the problem is not feasible at this time due to time constraints. If further exploration confirms that Ethernet is the issue, this would be in contradiction with our initial project requirements. Therefore, we will proceed with the external ADC as the primary ADC for the system, while the internal ADC will be reserved for estimating side effects and measurements.

References

[1] https://www.ti.com/lit/ds/symlink/ads9224r.pdf?ts=1730318477631&ref_url=https%253A%252F%252Fwww.ti.com%252Fproduct%252FADS9224R

[2] https://community.st.com/t5/stm32-mcus-products/fluctuations-in-adc-value-of-stm32h743-mcu/td-p/331487

[3] https://www.mdpi.com/2079-9292/12/20/4206

[4] https://www.youtube.com/playlist?list=PLTG-EoxvlLos_3Sex3R0yfDCwpDYyRSOo

© 2023 Open Energy Profiler Toolset. All Rights Reserved. made by