Skip to content

Commit

Permalink
setup UART for SOM debugging (commaai#1151)
Browse files Browse the repository at this point in the history
* cleanup external debug serial

* wip: bring up uart7

* more wip

* this does something

* this works

* increase fifo size

* fix misra

* cleanup

* fix misra again

* add SOM debug enum

* reduce SOM buffer on F4

Co-authored-by: Comma Device <device@comma.ai>
Co-authored-by: Adeeb Shihadeh <adeebshihadeh@gmail.com>
  • Loading branch information
3 people committed Nov 17, 2022
1 parent f0f67cc commit 5aa5f85
Show file tree
Hide file tree
Showing 13 changed files with 209 additions and 47 deletions.
4 changes: 4 additions & 0 deletions board/boards/tres.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions board/bootstub_declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
13 changes: 12 additions & 1 deletion board/drivers/uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
1 change: 1 addition & 0 deletions board/faults.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions board/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down
2 changes: 1 addition & 1 deletion board/main_comms.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
74 changes: 38 additions & 36 deletions board/stm32fx/lluart.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}
1 change: 1 addition & 0 deletions board/stm32h7/interrupt_handlers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);}
133 changes: 129 additions & 4 deletions board/stm32h7/lluart.h
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
1 change: 1 addition & 0 deletions board/stm32h7/peripherals.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
10 changes: 7 additions & 3 deletions board/stm32h7/stm32h7_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
3 changes: 2 additions & 1 deletion python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -727,7 +728,7 @@ def serial_read(self, port_number):
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):
Expand Down
9 changes: 8 additions & 1 deletion tests/debug_console.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
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
Expand All @@ -16,12 +17,14 @@
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")
Expand All @@ -35,7 +38,11 @@
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
Expand Down

0 comments on commit 5aa5f85

Please sign in to comment.