2020-11-28 09:38 AM
Hello,
I'm working on a board with STM32H745. The mcu has to interface with an external ADC
(LTC2335-16) to permit a max sample rate of 1M/s (during software develop 20KHz see images).
So, i've decide to use LPTIM2 to generate the 1MHz signal (50% duty) to generate the
start conversion for ADC (positive edge). After 500nsec the converted data is ready to
get out the 3 bytes read (see the attached images). So I configure the SPI with transmit and
receive DMA with the synchronization event for DMA TX with the falling edge of LPTIM2 signal.
Here is the peripheral initialization software.
SpiHandle.Instance = SPI4;
SpiHandle.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_ENABLE; // Recommended setting to avoid glitches
SpiHandle.Init.Mode = SPI_MODE_MASTER;
SpiHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; //SPI_BAUDRATEPRESCALER_128,
SpiHandle.Init.Direction = SPI_DIRECTION_2LINES;
SpiHandle.Init.CLKPhase = SPI_PHASE_1EDGE;
SpiHandle.Init.CLKPolarity = SPI_POLARITY_LOW;
SpiHandle.Init.DataSize = SPI_DATASIZE_8BIT;
SpiHandle.Init.FirstBit = SPI_FIRSTBIT_MSB;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
SpiHandle.Init.NSS = SPI_NSS_HARD_OUTPUT;
SpiHandle.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
SpiHandle.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
SpiHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
SpiHandle.Init.CRCPolynomial = 7;
SpiHandle.Init.CRCLength = SPI_CRC_LENGTH_8BIT;
SpiHandle.Init.TIMode = SPI_TIMODE_DISABLE;
if(HAL_SPI_Init(&SpiHandle) != HAL_OK)
{
// Initialization Error
while(1){};
}
/*##-1- Enable peripherals and GPIO Clocks #################################*/
SPI4_SCK_PORT_CLK_EN(); //PE2: SPI4_SCK
SPI4_NSS_PORT_CLK_EN(); //PE4: SPI4_NSS
SPI4_MISO_PORT_CLK_EN(); //PE5: SPI4_MISO
SPI4_MOSI_PORT_CLK_EN(); //PE6: SPI4_MOSI
SPI4_SCK_EN(); //Peripheral clock
/*##-2- Configure peripheral GPIO ##########################################*/
/* SPI SCK GPIO pin configuration */
GPIO_InitStruct.Pin = SPI4_SCK_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStruct.Alternate = SPI4_SCK_AF;
HAL_GPIO_Init(SPI4_SCK_GPIO_PORT, &GPIO_InitStruct);
/* SPI NSS GPIO pin configuration */
GPIO_InitStruct.Pin = SPI4_NSS_PIN;
GPIO_InitStruct.Alternate = SPI4_NSS_AF;
HAL_GPIO_Init(SPI4_NSS_GPIO_PORT, &GPIO_InitStruct);
/* SPI MISO GPIO pin configuration */
GPIO_InitStruct.Pin = SPI4_MISO_PIN;
GPIO_InitStruct.Alternate = SPI4_MISO_AF;
HAL_GPIO_Init(SPI4_MISO_GPIO_PORT, &GPIO_InitStruct);
/* SPI MOSI GPIO pin configuration */
GPIO_InitStruct.Pin = SPI4_MOSI_PIN;
GPIO_InitStruct.Alternate = SPI4_MOSI_AF;
HAL_GPIO_Init(SPI4_MOSI_GPIO_PORT, &GPIO_InitStruct);
/*##-3- Configure the DMA ##################################################*/
/* Enable DMA clock */
DMA1_CLK_ENABLE();
/* Configure the DMA handler for Transmission process */
hdma_tx.Instance = SPIx_TX_DMA_STREAM;
hdma_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;//>>DMA_FIFOMODE_DISABLE;
hdma_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_tx.Init.MemBurst = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_MBURST_INC4;
hdma_tx.Init.PeriphBurst = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_PBURST_INC4;
hdma_tx.Init.Request = SPIx_TX_DMA_REQUEST;
hdma_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_tx.Init.Mode = DMA_PFCTRL;//>>DMA_NORMAL;
hdma_tx.Init.Priority = DMA_PRIORITY_LOW;
HAL_DMA_Init(&hdma_tx);
/* Configure the DMAMUX with the Synchronization parameters */
DmaSyncConfig.EventEnable = ENABLE; /* Enable DMAMUX event generation each time RequestNumber are passed from DMAMUX to the DMA */
DmaSyncConfig.SyncPolarity = HAL_DMAMUX_SYNC_FALLING; /* Synchronization edge is Rising */
DmaSyncConfig.RequestNumber = 3;//3;//4; /* 4 requests are autorized after each edge of the sync signal */
DmaSyncConfig.SyncSignalID = HAL_DMAMUX1_SYNC_LPTIM2_OUT; /* Sync signal is LPTIM1_OUT */
DmaSyncConfig.SyncEnable = ENABLE; /* Synchronization is enabled */
HAL_DMAEx_ConfigMuxSync(&hdma_tx, &DmaSyncConfig);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(hspi, hdmatx, hdma_tx);
/* Configure the DMA handler for Transmission process */
hdma_rx.Instance = SPIx_RX_DMA_STREAM;
hdma_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
hdma_rx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_rx.Init.MemBurst = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_MBURST_INC4;
hdma_rx.Init.PeriphBurst = DMA_MBURST_INC4;//>>DMA_MBURST_SINGLE;//>>DMA_PBURST_INC4;
hdma_rx.Init.Request = SPIx_RX_DMA_REQUEST;
hdma_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_rx.Init.Mode = DMA_PFCTRL;//DMA_NORMAL;
hdma_rx.Init.Priority = DMA_PRIORITY_HIGH;
HAL_DMA_Init(&hdma_rx);
/* Associate the initialized DMA handle to the the SPI handle */
__HAL_LINKDMA(hspi, hdmarx, hdma_rx);
/*##-4- Configure the NVIC for DMA #########################################*/
/* NVIC configuration for DMA transfer complete interrupt (SPIx_TX) */
HAL_NVIC_SetPriority(SPIx_DMA_TX_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(SPIx_DMA_TX_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (SPIx_RX) */
HAL_NVIC_SetPriority(SPIx_DMA_RX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPIx_DMA_RX_IRQn);
/*##-5- Configure the NVIC for SPI #########################################*/
/* NVIC configuration for SPI transfer complete interrupt (SPIx) */
HAL_NVIC_SetPriority(SPIx_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPIx_IRQn);
And the ISR for SPI (I started from SPI_FullDuplex_ComDMA example)
/**
* @brief This function handles SPIx interrupt request.
* @param None
* @retval None
*/
void SPI4_IRQHandler(void)
{
HAL_SPI_IRQHandler(&SpiHandle);
}
/**
* @brief This function handles DMA Rx interrupt request.
* @param None
* @retval None
*/
void SPI4_DMA_RX_IRQHandler(void)
{
HAL_DMA_IRQHandler(SpiHandle.hdmarx);
}
/**
* @brief This function handles DMA Tx interrupt request.
* @param None
* @retval None
*/
void SPI4_DMA_TX_IRQHandler(void)
{
HAL_DMA_IRQHandler(SpiHandle.hdmatx);
}
This is the on period LPTIM2 isr
void LPTIM2_IRQHandler(void)
{
/* Clear interrupt flags */
__HAL_LPTIM_CLEAR_FLAG(&LptimHandle, LPTIM_IT_ARRM);
//read from DMA last conversion data
//Check if conversion sequence end
//If no prepare next packet to transmit
HAL_StatusTypeDef zResult = HAL_SPI_TransmitReceive_DMA(&SpiHandle, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, BUFFERSIZE);
}
I configured the LPTIM2 to get the on period interrupt event (on every rising edge):
so inside this ISR I prepare the 3bytes to trasmit on the next falling edge and read the
3 bytes of last conversion.
As you can see only the first SPI packet exit on falling edge and no more other.
Furthermore is it possible to get correct timing and data configuring without all the SPI,
DMA_TX amd DMA RX interrupt routines?
Thanks in advance foy any help to resolve this issue.
2020-11-28 03:54 PM
Break it down into smaller steps. Make sure your HAL_SPI_TransmitReceive_DMA calls work correctly on their own, then try to integrate them into the system. Ensure HAL_SPI_TransmitReceive_DMA returns HAL_OK as opposed to an error code.
Calling anything but the most trivial ISRs at 1 MHz is going to be a nonstarter. You can probably get away with 20 kHz.
For development, I'd slow things down even more so your scope waveforms look more square.
2020-11-29 01:55 AM
Post a foto of your setup.
Use Circular mode of DMA.
In case of unexpected behaviour, read out and check content of SPI and DMA registers.
JW
2020-12-03 08:37 AM
Hello to all.....I followed yours suggestions to split the step by step the setup sequence. After setting circular mode it seems to goes well...I'm doing few tests in these days. I will give you the final result in a few days.
Thanks for support,
regards
DM
2023-02-14 09:46 AM
do you mind sharing your code on github?