2025-04-27 4:23 AM
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);
}
2025-04-27 2:28 PM - edited 2025-04-27 2:29 PM
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.