2026-03-14 2:55 PM - last edited on 2026-03-16 5:34 AM by KDJEM.1
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);
}
}
2026-03-15 4:24 AM
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.