HAL library 08- SPI for STM32Fxxx

Next library in ported libs is SPI for HAL based drivers for STM32F4xx and STM32F7xx based devices.


Read more about new HAL libraries


  • Operate with up to 6 SPI peripherals
  • Send single or multiple bytes at time
  • Automatic SPI prescaler selection based on maximum clock selected for your external device
  • Software based Chip Select pin
  • Support for custom GPIO pins combination for SPI


  • HAL
  • TM
    • STM32Fxxx HAL
    • defines.h
    • GPIO


Table with SPI pins for different pinspack. Pinspack is selected on library initialization.

Pins pack 1 Pins pack 2 Pins pack 3 Pins pack 4
SPI2 PC3 PC2 PB10 PB15 PB14 PB13 PI3 PI2 PI0 PB15 PB14 PI1
SPI3 PB5 PB4 PB3 PC12 PC11 PC10
SPI4 PE6 PE5 PE2 PE14 PE13 PE12
SPI6 PG14 PG12 PG13

Functions and enumerations


Project is available on Github, download all libraries below.

TM STM32 Libraries

STM32 libraries based on STM32Fxxx HAL drivers.


Owner of this site. Also electronic enthusiasts, web developer, 3D printer fan, handball player and more. Big fan of STM32F4 devices. In anticipation of the new Discovery board for STM32F7 lines.

You may also like...

Read before commenting!

Before you make a new comment, make sure you agree with things listed below:

  • - Read post to make sure if it is already posted what you are asking for,
  • - Make sure you have the latest version of libraries used in your project,
  • - Make a clean and grammatically correct written message,
  • - Report as many details as possible, including what have you done so far,
  • - Do NOT post any code here. Use Pastebin,
  • - Do NOT post any error codes here. Use Pastebin,
  • - Specify STM32Fxxx family and used Discovery/EVAL/Nucleo or custom made board,
  • - Make sure your clock is set correct for PLL,
  • - If you are using my HAL drivers, please check this post how to start.
Comment will be deleted on breaking these rules without notification!
  • Pingback: All STM32 HAL libraries - STM32F4 Discovery()

  • Mohammad Kamel

    hi tilen

    i saw your great library thanks for sharing it but i have a question when i read your method like TM_SPI_SendMulti () i didn’t see hal method i think you will use methods like HAL_SPI_Transmit() or etc . now i am a little confused…. thanks for helping

    • Do you have any special reason for why I should use this?

      • Mohammad Kamel

        yes you are right but i have a question how to use HAL_SPI_Transmit()
        in your methodes or is there any need of using this function

        • You still didn’t answer me. So, is there a need to use HAL Transmit function on such an easy task as is writing to SPI data register and waiting bit to be done?

          In that case, you need additional structure for SPI Handle and so on. Useless.

          • Mohammad Kamel

            when we said spi-hal-library it means that we use its standard function like HAL_SPI_Transmit() i’am curios of khowing this fact your code is tottaly correct but don’t seem to be hal

          • Does it need to be? Why it need to be?

          • Mohammad Kamel

            no 🙂

            but you said HAL library 08- SPI for STM32Fxxx so i expect to be hal and using hal methodes

            thanks anyway 🙂

          • It means that is compatible with HAL. I’m doing this libs only, and only because other wants to use HAL. This does not mean, that they are not compatible with HAL, because they are. Just still little faster than HAL built-in HAL_SPI_Transmit for example.

          • Mohammad Kamel

            now i understand thank you alot

  • LB IN HB

    If I need to re-init SPI with different settings, Do I need to de-init it first or can I just call the TM_SPI_InitWithMode again with the new settings?


  • samir revelo

    Hello Majerle,
    thank you very much for your work. It is great!

    I´m trying to implement your HAL-fats library which works already at my stm32f4 discovery board with spi interface, since my SD-Card board has not the apropiate pin-conection for sdio-controller.

    For my porpouse the transmition with spi is too slow, since I´m losing CAN-interface-incoming data while the sd-card data-storage.

    So I´m trying to implement dma for your fats spi library. Do you have any idea how I should try to send the data to the sd-card, or to configure the dma to transfer the data I need to save in the sd-card? Have you ever implemented HAL-Library for SPI and DMA transmition together?

    Do you think my porpose is going to work for your fats-library or should I change too much your code? I need to implement the code soon, and may be it will take too much time to adapt your code for dma and spi transmition, right?

    Thank you in advance.

    • You cant use dma in this case, since when fatfs needs data, you have to read it and then send it back to fatfs, othwerwise it cant work.

      Use interrupts for CAN, increase spi frequency or use SDIO for communication.

      • samir revelo

        I have already implemented the CAN-interface and it is working with interrupts, so for the CAN-transmition the stm32f4 is losing data because I´m sending the 8 incomming CAN-bytes to the sd-card each time they´ve been received by the can-rx-interrupt. So it takes too much time until the sd-data-transmition is done, while this period a lot of new CAN-bytes have been detected by the can-rx-interrupt since the CAN-baudrate is 500 kbs. But while this period I´m not storing this incomming CAN-data elsewhere in the storage of the microcontroller itself (heap or stack).

        Should I rather store incomming CAN-data in an array and after that send the whole buffer to the sd-card? How could I do that with fats-library? or do you have any idea how to do that? With DMA could have worked well, i guess…

        How can i change the spi frequency in your library? May be by changing this option: TM_SPI2_PRESCALER in your “tm_stm32_spi.h” – header file?

        Thanks again in advance!

        • You are making 2 big mistakes here:
          1. Do NOT every write to SDCARD in IRQ,
          2. Always try to write a multiple of 512 bytes to card (read Application Manual on FATFS)

          So, to fix these 2 problems, you will do this:
          Make 2 arrays of the same length, they can be also 2 dimensional like uint8_t arr[2][512] and its sizes should be the same and multiple of 512 bytes. (Bigger is better, but multiple of 512).

          Then, in each IRQ just fill data to this buffers and together you need a variable where you store a pointer where to save next receive data from CAN.
          When you have full first buffer, start filling another buffer and write first buffer to SDCARD, NOT in IRQ but in normal thread (mail while loop).

          And then when you have another buffer full, do it opposite. This will fix your problem.

          If you don’t know how to implement this, you can contact me in private.

          Btw..using this define, you are able to change prescaler yes. Set value to 2 there on define.

          • samir revelo

            Thanks Majerle a lot for your answer! I´ll try to understand your idea and to implement it. If I´m not able to do this or i do have troubles, I´ll surely contact you soon again.

            How can I contact you in private?

            Thanks a lot for your help

          • Each example has my email, check about page.

  • Георгий

    SPI library for stm32f0xx will?

  • Marzelo Mangenatti

    Hi Majerle,

    I have been working on getting 2 discovery boards to communicate. The master can send values to the slave and when they arrive they are correct, but when I try to have the slave send values to the master, the HAL_SPI_Transmit function always waits for the timeout to complete (even if it’s something huge like 100 seconds), and does not always send the right values. Do you know why this might be the case? And do you have any advice on an appropriate BAUDRATEPRESCALER? Thank you in advance!

    • Master is the one who sends clocks even ifslave wants to send something. You must then do it in a way that slave notifies master data are ready to be sent to master. Use one gpio and set it low from slave to master when data ready. Master has interrupt and will start clocking data for you.

      • Marzelo Mangenatti

        Thank you Majerle! That fixed my problem.

      • Marzelo Mangenatti

        Hi again Majerle! I just wanted to ask you another quick question about what you suggested. I set up the system so that an exchange between the master and the slave goes like this:

        1) Master executes HAL_SPI_Transmit.
        2) Master tells slave he sent him data with a GPIO pin. When this pin is set high, it triggers an interrupt inside the slave. This interrupt makes the slave execute HAL_SPI_Receive.

        So far everything is good, but here is where I get confused. If I make the slave execute HAL_SPI_Transmit, it obviously waits for the timeout to complete since it is not being clocked, and it does not transmit anything. So what I did is:

        3) Slave tells master he is about to send data with a GPIO pin. When this pin is high, it triggers an interrupt inside the master. This interrupt makes it execute HAL_SPI_Receive.

        By doing this I was able to make 2 discovery boards communicate. I believe that executing HAL_SPI_Receive on the master somehow clocks the HAL_SPI_Transmit on the slave. This does not seem to work, however, for a discover board and a nucleo board. Is there an explicit way to tell the master to start clocking the slave? Or do the transmit and receive instructions need to execute at the same time on the slave and the master, respectively. Thank you for any advice!

        • You definetelly need to tell somehow from slave to master about new data slave wants to send to master. But you don’t need additional GPIO pin to notify slave when master has something for it. That’s why CS pin is here.

          Difference between HAL_SPI_Transmit, HAL_SPI_Receive and HAL_SPI_TransmitReceive is this:
          – Transmit function sends your data and does not care for received one,
          – Receive function sends dummy bytes (probably 0x00) and cares about received data,
          – TransmitReceive function sends your data and takes care about received data.

          If any function above is called as master, there will be clocking since each function sets data register to SPI and it clocks data out.

          When CS goes low on slave, you should use interrupt and start SPI_Receive function to receive data.

  • Pingback: HAL Library 33- DMA extension for SPI on STM32Fxxx - STM32F4 Discovery()

  • ArminT

    Hello Majerle
    I have been using your libraries for my STM32F429 Discovery Board. They are working great, thanks! Currently I want to control a MCP23S17 16 Bit expander via SPI. This expander needs one clock cycle after the chip select signal was driven high (Clock Delay Time (10)). Can you tell me if this is possible with your HAL driver? https://uploads.disquscdn.com/images/ff57e407d30b59413dc80cee69ee7feccb69f90ea09974b34022116a0296119b.png

    • This is not spi spec, lib does not support.

      • ArminT

        OK, thanks. Do you know if is there is a way to do this? I can’t find no information how to do that with a STM32…

  • Tobias K

    Hi Majerle,
    I like your library alot. ST should have hired you for their libs.
    Maybe I found two bugs in your SPI lib on STM32f7xx:
    1) In function TM_SPI_Send() it should be “*(__IO uint8_t *)&SPIx->DR = data;” otherwise I get 16 SCK cycles instead of 8. See also https://community.st.com/thread/34357-stm32f4-to-stm32f7-port-spi-wrong-clk-signal.
    2) In function TM_SPI_SetDataSize() the SPI_CR2_DS bits you are setting on STM32f7xx seem to be wrong.

    • 1. I know,
      2. Could be, but I’m not sure what are you trying to said, what exactly is wrong?

      I’m ST employee already.

      • Tobias K

        Nice! They actually did hire you. But are they paying you to maintain your lib? I am asking because I am going to use it in a commercial project and it would be nice to know if you will continue your work on it and keep this site online for the next 5…10 years maybe?
        To bug #2: You have got the wrong DataSize bit pattern: Instead of 8 bit you set it to 9 bit, instead of 16 bit you set it to 5 bit I believe. On the STM32F765. See Reference Manual. Or maybe write it like this: “SPIx->CR2 = (SPIx->CR2 & ~SPI_CR2_DS) | (SPI_DATASIZE_8BIT);”

        • My job has noting to do with this site. It is just personal site where I share my work.