STM32H743II SPI+DMA malfunction
I am porting a firmware from STM32F2/F4 to a H7 (STM32H743IIT6) platform on a custom board. There is an SST26VF064B-104I/SM flash on the boards with custom drivers with FAT FS file system driven by SPI and DMA. It works perfectly on older boards since many years, but not on the new one.
My problem is the SPI and/or the DMA peripheral goes insane after a single transmission (without reception) shoot.
I send a 0x00 (nop command) to the flash with single transmission.
After that I send a 0x9F command (read ID) to the flash and read 3 bytes, but it not works.
On a logic analyzer I see perfect signals and ID number.
If I swap the HAL_SPI_Transmit_DMA to HAL_SPI_TransmitReceive_DMA for nop operation,
the read ID transfer works correctly.
An other interesting situation is, if I take a breakpoint near after the line 1535:
SET_BIT(hspi->Instance->CR1, SPI_CR1_CSTART);
the following read ID works correctly.
I have no idea what the hell is going on!
All register is in OK state, except one:
In stm32h7xx_hal_spi.c HAL_SPI_TransmitReceive_DMA after HAL_SPI_Transmit_DMA till line 1530 everything is OK, but that line
1530 __HAL_SPI_ENABLE(hspi); triggers the RX DMA reception instantly before the SPI_CR1_CSTART and starting of TX DMA. So all date in the reception buffer is zero.
It is unable to set the RX DMA EN bit manually, because it goes to zero instantly.
I check the errata sheet and I found a paragraph:
2.10.1 Spurious DMA Rx transaction after simplex Tx traffic
It seems my problem is similar that description:
"Description
With empty RXFIFO, SPI/I2S can spuriously generate a DMA read request upon enabling DMA receive traffic (by setting RXDMAEN bit), provided that the preceding completed transaction is a simplex transmission.
Workaround
Before enabling DMA Rx transfer following a completed Tx simplex transfer, perform hardware reset of the SPI/I2S peripheral."
But the state of peripherals is unable the restore with any register magic even if HAL_Init(),
only hardware reset brings them back to the live.
I think this is a critical problem, and I have no workaround to manage this issue.
Please help me somebody!
My details:
- STM32H743IIT6 rev Y
- SST26VF064B-104I/SM
- SPI4 with RX-DMA1/0 TX-DMA1/1
- CubeMX 4.27.0 generated project with HAL 1.3.0
- My project is a test project now, and no other code in the firmware except SPI and DMA.
- Variables lays in AXI SRAM at 0x24000000 and no DCache enabled. I checked on 0x30000000 too.
- KEIL MDK 5
My app.c source (called from CubeMX generated main.c) is:
#include "stm32h7xx_hal.h"
#include "stm32h7xx_hal_spi.h"
#include "main.h"
#define DMA_BUFFER __attribute__((section(".dmabuffer"))) __align(32)
extern SPI_HandleTypeDef hspi4;
extern DMA_HandleTypeDef hdma_spi4_rx;
extern DMA_HandleTypeDef hdma_spi4_tx;
uint8_t DMA_BUFFER SPI_Buffer[8];
volatile int SPI_Complete = 0;
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi) { SPI_Complete = 1; }
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi) { SPI_Complete = 1; }
void HAL_SPI_TxRxCpltCallback(SPI_HandleTypeDef *hspi) { SPI_Complete = 1;}
void SPI_WaitForComplete(void)
{
uint32_t tick, tickstart = HAL_GetTick();
do tick = HAL_GetTick();
while ((!SPI_Complete) && (tick - tickstart < 2));
SPI_Complete = 0;
HAL_GPIO_WritePin(MEM_NSS0_GPIO_Port, MEM_NSS0_Pin, GPIO_PIN_SET);
}
void Flash_SendNop(void)
{
SPI_Buffer[0] = 0x00;
HAL_GPIO_WritePin(MEM_NSS0_GPIO_Port, MEM_NSS0_Pin, GPIO_PIN_RESET);
HAL_SPI_Transmit_DMA(&hspi4, SPI_Buffer, 1); // this line kills the hardware
//HAL_SPI_TransmitReceive_DMA(&hspi4, SPI_Buffer, SPI_Buffer, 1); // with this line it works correctly
//HAL_Delay(1); // delay doesn't fix the problem
SPI_WaitForComplete(); // breakpoint here, fix the problem, all breakpoint after SPI_CR1_CSTART is OK
}
int Flash_ReadID(void)
{
//HAL_SPI_Init(&hspi4); // this is not help
HAL_Init();
SPI_Buffer[0] = 0x9F;
HAL_GPIO_WritePin(MEM_NSS0_GPIO_Port, MEM_NSS0_Pin, GPIO_PIN_RESET);
HAL_SPI_TransmitReceive_DMA(&hspi4, SPI_Buffer, SPI_Buffer, 4);
SPI_WaitForComplete();
if ((SPI_Buffer[1] == 0xbf) && (SPI_Buffer[2] == 0x26) && (SPI_Buffer[3] == 0x43))
return 0;
else
return -1;
}
void SPI_Test(void)
{
Flash_SendNop();
Flash_ReadID();
}
void AppRun(void)
{
SPI_Test();
HAL_Delay(1);
}