diff --git a/board/boards/tres.h b/board/boards/tres.h index 7073cecf..17836e67 100644 --- a/board/boards/tres.h +++ b/board/boards/tres.h @@ -10,6 +10,10 @@ void tres_init(void) { red_chiplet_init(); + // SOM debugging UART + gpio_uart7_init(); + uart_init(&uart_ring_som_debug, 115200); + // SPI init set_gpio_alternate(GPIOE, 11, GPIO_AF5_SPI4); set_gpio_alternate(GPIOE, 12, GPIO_AF5_SPI4); diff --git a/board/bootstub_declarations.h b/board/bootstub_declarations.h index 06a24a2b..bca4a147 100644 --- a/board/bootstub_declarations.h +++ b/board/bootstub_declarations.h @@ -10,6 +10,10 @@ typedef struct harness_configuration harness_configuration; void can_flip_buses(uint8_t bus1, uint8_t bus2){UNUSED(bus1); UNUSED(bus2);} void pwm_init(TIM_TypeDef *TIM, uint8_t channel); void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage); +// No UART support in bootloader +typedef struct uart_ring {} uart_ring; +uart_ring uart_ring_som_debug; +void uart_init(uart_ring *q, int baud) { UNUSED(q); UNUSED(baud); } // ********************* Globals ********************** uint8_t hw_type = 0; diff --git a/board/drivers/uart.h b/board/drivers/uart.h index 2caa44fa..b5a9b7a2 100644 --- a/board/drivers/uart.h +++ b/board/drivers/uart.h @@ -51,7 +51,15 @@ UART_BUFFER(lin1, FIFO_SIZE_INT, FIFO_SIZE_INT, UART5, NULL, false) UART_BUFFER(lin2, FIFO_SIZE_INT, FIFO_SIZE_INT, USART3, NULL, false) // debug = USART2 -UART_BUFFER(debug, FIFO_SIZE_INT, FIFO_SIZE_INT, USART2, debug_ring_callback, false) +UART_BUFFER(debug, FIFO_SIZE_DMA, FIFO_SIZE_INT, USART2, debug_ring_callback, false) + +// SOM debug = UART7 +#ifdef STM32H7 + UART_BUFFER(som_debug, FIFO_SIZE_INT, FIFO_SIZE_INT, UART7, NULL, false) +#else + // UART7 is not available on F4 + UART_BUFFER(som_debug, 1U, 1U, NULL, NULL, false) +#endif uart_ring *get_ring_by_number(int a) { uart_ring *ring = NULL; @@ -68,6 +76,9 @@ uart_ring *get_ring_by_number(int a) { case 3: ring = &uart_ring_lin2; break; + case 4: + ring = &uart_ring_som_debug; + break; default: ring = NULL; break; diff --git a/board/faults.h b/board/faults.h index ad938b9d..e41e4f40 100644 --- a/board/faults.h +++ b/board/faults.h @@ -27,6 +27,7 @@ #define FAULT_INTERRUPT_RATE_TICK (1U << 21) #define FAULT_INTERRUPT_RATE_EXTI (1U << 22) #define FAULT_INTERRUPT_RATE_SPI (1U << 23) +#define FAULT_INTERRUPT_RATE_UART_7 (1U << 24) // Permanent faults #define PERMANENT_FAULTS 0U diff --git a/board/main.c b/board/main.c index 5b978fea..62d646d5 100644 --- a/board/main.c +++ b/board/main.c @@ -231,6 +231,7 @@ void tick_handler(void) { if (current_safety_mode != SAFETY_SILENT) { set_safety_mode(SAFETY_SILENT, 0U); } + if (power_save_status != POWER_SAVE_STATUS_ENABLED) { set_power_save_state(POWER_SAVE_STATUS_ENABLED); } diff --git a/board/main_comms.h b/board/main_comms.h index 29ad3a64..9dac7451 100644 --- a/board/main_comms.h +++ b/board/main_comms.h @@ -155,7 +155,7 @@ void comms_can_write(uint8_t *data, uint32_t len) { void comms_endpoint2_write(uint8_t *data, uint32_t len) { uart_ring *ur = get_ring_by_number(data[0]); if ((len != 0U) && (ur != NULL)) { - if ((data[0] < 2U) || safety_tx_lin_hook(data[0] - 2U, &data[1], len - 1U)) { + if ((data[0] < 2U) || (data[0] >= 4U) || safety_tx_lin_hook(data[0] - 2U, &data[1], len - 1U)) { for (uint32_t i = 1; i < len; i++) { while (!putc(ur, data[i])) { // wait diff --git a/board/stm32fx/lluart.h b/board/stm32fx/lluart.h index 69959a76..d9565ffb 100644 --- a/board/stm32fx/lluart.h +++ b/board/stm32fx/lluart.h @@ -192,44 +192,46 @@ void uart_set_baud(USART_TypeDef *u, unsigned int baud) { } void uart_init(uart_ring *q, int baud) { - // Register interrupts (max data rate: 115200 baud) - if(q->uart == USART1){ - REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1) - } else if (q->uart == USART2){ - REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2) - } else if (q->uart == USART3){ - REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3) - } else if (q->uart == UART5){ - REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5) - } else { - // UART not used. Skip registering interrupts - } - if(q->dma_rx){ - REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer - } + if(q->uart != NULL){ + // Register interrupts (max data rate: 115200 baud) + if(q->uart == USART1){ + REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1) + } else if (q->uart == USART2){ + REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2) + } else if (q->uart == USART3){ + REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3) + } else if (q->uart == UART5){ + REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5) + } else { + // UART not used. Skip registering interrupts + } + if(q->dma_rx){ + REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer + } - // Set baud and enable peripheral with TX and RX mode - uart_set_baud(q->uart, baud); - q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; - if ((q->uart == USART2) || (q->uart == USART3) || (q->uart == UART5)) { - q->uart->CR1 |= USART_CR1_RXNEIE; - } + // Set baud and enable peripheral with TX and RX mode + uart_set_baud(q->uart, baud); + q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; + if ((q->uart == USART2) || (q->uart == USART3) || (q->uart == UART5)) { + q->uart->CR1 |= USART_CR1_RXNEIE; + } - // Enable UART interrupts - if(q->uart == USART1){ - NVIC_EnableIRQ(USART1_IRQn); - } else if (q->uart == USART2){ - NVIC_EnableIRQ(USART2_IRQn); - } else if (q->uart == USART3){ - NVIC_EnableIRQ(USART3_IRQn); - } else if (q->uart == UART5){ - NVIC_EnableIRQ(UART5_IRQn); - } else { - // UART not used. Skip enabling interrupts - } + // Enable UART interrupts + if(q->uart == USART1){ + NVIC_EnableIRQ(USART1_IRQn); + } else if (q->uart == USART2){ + NVIC_EnableIRQ(USART2_IRQn); + } else if (q->uart == USART3){ + NVIC_EnableIRQ(USART3_IRQn); + } else if (q->uart == UART5){ + NVIC_EnableIRQ(UART5_IRQn); + } else { + // UART not used. Skip enabling interrupts + } - // Initialise RX DMA if used - if(q->dma_rx){ - dma_rx_init(q); + // Initialise RX DMA if used + if(q->dma_rx){ + dma_rx_init(q); + } } } diff --git a/board/stm32h7/interrupt_handlers.h b/board/stm32h7/interrupt_handlers.h index 2b0a2b42..0811ffe5 100644 --- a/board/stm32h7/interrupt_handlers.h +++ b/board/stm32h7/interrupt_handlers.h @@ -72,3 +72,4 @@ void OTG_HS_EP1_OUT_IRQHandler(void) {handle_interrupt(OTG_HS_EP1_OUT_IRQn);} void OTG_HS_EP1_IN_IRQHandler(void) {handle_interrupt(OTG_HS_EP1_IN_IRQn);} void OTG_HS_WKUP_IRQHandler(void) {handle_interrupt(OTG_HS_WKUP_IRQn);} void OTG_HS_IRQHandler(void) {handle_interrupt(OTG_HS_IRQn);} +void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);} diff --git a/board/stm32h7/lluart.h b/board/stm32h7/lluart.h index aa44f7bb..1124c336 100644 --- a/board/stm32h7/lluart.h +++ b/board/stm32h7/lluart.h @@ -1,5 +1,130 @@ -void uart_init(uart_ring *q, int baud) { UNUSED(q); UNUSED(baud); } -void uart_set_baud(USART_TypeDef *u, unsigned int baud) { UNUSED(u); UNUSED(baud); } + void dma_pointer_handler(uart_ring *q, uint32_t dma_ndtr) { UNUSED(q); UNUSED(dma_ndtr); } -void uart_rx_ring(uart_ring *q) { UNUSED(q); } -void uart_tx_ring(uart_ring *q) { UNUSED(q); } +void dma_rx_init(uart_ring *q) { UNUSED(q); } + +#define __DIV(_PCLK_, _BAUD_) (((_PCLK_) * 25U) / (4U * (_BAUD_))) +#define __DIVMANT(_PCLK_, _BAUD_) (__DIV((_PCLK_), (_BAUD_)) / 100U) +#define __DIVFRAQ(_PCLK_, _BAUD_) ((((__DIV((_PCLK_), (_BAUD_)) - (__DIVMANT((_PCLK_), (_BAUD_)) * 100U)) * 16U) + 50U) / 100U) +#define __USART_BRR(_PCLK_, _BAUD_) ((__DIVMANT((_PCLK_), (_BAUD_)) << 4) | (__DIVFRAQ((_PCLK_), (_BAUD_)) & 0x0FU)) + +void uart_rx_ring(uart_ring *q){ + // Do not read out directly if DMA enabled + if (q->dma_rx == false) { + ENTER_CRITICAL(); + + // Read out RX buffer + uint8_t c = q->uart->RDR; // This read after reading SR clears a bunch of interrupts + + uint16_t next_w_ptr = (q->w_ptr_rx + 1U) % q->rx_fifo_size; + // Do not overwrite buffer data + if (next_w_ptr != q->r_ptr_rx) { + q->elems_rx[q->w_ptr_rx] = c; + q->w_ptr_rx = next_w_ptr; + if (q->callback != NULL) { + q->callback(q); + } + } + + EXIT_CRITICAL(); + } +} + +void uart_tx_ring(uart_ring *q){ + ENTER_CRITICAL(); + // Send out next byte of TX buffer + if (q->w_ptr_tx != q->r_ptr_tx) { + // Only send if transmit register is empty (aka last byte has been sent) + if ((q->uart->ISR & USART_ISR_TXE_TXFNF) != 0) { + q->uart->TDR = q->elems_tx[q->r_ptr_tx]; // This clears TXE + q->r_ptr_tx = (q->r_ptr_tx + 1U) % q->tx_fifo_size; + } + + // Enable TXE interrupt if there is still data to be sent + if(q->r_ptr_tx != q->w_ptr_tx){ + q->uart->CR1 |= USART_CR1_TXEIE; + } else { + q->uart->CR1 &= ~USART_CR1_TXEIE; + } + } + EXIT_CRITICAL(); +} + +void uart_set_baud(USART_TypeDef *u, unsigned int baud) { + // UART7 is connected to APB1 at 60MHz + u->BRR = 60000000U / baud; +} + +// This read after reading ISR clears all error interrupts. We don't want compiler warnings, nor optimizations +#define UART_READ_RDR(uart) volatile uint8_t t = (uart)->RDR; UNUSED(t); + +void uart_interrupt_handler(uart_ring *q) { + ENTER_CRITICAL(); + + // Read UART status. This is also the first step necessary in clearing most interrupts + uint32_t status = q->uart->ISR; + + // If RXFNE is set, perform a read. This clears RXFNE, ORE, IDLE, NF and FE + if((status & USART_ISR_RXNE_RXFNE) != 0U){ + uart_rx_ring(q); + } + + // Detect errors and clear them + uint32_t err = (status & USART_ISR_ORE) | (status & USART_ISR_NE) | (status & USART_ISR_FE) | (status & USART_ISR_PE); + if(err != 0U){ + #ifdef DEBUG_UART + puts("Encountered UART error: "); puth(err); puts("\n"); + #endif + UART_READ_RDR(q->uart) + } + + if ((err & USART_ISR_ORE) != 0U) { + q->uart->ICR |= USART_ICR_ORECF; + } else if ((err & USART_ISR_NE) != 0U) { + q->uart->ICR |= USART_ICR_NECF; + } else if ((err & USART_ISR_FE) != 0U) { + q->uart->ICR |= USART_ICR_FECF; + } else if ((err & USART_ISR_PE) != 0U) { + q->uart->ICR |= USART_ICR_PECF; + } else {} + + // Send if necessary + uart_tx_ring(q); + + // Run DMA pointer handler if the line is idle + if(q->dma_rx && (status & USART_ISR_IDLE)){ + // Reset IDLE flag + UART_READ_RDR(q->uart) + + #ifdef DEBUG_UART + puts("No IDLE dma_pointer_handler implemented for this UART."); + #endif + } + + EXIT_CRITICAL(); +} + +void UART7_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_som_debug); } + +void uart_init(uart_ring *q, int baud) { + if (q->uart == UART7) { + REGISTER_INTERRUPT(UART7_IRQn, UART7_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_7) + + if (q->dma_rx) { + // TODO + } + + uart_set_baud(q->uart, baud); + q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; + + // Enable interrupt on RX not empty + q->uart->CR1 |= USART_CR1_RXNEIE; + + // Enable UART interrupts + NVIC_EnableIRQ(UART7_IRQn); + + // Initialise RX DMA if used + if (q->dma_rx) { + dma_rx_init(q); + } + } +} diff --git a/board/stm32h7/peripherals.h b/board/stm32h7/peripherals.h index cc52e608..01e9ff7c 100644 --- a/board/stm32h7/peripherals.h +++ b/board/stm32h7/peripherals.h @@ -103,6 +103,7 @@ void peripherals_init(void) { RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // SPI DMA RCC->APB1LENR |= RCC_APB1LENR_TIM2EN; // main counter RCC->APB1LENR |= RCC_APB1LENR_TIM6EN; // interrupt timer + RCC->APB1LENR |= RCC_APB1LENR_UART7EN; // SOM uart RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; // clock source timer RCC->APB1LENR |= RCC_APB1LENR_TIM12EN; // slow loop diff --git a/board/stm32h7/stm32h7_config.h b/board/stm32h7/stm32h7_config.h index 393d7ae3..c58f1ff4 100644 --- a/board/stm32h7/stm32h7_config.h +++ b/board/stm32h7/stm32h7_config.h @@ -7,7 +7,7 @@ #define CORE_FREQ 240U // in Mhz //APB1 - 120Mhz, APB2 - 120Mhz -#define APB1_FREQ CORE_FREQ/2U +#define APB1_FREQ CORE_FREQ/2U #define APB2_FREQ CORE_FREQ/2U #define BOOTLOADER_ADDRESS 0x1FF09804U @@ -55,12 +55,16 @@ #include "stm32h7/interrupt_handlers.h" #include "drivers/timers.h" #include "stm32h7/lladc.h" -#include "stm32h7/board.h" -#include "stm32h7/clock.h" #if !defined(BOOTSTUB) && defined(PANDA) #include "drivers/uart.h" #include "stm32h7/lluart.h" +#endif + +#include "stm32h7/board.h" +#include "stm32h7/clock.h" + +#if !defined(BOOTSTUB) && defined(PANDA) #include "stm32h7/llexti.h" #endif diff --git a/python/__init__.py b/python/__init__.py index ea25a4d9..4f0915cc 100644 --- a/python/__init__.py +++ b/python/__init__.py @@ -174,6 +174,7 @@ class Panda: SERIAL_ESP = 1 SERIAL_LIN1 = 2 SERIAL_LIN2 = 3 + SERIAL_SOM_DEBUG = 4 GMLAN_CAN2 = 1 GMLAN_CAN3 = 2 @@ -727,7 +728,7 @@ class Panda: def serial_write(self, port_number, ln): ret = 0 for i in range(0, len(ln), 0x20): - ret += self._handle.bulkWrite(2, struct.pack("B", port_number) + ln[i:i + 0x20]) + ret += self._handle.bulkWrite(2, struct.pack("B", port_number) + bytes(ln[i:i + 0x20], 'utf-8')) return ret def serial_clear(self, port_number): diff --git a/tests/debug_console.py b/tests/debug_console.py index d0c9628a..fd5e338f 100755 --- a/tests/debug_console.py +++ b/tests/debug_console.py @@ -4,6 +4,7 @@ import os import sys import time import select +import codecs sys.path.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "..")) from panda import Panda # noqa: E402 @@ -16,12 +17,14 @@ if __name__ == "__main__": try: port_number = int(os.getenv("PORT", "0")) claim = os.getenv("CLAIM") is not None + no_color = os.getenv("NO_COLOR") is not None serials = Panda.list() if os.getenv("SERIAL"): serials = [x for x in serials if x == os.getenv("SERIAL")] pandas = list([Panda(x, claim=claim) for x in serials]) + decoders = [codecs.getincrementaldecoder('utf-8')() for _ in pandas] if not len(pandas): sys.exit("no pandas found") @@ -35,7 +38,11 @@ if __name__ == "__main__": while True: ret = panda.serial_read(port_number) if len(ret) > 0: - sys.stdout.write(setcolor[i] + ret.decode('ascii') + unsetcolor) + decoded = decoders[i].decode(ret) + if no_color: + sys.stdout.write(decoded) + else: + sys.stdout.write(setcolor[i] + decoded + unsetcolor) sys.stdout.flush() else: break