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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 11 additions & 51 deletions Mainboard/Firmware/mainboard/Core/Inc/drv_uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ 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, STATE_GOT_MSB } rx_state_t;
typedef enum { STATE_IDLE, STATE_GOT_MSB, STATE_GOT_HEADER } rx_state_t;

typedef struct {
rx_state_t state;
Expand All @@ -42,72 +42,32 @@ extern uint8_t DAISY_RX2_Pool[AMDS_RX_BUF_SIZE];
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;

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);

/**
* 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
tracker1.state = STATE_IDLE;
tracker2.state = STATE_IDLE;
// 1. Reset state machines to gracefully await the next packet
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.
// 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
tracker1.read_index = mock_dma_write_head;
tracker2.read_index = mock_dma_write_head;
tracker1.read_index = mock_dma_write_head;
tracker2.read_index = mock_dma_write_head;
#else
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));
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
}
}

static inline void drv_uart_putc_fast(USART_TypeDef *uart, uint8_t data)
Expand Down
13 changes: 10 additions & 3 deletions Mainboard/Firmware/mainboard/Core/Src/adc.c
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,9 @@ void EXTI3_IRQHandler(void)
{
// alert daisy chained AMDSs to begin converting
GPIO_TOGGLE_PIN(GPIOD, GPIO_PIN_1);
// We can still receive DMA while IRQ are disabled, and we don't get
// any annoying 5us pauses that would happen normally if IRQ was enabled.
__disable_irq();

#ifdef BENCHMARK_MODE
// =========================================================================
Expand Down Expand Up @@ -285,7 +288,8 @@ void EXTI3_IRQHandler(void)
}

// Handle any DMA data that has been received from daisy chain
try_process_routing();
process_routing();
__enable_irq();

NVIC_ClearPendingIRQ(EXTI3_IRQn);
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_3);
Expand Down Expand Up @@ -394,7 +398,9 @@ void EXTI15_10_IRQHandler(void)
{
// alert daisy chained AMDSs to begin converting
GPIO_TOGGLE_PIN(GPIOG, GPIO_PIN_14);

// We can still receive DMA while IRQ are disabled, and we don't get
// any annoying 5us pauses that would happen normally if IRQ was enabled.
__disable_irq();
#ifdef BENCHMARK_MODE
// =========================================================================
// INJECT MOCK DMA DATA FOR BENCHMARKING
Expand Down Expand Up @@ -466,8 +472,9 @@ 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
process_routing(); // This try function is thread safe

__enable_irq();
// 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.
Expand Down
Loading
Loading