cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H743II SPI+DMA malfunction

laszpar
Associate II

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);
}

8 REPLIES 8
laszpar
Associate II

I know this article, and it helped many at start with H7, but it is useless know for this specific problem.

Joerg Wagner
Senior III

Something is strange but I don't know if it's in the hardware or HAL.

My application does not use DMA or IT, so variables are all in D1 domain.

I have IC's as slaves working perfect together with STM32F767.

Some of them with H743ZI (version Y) not and I still don't why.

I am having a similar or same problem. I am using a Nucleo-H743ZI board.

Another thread suggested to try the two board SPI full duplex DMA transmit example program from repository STM32Cube_FW_H7_V1.3.0. The project was generated with STM32CubeMX version 5.0.1.

I have only the one Nucleo, so I compiled the project SPI_FullDuplex_ComDMA set as master. This example is intended to transmit a message from one board as a master to another board as a slave. Since I don't have another board, I simply scoped the SCK pin and I see nothing when the user button is pushed (which is supposed to start the transmission). I also changed the baud divider to 256 so that the burst is more obvious.

If I use the polling version of the example instead, I see the clock burst - so I know I'm scoping the correct pin.

Is there a hardware problem? Is there a firmware problem? Is there a problem in the example code? I used the example to eliminate problems I might cause with my own code.

Would recommend you getting in contact with an FAE working out of a local sales office.

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
laszpar
Associate II

I think it is hardware issue.

I have no solution, but worked around the problem.

My all transfer is rx-tx style. When I need tx-only transfer, I give an 1-byte dummy buffer for reception with switching off the incrementation of destination memory pointer. In this case, I protect the original transmit buffer from incoming zeros. For rx-tx transfers I switch back the poiner incremenatation.

This cause some extra DMA initialization work and plus IT run time, but this is the only solution I found.

Thank you Clive and laszpar.

I also believe the issue is hardware, especially after trying the example code.

I will contact an FAE to see what they already know and could be working on.

In the meantime, it turns out I need to rethink using DMA for this particular application, but others I have planned could benefit from working DMA. The way the receiver chip works, I would need to initiate 8 DMA operations which would require the app to field 8 interrupts anyway. SPI transmit under interrupt control is working so this app can go forward, but as said, I still want DMA for SPI for future apps.

Thanks again.

Interested too. Please share the result.