2023-12-15 07:48 AM
I'm having a problem using DMA with SPI.
Fault is almost certainly me as this is the first time I have used SPI/DMA. Normally I just wait for SPI to finish, but on this occasion it is taking too long so I need to move the process away from the CPU waiting.
When I use normal SPI_TransmitReceive it is all ok so not suspecting a hardware problem. I'm not familiar with DMA at all, so not sure whether to use FIFO, circular buffers or how to allow enough space for the 27 Byte transfer.
RxBuffer is always 0x00...
Receive/Tx:
/Read all 8 channels
void SPI_ADC_READ(uint8_t ADCn)
{
uint8_t Cmd[27] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
//HAL_SPI_TransmitReceive(&ADC_SPI, Cmd, ADC_DATA, 27, 1000);
// HAL_SPI_TransmitReceive(&ADC_SPI, Cmd, ADS1298RData.ByteValue, 27, 1000);
// counter1++;
// HAL_SPI_TransmitReceive_DMA(SPI_HandleTypeDef *hspi, uint8_t *pTxData, uint8_t *pRxData, uint16_t Size);
HAL_SPI_TransmitReceive_DMA(&ADC_SPI, Cmd, RxBuffer, 27);
counter1++;
}
SPI/DMA config
/* SPI3 init function */
void MX_SPI_ADC_Init(void)
{
/* SPI3 parameter configuration*/
ADC_SPI.Instance = SPI4;
ADC_SPI.Init.Mode = SPI_MODE_MASTER;
ADC_SPI.Init.Direction = SPI_DIRECTION_2LINES;
ADC_SPI.Init.DataSize = SPI_DATASIZE_8BIT;
ADC_SPI.Init.CLKPolarity = SPI_POLARITY_LOW;
ADC_SPI.Init.CLKPhase = SPI_PHASE_2EDGE;//1EDGE or 2
ADC_SPI.Init.NSS = SPI_NSS_SOFT;
ADC_SPI.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
ADC_SPI.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;//2 is 20Mhz which is flat out for the ADC
ADC_SPI.Init.FirstBit = SPI_FIRSTBIT_MSB;
ADC_SPI.Init.TIMode = SPI_TIMODE_DISABLE;
ADC_SPI.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
ADC_SPI.Init.CRCPolynomial = 10;
ADC_SPI.Init.MasterKeepIOState=SPI_MASTER_KEEP_IO_STATE_ENABLE;
//New for DMA
ADC_SPI.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
//Configure the Peripheral
HAL_SPI_Init(&ADC_SPI);
/* Configure the DMA handler for Transmission process */
hdma_spi4_rx.Instance = DMA1_Stream0;
hdma_spi4_rx.Init.Request = DMA_REQUEST_SPI4_RX;
hdma_spi4_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi4_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi4_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi4_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi4_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi4_rx.Init.Mode = DMA_NORMAL;
hdma_spi4_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi4_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
HAL_DMA_Init(&hdma_spi4_rx);
__HAL_LINKDMA(&ADC_SPI,hdmarx,hdma_spi4_rx);
/* SPI4 interrupt Init */
HAL_NVIC_SetPriority(SPI4_DMA_TX_IRQn, 1, 1);
HAL_NVIC_EnableIRQ(SPI4_DMA_TX_IRQn);
/* NVIC configuration for DMA transfer complete interrupt (SPI1_RX) */
HAL_NVIC_SetPriority(SPI4_DMA_RX_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPI4_DMA_RX_IRQn);
/*##-5- Configure the NVIC for SPI #########################################*/
/* NVIC configuration for SPI transfer complete interrupt (SPI1) */
HAL_NVIC_SetPriority(SPI4_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(SPI4_IRQn);
}
2023-12-15 08:29 AM
A few pitfalls here:
See this for more information on the last two points:
https://community.st.com/t5/stm32-mcus/dma-is-not-working-on-stm32h7-devices/ta-p/49498
2023-12-22 01:34 AM
I'm still hopelessly stuck on this topic.
Played around with it for a few days now but not getting very far.
There doesn't seem to be much helpful documentation on what the SPI-DMA settings are doing within cube IDE, or how it is affecting the .ld file.
I'm relying on CubeIDE to configure the linker script correctly for me purposes...
Is there a very simple example for the H7 which might show how to read 27 bytes from the SPI bus when interrupted by a GPIO input. (The GPIO interrupt is working fine, but I can only read the SPI when the GPIO triggers)
/* USER CODE BEGIN 1 */
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi)
{
wTransferState = TRANSFER_COMPLETE;
/* Invalidate cache prior to access by CPU */
SCB_InvalidateDCache_by_Addr ((uint32_t *)aRxBuffer, BUFFERSIZE);
counter1++;
}
//Read all 8 channels
void SPI_ADC_DMA(void)
{
uint8_t Cmd[27] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
HAL_SPI_TransmitReceive_DMA(&hspi1, Cmd,aRxBuffer, 27);
// counter1++;
// while (wTransferState == TRANSFER_WAIT)
// {
// }
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if(spiHandle->Instance==SPI1)
{
/* USER CODE BEGIN SPI1_MspInit 0 */
/* USER CODE END SPI1_MspInit 0 */
/** Initializes the peripherals clock
*/
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_SPI1;
PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)
{
Error_Handler();
}
/* SPI1 clock enable */
__HAL_RCC_SPI1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**SPI1 GPIO Configuration
PA5 ------> SPI1_SCK
PA6 ------> SPI1_MISO
PA7 ------> SPI1_MOSI
*/
GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_6|GPIO_PIN_7;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF5_SPI1;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* SPI1 DMA Init */
/* SPI1_RX Init */
hdma_spi1_rx.Instance = DMA1_Stream0;
hdma_spi1_rx.Init.Request = DMA_REQUEST_SPI1_RX;
hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;
hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_rx.Init.Mode = DMA_NORMAL;
hdma_spi1_rx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
//
//
if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(spiHandle,hdmarx,hdma_spi1_rx);
/* SPI1_TX Init */
hdma_spi1_tx.Instance = DMA1_Stream1;
hdma_spi1_tx.Init.Request = DMA_REQUEST_SPI1_TX;
hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi1_tx.Init.Mode = DMA_NORMAL;
hdma_spi1_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)
{
Error_Handler();
}
__HAL_LINKDMA(spiHandle,hdmatx,hdma_spi1_tx);
/* SPI1 interrupt Init */
HAL_NVIC_SetPriority(SPI1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(SPI1_IRQn);
/* USER CODE BEGIN SPI1_MspInit 1 */
/* USER CODE END SPI1_MspInit 1 */
}
}
2023-12-22 05:33 AM
I would recommend disabling cache and getting started with blocking functions to get familiar with how the chip works. There are several SPI examples in the CubeMX repository, including ones that use DMA. You can use the Example Selector to open them.