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

 

 

 

 

17 REPLIES 17
TDK
Guru

TDK_0-1704478126479.png

No problems with MISO signal. The MOSI signal is still garbage.

If you have nothing connected to that pin during this test, the hardware is faulty (or your logic analyzer channel is broken. Swap channels to eliminate that possibility.). You'll have to get a new board.

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

It might be informative to take an analog capture of this signal (the GPIO output toggling test on the MOSI pin), though it won't solve the problem.

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

I tried swapping pins but as "expected" - one channel is broken. After the weekend, I will try a different logic analyzer and then consider buying a new board. I'll let you know about the results. Thank you! 

Oscilloscope pics are necessary, LA is good if software /protocol error, but pretty useless on this level of hardware debugging. You always can do loop back tests on the same SPI or cross-tests transmit-receive to-from another SPI on the same board.

RadoslawSajdak
Associate II

I got an oscilloscope and here's the result and other Logic Analyzer. Conclusion:
- Peaks came from a probably broken Logic Analyzer. Something was wrong internally, maybe just separation between channels.
- I noticed that every module I tried to use had pull-ups on every line (SCK/MISO/MOSI). After removing it I saw the correct signal BUT only in low-frequency signals. Let me explain with the pictures (sorry but my oscilloscope couldn't get a print screen...):
1) I achieved proper communication using both the HAL and registers approach.

a) BMP280 connected to the NUCLEO.

b) Pull-up resistors removed.

c) Oscilloscope probes connected to 2cm wires, soldered directly to the MCU.

d) Prescaler == 256 (15KBit/s)

e) Oscilloscope channel 1 - SCK; channel 2 - MOSI

 

RadoslawSajdak_0-1704659876455.png

RadoslawSajdak_1-1704659918963.jpeg

 

2) In my target project I will need higher SPI speeds. So I started to change it. Communication (digital) looks fine but I have noticed something alarming on the MOSI pin. The signal was affected by some capacitance.

a) BMP280 connected to the NUCLEO.

b) Pull-up resistors removed.

c) Oscilloscope probes connected to 2cm wires, soldered directly to the MCU.

d) Prescaler == 16 (250KBit/s)

e) Oscilloscope channel 1 - SCK; channel 2 - MOSI

RadoslawSajdak_2-1704660201150.jpeg

3) I changed the prescaler and now communication was impossible.

a) BMP280 connected to the NUCLEO.

b) Pull-up resistors removed.

c) Oscilloscope probes connected to 2cm wires, soldered directly to the MCU.

d) Prescaler == 2 (2MBbit/s)

e) Oscilloscope channel 1 - SCK; channel 2 - MOSI

RadoslawSajdak_3-1704660419674.jpeg

RadoslawSajdak_4-1704660447007.png

4) I thought the sensor could cause it so I removed it. Nothing changed. Some capacitance on MOSI line broke the signal. So here's my first question: What could cause the capacitance on MOSI pin if nothing is connected?

a) BMP280 NOT connected to the NUCLEO.

b) n.a.

c) Oscilloscope probes connected to 2cm wires, soldered directly to the MCU.

d) Prescaler == 2 (2MBbit/s)

e) Oscilloscope channel 1 - SCK; channel 2 - MOSI

RadoslawSajdak_5-1704660566175.jpeg

5) Then I soldered the resistors again and I got the result similar to that described last days. BUT Oscilloscope showed something weird. MOSI signal looked almost perfect but its amplitude was equal to half of expected. So when SCK was jumping between 0-3.3V, MOSI couldn't achieve 0V, oscillating between 3.3-2V. So if I manually wrote bits I got the expected 0xD0 but because 2V is too high to be recognized as LOW, I got 0xff and I couldn't communicate with the sensor. I have checked the sensor with atmega and it worked without any problems. So Do you have any idea, why MOSI with pull-ups couldn't go below 2V? I know SPI doesn't need pullup/down, but it should work with it. Especially with lower speeds. For me, it's not related because the signal is sharp and right placed.

a) BMP280 connected to the NUCLEO.

b) Resistors soldered to BMP280 (SCK/MISO/MOSI; 10kOhm)

c) Oscilloscope probes connected to 2cm wires, soldered directly to the MCU.

d) Prescaler == 256 (15KBbit/s)

e) Oscilloscope channel 1 - MOSI; channel 2 - SCK

RadoslawSajdak_6-1704660823673.jpeg

RadoslawSajdak_7-1704660948301.png

 

 

 

 

 

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".

@TDK You're right. The other pin works well with 2MBit/s. It doesn't matter how I set the pin frequency. How did you know that? Is the 2V value with resistors related? Or only because of capacitance?

MasterT
Lead

Check MOSI if nothing connected again.

My guess, is that sensor is likely a counterfait build on cheap uCPU that emulates SPI protocol by GPIO bit banging. If GPIO is periodicaly set to output instead of input, than two outputs are fighting for logic state. AtMega just have more power to overwrite wrong pin state.