Skip to main content
Visitor II
November 16, 2025
Question

F405 Bare Metal SPI

  • November 16, 2025
  • 2 replies
  • 315 views

Hi, I've been trying to get a ground-up bare metal implementation of SPI working on one of the STM32 boards I own, but I can't seem to make progress on any of them. I lack an ST Link for the 405, so I can't step through my program and see how the registers are configured sadly, so I figured I'd ask here to see if anyone has experience doing something similar. I've attached the relevant GPIO and SPI c code to this post, as well as the main function for my project. Any help would be much appreciated, thanks.

    This topic has been closed for replies.

    2 replies

    Graduate
    November 16, 2025

    You’re on the right track, but SPI on the F4 can be sensitive to small setup details. Most problems come from the wrong AF pin mapping or missing SSM/SSI settings when using software NSS. Try a simple loopback test by connecting MOSI to MISO to confirm your setup. If you share which pins you’re using, it’ll be easier to spot any config issues.

    tdorval23Author
    Visitor II
    November 16, 2025

    Based on the schematic for the board I'm using, the pins should be B13, B14, and B15. I believe I set them to AF5, which based on the datasheet seems to be the correct setting for their respective SPI functions. I have no reason to actually be using software slave select, I just thought that was the correct configuration based on the description of the register within the reference manual. If I set SSM low, does the slave selection become irrelevant?

    Super User
    November 17, 2025

    > I lack an ST Link for the 405, so I can't step through my program and see how the registers are configured

    I highly recommend you to get one. 

    But even without STLink, you should establish some way to gather information "from within", especially registers content; for example using UART.

    I also recommend you to use the symbols defined in the CMSIS-mandated device header, rather than defining your own. It's also better to use symbols defined there in a systematic manner (e.g. using the (value << MODULE_REGISTER_BITFIELD_Pos) pattern).

    The problem here is this:

    > #define GPIO_AF_SPI ((5U << 26) | (5U << 28) | (5U << 30))

    resulting in GPIOB->AFR[1] being set to 0x5400'0000 (rather than the needed 0x5550'0000), as the GPIOx_AFR[] bitfields are 4 bits wide rather than 2 bits. 

    Also, I recommend either writing values to GPIO registers directly, if you know there is no other code which sets or modifies the register; or using read-modify-write (AND-OR) so that you read and write the register only once, i.e. instead of register = register AND mask; register = register OR value; write a single register = (register AND mask) OR value;.

    JW