STM32 HAL_SPI_TransmitReceive_DMA restart bug
А вот и есть: рукожопость. Если внутри HAL_SPI_TxRxCpltCallback снова вызвать HAL_SPI_TransmitReceive_DMA, то трансфер никогда не завершится.
А вот почему? Изначально не понятно, я же хорошо написал код, захендлил все Error code-ы библиотеки и если что-то не так, то я бы увидел в терминале ошибку и код автоматом бы мне вызвал breakpoint. Но всё вроде как ок, ошибок нет!
Проверил под дебаггером – да, HAL_SPI_TransmitReceive_DMA во второй раз возвращает HAL_OK! Статусы/регистры все сконфигурены корректно в SPI, стейт BUSY но прерываний нет… о_О
Но не стоит недооценивать разработчиков HAL библиотеки, они те ещё рукожопы. Вспомнил я как несколько лет назад писал им в саппорт и уведомлял о баге, но конечно же его не починили )
Часть кода функции HAL_SPI_TransmitReceive_DMA:
/* Set the DMA AbortCpltCallback */
hspi->hdmarx->XferAbortCallback = NULL;
/* Enable the Rx DMA Stream/Channel */
HAL_DMA_Start_IT(hspi->hdmarx, (uint32_t)&hspi->Instance->DR, (uint32_t)hspi->pRxBuffPtr, hspi->RxXferCount);
/* Enable Rx DMA Request */
SET_BIT(hspi->Instance->CR2, SPI_CR2_RXDMAEN);
HAL_DMA_Start_IT возвращает код ошибки, который благополучно игнорируется! И кажется, что всё ОК )) А на самом деле HAL_SPI_TxRxCpltCallback вызывается из прерывания RX DMA канала, а обработчик TX канала ещё не вызывался к этому моменту (он вызовется после RX канала). И получается, что в колбэке RX DMA канала я перезапускаю передачу, которая не смогла запустить TX DMA канал (он ещё не разлочен своим обработчиком прерывания) и потому всё висит.
Это восхитительно. Мало того, что TX прерывания ещё не было, но уже вызвался HAL_SPI_TxRxCpltCallback , так ещё и коды ошибок нагло игнорируются, вводя в глубочайшее заблуждение. Вот как так? Железо у ST отличное, а код – говно…