Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 22 additions & 1 deletion src/application/main.c
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@

#include "protocol.h"
#include "system/bus/spi.h"
#include "system/led.h"
#include "system/system.h"
#include "util/error.h"
#include "util/logging.h"

typedef enum { TX_BUFFER_DATA = 0x9F, RX_BUFFER_LENGTH = 38 } BufferConstants;

int main(void)
{
SYSTEM_init();
Expand All @@ -16,6 +18,12 @@ int main(void)
return -1;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): SPI bus initialization error is logged but not handled.

Please ensure the function exits or handles the error when SPI_init returns NULL to prevent invalid SPI operations.


// Initialize the SPI bus
SPI_Handle *spi_handle = SPI_init(0);
if (spi_handle == NULL) {
LOG_ERROR("Failed to initialize SPI bus");
}

// Main application loop
while (1) {
// Process protocol tasks
Expand All @@ -29,6 +37,19 @@ int main(void)
LED_toggle(LED_GREEN);
last_toggle = SYSTEM_get_tick();
}

// SPI communication example
uint8_t tx_data = TX_BUFFER_DATA;
uint8_t rx_data[RX_BUFFER_LENGTH] = { 0 };
SPI_transmit_receive(spi_handle, &tx_data, rx_data, sizeof(rx_data));
LOG_INFO(
"SPI Received: %02X %02X %02X %02X %02X",
rx_data[0],
rx_data[1],
rx_data[2],
rx_data[3],
rx_data[4]
);
}

__builtin_unreachable();
Expand Down
2 changes: 2 additions & 0 deletions src/platform/h563xx/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ target_sources(pslab-platform
esp_ll.c
led_ll.c
platform.c
spi_ll.c
tim_ll.c
uart_ll.c
usb_ll.c
Expand Down Expand Up @@ -32,6 +33,7 @@ target_link_libraries(pslab-platform
HAL::STM32::H5::ICACHE
HAL::STM32::H5::GPIO
HAL::STM32::H5::RCCEx
HAL::STM32::H5::SPIEx
HAL::STM32::H5::PWREx
HAL::STM32::H5::TIMEx
HAL::STM32::H5::UARTEx
Expand Down
10 changes: 7 additions & 3 deletions src/platform/h563xx/platform.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,10 @@ static void system_clock_config(void)

/* Configure peripheral clocks - Set ADC clock source to PLL2R (75 MHz) */
RCC_PeriphCLKInitTypeDef periph_clk_init = { 0 };
periph_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADCDAC;
periph_clk_init.PeriphClockSelection =
RCC_PERIPHCLK_ADCDAC | RCC_PERIPHCLK_SPI3;
periph_clk_init.AdcDacClockSelection = RCC_ADCDACCLKSOURCE_PLL2R;
periph_clk_init.Spi3ClockSelection = RCC_SPI3CLKSOURCE_PLL2P;

// Configure PLL2 structure to match our desired configuration
// This is required because HAL_RCCEx_PeriphCLKConfig calls
Expand All @@ -148,16 +150,18 @@ static void system_clock_config(void)
// NOLINTBEGIN: readability-magic-numbers
periph_clk_init.PLL2.PLL2M = 5; // 25 MHz / 5 = 5 MHz
periph_clk_init.PLL2.PLL2N = 60; // 5 MHz * 60 = 300 MHz VCO
periph_clk_init.PLL2.PLL2P = 2; // 300 MHz / 2 = 150 MHz
periph_clk_init.PLL2.PLL2P = 3; // 300 MHz / 3 = 100 MHz (for SPI3)
periph_clk_init.PLL2.PLL2Q = 2; // 300 MHz / 2 = 150 MHz
periph_clk_init.PLL2.PLL2R = 4; // 300 MHz / 4 = 75 MHz (for ADC)
// NOLINTEND: readability-magic-numbers
periph_clk_init.PLL2.PLL2RGE = RCC_PLL2_VCIRANGE_2;
periph_clk_init.PLL2.PLL2VCOSEL =
RCC_PLL2_VCORANGE_MEDIUM; // 150-420 MHz VCO
periph_clk_init.PLL2.PLL2FRACN = 0;
// Enable PLL2R outputs
periph_clk_init.PLL2.PLL2ClockOut =
RCC_PLL2_DIVR; // Enable PLL2R output for ADC
RCC_PLL2_DIVR | // Enable PLL2R output for ADC
RCC_PLL2_DIVP; // Enable PLL2P output for SPI3

if (HAL_RCCEx_PeriphCLKConfig(&periph_clk_init) != HAL_OK) {
/* ADC clock configuration failed */
Expand Down
199 changes: 199 additions & 0 deletions src/platform/h563xx/spi_ll.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/**
* @file spi_ll.c
* @brief SPI hardware implementation for STM32H563xx
*
* This module handles initialization and operation of the SPI peripheral of
* the STM32H5 microcontroller. It configures the hardware and dispatches SPI
* interrupts to the hardware-independent SPI implementation.
*
* Implementation Details:
* - Supports single SPI instance (SPI1)
* - Configured for 8-bit data size
* - DMA-based transmission and reception
*
* @author Tejas Garg
* @date 2025-10-31
*/

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "stm32h5xx_hal.h"

#include "util/error.h"

#include "spi_ll.h"

/* SPI instance structure */
typedef struct {
SPI_HandleTypeDef *hspi;
bool initialized;
} SPIInstance;

/* HAL SPI handle */
static SPI_HandleTypeDef g_hspi1 = { nullptr };

/* SPI instance configuration */
static SPIInstance g_spi_instances[1] = {
[SPI_BUS_0] = {
.hspi = &g_hspi1,
},
};

void HAL_SPI_MspInit(SPI_HandleTypeDef *hspi)
{
GPIO_InitTypeDef gpio_init = { 0 };

if (hspi->Instance == SPI3) {
/* SPI3 clock enable */
__HAL_RCC_SPI3_CLK_ENABLE();
__HAL_RCC_GPIOC_CLK_ENABLE();

/* SPI1 GPIO Configuration: PC10=SCK, PC11=MISO, PC12=MOSI */
gpio_init.Pin = GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12;
gpio_init.Mode = GPIO_MODE_AF_PP;
gpio_init.Pull = GPIO_NOPULL;
gpio_init.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
gpio_init.Alternate = GPIO_AF6_SPI3;
HAL_GPIO_Init(GPIOC, &gpio_init);

} else {
THROW(ERROR_INVALID_ARGUMENT);
}
}

/**
* @brief Initialize the SPI peripheral.
*
* @param bus SPI bus instance to initialize
*/
void SPI_LL_init(SPI_Bus bus)
{
if (bus >= SPI_BUS_COUNT) {
THROW(ERROR_INVALID_ARGUMENT);
}

SPIInstance *instance = &g_spi_instances[bus];
if (instance->initialized) {
return;
}
SPI_TypeDef *spi_instance[SPI_BUS_COUNT] = {
[SPI_BUS_0] = SPI3,
};

/* Initialize SPI1 */
instance->hspi->Instance = spi_instance[bus];
instance->hspi->Init.Mode = SPI_MODE_MASTER;
instance->hspi->Init.Direction = SPI_DIRECTION_2LINES;
instance->hspi->Init.DataSize = SPI_DATASIZE_8BIT;
instance->hspi->Init.CLKPolarity = SPI_POLARITY_LOW;
instance->hspi->Init.CLKPhase = SPI_PHASE_1EDGE;
instance->hspi->Init.NSS = SPI_NSS_SOFT;
instance->hspi->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
instance->hspi->Init.FirstBit = SPI_FIRSTBIT_MSB;
instance->hspi->Init.TIMode = SPI_TIMODE_DISABLE;
instance->hspi->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;

if (HAL_SPI_Init(instance->hspi) != HAL_OK) {
THROW(ERROR_HARDWARE_FAULT);
}
instance->initialized = true;
}

/**
* @brief Deinitialize the SPI peripheral.
*
* @param bus SPI bus instance to deinitialize
*/
void SPI_LL_deinit(SPI_Bus bus)
{
if (bus >= SPI_BUS_COUNT) {
THROW(ERROR_INVALID_ARGUMENT);
}

SPIInstance *instance = &g_spi_instances[bus];
if (!instance->initialized) {
return;
}

/* Deinitialize SPI */
if (HAL_SPI_DeInit(instance->hspi) != HAL_OK) {
THROW(ERROR_HARDWARE_FAULT);
}
instance->initialized = false;
}

/**
* @brief Transmit data over SPI.
*
* @param bus SPI bus instance to use
* @param data Pointer to the data buffer to transmit
* @param size Size of the data buffer
*/
void SPI_LL_transmit(SPI_Bus bus, uint8_t const *txdata, size_t size)
{
if (bus >= SPI_BUS_COUNT) {
THROW(ERROR_INVALID_ARGUMENT);
}

SPIInstance *instance = &g_spi_instances[bus];
if (!instance->initialized) {
THROW(ERROR_INVALID_ARGUMENT);
}

// Start the transmission
HAL_SPI_Transmit(instance->hspi, (uint8_t *)txdata, size, HAL_MAX_DELAY);
}
/**
* @brief Receive data over SPI.
*
* @param bus SPI bus instance to use
* @param data Pointer to the buffer to store received data
* @param size Size of the data buffer
*/

void SPI_LL_receive(SPI_Bus bus, uint8_t *rxdata, size_t size)
{
if (bus >= SPI_BUS_COUNT) {
THROW(ERROR_INVALID_ARGUMENT);
}

SPIInstance *instance = &g_spi_instances[bus];
if (!instance->initialized) {
THROW(ERROR_INVALID_ARGUMENT);
}

// Start the reception
HAL_SPI_Receive(instance->hspi, rxdata, size, HAL_MAX_DELAY);
}

/**
* @brief Transmit and receive data over SPI.
*
* @param bus SPI bus instance to use
* @param tx_data Pointer to the data buffer to transmit
* @param rx_data Pointer to the buffer to store received data
* @param size Size of the data buffer
*/
void SPI_LL_transmit_receive(
SPI_Bus bus,
uint8_t const *tx_data,
uint8_t *rx_data,
size_t size
)
{
if (bus >= SPI_BUS_COUNT) {
THROW(ERROR_INVALID_ARGUMENT);
}

SPIInstance *instance = &g_spi_instances[bus];
if (!instance->initialized) {
THROW(ERROR_INVALID_ARGUMENT);
}

// Start the transmission and reception
HAL_SPI_TransmitReceive(
instance->hspi, (uint8_t *)tx_data, rx_data, size, HAL_MAX_DELAY
);
}
2 changes: 1 addition & 1 deletion src/platform/h563xx/stm32h5xx_hal_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ extern "C" {
// #define HAL_SDRAM_MODULE_ENABLED
// #define HAL_SMARTCARD_MODULE_ENABLED
// #define HAL_SMBUS_MODULE_ENABLED
// #define HAL_SPI_MODULE_ENABLED
#define HAL_SPI_MODULE_ENABLED
// #define HAL_SRAM_MODULE_ENABLED
#define HAL_TIM_MODULE_ENABLED
#define HAL_UART_MODULE_ENABLED
Expand Down
55 changes: 55 additions & 0 deletions src/platform/spi_ll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/**
* @file spi_ll.h
* @brief SPI low-level hardware interface for STM32H563xx
*/

#ifndef SPI_LL_H
#define SPI_LL_H

#include <stddef.h>
#include <stdint.h>

/**
* @brief SPI bus instance enumeration
*/
typedef enum { SPI_BUS_0 = 0, SPI_BUS_COUNT = 1 } SPI_Bus;

/**
* @brief Initialize the SPI peripheral.
*/
void SPI_LL_init(SPI_Bus bus);

/**
* @brief Deinitialize the SPI peripheral.
* @param bus SPI bus instance to deinitialize.
*/
void SPI_LL_deinit(SPI_Bus bus);

/**
* @brief Transmit data over SPI.
* @param txdata Pointer to the data buffer to transmit.
* @param size Size of the data buffer.
*/
void SPI_LL_transmit(SPI_Bus bus, uint8_t const *txdata, size_t size);

/**
* @brief Receive data over SPI.
* @param rxdata Pointer to the buffer to store received data.
* @param size Size of the data buffer.
*/
void SPI_LL_receive(SPI_Bus bus, uint8_t *rxdata, size_t size);

/**
* @brief Transmit and receive data over SPI.
* @param tx_data Pointer to the data buffer to transmit.
* @param rx_data Pointer to the buffer to store received data.
* @param size Size of the data buffer.
*/
void SPI_LL_transmit_receive(
SPI_Bus bus,
uint8_t const *tx_data,
uint8_t *rx_data,
size_t size
);

#endif /* SPI_LL_H */
1 change: 1 addition & 0 deletions src/system/bus/CMakeLists.target.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ target_include_directories(pslab-system

target_sources(pslab-system
PRIVATE
spi.c
uart.c
usb.c
)
Loading
Loading