cancel
Showing results for 
Search instead for 
Did you mean: 

Help with using the SPI protocol for the STM32H7A3RGT6 microcontroller.

FELM
Associate II

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 ACCEPTED SOLUTION

Accepted Solutions

Welcome to the forum.

Please see How to write your question to maximize your chances to find a solution; in particular, How to insert source code.

 


@FELM wrote:

 which registers and bits of the STM32H7A3RGT6 should be configured to achieve correct SPI functionality on this microcontroller?


That will be defined in the Reference Manual for the MCU - see the 'Documentation' tab on the Product Page:

https://www.st.com/en/microcontrollers-microprocessors/stm32h7a3rg.html#documentation

 

As @Pavel A. said, the best way is to take the provided examples, and examine what they do

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.

View solution in original post

4 REPLIES 4
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.

 

Okay, let me be more specific: which registers and bits of the STM32H7A3RGT6 should be configured to achieve correct SPI functionality on this microcontroller?

Pavel A.
Evangelist III

Hmm... quite many of them. Take your time please, use the examples.

 

Welcome to the forum.

Please see How to write your question to maximize your chances to find a solution; in particular, How to insert source code.

 


@FELM wrote:

 which registers and bits of the STM32H7A3RGT6 should be configured to achieve correct SPI functionality on this microcontroller?


That will be defined in the Reference Manual for the MCU - see the 'Documentation' tab on the Product Page:

https://www.st.com/en/microcontrollers-microprocessors/stm32h7a3rg.html#documentation

 

As @Pavel A. said, the best way is to take the provided examples, and examine what they do

A complex system that works is invariably found to have evolved from a simple system that worked.
A complex system designed from scratch never works and cannot be patched up to make it work.