Skip to content

Commit

Permalink
Interrupt refactor (NVIC_SM_1: #334) and Fault handling (#377) (PR #373)
Browse files Browse the repository at this point in the history
  • Loading branch information
robbederks committed Nov 28, 2019
1 parent 000282e commit 656f99b
Show file tree
Hide file tree
Showing 17 changed files with 473 additions and 190 deletions.
2 changes: 1 addition & 1 deletion board/boards/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ void peripherals_init(void){
RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // pedal and fan PWM
RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt and IR PWM
//RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
//RCC->APB1ENR |= RCC_APB1ENR_TIM6EN;
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // interrupt timer
RCC->APB1ENR |= RCC_APB1ENR_PWREN; // for RTC config
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN;
Expand Down
4 changes: 4 additions & 0 deletions board/bootstub.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@ const board *current_board;
// ********************* Includes *********************
#include "libc.h"
#include "provision.h"
#include "faults.h"

#include "drivers/interrupts.h"
#include "drivers/clock.h"
#include "drivers/llgpio.h"
#include "drivers/adc.h"
Expand Down Expand Up @@ -65,6 +67,8 @@ extern void *_app_start[];
// BOUNTY: $200 coupon on shop.comma.ai or $100 check.

int main(void) {
init_interrupts(false);

disable_interrupts();
clock_init();
detect_configuration();
Expand Down
4 changes: 4 additions & 0 deletions board/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
//#define DEBUG_UART
//#define DEBUG_USB
//#define DEBUG_SPI
//#define DEBUG_FAULTS

#ifdef STM32F4
#define PANDA
Expand Down Expand Up @@ -37,5 +38,8 @@

#define MAX_RESP_LEN 0x40U

// Around (1Mbps / 8 bits/byte / 12 bytes per message)
#define CAN_INTERRUPT_RATE 12000U

#endif

52 changes: 31 additions & 21 deletions board/drivers/can.h
Original file line number Diff line number Diff line change
Expand Up @@ -148,18 +148,6 @@ void can_set_speed(uint8_t can_number) {
}
}

void can_init(uint8_t can_number) {
if (can_number != 0xffU) {
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
can_set_speed(can_number);

llcan_init(CAN);

// in case there are queued up messages
process_can(can_number);
}
}

void can_init_all(void) {
for (uint8_t i=0U; i < CAN_MAX; i++) {
can_init(i);
Expand Down Expand Up @@ -407,17 +395,17 @@ void can_rx(uint8_t can_number) {
}
}

void CAN1_TX_IRQHandler(void) { process_can(0); }
void CAN1_RX0_IRQHandler(void) { can_rx(0); }
void CAN1_SCE_IRQHandler(void) { can_sce(CAN1); }
void CAN1_TX_IRQ_Handler(void) { process_can(0); }
void CAN1_RX0_IRQ_Handler(void) { can_rx(0); }
void CAN1_SCE_IRQ_Handler(void) { can_sce(CAN1); }

void CAN2_TX_IRQHandler(void) { process_can(1); }
void CAN2_RX0_IRQHandler(void) { can_rx(1); }
void CAN2_SCE_IRQHandler(void) { can_sce(CAN2); }
void CAN2_TX_IRQ_Handler(void) { process_can(1); }
void CAN2_RX0_IRQ_Handler(void) { can_rx(1); }
void CAN2_SCE_IRQ_Handler(void) { can_sce(CAN2); }

void CAN3_TX_IRQHandler(void) { process_can(2); }
void CAN3_RX0_IRQHandler(void) { can_rx(2); }
void CAN3_SCE_IRQHandler(void) { can_sce(CAN3); }
void CAN3_TX_IRQ_Handler(void) { process_can(2); }
void CAN3_RX0_IRQ_Handler(void) { can_rx(2); }
void CAN3_SCE_IRQ_Handler(void) { can_sce(CAN3); }

void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number, bool skip_tx_hook) {
if (skip_tx_hook || safety_tx_hook(to_push) != 0) {
Expand All @@ -439,3 +427,25 @@ void can_set_forwarding(int from, int to) {
can_forwarding[from] = to;
}

void can_init(uint8_t can_number) {
REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1)
REGISTER_INTERRUPT(CAN2_TX_IRQn, CAN2_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
REGISTER_INTERRUPT(CAN2_RX0_IRQn, CAN2_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
REGISTER_INTERRUPT(CAN2_SCE_IRQn, CAN2_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2)
REGISTER_INTERRUPT(CAN3_TX_IRQn, CAN3_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
REGISTER_INTERRUPT(CAN3_RX0_IRQn, CAN3_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)
REGISTER_INTERRUPT(CAN3_SCE_IRQn, CAN3_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3)

if (can_number != 0xffU) {
CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number);
can_set_speed(can_number);

llcan_init(CAN);

// in case there are queued up messages
process_can(can_number);
}
}

29 changes: 16 additions & 13 deletions board/drivers/fan.h
Original file line number Diff line number Diff line change
@@ -1,15 +1,3 @@
void fan_init(void){
// Init PWM speed control
pwm_init(TIM3, 3);

// Init TACH interrupt
SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI2_PD;
EXTI->IMR |= (1U << 2);
EXTI->RTSR |= (1U << 2);
EXTI->FTSR |= (1U << 2);
NVIC_EnableIRQ(EXTI2_IRQn);
}

void fan_set_power(uint8_t percentage){
pwm_set(TIM3, 3, percentage);
}
Expand All @@ -27,10 +15,25 @@ void fan_tick(void){
}

// TACH interrupt handler
void EXTI2_IRQHandler(void) {
void EXTI2_IRQ_Handler(void) {
volatile unsigned int pr = EXTI->PR & (1U << 2);
if ((pr & (1U << 2)) != 0U) {
fan_tach_counter++;
}
EXTI->PR = (1U << 2);
}

void fan_init(void){
// 5000RPM * 4 tach edges / 60 seconds
REGISTER_INTERRUPT(EXTI2_IRQn, EXTI2_IRQ_Handler, 700U, FAULT_INTERRUPT_RATE_TACH)

// Init PWM speed control
pwm_init(TIM3, 3);

// Init TACH interrupt
SYSCFG->EXTICR[0] = SYSCFG_EXTICR1_EXTI2_PD;
EXTI->IMR |= (1U << 2);
EXTI->RTSR |= (1U << 2);
EXTI->FTSR |= (1U << 2);
NVIC_EnableIRQ(EXTI2_IRQn);
}
4 changes: 3 additions & 1 deletion board/drivers/gmlan_alt.h
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ int gmlan_fail_count = 0;
#define REQUIRED_SILENT_TIME 10
#define MAX_FAIL_COUNT 10

void TIM4_IRQHandler(void) {
void TIM4_IRQ_Handler(void) {
if (gmlan_alt_mode == BITBANG) {
if ((TIM4->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
int read = get_gpio_input(GPIOB, 12);
Expand Down Expand Up @@ -279,6 +279,8 @@ bool bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);

// 33kbps
REGISTER_INTERRUPT(TIM4_IRQn, TIM4_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN)
setup_timer4();
}
return gmlan_send_ok;
Expand Down
190 changes: 190 additions & 0 deletions board/drivers/interrupts.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
// ********************* Interrupt helpers *********************
volatile bool interrupts_enabled = false;

void enable_interrupts(void) {
interrupts_enabled = true;
__enable_irq();
}

void disable_interrupts(void) {
interrupts_enabled = false;
__disable_irq();
}

uint8_t global_critical_depth = 0U;
#define ENTER_CRITICAL() \
__disable_irq(); \
global_critical_depth += 1U;

#define EXIT_CRITICAL() \
global_critical_depth -= 1U; \
if ((global_critical_depth == 0U) && interrupts_enabled) { \
__enable_irq(); \
}

// ********************* Interrupt handling *********************

typedef struct interrupt {
IRQn_Type irq_type;
void (*handler)(void);
uint32_t call_counter;
uint32_t max_call_rate; // Call rate is defined as the amount of calls each second
uint32_t call_rate_fault;
} interrupt;

void unused_interrupt_handler(void) {
// Something is wrong if this handler is called!
puts("Unused interrupt handler called!\n");
fault_occurred(FAULT_UNUSED_INTERRUPT_HANDLED);
}

#define NUM_INTERRUPTS 102U // There are 102 external interrupt sources (see stm32f413.h)
interrupt interrupts[NUM_INTERRUPTS];

#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate, rate_fault) \
interrupts[irq_num].irq_type = irq_num; \
interrupts[irq_num].handler = func_ptr; \
interrupts[irq_num].call_counter = 0U; \
interrupts[irq_num].max_call_rate = call_rate; \
interrupts[irq_num].call_rate_fault = rate_fault;

bool check_interrupt_rate = false;

void handle_interrupt(IRQn_Type irq_type){
interrupts[irq_type].call_counter++;
interrupts[irq_type].handler();

// Check that the interrupts don't fire too often
if(check_interrupt_rate && (interrupts[irq_type].call_counter > interrupts[irq_type].max_call_rate)){
puts("Interrupt 0x"); puth(irq_type); puts(" fired too often (0x"); puth(interrupts[irq_type].call_counter); puts("/s)!\n");
fault_occurred(interrupts[irq_type].call_rate_fault);
}
}

// Reset interrupt counter every second
void TIM6_DAC_IRQ_Handler(void) {
if (TIM6->SR != 0) {
for(uint16_t i=0U; i<NUM_INTERRUPTS; i++){
interrupts[i].call_counter = 0U;
}
}
TIM6->SR = 0;
}

void init_interrupts(bool check_rate_limit){
check_interrupt_rate = check_rate_limit;

for(uint16_t i=0U; i<NUM_INTERRUPTS; i++){
interrupts[i].handler = unused_interrupt_handler;
}

// Init timer 10 for a 1s interval
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // enable interrupt timer peripheral
REGISTER_INTERRUPT(TIM6_DAC_IRQn, TIM6_DAC_IRQ_Handler, 1, FAULT_INTERRUPT_RATE_INTERRUPTS)
TIM6->PSC = 732-1;
TIM6->DIER = TIM_DIER_UIE;
TIM6->CR1 = TIM_CR1_CEN;
TIM6->SR = 0;
NVIC_EnableIRQ(TIM6_DAC_IRQn);
}

// ********************* Bare interrupt handlers *********************
// Only implemented the STM32F413 interrupts for now, the STM32F203 specific ones do not fall into the scope of SIL2

void WWDG_IRQHandler(void) {handle_interrupt(WWDG_IRQn);}
void PVD_IRQHandler(void) {handle_interrupt(PVD_IRQn);}
void TAMP_STAMP_IRQHandler(void) {handle_interrupt(TAMP_STAMP_IRQn);}
void RTC_WKUP_IRQHandler(void) {handle_interrupt(RTC_WKUP_IRQn);}
void FLASH_IRQHandler(void) {handle_interrupt(FLASH_IRQn);}
void RCC_IRQHandler(void) {handle_interrupt(RCC_IRQn);}
void EXTI0_IRQHandler(void) {handle_interrupt(EXTI0_IRQn);}
void EXTI1_IRQHandler(void) {handle_interrupt(EXTI1_IRQn);}
void EXTI2_IRQHandler(void) {handle_interrupt(EXTI2_IRQn);}
void EXTI3_IRQHandler(void) {handle_interrupt(EXTI3_IRQn);}
void EXTI4_IRQHandler(void) {handle_interrupt(EXTI4_IRQn);}
void DMA1_Stream0_IRQHandler(void) {handle_interrupt(DMA1_Stream0_IRQn);}
void DMA1_Stream1_IRQHandler(void) {handle_interrupt(DMA1_Stream1_IRQn);}
void DMA1_Stream2_IRQHandler(void) {handle_interrupt(DMA1_Stream2_IRQn);}
void DMA1_Stream3_IRQHandler(void) {handle_interrupt(DMA1_Stream3_IRQn);}
void DMA1_Stream4_IRQHandler(void) {handle_interrupt(DMA1_Stream4_IRQn);}
void DMA1_Stream5_IRQHandler(void) {handle_interrupt(DMA1_Stream5_IRQn);}
void DMA1_Stream6_IRQHandler(void) {handle_interrupt(DMA1_Stream6_IRQn);}
void ADC_IRQHandler(void) {handle_interrupt(ADC_IRQn);}
void CAN1_TX_IRQHandler(void) {handle_interrupt(CAN1_TX_IRQn);}
void CAN1_RX0_IRQHandler(void) {handle_interrupt(CAN1_RX0_IRQn);}
void CAN1_RX1_IRQHandler(void) {handle_interrupt(CAN1_RX1_IRQn);}
void CAN1_SCE_IRQHandler(void) {handle_interrupt(CAN1_SCE_IRQn);}
void EXTI9_5_IRQHandler(void) {handle_interrupt(EXTI9_5_IRQn);}
void TIM1_BRK_TIM9_IRQHandler(void) {handle_interrupt(TIM1_BRK_TIM9_IRQn);}
void TIM1_UP_TIM10_IRQHandler(void) {handle_interrupt(TIM1_UP_TIM10_IRQn);}
void TIM1_TRG_COM_TIM11_IRQHandler(void) {handle_interrupt(TIM1_TRG_COM_TIM11_IRQn);}
void TIM1_CC_IRQHandler(void) {handle_interrupt(TIM1_CC_IRQn);}
void TIM2_IRQHandler(void) {handle_interrupt(TIM2_IRQn);}
void TIM3_IRQHandler(void) {handle_interrupt(TIM3_IRQn);}
void TIM4_IRQHandler(void) {handle_interrupt(TIM4_IRQn);}
void I2C1_EV_IRQHandler(void) {handle_interrupt(I2C1_EV_IRQn);}
void I2C1_ER_IRQHandler(void) {handle_interrupt(I2C1_ER_IRQn);}
void I2C2_EV_IRQHandler(void) {handle_interrupt(I2C2_EV_IRQn);}
void I2C2_ER_IRQHandler(void) {handle_interrupt(I2C2_ER_IRQn);}
void SPI1_IRQHandler(void) {handle_interrupt(SPI1_IRQn);}
void SPI2_IRQHandler(void) {handle_interrupt(SPI2_IRQn);}
void USART1_IRQHandler(void) {handle_interrupt(USART1_IRQn);}
void USART2_IRQHandler(void) {handle_interrupt(USART2_IRQn);}
void USART3_IRQHandler(void) {handle_interrupt(USART3_IRQn);}
void EXTI15_10_IRQHandler(void) {handle_interrupt(EXTI15_10_IRQn);}
void RTC_Alarm_IRQHandler(void) {handle_interrupt(RTC_Alarm_IRQn);}
void OTG_FS_WKUP_IRQHandler(void) {handle_interrupt(OTG_FS_WKUP_IRQn);}
void TIM8_BRK_TIM12_IRQHandler(void) {handle_interrupt(TIM8_BRK_TIM12_IRQn);}
void TIM8_UP_TIM13_IRQHandler(void) {handle_interrupt(TIM8_UP_TIM13_IRQn);}
void TIM8_TRG_COM_TIM14_IRQHandler(void) {handle_interrupt(TIM8_TRG_COM_TIM14_IRQn);}
void TIM8_CC_IRQHandler(void) {handle_interrupt(TIM8_CC_IRQn);}
void DMA1_Stream7_IRQHandler(void) {handle_interrupt(DMA1_Stream7_IRQn);}
void FSMC_IRQHandler(void) {handle_interrupt(FSMC_IRQn);}
void SDIO_IRQHandler(void) {handle_interrupt(SDIO_IRQn);}
void TIM5_IRQHandler(void) {handle_interrupt(TIM5_IRQn);}
void SPI3_IRQHandler(void) {handle_interrupt(SPI3_IRQn);}
void UART4_IRQHandler(void) {handle_interrupt(UART4_IRQn);}
void UART5_IRQHandler(void) {handle_interrupt(UART5_IRQn);}
void TIM6_DAC_IRQHandler(void) {handle_interrupt(TIM6_DAC_IRQn);}
void TIM7_IRQHandler(void) {handle_interrupt(TIM7_IRQn);}
void DMA2_Stream0_IRQHandler(void) {handle_interrupt(DMA2_Stream0_IRQn);}
void DMA2_Stream1_IRQHandler(void) {handle_interrupt(DMA2_Stream1_IRQn);}
void DMA2_Stream2_IRQHandler(void) {handle_interrupt(DMA2_Stream2_IRQn);}
void DMA2_Stream3_IRQHandler(void) {handle_interrupt(DMA2_Stream3_IRQn);}
void DMA2_Stream4_IRQHandler(void) {handle_interrupt(DMA2_Stream4_IRQn);}
void CAN2_TX_IRQHandler(void) {handle_interrupt(CAN2_TX_IRQn);}
void CAN2_RX0_IRQHandler(void) {handle_interrupt(CAN2_RX0_IRQn);}
void CAN2_RX1_IRQHandler(void) {handle_interrupt(CAN2_RX1_IRQn);}
void CAN2_SCE_IRQHandler(void) {handle_interrupt(CAN2_SCE_IRQn);}
void OTG_FS_IRQHandler(void) {handle_interrupt(OTG_FS_IRQn);}
void DMA2_Stream5_IRQHandler(void) {handle_interrupt(DMA2_Stream5_IRQn);}
void DMA2_Stream6_IRQHandler(void) {handle_interrupt(DMA2_Stream6_IRQn);}
void DMA2_Stream7_IRQHandler(void) {handle_interrupt(DMA2_Stream7_IRQn);}
void USART6_IRQHandler(void) {handle_interrupt(USART6_IRQn);}
void I2C3_EV_IRQHandler(void) {handle_interrupt(I2C3_EV_IRQn);}
void I2C3_ER_IRQHandler(void) {handle_interrupt(I2C3_ER_IRQn);}
#ifdef STM32F4
void DFSDM1_FLT0_IRQHandler(void) {handle_interrupt(DFSDM1_FLT0_IRQn);}
void DFSDM1_FLT1_IRQHandler(void) {handle_interrupt(DFSDM1_FLT1_IRQn);}
void CAN3_TX_IRQHandler(void) {handle_interrupt(CAN3_TX_IRQn);}
void CAN3_RX0_IRQHandler(void) {handle_interrupt(CAN3_RX0_IRQn);}
void CAN3_RX1_IRQHandler(void) {handle_interrupt(CAN3_RX1_IRQn);}
void CAN3_SCE_IRQHandler(void) {handle_interrupt(CAN3_SCE_IRQn);}
void RNG_IRQHandler(void) {handle_interrupt(RNG_IRQn);}
void FPU_IRQHandler(void) {handle_interrupt(FPU_IRQn);}
void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);}
void UART8_IRQHandler(void) {handle_interrupt(UART8_IRQn);}
void SPI4_IRQHandler(void) {handle_interrupt(SPI4_IRQn);}
void SPI5_IRQHandler(void) {handle_interrupt(SPI5_IRQn);}
void SAI1_IRQHandler(void) {handle_interrupt(SAI1_IRQn);}
void UART9_IRQHandler(void) {handle_interrupt(UART9_IRQn);}
void UART10_IRQHandler(void) {handle_interrupt(UART10_IRQn);}
void QUADSPI_IRQHandler(void) {handle_interrupt(QUADSPI_IRQn);}
void FMPI2C1_EV_IRQHandler(void) {handle_interrupt(FMPI2C1_EV_IRQn);}
void FMPI2C1_ER_IRQHandler(void) {handle_interrupt(FMPI2C1_ER_IRQn);}
void LPTIM1_IRQHandler(void) {handle_interrupt(LPTIM1_IRQn);}
void DFSDM2_FLT0_IRQHandler(void) {handle_interrupt(DFSDM2_FLT0_IRQn);}
void DFSDM2_FLT1_IRQHandler(void) {handle_interrupt(DFSDM2_FLT1_IRQn);}
void DFSDM2_FLT2_IRQHandler(void) {handle_interrupt(DFSDM2_FLT2_IRQn);}
void DFSDM2_FLT3_IRQHandler(void) {handle_interrupt(DFSDM2_FLT3_IRQn);}
#endif
Loading

0 comments on commit 656f99b

Please sign in to comment.