Skip to main content
CPurc.1
Associate II
February 19, 2022
Solved

Interface with external ADC via SPI at 1MS/s

  • February 19, 2022
  • 3 replies
  • 17455 views

Hi all,

I am using the NUCLEO-F446RE with the STM32F446RE. I am trying to interface with an external dual sampling differential ADC: ADS9224R.

ADC Timing Diagram

0693W00000KZlwCQAT.pngThe ADC can provide samples at up to 3M/s. I would be happy to achieve ~0.8M/s sampling.

I have been struggling to meet the timing that I require and can only reach ~180kHz with the STM32. My problem is that initiating separate SPI receive calls takes too long between commands.

Running the following code to initiate back to back SPI reads:

HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); //CS LOW
 HAL_SPI_Receive(&hspi1, (uint8_t *)spi_buffer, 1,40);
 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); //CS high
 
 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET); //CS LOW
 HAL_SPI_Receive(&hspi1, (uint8_t *)spi_buffer, 1,40);
 HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET); //CS high

Produces the following timing:

0693W00000KZlxPQAT.png 

The STM32 is operating at 180MHz, and the SPI CLK is at ~30MHz. You can see that once the SPI initiates it is very fast, but the time to initiate the next SPI read is taking too long (~6us) which is limiting the rate at which I can read from the ADC.

I understand that this approach will only read ADC-0A, and not ADC-0B simultaneously. I have an implementation that uses QSPI but suffers from the same problem. I have simplified to single line SPI in hope that more people can provide help and I can transfer this to a dual line implementation.

Thank you all for your help!

This topic has been closed for replies.
Best answer by KnarfB

Ok, next plan, no code yet. If the 2nd SPI is slave, why not put both in slave mode (with circular RX DMA)? Then, we need another component, generating the clock pulses. This could be Timer TIM1 in one pulse mode and using a repetition counter of 7 (for 8 pulses). The pulse train (clock) is output in PWM GenerationCH1 mode.

How to trigger TIM1? Manually, for testing, worked.

Next: Automatically from TIM2. (Put TIM into slave trigger mode and route the TIM2 event to TIM1 ITR.

Don't have that ADC for testing.

Soon more...

KnarfB

3 replies

KnarfB
Super User
February 19, 2022

HAL functions seem to be a bit heavy for tight timing. You may have go down to register level. This is almost trivial for the GPIO but not so much for the SPI. You might also generate low level (LL) code which is close to register level prog.

ADC sampling usually requires a low jitter. So triggering by software might not be feasible at all.

The most deterministic and "hardware only" way is using a timer event triggering SPI transfers using DMA. Here is an example: https://electronics.stackexchange.com/questions/353152/stm32f-how-to-config-dma-transfer-to-spi-triggered-by-timer

hth

KnarfB

CPurc.1
CPurc.1Author
Associate II
February 19, 2022

Thanks for your help. I understand that this is not deterministic, but I was trying to produce the lowest possible timing by executing the HAL commands back to back, without having to handle the interrupt of a timer to potentially slow down the execution.

Would DMA speed up the operation, because the CPU does not need to handle writing the buffer to memory between each SPI receive call, allowing the next SPI call can be initiated sooner?

Is the timing I require actually realistic for my processor? I have not worked at these data rates before, I thought having to read an external ADC with SPI at ~1MS/s would be a reasonably common application.

Thanks

TDK
February 19, 2022

The timing you require is possible, but not realistic with HAL. The synchronization of the CS line provides an additional hurdle, unless you can keep it low.

As KnarfB says, triggering the SPI from a timer is your best bet here. You'll also need a DMA channel to read the incoming data.

"If you feel a post has answered your question, please click ""Accept as Solution""."
MasterT
Lead II
February 19, 2022

Options:

a. Cascaded 2 Timers, first to generate CS (NSS), second - gated slave - to generate spi clock. Than you configure SPI as a slave and clocking data out of adc. SPI configured with DMA., both sides SPI and ADC pins interconnected and jumped to timers PWM outputs (except data pin, of course, this one goes directly to MISO)

The issue with stm32F4 is that timers don't have "Combine PWM" capability, so this trick I have successfully implemented on F7 & H7 uCPU may not work if ADC too sensitive for NSS-SCK timings phases.

b. Turn SPI into I2S mode. It solves problem that F4 spi don't drive CS(NSS) pin in hardware. If I2S mode, than Left-Right channel selector is your NSS driven by hardware. All it takes is to set I2S with DMA. I have interfaced with AD7988-5 / DAC80501 / and a lot others 16-24 bits ADC and DAC's. Especially this trick very jitterhelpful for 24-bits peripherals, since common SPI is 16-bits max, and driving something in software slow and creates a lot of jitter.

HAL driver limits I2S to 192 ksps, but there is a way:

 
 HAL_I2S_DMAPause( &hi2s2);
 Serial.print(F("\n\tchange i2s-2 clock to 250 ksps..."));
 delay(100);
 (*(uint32_t*)0x40003820) = 0x0000000C; 
// fS = I2SxCLK / [(32*2)*((2*I2SDIV)+ODD)*4)] 
// when the channel frame is 32-bit wide
 HAL_I2S_DMAResume( &hi2s2);

Associate
October 10, 2023

Hello, 

I am currently developing an MCU based radar. I tried to implement 4-channel ADC Sampling 1MSPS based on STM32H743, but the results were not good. There are many problems, but the biggest problem is the sampling rate, so to solve this, we plan to use an external high-speed ADC chip (AD7383-4). As you all know, the STM32H7 series supports QuadSPI. Of course, there are mainly examples related to Memory. Some engineers say that you can set it to indirect mode and do it. (https://stackoverflow.com/questions/73855861/qspi-connection-on-stm32-microcontrollers-with-other-peripherals-instead-of-flas). Another engineer said that STM32 Quad SPI is difficult to use because it is for memory and data is loaded alternately on the Quad SPI data line. This part seems to be somewhat limited to memory.

Do you know if there is a way to simultaneously receive 4 channel ADC data at 4MSPS using quad SPI on STM32H7?