From 3c0e0ccae4f0ad10f07a40c75a354f931d61b980 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 11 Mar 2026 14:36:59 -0500 Subject: [PATCH 01/72] add firmware to propogate sync signal --- .../.settings/stm32cubeide.project.prefs | 4 ++ .../Firmware/motherboard_v1/Core/Src/adc.c | 13 +++- .../motherboard_v1/Core/Src/drv_gpio.c | 6 +- .../motherboard_v1/Core/Src/drv_uart.c | 71 ++++++++++++++++++- 4 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 Mainboard/Firmware/motherboard_v1/.settings/stm32cubeide.project.prefs diff --git a/Mainboard/Firmware/motherboard_v1/.settings/stm32cubeide.project.prefs b/Mainboard/Firmware/motherboard_v1/.settings/stm32cubeide.project.prefs new file mode 100644 index 00000000..5064fdc4 --- /dev/null +++ b/Mainboard/Firmware/motherboard_v1/.settings/stm32cubeide.project.prefs @@ -0,0 +1,4 @@ +2F62501ED4689FB349E356AB974DBE57=DB4D67F16CA069769A3F87733D593AF2 +8DF89ED150041C4CBC7CB9A9CAA90856=DB4D67F16CA069769A3F87733D593AF2 +DC22A860405A8BF2F2C095E5B6529F12=D1E96F3EE32E2AB2CF91940507FB3624 +eclipse.preferences.version=1 diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 153ed98c..544e01b6 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -23,6 +23,7 @@ static void setup_pin_CONVST(void); // clang-format on #define GPIO_SET_PIN(port, pin, x) port->BSRR = (x) ? pin : (pin << 16) +#define GPIO_TOGGLE_PIN(port, pin) ((port)->BSRR = ((port)->ODR & (pin)) ? ((pin) << 16) : (pin)) #define SET_PIN_CONVST12_HIGH GPIO_SET_PIN(GPIOE, GPIO_PIN_10, 1) #define SET_PIN_CONVST34_HIGH GPIO_SET_PIN(GPIOE, GPIO_PIN_11, 1) @@ -147,7 +148,8 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) void EXTI3_IRQHandler(void) { // Perform the actual SPI transactions - uint16_t new_data[8] = { 0 }; + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); // Copy data into write buffer destination @@ -214,9 +216,12 @@ static void setup_pin_SYNC_ADC(void) GPIO_InitTypeDef GPIO_InitStruct = { 0 }; __HAL_RCC_GPIOA_CLK_ENABLE(); + __HAL_RCC_GPIOD_CLK_ENABLE(); // Configure GPIO pin Output Level HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET); + // Configure GPIO pins GPIO_InitStruct.Pin = GPIO_PIN_3; @@ -225,6 +230,12 @@ static void setup_pin_SYNC_ADC(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + GPIO_InitStruct.Pin = GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + // EXTI interrupt init HAL_NVIC_SetPriority(EXTI3_IRQn, 10, 0); HAL_NVIC_EnableIRQ(EXTI3_IRQn); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_gpio.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_gpio.c index 6f861e6e..6e1ab95f 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_gpio.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_gpio.c @@ -34,7 +34,7 @@ static void MX_GPIO_Init(void) // Configure GPIO pin Output Level HAL_GPIO_WritePin(GPIOD, - GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 + GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7, GPIO_PIN_RESET); @@ -78,9 +78,9 @@ static void MX_GPIO_Init(void) HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); // Configure GPIO pins : PD8 PD9 PD10 PD11 - // PD0 PD1 PD2 PD3 + // PD3 // PD4 PD5 PD6 PD7 - GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 + GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index c81c1767..5c1e0467 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -9,6 +9,9 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) static UART_HandleTypeDef huart2; static UART_HandleTypeDef huart3; +static UART_HandleTypeDef huart4; +static UART_HandleTypeDef huart5; + void drv_uart_init(void) { // Twiddle some bits in the RCC module to set USART2 and USART3 clock source. @@ -21,8 +24,14 @@ void drv_uart_init(void) __HAL_RCC_USART2_CONFIG(RCC_USART2CLKSOURCE_SYSCLK); __HAL_RCC_USART3_CONFIG(RCC_USART3CLKSOURCE_SYSCLK); + __HAL_RCC_UART4_CONFIG(RCC_UART4CLKSOURCE_SYSCLK); + __HAL_RCC_UART5_CONFIG(RCC_UART5CLKSOURCE_SYSCLK); + MX_USART_UART_Init(&huart2, USART2); MX_USART_UART_Init(&huart3, USART3); + + MX_USART_UART_Init(&huart4, UART4); + MX_USART_UART_Init(&huart5, UART5); } static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) @@ -47,7 +56,15 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) huart->Init.WordLength = UART_WORDLENGTH_9B; huart->Init.StopBits = UART_STOPBITS_2; huart->Init.Parity = UART_PARITY_ODD; - huart->Init.Mode = UART_MODE_TX; + + if (huart->Instance == UART4) { + huart->Init.Mode = UART_MODE_TX_RX; + } else if (huart->Instance == UART5) { + huart->Init.Mode = UART_MODE_RX; + } else { + huart->Init.Mode = UART_MODE_TX; + } + huart->Init.HwFlowCtl = UART_HWCONTROL_NONE; huart->Init.OverSampling = UART_OVERSAMPLING_8; huart->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; @@ -94,6 +111,37 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Alternate = GPIO_AF7_USART3; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } + + else if (uartHandle->Instance == UART4) { + // USART3 clock enable + __HAL_RCC_UART4_CLK_ENABLE(); + + __HAL_RCC_GPIOD_CLK_ENABLE(); + // USART3 GPIO Configuration + // PD0 ------> UART4_RX + // PD1 ------> UART4_TX + GPIO_InitStruct.Pin = GPIO_PIN_0; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART4; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + } + + else if (uartHandle->Instance == UART5) { + // USART3 clock enable + __HAL_RCC_UART5_CLK_ENABLE(); + + __HAL_RCC_GPIOD_CLK_ENABLE(); + // USART3 GPIO Configuration + // PD2 ------> UART5_RX + GPIO_InitStruct.Pin = GPIO_PIN_2; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_UART5; + HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + } } void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) @@ -120,4 +168,25 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10 | GPIO_PIN_11); } + + else if (uartHandle->Instance == UART4) { + /* Peripheral clock disable */ + __HAL_RCC_UART4_CLK_DISABLE(); + + /**USART3 GPIO Configuration + PD0 ------> UART4_RX + PD1 ------> UART4_TX + */ + HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0); + } + + else if (uartHandle->Instance == UART5) { + /* Peripheral clock disable */ + __HAL_RCC_UART5_CLK_DISABLE(); + + /**USART3 GPIO Configuration + PD2 ------> UART5_RX + */ + HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2); + } } From bf488edb9394b09ae9195519f0c9a474824107a3 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 11 Mar 2026 17:04:23 -0500 Subject: [PATCH 02/72] add first attempt at implementing queue --- .../Firmware/motherboard_v1/Core/Inc/queue.h | 44 +++++++++ .../Core/Inc/stm32f7xx_hal_conf.h | 1 + .../Firmware/motherboard_v1/Core/Src/adc.c | 3 + .../motherboard_v1/Core/Src/drv_uart.c | 91 +++++++++++++++++++ .../Firmware/motherboard_v1/Core/Src/main.c | 3 + .../Firmware/motherboard_v1/Core/Src/queue.c | 67 ++++++++++++++ 6 files changed, 209 insertions(+) create mode 100644 Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h create mode 100644 Mainboard/Firmware/motherboard_v1/Core/Src/queue.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h new file mode 100644 index 00000000..5ae59228 --- /dev/null +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h @@ -0,0 +1,44 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include +#include +#include + +extern uint32_t current_id; + +typedef struct { + uint16_t samples[8]; + uint32_t item_id; +} amds_item_t; + +typedef struct { + volatile uint32_t head; // written to + volatile uint32_t tail; // read from + uint32_t mask; // for fast indexing + uint32_t capacity; + amds_item_t *buffer; +} amds_queue_t; + +// must be power of two +#define AMDS_QUEUE_SIZE 8 + +extern amds_queue_t sensor_queue; +extern amds_item_t sensor_buffer[AMDS_QUEUE_SIZE]; + +// Initialize queue: buffer must point to an array of amds_item_t of size capacity +// capacity MUST be a power of two. +void queue_init(amds_queue_t *q, amds_item_t *buffer, uint32_t capacity); +void queue_reset(amds_queue_t *q); + +// enqueue: copies item into buffer and advances head. +// Returns true on success, false if queue full (item not enqueued). +bool queue_enqueue_from_isr(amds_queue_t *q, const amds_item_t *item, uint32_t item_id); + +// dequeue: returns true and fills out when an item available. +bool queue_dequeue(amds_queue_t *q, amds_item_t *out); + +// Number of items currently in queue (head - tail) +uint32_t queue_count(const amds_queue_t *q); + +#endif // QUEUE_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h index 904591ed..6015fb97 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h @@ -151,6 +151,7 @@ #define USE_RTOS 0U #define PREFETCH_ENABLE 0U #define ART_ACCLERATOR_ENABLE 0U /* To enable instruction cache and prefetch */ +#define USE_HAL_UART_REGISTER_CALLBACKS 1U /* UART register callback disabled */ /* ########################## Assert Selection ############################## */ /** diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 544e01b6..2fd24194 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -1,4 +1,5 @@ #include "adc.h" +#include "queue.h" #include "drv_spi.h" #include "platform.h" #include "tx.h" @@ -168,6 +169,8 @@ void EXTI3_IRQHandler(void) // Call the function in tx.c to transmit the sampled data back to the AMDC transmit_samples(); + current_id = HAL_GetTick(); + // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the // ADC conversions with the SYNC signal from the AMDC. diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 5c1e0467..c6cedf13 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -1,6 +1,7 @@ #include "drv_uart.h" #include "defines.h" #include "drv_clock.h" +#include "queue.h" #include "platform.h" #include @@ -12,6 +13,73 @@ static UART_HandleTypeDef huart3; static UART_HandleTypeDef huart4; static UART_HandleTypeDef huart5; +// 3-byte packet buffers for each UART +#define PACKET_SIZE 3 +#define PACKETS_PER_UART 4 +#define TOTAL_PACKETS (PACKETS_PER_UART * 2) // 8 packets, 24 bytes total + +static uint8_t UART4_RxBuf[PACKET_SIZE]; +static uint8_t UART5_RxBuf[PACKET_SIZE]; + +// Shared 24-byte accumulator +// Layout: [UART4 pkt0..3 | UART5 pkt0..3] +static uint8_t shared_samples[TOTAL_PACKETS * PACKET_SIZE]; +static uint8_t uart4_packet_count = 0; +static uint8_t uart5_packet_count = 0; + +static void try_enqueue(void) +{ + if (uart4_packet_count == PACKETS_PER_UART && + uart5_packet_count == PACKETS_PER_UART) + { + amds_item_t item; + for (int i = 0; i < sizeof(shared_samples); i++) { + item.samples[i] = shared_samples[i]; + } + queue_enqueue_from_isr(&sensor_queue, &item, current_id); + + // Reset for next set + uart4_packet_count = 0; + uart5_packet_count = 0; + } +} + +void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) +{ + if (huart->Instance == UART4) { + if (uart4_packet_count < PACKETS_PER_UART) { + uint8_t offset = uart4_packet_count * PACKET_SIZE; // first 12 bytes + for (int i = 0; i < PACKET_SIZE; i++) { + shared_samples[offset + i] = UART4_RxBuf[i]; + } + uart4_packet_count++; + } + HAL_UART_Receive_IT(huart, UART4_RxBuf, PACKET_SIZE); + try_enqueue(); + + } else if (huart->Instance == UART5) { + if (uart5_packet_count < PACKETS_PER_UART) { + uint8_t offset = (PACKETS_PER_UART * PACKET_SIZE) + uart5_packet_count * PACKET_SIZE; // last 12 bytes + for (int i = 0; i < PACKET_SIZE; i++) { + shared_samples[offset + i] = UART5_RxBuf[i]; + } + uart5_packet_count++; + } + HAL_UART_Receive_IT(huart, UART5_RxBuf, PACKET_SIZE); + try_enqueue(); + } +} + +void UART4_IRQHandler(void) +{ + HAL_UART_IRQHandler(&huart4); +} + +void UART5_IRQHandler(void) +{ + HAL_UART_IRQHandler(&huart5); +} + void drv_uart_init(void) { // Twiddle some bits in the RCC module to set USART2 and USART3 clock source. @@ -73,6 +141,29 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) if (HAL_UART_Init(huart) != HAL_OK) { PANIC; } + + // Interrupt setup must come AFTER HAL_UART_Init() + if (huart->Instance == UART4) { + NVIC_SetPriority(UART4_IRQn, 11); + HAL_NVIC_EnableIRQ(UART4_IRQn); + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + + if (HAL_UART_Receive_IT(huart, UART4_RxBuf, PACKET_SIZE) != HAL_OK) { + PANIC; + } + } else if (huart->Instance == UART5) { + NVIC_SetPriority(UART5_IRQn, 11); + HAL_NVIC_EnableIRQ(UART5_IRQn); + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + + if (HAL_UART_Receive_IT(huart, UART5_RxBuf, PACKET_SIZE) != HAL_OK) { + PANIC; + } + } } void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index f63b3119..50873781 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -1,6 +1,7 @@ // Drivers #include "drv_clock.h" #include "drv_gpio.h" +#include "queue.h" #include "drv_i2c.h" #include "drv_led.h" #include "drv_spi.h" @@ -27,6 +28,8 @@ int main(void) // Initialize the main modules adc_init(); + queue_init(&sensor_queue, sensor_buffer, AMDS_QUEUE_SIZE); + // Infinite loop (all real work is done in ISRs) uint8_t led = 0; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/queue.c b/Mainboard/Firmware/motherboard_v1/Core/Src/queue.c new file mode 100644 index 00000000..2d65bd5a --- /dev/null +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/queue.c @@ -0,0 +1,67 @@ +#include "queue.h" +#include +#include +#include + +uint32_t current_id; +amds_queue_t sensor_queue; +amds_item_t sensor_buffer[AMDS_QUEUE_SIZE]; + +void queue_init(amds_queue_t *q, amds_item_t *buffer, uint32_t capacity) +{ + // capacity must be non-zero and power of two + q->head = 0; + q->tail = 0; + q->buffer = buffer; + q->capacity = capacity; + q->mask = capacity - 1; +} + +void queue_reset(amds_queue_t *q) +{ + q->head = 0; + q->tail = 0; +} + +bool queue_enqueue_from_isr(amds_queue_t *q, const amds_item_t *item, uint32_t item_id) +{ + uint32_t head = q->head; + uint32_t tail = q->tail; + uint32_t next = head + 1; + + // full if number of items would exceed capacity + if ((next - tail) > q->capacity) { + return false; + } + + uint32_t idx = head & q->mask; + + // copy and attach item_id (producer-only) + amds_item_t tmp = *item; + tmp.item_id = item_id; + q->buffer[idx] = tmp; + + q->head = next; + return true; +} + +bool queue_dequeue(amds_queue_t *q, amds_item_t *out) +{ + uint32_t tail = q->tail; + uint32_t head = q->head; + + if (tail == head) { + return false; + } + + uint32_t idx = tail & q->mask; + *out = q->buffer[idx]; + + q->tail = tail + 1; + return true; +} + +uint32_t queue_count(const amds_queue_t *q) +{ + return (uint32_t)(q->head - q->tail); +} From 617b21df713e7b214f3004c54006126ecce09dca Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Thu, 12 Mar 2026 16:59:36 -0500 Subject: [PATCH 03/72] add new partial DMA implementation --- .../Firmware/motherboard_v1/Core/Inc/adc.h | 1 + .../motherboard_v1/Core/Inc/drv_uart.h | 32 +++ .../Firmware/motherboard_v1/Core/Inc/queue.h | 44 ---- .../Firmware/motherboard_v1/Core/Src/adc.c | 41 +++- .../motherboard_v1/Core/Src/drv_uart.c | 197 ++++++++++++++---- .../Firmware/motherboard_v1/Core/Src/main.c | 3 - .../Firmware/motherboard_v1/Core/Src/queue.c | 67 ------ .../Firmware/motherboard_v1/Core/Src/tx.c | 80 ++++++- 8 files changed, 298 insertions(+), 167 deletions(-) delete mode 100644 Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h delete mode 100644 Mainboard/Firmware/motherboard_v1/Core/Src/queue.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h index 227d4b0d..2cfc9944 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h @@ -18,5 +18,6 @@ void adc_init(void); // but if it is called in the middle of an conversion, // one sample old data will be returned. void adc_latest_bits(uint16_t *output); +void adc_latest_amds(uint16_t *output); #endif // ADC_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 9be9a754..0bdf65e4 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -3,9 +3,41 @@ #include "platform.h" #include +#include void drv_uart_init(void); +// 16-byte accumulator +// Layout: [UART4 pkt0-3 | UART5 pkt0-3][UART4 pkt4-7 | UART5 pkt4-7] +extern volatile uint16_t latest_valid_amds_samples[2][8]; +extern volatile bool amds_samples_ready[4]; +extern volatile uint8_t uart4_amds_sample_count; +extern volatile uint8_t uart5_amds_sample_count; + + +typedef enum { + STATE_IDLE, + STATE_GOT_HEADER, + STATE_GOT_BYTE1 +} rx_state_t; + +typedef struct { + rx_state_t state; + uint8_t header; + uint8_t data[2]; + uint32_t read_index; +} uart_rx_tracker_t; + +static uart_rx_tracker_t tracker4 = {0}; +static uart_rx_tracker_t tracker5 = {0}; + +#define AMDS_RX_BUF_SIZE 256 +static uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; +static uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; + + + + static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) { // Wait until UART is ready to accept next character diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h deleted file mode 100644 index 5ae59228..00000000 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/queue.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef QUEUE_H -#define QUEUE_H - -#include -#include -#include - -extern uint32_t current_id; - -typedef struct { - uint16_t samples[8]; - uint32_t item_id; -} amds_item_t; - -typedef struct { - volatile uint32_t head; // written to - volatile uint32_t tail; // read from - uint32_t mask; // for fast indexing - uint32_t capacity; - amds_item_t *buffer; -} amds_queue_t; - -// must be power of two -#define AMDS_QUEUE_SIZE 8 - -extern amds_queue_t sensor_queue; -extern amds_item_t sensor_buffer[AMDS_QUEUE_SIZE]; - -// Initialize queue: buffer must point to an array of amds_item_t of size capacity -// capacity MUST be a power of two. -void queue_init(amds_queue_t *q, amds_item_t *buffer, uint32_t capacity); -void queue_reset(amds_queue_t *q); - -// enqueue: copies item into buffer and advances head. -// Returns true on success, false if queue full (item not enqueued). -bool queue_enqueue_from_isr(amds_queue_t *q, const amds_item_t *item, uint32_t item_id); - -// dequeue: returns true and fills out when an item available. -bool queue_dequeue(amds_queue_t *q, amds_item_t *out); - -// Number of items currently in queue (head - tail) -uint32_t queue_count(const amds_queue_t *q); - -#endif // QUEUE_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 2fd24194..712c0807 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -1,5 +1,5 @@ #include "adc.h" -#include "queue.h" +#include "drv_uart.h" #include "drv_spi.h" #include "platform.h" #include "tx.h" @@ -45,6 +45,10 @@ static void setup_pin_CONVST(void); // Buffer of latest samples static volatile uint16_t latest_valid_adc_data[8] = { 0 }; +volatile uint16_t latest_valid_amds_samples[2][8] = { 0 }; + +volatile bool amds_samples_ready[4] = { 1 }; + void adc_init(void) { // Setup output pin which starts ADC conversions @@ -70,6 +74,37 @@ void adc_latest_bits(uint16_t *output) output[7] = data[7]; } +// NOTE: this function is called from the transmit function +void adc_latest_amds(uint16_t *output) +{ + volatile uint16_t *data1 = latest_valid_amds_samples[0]; + volatile uint16_t *data2 = latest_valid_amds_samples[1]; + + if (amds_samples_ready[0] && amds_samples_ready[1]) { + // Give user their data (unrolled for speed) + output[0] = data1[0]; + output[1] = data1[1]; + output[2] = data1[2]; + output[3] = data1[3]; + output[4] = data1[4]; + output[5] = data1[5]; + output[6] = data1[6]; + output[7] = data1[7]; + } + + if (amds_samples_ready[2] && amds_samples_ready[3]) { + // Give user their data (unrolled for speed) + output[8] = data2[0]; + output[9] = data2[1]; + output[10] = data2[2]; + output[11] = data2[3]; + output[12] = data2[4]; + output[13] = data2[5]; + output[14] = data2[6]; + output[15] = data2[7]; + } +} + static void adc_sample_all_daughtercards(uint16_t *sample_data_out) { // This function has been optimized for very @@ -169,8 +204,6 @@ void EXTI3_IRQHandler(void) // Call the function in tx.c to transmit the sampled data back to the AMDC transmit_samples(); - current_id = HAL_GetTick(); - // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the // ADC conversions with the SYNC signal from the AMDC. @@ -223,7 +256,7 @@ static void setup_pin_SYNC_ADC(void) // Configure GPIO pin Output Level HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); - HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_SET); // Configure GPIO pins diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index c6cedf13..3630cf95 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -1,7 +1,6 @@ #include "drv_uart.h" #include "defines.h" #include "drv_clock.h" -#include "queue.h" #include "platform.h" #include @@ -13,66 +12,119 @@ static UART_HandleTypeDef huart3; static UART_HandleTypeDef huart4; static UART_HandleTypeDef huart5; +static DMA_HandleTypeDef hdma_uart4_rx; +static DMA_HandleTypeDef hdma_uart5_rx; + // 3-byte packet buffers for each UART #define PACKET_SIZE 3 #define PACKETS_PER_UART 4 #define TOTAL_PACKETS (PACKETS_PER_UART * 2) // 8 packets, 24 bytes total -static uint8_t UART4_RxBuf[PACKET_SIZE]; -static uint8_t UART5_RxBuf[PACKET_SIZE]; - -// Shared 24-byte accumulator -// Layout: [UART4 pkt0..3 | UART5 pkt0..3] -static uint8_t shared_samples[TOTAL_PACKETS * PACKET_SIZE]; static uint8_t uart4_packet_count = 0; static uint8_t uart5_packet_count = 0; - -static void try_enqueue(void) -{ - if (uart4_packet_count == PACKETS_PER_UART && - uart5_packet_count == PACKETS_PER_UART) - { - amds_item_t item; - for (int i = 0; i < sizeof(shared_samples); i++) { - item.samples[i] = shared_samples[i]; +volatile uint8_t uart4_amds_sample_count = 0; +volatile uint8_t uart5_amds_sample_count = 0; + +void process_uart_fifo(UART_HandleTypeDef *huart, uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { + // Calculate current DMA write position (NDTR counts down) + uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); + + while (track->read_index != dma_write_ptr) { + uint8_t byte = pool[track->read_index]; + track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; + + switch (track->state) { + case STATE_IDLE: + // Look for any valid header (0x90, 0x94, 0x98 ranges) + if ((byte & 0xF0) == 0x90) { + track->header = byte; + track->state = STATE_GOT_HEADER; + } + break; + + case STATE_GOT_HEADER: + track->data[0] = byte; + track->state = STATE_GOT_BYTE1; + break; + + case STATE_GOT_BYTE1: + track->data[1] = byte; + + // Packet Complete: Reconstruct 16-bit value + uint16_t value = ((uint16_t)track->data[0] << 8) | track->data[1]; + + // Map to your global array logic from drv_uart.c + uint8_t offset = (track->header & 0x03) + (uart_id == 5 ? 4 : 0); + uint8_t sample_set = (track->header & 0x0C) >> 2; // e.g., 0 for 0x90, 1 for 0x94 + + latest_valid_amds_samples[sample_set][offset] = value; + amds_samples_ready[sample_set] = true; + + track->state = STATE_IDLE; + break; } - queue_enqueue_from_isr(&sensor_queue, &item, current_id); - - // Reset for next set - uart4_packet_count = 0; - uart5_packet_count = 0; } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart->Instance == UART4) { - if (uart4_packet_count < PACKETS_PER_UART) { - uint8_t offset = uart4_packet_count * PACKET_SIZE; // first 12 bytes - for (int i = 0; i < PACKET_SIZE; i++) { - shared_samples[offset + i] = UART4_RxBuf[i]; - } - uart4_packet_count++; + if (uart4_packet_count < PACKETS_PER_UART) { + + uint8_t offset = uart4_packet_count; + + uint16_t value = ((uint16_t)UART4_RxBuf[1] << 8) | (uint16_t)UART4_RxBuf[2]; + + latest_valid_amds_samples[uart4_amds_sample_count][offset] = value; + + uart4_packet_count++; + } + + if (uart4_packet_count == PACKETS_PER_UART) { + amds_samples_ready[uart4_amds_sample_count] = true; + uart4_amds_sample_count++; + uart4_packet_count = 0; } - HAL_UART_Receive_IT(huart, UART4_RxBuf, PACKET_SIZE); - try_enqueue(); - } else if (huart->Instance == UART5) { - if (uart5_packet_count < PACKETS_PER_UART) { - uint8_t offset = (PACKETS_PER_UART * PACKET_SIZE) + uart5_packet_count * PACKET_SIZE; // last 12 bytes - for (int i = 0; i < PACKET_SIZE; i++) { - shared_samples[offset + i] = UART5_RxBuf[i]; - } - uart5_packet_count++; + if (uart4_amds_sample_count == 2) { + amds_samples_ready[uart4_amds_sample_count + 1] = true; + uart4_amds_sample_count = 0; } - HAL_UART_Receive_IT(huart, UART5_RxBuf, PACKET_SIZE); - try_enqueue(); +// HAL_UART_Receive_DMA(huart, UART4_RxBuf, PACKET_SIZE); + } else if (huart->Instance == UART5) { + if (uart5_packet_count < PACKETS_PER_UART) { + + uint8_t offset = uart5_packet_count + 4; + + uint16_t value = ((uint16_t)UART5_RxBuf[1] << 8) | (uint16_t)UART5_RxBuf[2]; + + latest_valid_amds_samples[uart5_amds_sample_count][offset] = value; + + uart5_packet_count++; + } + + if (uart5_packet_count == PACKETS_PER_UART) { + amds_samples_ready[uart5_amds_sample_count] = true; + uart5_amds_sample_count++; + uart5_packet_count = 0; + } + + if (uart5_amds_sample_count == 2) { + amds_samples_ready[uart5_amds_sample_count + 2] = true; + uart5_amds_sample_count = 0; + } +// HAL_UART_Receive_DMA(huart, UART5_RxBuf, PACKET_SIZE); } } void UART4_IRQHandler(void) { - HAL_UART_IRQHandler(&huart4); + HAL_UART_IRQHandler(&huart4); +} + +void DMA1_Stream2_IRQHandler(void) +{ + HAL_DMA_IRQHandler(&hdma_uart4_rx); } void UART5_IRQHandler(void) @@ -80,6 +132,11 @@ void UART5_IRQHandler(void) HAL_UART_IRQHandler(&huart5); } +void DMA1_Stream0_IRQHandler(void) +{ + HAL_DMA_IRQHandler(&hdma_uart5_rx); +} + void drv_uart_init(void) { // Twiddle some bits in the RCC module to set USART2 and USART3 clock source. @@ -135,7 +192,7 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) huart->Init.HwFlowCtl = UART_HWCONTROL_NONE; huart->Init.OverSampling = UART_OVERSAMPLING_8; - huart->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE; + huart->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_ENABLE; huart->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(huart) != HAL_OK) { @@ -144,23 +201,23 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) // Interrupt setup must come AFTER HAL_UART_Init() if (huart->Instance == UART4) { - NVIC_SetPriority(UART4_IRQn, 11); + NVIC_SetPriority(UART4_IRQn, 9); HAL_NVIC_EnableIRQ(UART4_IRQn); __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_IT(huart, UART4_RxBuf, PACKET_SIZE) != HAL_OK) { + if (HAL_UART_Receive_DMA(&huart4, uart4_rx_dma_buf, RX_DMA_BUF_SIZE) != HAL_OK) { PANIC; } - } else if (huart->Instance == UART5) { - NVIC_SetPriority(UART5_IRQn, 11); + } else if (huart->Instance == UART5) { + NVIC_SetPriority(UART5_IRQn, 9); HAL_NVIC_EnableIRQ(UART5_IRQn); __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_IT(huart, UART5_RxBuf, PACKET_SIZE) != HAL_OK) { + if (HAL_UART_Receive_DMA(&huart5, uart5_rx_dma_buf, RX_DMA_BUF_SIZE) != HAL_OK) { PANIC; } } @@ -206,6 +263,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) else if (uartHandle->Instance == UART4) { // USART3 clock enable __HAL_RCC_UART4_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); // USART3 GPIO Configuration @@ -217,11 +275,36 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF8_UART4; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + // DMA config - check your device's DMA request mapping table + // for the correct stream/channel for UART4_RX + hdma_uart4_rx.Instance = DMA1_Stream2; // verify in datasheet + hdma_uart4_rx.Init.Channel = DMA_CHANNEL_4; // HAL constant for your device + hdma_uart4_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_uart4_rx.Init.PeriphInc = DMA_PINC_DISABLE; // RDR address stays fixed + hdma_uart4_rx.Init.MemInc = DMA_MINC_ENABLE; // buffer pointer increments + hdma_uart4_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_uart4_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_uart4_rx.Init.Mode = DMA_CIRCULAR; // or DMA_CIRCULAR (see note below) + hdma_uart4_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_uart4_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + if (HAL_DMA_Init(&hdma_uart4_rx) != HAL_OK) { + PANIC; + } + + // This links the DMA handle to the UART handle + __HAL_LINKDMA(uartHandle, hdmarx, hdma_uart4_rx); + + // DMA stream IRQ + NVIC_SetPriority(DMA1_Stream2_IRQn, 7); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); } else if (uartHandle->Instance == UART5) { // USART3 clock enable __HAL_RCC_UART5_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); // USART3 GPIO Configuration @@ -232,6 +315,30 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF8_UART5; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + + // DMA config - check your device's DMA request mapping table + // for the correct stream/channel for UART4_RX + hdma_uart5_rx.Instance = DMA1_Stream0; // verify in datasheet + hdma_uart5_rx.Init.Channel = DMA_CHANNEL_4; // HAL constant for your device + hdma_uart5_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_uart5_rx.Init.PeriphInc = DMA_PINC_DISABLE; // RDR address stays fixed + hdma_uart5_rx.Init.MemInc = DMA_MINC_ENABLE; // buffer pointer increments + hdma_uart5_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_uart5_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_uart5_rx.Init.Mode = DMA_CIRCULAR; // or DMA_CIRCULAR (see note below) + hdma_uart5_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_uart5_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + if (HAL_DMA_Init(&hdma_uart5_rx) != HAL_OK) { + PANIC; + } + + // This links the DMA handle to the UART handle + __HAL_LINKDMA(uartHandle, hdmarx, hdma_uart5_rx); + + // DMA stream IRQ + NVIC_SetPriority(DMA1_Stream0_IRQn, 8); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 50873781..f63b3119 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -1,7 +1,6 @@ // Drivers #include "drv_clock.h" #include "drv_gpio.h" -#include "queue.h" #include "drv_i2c.h" #include "drv_led.h" #include "drv_spi.h" @@ -28,8 +27,6 @@ int main(void) // Initialize the main modules adc_init(); - queue_init(&sensor_queue, sensor_buffer, AMDS_QUEUE_SIZE); - // Infinite loop (all real work is done in ISRs) uint8_t led = 0; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/queue.c b/Mainboard/Firmware/motherboard_v1/Core/Src/queue.c deleted file mode 100644 index 2d65bd5a..00000000 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/queue.c +++ /dev/null @@ -1,67 +0,0 @@ -#include "queue.h" -#include -#include -#include - -uint32_t current_id; -amds_queue_t sensor_queue; -amds_item_t sensor_buffer[AMDS_QUEUE_SIZE]; - -void queue_init(amds_queue_t *q, amds_item_t *buffer, uint32_t capacity) -{ - // capacity must be non-zero and power of two - q->head = 0; - q->tail = 0; - q->buffer = buffer; - q->capacity = capacity; - q->mask = capacity - 1; -} - -void queue_reset(amds_queue_t *q) -{ - q->head = 0; - q->tail = 0; -} - -bool queue_enqueue_from_isr(amds_queue_t *q, const amds_item_t *item, uint32_t item_id) -{ - uint32_t head = q->head; - uint32_t tail = q->tail; - uint32_t next = head + 1; - - // full if number of items would exceed capacity - if ((next - tail) > q->capacity) { - return false; - } - - uint32_t idx = head & q->mask; - - // copy and attach item_id (producer-only) - amds_item_t tmp = *item; - tmp.item_id = item_id; - q->buffer[idx] = tmp; - - q->head = next; - return true; -} - -bool queue_dequeue(amds_queue_t *q, amds_item_t *out) -{ - uint32_t tail = q->tail; - uint32_t head = q->head; - - if (tail == head) { - return false; - } - - uint32_t idx = tail & q->mask; - *out = q->buffer[idx]; - - q->tail = tail + 1; - return true; -} - -uint32_t queue_count(const amds_queue_t *q) -{ - return (uint32_t)(q->head - q->tail); -} diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 2897b88e..ebc66a2d 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -18,16 +18,13 @@ void transmit_samples(void) uint16_t bits[8]; adc_latest_bits(bits); - // Send data out over UART + // Send board's own ADC data out over UART for (int i = 0; i < 4; i++) { uint16_t sample1 = bits[(4 * 0) + i]; uint16_t sample2 = bits[(4 * 1) + i]; // Send header (not the first one) if (i > 0) { - // Send header as: - // bits[7:2] = 100100 - // bits[1:0] = # of DC (2 bits, 0..3) uint8_t header = 0x90; header |= (0x03 & i); @@ -44,9 +41,84 @@ void transmit_samples(void) drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); } + // Now attempt to send AMDS samples (if ready) using same header scheme. + // adc_latest_amds() will populate the array only when the corresponding + // amds_samples_ready pairs are set. + uint16_t amds[16] = {0}; + adc_latest_amds(amds); + + first_header = 0x94; + + // First AMDS set: indices 0..7 (requires amds_samples_ready[0] && [1]) + if (amds_samples_ready[0] && amds_samples_ready[1]) { + // Send header for this set + drv_uart_putc_fast(USART2, first_header); + drv_uart_putc_fast(USART3, first_header); + + for (int i = 0; i < 4; i++) { + if (i > 0) { + uint8_t header = 0x94; + header |= (0x07 & i); + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART3, header); + } + + uint16_t sample1 = amds[(4 * 0) + i]; // amds[0..3] + uint16_t sample2 = amds[(4 * 1) + i]; // amds[4..7] + + // Send ADC sample data MSBs + drv_uart_putc_fast(USART2, (uint8_t)(sample1 >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample2 >> 8)); + + // Send ADC sample data LSBs + drv_uart_putc_fast(USART2, (uint8_t)(sample1 & 0x00FF)); + drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); + } + + // Clear flags for this set + amds_samples_ready[0] = false; + amds_samples_ready[1] = false; + + first_header = 0x98; + + // Second AMDS set: indices 8..15 (requires amds_samples_ready[2] && [3]) + // Only if the first set was successful + if (amds_samples_ready[2] && amds_samples_ready[3]) { + drv_uart_putc_fast(USART2, first_header); + drv_uart_putc_fast(USART3, first_header); + + for (int i = 0; i < 4; i++) { + if (i > 0) { + uint8_t header = 0x98; + header |= (0x0B & i); + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART3, header); + } + + uint16_t sample1 = amds[8 + (4 * 0) + i]; // amds[8..11] + uint16_t sample2 = amds[8 + (4 * 1) + i]; // amds[12..15] + + // Send ADC sample data MSBs + drv_uart_putc_fast(USART2, (uint8_t)(sample1 >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample2 >> 8)); + + // Send ADC sample data LSBs + drv_uart_putc_fast(USART2, (uint8_t)(sample1 & 0x00FF)); + drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); + } + + // Clear flags for this set + amds_samples_ready[2] = false; + amds_samples_ready[3] = false; + } + } + // Wait for entire UART transmission to complete drv_uart_wait_TC(USART2); drv_uart_wait_TC(USART3); + + uart4_amds_sample_count = 0; + uart5_amds_sample_count = 0; } From 8a087893e7e3ab8057fef039920a807194a63609 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 13 Mar 2026 12:26:24 -0500 Subject: [PATCH 04/72] add all code for dma useage --- .../motherboard_v1/Core/Inc/drv_uart.h | 32 ++- .../Firmware/motherboard_v1/Core/Src/adc.c | 44 ++- .../motherboard_v1/Core/Src/drv_uart.c | 252 +++++++++++++----- .../Firmware/motherboard_v1/Core/Src/tx.c | 99 +++++-- 4 files changed, 308 insertions(+), 119 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 0bdf65e4..59820250 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -7,6 +7,9 @@ void drv_uart_init(void); +extern UART_HandleTypeDef huart2; +extern UART_HandleTypeDef huart3; + // 16-byte accumulator // Layout: [UART4 pkt0-3 | UART5 pkt0-3][UART4 pkt4-7 | UART5 pkt4-7] extern volatile uint16_t latest_valid_amds_samples[2][8]; @@ -28,15 +31,25 @@ typedef struct { uint32_t read_index; } uart_rx_tracker_t; -static uart_rx_tracker_t tracker4 = {0}; -static uart_rx_tracker_t tracker5 = {0}; +extern uart_rx_tracker_t tracker4; +extern uart_rx_tracker_t tracker5; #define AMDS_RX_BUF_SIZE 256 -static uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; -static uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; +extern uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; +extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; + +// Define large buffers for outgoing data +#define TX_BUF_SIZE 512 +extern uint8_t usart2_tx_ring[TX_BUF_SIZE]; +extern uint8_t usart3_tx_ring[TX_BUF_SIZE]; +extern uint32_t usart2_tx_write_idx; +extern uint32_t usart3_tx_write_idx; +void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); + +void dma_send(uint8_t uart_id, uint8_t *data, uint8_t len); static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) { @@ -49,6 +62,17 @@ static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) uart->TDR = data; } +static inline void drv_uart_putc_dma(USART_TypeDef *uart, uint8_t data) +{ + if (uart == USART2) { + usart2_tx_ring[usart2_tx_write_idx] = data; + usart2_tx_write_idx = (usart2_tx_write_idx + 1) % TX_BUF_SIZE; + } else if (uart == USART3) { + usart3_tx_ring[usart3_tx_write_idx] = data; + usart3_tx_write_idx = (usart3_tx_write_idx + 1) % TX_BUF_SIZE; + } +} + static inline void drv_uart_wait_TC(USART_TypeDef *uart) { // After done sending characters, must wait for TC flag!! diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 712c0807..bd411785 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -47,7 +47,7 @@ static volatile uint16_t latest_valid_adc_data[8] = { 0 }; volatile uint16_t latest_valid_amds_samples[2][8] = { 0 }; -volatile bool amds_samples_ready[4] = { 1 }; +volatile bool amds_samples_ready[4] = { 0 }; void adc_init(void) { @@ -80,29 +80,25 @@ void adc_latest_amds(uint16_t *output) volatile uint16_t *data1 = latest_valid_amds_samples[0]; volatile uint16_t *data2 = latest_valid_amds_samples[1]; - if (amds_samples_ready[0] && amds_samples_ready[1]) { - // Give user their data (unrolled for speed) - output[0] = data1[0]; - output[1] = data1[1]; - output[2] = data1[2]; - output[3] = data1[3]; - output[4] = data1[4]; - output[5] = data1[5]; - output[6] = data1[6]; - output[7] = data1[7]; - } - - if (amds_samples_ready[2] && amds_samples_ready[3]) { - // Give user their data (unrolled for speed) - output[8] = data2[0]; - output[9] = data2[1]; - output[10] = data2[2]; - output[11] = data2[3]; - output[12] = data2[4]; - output[13] = data2[5]; - output[14] = data2[6]; - output[15] = data2[7]; - } + // Give user their data (unrolled for speed) + output[0] = data1[0]; + output[1] = data1[1]; + output[2] = data1[2]; + output[3] = data1[3]; + output[4] = data1[4]; + output[5] = data1[5]; + output[6] = data1[6]; + output[7] = data1[7]; + + // Give user their data (unrolled for speed) + output[8] = data2[0]; + output[9] = data2[1]; + output[10] = data2[2]; + output[11] = data2[3]; + output[12] = data2[4]; + output[13] = data2[5]; + output[14] = data2[6]; + output[15] = data2[7]; } static void adc_sample_all_daughtercards(uint16_t *sample_data_out) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 3630cf95..f3c4ee49 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -6,8 +6,11 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle); -static UART_HandleTypeDef huart2; -static UART_HandleTypeDef huart3; +UART_HandleTypeDef huart2; +UART_HandleTypeDef huart3; + +static DMA_HandleTypeDef hdma_usart2_tx; +static DMA_HandleTypeDef hdma_usart3_tx; static UART_HandleTypeDef huart4; static UART_HandleTypeDef huart5; @@ -15,19 +18,39 @@ static UART_HandleTypeDef huart5; static DMA_HandleTypeDef hdma_uart4_rx; static DMA_HandleTypeDef hdma_uart5_rx; +uint8_t usart2_tx_ring[TX_BUF_SIZE]; +uint8_t usart3_tx_ring[TX_BUF_SIZE]; + +uint32_t usart2_tx_write_idx = 0; +uint32_t usart3_tx_write_idx = 0; + // 3-byte packet buffers for each UART #define PACKET_SIZE 3 #define PACKETS_PER_UART 4 #define TOTAL_PACKETS (PACKETS_PER_UART * 2) // 8 packets, 24 bytes total -static uint8_t uart4_packet_count = 0; -static uint8_t uart5_packet_count = 0; +//static uint8_t uart4_packet_count = 0; +//static uint8_t uart5_packet_count = 0; volatile uint8_t uart4_amds_sample_count = 0; volatile uint8_t uart5_amds_sample_count = 0; -void process_uart_fifo(UART_HandleTypeDef *huart, uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { + +uart_rx_tracker_t tracker4 = {0}; +uart_rx_tracker_t tracker5 = {0}; + +uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; +uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; + +void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { // Calculate current DMA write position (NDTR counts down) - uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); + UART_HandleTypeDef *huart; + if (uart_id == 4) { + huart = &huart4; + } else { + huart = &huart5; + } + + uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); while (track->read_index != dma_write_ptr) { uint8_t byte = pool[track->read_index]; @@ -55,10 +78,11 @@ void process_uart_fifo(UART_HandleTypeDef *huart, uint8_t *pool, uart_rx_tracker // Map to your global array logic from drv_uart.c uint8_t offset = (track->header & 0x03) + (uart_id == 5 ? 4 : 0); - uint8_t sample_set = (track->header & 0x0C) >> 2; // e.g., 0 for 0x90, 1 for 0x94 + // uint8_t sample_set = (track->header & 0x0C) >> 2; // e.g., 0 for 0x90, 1 for 0x94 + + latest_valid_amds_samples[uart_id == 4 ? 0 : 1][offset] = value; - latest_valid_amds_samples[sample_set][offset] = value; - amds_samples_ready[sample_set] = true; + amds_samples_ready[uart_id == 4 ? 0 : 1] = true; track->state = STATE_IDLE; break; @@ -68,58 +92,70 @@ void process_uart_fifo(UART_HandleTypeDef *huart, uint8_t *pool, uart_rx_tracker void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { - if (huart->Instance == UART4) { - if (uart4_packet_count < PACKETS_PER_UART) { - - uint8_t offset = uart4_packet_count; - - uint16_t value = ((uint16_t)UART4_RxBuf[1] << 8) | (uint16_t)UART4_RxBuf[2]; - - latest_valid_amds_samples[uart4_amds_sample_count][offset] = value; - - uart4_packet_count++; - } - - if (uart4_packet_count == PACKETS_PER_UART) { - amds_samples_ready[uart4_amds_sample_count] = true; - uart4_amds_sample_count++; - uart4_packet_count = 0; - } - - if (uart4_amds_sample_count == 2) { - amds_samples_ready[uart4_amds_sample_count + 1] = true; - uart4_amds_sample_count = 0; - } -// HAL_UART_Receive_DMA(huart, UART4_RxBuf, PACKET_SIZE); - } else if (huart->Instance == UART5) { - if (uart5_packet_count < PACKETS_PER_UART) { - - uint8_t offset = uart5_packet_count + 4; - - uint16_t value = ((uint16_t)UART5_RxBuf[1] << 8) | (uint16_t)UART5_RxBuf[2]; - - latest_valid_amds_samples[uart5_amds_sample_count][offset] = value; - - uart5_packet_count++; - } - - if (uart5_packet_count == PACKETS_PER_UART) { - amds_samples_ready[uart5_amds_sample_count] = true; - uart5_amds_sample_count++; - uart5_packet_count = 0; - } - - if (uart5_amds_sample_count == 2) { - amds_samples_ready[uart5_amds_sample_count + 2] = true; - uart5_amds_sample_count = 0; - } -// HAL_UART_Receive_DMA(huart, UART5_RxBuf, PACKET_SIZE); - } +// if (huart->Instance == UART4) { +// if (uart4_packet_count < PACKETS_PER_UART) { +// +// uint8_t offset = uart4_packet_count; +// +// uint16_t value = ((uint16_t)UART4_RxBuf[1] << 8) | (uint16_t)UART4_RxBuf[2]; +// +// latest_valid_amds_samples[uart4_amds_sample_count][offset] = value; +// +// uart4_packet_count++; +// } +// +// if (uart4_packet_count == PACKETS_PER_UART) { +// amds_samples_ready[uart4_amds_sample_count] = true; +// uart4_amds_sample_count++; +// uart4_packet_count = 0; +// } +// +// if (uart4_amds_sample_count == 2) { +// amds_samples_ready[uart4_amds_sample_count + 1] = true; +// uart4_amds_sample_count = 0; +// } +//// HAL_UART_Receive_DMA(huart, UART4_RxBuf, PACKET_SIZE); +// } else if (huart->Instance == UART5) { +// if (uart5_packet_count < PACKETS_PER_UART) { +// +// uint8_t offset = uart5_packet_count + 4; +// +// uint16_t value = ((uint16_t)UART5_RxBuf[1] << 8) | (uint16_t)UART5_RxBuf[2]; +// +// latest_valid_amds_samples[uart5_amds_sample_count][offset] = value; +// +// uart5_packet_count++; +// } +// +// if (uart5_packet_count == PACKETS_PER_UART) { +// amds_samples_ready[uart5_amds_sample_count] = true; +// uart5_amds_sample_count++; +// uart5_packet_count = 0; +// } +// +// if (uart5_amds_sample_count == 2) { +// amds_samples_ready[uart5_amds_sample_count + 2] = true; +// uart5_amds_sample_count = 0; +// } +//// HAL_UART_Receive_DMA(huart, UART5_RxBuf, PACKET_SIZE); +// } } void UART4_IRQHandler(void) { - HAL_UART_IRQHandler(&huart4); + // Check for Overrun, Noise, or Frame errors + if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&huart4, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&huart4, UART_FLAG_FE)) + { + // 1. Clear the error flags + __HAL_UART_CLEAR_IT(&huart4, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + + // 2. IMPORTANT: Re-enable DMA receiver request + // Sometimes HAL disables this bit (DMAR) on error. + SET_BIT(huart4.Instance->CR3, USART_CR3_DMAR); + } + HAL_UART_IRQHandler(&huart4); } void DMA1_Stream2_IRQHandler(void) @@ -129,7 +165,19 @@ void DMA1_Stream2_IRQHandler(void) void UART5_IRQHandler(void) { - HAL_UART_IRQHandler(&huart5); + // Check for Overrun, Noise, or Frame errors + if (__HAL_UART_GET_FLAG(&huart5, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&huart5, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&huart5, UART_FLAG_FE)) + { + // 1. Clear the error flags + __HAL_UART_CLEAR_IT(&huart5, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + + // 2. IMPORTANT: Re-enable DMA receiver request + // Sometimes HAL disables this bit (DMAR) on error. + SET_BIT(huart5.Instance->CR3, USART_CR3_DMAR); + } + HAL_UART_IRQHandler(&huart5); } void DMA1_Stream0_IRQHandler(void) @@ -137,6 +185,16 @@ void DMA1_Stream0_IRQHandler(void) HAL_DMA_IRQHandler(&hdma_uart5_rx); } +void DMA1_Stream3_IRQHandler(void) +{ + HAL_DMA_IRQHandler(&hdma_usart3_tx); +} + +void DMA1_Stream6_IRQHandler(void) +{ + HAL_DMA_IRQHandler(&hdma_usart2_tx); +} + void drv_uart_init(void) { // Twiddle some bits in the RCC module to set USART2 and USART3 clock source. @@ -207,9 +265,12 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_DMA(&huart4, uart4_rx_dma_buf, RX_DMA_BUF_SIZE) != HAL_OK) { - PANIC; + if (HAL_UART_Receive_DMA(&huart4, UART4_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + PANIC; } + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); } else if (huart->Instance == UART5) { NVIC_SetPriority(UART5_IRQn, 9); HAL_NVIC_EnableIRQ(UART5_IRQn); @@ -217,9 +278,26 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_DMA(&huart5, uart5_rx_dma_buf, RX_DMA_BUF_SIZE) != HAL_OK) { - PANIC; + if (HAL_UART_Receive_DMA(&huart5, UART5_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + PANIC; } + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + } else if (huart->Instance == USART2) { + NVIC_SetPriority(USART2_IRQn, 10); + HAL_NVIC_EnableIRQ(USART2_IRQn); + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + + } else if (huart->Instance == USART3) { + NVIC_SetPriority(USART3_IRQn, 10); + HAL_NVIC_EnableIRQ(USART3_IRQn); + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + } } @@ -231,6 +309,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) if (uartHandle->Instance == USART2) { // USART2 clock enable __HAL_RCC_USART2_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // USART2 GPIO Configuration @@ -242,11 +321,33 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // DMA config - check your device's DMA request mapping table + // for the correct stream/channel for USART2_TX + hdma_usart2_tx.Instance = DMA1_Stream6; + hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4; + hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // Memory -> UART + hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart2_tx.Init.Mode = DMA_NORMAL; // Keep it looping + hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; // Let RX have higher priority + + if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK) { + PANIC; + } + __HAL_LINKDMA(uartHandle, hdmatx, hdma_usart2_tx); + + // DMA stream IRQ + NVIC_SetPriority(DMA1_Stream6_IRQn, 7); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); } else if (uartHandle->Instance == USART3) { // USART3 clock enable __HAL_RCC_USART3_CLK_ENABLE(); + __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // USART3 GPIO Configuration @@ -258,6 +359,27 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART3; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + // DMA config - check your device's DMA request mapping table + // for the correct stream/channel for USART3_TX + hdma_usart3_tx.Instance = DMA1_Stream3; + hdma_usart3_tx.Init.Channel = DMA_CHANNEL_4; + hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // Memory -> UART + hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_usart3_tx.Init.Mode = DMA_NORMAL; // Keep it looping + hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW; // Let RX have higher priority + + if (HAL_DMA_Init(&hdma_usart3_tx) != HAL_OK) { + PANIC; + } + __HAL_LINKDMA(uartHandle, hdmatx, hdma_usart3_tx); + + // DMA stream IRQ + NVIC_SetPriority(DMA1_Stream3_IRQn, 7); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); } else if (uartHandle->Instance == UART4) { @@ -297,7 +419,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) __HAL_LINKDMA(uartHandle, hdmarx, hdma_uart4_rx); // DMA stream IRQ - NVIC_SetPriority(DMA1_Stream2_IRQn, 7); // higher priority than UART + NVIC_SetPriority(DMA1_Stream2_IRQn, 6); // higher priority than UART HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); } @@ -317,7 +439,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); // DMA config - check your device's DMA request mapping table - // for the correct stream/channel for UART4_RX + // for the correct stream/channel for UART5_RX hdma_uart5_rx.Instance = DMA1_Stream0; // verify in datasheet hdma_uart5_rx.Init.Channel = DMA_CHANNEL_4; // HAL constant for your device hdma_uart5_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; @@ -337,7 +459,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) __HAL_LINKDMA(uartHandle, hdmarx, hdma_uart5_rx); // DMA stream IRQ - NVIC_SetPriority(DMA1_Stream0_IRQn, 8); // higher priority than UART + NVIC_SetPriority(DMA1_Stream0_IRQn, 6); // higher priority than UART HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index ebc66a2d..b1e1b9a0 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -8,11 +8,56 @@ // void transmit_samples(void) { - // Send header before we compute anything +// // 1. Process incoming UARTs first +// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); +// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); + + // 2. Create a local buffer for this transmission "burst" + static uint8_t tx_data2[12]; + static uint8_t tx_data3[12]; + uint8_t idx = 0; + + uint16_t bits[8]; + adc_latest_bits(bits); + + for (int i = 0; i < 4; i++) { + uint8_t header = (i == 0) ? 0x90 : (0x90 | (0x03 & i)); + + tx_data2[idx] = header; + tx_data3[idx] = header; + idx++; + + tx_data2[idx] = (uint8_t)(bits[i] >> 8); // MSB + tx_data2[idx] = (uint8_t)(bits[i + 4] >> 8); // MSB + idx++; + + tx_data2[idx] = (uint8_t)(bits[i] & 0xFF); // LSB + tx_data2[idx] = (uint8_t)(bits[i + 4] & 0xFF); // LSB + idx++; + } + + // ... Add AMDS data to tx_data if ready ... + + // 4. Trigger the DMA to send exactly 'idx' bytes + // This function returns immediately while the hardware sends the data + if (huart2.gState == HAL_UART_STATE_READY && huart3.gState == HAL_UART_STATE_READY) { + HAL_UART_Transmit_DMA(&huart2, tx_data2, idx); + HAL_UART_Transmit_DMA(&huart3, tx_data3, idx); + } +} + + + + + + +void transmit_samples(void) +{ + // Send header before we compute anything // to get the UART warmed up and running! uint8_t first_header = 0x90; - drv_uart_putc_fast(USART2, first_header); - drv_uart_putc_fast(USART3, first_header); + drv_uart_putc_dma(USART2, first_header); + drv_uart_putc_dma(USART3, first_header); // Get latest data from ADC driver (non-blocking) uint16_t bits[8]; @@ -28,51 +73,53 @@ void transmit_samples(void) uint8_t header = 0x90; header |= (0x03 & i); - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); + drv_uart_putc_dma(USART2, header); + drv_uart_putc_dma(USART3, header); } // Send ADC sample data MSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 >> 8)); + drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); + drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); // Send ADC sample data LSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); + drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); + drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); } + process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); + process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); // Now attempt to send AMDS samples (if ready) using same header scheme. // adc_latest_amds() will populate the array only when the corresponding // amds_samples_ready pairs are set. uint16_t amds[16] = {0}; adc_latest_amds(amds); - + first_header = 0x94; // First AMDS set: indices 0..7 (requires amds_samples_ready[0] && [1]) if (amds_samples_ready[0] && amds_samples_ready[1]) { // Send header for this set - drv_uart_putc_fast(USART2, first_header); - drv_uart_putc_fast(USART3, first_header); + drv_uart_putc_dma(USART2, first_header); + drv_uart_putc_dma(USART3, first_header); for (int i = 0; i < 4; i++) { if (i > 0) { uint8_t header = 0x94; header |= (0x07 & i); - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); + drv_uart_putc_dma(USART2, header); + drv_uart_putc_dma(USART3, header); } uint16_t sample1 = amds[(4 * 0) + i]; // amds[0..3] uint16_t sample2 = amds[(4 * 1) + i]; // amds[4..7] // Send ADC sample data MSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 >> 8)); + drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); + drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); // Send ADC sample data LSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); + drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); + drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); } // Clear flags for this set @@ -84,27 +131,27 @@ void transmit_samples(void) // Second AMDS set: indices 8..15 (requires amds_samples_ready[2] && [3]) // Only if the first set was successful if (amds_samples_ready[2] && amds_samples_ready[3]) { - drv_uart_putc_fast(USART2, first_header); - drv_uart_putc_fast(USART3, first_header); + drv_uart_putc_dma(USART2, first_header); + drv_uart_putc_dma(USART3, first_header); for (int i = 0; i < 4; i++) { if (i > 0) { uint8_t header = 0x98; header |= (0x0B & i); - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); + drv_uart_putc_dma(USART2, header); + drv_uart_putc_dma(USART3, header); } uint16_t sample1 = amds[8 + (4 * 0) + i]; // amds[8..11] uint16_t sample2 = amds[8 + (4 * 1) + i]; // amds[12..15] // Send ADC sample data MSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 >> 8)); + drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); + drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); // Send ADC sample data LSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); + drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); + drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); } // Clear flags for this set From ee543299264a096fead5c298363b5edca9f4ef2c Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 18 Mar 2026 11:52:57 -0500 Subject: [PATCH 05/72] add currently working daisy chain firmware --- .../motherboard_v1/Core/Src/drv_uart.c | 26 +- .../Firmware/motherboard_v1/Core/Src/tx.c | 268 ++++++++++-------- 2 files changed, 160 insertions(+), 134 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index f3c4ee49..af3fbcb7 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -185,14 +185,22 @@ void DMA1_Stream0_IRQHandler(void) HAL_DMA_IRQHandler(&hdma_uart5_rx); } -void DMA1_Stream3_IRQHandler(void) -{ +// USART2 DMA and UART Interrupts +void DMA1_Stream6_IRQHandler(void) { + HAL_DMA_IRQHandler(&hdma_usart2_tx); +} + +void USART2_IRQHandler(void) { + HAL_UART_IRQHandler(&huart2); +} + +// USART3 DMA and UART Interrupts +void DMA1_Stream3_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_usart3_tx); } -void DMA1_Stream6_IRQHandler(void) -{ - HAL_DMA_IRQHandler(&hdma_usart2_tx); +void USART3_IRQHandler(void) { + HAL_UART_IRQHandler(&huart3); } void drv_uart_init(void) @@ -241,7 +249,7 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) huart->Init.Parity = UART_PARITY_ODD; if (huart->Instance == UART4) { - huart->Init.Mode = UART_MODE_TX_RX; + huart->Init.Mode = UART_MODE_RX; } else if (huart->Instance == UART5) { huart->Init.Mode = UART_MODE_RX; } else { @@ -268,9 +276,6 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) if (HAL_UART_Receive_DMA(&huart4, UART4_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } - - __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); - __HAL_UART_FLUSH_DRREGISTER(huart); } else if (huart->Instance == UART5) { NVIC_SetPriority(UART5_IRQn, 9); HAL_NVIC_EnableIRQ(UART5_IRQn); @@ -281,9 +286,6 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) if (HAL_UART_Receive_DMA(&huart5, UART5_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } - - __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); - __HAL_UART_FLUSH_DRREGISTER(huart); } else if (huart->Instance == USART2) { NVIC_SetPriority(USART2_IRQn, 10); HAL_NVIC_EnableIRQ(USART2_IRQn); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index b1e1b9a0..874e480d 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -8,10 +8,6 @@ // void transmit_samples(void) { -// // 1. Process incoming UARTs first -// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); -// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); - // 2. Create a local buffer for this transmission "burst" static uint8_t tx_data2[12]; static uint8_t tx_data3[12]; @@ -28,15 +24,43 @@ void transmit_samples(void) idx++; tx_data2[idx] = (uint8_t)(bits[i] >> 8); // MSB - tx_data2[idx] = (uint8_t)(bits[i + 4] >> 8); // MSB + tx_data3[idx] = (uint8_t)(bits[i + 4] >> 8); // MSB idx++; tx_data2[idx] = (uint8_t)(bits[i] & 0xFF); // LSB - tx_data2[idx] = (uint8_t)(bits[i + 4] & 0xFF); // LSB + tx_data3[idx] = (uint8_t)(bits[i + 4] & 0xFF); // LSB idx++; } + // 1. Process incoming UARTs first + process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); + process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); + + uint16_t amds[16] = {1}; + adc_latest_amds(amds); + // ... Add AMDS data to tx_data if ready ... + if (amds_samples_ready[0] && amds_samples_ready[1]) { + for (int i = 0; i < 4; i++) { + uint8_t header = (i == 0) ? 0x94 : (0x94 | (0x07 & i)); + + tx_data2[idx] = header; + tx_data3[idx] = header; + idx++; + + tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB + tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB + idx++; + + tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB + tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB + idx++; + + // Clear flags for this set + amds_samples_ready[0] = false; + amds_samples_ready[1] = false; + } + } // 4. Trigger the DMA to send exactly 'idx' bytes // This function returns immediately while the hardware sends the data @@ -51,121 +75,121 @@ void transmit_samples(void) -void transmit_samples(void) -{ - // Send header before we compute anything - // to get the UART warmed up and running! - uint8_t first_header = 0x90; - drv_uart_putc_dma(USART2, first_header); - drv_uart_putc_dma(USART3, first_header); - - // Get latest data from ADC driver (non-blocking) - uint16_t bits[8]; - adc_latest_bits(bits); - - // Send board's own ADC data out over UART - for (int i = 0; i < 4; i++) { - uint16_t sample1 = bits[(4 * 0) + i]; - uint16_t sample2 = bits[(4 * 1) + i]; - - // Send header (not the first one) - if (i > 0) { - uint8_t header = 0x90; - header |= (0x03 & i); - - drv_uart_putc_dma(USART2, header); - drv_uart_putc_dma(USART3, header); - } - - // Send ADC sample data MSBs - drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); - drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); - - // Send ADC sample data LSBs - drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); - } - - process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); - process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); - // Now attempt to send AMDS samples (if ready) using same header scheme. - // adc_latest_amds() will populate the array only when the corresponding - // amds_samples_ready pairs are set. - uint16_t amds[16] = {0}; - adc_latest_amds(amds); - - first_header = 0x94; - - // First AMDS set: indices 0..7 (requires amds_samples_ready[0] && [1]) - if (amds_samples_ready[0] && amds_samples_ready[1]) { - // Send header for this set - drv_uart_putc_dma(USART2, first_header); - drv_uart_putc_dma(USART3, first_header); - - for (int i = 0; i < 4; i++) { - if (i > 0) { - uint8_t header = 0x94; - header |= (0x07 & i); - drv_uart_putc_dma(USART2, header); - drv_uart_putc_dma(USART3, header); - } - - uint16_t sample1 = amds[(4 * 0) + i]; // amds[0..3] - uint16_t sample2 = amds[(4 * 1) + i]; // amds[4..7] - - // Send ADC sample data MSBs - drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); - drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); - - // Send ADC sample data LSBs - drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); - } - - // Clear flags for this set - amds_samples_ready[0] = false; - amds_samples_ready[1] = false; - - first_header = 0x98; - - // Second AMDS set: indices 8..15 (requires amds_samples_ready[2] && [3]) - // Only if the first set was successful - if (amds_samples_ready[2] && amds_samples_ready[3]) { - drv_uart_putc_dma(USART2, first_header); - drv_uart_putc_dma(USART3, first_header); - - for (int i = 0; i < 4; i++) { - if (i > 0) { - uint8_t header = 0x98; - header |= (0x0B & i); - drv_uart_putc_dma(USART2, header); - drv_uart_putc_dma(USART3, header); - } - - uint16_t sample1 = amds[8 + (4 * 0) + i]; // amds[8..11] - uint16_t sample2 = amds[8 + (4 * 1) + i]; // amds[12..15] - - // Send ADC sample data MSBs - drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); - drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); - - // Send ADC sample data LSBs - drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); - } - - // Clear flags for this set - amds_samples_ready[2] = false; - amds_samples_ready[3] = false; - } - } - - // Wait for entire UART transmission to complete - drv_uart_wait_TC(USART2); - drv_uart_wait_TC(USART3); - - uart4_amds_sample_count = 0; - uart5_amds_sample_count = 0; -} +//void transmit_samples(void) +//{ +// // Send header before we compute anything +// // to get the UART warmed up and running! +// uint8_t first_header = 0x90; +// drv_uart_putc_dma(USART2, first_header); +// drv_uart_putc_dma(USART3, first_header); +// +// // Get latest data from ADC driver (non-blocking) +// uint16_t bits[8]; +// adc_latest_bits(bits); +// +// // Send board's own ADC data out over UART +// for (int i = 0; i < 4; i++) { +// uint16_t sample1 = bits[(4 * 0) + i]; +// uint16_t sample2 = bits[(4 * 1) + i]; +// +// // Send header (not the first one) +// if (i > 0) { +// uint8_t header = 0x90; +// header |= (0x03 & i); +// +// drv_uart_putc_dma(USART2, header); +// drv_uart_putc_dma(USART3, header); +// } +// +// // Send ADC sample data MSBs +// drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); +// drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); +// +// // Send ADC sample data LSBs +// drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); +// drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); +// } +// +// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); +// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); +// // Now attempt to send AMDS samples (if ready) using same header scheme. +// // adc_latest_amds() will populate the array only when the corresponding +// // amds_samples_ready pairs are set. +// uint16_t amds[16] = {0}; +// adc_latest_amds(amds); +// +// first_header = 0x94; +// +// // First AMDS set: indices 0..7 (requires amds_samples_ready[0] && [1]) +// if (amds_samples_ready[0] && amds_samples_ready[1]) { +// // Send header for this set +// drv_uart_putc_dma(USART2, first_header); +// drv_uart_putc_dma(USART3, first_header); +// +// for (int i = 0; i < 4; i++) { +// if (i > 0) { +// uint8_t header = 0x94; +// header |= (0x07 & i); +// drv_uart_putc_dma(USART2, header); +// drv_uart_putc_dma(USART3, header); +// } +// +// uint16_t sample1 = amds[(4 * 0) + i]; // amds[0..3] +// uint16_t sample2 = amds[(4 * 1) + i]; // amds[4..7] +// +// // Send ADC sample data MSBs +// drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); +// drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); +// +// // Send ADC sample data LSBs +// drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); +// drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); +// } +// +// // Clear flags for this set +// amds_samples_ready[0] = false; +// amds_samples_ready[1] = false; +// +// first_header = 0x98; +// +// // Second AMDS set: indices 8..15 (requires amds_samples_ready[2] && [3]) +// // Only if the first set was successful +// if (amds_samples_ready[2] && amds_samples_ready[3]) { +// drv_uart_putc_dma(USART2, first_header); +// drv_uart_putc_dma(USART3, first_header); +// +// for (int i = 0; i < 4; i++) { +// if (i > 0) { +// uint8_t header = 0x98; +// header |= (0x0B & i); +// drv_uart_putc_dma(USART2, header); +// drv_uart_putc_dma(USART3, header); +// } +// +// uint16_t sample1 = amds[8 + (4 * 0) + i]; // amds[8..11] +// uint16_t sample2 = amds[8 + (4 * 1) + i]; // amds[12..15] +// +// // Send ADC sample data MSBs +// drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); +// drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); +// +// // Send ADC sample data LSBs +// drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); +// drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); +// } +// +// // Clear flags for this set +// amds_samples_ready[2] = false; +// amds_samples_ready[3] = false; +// } +// } +// +// // Wait for entire UART transmission to complete +// drv_uart_wait_TC(USART2); +// drv_uart_wait_TC(USART3); +// +// uart4_amds_sample_count = 0; +// uart5_amds_sample_count = 0; +//} From 98303b582669ee5f038902f24070e8bad90612ac Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 24 Mar 2026 12:49:36 -0500 Subject: [PATCH 06/72] add transmit firmware for channels 97 through 9B --- .../motherboard_v1/Core/Inc/drv_uart.h | 2 +- .../Firmware/motherboard_v1/Core/Src/adc.c | 2 +- .../motherboard_v1/Core/Src/drv_uart.c | 20 ++++-- .../Firmware/motherboard_v1/Core/Src/tx.c | 64 +++++++++++++++++-- 4 files changed, 75 insertions(+), 13 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 59820250..976bcc44 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -13,7 +13,7 @@ extern UART_HandleTypeDef huart3; // 16-byte accumulator // Layout: [UART4 pkt0-3 | UART5 pkt0-3][UART4 pkt4-7 | UART5 pkt4-7] extern volatile uint16_t latest_valid_amds_samples[2][8]; -extern volatile bool amds_samples_ready[4]; +extern volatile bool amds_samples_ready[2]; extern volatile uint8_t uart4_amds_sample_count; extern volatile uint8_t uart5_amds_sample_count; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index bd411785..cff541ad 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -47,7 +47,7 @@ static volatile uint16_t latest_valid_adc_data[8] = { 0 }; volatile uint16_t latest_valid_amds_samples[2][8] = { 0 }; -volatile bool amds_samples_ready[4] = { 0 }; +volatile bool amds_samples_ready[2] = { 0 }; void adc_init(void) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index af3fbcb7..7f107630 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -76,13 +76,23 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) // Packet Complete: Reconstruct 16-bit value uint16_t value = ((uint16_t)track->data[0] << 8) | track->data[1]; - // Map to your global array logic from drv_uart.c - uint8_t offset = (track->header & 0x03) + (uart_id == 5 ? 4 : 0); - // uint8_t sample_set = (track->header & 0x0C) >> 2; // e.g., 0 for 0x90, 1 for 0x94 + // 1. Calculate the absolute global channel index (e.g., 0 to 23) + uint8_t base_index = track->header & 0x03; + uint8_t sample_set = (track->header & 0x0C) >> 2; - latest_valid_amds_samples[uart_id == 4 ? 0 : 1][offset] = value; + // This gives a flat number from 0 up to 23 regardless of which UART it came from + uint8_t global_index = base_index + (uart_id == 5 ? 4 : 0) + (sample_set * 8); - amds_samples_ready[uart_id == 4 ? 0 : 1] = true; + // 2. Map the global index to your desired 2D array structure + // Assuming you want exactly 12 packets per bank (0-11 in bank 0, 12-23 in bank 1) + uint8_t bank = (global_index < 12) ? 0 : 1; + uint8_t local_index = (global_index < 12) ? global_index : (global_index - 12); + + // 3. Store the value logically rather than physically + latest_valid_amds_samples[bank][local_index] = value; + + // 4. Update the ready flag for the specific bank + amds_samples_ready[bank] = true; track->state = STATE_IDLE; break; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 874e480d..a2e04c5f 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -3,14 +3,28 @@ #include "drv_uart.h" #include "platform.h" +// clang-format off + +#define NOP1 asm("nop") +#define NOP2 NOP1;NOP1 +#define NOP4 NOP2;NOP2 +#define NOP8 NOP4;NOP4 +#define NOP16 NOP8;NOP8 +#define NOP32 NOP16;NOP16 +#define NOP64 NOP32;NOP32 +#define NOP128 NOP64;NOP64 +#define NOP256 NOP128;NOP128 + +// clang-format on + // Called after ADC conversions have been completed, // to send sampled data back to AMDC // void transmit_samples(void) { // 2. Create a local buffer for this transmission "burst" - static uint8_t tx_data2[12]; - static uint8_t tx_data3[12]; + static uint8_t tx_data2[36]; + static uint8_t tx_data3[36]; uint8_t idx = 0; uint16_t bits[8]; @@ -33,14 +47,32 @@ void transmit_samples(void) } // 1. Process incoming UARTs first - process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); - process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + NOP256; + process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); + process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); uint16_t amds[16] = {1}; adc_latest_amds(amds); // ... Add AMDS data to tx_data if ready ... - if (amds_samples_ready[0] && amds_samples_ready[1]) { + if (amds_samples_ready[0]) { for (int i = 0; i < 4; i++) { uint8_t header = (i == 0) ? 0x94 : (0x94 | (0x07 & i)); @@ -55,9 +87,29 @@ void transmit_samples(void) tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB idx++; + } + + // Clear flags for this set + amds_samples_ready[0] = false; + + if (amds_samples_ready[1]) { + for (int i = 0; i < 4; i++) { + uint8_t header = (i == 0) ? 0x98 : (0x98 | (0x0B & i)); + + tx_data2[idx] = header; + tx_data3[idx] = header; + idx++; + + tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB + tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB + idx++; + + tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB + tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB + idx++; + } // Clear flags for this set - amds_samples_ready[0] = false; amds_samples_ready[1] = false; } } From becf30a24fa0971b9da317e9afcbf931afdd9bae Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 27 Mar 2026 11:22:40 -0500 Subject: [PATCH 07/72] add current transmit implementation --- .../motherboard_v1/Core/Inc/drv_uart.h | 10 +- .../Firmware/motherboard_v1/Core/Inc/tx.h | 23 ++++ .../Firmware/motherboard_v1/Core/Src/adc.c | 28 +++-- .../motherboard_v1/Core/Src/drv_uart.c | 103 +++++------------- .../Firmware/motherboard_v1/Core/Src/main.c | 13 +++ .../Firmware/motherboard_v1/Core/Src/tx.c | 79 +++++++++++++- 6 files changed, 165 insertions(+), 91 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 976bcc44..d2198608 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -10,6 +10,15 @@ void drv_uart_init(void); extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart3; +extern UART_HandleTypeDef huart4; +extern UART_HandleTypeDef huart5; + +extern DMA_HandleTypeDef hdma_usart2_tx; +extern DMA_HandleTypeDef hdma_usart3_tx; + +extern DMA_HandleTypeDef hdma_uart4_rx; +extern DMA_HandleTypeDef hdma_uart5_rx; + // 16-byte accumulator // Layout: [UART4 pkt0-3 | UART5 pkt0-3][UART4 pkt4-7 | UART5 pkt4-7] extern volatile uint16_t latest_valid_amds_samples[2][8]; @@ -21,7 +30,6 @@ extern volatile uint8_t uart5_amds_sample_count; typedef enum { STATE_IDLE, STATE_GOT_HEADER, - STATE_GOT_BYTE1 } rx_state_t; typedef struct { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h index a55e8c85..93f6ccce 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h @@ -1,6 +1,29 @@ #ifndef TX_H #define TX_H +#include "platform.h" +#include +#include + +#define NUM_SETS 3 // 0 = local data, 1 = AMDS 1, 2 = AMDS 2 +#define PACKETS_PER_SET 8 + +typedef struct { + uint8_t header; + uint8_t msb; + uint8_t lsb; +} packet_t; + +// Global state arrays +extern volatile packet_t tx_packets[NUM_SETS * PACKETS_PER_SET]; +extern volatile bool packet_ready[NUM_SETS * PACKETS_PER_SET]; +extern bool packet_sent[NUM_SETS * PACKETS_PER_SET]; + +// Flag set by EXTI Sync Interrupt +extern volatile bool sync_event_flag; + +void process_transmissions(void); + void transmit_samples(void); #endif // TX_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index cff541ad..4790e2f8 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -184,21 +184,19 @@ void EXTI3_IRQHandler(void) uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); - // Copy data into write buffer destination - volatile uint16_t *dest = latest_valid_adc_data; - - // Unrolled loop for speed - dest[0] = new_data[0]; - dest[1] = new_data[1]; - dest[2] = new_data[2]; - dest[3] = new_data[3]; - dest[4] = new_data[4]; - dest[5] = new_data[5]; - dest[6] = new_data[6]; - dest[7] = new_data[7]; - - // Call the function in tx.c to transmit the sampled data back to the AMDC - transmit_samples(); + for (int i = 0; i < 8; i++) { + uint8_t header = (i % 4 == 0) ? 0x90 : (0x90 | (0x03 & (i % 4))); + + tx_packets[i].header = header; + tx_packets[i].msb = (uint8_t)(new_data[i] >> 8); + tx_packets[i].lsb = (uint8_t)(new_data[i] & 0xFF); + + // Clear 'sent' before raising 'ready' to avoid race conditions + packet_sent[i] = false; + packet_ready[i] = true; + } + + sync_event_flag = true; // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 7f107630..23bde68f 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -1,4 +1,5 @@ #include "drv_uart.h" +#include "tx.h" #include "defines.h" #include "drv_clock.h" #include "platform.h" @@ -9,14 +10,14 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) UART_HandleTypeDef huart2; UART_HandleTypeDef huart3; -static DMA_HandleTypeDef hdma_usart2_tx; -static DMA_HandleTypeDef hdma_usart3_tx; +DMA_HandleTypeDef hdma_usart2_tx; +DMA_HandleTypeDef hdma_usart3_tx; -static UART_HandleTypeDef huart4; -static UART_HandleTypeDef huart5; +UART_HandleTypeDef huart4; +UART_HandleTypeDef huart5; -static DMA_HandleTypeDef hdma_uart4_rx; -static DMA_HandleTypeDef hdma_uart5_rx; +DMA_HandleTypeDef hdma_uart4_rx; +DMA_HandleTypeDef hdma_uart5_rx; uint8_t usart2_tx_ring[TX_BUF_SIZE]; uint8_t usart3_tx_ring[TX_BUF_SIZE]; @@ -67,32 +68,36 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) case STATE_GOT_HEADER: track->data[0] = byte; - track->state = STATE_GOT_BYTE1; - break; - case STATE_GOT_BYTE1: + byte = pool[track->read_index]; + track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; track->data[1] = byte; - // Packet Complete: Reconstruct 16-bit value - uint16_t value = ((uint16_t)track->data[0] << 8) | track->data[1]; - - // 1. Calculate the absolute global channel index (e.g., 0 to 23) + // 1. Calculate the base index (0 to 3) within the 4-packet group uint8_t base_index = track->header & 0x03; - uint8_t sample_set = (track->header & 0x0C) >> 2; - // This gives a flat number from 0 up to 23 regardless of which UART it came from - uint8_t global_index = base_index + (uart_id == 5 ? 4 : 0) + (sample_set * 8); + // 2. Determine the set (0 for 0x90-0x93, 1 for 0x94-0x97) + // Changed mask from 0x0C to 0x04, since we only care about bit 2. + uint8_t sample_set = (track->header & 0x04) >> 2; - // 2. Map the global index to your desired 2D array structure - // Assuming you want exactly 12 packets per bank (0-11 in bank 0, 12-23 in bank 1) - uint8_t bank = (global_index < 12) ? 0 : 1; - uint8_t local_index = (global_index < 12) ? global_index : (global_index - 12); + // 3. Calculate the absolute global channel index (8 to 23) + uint8_t global_index = 8 + (sample_set * 8) + (uart_id == 5 ? 4 : 0) + base_index; - // 3. Store the value logically rather than physically - latest_valid_amds_samples[bank][local_index] = value; +// // 3. Store the value logically rather than physically +// latest_valid_amds_samples[bank][local_index] = value; +// +// // 4. Update the ready flag for the specific bank +// amds_samples_ready[bank] = true; - // 4. Update the ready flag for the specific bank - amds_samples_ready[bank] = true; + if (global_index < 24) { + tx_packets[global_index].header = track->header; + tx_packets[global_index].msb = track->data[0]; + tx_packets[global_index].lsb = track->data[1]; + + // Clear 'sent' before raising 'ready' + packet_sent[global_index] = false; + packet_ready[global_index] = true; + } track->state = STATE_IDLE; break; @@ -100,56 +105,6 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) } } -void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) -{ -// if (huart->Instance == UART4) { -// if (uart4_packet_count < PACKETS_PER_UART) { -// -// uint8_t offset = uart4_packet_count; -// -// uint16_t value = ((uint16_t)UART4_RxBuf[1] << 8) | (uint16_t)UART4_RxBuf[2]; -// -// latest_valid_amds_samples[uart4_amds_sample_count][offset] = value; -// -// uart4_packet_count++; -// } -// -// if (uart4_packet_count == PACKETS_PER_UART) { -// amds_samples_ready[uart4_amds_sample_count] = true; -// uart4_amds_sample_count++; -// uart4_packet_count = 0; -// } -// -// if (uart4_amds_sample_count == 2) { -// amds_samples_ready[uart4_amds_sample_count + 1] = true; -// uart4_amds_sample_count = 0; -// } -//// HAL_UART_Receive_DMA(huart, UART4_RxBuf, PACKET_SIZE); -// } else if (huart->Instance == UART5) { -// if (uart5_packet_count < PACKETS_PER_UART) { -// -// uint8_t offset = uart5_packet_count + 4; -// -// uint16_t value = ((uint16_t)UART5_RxBuf[1] << 8) | (uint16_t)UART5_RxBuf[2]; -// -// latest_valid_amds_samples[uart5_amds_sample_count][offset] = value; -// -// uart5_packet_count++; -// } -// -// if (uart5_packet_count == PACKETS_PER_UART) { -// amds_samples_ready[uart5_amds_sample_count] = true; -// uart5_amds_sample_count++; -// uart5_packet_count = 0; -// } -// -// if (uart5_amds_sample_count == 2) { -// amds_samples_ready[uart5_amds_sample_count + 2] = true; -// uart5_amds_sample_count = 0; -// } -//// HAL_UART_Receive_DMA(huart, UART5_RxBuf, PACKET_SIZE); -// } -} void UART4_IRQHandler(void) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index f63b3119..154b15cc 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -40,6 +40,19 @@ int main(void) SysTick->CTRL &= 0xFFFFFFFE; while (1) { + if (tracker4.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { + process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); + process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); + } + + // 2. Transmit Event Triggered by EXTI Sync + if (sync_event_flag) { + sync_event_flag = false; // Acknowledge flag + + // Package all ready sets and transmit + process_transmissions(); + } + drv_led_clear(); drv_led_on(1 << led); drv_led_display(); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index a2e04c5f..6a85b270 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -1,7 +1,84 @@ #include "tx.h" #include "adc.h" #include "drv_uart.h" -#include "platform.h" + +volatile packet_t tx_packets[NUM_SETS * PACKETS_PER_SET]; +volatile bool packet_ready[NUM_SETS * PACKETS_PER_SET]; +bool packet_sent[NUM_SETS * PACKETS_PER_SET]; + +volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR + +// Scans the state arrays, builds contiguous buffers, and fires DMA +void process_transmissions(void) { + // We only need a tiny 3-byte static buffer for each UART now. + // (Static is still required so the memory persists while DMA is working in the background) + static uint8_t dma_tx2[3]; + static uint8_t dma_tx3[3]; + + // Scan the array for ready/unsent packets + for (int pkt = 0; pkt < NUM_SETS * PACKETS_PER_SET; pkt++) { + // Check hardware states once at the start + while (huart2.gState != HAL_UART_STATE_READY) { + asm("nop"); + } + + while (huart3.gState != HAL_UART_STATE_READY) { + asm("nop"); + } + + if (packet_ready[pkt] && !packet_sent[pkt]) { + + // Route to UART2 + if ((pkt >= 0 && pkt <= 3) || (pkt >= 8 && pkt <= 11) || (pkt >= 16 && pkt <= 19)) { + + // Copy exactly 3 bytes into the UART2 DMA buffer + dma_tx2[0] = tx_packets[pkt].header; + dma_tx2[1] = tx_packets[pkt].msb; + dma_tx2[2] = tx_packets[pkt].lsb; + + packet_sent[pkt] = true; + + HAL_UART_Transmit_DMA(&huart2, dma_tx2, 3); + } + + // Route to UART3 + if ((pkt >= 4 && pkt <= 7) || (pkt >= 12 && pkt <= 15) || (pkt >= 20 && pkt <= 23)) { + + // Copy exactly 3 bytes into the UART3 DMA buffer + dma_tx3[0] = tx_packets[pkt].header; + dma_tx3[1] = tx_packets[pkt].msb; + dma_tx3[2] = tx_packets[pkt].lsb; + + packet_sent[pkt] = true; + + HAL_UART_Transmit_DMA(&huart3, dma_tx3, 3); + } + } + } +} + + + + + + + + + + + + + + + + + + + + + + + // clang-format off From bad7012013363a1827bbd3359b3ce10005fa5bc5 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 27 Mar 2026 16:53:59 -0500 Subject: [PATCH 08/72] add queue and buffers for uart2 and 3 --- .../motherboard_v1/Core/Inc/drv_uart.h | 29 ++++++----------- .../Firmware/motherboard_v1/Core/Inc/tx.h | 3 ++ .../Firmware/motherboard_v1/Core/Src/adc.c | 9 +++++- .../motherboard_v1/Core/Src/drv_uart.c | 20 ++---------- .../Firmware/motherboard_v1/Core/Src/main.c | 32 ++++++++++++------- .../Firmware/motherboard_v1/Core/Src/tx.c | 2 -- 6 files changed, 43 insertions(+), 52 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index d2198608..ba601380 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -26,7 +26,6 @@ extern volatile bool amds_samples_ready[2]; extern volatile uint8_t uart4_amds_sample_count; extern volatile uint8_t uart5_amds_sample_count; - typedef enum { STATE_IDLE, STATE_GOT_HEADER, @@ -46,18 +45,19 @@ extern uart_rx_tracker_t tracker5; extern uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; -// Define large buffers for outgoing data -#define TX_BUF_SIZE 512 -extern uint8_t usart2_tx_ring[TX_BUF_SIZE]; -extern uint8_t usart3_tx_ring[TX_BUF_SIZE]; - -extern uint32_t usart2_tx_write_idx; -extern uint32_t usart3_tx_write_idx; +extern volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); +void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); -void dma_send(uint8_t uart_id, uint8_t *data, uint8_t len); +static inline void dma_send(UART_HandleTypeDef *uart, uint8_t *data, uint8_t len) +{ + +} static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) { @@ -70,17 +70,6 @@ static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) uart->TDR = data; } -static inline void drv_uart_putc_dma(USART_TypeDef *uart, uint8_t data) -{ - if (uart == USART2) { - usart2_tx_ring[usart2_tx_write_idx] = data; - usart2_tx_write_idx = (usart2_tx_write_idx + 1) % TX_BUF_SIZE; - } else if (uart == USART3) { - usart3_tx_ring[usart3_tx_write_idx] = data; - usart3_tx_write_idx = (usart3_tx_write_idx + 1) % TX_BUF_SIZE; - } -} - static inline void drv_uart_wait_TC(USART_TypeDef *uart) { // After done sending characters, must wait for TC flag!! diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h index 93f6ccce..e4ee904f 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h @@ -1,6 +1,9 @@ #ifndef TX_H #define TX_H +#include "adc.h" +#include "drv_uart.h" + #include "platform.h" #include #include diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 4790e2f8..008c4197 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -179,8 +179,15 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) // this ISR, all the motherboard ADCs should be sampled. void EXTI3_IRQHandler(void) { - // Perform the actual SPI transactions + + for (int i = 0; i < 24; i++) { + packet_sent[i] = false; + packet_ready[i] = false; + } + + // alert daisy chained AMDSs to begin converting GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + // Perform the actual SPI transactions uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 23bde68f..c6ea3e51 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -19,23 +19,6 @@ UART_HandleTypeDef huart5; DMA_HandleTypeDef hdma_uart4_rx; DMA_HandleTypeDef hdma_uart5_rx; -uint8_t usart2_tx_ring[TX_BUF_SIZE]; -uint8_t usart3_tx_ring[TX_BUF_SIZE]; - -uint32_t usart2_tx_write_idx = 0; -uint32_t usart3_tx_write_idx = 0; - -// 3-byte packet buffers for each UART -#define PACKET_SIZE 3 -#define PACKETS_PER_UART 4 -#define TOTAL_PACKETS (PACKETS_PER_UART * 2) // 8 packets, 24 bytes total - -//static uint8_t uart4_packet_count = 0; -//static uint8_t uart5_packet_count = 0; -volatile uint8_t uart4_amds_sample_count = 0; -volatile uint8_t uart5_amds_sample_count = 0; - - uart_rx_tracker_t tracker4 = {0}; uart_rx_tracker_t tracker5 = {0}; @@ -105,6 +88,9 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) } } +void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { + +} void UART4_IRQHandler(void) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 154b15cc..9fe40137 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -29,6 +29,7 @@ int main(void) // Infinite loop (all real work is done in ISRs) uint8_t led = 0; + uint32_t ledDelta = HAL_GetTick(); // Disable the SysTick ISR // @@ -37,12 +38,15 @@ int main(void) // we do not need it to run during operation! // // Set bit 0 to 0 - SysTick->CTRL &= 0xFFFFFFFE; +// SysTick->CTRL &= 0xFFFFFFFE; while (1) { - if (tracker4.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { + if (tracker4.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { //update process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); - process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); + } + + if (tracker5.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx))) { //update + process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); } // 2. Transmit Event Triggered by EXTI Sync @@ -53,18 +57,22 @@ int main(void) process_transmissions(); } - drv_led_clear(); - drv_led_on(1 << led); - drv_led_display(); + if (HAL_GetTick() - ledDelta >= 250) { + ledDelta = HAL_GetTick(); + drv_led_clear(); + drv_led_on(1 << led); + drv_led_display(); - if (++led >= DRV_LED_NUM_TOTAL) { - led = 0; + if (++led >= DRV_LED_NUM_TOTAL) { + led = 0; + } } - volatile int i; - for (i = 0; i < 10000000; i++) { - asm("nop"); - } + +// volatile int i; +// for (i = 0; i < 10000000; i++) { +// asm("nop"); +// } } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 6a85b270..d8dacd59 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -1,6 +1,4 @@ #include "tx.h" -#include "adc.h" -#include "drv_uart.h" volatile packet_t tx_packets[NUM_SETS * PACKETS_PER_SET]; volatile bool packet_ready[NUM_SETS * PACKETS_PER_SET]; From e7e12010099df56730d72f5aac4cb79a7e4dd7e1 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 3 Apr 2026 12:21:06 -0500 Subject: [PATCH 09/72] add immediate transmit in adc.c --- .../motherboard_v1/Core/Inc/drv_uart.h | 20 +- .../Firmware/motherboard_v1/Core/Src/adc.c | 52 ++-- .../motherboard_v1/Core/Src/drv_uart.c | 100 +++---- .../Firmware/motherboard_v1/Core/Src/main.c | 19 +- .../Firmware/motherboard_v1/Core/Src/tx.c | 273 ++++++++---------- 5 files changed, 225 insertions(+), 239 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index ba601380..ce6fc193 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -19,16 +19,10 @@ extern DMA_HandleTypeDef hdma_usart3_tx; extern DMA_HandleTypeDef hdma_uart4_rx; extern DMA_HandleTypeDef hdma_uart5_rx; -// 16-byte accumulator -// Layout: [UART4 pkt0-3 | UART5 pkt0-3][UART4 pkt4-7 | UART5 pkt4-7] -extern volatile uint16_t latest_valid_amds_samples[2][8]; -extern volatile bool amds_samples_ready[2]; -extern volatile uint8_t uart4_amds_sample_count; -extern volatile uint8_t uart5_amds_sample_count; - typedef enum { STATE_IDLE, STATE_GOT_HEADER, + STATE_GOT_MSB } rx_state_t; typedef struct { @@ -47,18 +41,18 @@ extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; extern volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; extern volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; - extern volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; extern volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; +// Queue tracking indices +extern volatile uint16_t u2_q_head; +extern volatile uint16_t u2_q_tail; +extern volatile uint16_t u3_q_head; +extern volatile uint16_t u3_q_tail; + void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); -static inline void dma_send(UART_HandleTypeDef *uart, uint8_t *data, uint8_t len) -{ - -} - static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) { // Wait until UART is ready to accept next character diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 008c4197..c41ee8f8 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -179,31 +179,47 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) // this ISR, all the motherboard ADCs should be sampled. void EXTI3_IRQHandler(void) { - - for (int i = 0; i < 24; i++) { - packet_sent[i] = false; - packet_ready[i] = false; - } - // alert daisy chained AMDSs to begin converting GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + static uint8_t local_tx2[12] = {0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB}; + static uint8_t local_tx3[12] = {0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB}; // Perform the actual SPI transactions - uint16_t new_data[8] = { 0 }; + /*uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); - for (int i = 0; i < 8; i++) { - uint8_t header = (i % 4 == 0) ? 0x90 : (0x90 | (0x03 & (i % 4))); - - tx_packets[i].header = header; - tx_packets[i].msb = (uint8_t)(new_data[i] >> 8); - tx_packets[i].lsb = (uint8_t)(new_data[i] & 0xFF); - - // Clear 'sent' before raising 'ready' to avoid race conditions - packet_sent[i] = false; - packet_ready[i] = true; + // 3. Bypass the circular queue and write straight to local linear buffers + // We use static buffers so they persist in memory while the DMA sends them in the background + static uint8_t local_tx2[12]; + static uint8_t local_tx3[12]; + uint8_t idx = 0; + + for (int i = 0; i < 4; i++) { + // Ultra-fast header generation (0x90, 0x91, 0x92, 0x93) + uint8_t header = 0x90 | i; + + // Pack UART2 data (Channels 0-3) + local_tx2[idx] = header; + local_tx2[idx+1] = (uint8_t)(new_data[i] >> 8); + local_tx2[idx+2] = (uint8_t)(new_data[i] & 0xFF); + + // Pack UART3 data (Channels 4-7) + local_tx3[idx] = header; + local_tx3[idx+1] = (uint8_t)(new_data[i + 4] >> 8); + local_tx3[idx+2] = (uint8_t)(new_data[i + 4] & 0xFF); + + idx += 3; + }*/ + + // 4. Fire the DMA immediately, back-to-back! + // No waiting for the main loop. As soon as the CPU hits these lines, the bits hit the wire. + if (huart2.gState == HAL_UART_STATE_READY) { + HAL_UART_Transmit_DMA(&huart2, local_tx2, 12); + } + if (huart3.gState == HAL_UART_STATE_READY) { + HAL_UART_Transmit_DMA(&huart3, local_tx3, 12); } - sync_event_flag = true; +// sync_event_flag = true; // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index c6ea3e51..7a082b0b 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -25,6 +25,16 @@ uart_rx_tracker_t tracker5 = {0}; uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; + +volatile uint16_t u2_q_head = 0; +volatile uint16_t u2_q_tail = 0; +volatile uint16_t u3_q_head = 0; +volatile uint16_t u3_q_tail = 0; + void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { // Calculate current DMA write position (NDTR counts down) UART_HandleTypeDef *huart; @@ -36,60 +46,52 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); - while (track->read_index != dma_write_ptr) { - uint8_t byte = pool[track->read_index]; - track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; - - switch (track->state) { - case STATE_IDLE: - // Look for any valid header (0x90, 0x94, 0x98 ranges) - if ((byte & 0xF0) == 0x90) { - track->header = byte; - track->state = STATE_GOT_HEADER; - } - break; - - case STATE_GOT_HEADER: - track->data[0] = byte; - - byte = pool[track->read_index]; - track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; - track->data[1] = byte; - - // 1. Calculate the base index (0 to 3) within the 4-packet group - uint8_t base_index = track->header & 0x03; - - // 2. Determine the set (0 for 0x90-0x93, 1 for 0x94-0x97) - // Changed mask from 0x0C to 0x04, since we only care about bit 2. - uint8_t sample_set = (track->header & 0x04) >> 2; - - // 3. Calculate the absolute global channel index (8 to 23) - uint8_t global_index = 8 + (sample_set * 8) + (uart_id == 5 ? 4 : 0) + base_index; - -// // 3. Store the value logically rather than physically -// latest_valid_amds_samples[bank][local_index] = value; -// -// // 4. Update the ready flag for the specific bank -// amds_samples_ready[bank] = true; - - if (global_index < 24) { - tx_packets[global_index].header = track->header; - tx_packets[global_index].msb = track->data[0]; - tx_packets[global_index].lsb = track->data[1]; - - // Clear 'sent' before raising 'ready' - packet_sent[global_index] = false; - packet_ready[global_index] = true; + while (track->read_index != dma_write_ptr) { + uint8_t byte = pool[track->read_index]; + track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; + + switch (track->state) { + case STATE_IDLE: + // Look for any valid header (0x90, 0x94, 0x98 ranges) + if ((byte & 0xF0) == 0x90) { + track->header = byte; + track->state = STATE_GOT_HEADER; } + break; - track->state = STATE_IDLE; - break; - } - } + case STATE_GOT_HEADER: + track->data[0] = byte; + track->state = STATE_GOT_MSB; // Wait for the next loop iteration to get LSB! + break; + + case STATE_GOT_MSB: + track->data[1] = byte; + + uint8_t packet_to_send[3] = {track->header + 4, track->data[0], track->data[1]}; + if (uart_id == 4) { + dma_queue(2, packet_to_send, 3); + } else { + dma_queue(3, packet_to_send, 3); + } + + track->state = STATE_IDLE; + break; + } + } } void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { - + if (uart_id == 2) { + for (int i = 0; i < len; i++) { + uart2_dma_queue[u2_q_head] = data[i]; + u2_q_head = (u2_q_head + 1) % AMDS_RX_BUF_SIZE; + } + } else if (uart_id == 3) { + for (int i = 0; i < len; i++) { + uart3_dma_queue[u3_q_head] = data[i]; + u3_q_head = (u3_q_head + 1) % AMDS_RX_BUF_SIZE; + } + } } void UART4_IRQHandler(void) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 9fe40137..67f90430 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -41,6 +41,11 @@ int main(void) // SysTick->CTRL &= 0xFFFFFFFE; while (1) { + if ((u2_q_tail != u2_q_head) || u3_q_tail != u3_q_head) { + // Package all ready sets and transmit + process_transmissions(); + } + if (tracker4.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { //update process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); } @@ -49,14 +54,6 @@ int main(void) process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); } - // 2. Transmit Event Triggered by EXTI Sync - if (sync_event_flag) { - sync_event_flag = false; // Acknowledge flag - - // Package all ready sets and transmit - process_transmissions(); - } - if (HAL_GetTick() - ledDelta >= 250) { ledDelta = HAL_GetTick(); drv_led_clear(); @@ -67,12 +64,6 @@ int main(void) led = 0; } } - - -// volatile int i; -// for (i = 0; i < 10000000; i++) { -// asm("nop"); -// } } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index d8dacd59..5ebd6972 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -6,52 +6,35 @@ bool packet_sent[NUM_SETS * PACKETS_PER_SET]; volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR -// Scans the state arrays, builds contiguous buffers, and fires DMA void process_transmissions(void) { - // We only need a tiny 3-byte static buffer for each UART now. - // (Static is still required so the memory persists while DMA is working in the background) - static uint8_t dma_tx2[3]; - static uint8_t dma_tx3[3]; - - // Scan the array for ready/unsent packets - for (int pkt = 0; pkt < NUM_SETS * PACKETS_PER_SET; pkt++) { - // Check hardware states once at the start - while (huart2.gState != HAL_UART_STATE_READY) { - asm("nop"); - } - - while (huart3.gState != HAL_UART_STATE_READY) { - asm("nop"); - } - - if (packet_ready[pkt] && !packet_sent[pkt]) { - - // Route to UART2 - if ((pkt >= 0 && pkt <= 3) || (pkt >= 8 && pkt <= 11) || (pkt >= 16 && pkt <= 19)) { - - // Copy exactly 3 bytes into the UART2 DMA buffer - dma_tx2[0] = tx_packets[pkt].header; - dma_tx2[1] = tx_packets[pkt].msb; - dma_tx2[2] = tx_packets[pkt].lsb; - - packet_sent[pkt] = true; - - HAL_UART_Transmit_DMA(&huart2, dma_tx2, 3); - } - - // Route to UART3 - if ((pkt >= 4 && pkt <= 7) || (pkt >= 12 && pkt <= 15) || (pkt >= 20 && pkt <= 23)) { + uint16_t count2 = 0; + uint16_t count3 = 0; + + // Prepare UART 2 Data + if (huart2.gState == HAL_UART_STATE_READY && u2_q_tail != u2_q_head) { + // Pop all available bytes from the circular queue into the linear DMA buffer + while (u2_q_tail != u2_q_head) { + uart2_dma_buffer[count2++] = uart2_dma_queue[u2_q_tail]; + u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; + } + } - // Copy exactly 3 bytes into the UART3 DMA buffer - dma_tx3[0] = tx_packets[pkt].header; - dma_tx3[1] = tx_packets[pkt].msb; - dma_tx3[2] = tx_packets[pkt].lsb; + // Prepare UART 3 Data + if (huart3.gState == HAL_UART_STATE_READY && u3_q_tail != u3_q_head) { + // Pop all available bytes from the circular queue into the linear DMA buffer + while (u3_q_tail != u3_q_head) { + uart3_dma_buffer[count3++] = uart3_dma_queue[u3_q_tail]; + u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; + } + } - packet_sent[pkt] = true; + // Fire them back-to-back as fast as the CPU can execute the instructions + if (count2 > 0) { + HAL_UART_Transmit_DMA(&huart2, (uint8_t*)uart2_dma_buffer, count2); + } - HAL_UART_Transmit_DMA(&huart3, dma_tx3, 3); - } - } + if (count3 > 0) { + HAL_UART_Transmit_DMA(&huart3, (uint8_t*)uart3_dma_buffer, count3); } } @@ -92,110 +75,110 @@ void process_transmissions(void) { // clang-format on -// Called after ADC conversions have been completed, -// to send sampled data back to AMDC +//// Called after ADC conversions have been completed, +//// to send sampled data back to AMDC +//// +//void transmit_samples(void) +//{ +// // 2. Create a local buffer for this transmission "burst" +// static uint8_t tx_data2[36]; +// static uint8_t tx_data3[36]; +// uint8_t idx = 0; // -void transmit_samples(void) -{ - // 2. Create a local buffer for this transmission "burst" - static uint8_t tx_data2[36]; - static uint8_t tx_data3[36]; - uint8_t idx = 0; - - uint16_t bits[8]; - adc_latest_bits(bits); - - for (int i = 0; i < 4; i++) { - uint8_t header = (i == 0) ? 0x90 : (0x90 | (0x03 & i)); - - tx_data2[idx] = header; - tx_data3[idx] = header; - idx++; - - tx_data2[idx] = (uint8_t)(bits[i] >> 8); // MSB - tx_data3[idx] = (uint8_t)(bits[i + 4] >> 8); // MSB - idx++; - - tx_data2[idx] = (uint8_t)(bits[i] & 0xFF); // LSB - tx_data3[idx] = (uint8_t)(bits[i + 4] & 0xFF); // LSB - idx++; - } - - // 1. Process incoming UARTs first - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - NOP256; - process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); - process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); - - uint16_t amds[16] = {1}; - adc_latest_amds(amds); - - // ... Add AMDS data to tx_data if ready ... - if (amds_samples_ready[0]) { - for (int i = 0; i < 4; i++) { - uint8_t header = (i == 0) ? 0x94 : (0x94 | (0x07 & i)); - - tx_data2[idx] = header; - tx_data3[idx] = header; - idx++; - - tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB - tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB - idx++; - - tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB - tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB - idx++; - } - - // Clear flags for this set - amds_samples_ready[0] = false; - - if (amds_samples_ready[1]) { - for (int i = 0; i < 4; i++) { - uint8_t header = (i == 0) ? 0x98 : (0x98 | (0x0B & i)); - - tx_data2[idx] = header; - tx_data3[idx] = header; - idx++; - - tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB - tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB - idx++; - - tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB - tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB - idx++; - } - - // Clear flags for this set - amds_samples_ready[1] = false; - } - } - - // 4. Trigger the DMA to send exactly 'idx' bytes - // This function returns immediately while the hardware sends the data - if (huart2.gState == HAL_UART_STATE_READY && huart3.gState == HAL_UART_STATE_READY) { - HAL_UART_Transmit_DMA(&huart2, tx_data2, idx); - HAL_UART_Transmit_DMA(&huart3, tx_data3, idx); - } -} +// uint16_t bits[8]; +// adc_latest_bits(bits); +// +// for (int i = 0; i < 4; i++) { +// uint8_t header = (i == 0) ? 0x90 : (0x90 | (0x03 & i)); +// +// tx_data2[idx] = header; +// tx_data3[idx] = header; +// idx++; +// +// tx_data2[idx] = (uint8_t)(bits[i] >> 8); // MSB +// tx_data3[idx] = (uint8_t)(bits[i + 4] >> 8); // MSB +// idx++; +// +// tx_data2[idx] = (uint8_t)(bits[i] & 0xFF); // LSB +// tx_data3[idx] = (uint8_t)(bits[i + 4] & 0xFF); // LSB +// idx++; +// } +// +// // 1. Process incoming UARTs first +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// NOP256; +// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); +// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); +// +// uint16_t amds[16] = {1}; +// adc_latest_amds(amds); +// +// // ... Add AMDS data to tx_data if ready ... +// if (amds_samples_ready[0]) { +// for (int i = 0; i < 4; i++) { +// uint8_t header = (i == 0) ? 0x94 : (0x94 | (0x07 & i)); +// +// tx_data2[idx] = header; +// tx_data3[idx] = header; +// idx++; +// +// tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB +// tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB +// idx++; +// +// tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB +// tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB +// idx++; +// } +// +// // Clear flags for this set +// amds_samples_ready[0] = false; +// +// if (amds_samples_ready[1]) { +// for (int i = 0; i < 4; i++) { +// uint8_t header = (i == 0) ? 0x98 : (0x98 | (0x0B & i)); +// +// tx_data2[idx] = header; +// tx_data3[idx] = header; +// idx++; +// +// tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB +// tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB +// idx++; +// +// tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB +// tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB +// idx++; +// } +// +// // Clear flags for this set +// amds_samples_ready[1] = false; +// } +// } +// +// // 4. Trigger the DMA to send exactly 'idx' bytes +// // This function returns immediately while the hardware sends the data +// if (huart2.gState == HAL_UART_STATE_READY && huart3.gState == HAL_UART_STATE_READY) { +// HAL_UART_Transmit_DMA(&huart2, tx_data2, idx); +// HAL_UART_Transmit_DMA(&huart3, tx_data3, idx); +// } +//} From 65e6e41e02bd757505ad0cc4f8849adb8c476d0c Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Sun, 5 Apr 2026 12:36:26 -0500 Subject: [PATCH 10/72] add none dma transfer of sampled data --- .../motherboard_v1/Core/Inc/drv_uart.h | 37 +++++ .../Firmware/motherboard_v1/Core/Src/adc.c | 43 ++---- .../motherboard_v1/Core/Src/drv_uart.c | 135 +++++++++++++----- .../Firmware/motherboard_v1/Core/Src/main.c | 47 +++--- .../Firmware/motherboard_v1/Core/Src/tx.c | 32 ++--- 5 files changed, 180 insertions(+), 114 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index ce6fc193..5470590b 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -53,6 +53,11 @@ extern volatile uint16_t u3_q_tail; void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); + +void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart); +void process_routing(void); + + static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) { // Wait until UART is ready to accept next character @@ -83,4 +88,36 @@ static inline void drv_uart_send_fast(USART_TypeDef *uart, uint8_t *data, uint16 drv_uart_wait_TC(uart); } +static inline void drv_uart_dma_send_fast(UART_HandleTypeDef *huart, uint8_t *data, uint16_t len) +{ + DMA_Stream_TypeDef *dma = (DMA_Stream_TypeDef *)huart->hdmatx->Instance; + + // 1. Disable the DMA channel + dma->CR &= ~DMA_SxCR_EN; + + // 2. CRITICAL FIX: Wait for the hardware to actually halt. + // Writing to address registers while EN is still high causes a silent failure. + while ((dma->CR & DMA_SxCR_EN) != 0) { + asm("nop"); + } + + // 3. Clear the DMA Transfer Complete and Half Transfer flags + __HAL_DMA_CLEAR_FLAG(huart->hdmatx, __HAL_DMA_GET_TC_FLAG_INDEX(huart->hdmatx)); + __HAL_DMA_CLEAR_FLAG(huart->hdmatx, __HAL_DMA_GET_HT_FLAG_INDEX(huart->hdmatx)); + + // 4. CRITICAL FIX: Tell the DMA exactly *where* to push the bytes. + // It must point directly to the UART's Transmit Data Register. + dma->PAR = (uint32_t)&huart->Instance->TDR; + + // 5. Load the Memory Address and Length registers + dma->M0AR = (uint32_t)data; + dma->NDTR = len; + + // 6. Clear UART Transmission Complete flag to ensure it's ready for a fresh burst + huart->Instance->ICR = USART_ICR_TCCF; + + // 7. Fire! + dma->CR |= DMA_SxCR_EN; +} + #endif // DRV_UART_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index c41ee8f8..f8b894e0 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -181,45 +181,26 @@ void EXTI3_IRQHandler(void) { // alert daisy chained AMDSs to begin converting GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - static uint8_t local_tx2[12] = {0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB}; - static uint8_t local_tx3[12] = {0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB, 0xAB}; // Perform the actual SPI transactions - /*uint16_t new_data[8] = { 0 }; + uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); - // 3. Bypass the circular queue and write straight to local linear buffers - // We use static buffers so they persist in memory while the DMA sends them in the background - static uint8_t local_tx2[12]; - static uint8_t local_tx3[12]; - uint8_t idx = 0; - for (int i = 0; i < 4; i++) { // Ultra-fast header generation (0x90, 0x91, 0x92, 0x93) uint8_t header = 0x90 | i; // Pack UART2 data (Channels 0-3) - local_tx2[idx] = header; - local_tx2[idx+1] = (uint8_t)(new_data[i] >> 8); - local_tx2[idx+2] = (uint8_t)(new_data[i] & 0xFF); - - // Pack UART3 data (Channels 4-7) - local_tx3[idx] = header; - local_tx3[idx+1] = (uint8_t)(new_data[i + 4] >> 8); - local_tx3[idx+2] = (uint8_t)(new_data[i + 4] & 0xFF); - - idx += 3; - }*/ - - // 4. Fire the DMA immediately, back-to-back! - // No waiting for the main loop. As soon as the CPU hits these lines, the bits hit the wire. - if (huart2.gState == HAL_UART_STATE_READY) { - HAL_UART_Transmit_DMA(&huart2, local_tx2, 12); - } - if (huart3.gState == HAL_UART_STATE_READY) { - HAL_UART_Transmit_DMA(&huart3, local_tx3, 12); - } - -// sync_event_flag = true; + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART3, header); + + // Send ADC sample data MSBs + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + + // Send ADC sample data LSBs + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + } // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 7a082b0b..b8b815dc 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -37,49 +37,106 @@ volatile uint16_t u3_q_tail = 0; void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { // Calculate current DMA write position (NDTR counts down) - UART_HandleTypeDef *huart; - if (uart_id == 4) { - huart = &huart4; - } else { - huart = &huart5; + UART_HandleTypeDef *huart = (uart_id == 4) ? &huart4 : &huart5; + uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); + + while (track->read_index != dma_write_ptr) { + uint8_t byte = pool[track->read_index]; + track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; + + switch (track->state) { + case STATE_IDLE: + // Look for any valid header (0x90, 0x94, 0x98 ranges) + if ((byte & 0xF0) == 0x90) { + track->header = byte; + track->state = STATE_GOT_HEADER; + } + break; + + case STATE_GOT_HEADER: + track->data[0] = byte; + track->state = STATE_GOT_MSB; + break; + + case STATE_GOT_MSB: + track->data[1] = byte; + + // --- CUT-THROUGH TRANSMISSION --- + // Determine our target hardware register + USART_TypeDef *target_uart = (uart_id == 4) ? USART2 : USART3; + + // Fire the 3 bytes instantly + drv_uart_putc_fast(target_uart, track->header + 4); + drv_uart_putc_fast(target_uart, track->data[0]); + drv_uart_putc_fast(target_uart, track->data[1]); + + track->state = STATE_IDLE; + break; + } } +} - uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); - - while (track->read_index != dma_write_ptr) { - uint8_t byte = pool[track->read_index]; - track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; - - switch (track->state) { - case STATE_IDLE: - // Look for any valid header (0x90, 0x94, 0x98 ranges) - if ((byte & 0xF0) == 0x90) { - track->header = byte; - track->state = STATE_GOT_HEADER; - } - break; - - case STATE_GOT_HEADER: - track->data[0] = byte; - track->state = STATE_GOT_MSB; // Wait for the next loop iteration to get LSB! - break; - - case STATE_GOT_MSB: - track->data[1] = byte; - - uint8_t packet_to_send[3] = {track->header + 4, track->data[0], track->data[1]}; - if (uart_id == 4) { - dma_queue(2, packet_to_send, 3); - } else { - dma_queue(3, packet_to_send, 3); - } - - track->state = STATE_IDLE; - break; - } - } + +void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart) { + uint8_t byte = pool[track->read_index]; + track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; + + switch (track->state) { + case STATE_IDLE: + // Look for any valid header (0x90, 0x94, 0x98 ranges) + if ((byte & 0xF0) == 0x90) { + track->header = byte; + track->state = STATE_GOT_HEADER; + } + break; + + case STATE_GOT_HEADER: + track->data[0] = byte; + track->state = STATE_GOT_MSB; + break; + + case STATE_GOT_MSB: + track->data[1] = byte; + + // --- CUT-THROUGH TRANSMISSION --- + // The exact microsecond the packet is complete, blast it out + drv_uart_putc_fast(target_uart, track->header + 4); + drv_uart_putc_fast(target_uart, track->data[0]); + drv_uart_putc_fast(target_uart, track->data[1]); + + track->state = STATE_IDLE; + break; + } } +void process_routing(void) { + // Get the current write head for both DMA channels + uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); + uint32_t dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); + + // Loop as long as EITHER buffer has unread data + while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { + + // Process exactly ONE byte for UART4 + if (tracker4.read_index != dma_ptr4) { + process_single_byte(UART4_DMA_Pool, &tracker4, USART2); + } + + // Process exactly ONE byte for UART5 + if (tracker5.read_index != dma_ptr5) { + process_single_byte(UART5_DMA_Pool, &tracker5, USART3); + } + + // Re-read the DMA counters at the end of the loop in case + // new bytes physically arrived while we were parsing the last ones! + dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); + dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); + } +} + + + + void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { if (uart_id == 2) { for (int i = 0; i < len; i++) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 67f90430..5a02a5c7 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -24,6 +24,10 @@ int main(void) drv_uart_init(); drv_led_init(); + // Tell the UART to constantly route TX requests to the DMA controller +// huart2.Instance->CR3 |= USART_CR3_DMAT; +// huart3.Instance->CR3 |= USART_CR3_DMAT; + // Initialize the main modules adc_init(); @@ -41,30 +45,31 @@ int main(void) // SysTick->CTRL &= 0xFFFFFFFE; while (1) { - if ((u2_q_tail != u2_q_head) || u3_q_tail != u3_q_head) { - // Package all ready sets and transmit - process_transmissions(); - } +// // 1. Process and instantly forward UART4 data -> UART2 +// if (tracker4.read_index != (AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { +// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); +// } +// +// // 2. Process and instantly forward UART5 data -> UART3 +// if (tracker5.read_index != (AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx))) { +// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); +// } - if (tracker4.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { //update - process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); - } + // Interleave the parsing and routing for both lines simultaneously + process_routing(); - if (tracker5.read_index != ( AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx))) { //update - process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); - } + // 3. Handle slow UI tasks (LEDs) + if (HAL_GetTick() - ledDelta >= 250) { + ledDelta = HAL_GetTick(); + drv_led_clear(); + drv_led_on(1 << led); + drv_led_display(); - if (HAL_GetTick() - ledDelta >= 250) { - ledDelta = HAL_GetTick(); - drv_led_clear(); - drv_led_on(1 << led); - drv_led_display(); - - if (++led >= DRV_LED_NUM_TOTAL) { - led = 0; - } - } - } + if (++led >= DRV_LED_NUM_TOTAL) { + led = 0; + } + } +} } void HAL_MspInit(void) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 5ebd6972..793c71fa 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -7,35 +7,21 @@ bool packet_sent[NUM_SETS * PACKETS_PER_SET]; volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR void process_transmissions(void) { - uint16_t count2 = 0; - uint16_t count3 = 0; - - // Prepare UART 2 Data - if (huart2.gState == HAL_UART_STATE_READY && u2_q_tail != u2_q_head) { - // Pop all available bytes from the circular queue into the linear DMA buffer - while (u2_q_tail != u2_q_head) { - uart2_dma_buffer[count2++] = uart2_dma_queue[u2_q_tail]; + // Loop as long as there is data in EITHER queue + while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { + + // If UART2 has data, pop one byte and push it straight to the hardware + if (u2_q_tail != u2_q_head) { + drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; } - } - // Prepare UART 3 Data - if (huart3.gState == HAL_UART_STATE_READY && u3_q_tail != u3_q_head) { - // Pop all available bytes from the circular queue into the linear DMA buffer - while (u3_q_tail != u3_q_head) { - uart3_dma_buffer[count3++] = uart3_dma_queue[u3_q_tail]; + // If UART3 has data, pop one byte and push it straight to the hardware + if (u3_q_tail != u3_q_head) { + drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; } } - - // Fire them back-to-back as fast as the CPU can execute the instructions - if (count2 > 0) { - HAL_UART_Transmit_DMA(&huart2, (uint8_t*)uart2_dma_buffer, count2); - } - - if (count3 > 0) { - HAL_UART_Transmit_DMA(&huart3, (uint8_t*)uart3_dma_buffer, count3); - } } From 0e580457161c05a5de9831593384198785443c68 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Sun, 5 Apr 2026 14:04:51 -0500 Subject: [PATCH 11/72] add updated process singly byte function --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 4 +++- Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index f8b894e0..db29d3f5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -186,7 +186,6 @@ void EXTI3_IRQHandler(void) adc_sample_all_daughtercards(new_data); for (int i = 0; i < 4; i++) { - // Ultra-fast header generation (0x90, 0x91, 0x92, 0x93) uint8_t header = 0x90 | i; // Pack UART2 data (Channels 0-3) @@ -202,6 +201,9 @@ void EXTI3_IRQHandler(void) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); } + drv_uart_wait_TC(USART2); + drv_uart_wait_TC(USART3); + // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the // ADC conversions with the SYNC signal from the AMDC. diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index b8b815dc..cb668a87 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -87,6 +87,7 @@ void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef if ((byte & 0xF0) == 0x90) { track->header = byte; track->state = STATE_GOT_HEADER; + drv_uart_putc_fast(target_uart, track->header + 4); } break; @@ -100,7 +101,6 @@ void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef // --- CUT-THROUGH TRANSMISSION --- // The exact microsecond the packet is complete, blast it out - drv_uart_putc_fast(target_uart, track->header + 4); drv_uart_putc_fast(target_uart, track->data[0]); drv_uart_putc_fast(target_uart, track->data[1]); From 824bb43bfe5b18d1d2d23c92ee02e22673419638 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 7 Apr 2026 17:08:00 -0500 Subject: [PATCH 12/72] add more changes to the tranmission firmware --- .../motherboard_v1/Core/Inc/drv_uart.h | 1 + .../Firmware/motherboard_v1/Core/Src/adc.c | 64 ++++++------------- .../motherboard_v1/Core/Src/drv_uart.c | 50 ++++++++++++--- .../Firmware/motherboard_v1/Core/Src/main.c | 10 --- 4 files changed, 60 insertions(+), 65 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 5470590b..207e8235 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -56,6 +56,7 @@ void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart); void process_routing(void); +void process_routing_flipped(void); static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index db29d3f5..7e09d1a5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -45,9 +45,10 @@ static void setup_pin_CONVST(void); // Buffer of latest samples static volatile uint16_t latest_valid_adc_data[8] = { 0 }; -volatile uint16_t latest_valid_amds_samples[2][8] = { 0 }; -volatile bool amds_samples_ready[2] = { 0 }; +// Global bitmask: 1 = Active, 0 = Inactive. +// For example: 0b00010001 (0x0F) means channels 1-4 are active, 5-8 are disabled. +volatile uint8_t active_sensor_mask = 0x11; void adc_init(void) { @@ -74,33 +75,6 @@ void adc_latest_bits(uint16_t *output) output[7] = data[7]; } -// NOTE: this function is called from the transmit function -void adc_latest_amds(uint16_t *output) -{ - volatile uint16_t *data1 = latest_valid_amds_samples[0]; - volatile uint16_t *data2 = latest_valid_amds_samples[1]; - - // Give user their data (unrolled for speed) - output[0] = data1[0]; - output[1] = data1[1]; - output[2] = data1[2]; - output[3] = data1[3]; - output[4] = data1[4]; - output[5] = data1[5]; - output[6] = data1[6]; - output[7] = data1[7]; - - // Give user their data (unrolled for speed) - output[8] = data2[0]; - output[9] = data2[1]; - output[10] = data2[2]; - output[11] = data2[3]; - output[12] = data2[4]; - output[13] = data2[5]; - output[14] = data2[6]; - output[15] = data2[7]; -} - static void adc_sample_all_daughtercards(uint16_t *sample_data_out) { // This function has been optimized for very @@ -185,24 +159,24 @@ void EXTI3_IRQHandler(void) uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); - for (int i = 0; i < 4; i++) { + // Conditionally Transmit + for (int i = 0; i < 4; i++) { uint8_t header = 0x90 | i; - // Pack UART2 data (Channels 0-3) - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); - - // Send ADC sample data MSBs - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - - // Send ADC sample data LSBs - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); - } - - drv_uart_wait_TC(USART2); - drv_uart_wait_TC(USART3); + // Check Channel 0-3 (UART2) + if (active_sensor_mask & (1 << i)) { + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + } + + // Check Channel 4-7 (UART3) + if (active_sensor_mask & (1 << (i + 4))) { + drv_uart_putc_fast(USART3, header); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + } + } // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index cb668a87..6bc9ac6e 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -86,22 +86,21 @@ void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef // Look for any valid header (0x90, 0x94, 0x98 ranges) if ((byte & 0xF0) == 0x90) { track->header = byte; - track->state = STATE_GOT_HEADER; drv_uart_putc_fast(target_uart, track->header + 4); + track->state = STATE_GOT_HEADER; } break; case STATE_GOT_HEADER: track->data[0] = byte; + drv_uart_putc_fast(target_uart, track->data[0]); track->state = STATE_GOT_MSB; break; case STATE_GOT_MSB: track->data[1] = byte; - // --- CUT-THROUGH TRANSMISSION --- // The exact microsecond the packet is complete, blast it out - drv_uart_putc_fast(target_uart, track->data[0]); drv_uart_putc_fast(target_uart, track->data[1]); track->state = STATE_IDLE; @@ -134,6 +133,31 @@ void process_routing(void) { } } +void process_routing_flipped(void) { + // Get the current write head for both DMA channels + uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); + uint32_t dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); + + // Loop as long as EITHER buffer has unread data + while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { + + // Process exactly ONE byte for UART5 + if (tracker5.read_index != dma_ptr5) { + process_single_byte(UART5_DMA_Pool, &tracker5, USART3); + } + + // Process exactly ONE byte for UART4 + if (tracker4.read_index != dma_ptr4) { + process_single_byte(UART4_DMA_Pool, &tracker4, USART2); + } + + // Re-read the DMA counters at the end of the loop in case + // new bytes physically arrived while we were parsing the last ones! + dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); + dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); + } +} + @@ -153,18 +177,21 @@ void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { void UART4_IRQHandler(void) { - // Check for Overrun, Noise, or Frame errors - if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) || + // Check for Parity, Overrun, Noise, or Frame errors + if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) || __HAL_UART_GET_FLAG(&huart4, UART_FLAG_NE) || __HAL_UART_GET_FLAG(&huart4, UART_FLAG_FE)) { - // 1. Clear the error flags - __HAL_UART_CLEAR_IT(&huart4, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + // 1. Clear the error flags (Added UART_CLEAR_PEF) + __HAL_UART_CLEAR_IT(&huart4, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); // 2. IMPORTANT: Re-enable DMA receiver request - // Sometimes HAL disables this bit (DMAR) on error. + // The hardware/HAL drops this bit on error, halting the DMA stream. SET_BIT(huart4.Instance->CR3, USART_CR3_DMAR); } + + // Process normal RX/TX interrupts via the HAL HAL_UART_IRQHandler(&huart4); } @@ -176,12 +203,13 @@ void DMA1_Stream2_IRQHandler(void) void UART5_IRQHandler(void) { // Check for Overrun, Noise, or Frame errors - if (__HAL_UART_GET_FLAG(&huart5, UART_FLAG_ORE) || + if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&huart5, UART_FLAG_ORE) || __HAL_UART_GET_FLAG(&huart5, UART_FLAG_NE) || __HAL_UART_GET_FLAG(&huart5, UART_FLAG_FE)) { // 1. Clear the error flags - __HAL_UART_CLEAR_IT(&huart5, UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + __HAL_UART_CLEAR_IT(&huart5, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); // 2. IMPORTANT: Re-enable DMA receiver request // Sometimes HAL disables this bit (DMAR) on error. @@ -337,6 +365,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) // DMA config - check your device's DMA request mapping table // for the correct stream/channel for USART2_TX hdma_usart2_tx.Instance = DMA1_Stream6; + hdma_usart2_tx.Instance->CR |= USART_CR3_DDRE; hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4; hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // Memory -> UART hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; @@ -375,6 +404,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) // DMA config - check your device's DMA request mapping table // for the correct stream/channel for USART3_TX hdma_usart3_tx.Instance = DMA1_Stream3; + hdma_usart3_tx.Instance->CR |= USART_CR3_DDRE; hdma_usart3_tx.Init.Channel = DMA_CHANNEL_4; hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // Memory -> UART hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 5a02a5c7..c3f84c91 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -45,16 +45,6 @@ int main(void) // SysTick->CTRL &= 0xFFFFFFFE; while (1) { -// // 1. Process and instantly forward UART4 data -> UART2 -// if (tracker4.read_index != (AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx))) { -// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); -// } -// -// // 2. Process and instantly forward UART5 data -> UART3 -// if (tracker5.read_index != (AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx))) { -// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); -// } - // Interleave the parsing and routing for both lines simultaneously process_routing(); From e1c063084f9151e4112983d244a6f02da8cf2fad Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 10 Apr 2026 16:02:57 -0500 Subject: [PATCH 13/72] add ifs between transmission --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 7e09d1a5..e4a7ca46 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -48,7 +48,7 @@ static volatile uint16_t latest_valid_adc_data[8] = { 0 }; // Global bitmask: 1 = Active, 0 = Inactive. // For example: 0b00010001 (0x0F) means channels 1-4 are active, 5-8 are disabled. -volatile uint8_t active_sensor_mask = 0x11; +volatile uint8_t active_sensor_mask = 0xFF; void adc_init(void) { @@ -167,13 +167,20 @@ void EXTI3_IRQHandler(void) if (active_sensor_mask & (1 << i)) { drv_uart_putc_fast(USART2, header); drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); } // Check Channel 4-7 (UART3) if (active_sensor_mask & (1 << (i + 4))) { drv_uart_putc_fast(USART3, header); drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + } + + if (active_sensor_mask & (1 << i)) { + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + } + + // Check Channel 4-7 (UART3) + if (active_sensor_mask & (1 << (i + 4))) { drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); } } From ec6dca66a148617ea911a00be8bac6144512db90 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 10 Apr 2026 16:07:37 -0500 Subject: [PATCH 14/72] add boolean for second if --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index e4a7ca46..32987a89 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -162,25 +162,29 @@ void EXTI3_IRQHandler(void) // Conditionally Transmit for (int i = 0; i < 4; i++) { uint8_t header = 0x90 | i; + bool u3 = false; + bool u2 = false; // Check Channel 0-3 (UART2) if (active_sensor_mask & (1 << i)) { drv_uart_putc_fast(USART2, header); + u2 = true; drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); } // Check Channel 4-7 (UART3) if (active_sensor_mask & (1 << (i + 4))) { drv_uart_putc_fast(USART3, header); + u3 = true; drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); } - if (active_sensor_mask & (1 << i)) { + if (u2) { drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); } // Check Channel 4-7 (UART3) - if (active_sensor_mask & (1 << (i + 4))) { + if (u3) { drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); } } From 8744f6df0b43e0358d6625a9281fbf5be47f05a7 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 10 Apr 2026 16:36:12 -0500 Subject: [PATCH 15/72] add fastest version of personal data transmit --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 32987a89..dcf50cc2 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -180,12 +180,12 @@ void EXTI3_IRQHandler(void) } if (u2) { - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFE)); } // Check Channel 4-7 (UART3) if (u3) { - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFE)); } } From 8b208ae9f481f782fab5def2fde90a74f86c2ec4 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 10 Apr 2026 16:36:38 -0500 Subject: [PATCH 16/72] remove FE --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index dcf50cc2..32987a89 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -180,12 +180,12 @@ void EXTI3_IRQHandler(void) } if (u2) { - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFE)); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); } // Check Channel 4-7 (UART3) if (u3) { - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFE)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); } } From 275b668919d40b725798d48ac499606a7dc2e513 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 14 Apr 2026 16:19:43 -0500 Subject: [PATCH 17/72] turn process single byte into static inline --- .../motherboard_v1/Core/Inc/drv_uart.h | 3 -- .../motherboard_v1/Core/Src/drv_uart.c | 33 +++---------------- 2 files changed, 5 insertions(+), 31 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 207e8235..1aece6ae 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -53,10 +53,7 @@ extern volatile uint16_t u3_q_tail; void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); - -void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart); void process_routing(void); -void process_routing_flipped(void); static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 6bc9ac6e..4a109ae8 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -77,7 +77,7 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) } -void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart) { +static inline void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart) { uint8_t byte = pool[track->read_index]; track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; @@ -133,33 +133,6 @@ void process_routing(void) { } } -void process_routing_flipped(void) { - // Get the current write head for both DMA channels - uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); - uint32_t dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - - // Loop as long as EITHER buffer has unread data - while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { - - // Process exactly ONE byte for UART5 - if (tracker5.read_index != dma_ptr5) { - process_single_byte(UART5_DMA_Pool, &tracker5, USART3); - } - - // Process exactly ONE byte for UART4 - if (tracker4.read_index != dma_ptr4) { - process_single_byte(UART4_DMA_Pool, &tracker4, USART2); - } - - // Re-read the DMA counters at the end of the loop in case - // new bytes physically arrived while we were parsing the last ones! - dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); - dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - } -} - - - void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { if (uart_id == 2) { @@ -189,6 +162,8 @@ void UART4_IRQHandler(void) // 2. IMPORTANT: Re-enable DMA receiver request // The hardware/HAL drops this bit on error, halting the DMA stream. SET_BIT(huart4.Instance->CR3, USART_CR3_DMAR); + + return; } // Process normal RX/TX interrupts via the HAL @@ -214,6 +189,8 @@ void UART5_IRQHandler(void) // 2. IMPORTANT: Re-enable DMA receiver request // Sometimes HAL disables this bit (DMAR) on error. SET_BIT(huart5.Instance->CR3, USART_CR3_DMAR); + + return; } HAL_UART_IRQHandler(&huart5); } From 2a126aa042eaad1fef5d40a5b34df5979280e20f Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 15 Apr 2026 12:56:27 -0500 Subject: [PATCH 18/72] remove process_routing from main and place after interrupt --- .../motherboard_v1/Core/Inc/drv_uart.h | 2 +- .../Firmware/motherboard_v1/Core/Src/adc.c | 2 + .../motherboard_v1/Core/Src/drv_uart.c | 56 ++++++++++--------- .../Firmware/motherboard_v1/Core/Src/main.c | 2 +- 4 files changed, 34 insertions(+), 28 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 1aece6ae..8467369a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -29,7 +29,7 @@ typedef struct { rx_state_t state; uint8_t header; uint8_t data[2]; - uint32_t read_index; + uint8_t read_index; } uart_rx_tracker_t; extern uart_rx_tracker_t tracker4; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 32987a89..abd765df 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -189,6 +189,8 @@ void EXTI3_IRQHandler(void) } } + process_routing(); + // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the // ADC conversions with the SYNC signal from the AMDC. diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 4a109ae8..03975d00 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -79,30 +79,25 @@ void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) static inline void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart) { uint8_t byte = pool[track->read_index]; - track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; + + // read_index is 8 bits long so it will already wrap after 256 + track->read_index++; switch (track->state) { case STATE_IDLE: - // Look for any valid header (0x90, 0x94, 0x98 ranges) if ((byte & 0xF0) == 0x90) { - track->header = byte; - drv_uart_putc_fast(target_uart, track->header + 4); + drv_uart_putc_fast(target_uart, byte + 4); track->state = STATE_GOT_HEADER; } break; case STATE_GOT_HEADER: - track->data[0] = byte; - drv_uart_putc_fast(target_uart, track->data[0]); + drv_uart_putc_fast(target_uart, byte); track->state = STATE_GOT_MSB; break; case STATE_GOT_MSB: - track->data[1] = byte; - // --- CUT-THROUGH TRANSMISSION --- - // The exact microsecond the packet is complete, blast it out - drv_uart_putc_fast(target_uart, track->data[1]); - + drv_uart_putc_fast(target_uart, byte); track->state = STATE_IDLE; break; } @@ -113,24 +108,33 @@ void process_routing(void) { uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); uint32_t dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - // Loop as long as EITHER buffer has unread data - while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { + uint8_t i = 0; + while ((tracker4.read_index == dma_ptr4) || (tracker5.read_index == dma_ptr5)) { + asm("nop"); + if (i++ >= 10) + return; - // Process exactly ONE byte for UART4 - if (tracker4.read_index != dma_ptr4) { - process_single_byte(UART4_DMA_Pool, &tracker4, USART2); - } + dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); + dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); + } - // Process exactly ONE byte for UART5 - if (tracker5.read_index != dma_ptr5) { - process_single_byte(UART5_DMA_Pool, &tracker5, USART3); - } + // Loop as long as EITHER buffer has unread data + do { + while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { + if (tracker4.read_index != dma_ptr4) { + process_single_byte(UART4_DMA_Pool, &tracker4, USART2); + } + + if (tracker5.read_index != dma_ptr5) { + process_single_byte(UART5_DMA_Pool, &tracker5, USART3); + } + } - // Re-read the DMA counters at the end of the loop in case - // new bytes physically arrived while we were parsing the last ones! - dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); - dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - } + // Check one last time before returning to see if bytes arrived while parsing + dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); + dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); + + } while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index c3f84c91..f11878ed 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -46,7 +46,7 @@ int main(void) while (1) { // Interleave the parsing and routing for both lines simultaneously - process_routing(); +// process_routing(); // 3. Handle slow UI tasks (LEDs) if (HAL_GetTick() - ledDelta >= 250) { From 9d5b3e5f697d7e96595a387086fa88cf6cf4d144 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Thu, 16 Apr 2026 17:19:47 -0500 Subject: [PATCH 19/72] add synchronous single byte function --- .../motherboard_v1/Core/Src/drv_uart.c | 107 ++++++++++++++++-- .../Firmware/motherboard_v1/Core/Src/main.c | 2 +- 2 files changed, 98 insertions(+), 11 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 03975d00..3626dd77 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -103,21 +103,108 @@ static inline void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, } } +static inline void process_bytes_parallel(uint8_t len) { + bool send2 = false; + bool send3 = false; + for (uint8_t i = 0; i < len; i++) { + // Fetch bytes and increment indices (relies on 8-bit wrap around) + uint8_t byte4 = UART4_DMA_Pool[tracker4.read_index++]; + uint8_t byte5 = UART5_DMA_Pool[tracker5.read_index++]; + + // Evaluate Tracker 4 (UART4 -> USART2) + switch (tracker4.state) { + case STATE_IDLE: + if ((byte4 & 0xF0) == 0x90) { + byte4 += 4; + send2 = true; + tracker4.state = STATE_GOT_HEADER; + } + break; + case STATE_GOT_HEADER: + send2 = true; + tracker4.state = STATE_GOT_MSB; + break; + case STATE_GOT_MSB: + send2 = true; + tracker4.state = STATE_IDLE; + break; + } + + // Evaluate Tracker 5 (UART5 -> USART3) + switch (tracker5.state) { + case STATE_IDLE: + if ((byte5 & 0xF0) == 0x90) { + byte5 += 4; + send3 = true; + tracker5.state = STATE_GOT_HEADER; + } + break; + case STATE_GOT_HEADER: + send3 = true; + tracker5.state = STATE_GOT_MSB; + break; + case STATE_GOT_MSB: + send3 = true; + tracker5.state = STATE_IDLE; + break; + } + + // Interleave the hardware writes to minimize blocking + if (send2) { + drv_uart_putc_fast(USART2, byte4 & 0xFE); + } + if (send3) { + drv_uart_putc_fast(USART3, byte5 & 0xFE); + } + send2 = false; + send3 = false; + } +} + void process_routing(void) { + uint8_t dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + uint8_t dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx));; + uint8_t pending4; + uint8_t pending5; + + do { + // Calculate how many unread bytes exist in each buffer + pending4 = (uint8_t)(dma_ptr4 - tracker4.read_index); + pending5 = (uint8_t)(dma_ptr5 - tracker5.read_index); + + // Process the overlapping chunk in parallel + uint8_t common_len = (pending4 < pending5) ? pending4 : pending5; + if (common_len > 0) { + process_bytes_parallel(common_len); + } + + // Handle remaining bytes for UART4 if it received more + uint8_t remainder4 = pending4 - common_len; + while (remainder4--) { + process_single_byte(UART4_DMA_Pool, &tracker4, USART2); + } + + // Handle remaining bytes for UART5 if it received more + uint8_t remainder5 = pending5 - common_len; + while (remainder5--) { + process_single_byte(UART5_DMA_Pool, &tracker5, USART3); + } + + // Check one last time to see if new bytes arrived during the parsing loops + dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + + } while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); +} + + + + +void process_routing_old(void) { // Get the current write head for both DMA channels uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); uint32_t dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - uint8_t i = 0; - while ((tracker4.read_index == dma_ptr4) || (tracker5.read_index == dma_ptr5)) { - asm("nop"); - if (i++ >= 10) - return; - - dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); - dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - } - // Loop as long as EITHER buffer has unread data do { while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index f11878ed..c3f84c91 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -46,7 +46,7 @@ int main(void) while (1) { // Interleave the parsing and routing for both lines simultaneously -// process_routing(); + process_routing(); // 3. Handle slow UI tasks (LEDs) if (HAL_GetTick() - ledDelta >= 250) { From 7e08bf42be06bad3050e285d62048e05d8316c0c Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 17 Apr 2026 17:30:19 -0500 Subject: [PATCH 20/72] remove state machine --- .../motherboard_v1/Core/Inc/drv_uart.h | 20 +- .../Firmware/motherboard_v1/Core/Src/adc.c | 2 +- .../motherboard_v1/Core/Src/drv_uart.c | 198 +++++------------- .../Firmware/motherboard_v1/Core/Src/main.c | 8 +- .../Firmware/motherboard_v1/Core/Src/tx.c | 28 +-- 5 files changed, 77 insertions(+), 179 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 8467369a..f1e047f9 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -39,21 +39,19 @@ extern uart_rx_tracker_t tracker5; extern uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; - -// Queue tracking indices -extern volatile uint16_t u2_q_head; -extern volatile uint16_t u2_q_tail; -extern volatile uint16_t u3_q_head; -extern volatile uint16_t u3_q_tail; - void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); void process_routing(void); +void process_routing_old(void); + +static inline bool data_ready() +{ + uint8_t dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + uint8_t dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx));; + + return ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); +} static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index abd765df..cf84372a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -189,7 +189,7 @@ void EXTI3_IRQHandler(void) } } - process_routing(); + process_routing_old(); // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 3626dd77..d4bca2e8 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -25,145 +25,63 @@ uart_rx_tracker_t tracker5 = {0}; uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; -volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; -volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; -volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; -volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; - -volatile uint16_t u2_q_head = 0; -volatile uint16_t u2_q_tail = 0; -volatile uint16_t u3_q_head = 0; -volatile uint16_t u3_q_tail = 0; - -void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { - // Calculate current DMA write position (NDTR counts down) - UART_HandleTypeDef *huart = (uart_id == 4) ? &huart4 : &huart5; - uint32_t dma_write_ptr = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx); - - while (track->read_index != dma_write_ptr) { - uint8_t byte = pool[track->read_index]; - track->read_index = (track->read_index + 1) % AMDS_RX_BUF_SIZE; - - switch (track->state) { - case STATE_IDLE: - // Look for any valid header (0x90, 0x94, 0x98 ranges) - if ((byte & 0xF0) == 0x90) { - track->header = byte; - track->state = STATE_GOT_HEADER; - } - break; - - case STATE_GOT_HEADER: - track->data[0] = byte; - track->state = STATE_GOT_MSB; - break; - - case STATE_GOT_MSB: - track->data[1] = byte; - - // --- CUT-THROUGH TRANSMISSION --- - // Determine our target hardware register - USART_TypeDef *target_uart = (uart_id == 4) ? USART2 : USART3; - - // Fire the 3 bytes instantly - drv_uart_putc_fast(target_uart, track->header + 4); - drv_uart_putc_fast(target_uart, track->data[0]); - drv_uart_putc_fast(target_uart, track->data[1]); - - track->state = STATE_IDLE; - break; - } - } -} - +uint8_t count4 = 0; +uint8_t count5 = 0; -static inline void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart) { +static inline void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart, uint8_t count) { uint8_t byte = pool[track->read_index]; // read_index is 8 bits long so it will already wrap after 256 track->read_index++; - switch (track->state) { - case STATE_IDLE: - if ((byte & 0xF0) == 0x90) { - drv_uart_putc_fast(target_uart, byte + 4); - track->state = STATE_GOT_HEADER; - } - break; - - case STATE_GOT_HEADER: - drv_uart_putc_fast(target_uart, byte); - track->state = STATE_GOT_MSB; - break; - - case STATE_GOT_MSB: - drv_uart_putc_fast(target_uart, byte); - track->state = STATE_IDLE; - break; - } +// switch (track->state) { +// case STATE_IDLE: +// if ((byte & 0xF0) == 0x90) { +// drv_uart_putc_fast(target_uart, byte + 4); +// track->state = STATE_GOT_HEADER; +// } +// break; +// +// case STATE_GOT_HEADER: +// drv_uart_putc_fast(target_uart, byte); +// track->state = STATE_GOT_MSB; +// break; +// +// case STATE_GOT_MSB: +// drv_uart_putc_fast(target_uart, byte); +// track->state = STATE_IDLE; +// break; +// } + if (count == 0) + byte += 4; + + drv_uart_putc_fast(target_uart, byte); + } static inline void process_bytes_parallel(uint8_t len) { - bool send2 = false; - bool send3 = false; for (uint8_t i = 0; i < len; i++) { // Fetch bytes and increment indices (relies on 8-bit wrap around) uint8_t byte4 = UART4_DMA_Pool[tracker4.read_index++]; uint8_t byte5 = UART5_DMA_Pool[tracker5.read_index++]; - // Evaluate Tracker 4 (UART4 -> USART2) - switch (tracker4.state) { - case STATE_IDLE: - if ((byte4 & 0xF0) == 0x90) { - byte4 += 4; - send2 = true; - tracker4.state = STATE_GOT_HEADER; - } - break; - case STATE_GOT_HEADER: - send2 = true; - tracker4.state = STATE_GOT_MSB; - break; - case STATE_GOT_MSB: - send2 = true; - tracker4.state = STATE_IDLE; - break; - } + if ((byte4 & 0xF0) == 0x90) { + byte4 += 4; + } - // Evaluate Tracker 5 (UART5 -> USART3) - switch (tracker5.state) { - case STATE_IDLE: - if ((byte5 & 0xF0) == 0x90) { - byte5 += 4; - send3 = true; - tracker5.state = STATE_GOT_HEADER; - } - break; - case STATE_GOT_HEADER: - send3 = true; - tracker5.state = STATE_GOT_MSB; - break; - case STATE_GOT_MSB: - send3 = true; - tracker5.state = STATE_IDLE; - break; - } + if ((byte5 & 0xF0) == 0x90) { + byte5 += 4; + } // Interleave the hardware writes to minimize blocking - if (send2) { - drv_uart_putc_fast(USART2, byte4 & 0xFE); - } - if (send3) { - drv_uart_putc_fast(USART3, byte5 & 0xFE); - } - send2 = false; - send3 = false; + drv_uart_putc_fast(USART2, byte4 & 0xFE); + drv_uart_putc_fast(USART3, byte5 & 0xFE); } } void process_routing(void) { uint8_t dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - uint8_t dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx));; + uint8_t dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); uint8_t pending4; uint8_t pending5; @@ -178,17 +96,21 @@ void process_routing(void) { process_bytes_parallel(common_len); } - // Handle remaining bytes for UART4 if it received more - uint8_t remainder4 = pending4 - common_len; - while (remainder4--) { - process_single_byte(UART4_DMA_Pool, &tracker4, USART2); - } + while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { + if (tracker4.read_index != dma_ptr4) { + process_single_byte(UART4_DMA_Pool, &tracker4, USART2, count4); + count4++; + if (count4 > 2) + count4 = 0; + } - // Handle remaining bytes for UART5 if it received more - uint8_t remainder5 = pending5 - common_len; - while (remainder5--) { - process_single_byte(UART5_DMA_Pool, &tracker5, USART3); - } + if (tracker5.read_index != dma_ptr5) { + process_single_byte(UART5_DMA_Pool, &tracker5, USART3, count5); + count5++; + if (count5 > 2) + count5 = 0; + } + } // Check one last time to see if new bytes arrived during the parsing loops dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); @@ -197,9 +119,6 @@ void process_routing(void) { } while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); } - - - void process_routing_old(void) { // Get the current write head for both DMA channels uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); @@ -209,11 +128,11 @@ void process_routing_old(void) { do { while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { if (tracker4.read_index != dma_ptr4) { - process_single_byte(UART4_DMA_Pool, &tracker4, USART2); + process_single_byte(UART4_DMA_Pool, &tracker4, USART2, count4); } if (tracker5.read_index != dma_ptr5) { - process_single_byte(UART5_DMA_Pool, &tracker5, USART3); + process_single_byte(UART5_DMA_Pool, &tracker5, USART3, count5); } } @@ -224,21 +143,6 @@ void process_routing_old(void) { } while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); } - -void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { - if (uart_id == 2) { - for (int i = 0; i < len; i++) { - uart2_dma_queue[u2_q_head] = data[i]; - u2_q_head = (u2_q_head + 1) % AMDS_RX_BUF_SIZE; - } - } else if (uart_id == 3) { - for (int i = 0; i < len; i++) { - uart3_dma_queue[u3_q_head] = data[i]; - u3_q_head = (u3_q_head + 1) % AMDS_RX_BUF_SIZE; - } - } -} - void UART4_IRQHandler(void) { // Check for Parity, Overrun, Noise, or Frame errors diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index c3f84c91..73bce47d 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -24,10 +24,6 @@ int main(void) drv_uart_init(); drv_led_init(); - // Tell the UART to constantly route TX requests to the DMA controller -// huart2.Instance->CR3 |= USART_CR3_DMAT; -// huart3.Instance->CR3 |= USART_CR3_DMAT; - // Initialize the main modules adc_init(); @@ -46,9 +42,9 @@ int main(void) while (1) { // Interleave the parsing and routing for both lines simultaneously - process_routing(); + process_routing_old(); - // 3. Handle slow UI tasks (LEDs) + // 3. Handle LEDs if (HAL_GetTick() - ledDelta >= 250) { ledDelta = HAL_GetTick(); drv_led_clear(); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 793c71fa..f5ef2e9e 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -8,20 +8,20 @@ volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR void process_transmissions(void) { // Loop as long as there is data in EITHER queue - while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { - - // If UART2 has data, pop one byte and push it straight to the hardware - if (u2_q_tail != u2_q_head) { - drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); - u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; - } - - // If UART3 has data, pop one byte and push it straight to the hardware - if (u3_q_tail != u3_q_head) { - drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); - u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; - } - } +// while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { +// +// // If UART2 has data, pop one byte and push it straight to the hardware +// if (u2_q_tail != u2_q_head) { +// drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); +// u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; +// } +// +// // If UART3 has data, pop one byte and push it straight to the hardware +// if (u3_q_tail != u3_q_head) { +// drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); +// u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; +// } +// } } From df568e7191175891ac12697930c344d78369d841 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Sat, 18 Apr 2026 12:20:11 -0500 Subject: [PATCH 21/72] Optimize DMA routing time for ST MCU --- .../motherboard_v1/Core/Inc/drv_uart.h | 72 +++++- .../Firmware/motherboard_v1/Core/Src/adc.c | 5 +- .../motherboard_v1/Core/Src/drv_uart.c | 240 ++++++++++-------- .../Firmware/motherboard_v1/Core/Src/main.c | 31 ++- .../Firmware/motherboard_v1/Core/Src/tx.c | 28 +- 5 files changed, 236 insertions(+), 140 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index f1e047f9..b1a92755 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -35,24 +35,80 @@ typedef struct { extern uart_rx_tracker_t tracker4; extern uart_rx_tracker_t tracker5; -#define AMDS_RX_BUF_SIZE 256 +#define AMDS_RX_BUF_SIZE 256 // Must be 256 for uint8_t indexing and wrap-around logic to work correctly extern uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; +extern volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; + +// Queue tracking indices +extern volatile uint16_t u2_q_head; +extern volatile uint16_t u2_q_tail; +extern volatile uint16_t u3_q_head; +extern volatile uint16_t u3_q_tail; + +// Declare the global flag so all .c files know it exists +extern volatile bool is_routing_active; + void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); void process_routing(void); -void process_routing_old(void); - -static inline bool data_ready() -{ - uint8_t dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - uint8_t dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx));; - return ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); +/** + * Thread-safe, non-blocking wrapper for process_routing(). + * Uses an atomic try-lock to prevent reentrancy without + * stalling the CPU or blinding interrupts for too long. + */ +static inline void try_process_routing(void) { + // 1. Enter brief critical section (approx. 3 CPU cycles) + __disable_irq(); + + // 2. Check if the lock is already claimed + if (is_routing_active) { + // Someone else is already routing. Safely abort. + __enable_irq(); + return; + } + + // 3. Claim the lock + is_routing_active = true; + + // 4. Exit critical section BEFORE the heavy lifting + __enable_irq(); + + // 5. Perform the actual routing with interrupts perfectly active + process_routing(); + + // 6. Release the lock when finished + // (This single write is inherently atomic on a 32-bit ARM core, + // so we don't need to disable interrupts just to clear it). + is_routing_active = false; } +/** + * Attempt to instantly reset the routing state machine and flush buffers. + * To be called ONLY from the very beginning of EXTI3_IRQHandler. + */ +static inline void try_reset_routing_state(void) { + // Because we are inside an IRQ, we preempted main(). + // We do NOT need to disable interrupts here to check the flag safely. + if (!is_routing_active) { + + // 1. Reset state machines to gracefully await the next packet + tracker4.state = STATE_IDLE; + tracker5.state = STATE_IDLE; + + // 2. Soft-flush the DMA buffers. + // We advance our read pointers to exactly where the DMA hardware + // is currently writing. All old, unprocessed bytes are instantly discarded. + tracker4.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + tracker5.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + } +} static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index cf84372a..7122460a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -155,6 +155,8 @@ void EXTI3_IRQHandler(void) { // alert daisy chained AMDSs to begin converting GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //reset DMA routing state machine to ensure robust operation in case bytes were dropped + try_reset_routing_state(); // Perform the actual SPI transactions uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); @@ -189,7 +191,8 @@ void EXTI3_IRQHandler(void) } } - process_routing_old(); + //Handle any DMA data that has been received from daisy chain + try_process_routing(); // This try function is thread safe // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index d4bca2e8..98e637a3 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -25,122 +25,154 @@ uart_rx_tracker_t tracker5 = {0}; uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; -uint8_t count4 = 0; -uint8_t count5 = 0; - -static inline void process_single_byte(uint8_t *pool, uart_rx_tracker_t *track, USART_TypeDef *target_uart, uint8_t count) { - uint8_t byte = pool[track->read_index]; - - // read_index is 8 bits long so it will already wrap after 256 - track->read_index++; - -// switch (track->state) { -// case STATE_IDLE: -// if ((byte & 0xF0) == 0x90) { -// drv_uart_putc_fast(target_uart, byte + 4); -// track->state = STATE_GOT_HEADER; -// } -// break; -// -// case STATE_GOT_HEADER: -// drv_uart_putc_fast(target_uart, byte); -// track->state = STATE_GOT_MSB; -// break; -// -// case STATE_GOT_MSB: -// drv_uart_putc_fast(target_uart, byte); -// track->state = STATE_IDLE; -// break; -// } - if (count == 0) - byte += 4; - - drv_uart_putc_fast(target_uart, byte); +volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; +volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; -} - -static inline void process_bytes_parallel(uint8_t len) { - for (uint8_t i = 0; i < len; i++) { - // Fetch bytes and increment indices (relies on 8-bit wrap around) - uint8_t byte4 = UART4_DMA_Pool[tracker4.read_index++]; - uint8_t byte5 = UART5_DMA_Pool[tracker5.read_index++]; - - if ((byte4 & 0xF0) == 0x90) { - byte4 += 4; - } +volatile uint16_t u2_q_head = 0; +volatile uint16_t u2_q_tail = 0; +volatile uint16_t u3_q_head = 0; +volatile uint16_t u3_q_tail = 0; - if ((byte5 & 0xF0) == 0x90) { - byte5 += 4; - } +// Global flag to track if routing is actively occurring. +// Must be volatile so the compiler knows it can change inside an IRQ. +volatile bool is_routing_active = false; - // Interleave the hardware writes to minimize blocking - drv_uart_putc_fast(USART2, byte4 & 0xFE); - drv_uart_putc_fast(USART3, byte5 & 0xFE); - } -} void process_routing(void) { - uint8_t dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - uint8_t dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); - uint8_t pending4; - uint8_t pending5; - - do { - // Calculate how many unread bytes exist in each buffer - pending4 = (uint8_t)(dma_ptr4 - tracker4.read_index); - pending5 = (uint8_t)(dma_ptr5 - tracker5.read_index); - - // Process the overlapping chunk in parallel - uint8_t common_len = (pending4 < pending5) ? pending4 : pending5; - if (common_len > 0) { - process_bytes_parallel(common_len); + // 1. Load tracking state into local CPU registers for zero-wait-state access + uint8_t r4 = tracker4.read_index; + uint8_t r5 = tracker5.read_index; + uint8_t s4 = tracker4.state; + uint8_t s5 = tracker5.state; + + // 2. Read DMA hardware pointers ONCE at the start. + // NDTR counts down, so the write head is (SIZE - NDTR). + // Casting to uint8_t naturally handles the modulo wrap-around at 256. + uint8_t w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + uint8_t w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + + // 3. Process instantly as long as either buffer has data. No NOP delays! + while ((r4 != w4) || (r5 != w5)) { + + // --- Process ONE byte from UART4 --- + if (r4 != w4) { + uint8_t b4 = UART4_DMA_Pool[r4++]; + + if (s4 == STATE_IDLE) { + if ((b4 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART2, b4 + 4); // Increment ID + //If we have another byte, do the next state (this MCU can send 2 bytes fast) + if (r4 != w4) { + b4 = UART4_DMA_Pool[r4++]; + drv_uart_putc_fast(USART2, b4); + s4 = STATE_GOT_MSB; + } + else + s4 = STATE_GOT_HEADER; + } + } else if (s4 == STATE_GOT_HEADER) { + drv_uart_putc_fast(USART2, b4); + //If we have another byte, do the next state (this MCU can send 2 bytes fast) + if (r4 != w4) { + b4 = UART4_DMA_Pool[r4++]; + drv_uart_putc_fast(USART2, b4); + s4 = STATE_IDLE; + } + else + s4 = STATE_GOT_MSB; + } else { // STATE_GOT_MSB + drv_uart_putc_fast(USART2, b4); + //If we have another byte, do the next state (this MCU can send 2 bytes fast) + if (r4 != w4) { + b4 = UART4_DMA_Pool[r4++]; + if ((b4 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART2, b4 + 4); // Increment ID + s4 = STATE_GOT_HEADER; + } + else + s4 = STATE_IDLE; + } + else + s4 = STATE_IDLE; + } } - while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { - if (tracker4.read_index != dma_ptr4) { - process_single_byte(UART4_DMA_Pool, &tracker4, USART2, count4); - count4++; - if (count4 > 2) - count4 = 0; - } - - if (tracker5.read_index != dma_ptr5) { - process_single_byte(UART5_DMA_Pool, &tracker5, USART3, count5); - count5++; - if (count5 > 2) - count5 = 0; - } - } + // --- Process ONE byte from UART5 --- + // By interleaving this right after USART2, we give USART2 hardware + // time to shift bits onto the wire, preventing the 3rd byte from blocking! + if (r5 != w5) { + uint8_t b5 = UART5_DMA_Pool[r5++]; + + if (s5 == STATE_IDLE) { + if ((b5 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART3, b5 + 4); // Increment ID + //If we have another byte, do the next state (this MCU can send 2 bytes fast) + if (r5 != w5) { + b5 = UART5_DMA_Pool[r5++]; + drv_uart_putc_fast(USART3, b5); + s5 = STATE_GOT_MSB; + } + else + s5 = STATE_GOT_HEADER; + } + } else if (s5 == STATE_GOT_HEADER) { + drv_uart_putc_fast(USART3, b5); + //If we have another byte, do the next state (this MCU can send 2 bytes fast) + if (r5 != w5) { + b5 = UART5_DMA_Pool[r5++]; + drv_uart_putc_fast(USART3, b5); + s5 = STATE_IDLE; + } + else + s5 = STATE_GOT_MSB; + } else { // STATE_GOT_MSB + drv_uart_putc_fast(USART3, b5); + //If we have another byte, do the next state (this MCU can send 2 bytes fast) + if (r5 != w5) { + b5 = UART5_DMA_Pool[r5++]; + if ((b5 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART3, b5 + 4); // Increment ID + s5 = STATE_GOT_HEADER; + } + else + s5 = STATE_IDLE; + } + else + s5 = STATE_IDLE; + } + } - // Check one last time to see if new bytes arrived during the parsing loops - dma_ptr4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - dma_ptr5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + // 4. Check if we caught up to our cached write pointers. + // If so, re-sample the DMA registers to see if new data arrived + // while we were actively processing the previous bytes. + if ((r4 == w4) && (r5 == w5)) { + w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + } + } - } while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); + // 5. Store the local CPU register states back to global memory before exiting + tracker4.read_index = r4; + tracker5.read_index = r5; + tracker4.state = s4; + tracker5.state = s5; } -void process_routing_old(void) { - // Get the current write head for both DMA channels - uint32_t dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); - uint32_t dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - - // Loop as long as EITHER buffer has unread data - do { - while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)) { - if (tracker4.read_index != dma_ptr4) { - process_single_byte(UART4_DMA_Pool, &tracker4, USART2, count4); - } - - if (tracker5.read_index != dma_ptr5) { - process_single_byte(UART5_DMA_Pool, &tracker5, USART3, count5); - } - } - - // Check one last time before returning to see if bytes arrived while parsing - dma_ptr4 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx); - dma_ptr5 = AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx); - } while ((tracker4.read_index != dma_ptr4) || (tracker5.read_index != dma_ptr5)); +void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { + if (uart_id == 2) { + for (int i = 0; i < len; i++) { + uart2_dma_queue[u2_q_head] = data[i]; + u2_q_head = (u2_q_head + 1) % AMDS_RX_BUF_SIZE; + } + } else if (uart_id == 3) { + for (int i = 0; i < len; i++) { + uart3_dma_queue[u3_q_head] = data[i]; + u3_q_head = (u3_q_head + 1) % AMDS_RX_BUF_SIZE; + } + } } void UART4_IRQHandler(void) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 73bce47d..7a07ae8b 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -24,6 +24,10 @@ int main(void) drv_uart_init(); drv_led_init(); + // Tell the UART to constantly route TX requests to the DMA controller +// huart2.Instance->CR3 |= USART_CR3_DMAT; +// huart3.Instance->CR3 |= USART_CR3_DMAT; + // Initialize the main modules adc_init(); @@ -41,21 +45,22 @@ int main(void) // SysTick->CTRL &= 0xFFFFFFFE; while (1) { - // Interleave the parsing and routing for both lines simultaneously - process_routing_old(); - // 3. Handle LEDs - if (HAL_GetTick() - ledDelta >= 250) { - ledDelta = HAL_GetTick(); - drv_led_clear(); - drv_led_on(1 << led); - drv_led_display(); + // Handle DMA data from UARTs and route to correct destination + try_process_routing(); // This try function is thread safe - if (++led >= DRV_LED_NUM_TOTAL) { - led = 0; - } - } -} + // Handle LEDs + if (HAL_GetTick() - ledDelta >= 250) { + ledDelta = HAL_GetTick(); + drv_led_clear(); + drv_led_on(1 << led); + drv_led_display(); + + if (++led >= DRV_LED_NUM_TOTAL) { + led = 0; + } + } + } } void HAL_MspInit(void) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index f5ef2e9e..793c71fa 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -8,20 +8,20 @@ volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR void process_transmissions(void) { // Loop as long as there is data in EITHER queue -// while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { -// -// // If UART2 has data, pop one byte and push it straight to the hardware -// if (u2_q_tail != u2_q_head) { -// drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); -// u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; -// } -// -// // If UART3 has data, pop one byte and push it straight to the hardware -// if (u3_q_tail != u3_q_head) { -// drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); -// u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; -// } -// } + while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { + + // If UART2 has data, pop one byte and push it straight to the hardware + if (u2_q_tail != u2_q_head) { + drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); + u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; + } + + // If UART3 has data, pop one byte and push it straight to the hardware + if (u3_q_tail != u3_q_head) { + drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); + u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; + } + } } From 5760dbaa620177c28d846498e5f664d61a30ee93 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Mon, 20 Apr 2026 10:11:46 -0500 Subject: [PATCH 22/72] swap toggle and reset lines --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 7122460a..cdf46f52 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -154,9 +154,9 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) void EXTI3_IRQHandler(void) { // alert daisy chained AMDSs to begin converting + //reset DMA routing state machine to ensure robust operation in case bytes were dropped + try_reset_routing_state(); GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); // Perform the actual SPI transactions uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); From 85684284d4fe0bb1aad6b6083e1b204417a78294 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Mon, 20 Apr 2026 14:05:17 -0500 Subject: [PATCH 23/72] Optimize process_routing --- .../motherboard_v1/Core/Src/drv_uart.c | 165 ++++++++++-------- 1 file changed, 92 insertions(+), 73 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 98e637a3..96509799 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -41,119 +41,138 @@ volatile bool is_routing_active = false; void process_routing(void) { - // 1. Load tracking state into local CPU registers for zero-wait-state access + // 1. Load tracking state into local CPU registers uint8_t r4 = tracker4.read_index; uint8_t r5 = tracker5.read_index; uint8_t s4 = tracker4.state; uint8_t s5 = tracker5.state; - // 2. Read DMA hardware pointers ONCE at the start. - // NDTR counts down, so the write head is (SIZE - NDTR). - // Casting to uint8_t naturally handles the modulo wrap-around at 256. + // 2. Read DMA hardware pointers ONCE uint8_t w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); uint8_t w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); - // 3. Process instantly as long as either buffer has data. No NOP delays! while ((r4 != w4) || (r5 != w5)) { - // --- Process ONE byte from UART4 --- + // Calculate exactly how many bytes are sitting unread in the DMA buffer. + // Because everything is cast to uint8_t, this math safely handles + // circular buffer wrap-around natively (e.g. w4=2, r4=254 -> avail=4) + uint8_t avail4 = (uint8_t)(w4 - r4); + uint8_t avail5 = (uint8_t)(w5 - r5); + + // ===================================================================== + // OPTIMIZATION 1: DUAL-STREAM FAST PATH (Perfect Interleaving) + // ===================================================================== + // If BOTH streams have at least a full 3-byte packet, process them completely + // interleaved to keep both hardware lines saturated simultaneously. + if ((s4 == STATE_IDLE && avail4 >= 3) && (s5 == STATE_IDLE && avail5 >= 3)) { + uint8_t h4 = UART4_DMA_Pool[r4]; + uint8_t h5 = UART5_DMA_Pool[r5]; + + if (((h4 & 0xF0) == 0x90) && ((h5 & 0xF0) == 0x90)) { + // Byte 1: Headers (Incremented) + drv_uart_putc_fast(USART2, h4 + 4); + drv_uart_putc_fast(USART3, h5 + 4); + + // Byte 2: MSB + drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 1)]); + drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 1)]); + + // Byte 3: LSB + drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 2)]); + drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 2)]); + + r4 += 3; + r5 += 3; + + if ((r4 == w4) && (r5 == w5)) { + w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + } + continue; // Skip the rest of the loop and keep fast-pathing! + } + } + + // ===================================================================== + // OPTIMIZATION 2: SINGLE-STREAM FAST PATHS + // ===================================================================== + // If one UART receives data slightly faster than the other, process it. + if (s4 == STATE_IDLE && avail4 >= 3) { + uint8_t h4 = UART4_DMA_Pool[r4]; + if ((h4 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART2, h4 + 4); + drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 1)]); + drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 2)]); + r4 += 3; + + if ((r4 == w4) && (r5 == w5)) { + w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + } + continue; + } + } + + if (s5 == STATE_IDLE && avail5 >= 3) { + uint8_t h5 = UART5_DMA_Pool[r5]; + if ((h5 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART3, h5 + 4); + drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 1)]); + drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 2)]); + r5 += 3; + + if ((r4 == w4) && (r5 == w5)) { + w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); + w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + } + continue; + } + } + + // ===================================================================== + // SLOW PATH: Fragmentation / State Recovery + // ===================================================================== + // We only fall down here if a packet is fragmented across a DMA update + // boundary or if data is corrupted. We can safely revert to the simple + // 1-byte-at-a-time logic. if (r4 != w4) { uint8_t b4 = UART4_DMA_Pool[r4++]; - if (s4 == STATE_IDLE) { if ((b4 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART2, b4 + 4); // Increment ID - //If we have another byte, do the next state (this MCU can send 2 bytes fast) - if (r4 != w4) { - b4 = UART4_DMA_Pool[r4++]; - drv_uart_putc_fast(USART2, b4); - s4 = STATE_GOT_MSB; - } - else - s4 = STATE_GOT_HEADER; + drv_uart_putc_fast(USART2, b4 + 4); + s4 = STATE_GOT_HEADER; } } else if (s4 == STATE_GOT_HEADER) { drv_uart_putc_fast(USART2, b4); - //If we have another byte, do the next state (this MCU can send 2 bytes fast) - if (r4 != w4) { - b4 = UART4_DMA_Pool[r4++]; - drv_uart_putc_fast(USART2, b4); - s4 = STATE_IDLE; - } - else - s4 = STATE_GOT_MSB; + s4 = STATE_GOT_MSB; } else { // STATE_GOT_MSB drv_uart_putc_fast(USART2, b4); - //If we have another byte, do the next state (this MCU can send 2 bytes fast) - if (r4 != w4) { - b4 = UART4_DMA_Pool[r4++]; - if ((b4 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART2, b4 + 4); // Increment ID - s4 = STATE_GOT_HEADER; - } - else - s4 = STATE_IDLE; - } - else - s4 = STATE_IDLE; + s4 = STATE_IDLE; } } - // --- Process ONE byte from UART5 --- - // By interleaving this right after USART2, we give USART2 hardware - // time to shift bits onto the wire, preventing the 3rd byte from blocking! if (r5 != w5) { uint8_t b5 = UART5_DMA_Pool[r5++]; - if (s5 == STATE_IDLE) { if ((b5 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART3, b5 + 4); // Increment ID - //If we have another byte, do the next state (this MCU can send 2 bytes fast) - if (r5 != w5) { - b5 = UART5_DMA_Pool[r5++]; - drv_uart_putc_fast(USART3, b5); - s5 = STATE_GOT_MSB; - } - else - s5 = STATE_GOT_HEADER; + drv_uart_putc_fast(USART3, b5 + 4); + s5 = STATE_GOT_HEADER; } } else if (s5 == STATE_GOT_HEADER) { drv_uart_putc_fast(USART3, b5); - //If we have another byte, do the next state (this MCU can send 2 bytes fast) - if (r5 != w5) { - b5 = UART5_DMA_Pool[r5++]; - drv_uart_putc_fast(USART3, b5); - s5 = STATE_IDLE; - } - else - s5 = STATE_GOT_MSB; + s5 = STATE_GOT_MSB; } else { // STATE_GOT_MSB drv_uart_putc_fast(USART3, b5); - //If we have another byte, do the next state (this MCU can send 2 bytes fast) - if (r5 != w5) { - b5 = UART5_DMA_Pool[r5++]; - if ((b5 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART3, b5 + 4); // Increment ID - s5 = STATE_GOT_HEADER; - } - else - s5 = STATE_IDLE; - } - else - s5 = STATE_IDLE; + s5 = STATE_IDLE; } } - // 4. Check if we caught up to our cached write pointers. - // If so, re-sample the DMA registers to see if new data arrived - // while we were actively processing the previous bytes. if ((r4 == w4) && (r5 == w5)) { w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); } } - // 5. Store the local CPU register states back to global memory before exiting + // 5. Store states back tracker4.read_index = r4; tracker5.read_index = r5; tracker4.state = s4; From 07e7e4412e6d1cf0f93e8b0111895be8f7507b5a Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Mon, 20 Apr 2026 14:08:00 -0500 Subject: [PATCH 24/72] Restore helpful comments --- Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 96509799..b1afe6c7 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -41,16 +41,19 @@ volatile bool is_routing_active = false; void process_routing(void) { - // 1. Load tracking state into local CPU registers + // 1. Load tracking state into local CPU registers for zero-wait-state access uint8_t r4 = tracker4.read_index; uint8_t r5 = tracker5.read_index; uint8_t s4 = tracker4.state; uint8_t s5 = tracker5.state; - // 2. Read DMA hardware pointers ONCE + // 2. Read DMA hardware pointers ONCE at the start. + // NDTR counts down, so the write head is (SIZE - NDTR). + // Casting to uint8_t naturally handles the modulo wrap-around at 256. uint8_t w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); uint8_t w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + // Process instantly as long as either buffer has data. No NOP delays! while ((r4 != w4) || (r5 != w5)) { // Calculate exactly how many bytes are sitting unread in the DMA buffer. From c73b9aa7d18b0289b3b3dc1ce37c7aa695c489c1 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Mon, 20 Apr 2026 15:45:00 -0500 Subject: [PATCH 25/72] Refactor UART dual-stream and single-stream processing Refactor UART processing to use while loops for better handling of available data. Removed redundant checks and updated available byte counters. --- .../motherboard_v1/Core/Src/drv_uart.c | 39 +++++++++---------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index b1afe6c7..b4521dea 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -67,7 +67,7 @@ void process_routing(void) { // ===================================================================== // If BOTH streams have at least a full 3-byte packet, process them completely // interleaved to keep both hardware lines saturated simultaneously. - if ((s4 == STATE_IDLE && avail4 >= 3) && (s5 == STATE_IDLE && avail5 >= 3)) { + while ((s4 == STATE_IDLE && avail4 >= 3) && (s5 == STATE_IDLE && avail5 >= 3)) { uint8_t h4 = UART4_DMA_Pool[r4]; uint8_t h5 = UART5_DMA_Pool[r5]; @@ -86,12 +86,10 @@ void process_routing(void) { r4 += 3; r5 += 3; - - if ((r4 == w4) && (r5 == w5)) { - w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); - } - continue; // Skip the rest of the loop and keep fast-pathing! + avail4 -= 3; + avail5 -= 3; + } else { + break; // Misaligned or corrupted header, break to let the slow-path handle it } } @@ -99,35 +97,31 @@ void process_routing(void) { // OPTIMIZATION 2: SINGLE-STREAM FAST PATHS // ===================================================================== // If one UART receives data slightly faster than the other, process it. - if (s4 == STATE_IDLE && avail4 >= 3) { + while (s4 == STATE_IDLE && avail4 >= 3) { uint8_t h4 = UART4_DMA_Pool[r4]; if ((h4 & 0xF0) == 0x90) { drv_uart_putc_fast(USART2, h4 + 4); drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 1)]); drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 2)]); - r4 += 3; - if ((r4 == w4) && (r5 == w5)) { - w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); - } - continue; + r4 += 3; + avail4 -= 3; + } else { + break; } } - if (s5 == STATE_IDLE && avail5 >= 3) { + while (s5 == STATE_IDLE && avail5 >= 3) { uint8_t h5 = UART5_DMA_Pool[r5]; if ((h5 & 0xF0) == 0x90) { drv_uart_putc_fast(USART3, h5 + 4); drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 1)]); drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 2)]); - r5 += 3; - if ((r4 == w4) && (r5 == w5)) { - w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); - } - continue; + r5 += 3; + avail5 -= 3; + } else { + break; } } @@ -169,6 +163,9 @@ void process_routing(void) { } } + // Check if we caught up to our cached write pointers. + // If so, re-sample the DMA registers to see if new data arrived + // while we were actively processing the previous bytes. if ((r4 == w4) && (r5 == w5)) { w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); From 0a76fb45cb5c4faf95877e5f05ccb109de6c252f Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 21 Apr 2026 11:04:56 -0500 Subject: [PATCH 26/72] add initial changes to syncing fbc and amds firmware --- Mainboard/Firmware/motherboard_v1/.cproject | 37 +++-- .../Firmware/motherboard_v1/Core/Src/adc.c | 24 +++ .../motherboard_v1/Core/Src/drv_uart.c | 145 +++++++++++++++++- 3 files changed, 190 insertions(+), 16 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/.cproject b/Mainboard/Firmware/motherboard_v1/.cproject index ac257487..9d322226 100644 --- a/Mainboard/Firmware/motherboard_v1/.cproject +++ b/Mainboard/Firmware/motherboard_v1/.cproject @@ -10,6 +10,7 @@ + @@ -18,9 +19,9 @@ - - - + + + + + + + + + \ No newline at end of file diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index cff541ad..fe92ebbc 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -250,10 +250,19 @@ static void setup_pin_SYNC_ADC(void) __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOD_CLK_ENABLE(); + + __HAL_RCC_GPIOB_CLK_ENABLE(); + __HAL_RCC_GPIOG_CLK_ENABLE(); + B11 + G14 + // Configure GPIO pin Output Level HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOD, GPIO_PIN_1, GPIO_PIN_SET); + HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); + // Configure GPIO pins GPIO_InitStruct.Pin = GPIO_PIN_3; @@ -268,7 +277,22 @@ static void setup_pin_SYNC_ADC(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); + GPIO_InitStruct.Pin = GPIO_PIN_11; + GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); + + GPIO_InitStruct.Pin = GPIO_PIN_14; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + // EXTI interrupt init HAL_NVIC_SetPriority(EXTI3_IRQn, 10, 0); HAL_NVIC_EnableIRQ(EXTI3_IRQn); + + HAL_NVIC_SetPriority(EXTI15_10_IRQn, 10, 0); + HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 7f107630..6ec66ca5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -41,6 +41,19 @@ uart_rx_tracker_t tracker5 = {0}; uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; +// FBC Daisy Chain RX Peripherals +static UART_HandleTypeDef huart1; +static UART_HandleTypeDef huart6; + +static DMA_HandleTypeDef hdma_uart1_rx; +static DMA_HandleTypeDef hdma_uart6_rx; + +uart_rx_tracker_t tracker1 = {0}; +uart_rx_tracker_t tracker6 = {0}; + +uint8_t UART1_DMA_Pool[AMDS_RX_BUF_SIZE]; +uint8_t UART6_DMA_Pool[AMDS_RX_BUF_SIZE]; + void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id) { // Calculate current DMA write position (NDTR counts down) UART_HandleTypeDef *huart; @@ -228,11 +241,17 @@ void drv_uart_init(void) __HAL_RCC_UART4_CONFIG(RCC_UART4CLKSOURCE_SYSCLK); __HAL_RCC_UART5_CONFIG(RCC_UART5CLKSOURCE_SYSCLK); + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); + __HAL_RCC_USART6_CONFIG(RCC_USART6CLKSOURCE_SYSCLK); + MX_USART_UART_Init(&huart2, USART2); MX_USART_UART_Init(&huart3, USART3); MX_USART_UART_Init(&huart4, UART4); MX_USART_UART_Init(&huart5, UART5); + + MX_USART_UART_Init(&huart1, USART1); + MX_USART_UART_Init(&huart6, USART6); } static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) @@ -258,9 +277,9 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) huart->Init.StopBits = UART_STOPBITS_2; huart->Init.Parity = UART_PARITY_ODD; - if (huart->Instance == UART4) { + if (huart->Instance == UART4 || huart->Instance == USART6) { huart->Init.Mode = UART_MODE_RX; - } else if (huart->Instance == UART5) { + } else if (huart->Instance == UART5 || huart->Instance == USART1) { huart->Init.Mode = UART_MODE_RX; } else { huart->Init.Mode = UART_MODE_TX; @@ -296,6 +315,26 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) if (HAL_UART_Receive_DMA(&huart5, UART5_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } + } else if (huart->Instance == USART6) { + NVIC_SetPriority(USART6_IRQn, 9); + HAL_NVIC_EnableIRQ(USART6_IRQn); + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + + if (HAL_UART_Receive_DMA(&huart6, UART6_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + PANIC; + } + } else if (huart->Instance == USART1) { + NVIC_SetPriority(USART1_IRQn, 9); + HAL_NVIC_EnableIRQ(USART1_IRQn); + + __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); + __HAL_UART_FLUSH_DRREGISTER(huart); + + if (HAL_UART_Receive_DMA(&huart1, UART1_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + PANIC; + } } else if (huart->Instance == USART2) { NVIC_SetPriority(USART2_IRQn, 10); HAL_NVIC_EnableIRQ(USART2_IRQn); @@ -474,6 +513,86 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) NVIC_SetPriority(DMA1_Stream0_IRQn, 6); // higher priority than UART HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); } + + else if (uartHandle->Instance == USART6) { + // USART6 clock enable + __HAL_RCC_USART6_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + + __HAL_RCC_GPIOG_CLK_ENABLE(); + // USART3 GPIO Configuration + // PG9 ------> UART4_RX + GPIO_InitStruct.Pin = GPIO_PIN_9; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF8_USART6; + HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + + // DMA config - check your device's DMA request mapping table + // for the correct stream/channel for USART6_RX pg 253 of reference manual + hdma_uart6_rx.Instance = DMA2_Stream2; // verify in reference manual + hdma_uart6_rx.Init.Channel = DMA_CHANNEL_5; // verify in reference manual + hdma_uart6_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_uart6_rx.Init.PeriphInc = DMA_PINC_DISABLE; // RDR address stays fixed + hdma_uart6_rx.Init.MemInc = DMA_MINC_ENABLE; // buffer pointer increments + hdma_uart6_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_uart6_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_uart6_rx.Init.Mode = DMA_CIRCULAR; // or DMA_CIRCULAR (see note below) + hdma_uart6_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_uart6_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + if (HAL_DMA_Init(&hdma_uart6_rx) != HAL_OK) { + PANIC; + } + + // This links the DMA handle to the UART handle + __HAL_LINKDMA(uartHandle, hdmarx, hdma_uart6_rx); + + // DMA stream IRQ + NVIC_SetPriority(DMA2_Stream2_IRQn, 6); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA2_Stream2_IRQn); + } + + else if (uartHandle->Instance == USART1) { + // USART1 clock enable + __HAL_RCC_USART1_CLK_ENABLE(); + __HAL_RCC_DMA2_CLK_ENABLE(); + + __HAL_RCC_GPIOA_CLK_ENABLE(); + // USART1 GPIO Configuration + // PA10 ------> USART1_RX + GPIO_InitStruct.Pin = GPIO_PIN_10; + GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF7_USART1; + HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); + + // DMA config - check your device's DMA request mapping table + // for the correct stream/channel for USART1_RX pg 253 of reference manual + hdma_uart1_rx.Instance = DMA2_Stream5; // verify in reference manual + hdma_uart1_rx.Init.Channel = DMA_CHANNEL_4; // verify in reference manual + hdma_uart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_uart1_rx.Init.PeriphInc = DMA_PINC_DISABLE; // RDR address stays fixed + hdma_uart1_rx.Init.MemInc = DMA_MINC_ENABLE; // buffer pointer increments + hdma_uart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_uart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_uart1_rx.Init.Mode = DMA_CIRCULAR; // or DMA_CIRCULAR (see note below) + hdma_uart1_rx.Init.Priority = DMA_PRIORITY_HIGH; + hdma_uart1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + + if (HAL_DMA_Init(&hdma_uart1_rx) != HAL_OK) { + PANIC; + } + + // This links the DMA handle to the UART handle + __HAL_LINKDMA(uartHandle, hdmarx, hdma_uart1_rx); + + // DMA stream IRQ + NVIC_SetPriority(DMA2_Stream5_IRQn, 6); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn); + } } void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) @@ -521,4 +640,26 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) */ HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2); } + + else if (uartHandle->Instance == USART6) { + /* Peripheral clock disable */ + __HAL_RCC_USART6_CLK_DISABLE(); + + /**USART3 GPIO Configuration + PG9 ------> USART6_RX + PG10 ------> USART6_TX + */ + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_9 | GPIO_PIN_10); + } + + else if (uartHandle->Instance == USART1) { + /* Peripheral clock disable */ + __HAL_RCC_USART1_CLK_DISABLE(); + + /**USART3 GPIO Configuration + PA9 ------> UART5_TX + PA10 ------> UART5_RX + */ + HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10); + } } From 6ad38e8dc8ff9f66560e26e8f76345cffbd7e412 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Tue, 21 Apr 2026 11:12:01 -0500 Subject: [PATCH 27/72] Update header file for benchmark code --- .../Firmware/motherboard_v1/Core/Inc/drv_uart.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index b1a92755..672aef81 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -50,6 +50,17 @@ extern volatile uint16_t u2_q_tail; extern volatile uint16_t u3_q_head; extern volatile uint16_t u3_q_tail; +// ========================================================================= +// BENCHMARK MODE FLAG for DMA +// Comment out this line to return to real hardware DMA operation! +// ========================================================================= +#define BENCHMARK_MODE +// ========================================================================= + +#ifdef BENCHMARK_MODE +extern volatile uint8_t mock_dma_write_head; +#endif + // Declare the global flag so all .c files know it exists extern volatile bool is_routing_active; @@ -105,8 +116,13 @@ static inline void try_reset_routing_state(void) { // 2. Soft-flush the DMA buffers. // We advance our read pointers to exactly where the DMA hardware // is currently writing. All old, unprocessed bytes are instantly discarded. +#ifdef BENCHMARK_MODE + tracker4.read_index = mock_dma_write_head; + tracker5.read_index = mock_dma_write_head; +#else tracker4.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); tracker5.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); +#endif } } From 646a62aaa630e002f04744afa8894d6e3c893a33 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Tue, 21 Apr 2026 11:17:50 -0500 Subject: [PATCH 28/72] Add benchmarking code to the two adc and uart driver --- .../Firmware/motherboard_v1/Core/Src/adc.c | 21 +++++++++++++++++++ .../motherboard_v1/Core/Src/drv_uart.c | 16 ++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 7122460a..e9da5f3b 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -157,6 +157,27 @@ void EXTI3_IRQHandler(void) GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); //reset DMA routing state machine to ensure robust operation in case bytes were dropped try_reset_routing_state(); + +#ifdef BENCHMARK_MODE + // ========================================================================= + // INJECT MOCK DMA DATA FOR BENCHMARKING + // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. + // ========================================================================= + uint8_t current_head = mock_dma_write_head; + for (int i = 0; i < 24; i++) { + uint8_t idx = (uint8_t)(current_head + i); + if (i % 3 == 0) { + UART4_DMA_Pool[idx] = 0x90; // Valid Header + UART5_DMA_Pool[idx] = 0x90; + } else { + UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data + UART5_DMA_Pool[idx] = 0xBB; + } + } + // Instantly advance the mock hardware write head + mock_dma_write_head = (uint8_t)(current_head + 24); +#endif + // Perform the actual SPI transactions uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index b4521dea..f9a66422 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -39,6 +39,18 @@ volatile uint16_t u3_q_tail = 0; // Must be volatile so the compiler knows it can change inside an IRQ. volatile bool is_routing_active = false; +#ifdef BENCHMARK_MODE + volatile uint8_t mock_dma_write_head = 0; + #define GET_W4() mock_dma_write_head + #define GET_W5() mock_dma_write_head +#else + // NDTR counts down, so the write head is (SIZE - NDTR). + // Casting to uint8_t naturally handles the modulo wrap-around at 256. + // AMDS_RX_BUF_SIZE MUST BE 256 FOR THIS MATH TO WORK PROPERLY! + #define GET_W4() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)) + #define GET_W5() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)) +#endif + void process_routing(void) { // 1. Load tracking state into local CPU registers for zero-wait-state access @@ -167,8 +179,8 @@ void process_routing(void) { // If so, re-sample the DMA registers to see if new data arrived // while we were actively processing the previous bytes. if ((r4 == w4) && (r5 == w5)) { - w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + w4 = GET_W4(); + w5 = GET_W5(); } } From f66c75b3485be2f9597894e61e453f443aa83e60 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 21 Apr 2026 11:49:32 -0500 Subject: [PATCH 29/72] add faster initial transmit --- .../Firmware/motherboard_v1/Core/Src/adc.c | 53 ++++++++++++------- .../motherboard_v1/Core/Src/drv_uart.c | 4 +- 2 files changed, 36 insertions(+), 21 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index e9da5f3b..0b51da36 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -185,30 +185,45 @@ void EXTI3_IRQHandler(void) // Conditionally Transmit for (int i = 0; i < 4; i++) { uint8_t header = 0x90 | i; - bool u3 = false; - bool u2 = false; - // Check Channel 0-3 (UART2) - if (active_sensor_mask & (1 << i)) { + // If both channels in current iteration are enabled. We can do a much faster transmission + if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { + // Send header drv_uart_putc_fast(USART2, header); - u2 = true; - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - } - - // Check Channel 4-7 (UART3) - if (active_sensor_mask & (1 << (i + 4))) { drv_uart_putc_fast(USART3, header); - u3 = true; - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - } - if (u2) { - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); - } + // Send MSB + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - // Check Channel 4-7 (UART3) - if (u3) { - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + // Send LSB + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); + } else { // otherwise check each channel individually + bool u3 = false; + bool u2 = false; + // Check Channel 0-3 (UART2) + if (active_sensor_mask & (1 << i)) { + drv_uart_putc_fast(USART2, header); + u2 = true; + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + } + + // Check Channel 4-7 (UART3) + if (active_sensor_mask & (1 << (i + 4))) { + drv_uart_putc_fast(USART3, header); + u3 = true; + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + } + + if (u2) { + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + } + + // Check Channel 4-7 (UART3) + if (u3) { + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + } } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index f9a66422..e9f7e895 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -62,8 +62,8 @@ void process_routing(void) { // 2. Read DMA hardware pointers ONCE at the start. // NDTR counts down, so the write head is (SIZE - NDTR). // Casting to uint8_t naturally handles the modulo wrap-around at 256. - uint8_t w4 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - uint8_t w5 = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + uint8_t w4 = GET_W4(); + uint8_t w5 = GET_W5(); // Process instantly as long as either buffer has data. No NOP delays! while ((r4 != w4) || (r5 != w5)) { From afcbc5f919448060620415194301cf380760b0e6 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Tue, 21 Apr 2026 11:55:52 -0500 Subject: [PATCH 30/72] Optimize the send data in the ext irq function --- .../Firmware/motherboard_v1/Core/Src/adc.c | 115 +++++++++++------- 1 file changed, 71 insertions(+), 44 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 0b51da36..25913a9c 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -182,50 +182,77 @@ void EXTI3_IRQHandler(void) uint16_t new_data[8] = { 0 }; adc_sample_all_daughtercards(new_data); - // Conditionally Transmit - for (int i = 0; i < 4; i++) { - uint8_t header = 0x90 | i; - - // If both channels in current iteration are enabled. We can do a much faster transmission - if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { - // Send header - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); - - // Send MSB - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - - // Send LSB - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); - } else { // otherwise check each channel individually - bool u3 = false; - bool u2 = false; - // Check Channel 0-3 (UART2) - if (active_sensor_mask & (1 << i)) { - drv_uart_putc_fast(USART2, header); - u2 = true; - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - } - - // Check Channel 4-7 (UART3) - if (active_sensor_mask & (1 << (i + 4))) { - drv_uart_putc_fast(USART3, header); - u3 = true; - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - } - - if (u2) { - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); - } - - // Check Channel 4-7 (UART3) - if (u3) { - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); - } - } - } + // Send the data we sampled out as fast as possible + // + // ========================================================================= + // OPTIMIZATION: Zero-Branch Fast Path for Nominal Operation + // ========================================================================= + if (active_sensor_mask == 0xFF) { + // Channel 0 & 4 + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x90); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[0] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[4] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)new_data[0]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[4]); + + // Channel 1 & 5 + drv_uart_putc_fast(USART2, 0x91); + drv_uart_putc_fast(USART3, 0x91); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[1] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[5] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)new_data[1]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[5]); + + // Channel 2 & 6 + drv_uart_putc_fast(USART2, 0x92); + drv_uart_putc_fast(USART3, 0x92); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[2] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[6] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)new_data[2]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[6]); + + // Channel 3 & 7 + drv_uart_putc_fast(USART2, 0x93); + drv_uart_putc_fast(USART3, 0x93); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[3] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[7] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)new_data[3]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[7]); + } + // ========================================================================= + // SLOW PATH: Loop for Partial Masks + // ========================================================================= + else { + for (int i = 0; i < 4; i++) { + uint8_t header = 0x90 | i; + + if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART3, header); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); + } else { + bool u3 = false; + bool u2 = false; + + if (active_sensor_mask & (1 << i)) { + drv_uart_putc_fast(USART2, header); + u2 = true; + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + } + if (active_sensor_mask & (1 << (i + 4))) { + drv_uart_putc_fast(USART3, header); + u3 = true; + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + } + if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + } + } + } //Handle any DMA data that has been received from daisy chain try_process_routing(); // This try function is thread safe From 9745611fd4801e7ca1a01358640086e6368cfa37 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Tue, 21 Apr 2026 12:00:52 -0500 Subject: [PATCH 31/72] Go back to using loops for IRQ handler --- .../Firmware/motherboard_v1/Core/Src/adc.c | 54 ++++++------------- 1 file changed, 17 insertions(+), 37 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 25913a9c..9d2e4180 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -185,46 +185,26 @@ void EXTI3_IRQHandler(void) // Send the data we sampled out as fast as possible // // ========================================================================= - // OPTIMIZATION: Zero-Branch Fast Path for Nominal Operation + // OPTIMIZATION: "Tight Loop" Fast Path + // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching // ========================================================================= if (active_sensor_mask == 0xFF) { - // Channel 0 & 4 - drv_uart_putc_fast(USART2, 0x90); - drv_uart_putc_fast(USART3, 0x90); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[0] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[4] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)new_data[0]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[4]); - - // Channel 1 & 5 - drv_uart_putc_fast(USART2, 0x91); - drv_uart_putc_fast(USART3, 0x91); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[1] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[5] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)new_data[1]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[5]); - - // Channel 2 & 6 - drv_uart_putc_fast(USART2, 0x92); - drv_uart_putc_fast(USART3, 0x92); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[2] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[6] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)new_data[2]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[6]); - - // Channel 3 & 7 - drv_uart_putc_fast(USART2, 0x93); - drv_uart_putc_fast(USART3, 0x93); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[3] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[7] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)new_data[3]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[7]); + for (uint32_t i = 0; i < 4; i++) { + drv_uart_putc_fast(USART2, 0x90 | i); + drv_uart_putc_fast(USART3, 0x90 | i); + + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); + } } // ========================================================================= - // SLOW PATH: Loop for Partial Masks + // SLOW PATH: Safe loop for Partial Masks // ========================================================================= - else { - for (int i = 0; i < 4; i++) { + else { + for (uint32_t i = 0; i < 4; i++) { uint8_t header = 0x90 | i; if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { @@ -248,8 +228,8 @@ void EXTI3_IRQHandler(void) u3 = true; drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); } - if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); - if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); + if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); } } } From 8deab07fc5e7c4cd0f98fdc0046f51b5d7dcb7dd Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 21 Apr 2026 13:48:58 -0500 Subject: [PATCH 32/72] remove benchmark flag --- Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 672aef81..366ddb3c 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -54,7 +54,7 @@ extern volatile uint16_t u3_q_tail; // BENCHMARK MODE FLAG for DMA // Comment out this line to return to real hardware DMA operation! // ========================================================================= -#define BENCHMARK_MODE +//#define BENCHMARK_MODE // ========================================================================= #ifdef BENCHMARK_MODE From 399b6a7dfba0296812177acfe4c2dc78c2f13bc9 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 21 Apr 2026 15:24:48 -0500 Subject: [PATCH 33/72] add the rest of uart6 and 1 implementation --- .../motherboard_v1/Core/Inc/drv_uart.h | 17 ++ .../Firmware/motherboard_v1/Core/Src/adc.c | 153 +++++++++++++++++- .../motherboard_v1/Core/Src/drv_uart.c | 119 +++++++++++++- 3 files changed, 278 insertions(+), 11 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 366ddb3c..74b0eef0 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -13,12 +13,18 @@ extern UART_HandleTypeDef huart3; extern UART_HandleTypeDef huart4; extern UART_HandleTypeDef huart5; +extern UART_HandleTypeDef huart6; +extern UART_HandleTypeDef huart1; + extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_usart3_tx; extern DMA_HandleTypeDef hdma_uart4_rx; extern DMA_HandleTypeDef hdma_uart5_rx; +extern DMA_HandleTypeDef hdma_uart6_rx; +extern DMA_HandleTypeDef hdma_uart1_rx; + typedef enum { STATE_IDLE, STATE_GOT_HEADER, @@ -35,9 +41,14 @@ typedef struct { extern uart_rx_tracker_t tracker4; extern uart_rx_tracker_t tracker5; +extern uart_rx_tracker_t tracker6; +extern uart_rx_tracker_t tracker1; + #define AMDS_RX_BUF_SIZE 256 // Must be 256 for uint8_t indexing and wrap-around logic to work correctly extern uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; +extern uint8_t UART6_DMA_Pool[AMDS_RX_BUF_SIZE]; +extern uint8_t UART1_DMA_Pool[AMDS_RX_BUF_SIZE]; extern volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; extern volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; @@ -112,6 +123,8 @@ static inline void try_reset_routing_state(void) { // 1. Reset state machines to gracefully await the next packet tracker4.state = STATE_IDLE; tracker5.state = STATE_IDLE; + tracker6.state = STATE_IDLE; + tracker1.state = STATE_IDLE; // 2. Soft-flush the DMA buffers. // We advance our read pointers to exactly where the DMA hardware @@ -119,9 +132,13 @@ static inline void try_reset_routing_state(void) { #ifdef BENCHMARK_MODE tracker4.read_index = mock_dma_write_head; tracker5.read_index = mock_dma_write_head; + tracker6.read_index = mock_dma_write_head; + tracker1.read_index = mock_dma_write_head; #else tracker4.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); tracker5.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); + tracker6.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart6.hdmarx)); + tracker1.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx)); #endif } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 3a504b30..0342659a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -48,7 +48,7 @@ static volatile uint16_t latest_valid_adc_data[8] = { 0 }; // Global bitmask: 1 = Active, 0 = Inactive. // For example: 0b00010001 (0x0F) means channels 1-4 are active, 5-8 are disabled. -volatile uint8_t active_sensor_mask = 0xFF; +volatile uint8_t active_sensor_mask = 0x11; void adc_init(void) { @@ -148,14 +148,59 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) drv_spi_get_DR(SPI6, &sample_data_out[6]); } +static void adc_sample_1_5_daughtercards(uint16_t *sample_data_out) +{ + // This function has been optimized for very + // fast operation of SPI5 interface + // to cards 1 and 5. + // + // It directly manipulates the SPI peripherals' + // registers to read in data from the ADCs. The ordering + // of operations may look strange, but this is to minimize + // wait time of the various APB interconnects in the MCU. + // + // The ADC devices support a max of 400ksps. Looking at + // the waveforms from this function, the CONVST line is + // asserted for effectively 280kHz... It could be faster, + // but its not terrible... + + // Start all ADC conversions. + // ADC conversion triggered by CONVST56 connects to SPI5 + SET_PIN_CONVST56_HIGH; + + // Wait for ADC conversion to complete (per datasheet, >= 1300ns + // Each NOP takes 5ns, unrolled so branches don't affect timing... + // + // We need 260 NOPs + NOP256; + NOP4; + + // Smartly read all data from ADC. + // This starts the SPI peripheral,then waits for it to + // complete and gets the resulting data. + + // Start the SCLKs + drv_spi_start_read_two_16bits(SPI5); + + // Wait and read first ADC data + drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); + + // Wait for second ADC data to complete + drv_spi_wait_for_RX(SPI5); + + // End conversion + SET_PIN_CONVST56_LOW; + + // Read second ADC data + drv_spi_get_DR(SPI5, &sample_data_out[4]); +} + // This ISR is triggered by the AMDC to sync the ADC // conversions to the AMDC PWM carrier waveform. In // this ISR, all the motherboard ADCs should be sampled. void EXTI3_IRQHandler(void) { // alert daisy chained AMDSs to begin converting - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); //reset DMA routing state machine to ensure robust operation in case bytes were dropped try_reset_routing_state(); @@ -201,7 +246,16 @@ void EXTI3_IRQHandler(void) drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); } - } + } else if (active_sensor_mask == 0x11) { + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x94); + + drv_uart_putc_fast(USART2, (uint8_t)(new_data[0] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)new_data[0]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[4]); + } // ========================================================================= // SLOW PATH: Safe loop for Partial Masks // ========================================================================= @@ -249,6 +303,95 @@ void EXTI3_IRQHandler(void) NVIC_ClearPendingIRQ(EXTI3_IRQn); } +// This ISR is for the FBC and is triggered by the +// AMDC to sync the ADCconversions to the AMDC PWM +// carrier waveform. In this ISR, on 2 ADCs should be sampled. +//void EXTI15_10_IRQHandler(void) +void EXTI15_10_IRQHandler(void) +{ + // alert daisy chained AMDSs to begin converting + GPIO_TOGGLE_PIN(GPIOG, GPIO_PIN_14); + //reset DMA routing state machine to ensure robust operation in case bytes were dropped + try_reset_routing_state(); + +#ifdef BENCHMARK_MODE + // ========================================================================= + // INJECT MOCK DMA DATA FOR BENCHMARKING + // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. + // ========================================================================= + uint8_t current_head = mock_dma_write_head; + for (int i = 0; i < 6; i++) { + uint8_t idx = (uint8_t)(current_head + i); + if (i == 0) { + UART4_DMA_Pool[idx] = 0x90; // Valid Header + UART5_DMA_Pool[idx] = 0x90; + } else if (i == 3) { + UART4_DMA_Pool[idx] = 0x94; // Valid Header + UART5_DMA_Pool[idx] = 0x94; + } else { + UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data + UART5_DMA_Pool[idx] = 0xBB; + } + } + // Instantly advance the mock hardware write head + mock_dma_write_head = (uint8_t)(current_head + 6); +#endif + + // Perform the actual SPI transactions + uint16_t new_data[8] = { 0 }; + adc_sample_1_5_daughtercards(new_data); + + // Send the data we sampled out as fast as possible + // + // ========================================================================= + // OPTIMIZATION: "Tight Loop" Fast Path + // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching + // ========================================================================= + if (active_sensor_mask == 0x11) { + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x94); + + drv_uart_putc_fast(USART2, (uint8_t)(new_data[0] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)new_data[0]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[4]); + } + // ========================================================================= + // SLOW PATH: Safe loop for Partial Masks + // ========================================================================= + else { + bool u3 = false; + bool u2 = false; + uint8_t header = 0x90; + + if (active_sensor_mask & (1 << 0)) { + drv_uart_putc_fast(USART2, header); + u2 = true; + drv_uart_putc_fast(USART2, (uint8_t)(new_data[0] >> 8)); + } + if (active_sensor_mask & (1 << 4)) { + drv_uart_putc_fast(USART3, header); + u3 = true; + drv_uart_putc_fast(USART3, (uint8_t)(new_data[4] >> 8)); + } + if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[0])); + if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[4])); + } + + //Handle any DMA data that has been received from daisy chain + try_process_routing(); // This try function is thread safe + + // Clear all pending IRQs for ADC conversions at the + // end of this ISR so that the system realigns the + // ADC conversions with the SYNC signal from the AMDC. + // + // For some reason, this only works if we call both of these: + NVIC_ClearPendingIRQ(EXTI15_10_IRQn); + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_11); + NVIC_ClearPendingIRQ(EXTI15_10_IRQn); +} + static void setup_pin_CONVST(void) { GPIO_InitTypeDef GPIO_InitStruct = { 0 }; @@ -292,8 +435,6 @@ static void setup_pin_SYNC_ADC(void) __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); - B11 - G14 // Configure GPIO pin Output Level HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index ae10d0a9..aa3f6f29 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -27,11 +27,11 @@ uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; // FBC Daisy Chain RX Peripherals -static UART_HandleTypeDef huart6; -static UART_HandleTypeDef huart1; +UART_HandleTypeDef huart6; +UART_HandleTypeDef huart1; -static DMA_HandleTypeDef hdma_uart6_rx; -static DMA_HandleTypeDef hdma_uart1_rx; +DMA_HandleTypeDef hdma_uart6_rx; +DMA_HandleTypeDef hdma_uart1_rx; uart_rx_tracker_t tracker6 = {0}; uart_rx_tracker_t tracker1 = {0}; @@ -47,12 +47,16 @@ volatile bool is_routing_active = false; volatile uint8_t mock_dma_write_head = 0; #define GET_W4() mock_dma_write_head #define GET_W5() mock_dma_write_head + #define GET_W6() mock_dma_write_head + #define GET_W1() mock_dma_write_head #else // NDTR counts down, so the write head is (SIZE - NDTR). // Casting to uint8_t naturally handles the modulo wrap-around at 256. // AMDS_RX_BUF_SIZE MUST BE 256 FOR THIS MATH TO WORK PROPERLY! #define GET_W4() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)) #define GET_W5() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)) + #define GET_W6() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart6.hdmarx)) + #define GET_W1() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx)) #endif @@ -63,20 +67,29 @@ void process_routing(void) { uint8_t s4 = tracker4.state; uint8_t s5 = tracker5.state; + uint8_t r6 = tracker6.read_index; + uint8_t r1 = tracker1.read_index; + uint8_t s6 = tracker6.state; + uint8_t s1 = tracker1.state; + // 2. Read DMA hardware pointers ONCE at the start. // NDTR counts down, so the write head is (SIZE - NDTR). // Casting to uint8_t naturally handles the modulo wrap-around at 256. uint8_t w4 = GET_W4(); uint8_t w5 = GET_W5(); + uint8_t w6 = GET_W6(); + uint8_t w1 = GET_W1(); // Process instantly as long as either buffer has data. No NOP delays! - while ((r4 != w4) || (r5 != w5)) { + while ((r4 != w4) || (r5 != w5) || (r6 != w6) || (r1 != w1)) { // Calculate exactly how many bytes are sitting unread in the DMA buffer. // Because everything is cast to uint8_t, this math safely handles // circular buffer wrap-around natively (e.g. w4=2, r4=254 -> avail=4) uint8_t avail4 = (uint8_t)(w4 - r4); uint8_t avail5 = (uint8_t)(w5 - r5); + uint8_t avail6 = (uint8_t)(w6 - r6); + uint8_t avail1 = (uint8_t)(w1 - r1); // ===================================================================== // OPTIMIZATION 1: DUAL-STREAM FAST PATH (Perfect Interleaving) @@ -109,6 +122,32 @@ void process_routing(void) { } } + while ((s6 == STATE_IDLE && avail6 >= 3) && (s1 == STATE_IDLE && avail1 >= 3)) { + uint8_t h6 = UART6_DMA_Pool[r6]; + uint8_t h1 = UART1_DMA_Pool[r1]; + + if (((h6 & 0xF0) == 0x90) && ((h1 & 0xF0) == 0x90)) { + // Byte 1: Headers (Incremented) + drv_uart_putc_fast(USART6, h6 + 4); + drv_uart_putc_fast(USART1, h1 + 4); + + // Byte 2: MSB + drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); + drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); + + // Byte 3: LSB + drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); + drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); + + r6 += 3; + r1 += 3; + avail6 -= 3; + avail1 -= 3; + } else { + break; // Misaligned or corrupted header, break to let the slow-path handle it + } + } + // ===================================================================== // OPTIMIZATION 2: SINGLE-STREAM FAST PATHS // ===================================================================== @@ -141,6 +180,34 @@ void process_routing(void) { } } + while (s6 == STATE_IDLE && avail6 >= 3) { + uint8_t h6 = UART6_DMA_Pool[r6]; + if ((h6 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART6, h6 + 4); + drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); + drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); + + r6 += 3; + avail6 -= 3; + } else { + break; + } + } + + while (s1 == STATE_IDLE && avail1 >= 3) { + uint8_t h1 = UART1_DMA_Pool[r1]; + if ((h1 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART1, h1 + 4); + drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); + drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); + + r1 += 3; + avail1 -= 3; + } else { + break; + } + } + // ===================================================================== // SLOW PATH: Fragmentation / State Recovery // ===================================================================== @@ -179,6 +246,38 @@ void process_routing(void) { } } + if (r6 != w6) { + uint8_t b6 = UART6_DMA_Pool[r6++]; + if (s6 == STATE_IDLE) { + if ((b6 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART6, b6 + 4); + s6 = STATE_GOT_HEADER; + } + } else if (s6 == STATE_GOT_HEADER) { + drv_uart_putc_fast(USART6, b6); + s6 = STATE_GOT_MSB; + } else { // STATE_GOT_MSB + drv_uart_putc_fast(USART6, b6); + s6 = STATE_IDLE; + } + } + + if (r1 != w1) { + uint8_t b1 = UART1_DMA_Pool[r1++]; + if (s1 == STATE_IDLE) { + if ((b1 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART1, b1 + 4); + s1 = STATE_GOT_HEADER; + } + } else if (s1 == STATE_GOT_HEADER) { + drv_uart_putc_fast(USART1, b1); + s1 = STATE_GOT_MSB; + } else { // STATE_GOT_MSB + drv_uart_putc_fast(USART1, b1); + s1 = STATE_IDLE; + } + } + // Check if we caught up to our cached write pointers. // If so, re-sample the DMA registers to see if new data arrived // while we were actively processing the previous bytes. @@ -186,6 +285,11 @@ void process_routing(void) { w4 = GET_W4(); w5 = GET_W5(); } + + if ((r6 == w6) && (r1 == w1)) { + w6 = GET_W6(); + w1 = GET_W1(); + } } // 5. Store states back @@ -193,6 +297,11 @@ void process_routing(void) { tracker5.read_index = r5; tracker4.state = s4; tracker5.state = s5; + + tracker6.read_index = r6; + tracker1.read_index = r1; + tracker6.state = s6; + tracker1.state = s1; } From ea7813e2fe0f725124c16dfd4ad02566cf808d62 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 21 Apr 2026 17:37:53 -0500 Subject: [PATCH 34/72] fix daisy chain transmit function --- .../motherboard_v1/Core/Src/drv_uart.c | 94 +++++++++++++++---- 1 file changed, 74 insertions(+), 20 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index aa3f6f29..9a6fcf06 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -128,16 +128,16 @@ void process_routing(void) { if (((h6 & 0xF0) == 0x90) && ((h1 & 0xF0) == 0x90)) { // Byte 1: Headers (Incremented) - drv_uart_putc_fast(USART6, h6 + 4); - drv_uart_putc_fast(USART1, h1 + 4); + drv_uart_putc_fast(USART2, h6 + 4); + drv_uart_putc_fast(USART3, h1 + 4); // Byte 2: MSB - drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); - drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); + drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); + drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); // Byte 3: LSB - drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); - drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); + drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); + drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); r6 += 3; r1 += 3; @@ -183,9 +183,9 @@ void process_routing(void) { while (s6 == STATE_IDLE && avail6 >= 3) { uint8_t h6 = UART6_DMA_Pool[r6]; if ((h6 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART6, h6 + 4); - drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); - drv_uart_putc_fast(USART6, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); + drv_uart_putc_fast(USART2, h6 + 4); + drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); + drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); r6 += 3; avail6 -= 3; @@ -197,9 +197,9 @@ void process_routing(void) { while (s1 == STATE_IDLE && avail1 >= 3) { uint8_t h1 = UART1_DMA_Pool[r1]; if ((h1 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART1, h1 + 4); - drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); - drv_uart_putc_fast(USART1, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); + drv_uart_putc_fast(USART3, h1 + 4); + drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); + drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); r1 += 3; avail1 -= 3; @@ -250,14 +250,14 @@ void process_routing(void) { uint8_t b6 = UART6_DMA_Pool[r6++]; if (s6 == STATE_IDLE) { if ((b6 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART6, b6 + 4); + drv_uart_putc_fast(USART2, b6 + 4); s6 = STATE_GOT_HEADER; } } else if (s6 == STATE_GOT_HEADER) { - drv_uart_putc_fast(USART6, b6); + drv_uart_putc_fast(USART2, b6); s6 = STATE_GOT_MSB; } else { // STATE_GOT_MSB - drv_uart_putc_fast(USART6, b6); + drv_uart_putc_fast(USART2, b6); s6 = STATE_IDLE; } } @@ -266,14 +266,14 @@ void process_routing(void) { uint8_t b1 = UART1_DMA_Pool[r1++]; if (s1 == STATE_IDLE) { if ((b1 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART1, b1 + 4); + drv_uart_putc_fast(USART3, b1 + 4); s1 = STATE_GOT_HEADER; } } else if (s1 == STATE_GOT_HEADER) { - drv_uart_putc_fast(USART1, b1); + drv_uart_putc_fast(USART3, b1); s1 = STATE_GOT_MSB; } else { // STATE_GOT_MSB - drv_uart_putc_fast(USART1, b1); + drv_uart_putc_fast(USART3, b1); s1 = STATE_IDLE; } } @@ -376,6 +376,60 @@ void DMA1_Stream6_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_usart2_tx); } +void USART6_IRQHandler(void) +{ + // Check for Parity, Overrun, Noise, or Frame errors + if (__HAL_UART_GET_FLAG(&huart6, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&huart6, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&huart6, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&huart6, UART_FLAG_FE)) + { + // 1. Clear the error flags (Added UART_CLEAR_PEF) + __HAL_UART_CLEAR_IT(&huart6, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + + // 2. IMPORTANT: Re-enable DMA receiver request + // The hardware/HAL drops this bit on error, halting the DMA stream. + SET_BIT(huart6.Instance->CR3, USART_CR3_DMAR); + + return; + } + + // Process normal RX/TX interrupts via the HAL + HAL_UART_IRQHandler(&huart6); +} + +void DMA2_Stream2_IRQHandler(void) +{ + HAL_DMA_IRQHandler(&hdma_uart6_rx); +} + +void USART1_IRQHandler(void) +{ + // Check for Overrun, Noise, or Frame errors + if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&huart1, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&huart1, UART_FLAG_FE)) + { + // 1. Clear the error flags + __HAL_UART_CLEAR_IT(&huart1, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + + // 2. IMPORTANT: Re-enable DMA receiver request + // Sometimes HAL disables this bit (DMAR) on error. + SET_BIT(huart1.Instance->CR3, USART_CR3_DMAR); + + return; + } + HAL_UART_IRQHandler(&huart1); +} + +void DMA2_Stream5_IRQHandler(void) +{ + HAL_DMA_IRQHandler(&hdma_uart1_rx); +} + + + void USART2_IRQHandler(void) { HAL_UART_IRQHandler(&huart2); } @@ -812,9 +866,9 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) /**USART3 GPIO Configuration PG9 ------> USART6_RX - PG10 ------> USART6_TX + PG14 ------> USART6_TX */ - HAL_GPIO_DeInit(GPIOG, GPIO_PIN_9 | GPIO_PIN_10); + HAL_GPIO_DeInit(GPIOG, GPIO_PIN_9 | GPIO_PIN_14); } else if (uartHandle->Instance == USART1) { From c7a1640c2376d1766e46de9daea9652c1bb3209b Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Wed, 22 Apr 2026 20:33:25 -0500 Subject: [PATCH 35/72] Make main only use process_routing when data is available --- Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h | 3 +++ Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c | 9 +++++++++ Mainboard/Firmware/motherboard_v1/Core/Src/main.c | 8 ++++++-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 366ddb3c..d314c9be 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -67,6 +67,9 @@ extern volatile bool is_routing_active; void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); +// Add this prototype +bool drv_uart_has_dma_data(void); + void process_routing(void); /** diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index e9f7e895..f9b33359 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -51,6 +51,15 @@ volatile bool is_routing_active = false; #define GET_W5() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)) #endif +bool drv_uart_has_dma_data(void) { + // Perform an unprotected, non-atomic peek at the DMA hardware. + // Reading these 8-bit values is natively atomic, so it is safe to + // evaluate them even if an interrupt is modifying them in the background. + uint8_t w4 = GET_W4(); + uint8_t w5 = GET_W5(); + + return (tracker4.read_index != w4) || (tracker5.read_index != w5); +} void process_routing(void) { // 1. Load tracking state into local CPU registers for zero-wait-state access diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 7a07ae8b..9a49b818 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -46,8 +46,12 @@ int main(void) while (1) { - // Handle DMA data from UARTs and route to correct destination - try_process_routing(); // This try function is thread safe + // Handle DMA data from UARTs and route to correct destination. + // Only attempt to grab the lock and route data if there + // is actually data waiting in the DMA buffers to help the + // external IRQ retain higher priority access to process_routing + if (drv_uart_has_dma_data()) + try_process_routing(); // This try function is thread safe // Handle LEDs if (HAL_GetTick() - ledDelta >= 250) { From 8cf05d5241d124a63045f46d54f798fcb867bdef Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Thu, 23 Apr 2026 17:24:51 -0500 Subject: [PATCH 36/72] add conditionals and custom build config --- Mainboard/Firmware/motherboard_v1/.cproject | 196 +++++++- .../motherboard_v1/Core/Inc/drv_uart.h | 47 +- .../Firmware/motherboard_v1/Core/Src/adc.c | 10 +- .../motherboard_v1/Core/Src/drv_uart.c | 419 +++++++----------- .../Firmware/motherboard_v1/Core/Src/tx.c | 28 +- 5 files changed, 372 insertions(+), 328 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/.cproject b/Mainboard/Firmware/motherboard_v1/.cproject index 9d322226..8df5768d 100644 --- a/Mainboard/Firmware/motherboard_v1/.cproject +++ b/Mainboard/Firmware/motherboard_v1/.cproject @@ -30,6 +30,7 @@ @@ -160,21 +161,180 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - @@ -183,4 +343,22 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 74b0eef0..f53b453d 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -10,11 +10,8 @@ void drv_uart_init(void); extern UART_HandleTypeDef huart2; extern UART_HandleTypeDef huart3; -extern UART_HandleTypeDef huart4; -extern UART_HandleTypeDef huart5; - -extern UART_HandleTypeDef huart6; -extern UART_HandleTypeDef huart1; +extern UART_HandleTypeDef DAISY_RX1_UART; +extern UART_HandleTypeDef DAISY_RX2_UART; extern DMA_HandleTypeDef hdma_usart2_tx; extern DMA_HandleTypeDef hdma_usart3_tx; @@ -38,28 +35,12 @@ typedef struct { uint8_t read_index; } uart_rx_tracker_t; -extern uart_rx_tracker_t tracker4; -extern uart_rx_tracker_t tracker5; - -extern uart_rx_tracker_t tracker6; extern uart_rx_tracker_t tracker1; +extern uart_rx_tracker_t tracker2; #define AMDS_RX_BUF_SIZE 256 // Must be 256 for uint8_t indexing and wrap-around logic to work correctly -extern uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; -extern uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; -extern uint8_t UART6_DMA_Pool[AMDS_RX_BUF_SIZE]; -extern uint8_t UART1_DMA_Pool[AMDS_RX_BUF_SIZE]; - -extern volatile uint8_t uart2_dma_queue[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart3_dma_queue[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart2_dma_buffer[AMDS_RX_BUF_SIZE]; -extern volatile uint8_t uart3_dma_buffer[AMDS_RX_BUF_SIZE]; - -// Queue tracking indices -extern volatile uint16_t u2_q_head; -extern volatile uint16_t u2_q_tail; -extern volatile uint16_t u3_q_head; -extern volatile uint16_t u3_q_tail; +extern uint8_t DAISY_RX1_Pool[AMDS_RX_BUF_SIZE]; +extern uint8_t DAISY_RX2_Pool[AMDS_RX_BUF_SIZE]; // ========================================================================= // BENCHMARK MODE FLAG for DMA @@ -121,24 +102,18 @@ static inline void try_reset_routing_state(void) { if (!is_routing_active) { // 1. Reset state machines to gracefully await the next packet - tracker4.state = STATE_IDLE; - tracker5.state = STATE_IDLE; - tracker6.state = STATE_IDLE; - tracker1.state = STATE_IDLE; + tracker1.state = STATE_IDLE; + tracker2.state = STATE_IDLE; // 2. Soft-flush the DMA buffers. // We advance our read pointers to exactly where the DMA hardware // is currently writing. All old, unprocessed bytes are instantly discarded. #ifdef BENCHMARK_MODE - tracker4.read_index = mock_dma_write_head; - tracker5.read_index = mock_dma_write_head; - tracker6.read_index = mock_dma_write_head; - tracker1.read_index = mock_dma_write_head; + tracker1.read_index = mock_dma_write_head; + tracker2.read_index = mock_dma_write_head; #else - tracker4.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)); - tracker5.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)); - tracker6.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart6.hdmarx)); - tracker1.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx)); + tracker1.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(DAISY_RX1_UART.hdmarx)); + tracker2.read_index = (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(DAISY_RX2_UART.hdmarx)); #endif } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 0342659a..e746b362 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -48,7 +48,15 @@ static volatile uint16_t latest_valid_adc_data[8] = { 0 }; // Global bitmask: 1 = Active, 0 = Inactive. // For example: 0b00010001 (0x0F) means channels 1-4 are active, 5-8 are disabled. -volatile uint8_t active_sensor_mask = 0x11; +//#if defined(TARGET_AMDS) +// volatile uint8_t active_sensor_mask = 0xFF; +//#elif defined(TARGET_2S) +// volatile uint8_t active_sensor_mask = 0x11; +//#else +// #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +//#endif + +volatile uint8_t active_sensor_mask = 0xFF; void adc_init(void) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 9a6fcf06..f6e99114 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -13,31 +13,20 @@ UART_HandleTypeDef huart3; DMA_HandleTypeDef hdma_usart2_tx; DMA_HandleTypeDef hdma_usart3_tx; -// AMDS Daisy Chain RX Peripherals -UART_HandleTypeDef huart4; -UART_HandleTypeDef huart5; - DMA_HandleTypeDef hdma_uart4_rx; DMA_HandleTypeDef hdma_uart5_rx; -uart_rx_tracker_t tracker4 = {0}; -uart_rx_tracker_t tracker5 = {0}; - -uint8_t UART4_DMA_Pool[AMDS_RX_BUF_SIZE]; -uint8_t UART5_DMA_Pool[AMDS_RX_BUF_SIZE]; - -// FBC Daisy Chain RX Peripherals -UART_HandleTypeDef huart6; -UART_HandleTypeDef huart1; - DMA_HandleTypeDef hdma_uart6_rx; DMA_HandleTypeDef hdma_uart1_rx; -uart_rx_tracker_t tracker6 = {0}; -uart_rx_tracker_t tracker1 = {0}; +// Daisy Chain RX Peripherals +UART_HandleTypeDef DAISY_RX1_UART; +UART_HandleTypeDef DAISY_RX2_UART; -uint8_t UART6_DMA_Pool[AMDS_RX_BUF_SIZE]; -uint8_t UART1_DMA_Pool[AMDS_RX_BUF_SIZE]; +uart_rx_tracker_t tracker1; +uart_rx_tracker_t tracker2; +uint8_t DAISY_RX1_Pool[AMDS_RX_BUF_SIZE]; +uint8_t DAISY_RX2_Pool[AMDS_RX_BUF_SIZE]; // Global flag to track if routing is actively occurring. // Must be volatile so the compiler knows it can change inside an IRQ. @@ -45,300 +34,173 @@ volatile bool is_routing_active = false; #ifdef BENCHMARK_MODE volatile uint8_t mock_dma_write_head = 0; - #define GET_W4() mock_dma_write_head - #define GET_W5() mock_dma_write_head - #define GET_W6() mock_dma_write_head #define GET_W1() mock_dma_write_head + #define GET_W2() mock_dma_write_head #else // NDTR counts down, so the write head is (SIZE - NDTR). // Casting to uint8_t naturally handles the modulo wrap-around at 256. // AMDS_RX_BUF_SIZE MUST BE 256 FOR THIS MATH TO WORK PROPERLY! - #define GET_W4() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart4.hdmarx)) - #define GET_W5() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart5.hdmarx)) - #define GET_W6() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart6.hdmarx)) - #define GET_W1() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(huart1.hdmarx)) + #define GET_W1() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(DAISY_RX1_UART.hdmarx)) + #define GET_W2() (uint8_t)(AMDS_RX_BUF_SIZE - __HAL_DMA_GET_COUNTER(DAISY_RX2_UART.hdmarx)) #endif void process_routing(void) { // 1. Load tracking state into local CPU registers for zero-wait-state access - uint8_t r4 = tracker4.read_index; - uint8_t r5 = tracker5.read_index; - uint8_t s4 = tracker4.state; - uint8_t s5 = tracker5.state; - - uint8_t r6 = tracker6.read_index; uint8_t r1 = tracker1.read_index; - uint8_t s6 = tracker6.state; - uint8_t s1 = tracker1.state; + uint8_t r2 = tracker2.read_index; + uint8_t s1 = tracker1.state; + uint8_t s2 = tracker2.state; - // 2. Read DMA hardware pointers ONCE at the start. - // NDTR counts down, so the write head is (SIZE - NDTR). - // Casting to uint8_t naturally handles the modulo wrap-around at 256. - uint8_t w4 = GET_W4(); - uint8_t w5 = GET_W5(); - uint8_t w6 = GET_W6(); uint8_t w1 = GET_W1(); + uint8_t w2 = GET_W2(); // Process instantly as long as either buffer has data. No NOP delays! - while ((r4 != w4) || (r5 != w5) || (r6 != w6) || (r1 != w1)) { - + while ((r1 != w1) || (r2 != w2)) { // Calculate exactly how many bytes are sitting unread in the DMA buffer. // Because everything is cast to uint8_t, this math safely handles // circular buffer wrap-around natively (e.g. w4=2, r4=254 -> avail=4) - uint8_t avail4 = (uint8_t)(w4 - r4); - uint8_t avail5 = (uint8_t)(w5 - r5); - uint8_t avail6 = (uint8_t)(w6 - r6); uint8_t avail1 = (uint8_t)(w1 - r1); + uint8_t avail2 = (uint8_t)(w2 - r2); // ===================================================================== // OPTIMIZATION 1: DUAL-STREAM FAST PATH (Perfect Interleaving) // ===================================================================== // If BOTH streams have at least a full 3-byte packet, process them completely // interleaved to keep both hardware lines saturated simultaneously. - while ((s4 == STATE_IDLE && avail4 >= 3) && (s5 == STATE_IDLE && avail5 >= 3)) { - uint8_t h4 = UART4_DMA_Pool[r4]; - uint8_t h5 = UART5_DMA_Pool[r5]; + while ((s1 == STATE_IDLE && avail1 >= 3) && (s2 == STATE_IDLE && avail2 >= 3)) { + uint8_t h1 = DAISY_RX1_Pool[r1]; + uint8_t h2 = DAISY_RX2_Pool[r2]; - if (((h4 & 0xF0) == 0x90) && ((h5 & 0xF0) == 0x90)) { + if (((h1 & 0xF0) == 0x90) && ((h2 & 0xF0) == 0x90)) { // Byte 1: Headers (Incremented) - drv_uart_putc_fast(USART2, h4 + 4); - drv_uart_putc_fast(USART3, h5 + 4); + drv_uart_putc_fast(USART2, h1 + 4); + drv_uart_putc_fast(USART3, h2 + 4); // Byte 2: MSB - drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 1)]); - drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 1)]); + drv_uart_putc_fast(USART2, DAISY_RX1_Pool[(uint8_t)(r1 + 1)]); + drv_uart_putc_fast(USART3, DAISY_RX2_Pool[(uint8_t)(r2 + 1)]); // Byte 3: LSB - drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 2)]); - drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 2)]); + drv_uart_putc_fast(USART2, DAISY_RX1_Pool[(uint8_t)(r1 + 2)]); + drv_uart_putc_fast(USART3, DAISY_RX2_Pool[(uint8_t)(r2 + 2)]); - r4 += 3; - r5 += 3; - avail4 -= 3; - avail5 -= 3; + r1 += 3; + r2 += 3; + avail1 -= 3; + avail2 -= 3; } else { break; // Misaligned or corrupted header, break to let the slow-path handle it } } - while ((s6 == STATE_IDLE && avail6 >= 3) && (s1 == STATE_IDLE && avail1 >= 3)) { - uint8_t h6 = UART6_DMA_Pool[r6]; - uint8_t h1 = UART1_DMA_Pool[r1]; - - if (((h6 & 0xF0) == 0x90) && ((h1 & 0xF0) == 0x90)) { - // Byte 1: Headers (Incremented) - drv_uart_putc_fast(USART2, h6 + 4); - drv_uart_putc_fast(USART3, h1 + 4); - - // Byte 2: MSB - drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); - drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); - - // Byte 3: LSB - drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); - drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); - - r6 += 3; - r1 += 3; - avail6 -= 3; - avail1 -= 3; - } else { - break; // Misaligned or corrupted header, break to let the slow-path handle it - } - } - // ===================================================================== // OPTIMIZATION 2: SINGLE-STREAM FAST PATHS // ===================================================================== // If one UART receives data slightly faster than the other, process it. - while (s4 == STATE_IDLE && avail4 >= 3) { - uint8_t h4 = UART4_DMA_Pool[r4]; - if ((h4 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART2, h4 + 4); - drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 1)]); - drv_uart_putc_fast(USART2, UART4_DMA_Pool[(uint8_t)(r4 + 2)]); + while (s1 == STATE_IDLE && avail1 >= 3) { + uint8_t h1 = DAISY_RX1_Pool[r1]; + if ((h1 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART2, h1 + 4); + drv_uart_putc_fast(USART2, DAISY_RX1_Pool[(uint8_t)(r1 + 1)]); + drv_uart_putc_fast(USART2, DAISY_RX1_Pool[(uint8_t)(r1 + 2)]); - r4 += 3; - avail4 -= 3; + r1 += 3; + avail1 -= 3; } else { break; } } - while (s5 == STATE_IDLE && avail5 >= 3) { - uint8_t h5 = UART5_DMA_Pool[r5]; - if ((h5 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART3, h5 + 4); - drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 1)]); - drv_uart_putc_fast(USART3, UART5_DMA_Pool[(uint8_t)(r5 + 2)]); + while (s2 == STATE_IDLE && avail2 >= 3) { + uint8_t h2 = DAISY_RX2_Pool[r2]; + if ((h2 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART3, h2 + 4); + drv_uart_putc_fast(USART3, DAISY_RX2_Pool[(uint8_t)(r2 + 1)]); + drv_uart_putc_fast(USART3, DAISY_RX2_Pool[(uint8_t)(r2 + 2)]); - r5 += 3; - avail5 -= 3; + r2 += 3; + avail2 -= 3; } else { break; } } - while (s6 == STATE_IDLE && avail6 >= 3) { - uint8_t h6 = UART6_DMA_Pool[r6]; - if ((h6 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART2, h6 + 4); - drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 1)]); - drv_uart_putc_fast(USART2, UART6_DMA_Pool[(uint8_t)(r6 + 2)]); - - r6 += 3; - avail6 -= 3; - } else { - break; - } - } - - while (s1 == STATE_IDLE && avail1 >= 3) { - uint8_t h1 = UART1_DMA_Pool[r1]; - if ((h1 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART3, h1 + 4); - drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 1)]); - drv_uart_putc_fast(USART3, UART1_DMA_Pool[(uint8_t)(r1 + 2)]); - - r1 += 3; - avail1 -= 3; - } else { - break; - } - } - // ===================================================================== // SLOW PATH: Fragmentation / State Recovery // ===================================================================== // We only fall down here if a packet is fragmented across a DMA update // boundary or if data is corrupted. We can safely revert to the simple // 1-byte-at-a-time logic. - if (r4 != w4) { - uint8_t b4 = UART4_DMA_Pool[r4++]; - if (s4 == STATE_IDLE) { - if ((b4 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART2, b4 + 4); - s4 = STATE_GOT_HEADER; + if (r1 != w1) { + uint8_t b1 = DAISY_RX1_Pool[r1++]; + if (s1 == STATE_IDLE) { + if ((b1 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART2, b1 + 4); + s1 = STATE_GOT_HEADER; } - } else if (s4 == STATE_GOT_HEADER) { - drv_uart_putc_fast(USART2, b4); - s4 = STATE_GOT_MSB; + } else if (s1 == STATE_GOT_HEADER) { + drv_uart_putc_fast(USART2, b1); + s1 = STATE_GOT_MSB; } else { // STATE_GOT_MSB - drv_uart_putc_fast(USART2, b4); - s4 = STATE_IDLE; + drv_uart_putc_fast(USART2, b1); + s1 = STATE_IDLE; } } - if (r5 != w5) { - uint8_t b5 = UART5_DMA_Pool[r5++]; - if (s5 == STATE_IDLE) { - if ((b5 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART3, b5 + 4); - s5 = STATE_GOT_HEADER; + if (r2 != w2) { + uint8_t b2 = DAISY_RX2_Pool[r2++]; + if (s2 == STATE_IDLE) { + if ((b2 & 0xF0) == 0x90) { + drv_uart_putc_fast(USART3, b2 + 4); + s2 = STATE_GOT_HEADER; } - } else if (s5 == STATE_GOT_HEADER) { - drv_uart_putc_fast(USART3, b5); - s5 = STATE_GOT_MSB; + } else if (s2 == STATE_GOT_HEADER) { + drv_uart_putc_fast(USART3, b2); + s2 = STATE_GOT_MSB; } else { // STATE_GOT_MSB - drv_uart_putc_fast(USART3, b5); - s5 = STATE_IDLE; + drv_uart_putc_fast(USART3, b2); + s2 = STATE_IDLE; } } - if (r6 != w6) { - uint8_t b6 = UART6_DMA_Pool[r6++]; - if (s6 == STATE_IDLE) { - if ((b6 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART2, b6 + 4); - s6 = STATE_GOT_HEADER; - } - } else if (s6 == STATE_GOT_HEADER) { - drv_uart_putc_fast(USART2, b6); - s6 = STATE_GOT_MSB; - } else { // STATE_GOT_MSB - drv_uart_putc_fast(USART2, b6); - s6 = STATE_IDLE; - } - } - - if (r1 != w1) { - uint8_t b1 = UART1_DMA_Pool[r1++]; - if (s1 == STATE_IDLE) { - if ((b1 & 0xF0) == 0x90) { - drv_uart_putc_fast(USART3, b1 + 4); - s1 = STATE_GOT_HEADER; - } - } else if (s1 == STATE_GOT_HEADER) { - drv_uart_putc_fast(USART3, b1); - s1 = STATE_GOT_MSB; - } else { // STATE_GOT_MSB - drv_uart_putc_fast(USART3, b1); - s1 = STATE_IDLE; - } - } - // Check if we caught up to our cached write pointers. // If so, re-sample the DMA registers to see if new data arrived // while we were actively processing the previous bytes. - if ((r4 == w4) && (r5 == w5)) { - w4 = GET_W4(); - w5 = GET_W5(); + if ((r1 == w1) && (r2 == w2)) { + w1 = GET_W1(); + w2 = GET_W2(); } - - if ((r6 == w6) && (r1 == w1)) { - w6 = GET_W6(); - w1 = GET_W1(); - } } // 5. Store states back - tracker4.read_index = r4; - tracker5.read_index = r5; - tracker4.state = s4; - tracker5.state = s5; - - tracker6.read_index = r6; - tracker1.read_index = r1; - tracker6.state = s6; - tracker1.state = s1; -} - - -void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len) { - if (uart_id == 2) { - for (int i = 0; i < len; i++) { - uart2_dma_queue[u2_q_head] = data[i]; - u2_q_head = (u2_q_head + 1) % AMDS_RX_BUF_SIZE; - } - } else if (uart_id == 3) { - for (int i = 0; i < len; i++) { - uart3_dma_queue[u3_q_head] = data[i]; - u3_q_head = (u3_q_head + 1) % AMDS_RX_BUF_SIZE; - } - } + tracker1.read_index = r1; + tracker2.read_index = r2; + tracker1.state = s1; + tracker2.state = s2; } +#if defined(TARGET_AMDS) void UART4_IRQHandler(void) { // Check for Parity, Overrun, Noise, or Frame errors - if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_PE) || - __HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) || - __HAL_UART_GET_FLAG(&huart4, UART_FLAG_NE) || - __HAL_UART_GET_FLAG(&huart4, UART_FLAG_FE)) + if (__HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_FE)) { // 1. Clear the error flags (Added UART_CLEAR_PEF) - __HAL_UART_CLEAR_IT(&huart4, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + __HAL_UART_CLEAR_IT(&DAISY_RX1_UART, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); // 2. IMPORTANT: Re-enable DMA receiver request // The hardware/HAL drops this bit on error, halting the DMA stream. - SET_BIT(huart4.Instance->CR3, USART_CR3_DMAR); + SET_BIT(DAISY_RX1_UART.Instance->CR3, USART_CR3_DMAR); return; } // Process normal RX/TX interrupts via the HAL - HAL_UART_IRQHandler(&huart4); + HAL_UART_IRQHandler(&DAISY_RX1_UART); } void DMA1_Stream2_IRQHandler(void) @@ -349,53 +211,48 @@ void DMA1_Stream2_IRQHandler(void) void UART5_IRQHandler(void) { // Check for Overrun, Noise, or Frame errors - if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_PE) || - __HAL_UART_GET_FLAG(&huart5, UART_FLAG_ORE) || - __HAL_UART_GET_FLAG(&huart5, UART_FLAG_NE) || - __HAL_UART_GET_FLAG(&huart5, UART_FLAG_FE)) + if (__HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_FE)) { // 1. Clear the error flags - __HAL_UART_CLEAR_IT(&huart5, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + __HAL_UART_CLEAR_IT(&DAISY_RX2_UART, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); // 2. IMPORTANT: Re-enable DMA receiver request // Sometimes HAL disables this bit (DMAR) on error. - SET_BIT(huart5.Instance->CR3, USART_CR3_DMAR); + SET_BIT(DAISY_RX2_UART.Instance->CR3, USART_CR3_DMAR); return; } - HAL_UART_IRQHandler(&huart5); + HAL_UART_IRQHandler(&DAISY_RX2_UART); } void DMA1_Stream0_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_uart5_rx); } - -// USART2 DMA and UART Interrupts -void DMA1_Stream6_IRQHandler(void) { - HAL_DMA_IRQHandler(&hdma_usart2_tx); -} - +#elif defined(TARGET_2S) void USART6_IRQHandler(void) { // Check for Parity, Overrun, Noise, or Frame errors - if (__HAL_UART_GET_FLAG(&huart6, UART_FLAG_PE) || - __HAL_UART_GET_FLAG(&huart6, UART_FLAG_ORE) || - __HAL_UART_GET_FLAG(&huart6, UART_FLAG_NE) || - __HAL_UART_GET_FLAG(&huart6, UART_FLAG_FE)) + if (__HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&DAISY_RX1_UART, UART_FLAG_FE)) { // 1. Clear the error flags (Added UART_CLEAR_PEF) - __HAL_UART_CLEAR_IT(&huart6, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + __HAL_UART_CLEAR_IT(&DAISY_RX1_UART, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); // 2. IMPORTANT: Re-enable DMA receiver request // The hardware/HAL drops this bit on error, halting the DMA stream. - SET_BIT(huart6.Instance->CR3, USART_CR3_DMAR); + SET_BIT(DAISY_RX1_UART.Instance->CR3, USART_CR3_DMAR); return; } // Process normal RX/TX interrupts via the HAL - HAL_UART_IRQHandler(&huart6); + HAL_UART_IRQHandler(&DAISY_RX1_UART); } void DMA2_Stream2_IRQHandler(void) @@ -406,29 +263,34 @@ void DMA2_Stream2_IRQHandler(void) void USART1_IRQHandler(void) { // Check for Overrun, Noise, or Frame errors - if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_PE) || - __HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE) || - __HAL_UART_GET_FLAG(&huart1, UART_FLAG_NE) || - __HAL_UART_GET_FLAG(&huart1, UART_FLAG_FE)) + if (__HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_PE) || + __HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_ORE) || + __HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_NE) || + __HAL_UART_GET_FLAG(&DAISY_RX2_UART, UART_FLAG_FE)) { // 1. Clear the error flags - __HAL_UART_CLEAR_IT(&huart1, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); + __HAL_UART_CLEAR_IT(&DAISY_RX2_UART, UART_CLEAR_PEF | UART_CLEAR_OREF | UART_CLEAR_NEF | UART_CLEAR_FEF); // 2. IMPORTANT: Re-enable DMA receiver request // Sometimes HAL disables this bit (DMAR) on error. - SET_BIT(huart1.Instance->CR3, USART_CR3_DMAR); + SET_BIT(DAISY_RX2_UART.Instance->CR3, USART_CR3_DMAR); return; } - HAL_UART_IRQHandler(&huart1); + HAL_UART_IRQHandler(&DAISY_RX2_UART); } void DMA2_Stream5_IRQHandler(void) { HAL_DMA_IRQHandler(&hdma_uart1_rx); } +#else + #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +#endif - +void DMA1_Stream6_IRQHandler(void) { + HAL_DMA_IRQHandler(&hdma_usart2_tx); +} void USART2_IRQHandler(void) { HAL_UART_IRQHandler(&huart2); @@ -454,21 +316,28 @@ void drv_uart_init(void) __HAL_RCC_USART2_CONFIG(RCC_USART2CLKSOURCE_SYSCLK); __HAL_RCC_USART3_CONFIG(RCC_USART3CLKSOURCE_SYSCLK); - +#if defined(TARGET_AMDS) __HAL_RCC_UART4_CONFIG(RCC_UART4CLKSOURCE_SYSCLK); __HAL_RCC_UART5_CONFIG(RCC_UART5CLKSOURCE_SYSCLK); - +#elif defined(TARGET_2S) __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); __HAL_RCC_USART6_CONFIG(RCC_USART6CLKSOURCE_SYSCLK); +#else + #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +#endif MX_USART_UART_Init(&huart2, USART2); MX_USART_UART_Init(&huart3, USART3); - MX_USART_UART_Init(&huart4, UART4); - MX_USART_UART_Init(&huart5, UART5); - - MX_USART_UART_Init(&huart1, USART1); - MX_USART_UART_Init(&huart6, USART6); +#if defined(TARGET_AMDS) + MX_USART_UART_Init(&DAISY_RX1_UART, UART4); + MX_USART_UART_Init(&DAISY_RX2_UART, UART5); +#elif defined(TARGET_2S) + MX_USART_UART_Init(&DAISY_RX1_UART, USART6); + MX_USART_UART_Init(&DAISY_RX2_UART, USART1); +#else + #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +#endif } static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) @@ -511,7 +380,7 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) PANIC; } - // Interrupt setup must come AFTER HAL_UART_Init() +#if defined(TARGET_AMDS) if (huart->Instance == UART4) { NVIC_SetPriority(UART4_IRQn, 9); HAL_NVIC_EnableIRQ(UART4_IRQn); @@ -519,27 +388,31 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_DMA(&huart4, UART4_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + if (HAL_UART_Receive_DMA(&DAISY_RX1_UART, DAISY_RX1_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } - } else if (huart->Instance == UART5) { + } + + if (huart->Instance == UART5) { NVIC_SetPriority(UART5_IRQn, 9); HAL_NVIC_EnableIRQ(UART5_IRQn); __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_DMA(&huart5, UART5_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + if (HAL_UART_Receive_DMA(&DAISY_RX2_UART, DAISY_RX2_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } - } else if (huart->Instance == USART6) { + } +#elif defined(TARGET_2S) + if (huart->Instance == USART6) { NVIC_SetPriority(USART6_IRQn, 9); HAL_NVIC_EnableIRQ(USART6_IRQn); __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_DMA(&huart6, UART6_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + if (HAL_UART_Receive_DMA(&DAISY_RX1_UART, DAISY_RX1_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } } else if (huart->Instance == USART1) { @@ -549,10 +422,14 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_OREF); __HAL_UART_FLUSH_DRREGISTER(huart); - if (HAL_UART_Receive_DMA(&huart1, UART1_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + if (HAL_UART_Receive_DMA(&DAISY_RX2_UART, DAISY_RX2_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { PANIC; } - } else if (huart->Instance == USART2) { + } +#else + #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +#endif + if (huart->Instance == USART2) { NVIC_SetPriority(USART2_IRQn, 10); HAL_NVIC_EnableIRQ(USART2_IRQn); @@ -651,7 +528,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) NVIC_SetPriority(DMA1_Stream3_IRQn, 7); // higher priority than UART HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); } - +#if defined(TARGET_AMDS) else if (uartHandle->Instance == UART4) { // USART3 clock enable __HAL_RCC_UART4_CLK_ENABLE(); @@ -732,7 +609,7 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) NVIC_SetPriority(DMA1_Stream0_IRQn, 6); // higher priority than UART HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); } - +#elif defined(TARGET_2S) else if (uartHandle->Instance == USART6) { // USART6 clock enable __HAL_RCC_USART6_CLK_ENABLE(); @@ -812,6 +689,9 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) NVIC_SetPriority(DMA2_Stream5_IRQn, 6); // higher priority than UART HAL_NVIC_EnableIRQ(DMA2_Stream5_IRQn); } +#else + #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +#endif } void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) @@ -838,7 +718,7 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) */ HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10 | GPIO_PIN_11); } - +#if defined(TARGET_AMDS) else if (uartHandle->Instance == UART4) { /* Peripheral clock disable */ __HAL_RCC_UART4_CLK_DISABLE(); @@ -859,7 +739,7 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) */ HAL_GPIO_DeInit(GPIOD, GPIO_PIN_2); } - +#elif defined(TARGET_2S) else if (uartHandle->Instance == USART6) { /* Peripheral clock disable */ __HAL_RCC_USART6_CLK_DISABLE(); @@ -881,4 +761,7 @@ void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) */ HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10); } +#else + #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" +#endif } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 793c71fa..f5ef2e9e 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -8,20 +8,20 @@ volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR void process_transmissions(void) { // Loop as long as there is data in EITHER queue - while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { - - // If UART2 has data, pop one byte and push it straight to the hardware - if (u2_q_tail != u2_q_head) { - drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); - u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; - } - - // If UART3 has data, pop one byte and push it straight to the hardware - if (u3_q_tail != u3_q_head) { - drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); - u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; - } - } +// while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { +// +// // If UART2 has data, pop one byte and push it straight to the hardware +// if (u2_q_tail != u2_q_head) { +// drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); +// u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; +// } +// +// // If UART3 has data, pop one byte and push it straight to the hardware +// if (u3_q_tail != u3_q_head) { +// drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); +// u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; +// } +// } } From 03315fb1601d94337283443de172792262023e58 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 24 Apr 2026 11:26:57 -0500 Subject: [PATCH 37/72] switch back to debug build config --- Mainboard/Firmware/motherboard_v1/.cproject | 1 + Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 16 +++++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/.cproject b/Mainboard/Firmware/motherboard_v1/.cproject index 8df5768d..fa91ea49 100644 --- a/Mainboard/Firmware/motherboard_v1/.cproject +++ b/Mainboard/Firmware/motherboard_v1/.cproject @@ -40,6 +40,7 @@ + From 8ce8032a92d67867249df212fad16619dcd7690a Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 24 Apr 2026 15:05:16 -0500 Subject: [PATCH 42/72] add interleaved transmit function and modified irq handler --- Mainboard/Firmware/motherboard_v1/.gitignore | 2 + .../Firmware/motherboard_v1/Core/Src/adc.c | 252 ++++++++++++++---- .../Firmware/motherboard_v1/Core/Src/main.c | 5 + 3 files changed, 206 insertions(+), 53 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/.gitignore b/Mainboard/Firmware/motherboard_v1/.gitignore index 48daa56e..bf95e117 100644 --- a/Mainboard/Firmware/motherboard_v1/.gitignore +++ b/Mainboard/Firmware/motherboard_v1/.gitignore @@ -1,6 +1,8 @@ .settings/language.settings.xml Debug/ Release/ +AMDS/ +2S/ scripts/__pycache__/ *.o *.d diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 1dfc197f..3303c4a1 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -151,61 +151,212 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) // This ISR is triggered by the AMDC to sync the ADC // conversions to the AMDC PWM carrier waveform. In // this ISR, all the motherboard ADCs should be sampled. -void EXTI3_IRQHandler(void) +//void EXTI3_IRQHandler(void) +//{ +// // alert daisy chained AMDSs to begin converting +// //reset DMA routing state machine to ensure robust operation in case bytes were dropped +// try_reset_routing_state(); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// //reset DMA routing state machine to ensure robust operation in case bytes were dropped +// try_reset_routing_state(); +// +//#ifdef BENCHMARK_MODE +// // ========================================================================= +// // INJECT MOCK DMA DATA FOR BENCHMARKING +// // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. +// // ========================================================================= +// uint8_t current_head = mock_dma_write_head; +// for (int i = 0; i < 24; i++) { +// uint8_t idx = (uint8_t)(current_head + i); +// if (i % 3 == 0) { +// UART4_DMA_Pool[idx] = 0x90; // Valid Header +// UART5_DMA_Pool[idx] = 0x90; +// } else { +// UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data +// UART5_DMA_Pool[idx] = 0xBB; +// } +// } +// // Instantly advance the mock hardware write head +// mock_dma_write_head = (uint8_t)(current_head + 24); +//#endif +// +// // Perform the actual SPI transactions +// uint16_t new_data[8] = { 0 }; +// adc_sample_all_daughtercards(new_data); +// +// // Send the data we sampled out as fast as possible +// // +// // ========================================================================= +// // OPTIMIZATION: "Tight Loop" Fast Path +// // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching +// // ========================================================================= +// if (active_sensor_mask == 0xFF) { +// for (uint32_t i = 0; i < 4; i++) { +// drv_uart_putc_fast(USART2, 0x90 | i); +// drv_uart_putc_fast(USART3, 0x90 | i); +// +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// +// drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); +// drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); +// } +// } +// // ========================================================================= +// // SLOW PATH: Safe loop for Partial Masks +// // ========================================================================= +// else { +// for (uint32_t i = 0; i < 4; i++) { +// uint8_t header = 0x90 | i; +// +// if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { +// drv_uart_putc_fast(USART2, header); +// drv_uart_putc_fast(USART3, header); +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); +// } else { +// bool u3 = false; +// bool u2 = false; +// +// if (active_sensor_mask & (1 << i)) { +// drv_uart_putc_fast(USART2, header); +// u2 = true; +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// } +// if (active_sensor_mask & (1 << (i + 4))) { +// drv_uart_putc_fast(USART3, header); +// u3 = true; +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// } +// if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); +// if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); +// } +// } +// } +// +// //Handle any DMA data that has been received from daisy chain +// try_process_routing(); // This try function is thread safe +// +// // Clear all pending IRQs for ADC conversions at the +// // end of this ISR so that the system realigns the +// // ADC conversions with the SYNC signal from the AMDC. +// // +// // For some reason, this only works if we call both of these: +// NVIC_ClearPendingIRQ(EXTI3_IRQn); +// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); +// NVIC_ClearPendingIRQ(EXTI3_IRQn); +//} + +void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { - // alert daisy chained AMDSs to begin converting - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); + // Capture the exact clock cycle we start + uint32_t start_cycles = DWT->CYCCNT; + + // Calculate 1.3 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; + + // 1. Start all ADC conversions. + SET_PIN_CONVST12_HIGH; + SET_PIN_CONVST34_HIGH; + SET_PIN_CONVST56_HIGH; + SET_PIN_CONVST78_HIGH; -#ifdef BENCHMARK_MODE // ========================================================================= - // INJECT MOCK DMA DATA FOR BENCHMARKING - // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. + // LATENCY HIDE 1: We have 1.3us of free time! + // Send Header for Channel 0 & 4 while waiting for ADCs to convert! // ========================================================================= - uint8_t current_head = mock_dma_write_head; - for (int i = 0; i < 24; i++) { - uint8_t idx = (uint8_t)(current_head + i); - if (i % 3 == 0) { - UART4_DMA_Pool[idx] = 0x90; // Valid Header - UART5_DMA_Pool[idx] = 0x90; - } else { - UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data - UART5_DMA_Pool[idx] = 0xBB; - } + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x90); + + // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs + while ((DWT->CYCCNT - start_cycles) < wait_cycles) { + // Spin perfectly safely } - // Instantly advance the mock hardware write head - mock_dma_write_head = (uint8_t)(current_head + 24); -#endif - // Perform the actual SPI transactions - uint16_t new_data[8] = { 0 }; - adc_sample_all_daughtercards(new_data); + // 2. Start the SCLKs + drv_spi_start_read_two_16bits(SPI1); + drv_spi_start_read_two_16bits(SPI4); + drv_spi_start_read_two_16bits(SPI5); + drv_spi_start_read_two_16bits(SPI6); + + // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) + drv_spi_finish_read_one_16bits(SPI1, &sample_data_out[3]); + drv_spi_finish_read_one_16bits(SPI4, &sample_data_out[1]); + drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); + drv_spi_finish_read_one_16bits(SPI6, &sample_data_out[2]); + + // ========================================================================= + // LATENCY HIDE 2: We have to wait for the second SPI read! + // Send MSB for Channel 0 while waiting for SPI! + // (We can't send Ch 4 yet because it hasn't been read from SPI yet) + // ========================================================================= + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); + + // Wait for second ADC data to complete + drv_spi_wait_for_RX(SPI1); + drv_spi_wait_for_RX(SPI4); + drv_spi_wait_for_RX(SPI5); + drv_spi_wait_for_RX(SPI6); + + // End conversion + SET_PIN_CONVST12_LOW; + SET_PIN_CONVST34_LOW; + SET_PIN_CONVST56_LOW; + SET_PIN_CONVST78_LOW; + + // Read second ADC data (Channels 4, 5, 6, 7) + drv_spi_get_DR(SPI1, &sample_data_out[7]); + drv_spi_get_DR(SPI4, &sample_data_out[5]); + drv_spi_get_DR(SPI5, &sample_data_out[4]); + drv_spi_get_DR(SPI6, &sample_data_out[6]); + + // ========================================================================= + // LATENCY HIDE 3: Finish sending Channel 0 and 4 immediately + // ========================================================================= + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); // Send Ch 4 MSB + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0])); // Send Ch 0 LSB + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4])); // Send Ch 4 LSB - // Send the data we sampled out as fast as possible - // // ========================================================================= - // OPTIMIZATION: "Tight Loop" Fast Path - // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching + // SEND REMAINING CHANNELS: 1-3 & 5-7 + // Because Ch 0 & 4 were hidden in the latency, we only loop 3 times! + // ========================================================================= + for (uint32_t i = 1; i < 4; i++) { + drv_uart_putc_fast(USART2, 0x90 | i); + drv_uart_putc_fast(USART3, 0x90 | i); + + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[i + 4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 4]); + } +} + +void EXTI3_IRQHandler(void) +{ + // alert daisy chained AMDSs to begin converting + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + + // reset DMA routing state machine + try_reset_routing_state(); + + uint16_t new_data[8] = { 0 }; + + // ========================================================================= + // FAST PATH: Integrated Sampling and Transmission! // ========================================================================= if (active_sensor_mask == 0xFF) { - for (uint32_t i = 0; i < 4; i++) { - drv_uart_putc_fast(USART2, 0x90 | i); - drv_uart_putc_fast(USART3, 0x90 | i); - - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - - drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); - } - } + adc_sample_and_transmit_fast_path(new_data); + } // ========================================================================= - // SLOW PATH: Safe loop for Partial Masks + // SLOW PATH: Legacy sampling for Partial Masks // ========================================================================= else { + adc_sample_all_daughtercards(new_data); + for (uint32_t i = 0; i < 4; i++) { uint8_t header = 0x90 | i; @@ -216,10 +367,10 @@ void EXTI3_IRQHandler(void) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); - } else { + } else { bool u3 = false; bool u2 = false; - + if (active_sensor_mask & (1 << i)) { drv_uart_putc_fast(USART2, header); u2 = true; @@ -230,20 +381,15 @@ void EXTI3_IRQHandler(void) u3 = true; drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); } - if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); - if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); + if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); } } } - //Handle any DMA data that has been received from daisy chain - try_process_routing(); // This try function is thread safe + // Handle any DMA data that has been received from daisy chain + try_process_routing(); - // Clear all pending IRQs for ADC conversions at the - // end of this ISR so that the system realigns the - // ADC conversions with the SYNC signal from the AMDC. - // - // For some reason, this only works if we call both of these: NVIC_ClearPendingIRQ(EXTI3_IRQn); __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); NVIC_ClearPendingIRQ(EXTI3_IRQn); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 9a49b818..da55bab2 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -44,6 +44,11 @@ int main(void) // Set bit 0 to 0 // SysTick->CTRL &= 0xFFFFFFFE; + // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + while (1) { // Handle DMA data from UARTs and route to correct destination. From 99bf81e8fcaddf99a39d6de69016f957b4badba5 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 24 Apr 2026 15:42:14 -0500 Subject: [PATCH 43/72] enable counter --- Mainboard/Firmware/motherboard_v1/Core/Src/main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index da55bab2..ef0690f7 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -46,6 +46,7 @@ int main(void) // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->LAR = 0xC5ACCE55; DWT->CYCCNT = 0; DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; From 8cfb676781d2495a20dc14e665989fdbaf1dd7a1 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 24 Apr 2026 16:48:53 -0500 Subject: [PATCH 44/72] comment certain sections in order to get a baseline --- .../Firmware/motherboard_v1/Core/Src/adc.c | 319 +++++++++--------- .../Firmware/motherboard_v1/Core/Src/main.c | 8 +- 2 files changed, 163 insertions(+), 164 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 3303c4a1..9d7278f6 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -151,114 +151,112 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) // This ISR is triggered by the AMDC to sync the ADC // conversions to the AMDC PWM carrier waveform. In // this ISR, all the motherboard ADCs should be sampled. -//void EXTI3_IRQHandler(void) -//{ -// // alert daisy chained AMDSs to begin converting -// //reset DMA routing state machine to ensure robust operation in case bytes were dropped -// try_reset_routing_state(); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// //reset DMA routing state machine to ensure robust operation in case bytes were dropped -// try_reset_routing_state(); -// -//#ifdef BENCHMARK_MODE -// // ========================================================================= -// // INJECT MOCK DMA DATA FOR BENCHMARKING -// // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. -// // ========================================================================= -// uint8_t current_head = mock_dma_write_head; -// for (int i = 0; i < 24; i++) { -// uint8_t idx = (uint8_t)(current_head + i); -// if (i % 3 == 0) { -// UART4_DMA_Pool[idx] = 0x90; // Valid Header -// UART5_DMA_Pool[idx] = 0x90; -// } else { -// UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data -// UART5_DMA_Pool[idx] = 0xBB; -// } -// } -// // Instantly advance the mock hardware write head -// mock_dma_write_head = (uint8_t)(current_head + 24); -//#endif -// -// // Perform the actual SPI transactions -// uint16_t new_data[8] = { 0 }; -// adc_sample_all_daughtercards(new_data); -// -// // Send the data we sampled out as fast as possible -// // -// // ========================================================================= -// // OPTIMIZATION: "Tight Loop" Fast Path -// // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching -// // ========================================================================= -// if (active_sensor_mask == 0xFF) { -// for (uint32_t i = 0; i < 4; i++) { -// drv_uart_putc_fast(USART2, 0x90 | i); -// drv_uart_putc_fast(USART3, 0x90 | i); -// -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// -// drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); -// drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); -// } -// } -// // ========================================================================= -// // SLOW PATH: Safe loop for Partial Masks -// // ========================================================================= -// else { -// for (uint32_t i = 0; i < 4; i++) { -// uint8_t header = 0x90 | i; -// -// if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { -// drv_uart_putc_fast(USART2, header); -// drv_uart_putc_fast(USART3, header); -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); -// } else { -// bool u3 = false; -// bool u2 = false; -// -// if (active_sensor_mask & (1 << i)) { -// drv_uart_putc_fast(USART2, header); -// u2 = true; -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// } -// if (active_sensor_mask & (1 << (i + 4))) { -// drv_uart_putc_fast(USART3, header); -// u3 = true; -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// } -// if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); -// if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); -// } -// } -// } -// -// //Handle any DMA data that has been received from daisy chain -// try_process_routing(); // This try function is thread safe -// -// // Clear all pending IRQs for ADC conversions at the -// // end of this ISR so that the system realigns the -// // ADC conversions with the SYNC signal from the AMDC. -// // -// // For some reason, this only works if we call both of these: -// NVIC_ClearPendingIRQ(EXTI3_IRQn); -// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); -// NVIC_ClearPendingIRQ(EXTI3_IRQn); -//} +void EXTI3_IRQHandler(void) +{ + // alert daisy chained AMDSs to begin converting + //reset DMA routing state machine to ensure robust operation in case bytes were dropped + try_reset_routing_state(); + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //reset DMA routing state machine to ensure robust operation in case bytes were dropped + try_reset_routing_state(); + +#ifdef BENCHMARK_MODE + // ========================================================================= + // INJECT MOCK DMA DATA FOR BENCHMARKING + // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. + // ========================================================================= + uint8_t current_head = mock_dma_write_head; + for (int i = 0; i < 24; i++) { + uint8_t idx = (uint8_t)(current_head + i); + if (i % 3 == 0) { + UART4_DMA_Pool[idx] = 0x90; // Valid Header + UART5_DMA_Pool[idx] = 0x90; + } else { + UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data + UART5_DMA_Pool[idx] = 0xBB; + } + } + // Instantly advance the mock hardware write head + mock_dma_write_head = (uint8_t)(current_head + 24); +#endif + + // Perform the actual SPI transactions + uint16_t new_data[8] = { 0 }; + adc_sample_all_daughtercards(new_data); + + // Send the data we sampled out as fast as possible + // + // ========================================================================= + // OPTIMIZATION: "Tight Loop" Fast Path + // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching + // ========================================================================= + if (active_sensor_mask == 0xFF) { + for (uint32_t i = 0; i < 4; i++) { + drv_uart_putc_fast(USART2, 0x90 | i); + drv_uart_putc_fast(USART3, 0x90 | i); + + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); + drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); + } + } + // ========================================================================= + // SLOW PATH: Safe loop for Partial Masks + // ========================================================================= + else { + for (uint32_t i = 0; i < 4; i++) { + uint8_t header = 0x90 | i; + + if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART3, header); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); + } else { + bool u3 = false; + bool u2 = false; + + if (active_sensor_mask & (1 << i)) { + drv_uart_putc_fast(USART2, header); + u2 = true; + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + } + if (active_sensor_mask & (1 << (i + 4))) { + drv_uart_putc_fast(USART3, header); + u3 = true; + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + } + if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); + if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); + } + } + } + + //Handle any DMA data that has been received from daisy chain + try_process_routing(); // This try function is thread safe + + // Clear all pending IRQs for ADC conversions at the + // end of this ISR so that the system realigns the + // ADC conversions with the SYNC signal from the AMDC. + // + // For some reason, this only works if we call both of these: + NVIC_ClearPendingIRQ(EXTI3_IRQn); + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); + NVIC_ClearPendingIRQ(EXTI3_IRQn); +} void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { - // Capture the exact clock cycle we start - uint32_t start_cycles = DWT->CYCCNT; - - // Calculate 1.3 microseconds in CPU cycles (integer math safe) + // Calculate 1.3 microseconds in CPU cycles (integer math safe) uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; // 1. Start all ADC conversions. SET_PIN_CONVST12_HIGH; + uint32_t start_cycles = DWT->CYCCNT; SET_PIN_CONVST34_HIGH; SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; @@ -306,6 +304,7 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) SET_PIN_CONVST56_LOW; SET_PIN_CONVST78_LOW; + // Read second ADC data (Channels 4, 5, 6, 7) drv_spi_get_DR(SPI1, &sample_data_out[7]); drv_spi_get_DR(SPI4, &sample_data_out[5]); @@ -335,65 +334,65 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) } } -void EXTI3_IRQHandler(void) -{ - // alert daisy chained AMDSs to begin converting - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - - // reset DMA routing state machine - try_reset_routing_state(); - - uint16_t new_data[8] = { 0 }; - - // ========================================================================= - // FAST PATH: Integrated Sampling and Transmission! - // ========================================================================= - if (active_sensor_mask == 0xFF) { - adc_sample_and_transmit_fast_path(new_data); - } - // ========================================================================= - // SLOW PATH: Legacy sampling for Partial Masks - // ========================================================================= - else { - adc_sample_all_daughtercards(new_data); - - for (uint32_t i = 0; i < 4; i++) { - uint8_t header = 0x90 | i; - - if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); - } else { - bool u3 = false; - bool u2 = false; - - if (active_sensor_mask & (1 << i)) { - drv_uart_putc_fast(USART2, header); - u2 = true; - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - } - if (active_sensor_mask & (1 << (i + 4))) { - drv_uart_putc_fast(USART3, header); - u3 = true; - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - } - if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); - if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); - } - } - } - - // Handle any DMA data that has been received from daisy chain - try_process_routing(); - - NVIC_ClearPendingIRQ(EXTI3_IRQn); - __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); - NVIC_ClearPendingIRQ(EXTI3_IRQn); -} +//void EXTI3_IRQHandler(void) +//{ +// // alert daisy chained AMDSs to begin converting +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// +// // reset DMA routing state machine +// try_reset_routing_state(); +// +// uint16_t new_data[8] = { 0 }; +// +// // ========================================================================= +// // FAST PATH: Integrated Sampling and Transmission! +// // ========================================================================= +// if (active_sensor_mask == 0xFF) { +// adc_sample_and_transmit_fast_path(new_data); +// } +// // ========================================================================= +// // SLOW PATH: Legacy sampling for Partial Masks +// // ========================================================================= +// else { +// adc_sample_all_daughtercards(new_data); +// +// for (uint32_t i = 0; i < 4; i++) { +// uint8_t header = 0x90 | i; +// +// if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { +// drv_uart_putc_fast(USART2, header); +// drv_uart_putc_fast(USART3, header); +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); +// } else { +// bool u3 = false; +// bool u2 = false; +// +// if (active_sensor_mask & (1 << i)) { +// drv_uart_putc_fast(USART2, header); +// u2 = true; +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// } +// if (active_sensor_mask & (1 << (i + 4))) { +// drv_uart_putc_fast(USART3, header); +// u3 = true; +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// } +// if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); +// if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); +// } +// } +// } +// +// // Handle any DMA data that has been received from daisy chain +// try_process_routing(); +// +// NVIC_ClearPendingIRQ(EXTI3_IRQn); +// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); +// NVIC_ClearPendingIRQ(EXTI3_IRQn); +//} static void setup_pin_CONVST(void) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index ef0690f7..ffdf159a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -45,10 +45,10 @@ int main(void) // SysTick->CTRL &= 0xFFFFFFFE; // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->LAR = 0xC5ACCE55; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; +// CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; +// DWT->LAR = 0xC5ACCE55; +// DWT->CYCCNT = 0; +// DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; while (1) { From 9511f4617e3dd61ad1f777c417398342da1f2499 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Mon, 27 Apr 2026 10:34:47 -0500 Subject: [PATCH 45/72] add firmware used to get a benchmark --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 12 +++++++++++- Mainboard/Firmware/motherboard_v1/Core/Src/main.c | 8 ++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 9d7278f6..de7e7fa5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -256,10 +256,11 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // 1. Start all ADC conversions. SET_PIN_CONVST12_HIGH; - uint32_t start_cycles = DWT->CYCCNT; + SET_PIN_CONVST34_HIGH; SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; + uint32_t start_cycles = DWT->CYCCNT; // ========================================================================= // LATENCY HIDE 1: We have 1.3us of free time! @@ -268,10 +269,17 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) drv_uart_putc_fast(USART2, 0x90); drv_uart_putc_fast(USART3, 0x90); + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs while ((DWT->CYCCNT - start_cycles) < wait_cycles) { // Spin perfectly safely } + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + NOP256; + NOP4; + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); @@ -292,11 +300,13 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // ========================================================================= drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // Wait for second ADC data to complete drv_spi_wait_for_RX(SPI1); drv_spi_wait_for_RX(SPI4); drv_spi_wait_for_RX(SPI5); drv_spi_wait_for_RX(SPI6); + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // End conversion SET_PIN_CONVST12_LOW; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index ffdf159a..ef0690f7 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -45,10 +45,10 @@ int main(void) // SysTick->CTRL &= 0xFFFFFFFE; // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays -// CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; -// DWT->LAR = 0xC5ACCE55; -// DWT->CYCCNT = 0; -// DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->LAR = 0xC5ACCE55; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; while (1) { From 414d644f62b4d51b58c72550b2ec6176d7c99933 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Mon, 27 Apr 2026 10:48:34 -0500 Subject: [PATCH 46/72] move header transmit to avoid timeout --- .../Firmware/motherboard_v1/Core/Src/adc.c | 331 +++++++++--------- 1 file changed, 163 insertions(+), 168 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index de7e7fa5..0d5d7d1c 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -151,103 +151,103 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) // This ISR is triggered by the AMDC to sync the ADC // conversions to the AMDC PWM carrier waveform. In // this ISR, all the motherboard ADCs should be sampled. -void EXTI3_IRQHandler(void) -{ - // alert daisy chained AMDSs to begin converting - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); - -#ifdef BENCHMARK_MODE - // ========================================================================= - // INJECT MOCK DMA DATA FOR BENCHMARKING - // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. - // ========================================================================= - uint8_t current_head = mock_dma_write_head; - for (int i = 0; i < 24; i++) { - uint8_t idx = (uint8_t)(current_head + i); - if (i % 3 == 0) { - UART4_DMA_Pool[idx] = 0x90; // Valid Header - UART5_DMA_Pool[idx] = 0x90; - } else { - UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data - UART5_DMA_Pool[idx] = 0xBB; - } - } - // Instantly advance the mock hardware write head - mock_dma_write_head = (uint8_t)(current_head + 24); -#endif - - // Perform the actual SPI transactions - uint16_t new_data[8] = { 0 }; - adc_sample_all_daughtercards(new_data); - - // Send the data we sampled out as fast as possible - // - // ========================================================================= - // OPTIMIZATION: "Tight Loop" Fast Path - // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching - // ========================================================================= - if (active_sensor_mask == 0xFF) { - for (uint32_t i = 0; i < 4; i++) { - drv_uart_putc_fast(USART2, 0x90 | i); - drv_uart_putc_fast(USART3, 0x90 | i); - - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - - drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); - } - } - // ========================================================================= - // SLOW PATH: Safe loop for Partial Masks - // ========================================================================= - else { - for (uint32_t i = 0; i < 4; i++) { - uint8_t header = 0x90 | i; - - if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(USART3, header); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); - } else { - bool u3 = false; - bool u2 = false; - - if (active_sensor_mask & (1 << i)) { - drv_uart_putc_fast(USART2, header); - u2 = true; - drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); - } - if (active_sensor_mask & (1 << (i + 4))) { - drv_uart_putc_fast(USART3, header); - u3 = true; - drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); - } - if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); - if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); - } - } - } - - //Handle any DMA data that has been received from daisy chain - try_process_routing(); // This try function is thread safe - - // Clear all pending IRQs for ADC conversions at the - // end of this ISR so that the system realigns the - // ADC conversions with the SYNC signal from the AMDC. - // - // For some reason, this only works if we call both of these: - NVIC_ClearPendingIRQ(EXTI3_IRQn); - __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); - NVIC_ClearPendingIRQ(EXTI3_IRQn); -} +//void EXTI3_IRQHandler(void) +//{ +// // alert daisy chained AMDSs to begin converting +// //reset DMA routing state machine to ensure robust operation in case bytes were dropped +// try_reset_routing_state(); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// //reset DMA routing state machine to ensure robust operation in case bytes were dropped +// try_reset_routing_state(); +// +//#ifdef BENCHMARK_MODE +// // ========================================================================= +// // INJECT MOCK DMA DATA FOR BENCHMARKING +// // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. +// // ========================================================================= +// uint8_t current_head = mock_dma_write_head; +// for (int i = 0; i < 24; i++) { +// uint8_t idx = (uint8_t)(current_head + i); +// if (i % 3 == 0) { +// UART4_DMA_Pool[idx] = 0x90; // Valid Header +// UART5_DMA_Pool[idx] = 0x90; +// } else { +// UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data +// UART5_DMA_Pool[idx] = 0xBB; +// } +// } +// // Instantly advance the mock hardware write head +// mock_dma_write_head = (uint8_t)(current_head + 24); +//#endif +// +// // Perform the actual SPI transactions +// uint16_t new_data[8] = { 0 }; +// adc_sample_all_daughtercards(new_data); +// +// // Send the data we sampled out as fast as possible +// // +// // ========================================================================= +// // OPTIMIZATION: "Tight Loop" Fast Path +// // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching +// // ========================================================================= +// if (active_sensor_mask == 0xFF) { +// for (uint32_t i = 0; i < 4; i++) { +// drv_uart_putc_fast(USART2, 0x90 | i); +// drv_uart_putc_fast(USART3, 0x90 | i); +// +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// +// drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); +// drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); +// } +// } +// // ========================================================================= +// // SLOW PATH: Safe loop for Partial Masks +// // ========================================================================= +// else { +// for (uint32_t i = 0; i < 4; i++) { +// uint8_t header = 0x90 | i; +// +// if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { +// drv_uart_putc_fast(USART2, header); +// drv_uart_putc_fast(USART3, header); +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); +// } else { +// bool u3 = false; +// bool u2 = false; +// +// if (active_sensor_mask & (1 << i)) { +// drv_uart_putc_fast(USART2, header); +// u2 = true; +// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); +// } +// if (active_sensor_mask & (1 << (i + 4))) { +// drv_uart_putc_fast(USART3, header); +// u3 = true; +// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); +// } +// if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); +// if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); +// } +// } +// } +// +// //Handle any DMA data that has been received from daisy chain +// try_process_routing(); // This try function is thread safe +// +// // Clear all pending IRQs for ADC conversions at the +// // end of this ISR so that the system realigns the +// // ADC conversions with the SYNC signal from the AMDC. +// // +// // For some reason, this only works if we call both of these: +// NVIC_ClearPendingIRQ(EXTI3_IRQn); +// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); +// NVIC_ClearPendingIRQ(EXTI3_IRQn); +//} void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { @@ -266,20 +266,15 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // LATENCY HIDE 1: We have 1.3us of free time! // Send Header for Channel 0 & 4 while waiting for ADCs to convert! // ========================================================================= - drv_uart_putc_fast(USART2, 0x90); - drv_uart_putc_fast(USART3, 0x90); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs - while ((DWT->CYCCNT - start_cycles) < wait_cycles) { - // Spin perfectly safely - } - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs +// while ((DWT->CYCCNT - start_cycles) < wait_cycles) { +// // Spin perfectly safely +// } + NOP256; NOP4; - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); @@ -298,15 +293,15 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // Send MSB for Channel 0 while waiting for SPI! // (We can't send Ch 4 yet because it hasn't been read from SPI yet) // ========================================================================= + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x90); drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // Wait for second ADC data to complete drv_spi_wait_for_RX(SPI1); drv_spi_wait_for_RX(SPI4); drv_spi_wait_for_RX(SPI5); drv_spi_wait_for_RX(SPI6); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // End conversion SET_PIN_CONVST12_LOW; @@ -344,65 +339,65 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) } } -//void EXTI3_IRQHandler(void) -//{ -// // alert daisy chained AMDSs to begin converting -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// -// // reset DMA routing state machine -// try_reset_routing_state(); -// -// uint16_t new_data[8] = { 0 }; -// -// // ========================================================================= -// // FAST PATH: Integrated Sampling and Transmission! -// // ========================================================================= -// if (active_sensor_mask == 0xFF) { -// adc_sample_and_transmit_fast_path(new_data); -// } -// // ========================================================================= -// // SLOW PATH: Legacy sampling for Partial Masks -// // ========================================================================= -// else { -// adc_sample_all_daughtercards(new_data); -// -// for (uint32_t i = 0; i < 4; i++) { -// uint8_t header = 0x90 | i; -// -// if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { -// drv_uart_putc_fast(USART2, header); -// drv_uart_putc_fast(USART3, header); -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); -// } else { -// bool u3 = false; -// bool u2 = false; -// -// if (active_sensor_mask & (1 << i)) { -// drv_uart_putc_fast(USART2, header); -// u2 = true; -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// } -// if (active_sensor_mask & (1 << (i + 4))) { -// drv_uart_putc_fast(USART3, header); -// u3 = true; -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// } -// if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); -// if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); -// } -// } -// } -// -// // Handle any DMA data that has been received from daisy chain -// try_process_routing(); -// -// NVIC_ClearPendingIRQ(EXTI3_IRQn); -// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); -// NVIC_ClearPendingIRQ(EXTI3_IRQn); -//} +void EXTI3_IRQHandler(void) +{ + // alert daisy chained AMDSs to begin converting + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + + // reset DMA routing state machine + try_reset_routing_state(); + + uint16_t new_data[8] = { 0 }; + + // ========================================================================= + // FAST PATH: Integrated Sampling and Transmission! + // ========================================================================= + if (active_sensor_mask == 0xFF) { + adc_sample_and_transmit_fast_path(new_data); + } + // ========================================================================= + // SLOW PATH: Legacy sampling for Partial Masks + // ========================================================================= + else { + adc_sample_all_daughtercards(new_data); + + for (uint32_t i = 0; i < 4; i++) { + uint8_t header = 0x90 | i; + + if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { + drv_uart_putc_fast(USART2, header); + drv_uart_putc_fast(USART3, header); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); + } else { + bool u3 = false; + bool u2 = false; + + if (active_sensor_mask & (1 << i)) { + drv_uart_putc_fast(USART2, header); + u2 = true; + drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); + } + if (active_sensor_mask & (1 << (i + 4))) { + drv_uart_putc_fast(USART3, header); + u3 = true; + drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); + } + if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] & 0xFF)); + if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] & 0xFF)); + } + } + } + + // Handle any DMA data that has been received from daisy chain + try_process_routing(); + + NVIC_ClearPendingIRQ(EXTI3_IRQn); + __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); + NVIC_ClearPendingIRQ(EXTI3_IRQn); +} static void setup_pin_CONVST(void) { From d939be5fd58c822c2a7f3020e5cb5bd528e6bfcf Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Mon, 27 Apr 2026 11:00:46 -0500 Subject: [PATCH 47/72] remove uneccasry counter firmware' --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 4 ---- Mainboard/Firmware/motherboard_v1/Core/Src/main.c | 6 ------ 2 files changed, 10 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 0d5d7d1c..eddfdb85 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -251,16 +251,12 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { - // Calculate 1.3 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; - // 1. Start all ADC conversions. SET_PIN_CONVST12_HIGH; SET_PIN_CONVST34_HIGH; SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; - uint32_t start_cycles = DWT->CYCCNT; // ========================================================================= // LATENCY HIDE 1: We have 1.3us of free time! diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index ef0690f7..4bd92425 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -43,12 +43,6 @@ int main(void) // // Set bit 0 to 0 // SysTick->CTRL &= 0xFFFFFFFE; - - // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays - CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; - DWT->LAR = 0xC5ACCE55; - DWT->CYCCNT = 0; - DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; while (1) { From e4cf2f53d85b59a97b9dcc006b809301feb84e15 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 28 Apr 2026 12:18:48 -0500 Subject: [PATCH 48/72] remove second wait state --- .../Firmware/motherboard_v1/Core/Src/adc.c | 135 +++++++++++------- .../Firmware/motherboard_v1/Core/Src/main.c | 6 + 2 files changed, 93 insertions(+), 48 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index eddfdb85..688614eb 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -251,26 +251,30 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { + // Calculate 1.3 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; + // 1. Start all ADC conversions. SET_PIN_CONVST12_HIGH; - SET_PIN_CONVST34_HIGH; SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; + uint32_t start_cycles = DWT->CYCCNT; + // ========================================================================= // LATENCY HIDE 1: We have 1.3us of free time! // Send Header for Channel 0 & 4 while waiting for ADCs to convert! // ========================================================================= +// drv_uart_putc_fast(USART2, 0x90); +// drv_uart_putc_fast(USART3, 0x90); -// // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs -// while ((DWT->CYCCNT - start_cycles) < wait_cycles) { -// // Spin perfectly safely -// } + // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs + while ((DWT->CYCCNT - start_cycles) < wait_cycles) { + // Spin perfectly safely + } - NOP256; - NOP4; // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); @@ -283,56 +287,91 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) drv_spi_finish_read_one_16bits(SPI4, &sample_data_out[1]); drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); drv_spi_finish_read_one_16bits(SPI6, &sample_data_out[2]); + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // ========================================================================= // LATENCY HIDE 2: We have to wait for the second SPI read! // Send MSB for Channel 0 while waiting for SPI! // (We can't send Ch 4 yet because it hasn't been read from SPI yet) // ========================================================================= - drv_uart_putc_fast(USART2, 0x90); - drv_uart_putc_fast(USART3, 0x90); - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); - // Wait for second ADC data to complete - drv_spi_wait_for_RX(SPI1); - drv_spi_wait_for_RX(SPI4); - drv_spi_wait_for_RX(SPI5); - drv_spi_wait_for_RX(SPI6); - - // End conversion - SET_PIN_CONVST12_LOW; - SET_PIN_CONVST34_LOW; - SET_PIN_CONVST56_LOW; - SET_PIN_CONVST78_LOW; - - - // Read second ADC data (Channels 4, 5, 6, 7) - drv_spi_get_DR(SPI1, &sample_data_out[7]); - drv_spi_get_DR(SPI4, &sample_data_out[5]); - drv_spi_get_DR(SPI5, &sample_data_out[4]); - drv_spi_get_DR(SPI6, &sample_data_out[6]); - - // ========================================================================= - // LATENCY HIDE 3: Finish sending Channel 0 and 4 immediately - // ========================================================================= - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); // Send Ch 4 MSB - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0])); // Send Ch 0 LSB - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4])); // Send Ch 4 LSB - - // ========================================================================= - // SEND REMAINING CHANNELS: 1-3 & 5-7 - // Because Ch 0 & 4 were hidden in the latency, we only loop 3 times! - // ========================================================================= - for (uint32_t i = 1; i < 4; i++) { - drv_uart_putc_fast(USART2, 0x90 | i); - drv_uart_putc_fast(USART3, 0x90 | i); +// drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[1] >> 8)); +// +// drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[0]); +// drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[1]); - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[i] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[i + 4] >> 8)); - drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); - drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 4]); - } + // End conversion + SET_PIN_CONVST12_LOW; + SET_PIN_CONVST34_LOW; + SET_PIN_CONVST56_LOW; + SET_PIN_CONVST78_LOW; + + + // Read second ADC data (Channels 4, 5, 6, 7) + drv_spi_get_DR(SPI1, &sample_data_out[7]); + drv_spi_get_DR(SPI4, &sample_data_out[5]); + drv_spi_get_DR(SPI5, &sample_data_out[4]); + drv_spi_get_DR(SPI6, &sample_data_out[6]); + + for (uint32_t i = 0; i < 4; i++) { + drv_uart_putc_fast(USART2, 0x90 | i); + drv_uart_putc_fast(USART3, 0x90 | i); + + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[i] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[i + 4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 4]); + } + +// // Wait for second ADC data to complete +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// drv_spi_wait_for_RX(SPI4); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// drv_spi_wait_for_RX(SPI1); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// drv_spi_wait_for_RX(SPI5); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// drv_spi_wait_for_RX(SPI6); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// +// // End conversion +// SET_PIN_CONVST12_LOW; +// SET_PIN_CONVST34_LOW; +// SET_PIN_CONVST56_LOW; +// SET_PIN_CONVST78_LOW; +// +// +// // Read second ADC data (Channels 4, 5, 6, 7) +// drv_spi_get_DR(SPI1, &sample_data_out[7]); +// drv_spi_get_DR(SPI4, &sample_data_out[5]); +// drv_spi_get_DR(SPI5, &sample_data_out[4]); +// drv_spi_get_DR(SPI6, &sample_data_out[6]); +// +// // ========================================================================= +// // LATENCY HIDE 3: Finish sending Channel 0 and 4 immediately +// // ========================================================================= +//// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); // Send Ch 4 MSB +//// drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0])); // Send Ch 0 LSB +//// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4])); // Send Ch 4 LSB +// +// // ========================================================================= +// // SEND REMAINING CHANNELS: 1-3 & 5-7 +// // Because Ch 0 & 4 were hidden in the latency, we only loop 3 times! +// // ========================================================================= +// for (uint32_t i = 4; i < 8; i++) { +// drv_uart_putc_fast(USART2, 0x90 | i); +// drv_uart_putc_fast(USART3, 0x90 | (i + 1)); +// +// drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[i] >> 8)); +// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[i + 1] >> 8)); +// +// drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); +// drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 1]); +// i++; +// } } void EXTI3_IRQHandler(void) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 4bd92425..a924c410 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -44,6 +44,12 @@ int main(void) // Set bit 0 to 0 // SysTick->CTRL &= 0xFFFFFFFE; + // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays + CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; + DWT->LAR = 0xC5ACCE55; + DWT->CYCCNT = 0; + DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; + while (1) { // Handle DMA data from UARTs and route to correct destination. From 53b62d757ac6f3638e3c194f0b2e5ecb8d294c6b Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 28 Apr 2026 15:58:59 -0500 Subject: [PATCH 49/72] add reset to sample-transmit function --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 688614eb..0d89e629 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -261,6 +261,8 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) SET_PIN_CONVST78_HIGH; uint32_t start_cycles = DWT->CYCCNT; + // reset DMA routing state machine + try_reset_routing_state(); // ========================================================================= // LATENCY HIDE 1: We have 1.3us of free time! @@ -275,7 +277,6 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // Spin perfectly safely } - // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); drv_spi_start_read_two_16bits(SPI4); @@ -287,7 +288,6 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) drv_spi_finish_read_one_16bits(SPI4, &sample_data_out[1]); drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); drv_spi_finish_read_one_16bits(SPI6, &sample_data_out[2]); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // ========================================================================= // LATENCY HIDE 2: We have to wait for the second SPI read! @@ -379,9 +379,6 @@ void EXTI3_IRQHandler(void) // alert daisy chained AMDSs to begin converting GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - // reset DMA routing state machine - try_reset_routing_state(); - uint16_t new_data[8] = { 0 }; // ========================================================================= From b345641c8e968ec41fa03f7030cd70ad963a6219 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 28 Apr 2026 16:20:52 -0500 Subject: [PATCH 50/72] add more profiling code --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 0d89e629..922cb0a7 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -260,6 +260,7 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; uint32_t start_cycles = DWT->CYCCNT; + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // reset DMA routing state machine try_reset_routing_state(); @@ -276,18 +277,20 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) while ((DWT->CYCCNT - start_cycles) < wait_cycles) { // Spin perfectly safely } + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); drv_spi_start_read_two_16bits(SPI4); drv_spi_start_read_two_16bits(SPI5); drv_spi_start_read_two_16bits(SPI6); - + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) drv_spi_finish_read_one_16bits(SPI1, &sample_data_out[3]); drv_spi_finish_read_one_16bits(SPI4, &sample_data_out[1]); drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); drv_spi_finish_read_one_16bits(SPI6, &sample_data_out[2]); + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // ========================================================================= // LATENCY HIDE 2: We have to wait for the second SPI read! From 63b3d2c3c0a2c83df62b64f2b92daa7ed4121244 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 29 Apr 2026 12:32:15 -0500 Subject: [PATCH 51/72] add bad modified sample-transmit --- .../Firmware/motherboard_v1/Core/Src/adc.c | 115 +++++++++++++++--- 1 file changed, 99 insertions(+), 16 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 922cb0a7..6e16604c 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -251,16 +251,14 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { - // Calculate 1.3 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; - + bool send_header = false; // 1. Start all ADC conversions. SET_PIN_CONVST12_HIGH; SET_PIN_CONVST34_HIGH; SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; uint32_t start_cycles = DWT->CYCCNT; - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // reset DMA routing state machine try_reset_routing_state(); @@ -272,25 +270,33 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // drv_uart_putc_fast(USART2, 0x90); // drv_uart_putc_fast(USART3, 0x90); + //WE ARE WAITING HERE AND COULD DO MORE TASKS BEFORE CALLING THIS + // Calculate 1.3 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; + // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs while ((DWT->CYCCNT - start_cycles) < wait_cycles) { // Spin perfectly safely } - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); drv_spi_start_read_two_16bits(SPI4); drv_spi_start_read_two_16bits(SPI5); drv_spi_start_read_two_16bits(SPI6); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) + // IT LOOKS LIKE WE ARE WAITING HERE AND COULD DO OTHER TASKS BEFORE CALLING THESE (1.3 us) + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x90); + drv_spi_finish_read_one_16bits(SPI1, &sample_data_out[3]); drv_spi_finish_read_one_16bits(SPI4, &sample_data_out[1]); drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); drv_spi_finish_read_one_16bits(SPI6, &sample_data_out[2]); - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); +// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // ========================================================================= // LATENCY HIDE 2: We have to wait for the second SPI read! @@ -305,29 +311,106 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[1]); - // End conversion - SET_PIN_CONVST12_LOW; - SET_PIN_CONVST34_LOW; - SET_PIN_CONVST56_LOW; - SET_PIN_CONVST78_LOW; + //NEED TO BRING BACK WAIT STATE FOR 78 + //drv_spi_wait_for_RX(SPI6); + + //if (!(SPI6->SR & SPI_SR_RXNE)) + //{ + //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //if (!(SPI6->SR & SPI_SR_RXNE)) + //{ + // GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + // Wait until we have received at least one word + //while (!(SPI6->SR & SPI_SR_RXNE)) { + //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //} + //} + + + drv_spi_wait_for_RX(SPI6); + //} + //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + // Read second ADC data (Channels 4, 5, 6, 7) drv_spi_get_DR(SPI1, &sample_data_out[7]); drv_spi_get_DR(SPI4, &sample_data_out[5]); drv_spi_get_DR(SPI5, &sample_data_out[4]); drv_spi_get_DR(SPI6, &sample_data_out[6]); - for (uint32_t i = 0; i < 4; i++) { - drv_uart_putc_fast(USART2, 0x90 | i); - drv_uart_putc_fast(USART3, 0x90 | i); + /*for (uint32_t i = 0; i < 4; i++) { + if (send_header){ + drv_uart_putc_fast(USART2, 0x90 | i); + drv_uart_putc_fast(USART3, 0x90 | i); + } + else { + send_header = true; + } drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[i] >> 8)); drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[i + 4] >> 8)); drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 4]); - } + }*/ + + + + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[0]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[4]); + + SET_PIN_CONVST12_LOW; + + //packet 2 + + drv_uart_putc_fast(USART2, 0x91); + drv_uart_putc_fast(USART3, 0x91); + + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[1] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[5] >> 8)); + + SET_PIN_CONVST34_LOW; + + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[1]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[5]); + + //packet 3 + drv_uart_putc_fast(USART2, 0x92); + drv_uart_putc_fast(USART3, 0x92); + + SET_PIN_CONVST56_LOW; + + + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[2] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[6] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[2]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[6]); + + SET_PIN_CONVST78_LOW; + + //packet 4 + drv_uart_putc_fast(USART2, 0x93); + drv_uart_putc_fast(USART3, 0x93); + + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[3] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[7] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[3]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[7]); + + // End conversion +// SET_PIN_CONVST12_LOW; +// SET_PIN_CONVST34_LOW; +// SET_PIN_CONVST56_LOW; +// SET_PIN_CONVST78_LOW; // // Wait for second ADC data to complete // GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); From c9be271700364ef278fe9fe0ea95f4f72b40f009 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 29 Apr 2026 12:44:40 -0500 Subject: [PATCH 52/72] add cleaned up version of sample-transmit function --- .../Firmware/motherboard_v1/Core/Src/adc.c | 268 ++---------------- 1 file changed, 16 insertions(+), 252 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 6e16604c..0e62ac62 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -148,107 +148,6 @@ static void adc_sample_all_daughtercards(uint16_t *sample_data_out) drv_spi_get_DR(SPI6, &sample_data_out[6]); } -// This ISR is triggered by the AMDC to sync the ADC -// conversions to the AMDC PWM carrier waveform. In -// this ISR, all the motherboard ADCs should be sampled. -//void EXTI3_IRQHandler(void) -//{ -// // alert daisy chained AMDSs to begin converting -// //reset DMA routing state machine to ensure robust operation in case bytes were dropped -// try_reset_routing_state(); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// //reset DMA routing state machine to ensure robust operation in case bytes were dropped -// try_reset_routing_state(); -// -//#ifdef BENCHMARK_MODE -// // ========================================================================= -// // INJECT MOCK DMA DATA FOR BENCHMARKING -// // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. -// // ========================================================================= -// uint8_t current_head = mock_dma_write_head; -// for (int i = 0; i < 24; i++) { -// uint8_t idx = (uint8_t)(current_head + i); -// if (i % 3 == 0) { -// UART4_DMA_Pool[idx] = 0x90; // Valid Header -// UART5_DMA_Pool[idx] = 0x90; -// } else { -// UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data -// UART5_DMA_Pool[idx] = 0xBB; -// } -// } -// // Instantly advance the mock hardware write head -// mock_dma_write_head = (uint8_t)(current_head + 24); -//#endif -// -// // Perform the actual SPI transactions -// uint16_t new_data[8] = { 0 }; -// adc_sample_all_daughtercards(new_data); -// -// // Send the data we sampled out as fast as possible -// // -// // ========================================================================= -// // OPTIMIZATION: "Tight Loop" Fast Path -// // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching -// // ========================================================================= -// if (active_sensor_mask == 0xFF) { -// for (uint32_t i = 0; i < 4; i++) { -// drv_uart_putc_fast(USART2, 0x90 | i); -// drv_uart_putc_fast(USART3, 0x90 | i); -// -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// -// drv_uart_putc_fast(USART2, (uint8_t)new_data[i]); -// drv_uart_putc_fast(USART3, (uint8_t)new_data[i + 4]); -// } -// } -// // ========================================================================= -// // SLOW PATH: Safe loop for Partial Masks -// // ========================================================================= -// else { -// for (uint32_t i = 0; i < 4; i++) { -// uint8_t header = 0x90 | i; -// -// if ((active_sensor_mask & (1 << i)) && (active_sensor_mask & (1 << (i + 4)))) { -// drv_uart_putc_fast(USART2, header); -// drv_uart_putc_fast(USART3, header); -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); -// } else { -// bool u3 = false; -// bool u2 = false; -// -// if (active_sensor_mask & (1 << i)) { -// drv_uart_putc_fast(USART2, header); -// u2 = true; -// drv_uart_putc_fast(USART2, (uint8_t)(new_data[i] >> 8)); -// } -// if (active_sensor_mask & (1 << (i + 4))) { -// drv_uart_putc_fast(USART3, header); -// u3 = true; -// drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4] >> 8)); -// } -// if (u2) drv_uart_putc_fast(USART2, (uint8_t)(new_data[i])); -// if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[i + 4])); -// } -// } -// } -// -// //Handle any DMA data that has been received from daisy chain -// try_process_routing(); // This try function is thread safe -// -// // Clear all pending IRQs for ADC conversions at the -// // end of this ISR so that the system realigns the -// // ADC conversions with the SYNC signal from the AMDC. -// // -// // For some reason, this only works if we call both of these: -// NVIC_ClearPendingIRQ(EXTI3_IRQn); -// __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); -// NVIC_ClearPendingIRQ(EXTI3_IRQn); -//} - void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) { bool send_header = false; @@ -257,83 +156,39 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) SET_PIN_CONVST34_HIGH; SET_PIN_CONVST56_HIGH; SET_PIN_CONVST78_HIGH; - uint32_t start_cycles = DWT->CYCCNT; -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + //Timing optimization: do work before the wait state below. + + uint32_t start_cycles = DWT->CYCCNT; // reset DMA routing state machine try_reset_routing_state(); - // ========================================================================= - // LATENCY HIDE 1: We have 1.3us of free time! - // Send Header for Channel 0 & 4 while waiting for ADCs to convert! - // ========================================================================= -// drv_uart_putc_fast(USART2, 0x90); -// drv_uart_putc_fast(USART3, 0x90); - - //WE ARE WAITING HERE AND COULD DO MORE TASKS BEFORE CALLING THIS // Calculate 1.3 microseconds in CPU cycles (integer math safe) uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; - // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs while ((DWT->CYCCNT - start_cycles) < wait_cycles) { // Spin perfectly safely } -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // 2. Start the SCLKs drv_spi_start_read_two_16bits(SPI1); drv_spi_start_read_two_16bits(SPI4); drv_spi_start_read_two_16bits(SPI5); drv_spi_start_read_two_16bits(SPI6); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) - // IT LOOKS LIKE WE ARE WAITING HERE AND COULD DO OTHER TASKS BEFORE CALLING THESE (1.3 us) + + // Timing optimization: send our first header bytes here because code after this is waiting drv_uart_putc_fast(USART2, 0x90); drv_uart_putc_fast(USART3, 0x90); + // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) drv_spi_finish_read_one_16bits(SPI1, &sample_data_out[3]); drv_spi_finish_read_one_16bits(SPI4, &sample_data_out[1]); drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); drv_spi_finish_read_one_16bits(SPI6, &sample_data_out[2]); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - - // ========================================================================= - // LATENCY HIDE 2: We have to wait for the second SPI read! - // Send MSB for Channel 0 while waiting for SPI! - // (We can't send Ch 4 yet because it hasn't been read from SPI yet) - // ========================================================================= - -// drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[1] >> 8)); -// -// drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[0]); -// drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[1]); - - - - - //NEED TO BRING BACK WAIT STATE FOR 78 - //drv_spi_wait_for_RX(SPI6); - - //if (!(SPI6->SR & SPI_SR_RXNE)) - //{ - //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //if (!(SPI6->SR & SPI_SR_RXNE)) - //{ - // GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - // Wait until we have received at least one word - //while (!(SPI6->SR & SPI_SR_RXNE)) { - //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //} - //} - + //Timing optimization: wait for only the last SPI that we started drv_spi_wait_for_RX(SPI6); - //} - //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); - //GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); // Read second ADC data (Channels 4, 5, 6, 7) drv_spi_get_DR(SPI1, &sample_data_out[7]); @@ -341,7 +196,8 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) drv_spi_get_DR(SPI5, &sample_data_out[4]); drv_spi_get_DR(SPI6, &sample_data_out[6]); - /*for (uint32_t i = 0; i < 4; i++) { + for (uint32_t i = 0; i < 4; i++) { + //don't send first header because we sent it earlier (timing optimization) if (send_header){ drv_uart_putc_fast(USART2, 0x90 | i); drv_uart_putc_fast(USART3, 0x90 | i); @@ -355,111 +211,18 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 4]); - }*/ - - - - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); - - drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[0]); - drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[4]); + } + // End conversion SET_PIN_CONVST12_LOW; - - //packet 2 - - drv_uart_putc_fast(USART2, 0x91); - drv_uart_putc_fast(USART3, 0x91); - - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[1] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[5] >> 8)); - SET_PIN_CONVST34_LOW; - - - drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[1]); - drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[5]); - - //packet 3 - drv_uart_putc_fast(USART2, 0x92); - drv_uart_putc_fast(USART3, 0x92); - SET_PIN_CONVST56_LOW; - - - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[2] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[6] >> 8)); - - drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[2]); - drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[6]); - SET_PIN_CONVST78_LOW; - - //packet 4 - drv_uart_putc_fast(USART2, 0x93); - drv_uart_putc_fast(USART3, 0x93); - - drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[3] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[7] >> 8)); - - drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[3]); - drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[7]); - - // End conversion -// SET_PIN_CONVST12_LOW; -// SET_PIN_CONVST34_LOW; -// SET_PIN_CONVST56_LOW; -// SET_PIN_CONVST78_LOW; - -// // Wait for second ADC data to complete -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// drv_spi_wait_for_RX(SPI4); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// drv_spi_wait_for_RX(SPI1); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// drv_spi_wait_for_RX(SPI5); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// drv_spi_wait_for_RX(SPI6); -// GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); -// -// // End conversion -// SET_PIN_CONVST12_LOW; -// SET_PIN_CONVST34_LOW; -// SET_PIN_CONVST56_LOW; -// SET_PIN_CONVST78_LOW; -// -// -// // Read second ADC data (Channels 4, 5, 6, 7) -// drv_spi_get_DR(SPI1, &sample_data_out[7]); -// drv_spi_get_DR(SPI4, &sample_data_out[5]); -// drv_spi_get_DR(SPI5, &sample_data_out[4]); -// drv_spi_get_DR(SPI6, &sample_data_out[6]); -// -// // ========================================================================= -// // LATENCY HIDE 3: Finish sending Channel 0 and 4 immediately -// // ========================================================================= -//// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); // Send Ch 4 MSB -//// drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0])); // Send Ch 0 LSB -//// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4])); // Send Ch 4 LSB -// -// // ========================================================================= -// // SEND REMAINING CHANNELS: 1-3 & 5-7 -// // Because Ch 0 & 4 were hidden in the latency, we only loop 3 times! -// // ========================================================================= -// for (uint32_t i = 4; i < 8; i++) { -// drv_uart_putc_fast(USART2, 0x90 | i); -// drv_uart_putc_fast(USART3, 0x90 | (i + 1)); -// -// drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[i] >> 8)); -// drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[i + 1] >> 8)); -// -// drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[i]); -// drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[i + 1]); -// i++; -// } } +// This ISR is triggered by the AMDC to sync the ADC +// conversions to the AMDC PWM carrier waveform. In +// this ISR, all the motherboard ADCs should be sampled. void EXTI3_IRQHandler(void) { // alert daisy chained AMDSs to begin converting @@ -477,7 +240,8 @@ void EXTI3_IRQHandler(void) // SLOW PATH: Legacy sampling for Partial Masks // ========================================================================= else { - adc_sample_all_daughtercards(new_data); + try_reset_routing_state(); + adc_sample_all_daughtercards(new_data); for (uint32_t i = 0; i < 4; i++) { uint8_t header = 0x90 | i; From ba4e2738167c1516745c58fc6fe41f2afc208c0d Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 29 Apr 2026 13:53:07 -0500 Subject: [PATCH 53/72] add benchmark code to I3 handler --- .../Firmware/motherboard_v1/Core/Src/adc.c | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 0e62ac62..3fea8b7b 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -225,8 +225,28 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // this ISR, all the motherboard ADCs should be sampled. void EXTI3_IRQHandler(void) { - // alert daisy chained AMDSs to begin converting - GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + // alert daisy chained AMDSs to begin converting + GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1); + +#ifdef BENCHMARK_MODE + // ========================================================================= + // INJECT MOCK DMA DATA FOR BENCHMARKING + // Simulates 8 packets (24 bytes) arriving instantly on the SYNC edge. + // ========================================================================= + uint8_t current_head = mock_dma_write_head; + for (int i = 0; i < 24; i++) { + uint8_t idx = (uint8_t)(current_head + i); + if (i % 3 == 0) { + UART4_DMA_Pool[idx] = 0x90; // Valid Header + UART5_DMA_Pool[idx] = 0x90; + } else { + UART4_DMA_Pool[idx] = 0xAA; // Dummy Payload Data + UART5_DMA_Pool[idx] = 0xBB; + } + } + // Instantly advance the mock hardware write head + mock_dma_write_head = (uint8_t)(current_head + 24); +#endif uint16_t new_data[8] = { 0 }; From 804a807f87b23860a88ee4d22bf5851a4d719155 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 29 Apr 2026 14:30:37 -0500 Subject: [PATCH 54/72] add interleaved transmit for FBC --- Mainboard/Firmware/motherboard_v1/.cproject | 13 +--- .../Firmware/motherboard_v1/Core/Src/adc.c | 69 ++++++++++++++----- 2 files changed, 54 insertions(+), 28 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/.cproject b/Mainboard/Firmware/motherboard_v1/.cproject index 1b657d5d..3033ecf8 100644 --- a/Mainboard/Firmware/motherboard_v1/.cproject +++ b/Mainboard/Firmware/motherboard_v1/.cproject @@ -369,20 +369,11 @@ - - - - - - - - - - - + + \ No newline at end of file diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 26dfbd29..624164db 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -358,6 +358,52 @@ static void adc_sample_1_5_daughtercards(uint16_t *sample_data_out) drv_spi_get_DR(SPI5, &sample_data_out[4]); } +void adc_sample_and_transmit_1_5_fast_path(uint16_t *sample_data_out) +{ + // 1. Start all ADC conversions. + SET_PIN_CONVST56_HIGH; + + //Timing optimization: do work before the wait state below. + + uint32_t start_cycles = DWT->CYCCNT; + // reset DMA routing state machine + try_reset_routing_state(); + + // Calculate 1.3 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; + + // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs + while ((DWT->CYCCNT - start_cycles) < wait_cycles) { + // Spin perfectly safely + } + + // 2. Start the SCLK + drv_spi_start_read_two_16bits(SPI5); + + // Timing optimization: send our first header bytes here because code after this is waiting + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x90); + + // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) + drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); + + //Timing optimization: wait for only the last SPI that we started + drv_spi_wait_for_RX(SPI5); + + // Read second ADC data (Channels 4, 5, 6, 7) + drv_spi_get_DR(SPI5, &sample_data_out[4]); + + //don't send first header because we sent it earlier (timing optimization) + drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); + drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); + + drv_uart_putc_fast(USART2, (uint8_t)sample_data_out[0]); + drv_uart_putc_fast(USART3, (uint8_t)sample_data_out[4]); + + // End conversion + SET_PIN_CONVST56_LOW; +} + // This ISR is for the FBC and is triggered by the // AMDC to sync the ADCconversions to the AMDC PWM // carrier waveform. In this ISR, on 2 ADCs should be sampled. @@ -366,8 +412,6 @@ void EXTI15_10_IRQHandler(void) { // alert daisy chained AMDSs to begin converting GPIO_TOGGLE_PIN(GPIOG, GPIO_PIN_14); - //reset DMA routing state machine to ensure robust operation in case bytes were dropped - try_reset_routing_state(); #ifdef BENCHMARK_MODE // ========================================================================= @@ -392,30 +436,21 @@ void EXTI15_10_IRQHandler(void) mock_dma_write_head = (uint8_t)(current_head + 6); #endif - // Perform the actual SPI transactions uint16_t new_data[8] = { 0 }; - adc_sample_1_5_daughtercards(new_data); - // Send the data we sampled out as fast as possible - // // ========================================================================= - // OPTIMIZATION: "Tight Loop" Fast Path - // Tiny code footprint (fits in I-Cache) + Zero bitwise conditional branching + // FAST PATH: Integrated Sampling and Transmission! // ========================================================================= - if (active_sensor_mask == 0x11) { - drv_uart_putc_fast(USART2, 0x90); - drv_uart_putc_fast(USART3, 0x94); - - drv_uart_putc_fast(USART2, (uint8_t)(new_data[0] >> 8)); - drv_uart_putc_fast(USART3, (uint8_t)(new_data[4] >> 8)); - - drv_uart_putc_fast(USART2, (uint8_t)new_data[0]); - drv_uart_putc_fast(USART3, (uint8_t)new_data[4]); + if (active_sensor_mask == 0xFF) { + adc_sample_and_transmit_1_5_fast_path(new_data); } // ========================================================================= // SLOW PATH: Safe loop for Partial Masks // ========================================================================= else { + try_reset_routing_state(); + adc_sample_1_5_daughtercards(new_data); + bool u3 = false; bool u2 = false; uint8_t header = 0x90; From 5951f3243c3d3c9d44a95ab80d79f80b88d2781a Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 29 Apr 2026 15:09:12 -0500 Subject: [PATCH 55/72] update active mask comment to be accurate --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 624164db..afca6357 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -47,7 +47,7 @@ static volatile uint16_t latest_valid_adc_data[8] = { 0 }; // Global bitmask: 1 = Active, 0 = Inactive. -// For example: 0b00010001 (0x0F) means channels 1-4 are active, 5-8 are disabled. +// For example: 0b00001111 (0x0F) means channels 1-4 are active, 5-8 are disabled. #if defined(TARGET_AMDS) volatile uint8_t active_sensor_mask = 0xFF; #elif defined(TARGET_2S) From ceddddae7c63978f05e9931e9a2794049724dd5c Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 29 Apr 2026 15:48:14 -0500 Subject: [PATCH 56/72] update I15_10 interrupt handler to actually use the fast path sample-tranmit function --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index afca6357..f6f36421 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -441,7 +441,7 @@ void EXTI15_10_IRQHandler(void) // ========================================================================= // FAST PATH: Integrated Sampling and Transmission! // ========================================================================= - if (active_sensor_mask == 0xFF) { + if (active_sensor_mask == 0x11) { adc_sample_and_transmit_1_5_fast_path(new_data); } // ========================================================================= From 207d8d38abbb25a34da0232b59d423b3d259fa1b Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Thu, 30 Apr 2026 11:06:55 -0500 Subject: [PATCH 57/72] cleanup comments and remove old and unused code --- .../Firmware/motherboard_v1/Core/Inc/adc.h | 15 - .../motherboard_v1/Core/Inc/drv_uart.h | 48 +-- .../Firmware/motherboard_v1/Core/Inc/tx.h | 32 -- .../Firmware/motherboard_v1/Core/Src/adc.c | 20 -- .../motherboard_v1/Core/Src/drv_uart.c | 72 +---- .../Firmware/motherboard_v1/Core/Src/main.c | 5 - .../Firmware/motherboard_v1/Core/Src/tx.c | 291 ------------------ 7 files changed, 9 insertions(+), 474 deletions(-) delete mode 100644 Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h delete mode 100644 Mainboard/Firmware/motherboard_v1/Core/Src/tx.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h index 2cfc9944..7e64d264 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h @@ -5,19 +5,4 @@ void adc_init(void); -// Read the latest bits from the ADCs. -// -// Note that this is the RAW bits at the ADC output, -// so the user must massage this into a usable value -// for their application. -// -// This is a non-blocking function. -// -// The ADC sampling is happening in the background. -// This function is guaranteed to return valid data, -// but if it is called in the middle of an conversion, -// one sample old data will be returned. -void adc_latest_bits(uint16_t *output); -void adc_latest_amds(uint16_t *output); - #endif // ADC_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index 451916ec..f277e8da 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -1,6 +1,9 @@ #ifndef DRV_UART_H #define DRV_UART_H +// BENCHMARK MODE FLAG for DMA +//#define BENCHMARK_MODE + #include "platform.h" #include #include @@ -13,9 +16,6 @@ extern UART_HandleTypeDef huart3; extern UART_HandleTypeDef DAISY_RX1_UART; extern UART_HandleTypeDef DAISY_RX2_UART; -extern DMA_HandleTypeDef hdma_usart2_tx; -extern DMA_HandleTypeDef hdma_usart3_tx; - extern DMA_HandleTypeDef hdma_uart4_rx; extern DMA_HandleTypeDef hdma_uart5_rx; @@ -42,13 +42,6 @@ extern uart_rx_tracker_t tracker2; extern uint8_t DAISY_RX1_Pool[AMDS_RX_BUF_SIZE]; extern uint8_t DAISY_RX2_Pool[AMDS_RX_BUF_SIZE]; -// ========================================================================= -// BENCHMARK MODE FLAG for DMA -// Comment out this line to return to real hardware DMA operation! -// ========================================================================= -//#define BENCHMARK_MODE -// ========================================================================= - #ifdef BENCHMARK_MODE extern volatile uint8_t mock_dma_write_head; #endif @@ -56,9 +49,6 @@ extern volatile uint8_t mock_dma_write_head; // Declare the global flag so all .c files know it exists extern volatile bool is_routing_active; -void process_uart_fifo(uint8_t *pool, uart_rx_tracker_t *track, uint8_t uart_id); -void dma_queue(uint8_t uart_id, uint8_t *data, uint8_t len); - // Add this prototype bool drv_uart_has_dma_data(void); @@ -151,36 +141,4 @@ static inline void drv_uart_send_fast(USART_TypeDef *uart, uint8_t *data, uint16 drv_uart_wait_TC(uart); } -static inline void drv_uart_dma_send_fast(UART_HandleTypeDef *huart, uint8_t *data, uint16_t len) -{ - DMA_Stream_TypeDef *dma = (DMA_Stream_TypeDef *)huart->hdmatx->Instance; - - // 1. Disable the DMA channel - dma->CR &= ~DMA_SxCR_EN; - - // 2. CRITICAL FIX: Wait for the hardware to actually halt. - // Writing to address registers while EN is still high causes a silent failure. - while ((dma->CR & DMA_SxCR_EN) != 0) { - asm("nop"); - } - - // 3. Clear the DMA Transfer Complete and Half Transfer flags - __HAL_DMA_CLEAR_FLAG(huart->hdmatx, __HAL_DMA_GET_TC_FLAG_INDEX(huart->hdmatx)); - __HAL_DMA_CLEAR_FLAG(huart->hdmatx, __HAL_DMA_GET_HT_FLAG_INDEX(huart->hdmatx)); - - // 4. CRITICAL FIX: Tell the DMA exactly *where* to push the bytes. - // It must point directly to the UART's Transmit Data Register. - dma->PAR = (uint32_t)&huart->Instance->TDR; - - // 5. Load the Memory Address and Length registers - dma->M0AR = (uint32_t)data; - dma->NDTR = len; - - // 6. Clear UART Transmission Complete flag to ensure it's ready for a fresh burst - huart->Instance->ICR = USART_ICR_TCCF; - - // 7. Fire! - dma->CR |= DMA_SxCR_EN; -} - #endif // DRV_UART_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h deleted file mode 100644 index e4ee904f..00000000 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/tx.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef TX_H -#define TX_H - -#include "adc.h" -#include "drv_uart.h" - -#include "platform.h" -#include -#include - -#define NUM_SETS 3 // 0 = local data, 1 = AMDS 1, 2 = AMDS 2 -#define PACKETS_PER_SET 8 - -typedef struct { - uint8_t header; - uint8_t msb; - uint8_t lsb; -} packet_t; - -// Global state arrays -extern volatile packet_t tx_packets[NUM_SETS * PACKETS_PER_SET]; -extern volatile bool packet_ready[NUM_SETS * PACKETS_PER_SET]; -extern bool packet_sent[NUM_SETS * PACKETS_PER_SET]; - -// Flag set by EXTI Sync Interrupt -extern volatile bool sync_event_flag; - -void process_transmissions(void); - -void transmit_samples(void); - -#endif // TX_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index f6f36421..29545877 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -2,7 +2,6 @@ #include "drv_uart.h" #include "drv_spi.h" #include "platform.h" -#include "tx.h" #include #include @@ -42,9 +41,6 @@ static void setup_pin_CONVST(void); #define ADC_BITS_TO_VOLTS(bits) (ADC_VOLTS_PER_BIT * (float) bits) -// Buffer of latest samples -static volatile uint16_t latest_valid_adc_data[8] = { 0 }; - // Global bitmask: 1 = Active, 0 = Inactive. // For example: 0b00001111 (0x0F) means channels 1-4 are active, 5-8 are disabled. @@ -65,22 +61,6 @@ void adc_init(void) setup_pin_SYNC_ADC(); } -// NOTE: this function is called from the transmit function -void adc_latest_bits(uint16_t *output) -{ - volatile uint16_t *data = latest_valid_adc_data; - - // Give user their data (unrolled for speed) - output[0] = data[0]; - output[1] = data[1]; - output[2] = data[2]; - output[3] = data[3]; - output[4] = data[4]; - output[5] = data[5]; - output[6] = data[6]; - output[7] = data[7]; -} - #if defined(TARGET_AMDS) static void adc_sample_all_daughtercards(uint16_t *sample_data_out) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index cfaf95d2..52c8faa3 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -1,5 +1,4 @@ #include "drv_uart.h" -#include "tx.h" #include "defines.h" #include "drv_clock.h" #include "platform.h" @@ -10,9 +9,6 @@ static void MX_USART_UART_Init(UART_HandleTypeDef *huart, USART_TypeDef *handle) UART_HandleTypeDef huart2; UART_HandleTypeDef huart3; -DMA_HandleTypeDef hdma_usart2_tx; -DMA_HandleTypeDef hdma_usart3_tx; - DMA_HandleTypeDef hdma_uart4_rx; DMA_HandleTypeDef hdma_uart5_rx; @@ -45,7 +41,6 @@ volatile bool is_routing_active = false; #endif bool drv_uart_has_dma_data(void) { - // Perform an unprotected, non-atomic peek at the DMA hardware. // Reading these 8-bit values is natively atomic, so it is safe to // evaluate them even if an interrupt is modifying them in the background. uint8_t w1 = GET_W1(); @@ -55,7 +50,7 @@ bool drv_uart_has_dma_data(void) { } void process_routing(void) { - // 1. Load tracking state into local CPU registers for zero-wait-state access + // Load tracking state into local CPU registers uint8_t r1 = tracker1.read_index; uint8_t r2 = tracker2.read_index; uint8_t s1 = tracker1.state; @@ -64,9 +59,9 @@ void process_routing(void) { uint8_t w1 = GET_W1(); uint8_t w2 = GET_W2(); - // Process instantly as long as either buffer has data. No NOP delays! + // Process as long as either buffer has data while ((r1 != w1) || (r2 != w2)) { - // Calculate exactly how many bytes are sitting unread in the DMA buffer. + // Calculate how many bytes are sitting unread in the DMA buffer // Because everything is cast to uint8_t, this math safely handles // circular buffer wrap-around natively (e.g. w4=2, r4=254 -> avail=4) uint8_t avail1 = (uint8_t)(w1 - r1); @@ -75,7 +70,7 @@ void process_routing(void) { // ===================================================================== // OPTIMIZATION 1: DUAL-STREAM FAST PATH (Perfect Interleaving) // ===================================================================== - // If BOTH streams have at least a full 3-byte packet, process them completely + // If both streams have at least a full 3-byte packet, process them completely // interleaved to keep both hardware lines saturated simultaneously. while ((s1 == STATE_IDLE && avail1 >= 3) && (s2 == STATE_IDLE && avail2 >= 3)) { uint8_t h1 = DAISY_RX1_Pool[r1]; @@ -182,7 +177,7 @@ void process_routing(void) { } } - // 5. Store states back + // Store states back tracker1.read_index = r1; tracker2.read_index = r2; tracker1.state = s1; @@ -297,19 +292,10 @@ void DMA2_Stream5_IRQHandler(void) #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" #endif -void DMA1_Stream6_IRQHandler(void) { - HAL_DMA_IRQHandler(&hdma_usart2_tx); -} - void USART2_IRQHandler(void) { HAL_UART_IRQHandler(&huart2); } -// USART3 DMA and UART Interrupts -void DMA1_Stream3_IRQHandler(void) { - HAL_DMA_IRQHandler(&hdma_usart3_tx); -} - void USART3_IRQHandler(void) { HAL_UART_IRQHandler(&huart3); } @@ -329,8 +315,8 @@ void drv_uart_init(void) __HAL_RCC_UART4_CONFIG(RCC_UART4CLKSOURCE_SYSCLK); __HAL_RCC_UART5_CONFIG(RCC_UART5CLKSOURCE_SYSCLK); #elif defined(TARGET_2S) - __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); __HAL_RCC_USART6_CONFIG(RCC_USART6CLKSOURCE_SYSCLK); + __HAL_RCC_USART1_CONFIG(RCC_USART1CLKSOURCE_SYSCLK); #else #error "Please define a target board (TARGET_AMDS or TARGET_2S)!" #endif @@ -463,7 +449,6 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) if (uartHandle->Instance == USART2) { // USART2 clock enable __HAL_RCC_USART2_CLK_ENABLE(); - __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); // USART2 GPIO Configuration @@ -475,34 +460,11 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART2; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); - - // DMA config - check your device's DMA request mapping table - // for the correct stream/channel for USART2_TX - hdma_usart2_tx.Instance = DMA1_Stream6; - hdma_usart2_tx.Instance->CR |= USART_CR3_DDRE; - hdma_usart2_tx.Init.Channel = DMA_CHANNEL_4; - hdma_usart2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // Memory -> UART - hdma_usart2_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart2_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_usart2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart2_tx.Init.Mode = DMA_NORMAL; // Keep it looping - hdma_usart2_tx.Init.Priority = DMA_PRIORITY_LOW; // Let RX have higher priority - - if (HAL_DMA_Init(&hdma_usart2_tx) != HAL_OK) { - PANIC; - } - __HAL_LINKDMA(uartHandle, hdmatx, hdma_usart2_tx); - - // DMA stream IRQ - NVIC_SetPriority(DMA1_Stream6_IRQn, 7); // higher priority than UART - HAL_NVIC_EnableIRQ(DMA1_Stream6_IRQn); } else if (uartHandle->Instance == USART3) { // USART3 clock enable __HAL_RCC_USART3_CLK_ENABLE(); - __HAL_RCC_DMA1_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // USART3 GPIO Configuration @@ -514,28 +476,6 @@ void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF7_USART3; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); - - // DMA config - check your device's DMA request mapping table - // for the correct stream/channel for USART3_TX - hdma_usart3_tx.Instance = DMA1_Stream3; - hdma_usart3_tx.Instance->CR |= USART_CR3_DDRE; - hdma_usart3_tx.Init.Channel = DMA_CHANNEL_4; - hdma_usart3_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; // Memory -> UART - hdma_usart3_tx.Init.PeriphInc = DMA_PINC_DISABLE; - hdma_usart3_tx.Init.MemInc = DMA_MINC_ENABLE; - hdma_usart3_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; - hdma_usart3_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; - hdma_usart3_tx.Init.Mode = DMA_NORMAL; // Keep it looping - hdma_usart3_tx.Init.Priority = DMA_PRIORITY_LOW; // Let RX have higher priority - - if (HAL_DMA_Init(&hdma_usart3_tx) != HAL_OK) { - PANIC; - } - __HAL_LINKDMA(uartHandle, hdmatx, hdma_usart3_tx); - - // DMA stream IRQ - NVIC_SetPriority(DMA1_Stream3_IRQn, 7); // higher priority than UART - HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); } #if defined(TARGET_AMDS) else if (uartHandle->Instance == UART4) { diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index a924c410..8782bd86 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -9,7 +9,6 @@ // Modules #include "adc.h" -#include "tx.h" int main(void) { @@ -24,10 +23,6 @@ int main(void) drv_uart_init(); drv_led_init(); - // Tell the UART to constantly route TX requests to the DMA controller -// huart2.Instance->CR3 |= USART_CR3_DMAT; -// huart3.Instance->CR3 |= USART_CR3_DMAT; - // Initialize the main modules adc_init(); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c deleted file mode 100644 index f5ef2e9e..00000000 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ /dev/null @@ -1,291 +0,0 @@ -#include "tx.h" - -volatile packet_t tx_packets[NUM_SETS * PACKETS_PER_SET]; -volatile bool packet_ready[NUM_SETS * PACKETS_PER_SET]; -bool packet_sent[NUM_SETS * PACKETS_PER_SET]; - -volatile bool sync_event_flag = false; // Set this to true in your EXTI ISR - -void process_transmissions(void) { - // Loop as long as there is data in EITHER queue -// while ((u2_q_tail != u2_q_head) || (u3_q_tail != u3_q_head)) { -// -// // If UART2 has data, pop one byte and push it straight to the hardware -// if (u2_q_tail != u2_q_head) { -// drv_uart_putc_fast(USART2, uart2_dma_queue[u2_q_tail]); -// u2_q_tail = (u2_q_tail + 1) % AMDS_RX_BUF_SIZE; -// } -// -// // If UART3 has data, pop one byte and push it straight to the hardware -// if (u3_q_tail != u3_q_head) { -// drv_uart_putc_fast(USART3, uart3_dma_queue[u3_q_tail]); -// u3_q_tail = (u3_q_tail + 1) % AMDS_RX_BUF_SIZE; -// } -// } -} - - - - - - - - - - - - - - - - - - - - - - - - -// clang-format off - -#define NOP1 asm("nop") -#define NOP2 NOP1;NOP1 -#define NOP4 NOP2;NOP2 -#define NOP8 NOP4;NOP4 -#define NOP16 NOP8;NOP8 -#define NOP32 NOP16;NOP16 -#define NOP64 NOP32;NOP32 -#define NOP128 NOP64;NOP64 -#define NOP256 NOP128;NOP128 - -// clang-format on - -//// Called after ADC conversions have been completed, -//// to send sampled data back to AMDC -//// -//void transmit_samples(void) -//{ -// // 2. Create a local buffer for this transmission "burst" -// static uint8_t tx_data2[36]; -// static uint8_t tx_data3[36]; -// uint8_t idx = 0; -// -// uint16_t bits[8]; -// adc_latest_bits(bits); -// -// for (int i = 0; i < 4; i++) { -// uint8_t header = (i == 0) ? 0x90 : (0x90 | (0x03 & i)); -// -// tx_data2[idx] = header; -// tx_data3[idx] = header; -// idx++; -// -// tx_data2[idx] = (uint8_t)(bits[i] >> 8); // MSB -// tx_data3[idx] = (uint8_t)(bits[i + 4] >> 8); // MSB -// idx++; -// -// tx_data2[idx] = (uint8_t)(bits[i] & 0xFF); // LSB -// tx_data3[idx] = (uint8_t)(bits[i + 4] & 0xFF); // LSB -// idx++; -// } -// -// // 1. Process incoming UARTs first -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// NOP256; -// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); -// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); -// -// uint16_t amds[16] = {1}; -// adc_latest_amds(amds); -// -// // ... Add AMDS data to tx_data if ready ... -// if (amds_samples_ready[0]) { -// for (int i = 0; i < 4; i++) { -// uint8_t header = (i == 0) ? 0x94 : (0x94 | (0x07 & i)); -// -// tx_data2[idx] = header; -// tx_data3[idx] = header; -// idx++; -// -// tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB -// tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB -// idx++; -// -// tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB -// tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB -// idx++; -// } -// -// // Clear flags for this set -// amds_samples_ready[0] = false; -// -// if (amds_samples_ready[1]) { -// for (int i = 0; i < 4; i++) { -// uint8_t header = (i == 0) ? 0x98 : (0x98 | (0x0B & i)); -// -// tx_data2[idx] = header; -// tx_data3[idx] = header; -// idx++; -// -// tx_data2[idx] = (uint8_t)(amds[i] >> 8); // MSB -// tx_data3[idx] = (uint8_t)(amds[i + 4] >> 8); // MSB -// idx++; -// -// tx_data2[idx] = (uint8_t)(amds[i] & 0xFF); // LSB -// tx_data3[idx] = (uint8_t)(amds[i + 4] & 0xFF); // LSB -// idx++; -// } -// -// // Clear flags for this set -// amds_samples_ready[1] = false; -// } -// } -// -// // 4. Trigger the DMA to send exactly 'idx' bytes -// // This function returns immediately while the hardware sends the data -// if (huart2.gState == HAL_UART_STATE_READY && huart3.gState == HAL_UART_STATE_READY) { -// HAL_UART_Transmit_DMA(&huart2, tx_data2, idx); -// HAL_UART_Transmit_DMA(&huart3, tx_data3, idx); -// } -//} - - - - - - -//void transmit_samples(void) -//{ -// // Send header before we compute anything -// // to get the UART warmed up and running! -// uint8_t first_header = 0x90; -// drv_uart_putc_dma(USART2, first_header); -// drv_uart_putc_dma(USART3, first_header); -// -// // Get latest data from ADC driver (non-blocking) -// uint16_t bits[8]; -// adc_latest_bits(bits); -// -// // Send board's own ADC data out over UART -// for (int i = 0; i < 4; i++) { -// uint16_t sample1 = bits[(4 * 0) + i]; -// uint16_t sample2 = bits[(4 * 1) + i]; -// -// // Send header (not the first one) -// if (i > 0) { -// uint8_t header = 0x90; -// header |= (0x03 & i); -// -// drv_uart_putc_dma(USART2, header); -// drv_uart_putc_dma(USART3, header); -// } -// -// // Send ADC sample data MSBs -// drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); -// drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); -// -// // Send ADC sample data LSBs -// drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); -// drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); -// } -// -// process_uart_fifo(UART4_DMA_Pool, &tracker4, 4); -// process_uart_fifo(UART5_DMA_Pool, &tracker5, 5); -// // Now attempt to send AMDS samples (if ready) using same header scheme. -// // adc_latest_amds() will populate the array only when the corresponding -// // amds_samples_ready pairs are set. -// uint16_t amds[16] = {0}; -// adc_latest_amds(amds); -// -// first_header = 0x94; -// -// // First AMDS set: indices 0..7 (requires amds_samples_ready[0] && [1]) -// if (amds_samples_ready[0] && amds_samples_ready[1]) { -// // Send header for this set -// drv_uart_putc_dma(USART2, first_header); -// drv_uart_putc_dma(USART3, first_header); -// -// for (int i = 0; i < 4; i++) { -// if (i > 0) { -// uint8_t header = 0x94; -// header |= (0x07 & i); -// drv_uart_putc_dma(USART2, header); -// drv_uart_putc_dma(USART3, header); -// } -// -// uint16_t sample1 = amds[(4 * 0) + i]; // amds[0..3] -// uint16_t sample2 = amds[(4 * 1) + i]; // amds[4..7] -// -// // Send ADC sample data MSBs -// drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); -// drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); -// -// // Send ADC sample data LSBs -// drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); -// drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); -// } -// -// // Clear flags for this set -// amds_samples_ready[0] = false; -// amds_samples_ready[1] = false; -// -// first_header = 0x98; -// -// // Second AMDS set: indices 8..15 (requires amds_samples_ready[2] && [3]) -// // Only if the first set was successful -// if (amds_samples_ready[2] && amds_samples_ready[3]) { -// drv_uart_putc_dma(USART2, first_header); -// drv_uart_putc_dma(USART3, first_header); -// -// for (int i = 0; i < 4; i++) { -// if (i > 0) { -// uint8_t header = 0x98; -// header |= (0x0B & i); -// drv_uart_putc_dma(USART2, header); -// drv_uart_putc_dma(USART3, header); -// } -// -// uint16_t sample1 = amds[8 + (4 * 0) + i]; // amds[8..11] -// uint16_t sample2 = amds[8 + (4 * 1) + i]; // amds[12..15] -// -// // Send ADC sample data MSBs -// drv_uart_putc_dma(USART2, (uint8_t)(sample1 >> 8)); -// drv_uart_putc_dma(USART3, (uint8_t)(sample2 >> 8)); -// -// // Send ADC sample data LSBs -// drv_uart_putc_dma(USART2, (uint8_t)(sample1 & 0x00FF)); -// drv_uart_putc_dma(USART3, (uint8_t)(sample2 & 0x00FF)); -// } -// -// // Clear flags for this set -// amds_samples_ready[2] = false; -// amds_samples_ready[3] = false; -// } -// } -// -// // Wait for entire UART transmission to complete -// drv_uart_wait_TC(USART2); -// drv_uart_wait_TC(USART3); -// -// uart4_amds_sample_count = 0; -// uart5_amds_sample_count = 0; -//} - - From 4b66c69166cf2364d6b0763c4fce8170af2782e7 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 5 May 2026 15:41:30 -0500 Subject: [PATCH 58/72] add delays to transmission --- .../Firmware/motherboard_v1/Core/Src/adc.c | 28 +++++++++++++++---- .../motherboard_v1/Core/Src/drv_uart.c | 10 +++++++ .../Firmware/motherboard_v1/Core/Src/main.c | 2 +- 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 29545877..b16f1ea5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -360,20 +360,19 @@ void adc_sample_and_transmit_1_5_fast_path(uint16_t *sample_data_out) // 2. Start the SCLK drv_spi_start_read_two_16bits(SPI5); - // Timing optimization: send our first header bytes here because code after this is waiting - drv_uart_putc_fast(USART2, 0x90); - drv_uart_putc_fast(USART3, 0x90); - // 3. Wait and read first ADC data (Channels 0, 1, 2, 3) drv_spi_finish_read_one_16bits(SPI5, &sample_data_out[0]); //Timing optimization: wait for only the last SPI that we started drv_spi_wait_for_RX(SPI5); + drv_uart_putc_fast(USART2, 0x90); + drv_uart_putc_fast(USART3, 0x90); + // Read second ADC data (Channels 4, 5, 6, 7) drv_spi_get_DR(SPI5, &sample_data_out[4]); - //don't send first header because we sent it earlier (timing optimization) + // don't send first header drv_uart_putc_fast(USART2, (uint8_t)(sample_data_out[0] >> 8)); drv_uart_putc_fast(USART3, (uint8_t)(sample_data_out[4] >> 8)); @@ -449,6 +448,25 @@ void EXTI15_10_IRQHandler(void) if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[4])); } +// uint32_t start_cycles = DWT->CYCCNT; +// +// // Calculate 1 microseconds in CPU cycles (integer math safe) +// uint32_t wait_cycles = (SystemCoreClock / 1000000); +// +// // Deterministic wait for exactly 1000ns using hardware cycles, not NOPs +// while ((DWT->CYCCNT - start_cycles) < wait_cycles) { +// // Spin perfectly safely +// } +// +//// NOP128; +//// NOP64; +//// NOP8; + + uint32_t start_cycles = DWT->CYCCNT; + uint32_t wait_cycles = (SystemCoreClock / 1000000); + + while ((DWT->CYCCNT - start_cycles) < wait_cycles); + //Handle any DMA data that has been received from daisy chain try_process_routing(); // This try function is thread safe diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 52c8faa3..088b3ead 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -93,6 +93,16 @@ void process_routing(void) { r2 += 3; avail1 -= 3; avail2 -= 3; + + uint32_t start_cycles = DWT->CYCCNT; + + // Calculate 1 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 2; + + // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs + while ((DWT->CYCCNT - start_cycles) < wait_cycles) { + // Spin perfectly safely + } } else { break; // Misaligned or corrupted header, break to let the slow-path handle it } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 8782bd86..abd5373a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -52,7 +52,7 @@ int main(void) // is actually data waiting in the DMA buffers to help the // external IRQ retain higher priority access to process_routing if (drv_uart_has_dma_data()) - try_process_routing(); // This try function is thread safe + try_process_routing(); // This try function is thread safe // Handle LEDs if (HAL_GetTick() - ledDelta >= 250) { From d9d065b17b1c8443f8c2989bec98f7d77c01473b Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Tue, 5 May 2026 16:14:00 -0500 Subject: [PATCH 59/72] add docs changes to readme --- Mainboard/Firmware/README.md | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/Mainboard/Firmware/README.md b/Mainboard/Firmware/README.md index b05666ef..d69aa095 100644 --- a/Mainboard/Firmware/README.md +++ b/Mainboard/Firmware/README.md @@ -20,30 +20,20 @@ This tool is analogous to the Xilinx SDK tool (for the AMDC). It is effectively To develop code for STM32 processors: -#### Generating New Projects +### Testing / Debugging Code -1. Use the STM32CubeIDE to generate a new project -2. When configuring this project, select the exact MCU device which you are targetting (the mainboard uses `STM32F765ZGT6`) -3. Open the CubeMX perspective (i.e. `*.ioc` file) and configure all desired peripherals (SPIs, UARTs, ETH, etc) -4. Change to the clock configuration tab and use the GUI to configure the PLL settings -5. Generate initialization code to boot-strap your project. This will configure the clock and peripherals like you specified. +1. Use the IDE to compile your code and ensure there are no errors. +2. To flash the hardware, plug in a SWD debugger device to your PC + board (highly recommend [`STLINK-V3SET`](https://www.digikey.com/product-detail/en/stmicroelectronics/STLINK-V3SET/497-18216-ND/9636028)) +3. Configure a debug session in the IDE +4. Run the debug sessions. This will flash the MCU and start the code (probably breakpoint at `main()`) -#### Writing Code - -6. Now that you have a base project, write all your application-specific code... - -#### Testing / Debugging Code - -7. Use the IDE to compile your code and ensure there are no errors. -8. To flash the hardware, plug in a SWD debugger device to your PC + board (highly recommend [`STLINK-V3SET`](https://www.digikey.com/product-detail/en/stmicroelectronics/STLINK-V3SET/497-18216-ND/9636028)) -9. Configure a debug session in the IDE -10. Run the debug sessions. This will flash the MCU and start the code (probably breakpoint at `main()`) +For more detailed instructions on programming the AMDS, please refer to the [AMDS Documentation](https://docs.amdc.dev/accessories/amds/index.html). NOTE: The STM32 devices are typically programmed into non-volatile memory. Therefore, there is no seperate "flashing" step. Every time you upload code, it is permanantely stored on the processor. You can power cycle the device and your code will start running again. ## Mainboard Firmware Design -The mainboard firmware is fairly simple, yet very specialized for the application. Before changing *anything* in the code, make sure you understand how it works. Practically every line of the code is optimized for speed and efficiency! Using a multi-channel logic analyzer / oscilloscope is absolutely required when updating the mainboard firmware to validate code timing. +The mainboard firmware is fairly simple, yet very specialized for the application. Before changing *anything* in the code, make sure you understand how it works. Practically every line of the code is optimized for speed and efficiency! Using a multi-channel logic analyzer / oscilloscope is absolutely required when updating the mainboard firmware to validate code timing. Please refer to the [Firmware Architecture Documentation](https://docs.amdc.dev/accessories/amds/firmware/index.html) for more information. **Do not blindly change the code.** From 264615fd13f8b3025eafd8ceabb848f3893c1f2f Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 6 May 2026 11:32:50 -0500 Subject: [PATCH 60/72] add debugging logic and delays --- .../Firmware/motherboard_v1/Core/Inc/adc.h | 3 ++ .../motherboard_v1/Core/Inc/drv_uart.h | 2 + .../Firmware/motherboard_v1/Core/Src/adc.c | 40 ++++++++++++------- .../motherboard_v1/Core/Src/drv_uart.c | 4 +- .../Firmware/motherboard_v1/Core/Src/main.c | 4 +- 5 files changed, 36 insertions(+), 17 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h index 7e64d264..9aa3ea1e 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h @@ -5,4 +5,7 @@ void adc_init(void); +extern int main_inc; +extern int int_inc; + #endif // ADC_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h index f277e8da..6e22a5ac 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -52,6 +52,8 @@ extern volatile bool is_routing_active; // Add this prototype bool drv_uart_has_dma_data(void); +#define GPIO_TOGGLE_PIN(port, pin) ((port)->BSRR = ((port)->ODR & (pin)) ? ((pin) << 16) : (pin)) + void process_routing(void); /** diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index b16f1ea5..c58974a5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -383,6 +383,9 @@ void adc_sample_and_transmit_1_5_fast_path(uint16_t *sample_data_out) SET_PIN_CONVST56_LOW; } +int main_inc = 0; +int int_inc = 0; + // This ISR is for the FBC and is triggered by the // AMDC to sync the ADCconversions to the AMDC PWM // carrier waveform. In this ISR, on 2 ADCs should be sampled. @@ -448,25 +451,22 @@ void EXTI15_10_IRQHandler(void) if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[4])); } -// uint32_t start_cycles = DWT->CYCCNT; -// -// // Calculate 1 microseconds in CPU cycles (integer math safe) -// uint32_t wait_cycles = (SystemCoreClock / 1000000); -// -// // Deterministic wait for exactly 1000ns using hardware cycles, not NOPs -// while ((DWT->CYCCNT - start_cycles) < wait_cycles) { -// // Spin perfectly safely -// } -// -//// NOP128; -//// NOP64; -//// NOP8; +// NOP128; +// NOP64; +// NOP8; uint32_t start_cycles = DWT->CYCCNT; - uint32_t wait_cycles = (SystemCoreClock / 1000000); - while ((DWT->CYCCNT - start_cycles) < wait_cycles); + // Calculate 1 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000) / 10; + // Deterministic wait for exactly 1000ns using hardware cycles, not NOPs + while ((DWT->CYCCNT - start_cycles) < wait_cycles) { + // Spin perfectly safely + } +// +// int_inc++; +// main_inc--; //Handle any DMA data that has been received from daisy chain try_process_routing(); // This try function is thread safe @@ -548,10 +548,14 @@ static void setup_pin_SYNC_ADC(void) __HAL_RCC_GPIOB_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); + __HAL_RCC_GPIOC_CLK_ENABLE(); + // Configure GPIO pin Output Level HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET); HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); + // Configure GPIO pins GPIO_InitStruct.Pin = GPIO_PIN_11; GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING; @@ -565,6 +569,12 @@ static void setup_pin_SYNC_ADC(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); + GPIO_InitStruct.Pin = GPIO_PIN_6; + GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); + // EXTI interrupt init HAL_NVIC_SetPriority(EXTI15_10_IRQn, 10, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 088b3ead..81932e7a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -50,6 +50,7 @@ bool drv_uart_has_dma_data(void) { } void process_routing(void) { + GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_6); // Load tracking state into local CPU registers uint8_t r1 = tracker1.read_index; uint8_t r2 = tracker2.read_index; @@ -97,12 +98,13 @@ void process_routing(void) { uint32_t start_cycles = DWT->CYCCNT; // Calculate 1 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000) * 2; + uint32_t wait_cycles = (SystemCoreClock / 1000000); // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs while ((DWT->CYCCNT - start_cycles) < wait_cycles) { // Spin perfectly safely } + GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_6); } else { break; // Misaligned or corrupted header, break to let the slow-path handle it } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index abd5373a..4b490042 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -51,8 +51,10 @@ int main(void) // Only attempt to grab the lock and route data if there // is actually data waiting in the DMA buffers to help the // external IRQ retain higher priority access to process_routing - if (drv_uart_has_dma_data()) + if (drv_uart_has_dma_data()) { +// main_inc++; try_process_routing(); // This try function is thread safe + } // Handle LEDs if (HAL_GetTick() - ledDelta >= 250) { From de9a3ce50a3882bdd02705266e2ccc1c677a0849 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 6 May 2026 15:07:22 -0500 Subject: [PATCH 61/72] replace delays with timeouts --- .../Firmware/motherboard_v1/Core/Inc/adc.h | 3 -- .../Firmware/motherboard_v1/Core/Src/adc.c | 19 -------- .../motherboard_v1/Core/Src/drv_uart.c | 47 +++++++++++++++---- .../Firmware/motherboard_v1/Core/Src/main.c | 4 +- 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h index 9aa3ea1e..7e64d264 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h @@ -5,7 +5,4 @@ void adc_init(void); -extern int main_inc; -extern int int_inc; - #endif // ADC_H diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index c58974a5..fbc17686 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -383,9 +383,6 @@ void adc_sample_and_transmit_1_5_fast_path(uint16_t *sample_data_out) SET_PIN_CONVST56_LOW; } -int main_inc = 0; -int int_inc = 0; - // This ISR is for the FBC and is triggered by the // AMDC to sync the ADCconversions to the AMDC PWM // carrier waveform. In this ISR, on 2 ADCs should be sampled. @@ -451,22 +448,6 @@ void EXTI15_10_IRQHandler(void) if (u3) drv_uart_putc_fast(USART3, (uint8_t)(new_data[4])); } -// NOP128; -// NOP64; -// NOP8; - - uint32_t start_cycles = DWT->CYCCNT; - - // Calculate 1 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000) / 10; - - // Deterministic wait for exactly 1000ns using hardware cycles, not NOPs - while ((DWT->CYCCNT - start_cycles) < wait_cycles) { - // Spin perfectly safely - } -// -// int_inc++; -// main_inc--; //Handle any DMA data that has been received from daisy chain try_process_routing(); // This try function is thread safe diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 81932e7a..0ce20444 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -68,6 +68,28 @@ void process_routing(void) { uint8_t avail1 = (uint8_t)(w1 - r1); uint8_t avail2 = (uint8_t)(w2 - r2); + + if (avail1 < 3 || avail2 < 3) { + // 2us timeout to let us receive enough data for dual-stream fast path + uint32_t start_cycles = DWT->CYCCNT; + + // Calculate 2 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000); + + while ((avail1 >= 1 && avail1 <= 3) || (avail2 >= 1 && avail2 <= 3)) { + w1 = GET_W1(); + w2 = GET_W2(); + + avail1 = (uint8_t)(w1 - r1); + avail2 = (uint8_t)(w2 - r2); + + // Break if we reach the 2us timeout + if ((DWT->CYCCNT - start_cycles) > wait_cycles) { + break; + } + } + } + // ===================================================================== // OPTIMIZATION 1: DUAL-STREAM FAST PATH (Perfect Interleaving) // ===================================================================== @@ -95,16 +117,25 @@ void process_routing(void) { avail1 -= 3; avail2 -= 3; - uint32_t start_cycles = DWT->CYCCNT; + if (avail1 < 3 || avail2 < 3) { + uint32_t start_cycles = DWT->CYCCNT; - // Calculate 1 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000); + // Calculate 2 microseconds in CPU cycles (integer math safe) + uint32_t wait_cycles = (SystemCoreClock / 1000000); - // Deterministic wait for exactly 1300ns using hardware cycles, not NOPs - while ((DWT->CYCCNT - start_cycles) < wait_cycles) { - // Spin perfectly safely - } - GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_6); + while ((avail1 >= 1 && avail1 <= 3) || (avail2 >= 1 && avail2 <= 3)) { + w1 = GET_W1(); + w2 = GET_W2(); + + avail1 = (uint8_t)(w1 - r1); + avail2 = (uint8_t)(w2 - r2); + + // Break if we reach the 2us timeout + if ((DWT->CYCCNT - start_cycles) > wait_cycles) { + break; + } + } + } } else { break; // Misaligned or corrupted header, break to let the slow-path handle it } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 4b490042..abd5373a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -51,10 +51,8 @@ int main(void) // Only attempt to grab the lock and route data if there // is actually data waiting in the DMA buffers to help the // external IRQ retain higher priority access to process_routing - if (drv_uart_has_dma_data()) { -// main_inc++; + if (drv_uart_has_dma_data()) try_process_routing(); // This try function is thread safe - } // Handle LEDs if (HAL_GetTick() - ledDelta >= 250) { From e3584b438936c490ceec82c7d7a28691440f16c9 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 6 May 2026 16:46:12 -0500 Subject: [PATCH 62/72] add conditional to handler and switch led control in main --- .../Firmware/motherboard_v1/Core/Src/adc.c | 3 +- .../Firmware/motherboard_v1/Core/Src/main.c | 44 +++++++++++++------ 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index fbc17686..b6a2d824 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -449,7 +449,8 @@ void EXTI15_10_IRQHandler(void) } //Handle any DMA data that has been received from daisy chain - try_process_routing(); // This try function is thread safe + if (drv_uart_has_dma_data()) + try_process_routing(); // This try function is thread safe // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index abd5373a..7ad6d394 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -28,7 +28,13 @@ int main(void) // Infinite loop (all real work is done in ISRs) uint8_t led = 0; - uint32_t ledDelta = HAL_GetTick(); +// uint32_t ledDelta = HAL_GetTick(); + + // Use DWT cycle counter instead of HAL_GetTick() + uint32_t ledDelta = DWT->CYCCNT; + + // Calculate how many CPU cycles are in 250ms. + uint32_t cyclesPer250ms = SystemCoreClock / 4; // Disable the SysTick ISR // @@ -37,7 +43,7 @@ int main(void) // we do not need it to run during operation! // // Set bit 0 to 0 -// SysTick->CTRL &= 0xFFFFFFFE; + SysTick->CTRL &= 0xFFFFFFFE; // Enable the Cortex-M7 DWT Cycle Counter for perfect hardware delays CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk; @@ -54,17 +60,29 @@ int main(void) if (drv_uart_has_dma_data()) try_process_routing(); // This try function is thread safe - // Handle LEDs - if (HAL_GetTick() - ledDelta >= 250) { - ledDelta = HAL_GetTick(); - drv_led_clear(); - drv_led_on(1 << led); - drv_led_display(); - - if (++led >= DRV_LED_NUM_TOTAL) { - led = 0; - } - } +// // Handle LEDs +// if (HAL_GetTick() - ledDelta >= 250) { +// ledDelta = HAL_GetTick(); +// drv_led_clear(); +// drv_led_on(1 << led); +// drv_led_display(); +// +// if (++led >= DRV_LED_NUM_TOTAL) { +// led = 0; +// } +// } + // Handle LEDs using hardware cycle counts + if (DWT->CYCCNT - ledDelta >= cyclesPer250ms) { + ledDelta = DWT->CYCCNT; + drv_led_clear(); + + drv_led_on(1 << led); + drv_led_display(); + + if (++led >= DRV_LED_NUM_TOTAL) { + led = 0; + } + } } } From 8aa489d612ba4830a983766a1019b956380653ed Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Wed, 6 May 2026 17:06:27 -0500 Subject: [PATCH 63/72] cleanup the code --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 3 ++- .../Firmware/motherboard_v1/Core/Src/drv_uart.c | 5 ++--- Mainboard/Firmware/motherboard_v1/Core/Src/main.c | 12 ------------ 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index b6a2d824..03323fe5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -282,7 +282,8 @@ void EXTI3_IRQHandler(void) } // Handle any DMA data that has been received from daisy chain - try_process_routing(); + if (drv_uart_has_dma_data()) + try_process_routing(); NVIC_ClearPendingIRQ(EXTI3_IRQn); __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 0ce20444..0e21c73a 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -50,7 +50,6 @@ bool drv_uart_has_dma_data(void) { } void process_routing(void) { - GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_6); // Load tracking state into local CPU registers uint8_t r1 = tracker1.read_index; uint8_t r2 = tracker2.read_index; @@ -74,7 +73,7 @@ void process_routing(void) { uint32_t start_cycles = DWT->CYCCNT; // Calculate 2 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000); + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 2; while ((avail1 >= 1 && avail1 <= 3) || (avail2 >= 1 && avail2 <= 3)) { w1 = GET_W1(); @@ -121,7 +120,7 @@ void process_routing(void) { uint32_t start_cycles = DWT->CYCCNT; // Calculate 2 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000); + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 2; while ((avail1 >= 1 && avail1 <= 3) || (avail2 >= 1 && avail2 <= 3)) { w1 = GET_W1(); diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c index 7ad6d394..2970d009 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/main.c @@ -28,7 +28,6 @@ int main(void) // Infinite loop (all real work is done in ISRs) uint8_t led = 0; -// uint32_t ledDelta = HAL_GetTick(); // Use DWT cycle counter instead of HAL_GetTick() uint32_t ledDelta = DWT->CYCCNT; @@ -60,17 +59,6 @@ int main(void) if (drv_uart_has_dma_data()) try_process_routing(); // This try function is thread safe -// // Handle LEDs -// if (HAL_GetTick() - ledDelta >= 250) { -// ledDelta = HAL_GetTick(); -// drv_led_clear(); -// drv_led_on(1 << led); -// drv_led_display(); -// -// if (++led >= DRV_LED_NUM_TOTAL) { -// led = 0; -// } -// } // Handle LEDs using hardware cycle counts if (DWT->CYCCNT - ledDelta >= cyclesPer250ms) { ledDelta = DWT->CYCCNT; From 161bdd5967219398d563bf424a4026a63be11605 Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Thu, 7 May 2026 17:18:08 -0500 Subject: [PATCH 64/72] add more debugging logic --- Mainboard/Firmware/motherboard_v1/Core/Src/adc.c | 6 +++--- Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c | 7 +++++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c index 03323fe5..c4d72353 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c @@ -450,8 +450,7 @@ void EXTI15_10_IRQHandler(void) } //Handle any DMA data that has been received from daisy chain - if (drv_uart_has_dma_data()) - try_process_routing(); // This try function is thread safe + try_process_routing(); // This try function is thread safe // Clear all pending IRQs for ADC conversions at the // end of this ISR so that the system realigns the @@ -538,6 +537,7 @@ static void setup_pin_SYNC_ADC(void) HAL_GPIO_WritePin(GPIOG, GPIO_PIN_14, GPIO_PIN_SET); HAL_GPIO_WritePin(GPIOC, GPIO_PIN_6, GPIO_PIN_RESET); + HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET); // Configure GPIO pins GPIO_InitStruct.Pin = GPIO_PIN_11; @@ -552,7 +552,7 @@ static void setup_pin_SYNC_ADC(void) GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; HAL_GPIO_Init(GPIOG, &GPIO_InitStruct); - GPIO_InitStruct.Pin = GPIO_PIN_6; + GPIO_InitStruct.Pin = GPIO_PIN_6 | GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c index 0e21c73a..10e6a453 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -50,6 +50,7 @@ bool drv_uart_has_dma_data(void) { } void process_routing(void) { + GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_6); // Load tracking state into local CPU registers uint8_t r1 = tracker1.read_index; uint8_t r2 = tracker2.read_index; @@ -73,7 +74,7 @@ void process_routing(void) { uint32_t start_cycles = DWT->CYCCNT; // Calculate 2 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000) * 2; + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; while ((avail1 >= 1 && avail1 <= 3) || (avail2 >= 1 && avail2 <= 3)) { w1 = GET_W1(); @@ -84,6 +85,7 @@ void process_routing(void) { // Break if we reach the 2us timeout if ((DWT->CYCCNT - start_cycles) > wait_cycles) { + GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_7); break; } } @@ -120,7 +122,7 @@ void process_routing(void) { uint32_t start_cycles = DWT->CYCCNT; // Calculate 2 microseconds in CPU cycles (integer math safe) - uint32_t wait_cycles = (SystemCoreClock / 1000000) * 2; + uint32_t wait_cycles = (SystemCoreClock / 1000000) * 13 / 10; while ((avail1 >= 1 && avail1 <= 3) || (avail2 >= 1 && avail2 <= 3)) { w1 = GET_W1(); @@ -131,6 +133,7 @@ void process_routing(void) { // Break if we reach the 2us timeout if ((DWT->CYCCNT - start_cycles) > wait_cycles) { + GPIO_TOGGLE_PIN(GPIOC, GPIO_PIN_7); break; } } From 2356cc2c885335c055feef9c57e6f83d04a439fa Mon Sep 17 00:00:00 2001 From: Mohamed-dek Mohamed Date: Fri, 8 May 2026 12:41:40 -0500 Subject: [PATCH 65/72] fix indexing for timeout conditions --- Mainboard/Firmware/motherboard_v1/.cproject | 2 +- .../Firmware/motherboard_v1/Core/Src/adc.c | 11 +++++++++++ .../Firmware/motherboard_v1/Core/Src/drv_uart.c | 17 ++++++++++------- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/Mainboard/Firmware/motherboard_v1/.cproject b/Mainboard/Firmware/motherboard_v1/.cproject index 3033ecf8..c7ab5132 100644 --- a/Mainboard/Firmware/motherboard_v1/.cproject +++ b/Mainboard/Firmware/motherboard_v1/.cproject @@ -301,7 +301,7 @@ - + - + - + - + diff --git a/Mainboard/Firmware/motherboard_v1/.github/workflows/main.yml b/Mainboard/Firmware/mainboard/.github/workflows/main.yml similarity index 100% rename from Mainboard/Firmware/motherboard_v1/.github/workflows/main.yml rename to Mainboard/Firmware/mainboard/.github/workflows/main.yml diff --git a/Mainboard/Firmware/motherboard_v1/.gitignore b/Mainboard/Firmware/mainboard/.gitignore similarity index 100% rename from Mainboard/Firmware/motherboard_v1/.gitignore rename to Mainboard/Firmware/mainboard/.gitignore diff --git a/Mainboard/Firmware/motherboard_v1/.mxproject b/Mainboard/Firmware/mainboard/.mxproject similarity index 92% rename from Mainboard/Firmware/motherboard_v1/.mxproject rename to Mainboard/Firmware/mainboard/.mxproject index 1612937d..d510d269 100644 --- a/Mainboard/Firmware/motherboard_v1/.mxproject +++ b/Mainboard/Firmware/mainboard/.mxproject @@ -9,25 +9,25 @@ CDefines=USE_HAL_DRIVER;STM32F765xx;USE_HAL_DRIVER;USE_HAL_DRIVER; [PreviousGenFiles] AdvancedFolderStructure=true HeaderFileListSize=7 -HeaderFiles#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/gpio.h -HeaderFiles#1=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/i2c.h -HeaderFiles#2=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/spi.h -HeaderFiles#3=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/usart.h -HeaderFiles#4=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/stm32f7xx_it.h -HeaderFiles#5=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h -HeaderFiles#6=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc/main.h +HeaderFiles#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/gpio.h +HeaderFiles#1=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/i2c.h +HeaderFiles#2=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/spi.h +HeaderFiles#3=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/usart.h +HeaderFiles#4=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/stm32f7xx_it.h +HeaderFiles#5=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/stm32f7xx_hal_conf.h +HeaderFiles#6=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc/main.h HeaderFolderListSize=1 -HeaderPath#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Inc +HeaderPath#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Inc HeaderFiles=; SourceFileListSize=7 -SourceFiles#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/gpio.c -SourceFiles#1=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/i2c.c -SourceFiles#2=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/spi.c -SourceFiles#3=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/usart.c -SourceFiles#4=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/stm32f7xx_it.c -SourceFiles#5=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/stm32f7xx_hal_msp.c -SourceFiles#6=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src/main.c +SourceFiles#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/gpio.c +SourceFiles#1=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/i2c.c +SourceFiles#2=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/spi.c +SourceFiles#3=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/usart.c +SourceFiles#4=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/stm32f7xx_it.c +SourceFiles#5=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/stm32f7xx_hal_msp.c +SourceFiles#6=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src/main.c SourceFolderListSize=1 -SourcePath#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/motherboard_v1/Core/Src +SourcePath#0=C:/Users/npetersen2/STM32CubeIDE/workspace_1.3.0/mainboard/Core/Src SourceFiles=; diff --git a/Mainboard/Firmware/motherboard_v1/.project b/Mainboard/Firmware/mainboard/.project similarity index 97% rename from Mainboard/Firmware/motherboard_v1/.project rename to Mainboard/Firmware/mainboard/.project index ce44526f..46f68d3f 100644 --- a/Mainboard/Firmware/motherboard_v1/.project +++ b/Mainboard/Firmware/mainboard/.project @@ -1,6 +1,6 @@ - motherboard_v1 + mainboard diff --git a/Mainboard/Firmware/mainboard/.settings/com.st.stm32cube.ide.mcu.sfrview.prefs b/Mainboard/Firmware/mainboard/.settings/com.st.stm32cube.ide.mcu.sfrview.prefs new file mode 100644 index 00000000..98a69fc7 --- /dev/null +++ b/Mainboard/Firmware/mainboard/.settings/com.st.stm32cube.ide.mcu.sfrview.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +sfrviewstate={"fFavorites"\:{"fLists"\:{}},"fProperties"\:{"fNodeProperties"\:{}}} diff --git a/Mainboard/Firmware/motherboard_v1/.settings/stm32cubeide.project.prefs b/Mainboard/Firmware/mainboard/.settings/stm32cubeide.project.prefs similarity index 100% rename from Mainboard/Firmware/motherboard_v1/.settings/stm32cubeide.project.prefs rename to Mainboard/Firmware/mainboard/.settings/stm32cubeide.project.prefs diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h b/Mainboard/Firmware/mainboard/Core/Inc/adc.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h rename to Mainboard/Firmware/mainboard/Core/Inc/adc.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/defines.h b/Mainboard/Firmware/mainboard/Core/Inc/defines.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/defines.h rename to Mainboard/Firmware/mainboard/Core/Inc/defines.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_clock.h b/Mainboard/Firmware/mainboard/Core/Inc/drv_clock.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/drv_clock.h rename to Mainboard/Firmware/mainboard/Core/Inc/drv_clock.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_gpio.h b/Mainboard/Firmware/mainboard/Core/Inc/drv_gpio.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/drv_gpio.h rename to Mainboard/Firmware/mainboard/Core/Inc/drv_gpio.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_i2c.h b/Mainboard/Firmware/mainboard/Core/Inc/drv_i2c.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/drv_i2c.h rename to Mainboard/Firmware/mainboard/Core/Inc/drv_i2c.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_led.h b/Mainboard/Firmware/mainboard/Core/Inc/drv_led.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/drv_led.h rename to Mainboard/Firmware/mainboard/Core/Inc/drv_led.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_spi.h b/Mainboard/Firmware/mainboard/Core/Inc/drv_spi.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/drv_spi.h rename to Mainboard/Firmware/mainboard/Core/Inc/drv_spi.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h b/Mainboard/Firmware/mainboard/Core/Inc/drv_uart.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h rename to Mainboard/Firmware/mainboard/Core/Inc/drv_uart.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/platform.h b/Mainboard/Firmware/mainboard/Core/Inc/platform.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/platform.h rename to Mainboard/Firmware/mainboard/Core/Inc/platform.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h b/Mainboard/Firmware/mainboard/Core/Inc/stm32f7xx_hal_conf.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h rename to Mainboard/Firmware/mainboard/Core/Inc/stm32f7xx_hal_conf.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_it.h b/Mainboard/Firmware/mainboard/Core/Inc/stm32f7xx_it.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_it.h rename to Mainboard/Firmware/mainboard/Core/Inc/stm32f7xx_it.h diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c b/Mainboard/Firmware/mainboard/Core/Src/adc.c similarity index 99% rename from Mainboard/Firmware/motherboard_v1/Core/Src/adc.c rename to Mainboard/Firmware/mainboard/Core/Src/adc.c index 975b3dad..92abcd83 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/adc.c +++ b/Mainboard/Firmware/mainboard/Core/Src/adc.c @@ -210,7 +210,7 @@ void adc_sample_and_transmit_fast_path(uint16_t *sample_data_out) // This ISR is triggered by the AMDC to sync the ADC // conversions to the AMDC PWM carrier waveform. In -// this ISR, all the motherboard ADCs should be sampled. +// this ISR, all the mainboard ADCs should be sampled. void EXTI3_IRQHandler(void) { // alert daisy chained AMDSs to begin converting @@ -511,7 +511,7 @@ static void setup_pin_CONVST(void) static void setup_pin_SYNC_ADC(void) { // ADC Sync is a square wave input where every edge should - // trigger a sampling event from the motherboard ADCs. + // trigger a sampling event from the mainboard ADCs. // // These edges are aligned to the PWM carrier on the AMDC. diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_clock.c b/Mainboard/Firmware/mainboard/Core/Src/drv_clock.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/drv_clock.c rename to Mainboard/Firmware/mainboard/Core/Src/drv_clock.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_gpio.c b/Mainboard/Firmware/mainboard/Core/Src/drv_gpio.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/drv_gpio.c rename to Mainboard/Firmware/mainboard/Core/Src/drv_gpio.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_i2c.c b/Mainboard/Firmware/mainboard/Core/Src/drv_i2c.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/drv_i2c.c rename to Mainboard/Firmware/mainboard/Core/Src/drv_i2c.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_led.c b/Mainboard/Firmware/mainboard/Core/Src/drv_led.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/drv_led.c rename to Mainboard/Firmware/mainboard/Core/Src/drv_led.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_spi.c b/Mainboard/Firmware/mainboard/Core/Src/drv_spi.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/drv_spi.c rename to Mainboard/Firmware/mainboard/Core/Src/drv_spi.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c b/Mainboard/Firmware/mainboard/Core/Src/drv_uart.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c rename to Mainboard/Firmware/mainboard/Core/Src/drv_uart.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/main.c b/Mainboard/Firmware/mainboard/Core/Src/main.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/main.c rename to Mainboard/Firmware/mainboard/Core/Src/main.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/stm32f7xx_it.c b/Mainboard/Firmware/mainboard/Core/Src/stm32f7xx_it.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/stm32f7xx_it.c rename to Mainboard/Firmware/mainboard/Core/Src/stm32f7xx_it.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/syscalls.c b/Mainboard/Firmware/mainboard/Core/Src/syscalls.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/syscalls.c rename to Mainboard/Firmware/mainboard/Core/Src/syscalls.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/sysmem.c b/Mainboard/Firmware/mainboard/Core/Src/sysmem.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/sysmem.c rename to Mainboard/Firmware/mainboard/Core/Src/sysmem.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/system_stm32f7xx.c b/Mainboard/Firmware/mainboard/Core/Src/system_stm32f7xx.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Src/system_stm32f7xx.c rename to Mainboard/Firmware/mainboard/Core/Src/system_stm32f7xx.c diff --git a/Mainboard/Firmware/motherboard_v1/Core/Startup/startup_stm32f765zgtx.s b/Mainboard/Firmware/mainboard/Core/Startup/startup_stm32f765zgtx.s similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Core/Startup/startup_stm32f765zgtx.s rename to Mainboard/Firmware/mainboard/Core/Startup/startup_stm32f765zgtx.s diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f765xx.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f765xx.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f765xx.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f765xx.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f7xx.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f7xx.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f7xx.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Device/ST/STM32F7xx/Include/stm32f7xx.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Device/ST/STM32F7xx/Include/system_stm32f7xx.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Device/ST/STM32F7xx/Include/system_stm32f7xx.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Device/ST/STM32F7xx/Include/system_stm32f7xx.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Device/ST/STM32F7xx/Include/system_stm32f7xx.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_armcc.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_armcc.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_armcc.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_armcc.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_armclang.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_armclang.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_armclang.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_armclang.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_compiler.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_compiler.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_compiler.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_compiler.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_gcc.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_gcc.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_gcc.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_gcc.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_iccarm.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_iccarm.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_iccarm.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_iccarm.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_version.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_version.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/cmsis_version.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/cmsis_version.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_armv8mbl.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_armv8mbl.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_armv8mbl.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_armv8mbl.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_armv8mml.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_armv8mml.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_armv8mml.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_armv8mml.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm0.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm0.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm0.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm0.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm0plus.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm0plus.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm0plus.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm0plus.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm1.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm1.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm1.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm1.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm23.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm23.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm23.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm23.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm3.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm3.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm3.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm3.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm33.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm33.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm33.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm33.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm4.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm4.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm4.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm4.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm7.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm7.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_cm7.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_cm7.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_sc000.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_sc000.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_sc000.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_sc000.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_sc300.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_sc300.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/core_sc300.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/core_sc300.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/mpu_armv7.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/mpu_armv7.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/mpu_armv7.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/mpu_armv7.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/mpu_armv8.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/mpu_armv8.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/mpu_armv8.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/mpu_armv8.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/tz_context.h b/Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/tz_context.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/CMSIS/Include/tz_context.h rename to Mainboard/Firmware/mainboard/Drivers/CMSIS/Include/tz_context.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/Legacy/stm32_hal_legacy.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_cortex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_cortex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_cortex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_cortex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_def.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_def.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_def.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_def.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_dma_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_exti.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_exti.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_exti.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_exti.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_flash_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_gpio_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_i2c_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_pwr_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_rcc_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_spi_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_tim_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart_ex.h b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart_ex.h similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart_ex.h rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Inc/stm32f7xx_hal_uart_ex.h diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_cortex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_cortex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_cortex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_cortex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_dma_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_exti.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_exti.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_exti.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_exti.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_flash_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_gpio.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_gpio.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_gpio.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_gpio.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_i2c_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_pwr_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_rcc_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_spi_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_tim_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart.c diff --git a/Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart_ex.c b/Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart_ex.c similarity index 100% rename from Mainboard/Firmware/motherboard_v1/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart_ex.c rename to Mainboard/Firmware/mainboard/Drivers/STM32F7xx_HAL_Driver/Src/stm32f7xx_hal_uart_ex.c diff --git a/Mainboard/Firmware/motherboard_v1/STM32F765ZGTX_FLASH.ld b/Mainboard/Firmware/mainboard/STM32F765ZGTX_FLASH.ld similarity index 100% rename from Mainboard/Firmware/motherboard_v1/STM32F765ZGTX_FLASH.ld rename to Mainboard/Firmware/mainboard/STM32F765ZGTX_FLASH.ld diff --git a/Mainboard/Firmware/motherboard_v1/STM32F765ZGTX_RAM.ld b/Mainboard/Firmware/mainboard/STM32F765ZGTX_RAM.ld similarity index 100% rename from Mainboard/Firmware/motherboard_v1/STM32F765ZGTX_RAM.ld rename to Mainboard/Firmware/mainboard/STM32F765ZGTX_RAM.ld diff --git a/Mainboard/Firmware/motherboard_v1/motherboard_v1.ioc b/Mainboard/Firmware/mainboard/mainboard.ioc similarity index 99% rename from Mainboard/Firmware/motherboard_v1/motherboard_v1.ioc rename to Mainboard/Firmware/mainboard/mainboard.ioc index 26496dc9..5e4ff89a 100644 --- a/Mainboard/Firmware/motherboard_v1/motherboard_v1.ioc +++ b/Mainboard/Firmware/mainboard/mainboard.ioc @@ -228,8 +228,8 @@ ProjectManager.MainLocation=Core/Src ProjectManager.NoMain=false ProjectManager.PreviousToolchain=STM32CubeIDE ProjectManager.ProjectBuild=false -ProjectManager.ProjectFileName=motherboard_v1.ioc -ProjectManager.ProjectName=motherboard_v1 +ProjectManager.ProjectFileName=mainboard.ioc +ProjectManager.ProjectName=mainboard ProjectManager.StackSize=0x400 ProjectManager.TargetToolchain=STM32CubeIDE ProjectManager.ToolChainLocation= diff --git a/Mainboard/Firmware/motherboard_v1/scripts/check-format.sh b/Mainboard/Firmware/mainboard/scripts/check-format.sh similarity index 100% rename from Mainboard/Firmware/motherboard_v1/scripts/check-format.sh rename to Mainboard/Firmware/mainboard/scripts/check-format.sh diff --git a/Mainboard/Firmware/motherboard_v1/scripts/clang-format b/Mainboard/Firmware/mainboard/scripts/clang-format similarity index 100% rename from Mainboard/Firmware/motherboard_v1/scripts/clang-format rename to Mainboard/Firmware/mainboard/scripts/clang-format diff --git a/Mainboard/Firmware/motherboard_v1/scripts/format.sh b/Mainboard/Firmware/mainboard/scripts/format.sh similarity index 100% rename from Mainboard/Firmware/motherboard_v1/scripts/format.sh rename to Mainboard/Firmware/mainboard/scripts/format.sh diff --git a/Mainboard/Firmware/motherboard_v1/scripts/run-clang-format.py b/Mainboard/Firmware/mainboard/scripts/run-clang-format.py similarity index 100% rename from Mainboard/Firmware/motherboard_v1/scripts/run-clang-format.py rename to Mainboard/Firmware/mainboard/scripts/run-clang-format.py From 818233ed6e8d7613c8a0d5f6de9efb71f6e53c39 Mon Sep 17 00:00:00 2001 From: Eric Severson Date: Sun, 17 May 2026 10:26:26 -0500 Subject: [PATCH 72/72] Enhance comments on DMA data handling Clarify that this should not be the regular path --- Mainboard/Firmware/mainboard/Core/Src/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Mainboard/Firmware/mainboard/Core/Src/main.c b/Mainboard/Firmware/mainboard/Core/Src/main.c index 211136f5..bdf6ac47 100644 --- a/Mainboard/Firmware/mainboard/Core/Src/main.c +++ b/Mainboard/Firmware/mainboard/Core/Src/main.c @@ -56,6 +56,11 @@ int main(void) // Only attempt to grab the lock and route data if there // is actually data waiting in the DMA buffers to help the // external IRQ retain higher priority access to process_routing + // IMPORTANT NOTE: the goal is to handle all data in the + // interrupts. This pathway to process_routing() is being provided + // as a fail safe. If it is regularly being used, consider this a + // warning sign of a broader system problem as it will cause slow + // link speeds. if (drv_uart_has_dma_data()) try_process_routing(); // This try function is thread safe