From 1876a1808ce4ebb42f7b266e7113457eaddecfe7 Mon Sep 17 00:00:00 2001 From: Jakub Kaszowski Date: Mon, 16 Jun 2025 21:32:42 +0200 Subject: [PATCH 1/5] Rework uart --- bsp/CMakeLists.txt | 1 + bsp/drivers/clock/clock.cpp | 59 +++++++++++++++++++------------------ bsp/drivers/uart/uart.cpp | 35 ++++++++++++++++++---- bsp/drivers/uart/uart.hpp | 9 ++++++ src/interrupts.c | 7 +++-- src/main.cpp | 37 +++++++++++++---------- 6 files changed, 97 insertions(+), 51 deletions(-) diff --git a/bsp/CMakeLists.txt b/bsp/CMakeLists.txt index ae39242..db2f378 100644 --- a/bsp/CMakeLists.txt +++ b/bsp/CMakeLists.txt @@ -15,5 +15,6 @@ target_include_directories( ${CMAKE_SOURCE_DIR}/thirdparty/cmsis-device-h5/Include ${CMAKE_SOURCE_DIR}/thirdparty/STM32CubeH5/Drivers/STM32H5xx_HAL_Driver/Inc ${CMAKE_SOURCE_DIR}/thirdparty/fatfs/source + ${CMAKE_SOURCE_DIR}/thirdparty/etl/include ${CMAKE_SOURCE_DIR}/bsp ) diff --git a/bsp/drivers/clock/clock.cpp b/bsp/drivers/clock/clock.cpp index ce42984..d695368 100644 --- a/bsp/drivers/clock/clock.cpp +++ b/bsp/drivers/clock/clock.cpp @@ -51,25 +51,27 @@ clock_setup_HSE(uint8_t M, uint32_t N, uint8_t Q, uint8_t P) uint8_t pll2_m = 16; uint32_t pll2_n = 192; uint8_t pll2_r = 4; - // set as 100 MHz - RCC->CR &= ~RCC_CR_PLL2ON; - - // Set source for PLL 1 - RCC->PLL2CFGR |= (pll2_m << RCC_PLL2CFGR_PLL2M_Pos); // Set dividers for PLL 1 - //Enable outputs $ - RCC->PLL2CFGR |= RCC_PLL2CFGR_PLL2REN; - - RCC->PLL2DIVR |= ((pll2_r-1) << RCC_PLL2DIVR_PLL2R_Pos | ((pll2_n-1)&RCC_PLL2DIVR_PLL2N) ); - // Set HSE as source for PLL 1 - RCC->PLL2CFGR |= 3 << RCC_PLL2CFGR_PLL2SRC_Pos; - // Enable PLL 1 - RCC->CR |= RCC_CR_PLL2ON; - - // Wait for PLL to stabilize - while (!(RCC->CR & RCC_CR_PLL2RDY_Msk)) - ; - // Makes SDMMC use PLL 2 - RCC->CCIPR4 |= (1 << RCC_CCIPR4_SDMMC1SEL_Pos); + // set as 100 MHz + RCC->CR &= ~RCC_CR_PLL2ON; + + // Set source for PLL 1 + RCC->PLL2CFGR |= (pll2_m << RCC_PLL2CFGR_PLL2M_Pos); // Set dividers for PLL 1 + //Enable outputs $ + RCC->PLL2CFGR |= RCC_PLL2CFGR_PLL2REN; + + RCC->PLL2DIVR |= ((pll2_r - 1) << RCC_PLL2DIVR_PLL2R_Pos | ((pll2_n - 1) & RCC_PLL2DIVR_PLL2N)); + // Set HSE as source for PLL 1 + RCC->PLL2CFGR |= 3 << RCC_PLL2CFGR_PLL2SRC_Pos; + // Enable PLL 1 + RCC->CR |= RCC_CR_PLL2ON; + + // Wait for PLL to stabilize + while (!(RCC->CR & RCC_CR_PLL2RDY_Msk)) + ; + // Makes SDMMC use PLL 2 + RCC->CCIPR4 |= (1 << RCC_CCIPR4_SDMMC1SEL_Pos); + + RCC->AHB1ENR |= RCC_AHB1ENR_BKPRAMEN; } static uint32_t ticks = 0; @@ -81,11 +83,7 @@ sleep_ms(uint32_t ms) ; } - - -extern "C"{ - - +extern "C" { void SysTick_Handler(void) @@ -99,12 +97,15 @@ SysTick_get_tick_count() return ticks; } -uint32_t HAL_GetTick(){ - return ticks; +uint32_t +HAL_GetTick() +{ + return ticks; } -void HAL_Delay(uint32_t t){ - sleep_ms(t); +void +HAL_Delay(uint32_t t) +{ + sleep_ms(t); } - } diff --git a/bsp/drivers/uart/uart.cpp b/bsp/drivers/uart/uart.cpp index 8ba5b70..7e8eee5 100644 --- a/bsp/drivers/uart/uart.cpp +++ b/bsp/drivers/uart/uart.cpp @@ -1,14 +1,21 @@ #include "uart.hpp" - #include "config.h" #include #include +#include "etl/queue.h" +#include "etl/string.h" + #include "stm32h533xx.h" uint8_t uart4_busy = 0; -uint8_t gotMessage = false; + +constexpr uint32_t max_messages_no = 16; +//constexpr uint32_t UART4_RX_BUFFER_SIZE = 1023; +uint8_t uart4_receive_buffer[UART4_RX_BUFFER_SIZE]; + +etl::queue, max_messages_no> queue; void print(const char* str) @@ -26,9 +33,6 @@ print(const char* str) GPDMA1_Channel0->CCR = DMA_CCR_TCIE | DMA_CCR_EN; } -constexpr const uint32_t UART4_RX_BUFFER_SIZE = 1024; -uint8_t uart4_receive_buffer[UART4_RX_BUFFER_SIZE]; - void uart4_receive_to_idle() { @@ -70,6 +74,27 @@ uart4_setup() UART4->ICR |= USART_ICR_IDLECF; NVIC_SetPriority(UART4_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 2)); NVIC_EnableIRQ(UART4_IRQn); + + uart4_receive_to_idle(); +} + +void +__uart4_received_message(uint8_t* cstr) +{ + if (queue.size() >= max_messages_no) + return; + queue.push((const char*) cstr); +} + +bool +uart4_data_received(etl::string& str) +{ + if (queue.empty()) + return false; + // str = std::move(queue.front()); + queue.pop_into(str); + return true; + // return queue.front(); } void diff --git a/bsp/drivers/uart/uart.hpp b/bsp/drivers/uart/uart.hpp index 627ee89..46f521f 100644 --- a/bsp/drivers/uart/uart.hpp +++ b/bsp/drivers/uart/uart.hpp @@ -1,14 +1,23 @@ #pragma once +#include +#include "etl/string.h" + #ifdef __cplusplus extern "C" { #endif +constexpr uint32_t UART4_RX_BUFFER_SIZE = 1023; + void print(const char* str); void uart4_receive_to_idle(); +bool uart4_data_received(etl::string& str); void uart4_setup(); void uart6_setup(); + +void __uart4_received_message(uint8_t*); + #ifdef __cplusplus } #endif diff --git a/src/interrupts.c b/src/interrupts.c index 570c083..4aaf92e 100644 --- a/src/interrupts.c +++ b/src/interrupts.c @@ -2,6 +2,9 @@ #include "stdint.h" #include "stm32h533xx.h" +void __uart4_received_message(uint8_t *); +void uart4_receive_to_idle(); + extern uint8_t uart4_busy; void GPDMA1_CH0_IRQHandler(void) { @@ -11,7 +14,6 @@ void GPDMA1_CH0_IRQHandler(void) { } } -extern uint8_t gotMessage; extern uint8_t uart4_receive_buffer[1024]; void UART4_IRQHandler(void) { @@ -24,7 +26,8 @@ void UART4_IRQHandler(void) { while (!(GPDMA1_Channel1->CSR & DMA_CSR_SUSPF)) ; GPDMA1_Channel1->CCR |= DMA_CCR_RESET; - gotMessage = 1; + __uart4_received_message(uart4_receive_buffer); + uart4_receive_to_idle(); } } } diff --git a/src/main.cpp b/src/main.cpp index 19d2c85..eb05e6c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,11 +4,10 @@ #include "drivers/gpio/gpio.hpp" #include "drivers/i2c/i2c.hpp" #include "drivers/sd/sd.hpp" -#include "proxy/logger/logger.hpp" #include "drivers/uart/uart.hpp" +#include "proxy/logger/logger.hpp" #include "etl/string.h" -#include "interrupts.h" #include "stm32h533xx.h" #include "system/system.h" @@ -20,9 +19,6 @@ int main() { - etl::string<12> str; - str.clear(); - clock_setup_HSE(16, desiredMhz, 1, 1); SystemCoreClockUpdate(); @@ -55,12 +51,25 @@ main() float vbat = 0; sd_init(); + // Enable write access to BKPSRAM + PWR->DBPCR |= PWR_DBPCR_DBP; + // Enable voltage regulator for backup domain + PWR->BDCR |= PWR_BDCR_BREN; +// uint32_t myvar; + struct backup{ + uint32_t a; + uint32_t b; + }; + auto mem = reinterpret_cast(BKPSRAM_BASE); +// mem->a = 2137; +// mem->b = 0xDEAD; list_root_directory(); + etl::string str; + while (1) { - // uart4_receive_to_idle(); dbgLed.toggle(); list_root_directory(); @@ -70,16 +79,14 @@ main() vbat = ((data[1] << 8 | data[0]) >> 1) * 1.99; vsys = ((data[3] << 8 | data[2]) >> 1) * 1.99; // static char message[128]; //= "Hello world from CanSat!!!\r\n"; - printf("System: %f mV\r\nBattery: %f mV\r\n", + printf("System: %f mV\r\nBattery: %f mV\r\nmyvar: %ld\r\n", vsys, - vbat); // @suppress("Float formatting support") - // sleep_ms(200); - // if (gotMessage) - // { - // print((const char*) uart4_receive_buffer); - // uart4_receive_to_idle(); - // gotMessage = 0; - // } + vbat, + mem->a); + + if(uart4_data_received(str)){ + printf("Got message: '%s'\r\n", str.c_str()); + } sleep_ms(1000); } } From 5f36f736883e77b882b4b32754305bc121ea1415 Mon Sep 17 00:00:00 2001 From: Jakub Kaszowski Date: Wed, 10 Sep 2025 23:10:00 +0200 Subject: [PATCH 2/5] Rework UART --- CMakeLists.txt | 5 +- bsp/CMakeLists.txt | 1 + bsp/drivers/uart/uart.cpp | 110 +++++++++++++++++++++++---------- bsp/drivers/uart/uart.hpp | 32 ++++++++-- src/interrupts.c | 47 --------------- src/interrupts.cpp | 69 +++++++++++++++++++++ src/interrupts.h | 12 ---- src/interrupts.hpp | 41 +++++++++++++ src/main.cpp | 124 +++++++++++++++++++++++++++++++------- 9 files changed, 321 insertions(+), 120 deletions(-) delete mode 100644 src/interrupts.c create mode 100644 src/interrupts.cpp delete mode 100644 src/interrupts.h create mode 100644 src/interrupts.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 7ec5914..e820a4c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,7 +32,7 @@ enable_language(ASM) set(CMAKE_EXECUTABLE_SUFFIX ".elf") set(CMAKE_C_FLAGS "${MCPU} -std=gnu11 ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror") -set(CMAKE_CXX_FLAGS "${MCPU} -std=c++17 ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror") +set(CMAKE_CXX_FLAGS "${MCPU} -std=c++20 ${MFPU} ${MFLOAT_ABI} ${RUNTIME_LIBRARY} -mthumb -Wall -Werror") set(CMAKE_EXE_LINKER_FLAGS "-T${LINKER_SCRIPT} ${RUNTIME_LIBRARY_SYSCALLS} -Wl,-Map=test.map -Wl,--gc-sections -static -Wl,--start-group -lc -lm -Wl,--end-group -u _printf_float") set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp") @@ -44,7 +44,7 @@ add_subdirectory(thirdparty) add_executable( ${PROJECT_NAME} src/main.cpp - src/interrupts.c + src/interrupts.cpp bsp/system/syscalls.c bsp/system/sysmem.c bsp/system/system_stm32h5xx.c @@ -74,6 +74,7 @@ target_include_directories( ${PROJECT_NAME} PRIVATE bsp + bsp/thirdparty/etl/include ) add_custom_command(TARGET ${CMAKE_PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_SIZE} $) diff --git a/bsp/CMakeLists.txt b/bsp/CMakeLists.txt index db2f378..3d4f7bd 100644 --- a/bsp/CMakeLists.txt +++ b/bsp/CMakeLists.txt @@ -17,4 +17,5 @@ target_include_directories( ${CMAKE_SOURCE_DIR}/thirdparty/fatfs/source ${CMAKE_SOURCE_DIR}/thirdparty/etl/include ${CMAKE_SOURCE_DIR}/bsp + ${CMAKE_SOURCE_DIR}/src ) diff --git a/bsp/drivers/uart/uart.cpp b/bsp/drivers/uart/uart.cpp index 7e8eee5..e1aff61 100644 --- a/bsp/drivers/uart/uart.cpp +++ b/bsp/drivers/uart/uart.cpp @@ -11,11 +11,57 @@ uint8_t uart4_busy = 0; -constexpr uint32_t max_messages_no = 16; -//constexpr uint32_t UART4_RX_BUFFER_SIZE = 1023; -uint8_t uart4_receive_buffer[UART4_RX_BUFFER_SIZE]; +Uart::Uart(uint8_t port_id, int interruptId) : callback(*this), port_id(port_id) +{ + GetInterruptVectorsInstance().register_callback(interruptId, callback); + if (port_id == 4) + { + uart4_setup(); + receive_to_idle(); + } +} + +// Handler for interrupts from the UART. +void +Uart::InterruptHandler(const size_t id) +{ + if (UART4->ISR & USART_ISR_IDLE) + { + UART4->ICR |= USART_ICR_IDLECF; -etl::queue, max_messages_no> queue; + if (GPDMA1_Channel1->CCR & DMA_CCR_EN) + { + *((uint8_t*) GPDMA1_Channel1->CDAR) = 0; + GPDMA1_Channel1->CCR |= DMA_CCR_SUSP; + while (!(GPDMA1_Channel1->CSR & DMA_CSR_SUSPF)) + ; + GPDMA1_Channel1->CCR |= DMA_CCR_RESET; + // __uart4_received_message(uart4_receive_buffer); + if (_queue.size() < max_messages_no) + _queue.push((const char*) _raw_rx); + receive_to_idle(); + } + } +} +bool +Uart::data_received(etl::string& str) +{ + if (_queue.empty()) + return false; + // str = std::move(queue.front()); + _queue.pop_into(str); + return true; +} + +void +Uart::receive_to_idle() +{ + UART4->ICR |= USART_ICR_IDLECF; + GPDMA1_Channel1->CBR1 = RX_BUFFER_SIZE - 1; + GPDMA1_Channel1->CDAR = (uint32_t) _raw_rx; + GPDMA1_Channel1->CSAR = (uint32_t) &UART4->RDR; + GPDMA1_Channel1->CCR = DMA_CCR_EN; +} void print(const char* str) @@ -25,7 +71,7 @@ print(const char* str) while (uart4_busy) ; uart4_busy = 1; - uint32_t bytes_amount = strlen(str); + uint32_t bytes_amount = etl::strlen(str); GPDMA1_Channel0->CBR1 = bytes_amount; GPDMA1_Channel0->CSAR = (uint32_t) str; GPDMA1_Channel0->CDAR = (uint32_t) &UART4->TDR; @@ -33,15 +79,15 @@ print(const char* str) GPDMA1_Channel0->CCR = DMA_CCR_TCIE | DMA_CCR_EN; } -void -uart4_receive_to_idle() -{ - UART4->ICR |= USART_ICR_IDLECF; - GPDMA1_Channel1->CBR1 = UART4_RX_BUFFER_SIZE; - GPDMA1_Channel1->CDAR = (uint32_t) uart4_receive_buffer; - GPDMA1_Channel1->CSAR = (uint32_t) &UART4->RDR; - GPDMA1_Channel1->CCR = DMA_CCR_EN; -} +// void +// uart4_receive_to_idle() +// { +// UART4->ICR |= USART_ICR_IDLECF; +// GPDMA1_Channel1->CBR1 = Uart4::RX_BUFFER_SIZE; +// GPDMA1_Channel1->CDAR = (uint32_t) uart4_receive_buffer; +// GPDMA1_Channel1->CSAR = (uint32_t) &UART4->RDR; +// GPDMA1_Channel1->CCR = DMA_CCR_EN; +// } void uart4_setup() @@ -75,27 +121,27 @@ uart4_setup() NVIC_SetPriority(UART4_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 1, 2)); NVIC_EnableIRQ(UART4_IRQn); - uart4_receive_to_idle(); + // uart4_receive_to_idle(); } -void -__uart4_received_message(uint8_t* cstr) -{ - if (queue.size() >= max_messages_no) - return; - queue.push((const char*) cstr); -} +// void +// __uart4_received_message(uint8_t* cstr) +// { +// if (queue.size() >= max_messages_no) +// return; +// queue.push((const char*) cstr); +// } -bool -uart4_data_received(etl::string& str) -{ - if (queue.empty()) - return false; - // str = std::move(queue.front()); - queue.pop_into(str); - return true; - // return queue.front(); -} +// bool +// uart4_data_received(etl::string& str) +// { +// if (queue.empty()) +// return false; +// // str = std::move(queue.front()); +// queue.pop_into(str); +// return true; +// // return queue.front(); +// } void uart6_setup() diff --git a/bsp/drivers/uart/uart.hpp b/bsp/drivers/uart/uart.hpp index 46f521f..62ab5f3 100644 --- a/bsp/drivers/uart/uart.hpp +++ b/bsp/drivers/uart/uart.hpp @@ -1,21 +1,45 @@ #pragma once -#include +#include "etl/queue.h" #include "etl/string.h" +#include "interrupts.hpp" +#include #ifdef __cplusplus extern "C" { #endif -constexpr uint32_t UART4_RX_BUFFER_SIZE = 1023; +class Uart +{ + constexpr static uint32_t max_messages_no = 16; + +public: + constexpr static uint32_t RX_BUFFER_SIZE = 1024; + Uart(uint8_t port_id, int interruptId); + + void InterruptHandler(const size_t id); + + bool data_received(etl::string& str); + void receive_to_idle(); + + // Callback for the interrupt handler. + etl::function_mp callback; + + //constexpr uint32_t UART4_RX_BUFFER_SIZE = 1023; + uint8_t uart4_receive_buffer[RX_BUFFER_SIZE]; + +private: + etl::queue, max_messages_no> _queue; + uint8_t port_id; + uint8_t _raw_rx[RX_BUFFER_SIZE]; +}; void print(const char* str); void uart4_receive_to_idle(); -bool uart4_data_received(etl::string& str); +// bool uart4_data_received(etl::string& str); void uart4_setup(); void uart6_setup(); - void __uart4_received_message(uint8_t*); #ifdef __cplusplus diff --git a/src/interrupts.c b/src/interrupts.c deleted file mode 100644 index 4aaf92e..0000000 --- a/src/interrupts.c +++ /dev/null @@ -1,47 +0,0 @@ -#include "interrupts.h" -#include "stdint.h" -#include "stm32h533xx.h" - -void __uart4_received_message(uint8_t *); -void uart4_receive_to_idle(); - -extern uint8_t uart4_busy; - -void GPDMA1_CH0_IRQHandler(void) { - if (GPDMA1_Channel0->CSR & DMA_CSR_TCF) { - GPDMA1_Channel0->CFCR |= DMA_CFCR_TCF; - uart4_busy = 0; - } -} - -extern uint8_t uart4_receive_buffer[1024]; - -void UART4_IRQHandler(void) { - if (UART4->ISR & USART_ISR_IDLE) { - UART4->ICR |= USART_ICR_IDLECF; - - if (GPDMA1_Channel1->CCR & DMA_CCR_EN) { - *((uint8_t *)GPDMA1_Channel1->CDAR) = 0; - GPDMA1_Channel1->CCR |= DMA_CCR_SUSP; - while (!(GPDMA1_Channel1->CSR & DMA_CSR_SUSPF)) - ; - GPDMA1_Channel1->CCR |= DMA_CCR_RESET; - __uart4_received_message(uart4_receive_buffer); - uart4_receive_to_idle(); - } - } -} - -void HardFault_Handler(void) { - volatile uint32_t *SCB_HFSR = (uint32_t *)0xE000ED2C; - volatile uint32_t *SCB_CFSR = (uint32_t *)0xE000ED28; - volatile uint32_t *SCB_BFAR = (uint32_t *)0xE000ED38; - volatile uint32_t *SCB_MMAR = (uint32_t *)0xE000ED34; - (void)SCB_HFSR; - (void)SCB_CFSR; - (void)SCB_BFAR; - (void)SCB_MMAR; - - while (1) - ; // set breakpoint here -} diff --git a/src/interrupts.cpp b/src/interrupts.cpp new file mode 100644 index 0000000..43de924 --- /dev/null +++ b/src/interrupts.cpp @@ -0,0 +1,69 @@ +#include "interrupts.hpp" +#include "etl/type_traits.h" +#include "stdint.h" +#include "stm32h533xx.h" + +// Ensure that the callback service is initialised before use. +InterruptVectors& +GetInterruptVectorsInstance() +{ + static InterruptVectors interruptVectors; + + return interruptVectors; +} + +extern "C" void __uart4_received_message(uint8_t*); +extern "C" void uart4_receive_to_idle(); + +extern uint8_t uart4_busy; + +void +GPDMA1_CH0_IRQHandler(void) +{ + if (GPDMA1_Channel0->CSR & DMA_CSR_TCF) + { + GPDMA1_Channel0->CFCR |= DMA_CFCR_TCF; + uart4_busy = 0; + } +} + +extern uint8_t uart4_receive_buffer[1024]; + +InterruptVectors& vector = GetInterruptVectorsInstance(); + +void +UART4_IRQHandler(void) +{ + vector.callback(); + // if (UART4->ISR & USART_ISR_IDLE) + // { + // UART4->ICR |= USART_ICR_IDLECF; + // + // if (GPDMA1_Channel1->CCR & DMA_CCR_EN) + // { + // *((uint8_t*) GPDMA1_Channel1->CDAR) = 0; + // GPDMA1_Channel1->CCR |= DMA_CCR_SUSP; + // while (!(GPDMA1_Channel1->CSR & DMA_CSR_SUSPF)) + // ; + // GPDMA1_Channel1->CCR |= DMA_CCR_RESET; + // __uart4_received_message(uart4_receive_buffer); + // uart4_receive_to_idle(); + // } + // } +} + +void +HardFault_Handler(void) +{ + volatile uint32_t* SCB_HFSR = (uint32_t*) 0xE000ED2C; + volatile uint32_t* SCB_CFSR = (uint32_t*) 0xE000ED28; + volatile uint32_t* SCB_BFAR = (uint32_t*) 0xE000ED38; + volatile uint32_t* SCB_MMAR = (uint32_t*) 0xE000ED34; + (void) SCB_HFSR; + (void) SCB_CFSR; + (void) SCB_BFAR; + (void) SCB_MMAR; + + while (1) + ; // set breakpoint here +} diff --git a/src/interrupts.h b/src/interrupts.h deleted file mode 100644 index e137e4b..0000000 --- a/src/interrupts.h +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#ifdef __cplusplus -extern "C" { -#endif - -void GPDMA1_CH0_IRQHandler(void); -void UART4_IRQHandler(void); -void HardFault_Handler(void); - -#ifdef __cplusplus -} -#endif diff --git a/src/interrupts.hpp b/src/interrupts.hpp new file mode 100644 index 0000000..d953553 --- /dev/null +++ b/src/interrupts.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include "etl/callback_service.h" +#include "etl/function.h" +#include "stm32h533xx.h" + +constexpr auto VECTOR_ID_OFFSET = SPI1_IRQn; +enum class VectorId +{ + SPI_1 = SPI1_IRQn, + SPI_2 = SPI2_IRQn, + SPI_3 = SPI3_IRQn, + USART_1 = USART1_IRQn, + USART_2 = USART2_IRQn, + USART_3 = USART3_IRQn, + UART_4 = UART4_IRQn, + UART_5 = UART5_IRQn, + __END, + __OFFSET = SPI_1, + __RANGE = __END - __OFFSET +}; + +constexpr auto VECTOR_ID_RANGE = + static_cast(VectorId::__END) - static_cast(VectorId::__OFFSET); + +typedef etl::callback_service InterruptVectors; + +// Ensure that the callback service is initialised before use. +InterruptVectors& GetInterruptVectorsInstance(); + +#ifdef __cplusplus +extern "C" { +#endif + +void GPDMA1_CH0_IRQHandler(void); +void UART4_IRQHandler(void); +void HardFault_Handler(void); + +#ifdef __cplusplus +} +#endif diff --git a/src/main.cpp b/src/main.cpp index eb05e6c..186a4f0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,10 +4,15 @@ #include "drivers/gpio/gpio.hpp" #include "drivers/i2c/i2c.hpp" #include "drivers/sd/sd.hpp" +#include "drivers/spi/spi.hpp" #include "drivers/uart/uart.hpp" #include "proxy/logger/logger.hpp" #include "etl/string.h" +#include "etl/string_stream.h" +#include "etl/string_utilities.h" +#include "etl/string_view.h" +#include "etl/vector.h" #include "stm32h533xx.h" #include "system/system.h" @@ -16,6 +21,40 @@ #include #include +void +parse(etl::string_view v) +{ + // etl::vector v; + if (!v.starts_with("CMD")) + { + printf("%d Wrong format!\r\n", 10); + return; + } + size_t pos = v.find(','); + while (pos != etl::string_view::npos) + { + size_t newpos = v.find(',', pos + 1); + etl::string<256> token(v.substr(pos + 1, newpos - pos)); + token.repair(); + printf("%s\r\n", token.data()); + + pos = newpos; + } + // size_t newpos = 0; + // + // while (pos != 0) + // { + // newpos = view.find(',', pos); + // if (newpos != -1) + // { + // view.substr(pos, newpos); + // printf("%s\r\n", view.data()); + // //extract string + // } + // pos = newpos; + // } +} + int main() { @@ -37,55 +76,94 @@ main() Gpio sd_d3('C', 11, Mode::AF, Type::PP, Pull::Up, Speed::VeryHigh, 12); Gpio sd_clk('C', 12, Mode::AF, Type::PP, Pull::None, Speed::VeryHigh, 12); Gpio sd_cmd('D', 2, Mode::AF, Type::PP, Pull::None, Speed::VeryHigh, 12); + Gpio spi4_sck('E', 2, Mode::AF, Type::OD, 5); + Gpio spi4_miso('E', 5, Mode::AF, Type::OD, 5); + Gpio spi4_mosi('E', 6, Mode::AF, Type::OD, 5); + Gpio accel_cs('E', 3, Mode::Out); + + Gpio spi3_sck('B', 3, Mode::AF, Type::OD, 6); + Gpio spi3_miso('D', 7, Mode::AF, Type::OD, 6); + Gpio spi3_mosi('D', 6, Mode::AF, Type::OD, 5); + Gpio bme_cs('D', 4, Mode::Out); + bme_cs.set(); + + SPI4_setup(); + SPI3_setup(); + Uart gs(4, UART4_IRQn); xbeeRst.set(); mux.set(); + accel_cs.set(); uart4_setup(); I2C2_setup(); - uint8_t bq_config[1] = {1 << 7 | 3 << 4 | 1 << 2}; - I2C2_Master_Write(0x6B, 0x26, bq_config, 1); + uint8_t bq_config[1] = {1 << 7 | 3 << 4 | 1 << 3 | 1 << 2}; + I2C2_Master_Write((0x6B | 0x01), 0x26, bq_config, 1); uint8_t data[16] = {}; - float vsys = 0; - float vbat = 0; + // float vsys = 0; + // float vbat = 0; sd_init(); // Enable write access to BKPSRAM PWR->DBPCR |= PWR_DBPCR_DBP; // Enable voltage regulator for backup domain PWR->BDCR |= PWR_BDCR_BREN; -// uint32_t myvar; - struct backup{ - uint32_t a; - uint32_t b; + // uint32_t myvar; + struct backup + { + uint32_t a; + uint32_t b; }; - auto mem = reinterpret_cast(BKPSRAM_BASE); -// mem->a = 2137; -// mem->b = 0xDEAD; + // auto mem = reinterpret_cast(BKPSRAM_BASE); + // mem->a = 2137; + // mem->b = 0xDEAD; list_root_directory(); - etl::string str; + etl::string str; + + // accel_cs.reset(); + // uint8_t tx_config[2]={0x12, 0x08}; + // SPI4_Transmit_HalfDuplex(tx_config, 2); + // accel_cs.set(); + uint8_t bmp_setup[] = {0x09 | 0x80, 0xAA, 0xAA, 0xAA, 0xAA}; + // etl::string<256> input = "CMD,2044,CX,ON\r\n"; while (1) { dbgLed.toggle(); - list_root_directory(); + bme_cs.reset(); + uint8_t* rec = SPI3_xfer(bmp_setup, 5); + (void) rec; + bme_cs.set(); + + // accel_cs.reset(); + // uint8_t tx_data[16]={0x0F}; + // uint8_t rx_data[16]={}; + // SPI4_Transmit_HalfDuplex(tx_data, 1); + // SPI4_Receive_HalfDuplex(rx_data, 1); + // accel_cs.set(); + + // list_root_directory(); I2C2_Master_Read(0x6B, 0x30, data, 4); // raw_reading = (data[1] << 8 | data[0]) >> 1; - vbat = ((data[1] << 8 | data[0]) >> 1) * 1.99; - vsys = ((data[3] << 8 | data[2]) >> 1) * 1.99; - // static char message[128]; //= "Hello world from CanSat!!!\r\n"; - printf("System: %f mV\r\nBattery: %f mV\r\nmyvar: %ld\r\n", - vsys, - vbat, - mem->a); - - if(uart4_data_received(str)){ - printf("Got message: '%s'\r\n", str.c_str()); + // vbat = ((data[1] << 8 | data[0]) >> 1) * 1.99; + // vsys = ((data[3] << 8 | data[2]) >> 1) * 1.99; + // static char message[128]; //= "Hello world from CanSat!!!\r\n"; + // printf("System: %f mV\r\nBattery: %f mV\r\nmyvar: %ld\r\n", vsys, vbat, mem->a); + + // if (uart4_data_received(str)) + // { + // // printf("Got message: '%s'\r\n", str.c_str()); + // parse(str); + // } + if (gs.data_received(str)) + { + printf("Got message: '%s'\r\n", str.c_str()); + str.clear(); } sleep_ms(1000); } From 621886237c49baa046f886499918813d039771d0 Mon Sep 17 00:00:00 2001 From: Jakub Kaszowski Date: Wed, 10 Sep 2025 23:10:32 +0200 Subject: [PATCH 3/5] Add a basic SPI driver --- bsp/CMakeLists.txt | 1 + bsp/drivers/spi/spi.cpp | 140 ++++++++++++++++++++++++++++++++++++++++ bsp/drivers/spi/spi.hpp | 17 +++++ 3 files changed, 158 insertions(+) create mode 100644 bsp/drivers/spi/spi.cpp create mode 100644 bsp/drivers/spi/spi.hpp diff --git a/bsp/CMakeLists.txt b/bsp/CMakeLists.txt index 3d4f7bd..68ea432 100644 --- a/bsp/CMakeLists.txt +++ b/bsp/CMakeLists.txt @@ -5,6 +5,7 @@ add_library(bsplib drivers/i2c/i2c.cpp drivers/sd/sd.cpp drivers/uart/uart.cpp + drivers/spi/spi.cpp proxy/logger/logger.cpp ) diff --git a/bsp/drivers/spi/spi.cpp b/bsp/drivers/spi/spi.cpp new file mode 100644 index 0000000..ef864ff --- /dev/null +++ b/bsp/drivers/spi/spi.cpp @@ -0,0 +1,140 @@ +#include "spi.hpp" + +#include "stm32h533xx.h" + + +uint8_t* SPI3_xfer(uint8_t* data, uint8_t size) { + // Set SPI to transmit mode + SPI3->CR1 &= ~SPI_CR1_SPE; + SPI3->CR2 = size; + SPI3->CR1 |= SPI_CR1_SPE; + static uint8_t recv[128]; + + for (uint16_t i = 0; i < size; i++) { + SPI3->TXDR = data[i]; + recv[i] = SPI3->RXDR; +// while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion + } + return recv; +} + +void SPI4_Receive_HalfDuplex(uint8_t *data, uint16_t size) { + + // Set SPI to receive mode + SPI4->CR1 &= ~SPI_CR1_SPE; + SPI4->CR1 &= ~SPI_CR1_HDDIR; // BIDIOE = 0 for receive + SPI4->CR2 = size; + SPI4->CR1 |= SPI_CR1_SPE; + + // Initiate reception (e.g., by writing dummy data for master to generate clocks) + // As mentioned, for half-duplex receive, if the slave needs clocks from the master, + // the master will perform dummy writes to SPI4->DR to generate those clocks. + // However, the data read will come from the slave. + + for (uint16_t i = 0; i < size; i++) { + // Dummy write to generate clock pulses (if your slave needs them to send data) + // Ensure you toggle BIDIOE back to transmit for *this specific dummy write* if needed + // but typically, once in RX mode, you just wait for RXNE after the initial setup. + // If your slave simply starts sending data when NSS is asserted, no dummy write is needed. + // If your slave waits for a master clock, a dummy write would be done here: + SPI4->CR1 |= SPI_CR1_HDDIR; + SPI4->TXDR = 0xFF; + SPI4->CR1 &= ~SPI_CR1_HDDIR; + // while (!(SPI4->SR & SPI_SR_TXE)); // Wait for dummy transmit to start clock generation + + // Wait until receive buffer is not empty +// while (!(SPI4->SR & SPI_SR_EOT)); // Wait for transfer completion + while(!(SPI4->SR & SPI_SR_RXP)) + ; + // Read data from the data register + data[i] = SPI4->RXDR; + } + + // Wait until not busy (if applicable after reading all data) +// while (!(SPI4->SR & SPI_SR_EOT)); // Wait for transfer completion + +} + + +void SPI4_Transmit_HalfDuplex(uint8_t *data, uint16_t size) { + // Set SPI to transmit mode + SPI4->CR1 &= ~SPI_CR1_SPE; + SPI4->CR1 |= SPI_CR1_HDDIR; // Set transmitte + SPI4->CR2 = size; + SPI4->CR1 |= SPI_CR1_SPE; + + for (uint16_t i = 0; i < size; i++) { + // Wait until transmit buffer is empty + + + // Write data to the data register + SPI4->TXDR = data[i]; +// while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion + } + + // Wait until transmission is complete (BSY flag clear) +// while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion +} + + +void SPI4_setup(){ + RCC->APB2ENR |= RCC_APB2ENR_SPI4EN; + + RCC->CCIPR3 &= ~RCC_CCIPR3_SPI4SEL; + // Just use directly HSE as clk source +// RCC->CCIPR3 |= (0b101 << RCC_CCIPR3_SPI4SEL_Pos); + // Half duplex mode +// SPI4->CFG2 |= (0b11 << SPI_CFG2_COMM_Pos); + // 1. Disable SPI4 to configure it + SPI4->CR1 &= ~SPI_CR1_SPE; // Clear SPE bit using the defined bit mask + + // 2. Configure CR1 + SPI4->CR1 = 0; // Reset CR1 for clean configuration + + // Master mode (MSTR) + SPI4->CFG1 = 0; + SPI4->CFG2 = 0; + SPI4->CFG1 &= ~(SPI_CFG1_MBR | SPI_CFG1_DSIZE); + SPI4->CFG1 |= (1 << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); + + // Half-duplex mode (BIDIMODE) + SPI4->CFG2 |= (1 << SPI_CFG2_AFCNTR_Pos) | SPI_CFG2_MASTER | (0b11 << SPI_CFG2_COMM_Pos); + + + // 4. Enable SPI4 + SPI4->IFCR |= SPI_IFCR_MODFC; + SPI4->CR1 |= SPI_CR1_SPE; + +} + + +void SPI3_setup(){ + RCC->APB1LENR |= RCC_APB1LENR_SPI3EN; + +// RCC->CCIPR3 &= ~RCC_CCIPR3_SPI4SEL; + // Just use directly HSE as clk source +// RCC->CCIPR3 |= (0b101 << RCC_CCIPR3_SPI4SEL_Pos); + // Half duplex mode +// SPI4->CFG2 |= (0b11 << SPI_CFG2_COMM_Pos); + // 1. Disable SPI4 to configure it + SPI3->CR1 &= ~SPI_CR1_SPE; // Clear SPE bit using the defined bit mask + + // 2. Configure CR1 + SPI3->CR1 = 0; // Reset CR1 for clean configuration + + // Master mode (MSTR) +// SPI3->CFG1 = 0; +// SPI3->CFG2 = 0; + SPI3->CFG1 &= ~(SPI_CFG1_MBR | SPI_CFG1_DSIZE); + SPI3->CFG1 |= (0b100 << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); + + // Half-duplex mode (BIDIMODE) + SPI3->CFG2 |= (1 << SPI_CFG2_MASTER_Pos); + + + // 4. Enable SPI4 +// SPI3->IFCR |= SPI_IFCR_MODFC; + SPI3->CR1 |= SPI_CR1_SPE; + +} + diff --git a/bsp/drivers/spi/spi.hpp b/bsp/drivers/spi/spi.hpp new file mode 100644 index 0000000..3ad0cf3 --- /dev/null +++ b/bsp/drivers/spi/spi.hpp @@ -0,0 +1,17 @@ +#pragma once + +#ifdef __cplusplus +extern "C"{ +#endif +#include + +void SPI4_setup(); +void SPI4_Transmit_HalfDuplex(uint8_t *data, uint16_t size); +void SPI4_Receive_HalfDuplex(uint8_t *data, uint16_t size); + +void SPI3_setup(); +uint8_t* SPI3_xfer(uint8_t* data, uint8_t size); + +#ifdef __cplusplus +} +#endif From ee617386473ef5e15c45a35fcc1e7639a5691811 Mon Sep 17 00:00:00 2001 From: Jakub Kaszowski Date: Wed, 10 Sep 2025 23:11:34 +0200 Subject: [PATCH 4/5] Fix comments --- bsp/drivers/clock/clock.cpp | 4 ++-- bsp/drivers/sd/sd.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bsp/drivers/clock/clock.cpp b/bsp/drivers/clock/clock.cpp index d695368..a19c63e 100644 --- a/bsp/drivers/clock/clock.cpp +++ b/bsp/drivers/clock/clock.cpp @@ -54,7 +54,7 @@ clock_setup_HSE(uint8_t M, uint32_t N, uint8_t Q, uint8_t P) // set as 100 MHz RCC->CR &= ~RCC_CR_PLL2ON; - // Set source for PLL 1 + // Set source for PLL 2 RCC->PLL2CFGR |= (pll2_m << RCC_PLL2CFGR_PLL2M_Pos); // Set dividers for PLL 1 //Enable outputs $ RCC->PLL2CFGR |= RCC_PLL2CFGR_PLL2REN; @@ -62,7 +62,7 @@ clock_setup_HSE(uint8_t M, uint32_t N, uint8_t Q, uint8_t P) RCC->PLL2DIVR |= ((pll2_r - 1) << RCC_PLL2DIVR_PLL2R_Pos | ((pll2_n - 1) & RCC_PLL2DIVR_PLL2N)); // Set HSE as source for PLL 1 RCC->PLL2CFGR |= 3 << RCC_PLL2CFGR_PLL2SRC_Pos; - // Enable PLL 1 + // Enable PLL 2 RCC->CR |= RCC_CR_PLL2ON; // Wait for PLL to stabilize diff --git a/bsp/drivers/sd/sd.cpp b/bsp/drivers/sd/sd.cpp index 647a08c..6671f93 100644 --- a/bsp/drivers/sd/sd.cpp +++ b/bsp/drivers/sd/sd.cpp @@ -35,7 +35,7 @@ sd_init() hsd1.Instance = SDMMC1; hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; - hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B; // Start with 1-bit + hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B; hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; hsd1.Init.ClockDiv = 3; if (HAL_SD_Init(&hsd1) == HAL_OK) From 7037f228e3acde50ed0d460623c2cc3eb8fb6f00 Mon Sep 17 00:00:00 2001 From: Jakub Kaszowski Date: Wed, 10 Sep 2025 23:15:42 +0200 Subject: [PATCH 5/5] Reformat SPI driver --- bsp/drivers/spi/spi.cpp | 193 +++++++++++++++------------------------- 1 file changed, 70 insertions(+), 123 deletions(-) diff --git a/bsp/drivers/spi/spi.cpp b/bsp/drivers/spi/spi.cpp index ef864ff..1d435c7 100644 --- a/bsp/drivers/spi/spi.cpp +++ b/bsp/drivers/spi/spi.cpp @@ -2,139 +2,86 @@ #include "stm32h533xx.h" - -uint8_t* SPI3_xfer(uint8_t* data, uint8_t size) { - // Set SPI to transmit mode - SPI3->CR1 &= ~SPI_CR1_SPE; - SPI3->CR2 = size; - SPI3->CR1 |= SPI_CR1_SPE; - static uint8_t recv[128]; - - for (uint16_t i = 0; i < size; i++) { - SPI3->TXDR = data[i]; - recv[i] = SPI3->RXDR; -// while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion - } - return recv; +uint8_t* +SPI3_xfer(uint8_t* data, uint8_t size) +{ + // Set SPI to transmit mode + SPI3->CR1 &= ~SPI_CR1_SPE; + SPI3->CR2 = size; + SPI3->CR1 |= SPI_CR1_SPE; + static uint8_t recv[128]; + + for (uint16_t i = 0; i < size; i++) + { + SPI3->TXDR = data[i]; + recv[i] = SPI3->RXDR; + // while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion + } + return recv; } -void SPI4_Receive_HalfDuplex(uint8_t *data, uint16_t size) { - - // Set SPI to receive mode - SPI4->CR1 &= ~SPI_CR1_SPE; - SPI4->CR1 &= ~SPI_CR1_HDDIR; // BIDIOE = 0 for receive - SPI4->CR2 = size; - SPI4->CR1 |= SPI_CR1_SPE; - - // Initiate reception (e.g., by writing dummy data for master to generate clocks) - // As mentioned, for half-duplex receive, if the slave needs clocks from the master, - // the master will perform dummy writes to SPI4->DR to generate those clocks. - // However, the data read will come from the slave. - - for (uint16_t i = 0; i < size; i++) { - // Dummy write to generate clock pulses (if your slave needs them to send data) - // Ensure you toggle BIDIOE back to transmit for *this specific dummy write* if needed - // but typically, once in RX mode, you just wait for RXNE after the initial setup. - // If your slave simply starts sending data when NSS is asserted, no dummy write is needed. - // If your slave waits for a master clock, a dummy write would be done here: - SPI4->CR1 |= SPI_CR1_HDDIR; - SPI4->TXDR = 0xFF; - SPI4->CR1 &= ~SPI_CR1_HDDIR; - // while (!(SPI4->SR & SPI_SR_TXE)); // Wait for dummy transmit to start clock generation - - // Wait until receive buffer is not empty -// while (!(SPI4->SR & SPI_SR_EOT)); // Wait for transfer completion - while(!(SPI4->SR & SPI_SR_RXP)) - ; - // Read data from the data register - data[i] = SPI4->RXDR; - } - - // Wait until not busy (if applicable after reading all data) -// while (!(SPI4->SR & SPI_SR_EOT)); // Wait for transfer completion - +void +SPI4_Receive_HalfDuplex(uint8_t* data, uint16_t size) +{ + SPI4->CR1 &= ~SPI_CR1_SPE; + SPI4->CR1 &= ~SPI_CR1_HDDIR; // BIDIOE = 0 for receive + SPI4->CR2 = size; + SPI4->CR1 |= SPI_CR1_SPE; + + for (uint16_t i = 0; i < size; i++) + { + SPI4->CR1 |= SPI_CR1_HDDIR; + SPI4->TXDR = 0xFF; + SPI4->CR1 &= ~SPI_CR1_HDDIR; + while (!(SPI4->SR & SPI_SR_RXP)) + ; + data[i] = SPI4->RXDR; + } } - -void SPI4_Transmit_HalfDuplex(uint8_t *data, uint16_t size) { - // Set SPI to transmit mode - SPI4->CR1 &= ~SPI_CR1_SPE; - SPI4->CR1 |= SPI_CR1_HDDIR; // Set transmitte - SPI4->CR2 = size; - SPI4->CR1 |= SPI_CR1_SPE; - - for (uint16_t i = 0; i < size; i++) { - // Wait until transmit buffer is empty - - - // Write data to the data register - SPI4->TXDR = data[i]; -// while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion - } - - // Wait until transmission is complete (BSY flag clear) -// while (!(SPI4->SR & SPI_SR_TXC)); // Wait for transfer completion +void +SPI4_Transmit_HalfDuplex(uint8_t* data, uint16_t size) +{ + SPI4->CR1 &= ~SPI_CR1_SPE; + SPI4->CR1 |= SPI_CR1_HDDIR; // Set transmitte + SPI4->CR2 = size; + SPI4->CR1 |= SPI_CR1_SPE; + + for (uint16_t i = 0; i < size; i++) + { + SPI4->TXDR = data[i]; + } } +void +SPI4_setup() +{ + RCC->APB2ENR |= RCC_APB2ENR_SPI4EN; -void SPI4_setup(){ - RCC->APB2ENR |= RCC_APB2ENR_SPI4EN; + RCC->CCIPR3 &= ~RCC_CCIPR3_SPI4SEL; + SPI4->CR1 &= ~SPI_CR1_SPE; // Clear SPE bit using the defined bit mask + SPI4->CR1 = 0; // Reset CR1 for clean configuration - RCC->CCIPR3 &= ~RCC_CCIPR3_SPI4SEL; - // Just use directly HSE as clk source -// RCC->CCIPR3 |= (0b101 << RCC_CCIPR3_SPI4SEL_Pos); - // Half duplex mode -// SPI4->CFG2 |= (0b11 << SPI_CFG2_COMM_Pos); - // 1. Disable SPI4 to configure it - SPI4->CR1 &= ~SPI_CR1_SPE; // Clear SPE bit using the defined bit mask + SPI4->CFG1 = 0; + SPI4->CFG2 = 0; + SPI4->CFG1 &= ~(SPI_CFG1_MBR | SPI_CFG1_DSIZE); + SPI4->CFG1 |= (1 << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); - // 2. Configure CR1 - SPI4->CR1 = 0; // Reset CR1 for clean configuration - - // Master mode (MSTR) - SPI4->CFG1 = 0; - SPI4->CFG2 = 0; - SPI4->CFG1 &= ~(SPI_CFG1_MBR | SPI_CFG1_DSIZE); - SPI4->CFG1 |= (1 << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); - - // Half-duplex mode (BIDIMODE) - SPI4->CFG2 |= (1 << SPI_CFG2_AFCNTR_Pos) | SPI_CFG2_MASTER | (0b11 << SPI_CFG2_COMM_Pos); - - - // 4. Enable SPI4 - SPI4->IFCR |= SPI_IFCR_MODFC; - SPI4->CR1 |= SPI_CR1_SPE; + SPI4->CFG2 |= (1 << SPI_CFG2_AFCNTR_Pos) | SPI_CFG2_MASTER | (0b11 << SPI_CFG2_COMM_Pos); + // 4. Enable SPI4 + SPI4->IFCR |= SPI_IFCR_MODFC; + SPI4->CR1 |= SPI_CR1_SPE; } - -void SPI3_setup(){ - RCC->APB1LENR |= RCC_APB1LENR_SPI3EN; - -// RCC->CCIPR3 &= ~RCC_CCIPR3_SPI4SEL; - // Just use directly HSE as clk source -// RCC->CCIPR3 |= (0b101 << RCC_CCIPR3_SPI4SEL_Pos); - // Half duplex mode -// SPI4->CFG2 |= (0b11 << SPI_CFG2_COMM_Pos); - // 1. Disable SPI4 to configure it - SPI3->CR1 &= ~SPI_CR1_SPE; // Clear SPE bit using the defined bit mask - - // 2. Configure CR1 - SPI3->CR1 = 0; // Reset CR1 for clean configuration - - // Master mode (MSTR) -// SPI3->CFG1 = 0; -// SPI3->CFG2 = 0; - SPI3->CFG1 &= ~(SPI_CFG1_MBR | SPI_CFG1_DSIZE); - SPI3->CFG1 |= (0b100 << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); - - // Half-duplex mode (BIDIMODE) - SPI3->CFG2 |= (1 << SPI_CFG2_MASTER_Pos); - - - // 4. Enable SPI4 -// SPI3->IFCR |= SPI_IFCR_MODFC; - SPI3->CR1 |= SPI_CR1_SPE; - +void +SPI3_setup() +{ + RCC->APB1LENR |= RCC_APB1LENR_SPI3EN; + SPI3->CR1 &= ~SPI_CR1_SPE; // Clear SPE bit using the defined bit mask + SPI3->CR1 = 0; // Reset CR1 for clean configuration + SPI3->CFG1 &= ~(SPI_CFG1_MBR | SPI_CFG1_DSIZE); + SPI3->CFG1 |= (0b100 << SPI_CFG1_MBR_Pos) | (7 << SPI_CFG1_DSIZE_Pos); + SPI3->CFG2 |= (1 << SPI_CFG2_MASTER_Pos); + SPI3->CR1 |= SPI_CR1_SPE; } -