Skip to main content
Explorer II
January 4, 2024
Solved

R/W SPI with STM32H743

  • January 4, 2024
  • 9 replies
  • 6539 views

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

 

 

 

 

    This topic has been closed for replies.
    Best answer by TDK

    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.

    9 replies

    Super User
    January 4, 2024

    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.

     

    Explorer II
    January 4, 2024

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

    Super User
    January 4, 2024

    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.

    Explorer II
    January 5, 2024

    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.

     

     

    Explorer
    January 5, 2024

    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

    Explorer II
    January 5, 2024

    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

     

    Explorer
    January 5, 2024

    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.

    Explorer II
    January 5, 2024

    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

     

    Super User
    January 5, 2024

    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.

    Super User
    January 5, 2024

    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.

    Explorer II
    January 7, 2024

    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

     

     

     

     

     

    TDKAnswer
    Super User
    January 7, 2024

    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.

    Explorer II
    January 7, 2024

    @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?

    Explorer
    January 7, 2024

    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.