2021-12-01 03:38 AM
Hello,
I am working stm32mp157c. I want to send the data coming from ipcc to m4 to another chip with spi.
My code is;
void MX_SPI4_Init(void)
{
hspi4.Instance = SPI4;
hspi4.Init.Mode = SPI_MODE_MASTER;
hspi4.Init.Direction = SPI_DIRECTION_2LINES_TXONLY;
hspi4.Init.DataSize = SPI_DATASIZE_8BIT;
hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi4.Init.CLKPhase = SPI_PHASE_2EDGE;
hspi4.Init.NSS = SPI_NSS_HARD_OUTPUT;
hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi4.Init.CRCPolynomial = 0x0;
hspi4.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
hspi4.Init.NSSPolarity = SPI_NSS_POLARITY_HIGH;
hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
hspi4.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi4.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
hspi4.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
hspi4.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
hspi4.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
hspi4.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
hspi4.Init.IOSwap = SPI_IO_SWAP_DISABLE;
if (HAL_SPI_Init(&hspi4) != HAL_OK)
{
Error_Handler();
}
}
void MX_DMA_Init(void)
{
/* DMA controller clock enable */
__HAL_RCC_DMAMUX_CLK_ENABLE();
__HAL_RCC_DMA2_CLK_ENABLE();
/* DMA interrupt init */
/* DMA2_Stream0_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn);
/* DMA2_Stream1_IRQn interrupt configuration */
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 1, 0);
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
}
void HAL_SPI_MspInit(SPI_HandleTypeDef* spiHandle)
{
...
/* SPI4 DMA Init */
/* SPI4_TX Init */
hdma_spi4_tx.Instance = DMA2_Stream1;
hdma_spi4_tx.Init.Request = DMA_REQUEST_SPI4_TX;
hdma_spi4_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;
hdma_spi4_tx.Init.PeriphInc = DMA_PINC_DISABLE;
hdma_spi4_tx.Init.MemInc = DMA_MINC_ENABLE;
hdma_spi4_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;
hdma_spi4_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;
hdma_spi4_tx.Init.Mode = DMA_NORMAL;
hdma_spi4_tx.Init.Priority = DMA_PRIORITY_LOW;
hdma_spi4_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
...
}
int main()
{
MX_SPI4_Init();
MX_DMA_Init();
VIRT_UART_Init(&huart0);
VIRT_UART_RegisterCallback(&huart0, VIRT_UART_RXCPLT_CB_ID, data_receive)
while (1)
{
...
}
}
void data_receive(VIRT_UART_HandleTypeDef *huart)
{
uint8_t buffer[1000] = { 0 };
uint16_t recSize = huart->RxXferSize < MAX_BUFFER_SIZE ? huart->RxXferSize : MAX_BUFFER_SIZE-1;
memcpy(buffer, huart->pRxBuffPtr, recSize);
if (GL.spi[SPI_MOD]->State == HAL_SPI_STATE_READY)
{
HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);
}
}
As the data size from ipcc(data_receive) increases, hal_spi_transmit_dma stucks. But when i use hal_spi_transmit instead of hal_spi_transmit_dma stuck does not occur.
Why do you think hal_spi_transmit_dma could cause such a thing?
Best Regards,
Mesut Ince
2021-12-01 04:13 AM
Note: some time after using hal_spi_transmit_dma Spi state never turn in ready. Even when I reset the m4, the situation does not change. until i reset the a7. (i guess this problem occur spi clock. Because a7 side in chip sets peripheral clocks.)
2021-12-01 08:22 AM
Hi,
did you ensure the DMA is finished when your restart it ?
Might be better to have a clean 'flag' set by SPI call back interrupt instead of polling the SPI state.
e.g. something like:
bool volatile DMA_Finished = true;
.......
if (DMA_Finished == true)
{
DMA_Finished = false;
HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);
}
......
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
DMA_Finished = true;
}
For the mis-restart of M4 application, rhis is a know behavior as peripherals are not reset when M4 is restarted (and HAL could fail to init then a second time).
Could be easily overcome by using some 'manual' reset before your inits.
e.g. something like:
// ensure clear any pending peripherals settings, interrupt or dmas
hspi4.Instance = SPI4;
HAL_SPI_DeInit(&hspi4);
HAL_SPI_MspDeInit(&hspi4);
HAL_NVIC_DisableIRQ(SPI4_IRQn);
__HAL_RCC_SPI4_FORCE_RESET();
__HAL_RCC_SPI4_RELEASE_RESET();
HAL_NVIC_DisableIRQ(DMA2_Stream1_IRQn);
__HAL_RCC_DMA2_FORCE_RESET();
__HAL_RCC_DMA2_RELEASE_RESET();
// then regular init could be done
MX_SPI4_Init();
MX_DMA_Init();
VIRT_UART_Init(&huart0);
Regards.
2021-12-01 11:00 PM
Hi @PatrickF ,
Thank you for your supporting.
M4 reboot problem solved.
But when I added DMA_Finished control, there was no improvement.
Best Regards
Mesut Ince
2021-12-01 11:29 PM
Hi,
I'm puzzle with this line
HAL_SPI_Transmit_DMA(buffer, buf_addr, MPEGTS_PACKET_SIZE);
which should be in the form
HAL_SPI_Transmit_DMA(&hspi4, buffer, MPEGTS_PACKET_SIZE);
Maybe 'buffer' should be better declared as a global variable to avoid potential memory reallocation and corruption during the DMA background execution.
Furthermore, sound strange to have the 'memcpy' before the check than previous 'buffer' transfer is finished.
Need to debug step by step on your side, but I think one of the usual cause of hal_spi_transmit_dma() stuck is the issue of a new DMA transfer command while the previous is not finished. This is why I recommended to use the HAL_SPI_TxCpltCallback.
It is also recommended to check any HAL_*** return value with != HAL_OK to check for returned errors.
Any chances to debug using GPIOs set/clr around HAL_SPI_Transmit_DMA() and an oscilloscope to see real time SPI transfer timings ?
Regards.
2021-12-01 11:46 PM
Hi @PatrickF ,
I'm sorry, I mistyped while copy-pasting. In fact, the code is
HAL_SPI_Transmit_DMA(&hspi4, buffer, MPEGTS_PACKET_SIZE);
When I measure spi_clock with an oscilloscope, It stays drawn to gnd while in the stuck state.
Best Regards
Mesut Ince
2021-12-01 11:57 PM
Note: i'm checking hspi4->state in code.
if (&hspi4>State == HAL_SPI_STATE_READY)
{
HAL_SPI_Transmit_DMA(&hspi4, buffer, MPEGTS_PACKET_SIZE);
}
hspi->State is HAL_SPI_STATE_BUSY_TX while in the stuck state. Never get into if state.
2021-12-03 07:33 AM
Hi @PatrickF ,
We are testing spi dma 3Mbit/s data rate. After a while dma lock never turn unlock and not return errorcode.
I added the main;
int main ()
{
...
while(1)
{
...
if (HAL_GetTick () - lastReadySpiDma)
{
HAL_SPI_Abort(&hspi4);
}
....
}
...
}
Above code solved spi dma stuck problem. but why spi dma stays locked at 3Mbit/s data rate. I wonder if it's missing irq.
Why stays locked?
Best Regards
Mesut Ince
2021-12-03 07:34 AM
Note: The code is actually
int main ()
{
...
while(1)
{
...
if (HAL_GetTick () - lastReadySpiDma > 100)
{
HAL_SPI_Abort(&hspi4);
}
....
}
...
}
2021-12-06 12:23 AM
Hi,
maybe try to enable FIFO
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
....
hdma_spi4_tx.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
hdma_spi4_tx.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
hdma_spi4_tx.Init.MemBurst = DMA_MBURST_SINGLE;
hdma_spi4_tx.Init.PeriphBurst = DMA_PBURST_SINGLE;
....
Did to try adding a debug wait time in between each HAL_SPI_Transmit_DMA() ?
This might highlight that there is some real time issue (e.g. start a new DMA when previous not completely finished).
Regards.