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 0000000..5064fdc --- /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/Inc/adc.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/adc.h index 227d4b0..2cfc994 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 9be9a75..976bcc4 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h +++ b/Mainboard/Firmware/motherboard_v1/Core/Inc/drv_uart.h @@ -3,9 +3,54 @@ #include "platform.h" #include +#include 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]; +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_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; + +extern uart_rx_tracker_t tracker4; +extern uart_rx_tracker_t tracker5; + +#define AMDS_RX_BUF_SIZE 256 +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) { // Wait until UART is ready to accept next character @@ -17,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/Inc/stm32f7xx_hal_conf.h b/Mainboard/Firmware/motherboard_v1/Core/Inc/stm32f7xx_hal_conf.h index 904591e..6015fb9 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 153ed98..cff541a 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 "drv_uart.h" #include "drv_spi.h" #include "platform.h" #include "tx.h" @@ -23,6 +24,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) @@ -43,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[2] = { 0 }; + void adc_init(void) { // Setup output pin which starts ADC conversions @@ -68,6 +74,33 @@ 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 @@ -147,7 +180,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 +248,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_SET); + // Configure GPIO pins GPIO_InitStruct.Pin = GPIO_PIN_3; @@ -225,6 +262,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 6f861e6..6e1ab95 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 c81c176..7f10763 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/drv_uart.c @@ -6,8 +6,212 @@ 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; + +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; +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}; + +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) + 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]; + 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]; + + // 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; + + // 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. 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; + } + } +} + +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) +{ + // 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) +{ + HAL_DMA_IRQHandler(&hdma_uart4_rx); +} + +void UART5_IRQHandler(void) +{ + // 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) +{ + HAL_DMA_IRQHandler(&hdma_uart5_rx); +} + +// 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 USART3_IRQHandler(void) { + HAL_UART_IRQHandler(&huart3); +} void drv_uart_init(void) { @@ -21,8 +225,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,15 +257,60 @@ 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_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; + huart->Init.OneBitSampling = UART_ONE_BIT_SAMPLE_ENABLE; huart->AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT; if (HAL_UART_Init(huart) != HAL_OK) { PANIC; } + + // Interrupt setup must come AFTER HAL_UART_Init() + if (huart->Instance == UART4) { + 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_DMA(&huart4, UART4_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + PANIC; + } + } 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_DMA(&huart5, UART5_DMA_Pool, AMDS_RX_BUF_SIZE) != HAL_OK) { + PANIC; + } + } 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); + + } } void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle) @@ -66,6 +321,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 @@ -77,11 +333,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 @@ -93,7 +371,109 @@ 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) { + // USART3 clock enable + __HAL_RCC_UART4_CLK_ENABLE(); + __HAL_RCC_DMA1_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); + + // 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, 6); // 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 + // 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); + + // DMA config - check your device's DMA request mapping table + // 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; + 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, 6); // higher priority than UART + HAL_NVIC_EnableIRQ(DMA1_Stream0_IRQn); + } } void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle) @@ -120,4 +500,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); + } } diff --git a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c index 2897b88..a2e04c5 100644 --- a/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c +++ b/Mainboard/Firmware/motherboard_v1/Core/Src/tx.c @@ -3,50 +3,245 @@ #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) { - // 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); + // 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; - // Get latest data from ADC driver (non-blocking) uint16_t bits[8]; adc_latest_bits(bits); - // Send 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); - - drv_uart_putc_fast(USART2, header); - drv_uart_putc_fast(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)); - - // Send ADC sample data LSBs - drv_uart_putc_fast(USART2, (uint8_t)(sample1 & 0x00FF)); - drv_uart_putc_fast(USART3, (uint8_t)(sample2 & 0x00FF)); + 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; + } } - // Wait for entire UART transmission to complete - drv_uart_wait_TC(USART2); - drv_uart_wait_TC(USART3); + // 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; +//} + +