cancel
Showing results for 
Search instead for 
Did you mean: 

200kHz ADC Communication

UL
Associate III

Hello, 

 

I have been using the STM32F4 chip for a while but I ran into an issue when trying to communicate with an ADC to sample at 200kHz. So I have started to work with the STM32U5 chip. My goal is to use the SPI RDY feature or the GPDMA triggered from an external interrupt in order to handle the spi communication and fill a buffer. Unfortunately I have been struggling to find good resources on how to use these features or examples that I can try to follow through. I am able to do spi communication that are called from the main process but I can't get a message to trigger from an external interrupt. 

 

Any advice on how I can learn about these features would be greatly appreciated,

 

I have also included the code as I have it thus far.

 

Thanks!

1 ACCEPTED SOLUTION

Accepted Solutions

Hello @UL 

 

To trigger an SPI Master communication using an external interrupt, you need to connect the DRDY pin from the ADC to an EXTI pin (EXTI4 or EXTI9, please refer to the reference manual for more details) and perform the following settings:

 

 

  /* EXTI Configuration **********************************************/
  /* Enable the GPIO clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  /* Configure pin as the EXTI input event line in interrupt mode */
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* Configure pin as Output now to generate automatically the event */
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI4_IRQn, 3, 0);
  HAL_NVIC_EnableIRQ(EXTI4_IRQn);

  /* Init the SPI peripheral */

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_4BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x7;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  hspi1.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
  HAL_SPI_Init(&hspi1);
  /* SPI Trigger Configuration ****************************************/
  AutonomousConfig.TriggerState      = SPI_AUTO_MODE_ENABLE;
  AutonomousConfig.TriggerSelection  = SPI_GRP1_EXTI4_TRG;
  AutonomousConfig.TriggerPolarity   = SPI_TRIG_POLARITY_RISING;
  HAL_SPIEx_SetConfigAutonomousMode(&hSPI1, &AutonomousConfig);

 

 

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar

View solution in original post

12 REPLIES 12
Saket_Om
ST Employee

Hello @UL 

 

In order to initiate SPI communication via an external interrupt, you need to connect the slave device's RDY pin to the master device's external interrupt pin.

Additionally, it is important to configure the ReadyMasterManagement and ReadyPolarity parameters correctly. Here is an example code snippet for these settings:

 

  hspi1.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_EXTERNALLY;
  hspi1.Init.ReadyPolarity = SPI_RDY_POLARITY_HIGH;

Please ensure that the polarity setting is suitable for your application.

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar
UL
Associate III

Hi OSAKE,

So the ready pin is only used to note that the SPI is ready to recieve a message. Can you use the RDY pin to trigger a message on the slave device?

 

 

What I am trying to do is trigger a message from the Master device (STM32U5) when a DRDY signal goes high on the ADC. I am trying to off load this task to an autonomous function that won't require the main loop. Reading your message, it seems like the RDY is not meant for this type of functionality.

 

thanks,

Spencer

Hello @UL 

 

The RDY signal is featured in some SPI versions, which performs the slave's FIFOs occupancy status,
and so its capability to continue at operation without any risk of data underrun or overrun. If the master disregards
RDY and continues the transfer, the slave risks an underrun or overrun condition. On STM32 devices, the master
communication is temporarily frozen when the slave provides a not-ready status. 

 

For your application I understand that you are looking to streamline it by offloading tasks from the main loop. To achieve this, you can indeed utilize the HAL_ADC_ConvCpltCallback() function. This callback function is executed when the ADC conversion is complete and can be used to initiate SPI communication autonomously.

Here's a step-by-step guide on how you can implement this:

  1. Enable ADC EOC (End Of Conversion) interrupt: Make sure that the ADC interrupt is enabled to trigger the callback function upon completion of the conversion.

  2. Implement the HAL_ADC_ConvCpltCallback(): Within this function, you can place your code to start the SPI communication. This function will be called automatically when the ADC conversion is complete.

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar
UL
Associate III

HI OSAKE,

 

I believe that would only work for the internal ADC. Sorry I should have clarified that it is an external ADC that sends a DRDY back to the MCU when the conversion is completed. (Conversion is handled internally to the ADC). What I have been trying to do is use the DMA LL architecture to do the following. 

 

1. Configured DMA:

  • Circular mode
  • First node has a trigger from external interrupt 
    • basically a dummy node that does no real transfer
  • second node triggers a RX for 4 bytes from the ADC using SPI (SPI1)
  • trigger an interrupt stating the conversion has been completed or increment the location of the next message so that I could do a burst of 50000 transfers in a buffer before handing off to the main loop for further processing

Thus far I am unable to get the SPI message to trigger using this approach. I am able to see clock signals if I manually start the SPI message using the HAL_SPI_Receive_DMA(&hspi1, data, 4); command or by manually changing the SET_BIT(hspi1.Instance->CR1, SPI_CR1_CSTART);. 

Thus far I am unable to get the DMA to cause any SPI message to be originated head-lessly from the DMA. I have also tried using a 1 node chain for the LL that is the SPI RX that contians the trigger but reading the User Manual it seemed like a n-1 node was required for the pause to execute correctly. (User Manual RM0456 698 - 700)

UL_0-1715693954953.png

 

Hello @UL 

 

To trigger an SPI Master communication using an external interrupt, you need to connect the DRDY pin from the ADC to an EXTI pin (EXTI4 or EXTI9, please refer to the reference manual for more details) and perform the following settings:

 

 

  /* EXTI Configuration **********************************************/
  /* Enable the GPIO clock */
  __HAL_RCC_GPIOA_CLK_ENABLE();
  /* Configure pin as the EXTI input event line in interrupt mode */
  GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Pin = GPIO_PIN_4;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  /* Configure pin as Output now to generate automatically the event */
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLDOWN;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET);
  /* EXTI interrupt init*/
  HAL_NVIC_SetPriority(EXTI4_IRQn, 3, 0);
  HAL_NVIC_EnableIRQ(EXTI4_IRQn);

  /* Init the SPI peripheral */

  hspi1.Instance = SPI1;
  hspi1.Init.Mode = SPI_MODE_MASTER;
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
  hspi1.Init.DataSize = SPI_DATASIZE_4BIT;
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi1.Init.NSS = SPI_NSS_SOFT;
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
  hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi1.Init.CRCPolynomial = 0x7;
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  hspi1.Init.ReadyMasterManagement = SPI_RDY_MASTER_MANAGEMENT_INTERNALLY;
  HAL_SPI_Init(&hspi1);
  /* SPI Trigger Configuration ****************************************/
  AutonomousConfig.TriggerState      = SPI_AUTO_MODE_ENABLE;
  AutonomousConfig.TriggerSelection  = SPI_GRP1_EXTI4_TRG;
  AutonomousConfig.TriggerPolarity   = SPI_TRIG_POLARITY_RISING;
  HAL_SPIEx_SetConfigAutonomousMode(&hSPI1, &AutonomousConfig);

 

 

 

If your question is answered, please close this topic by clicking "Accept as Solution".

Thanks
Omar
Uwe Bonnes
Principal III

Tell us what external ADC you use. Probably the ADC will complete the conversion in some maximum time guaranteed in the datasheet. Set up a timer to ensure this maximum time is over and read out without looking at DRDY.

UL
Associate III

When using a solution like this how do you specify the type of message i.e. number of bytes that will be received during the automated system?

Hi Uwe,

 

I am using the ADS127L11. I could do that but I still need to get more of the messaging off the main loop. In pervious tests I didn't have enough time to move the data around after the messaging even when using the SPI interrupt mode. 

 

I have been trying to work through the messaging similar to the STM32U5 workshop: STM32U5 Workshop (rristm.github.io).

 

I have been able to get the USART working as they show but I cannot get the SPI to work in a similar manor. Do you know if there is something special about the SPI protocol or controller that prevents this type of architecture?

Do you want to read out like Figure 8-35. SDO/DRDY and DRDY Function?

Have you tried to use EXTI(DRDY) as trigger for a SPI transfer of 24 bit  and SPI_RX_DMA to write the result to a block of memory?