cancel
Showing results for 
Search instead for 
Did you mean: 

Help with using the SPI protocol for the STM32H7A3RGT6 microcontroller.

FELM
Associate

Hello, I am trying to use SPI with the STM32H7A3RGT6 microcontroller to send and receive data. However, I am not sure if I have created my functions correctly, or if I have properly configured the registers to achieve full-duplex SPI functionality. Here are my codes:

Header files.

 

 

 

/*

* spi.h

*

* Created on: Apr 23, 2025

* Author: HP

*/

 

#ifndef INC_SPI_H_

#define INC_SPI_H_

 

#include "stm32h7a3rgxx.h"

#include <stdint.h>

void SPI3_gpio_init(void);

void SPI3_init(void);

void cs_enable(void);

void cs_disable(void);

void SPI3_transmit(uint8_t *data, uint32_t len);

void SPI3_receive(uint8_t *data, uint32_t len);

#endif /* INC_SPI_H_ */

 

 

 

 

 

 

 

 

 

 

 

 

 

 

/*

* Clock enable Macros for GPIOx peripherals

*/

 

#define GPIOA_PCLK_EN() (RCC->AHB4ENR |= (1<<0))

#define GPIOB_PCLK_EN() (RCC->AHB4ENR |= (1<<1))

#define GPIOC_PCLK_EN() (RCC->AHB4ENR |= (1<<2))

#define GPIOD_PCLK_EN() (RCC->AHB4ENR |= (1<<3))

#define GPIOE_PCLK_EN() (RCC->AHB4ENR |= (1<<4))

#define GPIOF_PCLK_EN() (RCC->AHB4ENR |= (1<<5))

#define GPIOG_PCLK_EN() (RCC->AHB4ENR |= (1<<6))

#define GPIOH_PCLK_EN() (RCC->AHB4ENR |= (1<<7))

#define GPIOI_PCLK_EN() (RCC->AHB4ENR |= (1<<8))

#define GPIOJ_PCLK_EN() (RCC->AHB4ENR |= (1<<9))

#define GPIOK_PCLK_EN() (RCC->AHB4ENR |= (1<<10))

 

 

 

/*

* Clock enable Macros for I2Cx peripherals

*/

#define I2C1_PCLK_EN() (RCC->APB1LENR |= (1<<21))

#define I2C2_PCLK_EN() (RCC->APB1LENR |= (1<<22))

#define I2C3_PCLK_EN() (RCC->APB1LENR |= (1<<23))

#define I2C4_PCLK_EN() (RCC->APB4ENR |= (1<<7))

 

 

 

 

/*

* Clock enable Macros for SPIx peripherals

*/

 

#define SPI1_PCLK_EN() (RCC->APB2ENR |= (1<<12))

#define SPI2_PCLK_EN() (RCC->APB1LENR |= (1<<14))

#define SPI3_PCLK_EN() (RCC->APB1LENR |= (1<<15))

#define SPI4_PCLK_EN() (RCC->APB2ENR |= (1<<13))

#define SPI5_PCLK_EN() (RCC->APB2ENR |= (1<<20))

 

 

 

 

 

/*

* Clock enable Macros for USARTx peripherals

*/

 

#define USART1_PCLK_EN() (RCC->APB2ENR |= (1<<4))

#define USART2_PCLK_EN() (RCC->APB1LENR |= (1<<17))

#define USART3_PCLK_EN() (RCC->APB1LENR |= (1<<18))

 

 

 

 

 

/*

* Clock enable Macros for UARTx peripherals

*/

#define UART4_PCLK_EN() (RCC->APB1LENR |= (1<<19))

#define UART5_PCLK_EN() (RCC->APB1LENR |= (1<<20))

 

 

 

/*

* Clock enable Macros for EXTI peripherals

*/

 

 

/*

* Clock enable Macros for SYSCFG peripherals

*/

 

#define SYSCFG_PCLK_EN() (RCC->APB4ENR |= (1<<1))

 

/*

* Clock disable Macros for GPIOx peripherals

*/

 

#define GPIOA_PCLK_DI() (RCC->AHB4ENR &= ~(1<<0))

#define GPIOB_PCLK_DI() (RCC->AHB4ENR &= ~(1<<1))

#define GPIOC_PCLK_DI() (RCC->AHB4ENR &= ~(1<<2))

#define GPIOD_PCLK_DI() (RCC->AHB4ENR &= ~(1<<3))

#define GPIOE_PCLK_DI() (RCC->AHB4ENR &= ~(1<<4))

#define GPIOF_PCLK_DI() (RCC->AHB4ENR &= ~(1<<5))

#define GPIOG_PCLK_DI() (RCC->AHB4ENR &= ~(1<<6))

#define GPIOH_PCLK_DI() (RCC->AHB4ENR &= ~(1<<7))

#define GPIOI_PCLK_DI() (RCC->AHB4ENR &= ~(1<<8))

#define GPIOJ_PCLK_DI() (RCC->AHB4ENR &= ~(1<<9))

#define GPIOK_PCLK_DI() (RCC->AHB4ENR &= ~(1<<10))

 

 

 

 

 

/*

* Clock disable Macros for I2Cx peripherals

*/

 

#define I2C1_PCLK_DI() (RCC->APB1LENR &= ~(1<<21))

#define I2C2_PCLK_DI() (RCC->APB1LENR &= ~(1<<22))

#define I2C3_PCLK_DI() (RCC->APB1LENR &= ~(1<<23))

#define I2C4_PCLK_DI() (RCC->APB4ENR &= ~(1<<7))

 

 

/*

* Clock disable Macros for SPIx peripherals

*/

 

#define SPI1_PCLK_DI() (RCC->APB2ENR &= ~(1<<12))

#define SPI2_PCLK_DI() (RCC->APB1LENR &= ~(1<<14))

#define SPI3_PCLK_DI() (RCC->APB1LENR &= ~(1<<15))

#define SPI4_PCLK_DI() (RCC->APB2ENR &= ~(1<<13))

#define SPI5_PCLK_DI() (RCC->APB2ENR &= ~(1<<20))

 

 

 

/*

* Clock disable Macros for USARTx peripherals

*/

 

 

#define USART1_PCLK_DI() (RCC->APB2ENR &= ~(1<<4))

#define USART2_PCLK_DI() (RCC->APB1LENR &= ~(1<<17))

#define USART3_PCLK_DI() (RCC->APB1LENR &= ~(1<<18))

 

 

 

/*

* Clock disable Macros for UARTx peripherals

*/

 

#define UART4_PCLK_DI() (RCC->APB1LENR &= ~(1<<19))

#define UART5_PCLK_DI() (RCC->APB1LENR &= ~(1<<20))

 

 

/*

* Clock disable Macros for SYSCFG peripherals

*/

 

#define SYSCFG_PCLK_DI() (RCC->APB4ENR &= ~(1<<1))

 

/*

* Macros to reset GPIOx peripherals

*/

 

#define GPIOA_REG_RESET() do{(RCC->AHB4RSTR |= (1<<0)); (RCC->AHB4RSTR &= ~(1<<0));} while(0)

#define GPIOB_REG_RESET() do{(RCC->AHB4RSTR |= (1<<1)); (RCC->AHB4RSTR &= ~(1<<1));} while(0)

#define GPIOC_REG_RESET() do{(RCC->AHB4RSTR |= (1<<2)); (RCC->AHB4RSTR &= ~(1<<2));} while(0)

#define GPIOD_REG_RESET() do{(RCC->AHB4RSTR |= (1<<3)); (RCC->AHB4RSTR &= ~(1<<3));} while(0)

#define GPIOE_REG_RESET() do{(RCC->AHB4RSTR |= (1<<4)); (RCC->AHB4RSTR &= ~(1<<4));} while(0)

#define GPIOF_REG_RESET() do{(RCC->AHB4RSTR |= (1<<5)); (RCC->AHB4RSTR &= ~(1<<5));} while(0)

#define GPIOG_REG_RESET() do{(RCC->AHB4RSTR |= (1<<6)); (RCC->AHB4RSTR &= ~(1<<6));} while(0)

#define GPIOH_REG_RESET() do{(RCC->AHB4RSTR |= (1<<7)); (RCC->AHB4RSTR &= ~(1<<7));} while(0)

#define GPIOI_REG_RESET() do{(RCC->AHB4RSTR |= (1<<8)); (RCC->AHB4RSTR &= ~(1<<8));} while(0)

#define GPIOJ_REG_RESET() do{(RCC->AHB4RSTR |= (1<<9)); (RCC->AHB4RSTR &= ~(1<<9));} while(0)

#define GPIOK_REG_RESET() do{(RCC->AHB4RSTR |= (1<<10)); (RCC->AHB4RSTR &= ~(1<<10));} while(0)

 

 

 

/*

* Return port code for given GPIOx base address

*/

 

#define GPIO_BASEADDR_TO_CODE(x) ((x == GPIOA)?0:\

(x == GPIOB)?1:\

(x == GPIOC)?2:\

(x == GPIOD)?3:\

(x == GPIOE)?4:\

(x == GPIOF)?5:\

(x == GPIOG)?6:\

(x == GPIOH)?7:\

(x == GPIOI)?8:\

(x == GPIOJ)?9:\

(x == GPIOK)?10:0)

 

 

 

 

 

/*

* IRQ (Interrupt request) numbers of STM32H7A3RGT6 MCU

*/

 

#define IRQ_NO_EXTI0 6

#define IRQ_NO_EXTI1 7

#define IRQ_NO_EXTI2 8

#define IRQ_NO_EXTI3 9

#define IRQ_NO_EXTI4 10

#define IRQ_NO_EXTI9_5 23

#define IRQ_NO_EXTI15_10 40

 

 

/*

* macros for all the possible priority levels

*/

 

#define NVIC_IRQ_PRIO0 0

#define NVIC_IRQ_PRIO1 1

#define NVIC_IRQ_PRIO2 2

#define NVIC_IRQ_PRIO15 15

 

 

 

 

 

//Some generic MACROS

 

 

#define ENABLE 1

#define DISABLE 0

#define SET ENABLE

#define RESET DISABLE

#define GPIO_PIN_SET SET

#define GPIO_PIN_RESET RESET

#define FLAG_RESET RESET

#define FLAG_SET SET

 

 

 

/*

* Bit position definitions of SPI peripheral (STM32H7)

*/

#define SPI_CFG2_MASTER 22

#define SPI_CFG2_COMM 17

#define SPI_CFG2_CPOL 25

#define SPI_CFG2_CPHA 24

#define SPI_CFG1_MBR 28

#define SPI_CFG1_DSIZE 0

 

#define SPI_CR1_SPE 0

#define SPI_CR1_SSI 12

 

 

 

 

 

#endif /* INC_STM32H7A3RGXX_H_ */

 

 

 

 

 

 

 



Source Files

 

/*

* spi.c

*

* Created on: Apr 23, 2025

* Author: HP

*/

 

 

#include "stm32h7a3rgxx.h"

 

#define GPIOCEN (1U << 2)

#define GPIOAEN (1U << 0)

#define SPI3EN (1U << 15)

 

#define SR_TXP (1U << 1)

#define SR_RXP (1U << 0)

#define SR_EOT (1U << 3)

 

void SPI3_gpio_init(void)

{

RCC->AHB4ENR |= GPIOCEN | GPIOAEN;

 

// PC10 -> SPI3_SCK (AF6)

// PC11 -> SPI3_MISO (AF6)

// PC12 -> SPI3_MOSI (AF6)

GPIOC->MODER &= ~((3U << 20) | (3U << 22) | (3U << 24));

GPIOC->MODER |= ((2U << 20) | (2U << 22) | (2U << 24));

GPIOC->AFR[1] |= (6U << 8) | (6U << 12) | (6U << 16); // AFRH

 

// PA15 -> SPI3_NSS (Manual CS) as GPIO output

GPIOA->MODER &= ~(3U << 30);

GPIOA->MODER |= (1U << 30); // Output

GPIOA->ODR |= (1U << 15); // Set high (inactive)

}

 

void SPI3_init(void)

{

RCC->APB1LENR |= SPI3EN;

 

SPI3->CR1 = 0; // Disable SPI for config

 

// CFG1

SPI3->CFG1 = (0 << 28) | // MBR = /256 (slowest for test)

(7 << 0) | // DSIZE = 8-bit (7)

(0 << 5) | // FTHLV = 1/4 FIFO (TXP when 1 byte available)

(0 << 14) | // RXDMAEN = 0

(0 << 15); // TXDMAEN = 0

 

// CFG2

 

SPI3->CFG2 &= ~(1 << 25); // CPOL = 0

SPI3->CFG2 &= ~(1 << 24); // CPHA = 0

SPI3->CFG2 &= ~(1 << 28); // SSIOP = 0 (active low, default)

SPI3->CFG2 |= (1 << 26); // SSM = software slave

SPI3->CR1 |= (1 << 12); // SSI=1

SPI3->CFG2 &= ~(1 << 29); // SSOE =0 (disable hardware NSS output)

SPI3->CFG2 &= ~(1 << 30); // SSOM =0

SPI3->CFG2 &= ~(1 << 15); // IOSWP =0

SPI3->CFG2 &= ~(0xF << 4); // MIDI = 0

SPI3->CFG2 |= (1 << 22); // Master mode

 

 

 

 

SPI3->CR2 = 1; // Set TSIZE = 1 for each byte by default

SPI3->CR1 |= (1 << 0); // Enable SPI

}

 

void cs_enable(void)

{

GPIOA->ODR &= ~(1U << 15); // Active low

}

 

void cs_disable(void)

{

GPIOA->ODR |= (1U << 15);

}

 

void SPI3_transmit(uint8_t *data, uint32_t len)

{

SPI3->CR2 = len;

for (uint32_t i = 0; i < len; i++)

{

while (!(SPI3->SR & SR_TXP)) {}

*((__vo uint8_t *)&SPI3->TXDR) = data[i];

}

 

while (!(SPI3->SR & SR_EOT)) {}

SPI3->IFCR |= SR_EOT;

}

 

void SPI3_receive(uint8_t *data, uint32_t len)

{

SPI3->CR2 = len;

for (uint32_t i = 0; i < len; i++)

{

while (!(SPI3->SR & SR_TXP)) {}

*((__vo uint8_t *)&SPI3->TXDR) = 0xFF;

 

while (!(SPI3->SR & SR_RXP)) {}

data[i] = *((__vo uint8_t *)&SPI3->RXDR);

}

 

while (!(SPI3->SR & SR_EOT)) {}

SPI3->IFCR |= SR_EOT;

}

 

 

 

 

 

 

 

 

 

 

 

 

/**

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

* @file : main.c

* @author : Auto-generated by STM32CubeIDE

* @brief : Main program body

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

* @attention

*

* Copyright (c) 2025 STMicroelectronics.

* All rights reserved.

*

* This software is licensed under terms that can be found in the LICENSE file

* in the root directory of this software component.

* If no LICENSE file comes with this software, it is provided AS-IS.

*

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

*/

 

#include <stdint.h>

#include "stm32h7a3rgxx.h"

#include "spi.h"

 

int main(void)

{

uint8_t data[] = {0xAB, 0xCD, 0xBE,0xEF};

SPI3_gpio_init();

SPI3_init();

 

cs_enable();

SPI3_transmit(data, sizeof(data));

cs_disable();

 

while (1);

}

 

 

1 REPLY 1
Pavel A.
Evangelist III

Start from a ready, pre-configured example for same board or MCU in the Cube H7 library. Play with it, debug it, see how the SPI works.

If you have a specific issue (rather than "not sure") please see this text.