2025-04-10 2:42 AM - last edited on 2025-04-10 3:06 AM by Andrew Neil
Hello,
I have the TI ADS8350 and want to read both channels in parallel. They support SPI, but I can not figure out how to setup the dual SPI for this. Another way would be to use DMA, could someone point me in the right direction. I am using SMT32F412.
Thanks.
Solved! Go to Solution.
2025-04-10 7:13 AM
I interfaced ads8354 to stm32h743, using one spi as master, and another as a slave 2-line rx only. The beauty of H7 is that it can drive CS line by spi in master /dma mode. F4 & F7 don't have this future, so if you can't switch project to h7m than I'd recommend config two spi as slaves driven by two linked timers. First timer -gated generates 16-clock for SCLK, and second drives CS and defines sampling rate.
2025-04-10 3:00 AM - edited 2025-04-10 3:31 AM
So this: https://www.ti.com/product/ADS8350
Do TI have any suggestions/recommendations on this?
https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum
In SPI terms, Looks like it has a single SCLK, two MISOs, and no MOSI:
So the start of the read is triggered purely by /CS:
So maybe try:
You'll need to manually control /CS anyhow to get the tCONV timing
PS:
You may also need to feed the /CS back into the Slave...
2025-04-10 6:50 AM
And if I want to have a specific acquisition time should I use one /CS for slave SPI and second for ADC because with this ADC the acquisition time is controlled by the /CS pin.
2025-04-10 7:01 AM - edited 2025-04-10 7:02 AM
I would think not: there should be just one /CS - that's what synchronises everything.
Looking at it again, it seems that tCONV isn't (just) a time - it's a number of clock cycles.
You should be able to get that by the Master clocking-out a 16-bit value (just a dummy that gets ignored).
Again, this is all about the TI chip; so TI would be experts and they would be the ones to ask.
https://e2e.ti.com/support/data-converters-group/data-converters/f/data-converters-forum
None of this is specific to STM32.
2025-04-10 7:13 AM
I interfaced ads8354 to stm32h743, using one spi as master, and another as a slave 2-line rx only. The beauty of H7 is that it can drive CS line by spi in master /dma mode. F4 & F7 don't have this future, so if you can't switch project to h7m than I'd recommend config two spi as slaves driven by two linked timers. First timer -gated generates 16-clock for SCLK, and second drives CS and defines sampling rate.
2025-04-10 7:58 AM
Thanks, I am forced to use the F4. So I should confing 2 spi slaves that will just read with first gated timer being trigered by some ITR, and second timer for CS, and I get the ITR from its output compare?
2025-04-10 8:10 AM - edited 2025-04-10 8:19 AM
You could still try the Master + Slave, and get the Master to give the 16 clocks as suggested?
Should be easy enough to try ...
PS:
The F4 does have a kind of hardware /CS control:
Maybe that could be made to work?
There's also QUADSPI ...
2025-04-10 8:23 AM
Here a code that link Tim2 Tim-3 and SPI-3 on F446re.
void SPI3_DMA_Init(void)
{
__HAL_RCC_DMA1_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA1_Stream0_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn);
}
void SPI3_Init(void)
{
hspi3.Instance = SPI3;
hspi3.Init.Mode = SPI_MODE_SLAVE;
hspi3.Init.Direction = SPI_DIRECTION_2LINES_RXONLY;
hspi3.Init.DataSize = SPI_DATASIZE_16BIT;
hspi3.Init.CLKPolarity = SPI_POLARITY_HIGH;
hspi3.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi3.Init.NSS = SPI_NSS_HARD_INPUT;
hspi3.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi3.Init.TIMode = SPI_TIMODE_DISABLE;
hspi3.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi3.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi3) != HAL_OK)
{
Error_Handler();
}
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
GPIO_InitTypeDef GPIO_InitStruct = { 0};
if(hspi->Instance == SPI3) {
__HAL_RCC_SPI3_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();
/**SPI3 GPIO Configuration
PA15 ------> SPI3_NSS
PC10 ------> SPI3_SCK
PC11 ------> SPI3_MISO
*/
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_12;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/* SPI3 DMA Init */
/* SPI3_RX Init */
hdma_spi3_rx.Instance = DMA1_Stream0;
hdma_spi3_rx.Init.Channel = DMA_CHANNEL_0;
hdma_spi3_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi3_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi3_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi3_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
hdma_spi3_rx.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
hdma_spi3_rx.Init.Mode = DMA_CIRCULAR;
hdma_spi3_rx.Init.Priority = DMA_PRIORITY_HIGH;
hdma_spi3_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi3_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(hspi,hdmarx,hdma_spi3_rx);
}
}
void TIM2_Config(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = { 0};
TIM_MasterConfigTypeDef sMasterConfig = { 0};
TIM_OC_InitTypeDef sConfigOC = { 0};
__HAL_RCC_TIM2_CLK_ENABLE();
htim2.Instance = TIM2;
htim2.Init.Prescaler = 0;
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 219;//409kHz
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
// htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim2, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_OC3REF;//TIM_TRGO_OC4REF;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 32;
// sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;//TIM_OCPOLARITY_LOW;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
//
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 50;//36;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_Base_Start(&htim2);
if (HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_4) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
}
void TIM3_Config(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig = { 0};
TIM_SlaveConfigTypeDef sSlaveConfig = { 0};
TIM_MasterConfigTypeDef sMasterConfig = { 0};
TIM_OC_InitTypeDef sConfigOC = { 0};
__HAL_RCC_TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sSlaveConfig.SlaveMode = TIM_SLAVEMODE_GATED;
sSlaveConfig.InputTrigger = TIM_TS_ITR1;
if (HAL_TIM_SlaveConfigSynchronization(&htim3, &sSlaveConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 1;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_Base_Start(&htim3);
if (HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3) != HAL_OK)
{
Error_Handler();
}
}