Skip to main content
Visitor II
March 14, 2026
Question

Unable to configure hardware SPI 1

  • March 14, 2026
  • 1 reply
  • 143 views

Hi I am trying to set up hardware SPI using the following. My software SPI works fine, but the hardware SPI doesn't even have a clock signal.

 
/**

******************************************************************************

* @file : main.c

* @brief : P7-SPI2: Two bursts, same 6 bytes. Burst1: SW SPI (PE2/PE6).

* Burst2: Hardware SPI1 (PA5/PA7). Probe D0=PE2, D1=PE6, D2=PA5, D3=PA7.

* HW SPI1: kernel clock per_ck, GPIO before SPI, CSTART errata workaround.

******************************************************************************

*/



#include <stdint.h>



#define RCC_AHB4ENR (*(volatile uint32_t *)0x580244E0u)

#define RCC_APB2ENR (*(volatile uint32_t *)0x580244F0u)

#define RCC_D2CCIP1R (*(volatile uint32_t *)0x58024450u)

#define GPIOA_MODER (*(volatile uint32_t *)0x58020000u)

#define GPIOA_AFRL (*(volatile uint32_t *)0x58020020u)

#define GPIOA_ODR (*(volatile uint32_t *)0x58020014u)

#define GPIOE_MODER (*(volatile uint32_t *)0x58021000u)

#define GPIOE_ODR (*(volatile uint32_t *)0x58021014u)



#define GPIOAEN (1u << 0)

#define GPIOEEN (1u << 4)

#define SPI1EN (1u << 12)



#define SW_SCK_PIN (1u << 2)

#define SW_MOSI_PIN (1u << 6)

#define PA_SCK_PIN (1u << 5)

#define PA_MOSI_PIN (1u << 7)



#define SW_SPI_DELAY 64u



/* ----- SPI1: P5/STM32H753xx style. CR1@0x00, CR2@0x04, CFG1@0x08, CFG2@0x0C, SR@0x14, TXDR@0x20, RXDR@0x30 ----- */

#define SPI1_BASE 0x40013000u

#define SPI1_CR1 (*(volatile uint32_t *)(SPI1_BASE + 0x00u))

#define SPI1_CR2 (*(volatile uint32_t *)(SPI1_BASE + 0x04u))

#define SPI1_CFG1 (*(volatile uint32_t *)(SPI1_BASE + 0x08u))

#define SPI1_CFG2 (*(volatile uint32_t *)(SPI1_BASE + 0x0Cu))

#define SPI1_SR (*(volatile uint32_t *)(SPI1_BASE + 0x14u))

#define SPI1_IFCR (*(volatile uint32_t *)(SPI1_BASE + 0x18u))

#define SPI1_TXDR8 (*(volatile uint8_t *)(SPI1_BASE + 0x20u))

#define SPI1_RXDR8 (*(volatile uint8_t *)(SPI1_BASE + 0x30u))



/* RM0433 50.11: CR1@0x00, CR2@0x04, CFG1@0x08. CFG1: MBR[30:28], FTHLV[8:5]=0 (1 frame), DSIZE[4:0]=7 (8-bit). */

#define SPI_CFG1_MBR_DIV16 (3u << 28)

#define SPI_CFG1_FTHLV_0 (0u << 5) /* 1 data frame per packet so TXP/RXWNE per byte */

#define SPI_CFG1_DSIZE_8BIT (7u << 0)

#define SPI_CFG2_MASTER (1u << 22)

#define SPI_CFG2_SSM (1u << 26)

#define SPI_CR1_SPE (1u << 0)

#define SPI_CR1_CSTART (1u << 9)

#define SPI_CR1_SSI (1u << 12)

#define SPI_SR_TXP (1u << 1)

#define SPI_SR_RXWNE (1u << 15)



static const uint8_t msg[] = { 0x55u, 0xAAu, 0xF0u, 0x0Fu, 0x12u, 0x34u };

#define MSG_LEN 6u



void SystemInit(void) { }



static void delay_cycles(volatile uint32_t n)

{

while (n--) { __asm volatile ("nop"); }

}



/* ----- Software SPI: PE2=SCK, PE6=MOSI ----- */

static void sw_spi_init(void)

{

RCC_AHB4ENR |= GPIOEEN;

(void)RCC_AHB4ENR;

GPIOE_MODER &= ~(3u << 4 | 3u << 12);

GPIOE_MODER |= (1u << 4) | (1u << 12);

GPIOE_ODR &= ~(SW_SCK_PIN | SW_MOSI_PIN);

}



static void sw_spi_send_byte(uint8_t tx)

{

int i;

for (i = 7; i >= 0; i--) {

if (tx & (1u << i))

GPIOE_ODR |= SW_MOSI_PIN;

else

GPIOE_ODR &= ~SW_MOSI_PIN;

delay_cycles(SW_SPI_DELAY);

GPIOE_ODR |= SW_SCK_PIN;

delay_cycles(SW_SPI_DELAY);

GPIOE_ODR &= ~SW_SCK_PIN;

delay_cycles(SW_SPI_DELAY);

}

}



/* ----- Burst2: bit-bang on PA5 (SCK), PA7 (MOSI). Same timing as burst1 so you see both on analyzer. ----- */

static void pa_bb_spi_init(void)

{

RCC_AHB4ENR |= GPIOAEN;

(void)RCC_AHB4ENR;

GPIOA_MODER &= ~(3u << 10 | 3u << 14);

GPIOA_MODER |= (1u << 10) | (1u << 14); /* PA5, PA7 output */

GPIOA_ODR &= ~(PA_SCK_PIN | PA_MOSI_PIN);

}



static void pa_bb_send_byte(uint8_t tx)

{

int i;

for (i = 7; i >= 0; i--) {

if (tx & (1u << i))

GPIOA_ODR |= PA_MOSI_PIN;

else

GPIOA_ODR &= ~PA_MOSI_PIN;

delay_cycles(SW_SPI_DELAY);

GPIOA_ODR |= PA_SCK_PIN;

delay_cycles(SW_SPI_DELAY);

GPIOA_ODR &= ~PA_SCK_PIN;

delay_cycles(SW_SPI_DELAY);

}

}



/* ----- Hardware SPI1: P5 layout, CSTART + TXDR/RXDR ----- */

static void spi1_wait_txp(void)

{

uint32_t t = 10000u;

while (!(SPI1_SR & SPI_SR_TXP) && t) { t--; }

}



static void spi1_wait_rxwne(void)

{

uint32_t t = 10000u;

while (!(SPI1_SR & SPI_SR_RXWNE) && t) { t--; }

}



/* 50.4.10: write TXDR then set CSTART. Errata: delay after EOT before next CSTART to avoid stall. */

static void hw_spi_send_byte(uint8_t tx)

{

spi1_wait_txp();

SPI1_TXDR8 = tx;

SPI1_CR1 |= SPI_CR1_CSTART;

spi1_wait_rxwne();

(void)SPI1_RXDR8;

delay_cycles(100u); /* errata: wait after EOT before next CSTART */

}



/* SPI1/2/3 kernel clock: 0=PLL1Q, 3=per_ck. Use per_ck when PLL not running. RM0433 RCC D2CCIP1R. */

#define SPI123SEL_PERCK (3u << 12)



static void hw_spi_init(void)

{

/* GPIO before SPI (required: AF must be set before enabling SPI). */

RCC_AHB4ENR |= GPIOAEN;

(void)RCC_AHB4ENR;

/* PA5=SCK, PA6=MISO, PA7=MOSI = AF5 for SPI1 */

GPIOA_MODER &= ~(3u << 10 | 3u << 12 | 3u << 14);

GPIOA_MODER |= (2u << 10 | 2u << 12 | 2u << 14);

GPIOA_AFRL &= ~(0xFFFu << 20);

GPIOA_AFRL |= (0x555u << 20);



RCC_APB2ENR |= SPI1EN;

RCC_D2CCIP1R = (RCC_D2CCIP1R & ~(7u << 12)) | SPI123SEL_PERCK;

(void)RCC_APB2ENR;



/* Config only writable when SPE=0. Do not set CSTART here; set it per transfer. */

SPI1_CR1 = 0u;

SPI1_IFCR = 0xFFFFFFFFu; /* clear status flags */

SPI1_CFG1 = SPI_CFG1_MBR_DIV16 | SPI_CFG1_FTHLV_0 | SPI_CFG1_DSIZE_8BIT;

SPI1_CFG2 = SPI_CFG2_MASTER | SPI_CFG2_SSM;

SPI1_CR2 = 0u; /* TSIZE=0: trigger by TXDR write + CSTART */

SPI1_CR1 = SPI_CR1_SPE | SPI_CR1_SSI;

}



int main(void)

{

uint32_t i;



sw_spi_init();

hw_spi_init(); /* burst2 = hardware SPI1 on PA5/PA7 */



for (;;) {

for (i = 0; i < MSG_LEN; i++)

sw_spi_send_byte(msg[i]);

delay_cycles(50000u);



for (i = 0; i < MSG_LEN; i++)

hw_spi_send_byte(msg[i]);

delay_cycles(500000u);

}

}

 

 

 

1 reply

gbm
Principal
March 15, 2026

1. Rewrite your code so that it uses standard peripheral, register and bit mask definition from stm32xxxx.h. Most of errors like yours origin from mistakes in non-standard user definitions.

2. Format your code using code tags </>

3. After you do the above, supply the most basic piece of information missing from your post - the MCU type.

My STM32 stuff on github - compact USB device stack and more: https://github.com/gbm-ii/gbmUSBdevice