2014-08-06 11:23 AM
Background:
- I have a system with two STM32F407 processors communicating via SPI. - I am using the HAL drivers generated by STMCube - They use the same firmware and adjust their behavior into master or slave mode depending on the state of a pin at startup. - On startup they attempt to synchronize by performing a full duplex SPI exchange via DMA transfer and comparing the results. - After the SYNC the slave calls HAL_SPI_ReceiveDMA() to prepare to receive a command from the master - On a user input, the master sends a a command to the slave via HAL_SPI_TransmitDMA(). - The command should be a 3 byte transfer, in this case 0x42 0x00 0x03. A logic analyzer confirms the master transmits this correctly. Problem: - The slave 'receives' 0x03 0x00 0x00. This is the contents of the register when accessed from the SPI RX Complete callback. Some Relevant Code: - SPI Initialization/* SPI1 init function */
voidMX_SPI_Init(
void) {
hspi.Instance = SPI_NUM; if(isDevice ==
true) {
hspi.Init.Mode = SPI_MODE_MASTER; hspi.Init.NSS = SPI_NSS_HARD_OUTPUT; } else{
hspi.Init.Mode = SPI_MODE_SLAVE; hspi.Init.NSS = SPI_NSS_SOFT; } hspi.Init.Direction = SPI_DIRECTION_2LINES; hspi.Init.DataSize = SPI_DATASIZE_8BIT; hspi.Init.CLKPolarity = SPI_POLARITY_LOW; hspi.Init.CLKPhase = SPI_PHASE_1EDGE; hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256; hspi.Init.FirstBit = SPI_FIRSTBIT_MSB; hspi.Init.TIMode = SPI_TIMODE_DISABLED; hspi.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; //SPI_CRCCALCULATION_ENABLED;hspi.Init.CRCPolynomial = 469;
HAL_SPI_Init(&hspi); SPI_Initialize(&hspi); } - SPI DMA Initvoid
HAL_SPI_MspInit(SPI_HandleTypeDef* hspi) {
/* GPIO Init code */ /* Peripheral DMA init*/ hdma_spi_rx.Instance = SPI_DMA_RX_STREAM; hdma_spi_rx.Init.Channel = SPI_DMA_RX_CHANNEL; hdma_spi_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; hdma_spi_rx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi_rx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_spi_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_spi_rx.Init.Mode = DMA_NORMAL; hdma_spi_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_spi_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_DeInit(&hdma_spi_rx); HAL_DMA_Init(&hdma_spi_rx); __HAL_LINKDMA(hspi, hdmarx, hdma_spi_rx); hdma_spi_tx.Instance = SPI_DMA_TX_STREAM; hdma_spi_tx.Init.Channel = SPI_DMA_TX_CHANNEL; hdma_spi_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; hdma_spi_tx.Init.PeriphInc = DMA_PINC_DISABLE; hdma_spi_tx.Init.MemInc = DMA_MINC_ENABLE; hdma_spi_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; hdma_spi_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; hdma_spi_tx.Init.Mode = DMA_NORMAL; hdma_spi_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH; hdma_spi_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; HAL_DMA_DeInit(&hdma_spi_rx); HAL_DMA_Init(&hdma_spi_tx); __HAL_LINKDMA(hspi, hdmatx, hdma_spi_tx); /* Peripheral interrupt init*/ /* Sets the priority grouping field */ HAL_NVIC_SetPriorityGrouping(GLOBAL_IRQ_PRI_GROUP); HAL_NVIC_SetPriority(SPI_IRQn, SPI_IRQ_PREEMPT_PRI, SPI_IRQ_SUB_PRI); HAL_NVIC_EnableIRQ(SPI_IRQn); } - Setup for slave to receive a command:static
voidWaitForCommand(
void) {
printf(
''Waiting for command...\n\r'');
spiEngine.state = WAITING_FOR_CMD; HAL_StatusTypeDef status = HAL_SPI_Receive_DMA(spiEngine.handle, rxCmdBuffer, SPI_CMD_LEN); if(status != HAL_OK) {
Error_Handler(); } if(isDevice) {
SPI_SendHostReadySignal(); } } - Command receive buffer definition:static
uint8_t rxCmdBuffer[3];
Since the synchronization at the beginning functions properly, I do not believe there is a problem with the configuration of the SPI on either end, especially since the master transmits correctly. Perhaps there is something happening where the slave is in some faulty state? Is there a register I should clear or access to get things moving properly? Insights and suggestions are most welcome. Thankyou. EDIT 1: I noticed that if I set the receive transfer size to 1, the value in the buffer is the expected first byte. #dma #stm32f4 #spi #error2014-08-12 05:08 PM
I traced the problem down to the call I have for
HAL_DMA_DeInit()
prior to the initialization call. Apparently the DeInit function puts the DMA into some state the Init isn't able to properly recover from.