cancel
Showing results for 
Search instead for 
Did you mean: 

R/W SPI with STM32H743

RadoslawSajdak
Associate II

Hi everyone!
It's my first post and I'm trying to make something with the SPI but I met the problems. Even if I configure the interface (hopefully correctly), I can't communicate with any SPI device. I bought BMP280 as a simple sensor to communicate with. What I'm trying to do is to read DevID. It should be done by writing 0xD0 and then reading a byte (expected 0x58).

But it's not working at all. Using logic-level analyzer I have noticed something weird - bytes sent by SPI are delayed by about half a period of the signal. About, because it's not equal between the next attempts... I have set CPOL=CPHA=0 on both STM32H7 and the analyzer. If I change one side to CPOL=0 && CPHA=1 then I get the expected data (decoded) but only sometimes and only on the MOSI (0xD0 sent). The screens below show both situations.
CPOL=CPHA=0 Both

RadoslawSajdak_0-1704395076266.png

CPOL=0 CPOHA=1 One side

RadoslawSajdak_1-1704395232572.png

I have checked connections, I have checked the sensor (with the different MCU, not STM), and I have checked different pin configurations. I even tried to use AruinoSPI with PlatformioIDE. No matter what am I doing I'm getting similar results - random bits on the SPI...
I have also checked errata (2.22) for this MCU [Errata URL]  but I don't think that anything is similar to my "problem".

I was looking for hints in the datasheet and application notes without success. I saw 
Could you please take a look at my code? I believe I missed something key but I have no idea what it could be...
Please let me know if you have any advice. If somebody could share a similar sample (nucleo+simple, single SPI sensor, or even SD card) I would be grateful.

My setup:
- Nucleo-H743ZI2
- BMP280
- CubeIDE Version: 1.14.0 Build: 19471_20231121_1200 (UTC)
- FW: STM32Cube FW_H7 V1.11.1 (V1.11.0 has no difference)

I am attaching .tar and .7z libraries with my entire project. Most of the code is generated by CubeMX.
Crucial fragments are below:

 

 

 

void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Supply configuration update enable
  */
  HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);

  /** Configure the main internal regulator output voltage
  */
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE3);

  while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_BYPASS;
  RCC_OscInitStruct.HSIState = RCC_HSI_DIV4;
  RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 1;
  RCC_OscInitStruct.PLL.PLLN = 24;
  RCC_OscInitStruct.PLL.PLLP = 2;
  RCC_OscInitStruct.PLL.PLLQ = 48;
  RCC_OscInitStruct.PLL.PLLR = 2;
  RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
  RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
  RCC_OscInitStruct.PLL.PLLFRACN = 0;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
                              |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
  RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
  RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV1;
  RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
  {
    Error_Handler();
  }
}
int main(void)
{
  /* MCU Configuration--------------------------------------------------------*/
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_SPI2_Init();

  printf("Start\n");
  HAL_Delay(1000);

  while (!((SPI2->SR)&SPI_SR_TXP)) {};
  SPI2->CR2 |= (SPI_CR2_TSIZE & 2); // Config size 1
  SPI2->CR1 |= SPI_CR1_SPE; //Enable SPI
  SPI2->CR1 |= SPI_CR1_CSTART; //Start transaction
  HAL_GPIO_WritePin(BMP_CS_GPIO_Port, BMP_CS_Pin, 0);

  HAL_Delay(1);
  printf("CS 0\n");
  uint8_t temp = 0;
  if(SPI2->SR & SPI_SR_TXP) // Enough space in FIFO
  {
    SPI2->TXDR = 0xd0 | 0x80;
    while (!((SPI2->SR)&SPI_SR_TXP)) {};
    SPI2->TXDR = 0xff;
    printf("DR loaded 0x0d\n");
    while (!((SPI2->SR)&SPI_SR_RXP)) {}; //Waiting for rcv in fifo
    temp = SPI2->RXDR;
    printf("Dummy 0x%02x\n", temp);
    temp = SPI2->RXDR;
    printf("Got 0x%02x\n", temp);
  }
  while(!(SPI2->SR & SPI_SR_EOT)){}; //Wait for end of transaction
  printf("SR empty EOT flag\n");
  SPI2->CR1 &= ~SPI_CR1_SPE; //Disable SPI

  while (1)
  {
  }
}
void MX_GPIO_Init(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOC_CLK_ENABLE();
  __HAL_RCC_GPIOH_CLK_ENABLE();
  __HAL_RCC_GPIOB_CLK_ENABLE();
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOE_CLK_ENABLE();

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(GPIOB, LD1_Pin|LD3_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(BMP_CS_GPIO_Port, BMP_CS_Pin, GPIO_PIN_SET);

  /*Configure GPIO pin Output Level */
  HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = B1_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  HAL_GPIO_Init(B1_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pins : PBPin PBPin */
  GPIO_InitStruct.Pin = LD1_Pin|LD3_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = BMP_CS_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_PULLUP;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
  HAL_GPIO_Init(BMP_CS_GPIO_Port, &GPIO_InitStruct);

  /*Configure GPIO pin : PtPin */
  GPIO_InitStruct.Pin = LD2_Pin;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
  HAL_GPIO_Init(LD2_GPIO_Port, &GPIO_InitStruct);
}
void MX_SPI2_Init(void)
{
  hspi2.Instance = SPI2;
  hspi2.Init.Mode = SPI_MODE_MASTER;
  hspi2.Init.Direction = SPI_DIRECTION_2LINES;
  hspi2.Init.DataSize = SPI_DATASIZE_8BIT;
  hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
  hspi2.Init.CLKPhase = SPI_PHASE_1EDGE;
  hspi2.Init.NSS = SPI_NSS_SOFT;
  hspi2.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
  hspi2.Init.FirstBit = SPI_FIRSTBIT_MSB;
  hspi2.Init.TIMode = SPI_TIMODE_DISABLE;
  hspi2.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
  hspi2.Init.CRCPolynomial = 0x0;
  hspi2.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
  hspi2.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
  hspi2.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
  hspi2.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
  hspi2.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
  hspi2.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
  hspi2.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
  hspi2.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
  hspi2.Init.IOSwap = SPI_IO_SWAP_DISABLE;
  if (HAL_SPI_Init(&hspi2) != HAL_OK)
  {
    Error_Handler();
  }
}

 

 

 

 

1 ACCEPTED SOLUTION

Accepted Solutions

It sounds like your MOSI pin is damaged, particularly the high-side protection diode. No fix for that but to get a new chip, or use a different pin.

Perhaps it was damaged by the same thing that damaged the logic analyzer channel, or perhaps the bad logic analyzer channel damaged it.

Double check that the MOSI pin frequency is set to very high, or set to the same as the SCK pin, but I doubt that's the problem.

If you feel a post has answered your question, please click "Accept as Solution".

View solution in original post

17 REPLIES 17
TDK
Guru

Looks like a hardware issue, not a code issue. Looks like MOSI and MISO pins are shorted high, or something else is competing for their use.

Which pins? Check the schematic to ensure these pins are available for use and not being used by something else. Very likely this is the issue.

 

If you feel a post has answered your question, please click "Accept as Solution".
RadoslawSajdak
Associate II

@TDK Thank you for your attention!
I have tried the different pinouts with the same result. Currently I'm using:
- PC2_C - MISO
- PC3_C - MOSI
- PD3 - SCK
- PB9 - CS
Due to the datasheet PC2/3 are dedicated for SPI2 (which I'm using). Is it possible that driver/sdk is changing pin function somewhere deeper? It would be ridiculous but I believe not impossible.

My second idea is the logic-level analyzer. It's cheap but it shouldn't affect the signals. But maybe it is? Could you take a look at the main() function? If it should work I'll try to get the better device and check it after a weekend...

PC2 and PC3 are free on that board.

Disconnect the BMP280 and look the readings again. If MOSI looks correct, issue is in how BMP280 is hooked up. How is the BMP280 board hooked up exactly? What board is it?

Logic analyzer isn't the issue here--the SCK line looks perfect.

If you feel a post has answered your question, please click "Accept as Solution".

I have followed your advice but it's not the problem. Okay - this time I've got proper readings every time (0xD0 on MOSI) but ONLY if I set CPOL=0 && CPHA=1 on the one side.

RadoslawSajdak_0-1704460481349.png
I'm using module from Botland  and here's the Datasheet.

The connection is:

STM32 | BMP
PC2_C -> SD0 (MISO)
PC3_C -> SDA(MOSI)
PD3 -> SCL
PB9 -> CSB
3V3 -> VCC
GND -> GND

But as I mentioned - the behavior without the sensor is similar. Short peaks on the MOSI line are also confusing for me.

 

 

Sebastiaan
Senior

I've used SPI plenty of times, and this pattern on the MOSI is not normal. Was this monitored with the BMP disconnected? If not please, do that first to verify your MOSI output.

Then you can hook up the BMP again. If the BMP messes up the MOSI signal, it means that it's incorrectly connected.

Another thing that could help is to set CS high and low again after each transfer, if there's any clock mismatch between the 2 devices, that should recover it. Make sure it's long enough (so use HAL_Delay(1)).

Also, why are you not using the HAL SPI functions? For example HAL_SPI_TransmitReceive?

 

Best regards,

Sebastiaan

Those are not good signals. SCK is good, but MOSI and MISO should not be spikes.

Without the BMP280 connected, try initializing PC2_C and PC3_C as GPIO outputs and toggling them to verify the hardware can actually drive those pins correctly.

If you feel a post has answered your question, please click "Accept as Solution".
RadoslawSajdak
Associate II

My previous answer in measured without BMP connected. Only the logic-level analyzer and board.
@Sebastiaan I decided to use registers instead of HAL because I had the same problems with it so I thought maybe something was wrong with SDK.
I have changed main() to HAL:

int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART3_UART_Init();
  MX_SPI2_Init();

  printf("Start\n");
  HAL_Delay(1000);
  uint8_t tx_data[32], rx_data[32];
  tx_data[0] = 0xd0;
  tx_data[1] = 0xff;

  HAL_GPIO_WritePin(BMP_CS_GPIO_Port, BMP_CS_Pin, 0);
  HAL_Delay(100);
  HAL_SPI_TransmitReceive(&hspi2, tx_data, rx_data, 2, HAL_MAX_DELAY);
  HAL_GPIO_WritePin(BMP_CS_GPIO_Port, BMP_CS_Pin, 1);

  while (1)
  {
  }
}

But the result is similar (peaks and mismatches in CPOL/CPHA)

RadoslawSajdak_0-1704466047854.png


@TDK I have changed main to toggle the pins:

MX_GPIO_Init()
{
...
  /*Configure GPIO pins : PC2 PC3 */
  GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
  GPIO_InitStruct.Pull = GPIO_NOPULL;
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;
  HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
...
}
int main(void)
{
  HAL_Init();
  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART3_UART_Init();

  printf("Start\n");
  HAL_Delay(1000);
  for(int i = 0; i < 16; i++)
  {
	  HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_2);
	  HAL_Delay(1);
  }
  while(1){}
}

And something happened... I've peaks on MOSI, switching MISO

RadoslawSajdak_1-1704466655272.png

But everything is okay while switching MOSI

RadoslawSajdak_2-1704466727122.png

So It's not short between lines. It happens even if I disconnect MISO from the analyzer while switching.

RadoslawSajdak_3-1704466869386.png

 

Sebastiaan
Senior

That's a good suggestion of @TDK, and shows there's a certain type of coupling.

You've never mentioned on what kind of platform you're working, that's becoming more important now. Is it a custom board, or an stm32 nucleo board? Or something else? Even if there's no short, there might be another component connected to the same ports? Can you look in the schematics?

Also, the glitches on the MOSI while doing the SPI transfer via HAL library are not the same anymore, they're only seen on the first byte now. Not sure what's the reason for that, maybe it's due to the CS that you're using now. You could also try to repeat the toggle test on the clock, and see if you see again the same glitches on MOSI.

But all of this is pointing towards some board issue, the code itself seems fine.

RadoslawSajdak
Associate II

Sorry, but I forgot about it before. Switching SCK also results in MOSI peaks.

RadoslawSajdak_0-1704473442074.png

I'm using Nucleo-H743ZI2 (NUH743ZI$AT3). I looked at the schematics before I posted (schematics). Nothing is connected to PC2/3 or PD3. PD3 can be used with USART as a CTS but I'm not using Flow Control. To make sure I removed USART from my code but nothing changed (peaks are present as above).

Just for the test, I have switched to Hardware NSS but nothing changed.
(CPOL=0 && CPHA=1)

RadoslawSajdak_1-1704474362789.png