1
\$\begingroup\$

I have been taking a udemy course on STM32F4. The course uses a different board than the one I have but from same family STM32F4. I couldn't make the SPI driver developed in the course to work in my board, so I tried t0 first test it using HAL. I am using this video as a reference to communicate to L3GD20 Gyro in the development board. What I'm doing this is writing 0X11 to the CTRL_REG1(0x20) of the Gyroscope and then reading this register to check whether the value is written successfully or not. I could do that in HAL code

// ***** Spi Transmit ***** //
    // 1. Bring slave select low
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
    // 2. Transmit register + data
    spiTxBuf[0] = 0x20;
    spiTxBuf[1] = 0X11;
    HAL_SPI_Transmit(&hspi5, spiTxBuf, 2, 50);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);

    // ***** Spi Receive ***** //
    // 1. Bring slave select low
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
    // 2. Transmit register + data
    spiTxBuf[0] = 0x20 | 0x80;
    HAL_SPI_Transmit(&hspi5, spiTxBuf, 1, 50);
    // 3. Receive data
    HAL_SPI_Receive(&hspi5, spiRxBuf, 1, 50);
    // 4. Bring slave select high
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

}

Above code works

But to learn the register level code I tried to create a write function

void SPI5_write(unsigned char data) {
    while (!(SPI5->SR & 2)) {}      /* wait until Transfer buffer Empty */
    SPI5->DR = data;                /* write data */
    while (SPI5->SR & 0x80) {}      /* wait for transmission done */
}

and used that to send data (reference)

// ***** Spi Transmit ***** //
    // 1. Bring slave select low
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
    // 2. Transmit register + data
    spiTxBuf[0] = 0x20;
    spiTxBuf[1] = 0X11;
    //HAL_SPI_Transmit(&hspi5, spiTxBuf, 2, 50);

    SPI5_write(spiTxBuf[0]);
    SPI5_write(spiTxBuf[1]);
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);

    // ***** Spi Receive ***** //
    // 1. Bring slave select low
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_RESET);
    // 2. Transmit register + data
    spiTxBuf[0] = 0x20 | 0x80;
    HAL_SPI_Transmit(&hspi5, spiTxBuf, 1, 50);
    // 3. Receive data
    HAL_SPI_Receive(&hspi5, spiRxBuf, 1, 50);
    // 4. Bring slave select high
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_1, GPIO_PIN_SET);

  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {

    }

But it's not working. I checked using debugger. What I understand is that, it sends first byte and when SPI5_write called second time, it hangs at first while loop==> TXE buffer not empty

What causing this?

EDIT: Complete code IDE : KEIL MDK 5

\$\endgroup\$
  • \$\begingroup\$ Compare your code to the HAL's. Also your post is missing the setup, if the SPI is not enabled and clocked the bit can never change. \$\endgroup\$ – Chris Stratton Mar 9 at 12:54
  • \$\begingroup\$ @ChrisStratton I have used CubeMX to generate the code. The first code shown in the post is using HAL libraries and that works. In the same file I replaced HAL_SPI_Transmit with transmit function. SPI and other clocks are already enabled by cubeMX. I have added link to my complete code. IDE: KEIL MDK 5 \$\endgroup\$ – Athul Mar 9 at 13:57
  • \$\begingroup\$ You need to compare your code to the internal implementation of the HAL code. Even if it came from that cube toy, there's till source code that feeds into the compiler which you can read and compare. When you figure out what you are doing differently than it is, you'll have the start of your solution. The code which initializes the SPI belongs in your question, as questions here are required to stand on their own. \$\endgroup\$ – Chris Stratton Mar 9 at 13:58
1
\$\begingroup\$

I think I figured out the issue

SPI was enabled inside the HAL_SPI_Transmit() function. It checks wheter SPI is enabled or not inside the function, if not enabled it will enable it.

So if I want to write my own transmit function, I have to enable the corresponding SPI before transmission

eg:

SPI5->CR1 |=  SPI_CR1_SPE;
SPI5_write(spiTxBuf[0]);
SPI5_write(spiTxBuf[1]);

where

void SPI5_write(unsigned char data) {
    while (!(SPI5->SR & 2)) {}      /* wait until Transfer buffer Empty */
    SPI5->DR = data;                /* write data */
    while (SPI5->SR & 0x80) {}      /* wait for transmission done */
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.