diff --git a/.gitignore b/.gitignore index 612b14f74d5..527a4bce5ff 100644 --- a/.gitignore +++ b/.gitignore @@ -14,7 +14,7 @@ a.out dist/ build/ pandacan.egg-info/ -obj/ +/board/obj/ examples/output.csv .DS_Store .vscode* diff --git a/SConscript b/SConscript index 957982cae81..0f2208c5277 100644 --- a/SConscript +++ b/SConscript @@ -60,7 +60,7 @@ def to_c_uint32(x): return "{" + 'U,'.join(map(str, nums)) + "U}" -def build_project(project_name, project, main, extra_flags): +def build_project(project_name, project, main, shared, extra_flags): project_dir = Dir(f'./board/obj/{project_name}/') flags = project["FLAGS"] + extra_flags + common_flags + [ @@ -100,28 +100,73 @@ def build_project(project_name, project, main, extra_flags): startup = env.Object(project["STARTUP_FILE"]) + shared += [ + "./crypto/rsa.c", + "./crypto/sha.c", + "./board/libc.c", + "./board/early_init.c", + "./board/drivers/critical.c", + "./board/drivers/led.c", + "./board/drivers/pwm.c", + "./board/drivers/gpio.c", + "./board/drivers/fake_siren.c", + "./board/stm32h7/lli2c.c", + "./board/stm32h7/clock.c", + "./board/drivers/clock_source.c", + "./board/stm32h7/sound.c", + "./board/stm32h7/llflash.c", + "./board/stm32h7/stm32h7_config.c", + "./board/drivers/registers.c", + "./board/drivers/interrupts.c", + "./board/stm32h7/interrupt_handlers.c", + "./board/provision.c", + "./board/stm32h7/peripherals.c", + "./board/stm32h7/llusb.c", + "./board/drivers/usb.c", + "./board/drivers/spi.c", + "./board/drivers/timers.c", + "./board/stm32h7/lladc.c", + "./board/stm32h7/llspi.c", + "./board/drivers/faults.c", + "./board/boards/unused_funcs.c", + "./board/utils.c", + "./board/globals.c", + "./board/obj/gitversion.c", + "./board/stm32h7/lluart.c", + "./board/drivers/uart.c", + ] + # Build bootstub bs_env = env.Clone() + bs_obj_dir = Dir(f'./board/obj/{project_name}/bootstub') + bs_env = env.Clone(OBJPREFIX=bs_obj_dir) + bs_env.Append(CFLAGS="-DBOOTSTUB", ASFLAGS="-DBOOTSTUB", LINKFLAGS="-DBOOTSTUB") bs_elf = bs_env.Program(f"{project_dir}/bootstub.elf", [ startup, - "./crypto/rsa.c", - "./crypto/sha.c", "./board/bootstub.c", - ]) + "./board/drivers/flasher.c", + ] + shared) bs_env.Objcopy(f"./board/obj/bootstub.{project_name}.bin", bs_elf) # Build + sign main (aka app) main_elf = env.Program(f"{project_dir}/main.elf", [ startup, - main - ], LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags) + "./board/can_comms.c", + "./board/drivers/fan.c", + "./board/drivers/power_saving.c", + "./board/stm32h7/llfdcan.c", + "./board/drivers/harness.c", + "./board/drivers/bootkick.c", + "./board/stm32h7/llfan.c", + "./board/drivers/fdcan.c", + "./board/drivers/can_common.c", + main, + ] + shared, LINKFLAGS=[f"-Wl,--section-start,.isr_vector={project['APP_START_ADDRESS']}"] + flags) main_bin = env.Objcopy(f"{project_dir}/main.bin", main_elf) - sign_py = File(f"./crypto/sign.py").srcnode().relpath + sign_py = File(f"crypto/sign.py").srcnode().relpath env.Command(f"./board/obj/{project_name}.bin.signed", main_bin, f"SETLEN=1 {sign_py} $SOURCE $TARGET {cert_fn}") - - base_project_h7 = { "STARTUP_FILE": "./board/stm32h7/startup_stm32h7x5xx.s", "LINKER_SCRIPT": "./board/stm32h7/stm32h7x5_flash.ld", @@ -137,21 +182,40 @@ base_project_h7 = { } # Common autogenerated includes -with open("board/obj/gitversion.h", "w") as f: +with open("./board/obj/gitversion.c", "w") as f: version = get_version(BUILDER, BUILD_TYPE) - f.write(f'extern const uint8_t gitversion[{len(version)+1}];\n') + f.write('#include "gitversion.h"\n') f.write(f'const uint8_t gitversion[{len(version)+1}] = "{version}";\n') -with open("board/obj/version", "w") as f: +with open("./board/obj/gitversion.h", "w") as f: + version = get_version(BUILDER, BUILD_TYPE) + f.write("#pragma once\n") + f.write("#include \n") + f.write(f'extern const uint8_t gitversion[{len(version)+1}];\n') + +with open("./board/obj/version", "w") as f: f.write(f'{get_version(BUILDER, BUILD_TYPE)}') certs = [get_key_header(n) for n in ["debug", "release"]] -with open("board/obj/cert.h", "w") as f: +with open("./board/obj/cert.h", "w") as f: for cert in certs: f.write("\n".join(cert) + "\n") -# panda fw -build_project("panda_h7", base_project_h7, "./board/main.c", []) +panda_main = [ + "./board/main_comms.c", + "./board/main.c", + "./board/drivers/simple_watchdog.c", +] + +panda_shared = [ + "./board/stm32h7/board.c", + "./board/boards/tres.c", + "./board/boards/red.c", + "./board/boards/cuatro.c", + "./board/main_definitions.c" +] + +build_project("panda_h7", base_project_h7, panda_main, panda_shared, ["-DPANDA"]) # panda jungle fw flags = [ @@ -159,10 +223,30 @@ flags = [ ] if os.getenv("FINAL_PROVISIONING"): flags += ["-DFINAL_PROVISIONING"] -build_project("panda_jungle_h7", base_project_h7, "./board/jungle/main.c", flags) + +jungle_main = [ + "./board/jungle/main_comms.c", + "./board/jungle/main.c", +] +jungle_shared = [ + "./board/jungle/stm32h7/board.c", + "./board/jungle/boards/board_v2.c", +] +build_project("panda_jungle_h7", base_project_h7, jungle_main, jungle_shared, flags) # body fw -build_project("body_h7", base_project_h7, "./board/body/main.c", ["-DPANDA_BODY"]) +body_main = [ + "./board/body/main.c", + "./board/body/main_comms.c", +] +body_shared = [ + "./board/body/boards/board_body.c", + "./board/body/stm32h7/board.c", + "./board/body/motor_control.c", + "./board/body/motor_encoder.c" +] + +build_project("body_h7", base_project_h7, body_main, body_shared, ["-DPANDA_BODY"]) # test files if GetOption('extras'): diff --git a/board/boards/board_declarations.h b/board/boards/board_declarations.h deleted file mode 100644 index ff5ca97a86b..00000000000 --- a/board/boards/board_declarations.h +++ /dev/null @@ -1,62 +0,0 @@ -#pragma once - -#include -#include - -// ******************** Prototypes ******************** -typedef enum { - BOOT_STANDBY, - BOOT_BOOTKICK, - BOOT_RESET, -} BootState; - -typedef void (*board_init)(void); -typedef void (*board_init_bootloader)(void); -typedef void (*board_enable_can_transceiver)(uint8_t transceiver, bool enabled); -typedef void (*board_set_can_mode)(uint8_t mode); -typedef uint32_t (*board_read_voltage_mV)(void); -typedef uint32_t (*board_read_current_mA)(void); -typedef void (*board_set_ir_power)(uint8_t percentage); -typedef void (*board_set_fan_enabled)(bool enabled); -typedef void (*board_set_siren)(bool enabled); -typedef void (*board_set_bootkick)(BootState state); -typedef bool (*board_read_som_gpio)(void); -typedef void (*board_set_amp_enabled)(bool enabled); - -struct board { - harness_configuration *harness_config; - GPIO_TypeDef * const led_GPIO[3]; - const uint8_t led_pin[3]; - const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM - const bool has_spi; - const bool has_fan; - const uint16_t avdd_mV; - const uint8_t fan_enable_cooldown_time; - board_init init; - board_init_bootloader init_bootloader; - board_enable_can_transceiver enable_can_transceiver; - board_set_can_mode set_can_mode; - board_read_voltage_mV read_voltage_mV; - board_read_current_mA read_current_mA; - board_set_ir_power set_ir_power; - board_set_fan_enabled set_fan_enabled; - board_set_siren set_siren; - board_set_bootkick set_bootkick; - board_read_som_gpio read_som_gpio; - board_set_amp_enabled set_amp_enabled; -}; - -// ******************* Definitions ******************** -// These should match the enums in cereal/log.capnp and __init__.py -#define HW_TYPE_UNKNOWN 0U -#define HW_TYPE_RED_PANDA 7U -#define HW_TYPE_TRES 9U -#define HW_TYPE_CUATRO 10U - -// CAN modes -#define CAN_MODE_NORMAL 0U -#define CAN_MODE_OBD_CAN2 1U - -extern struct board board_tres; -extern struct board board_cuatro; -extern struct board board_red; diff --git a/board/boards/boards.h b/board/boards/boards.h new file mode 100644 index 00000000000..7b98fd295cd --- /dev/null +++ b/board/boards/boards.h @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +#include "board/config.h" + +// ======================= BOOT STATE ======================= + +typedef enum { + BOOT_STANDBY, + BOOT_BOOTKICK, + BOOT_RESET, +} BootState; + +// ======================= BOARD FUNCTION TYPES ======================= + +typedef bool (*board_get_button)(void); +typedef bool (*board_read_som_gpio)(void); +typedef float (*board_get_channel_power)(uint8_t channel); +typedef uint16_t (*board_get_sbu_mV)(uint8_t channel, uint8_t sbu); +typedef uint32_t (*board_read_current_mA)(void); +typedef uint32_t (*board_read_voltage_mV)(void); +typedef void (*board_board_tick)(void); +typedef void (*board_enable_can_transceiver)(uint8_t transceiver, bool enabled); +typedef void (*board_enable_header_pin)(uint8_t pin_num, bool enabled); +typedef void (*board_init_bootloader)(void); +typedef void (*board_init)(void); +typedef void (*board_set_amp_enabled)(bool enabled); +typedef void (*board_set_bootkick)(BootState state); +typedef void (*board_set_can_mode)(uint8_t mode); +typedef void (*board_set_fan_enabled)(bool enabled); +typedef void (*board_set_harness_orientation)(uint8_t orientation); +typedef void (*board_set_ignition)(bool enabled); +typedef void (*board_set_individual_ignition)(uint8_t bitmask); +typedef void (*board_set_ir_power)(uint8_t percentage); +typedef void (*board_set_panda_individual_power)(uint8_t port_num, bool enabled); +typedef void (*board_set_panda_power)(bool enabled); +typedef void (*board_set_siren)(bool enabled); + +// ======================= BOARD STRUCT ======================= + +typedef struct board { + struct harness_configuration *harness_config; + GPIO_TypeDef * const led_GPIO[3]; + const uint8_t led_pin[3]; + const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM + const bool has_spi; + const bool has_fan; + const uint16_t avdd_mV; + const uint8_t fan_enable_cooldown_time; + board_init init; + board_init_bootloader init_bootloader; + board_board_tick board_tick; + board_set_panda_power set_panda_power; + board_get_button get_button; + board_enable_can_transceiver enable_can_transceiver; + board_set_can_mode set_can_mode; + board_read_voltage_mV read_voltage_mV; + board_read_current_mA read_current_mA; + board_set_ir_power set_ir_power; + board_set_fan_enabled set_fan_enabled; + board_set_siren set_siren; + board_set_bootkick set_bootkick; + board_read_som_gpio read_som_gpio; + board_set_amp_enabled set_amp_enabled; + board_set_panda_individual_power set_panda_individual_power; + board_set_ignition set_ignition; + board_set_individual_ignition set_individual_ignition; + board_set_harness_orientation set_harness_orientation; + board_enable_header_pin enable_header_pin; + board_get_channel_power get_channel_power; + board_get_sbu_mV get_sbu_mV; +} board; + +// ======================= UNUSED FUNCS ======================= + +void unused_init_bootloader(void); +void unused_set_ir_power(uint8_t percentage); +void unused_set_fan_enabled(bool enabled); +void unused_set_siren(bool enabled); +uint32_t unused_read_current(void); +void unused_set_bootkick(BootState state); +bool unused_read_som_gpio(void); +void unused_set_amp_enabled(bool enabled); + +// ======================= RED ======================= +// Red Panda (STM32H7) + Harness + +struct harness_configuration; + +extern struct harness_configuration red_harness_config; +extern struct board board_red; + +uint32_t red_read_voltage_mV(void); + +// ======================= TRES ======================= + +extern struct board board_tres; + +void tres_set_can_mode(uint8_t mode); +bool tres_read_som_gpio(void); + +// ======================= CUATRO ======================= +// Cuatro (STM32H7) + Harness + +extern struct board board_cuatro; diff --git a/board/boards/cuatro.h b/board/boards/cuatro.c similarity index 96% rename from board/boards/cuatro.h rename to board/boards/cuatro.c index 0c34174cf3d..b1b17daa92b 100644 --- a/board/boards/cuatro.h +++ b/board/boards/cuatro.c @@ -1,6 +1,7 @@ -#pragma once - -#include "board_declarations.h" +#include "board/config.h" +#include "board/boards/boards.h" +#include "board/drivers/drivers.h" +#include "board/stm32h7/lldrivers.h" // ////////////////////////// // // Cuatro (STM32H7) + Harness // diff --git a/board/boards/red.h b/board/boards/red.c similarity index 95% rename from board/boards/red.h rename to board/boards/red.c index 761c2799ec8..4e1903bc6cf 100644 --- a/board/boards/red.h +++ b/board/boards/red.c @@ -1,6 +1,6 @@ -#pragma once +#include "boards.h" -#include "board_declarations.h" +#include "board/globals.h" // ///////////////////////////// // // Red Panda (STM32H7) + Harness // @@ -67,7 +67,7 @@ static void red_set_can_mode(uint8_t mode) { } } -static uint32_t red_read_voltage_mV(void){ +uint32_t red_read_voltage_mV(void){ return adc_get_mV(&(const adc_signal_t) ADC_CHANNEL_DEFAULT(ADC1, 2)) * 11U; } @@ -98,7 +98,7 @@ static void red_init(void) { set_gpio_output(GPIOB, 14, 1); } -static harness_configuration red_harness_config = { +harness_configuration red_harness_config = { .GPIO_SBU1 = GPIOC, .GPIO_SBU2 = GPIOA, .GPIO_relay_SBU1 = GPIOC, @@ -111,7 +111,7 @@ static harness_configuration red_harness_config = { .adc_signal_SBU2 = ADC_CHANNEL_DEFAULT(ADC1, 17) }; -board board_red = { +struct board board_red = { .set_bootkick = unused_set_bootkick, .harness_config = &red_harness_config, .has_spi = false, diff --git a/board/boards/tres.h b/board/boards/tres.c similarity index 95% rename from board/boards/tres.h rename to board/boards/tres.c index 653df969925..eab495b087a 100644 --- a/board/boards/tres.h +++ b/board/boards/tres.c @@ -1,6 +1,8 @@ -#pragma once +#include "boards.h" -#include "board_declarations.h" +#include "board/drivers/drivers.h" +#include "board/globals.h" +#include "board/stm32h7/lldrivers.h" // /////////////////////////// // Tres (STM32H7) + Harness // @@ -55,7 +57,7 @@ static void tres_enable_can_transceiver(uint8_t transceiver, bool enabled) { set_gpio_output(GPIOD, 7, !(can0_enabled || can2_enabled)); } -static void tres_set_can_mode(uint8_t mode) { +void tres_set_can_mode(uint8_t mode) { current_board->enable_can_transceiver(2U, false); current_board->enable_can_transceiver(4U, false); switch (mode) { @@ -97,7 +99,7 @@ static void tres_set_can_mode(uint8_t mode) { } } -static bool tres_read_som_gpio (void) { +bool tres_read_som_gpio (void) { return (get_gpio_input(GPIOC, 2) != 0); } @@ -105,7 +107,7 @@ static void tres_init(void) { // Enable USB 3.3V LDO for USB block register_set_bits(&(PWR->CR3), PWR_CR3_USBREGEN); register_set_bits(&(PWR->CR3), PWR_CR3_USB33DEN); - while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0U); + while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0U) {} common_init_gpio(); diff --git a/board/boards/unused_funcs.h b/board/boards/unused_funcs.c similarity index 85% rename from board/boards/unused_funcs.h rename to board/boards/unused_funcs.c index 588cf63654d..f6506cd78b6 100644 --- a/board/boards/unused_funcs.h +++ b/board/boards/unused_funcs.c @@ -1,4 +1,6 @@ -#pragma once +#include "boards.h" + +#include "board/utils.h" void unused_init_bootloader(void) { } @@ -27,6 +29,7 @@ bool unused_read_som_gpio(void) { return false; } +// cppcheck-suppress misra-c2012-8.7 void unused_set_amp_enabled(bool enabled) { UNUSED(enabled); } diff --git a/board/body/boards/board_body.c b/board/body/boards/board_body.c new file mode 100644 index 00000000000..dc8fc2a2685 --- /dev/null +++ b/board/body/boards/board_body.c @@ -0,0 +1,23 @@ +#include "board_body.h" + +#include "board/boards/boards.h" + +void board_body_init(void) { + motor_init(); + motor_encoder_init(); + motor_speed_controller_init(); + motor_encoder_reset(1); + motor_encoder_reset(2); + + // Initialize CAN pins + set_gpio_pullup(GPIOD, 0, PULL_NONE); + set_gpio_alternate(GPIOD, 0, GPIO_AF9_FDCAN1); + set_gpio_pullup(GPIOD, 1, PULL_NONE); + set_gpio_alternate(GPIOD, 1, GPIO_AF9_FDCAN1); +} + +struct board board_body = { + .led_GPIO = {GPIOC, GPIOC, GPIOC}, + .led_pin = {7, 7, 7}, + .init = board_body_init, +}; diff --git a/board/body/boards/board_body.h b/board/body/boards/board_body.h index a1eebfdb8d2..8d65e9928a3 100644 --- a/board/body/boards/board_body.h +++ b/board/body/boards/board_body.h @@ -1,21 +1,7 @@ -#include "board/body/motor_control.h" +#pragma once -void board_body_init(void) { - motor_init(); - motor_encoder_init(); - motor_speed_controller_init(); - motor_encoder_reset(1); - motor_encoder_reset(2); +#include "board/body/motor_control.h" - // Initialize CAN pins - set_gpio_pullup(GPIOD, 0, PULL_NONE); - set_gpio_alternate(GPIOD, 0, GPIO_AF9_FDCAN1); - set_gpio_pullup(GPIOD, 1, PULL_NONE); - set_gpio_alternate(GPIOD, 1, GPIO_AF9_FDCAN1); -} +void board_body_init(void); -board board_body = { - .led_GPIO = {GPIOC, GPIOC, GPIOC}, - .led_pin = {7, 7, 7}, - .init = board_body_init, -}; +extern struct board board_body; \ No newline at end of file diff --git a/board/body/boards/board_declarations.h b/board/body/boards/board_declarations.h deleted file mode 100644 index 09c43f86672..00000000000 --- a/board/body/boards/board_declarations.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include -#include - -// ******************** Prototypes ******************** -typedef void (*board_init)(void); -typedef void (*board_init_bootloader)(void); -typedef void (*board_enable_can_transceiver)(uint8_t transceiver, bool enabled); - -struct board { - GPIO_TypeDef * const led_GPIO[3]; - const uint8_t led_pin[3]; - const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM - board_init init; - board_init_bootloader init_bootloader; - const bool has_spi; -}; - -// ******************* Definitions ******************** -#define HW_TYPE_BODY 0xB1U diff --git a/board/body/can.h b/board/body/can.h index 94010ded051..3533b66e35d 100644 --- a/board/body/can.h +++ b/board/body/can.h @@ -6,7 +6,7 @@ #include "board/can.h" #include "board/health.h" #include "board/body/motor_control.h" -#include "board/drivers/can_common_declarations.h" +#include "board/drivers/drivers.h" #include "opendbc/safety/declarations.h" #define BODY_CAN_ADDR_MOTOR_SPEED 0x201U diff --git a/board/body/main.c b/board/body/main.c index 4a2d0b4c537..c06576a343b 100644 --- a/board/body/main.c +++ b/board/body/main.c @@ -2,19 +2,13 @@ #include #include "board/config.h" -#include "board/drivers/led.h" -#include "board/drivers/pwm.h" -#include "board/drivers/usb.h" +#include "board/drivers/drivers.h" #include "board/early_init.h" #include "board/obj/gitversion.h" #include "board/body/motor_control.h" #include "board/body/can.h" #include "opendbc/safety/safety.h" -#include "board/drivers/can_common.h" -#include "board/drivers/fdcan.h" -#include "board/can_comms.h" - -extern int _app_start[0xc000]; +#include "board/body/boards/board_body.h" #include "board/body/main_comms.h" diff --git a/board/body/main_comms.c b/board/body/main_comms.c new file mode 100644 index 00000000000..5f87e21d6c9 --- /dev/null +++ b/board/body/main_comms.c @@ -0,0 +1,118 @@ +#include "board/body/main_comms.h" +#include "board/globals.h" +#include "board/config.h" +#include "board/health.h" +#include "board/provision.h" +#include "board/early_init.h" +#include "board/obj/gitversion.h" +#include "board/stm32h7/lldrivers.h" +#include "board/libc.h" +#include "board/drivers/drivers.h" +#include "board/body/motor_control.h" +#include "board/print.h" + +void comms_endpoint2_write(const uint8_t *data, uint32_t len) { + UNUSED(data); + UNUSED(len); +} + +int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { + unsigned int resp_len = 0; + + switch (req->request) { + // **** 0xc1: get hardware type + case 0xc1: + resp[0] = hw_type; + resp_len = 1; + break; + + // **** 0xd1: enter bootloader mode + case 0xd1: + switch (req->param1) { + case 0: + print("-> entering bootloader\n"); + enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; + NVIC_SystemReset(); + break; + case 1: + print("-> entering softloader\n"); + enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; + NVIC_SystemReset(); + break; + default: + print("Bootloader mode invalid\n"); + break; + } + break; + + // **** 0xd3/0xd4: signature bytes + case 0xd3: + case 0xd4: { + uint8_t offset = (req->request == 0xd3) ? 0U : 64U; + resp_len = 64U; + char *code = (char *)_app_start; + int code_len = _app_start[0]; + (void)memcpy(resp, &code[code_len + offset], resp_len); + break; + } + + // **** 0xd6: get version + case 0xd6: + (void)memcpy(resp, gitversion, sizeof(gitversion)); + resp_len = sizeof(gitversion) - 1U; + break; + + // **** 0xd8: reset ST + case 0xd8: + NVIC_SystemReset(); + break; + + // **** 0xe0: set motor speed + case 0xe0: + motor_set_speed((uint8_t)req->param1, (int8_t)req->param2); + break; + + // **** 0xe1: stop motor + case 0xe1: + motor_set_speed((uint8_t)req->param1, 0); + break; + + // **** 0xe2: get motor encoder state + case 0xe2: { + uint8_t motor = (uint8_t)req->param1; + int32_t position = motor_encoder_get_position(motor); + float rpm = motor_encoder_get_speed_rpm(motor); + int32_t rpm_milli = (int32_t)(rpm * 1000.0f); + (void)memcpy(resp, &position, sizeof(position)); + (void)memcpy(resp + sizeof(position), &rpm_milli, sizeof(rpm_milli)); + resp_len = (uint8_t)(sizeof(position) + sizeof(rpm_milli)); + break; + } + + // **** 0xe3: reset encoder position + case 0xe3: + motor_encoder_reset((uint8_t)req->param1); + break; + + // **** 0xe4: set motor target speed (rpm * 0.1) + case 0xe4: { + uint8_t motor = (uint8_t)req->param1; + float target_rpm = ((int16_t)req->param2) * 0.1f; + motor_speed_controller_set_target_rpm(motor, target_rpm); + break; + } + + // **** 0xdd: get healthpacket and CANPacket versions + case 0xdd: + resp[0] = HEALTH_PACKET_VERSION; + resp[1] = CAN_PACKET_VERSION; + resp[2] = CAN_HEALTH_PACKET_VERSION; + resp_len = 3U; + break; + + default: + // Ignore unhandled requests + break; + } + return resp_len; +} diff --git a/board/body/main_comms.h b/board/body/main_comms.h index 95801332315..ef7823eecc4 100644 --- a/board/body/main_comms.h +++ b/board/body/main_comms.h @@ -1,105 +1,3 @@ -void comms_endpoint2_write(const uint8_t *data, uint32_t len) { - UNUSED(data); - UNUSED(len); -} +#pragma once -int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { - unsigned int resp_len = 0; - - switch (req->request) { - // **** 0xc1: get hardware type - case 0xc1: - resp[0] = hw_type; - resp_len = 1; - break; - - // **** 0xd1: enter bootloader mode - case 0xd1: - switch (req->param1) { - case 0: - print("-> entering bootloader\n"); - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - break; - case 1: - print("-> entering softloader\n"); - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - NVIC_SystemReset(); - break; - default: - print("Bootloader mode invalid\n"); - break; - } - break; - - // **** 0xd3/0xd4: signature bytes - case 0xd3: - case 0xd4: { - uint8_t offset = (req->request == 0xd3) ? 0U : 64U; - resp_len = 64U; - char *code = (char *)_app_start; - int code_len = _app_start[0]; - (void)memcpy(resp, &code[code_len + offset], resp_len); - break; - } - - // **** 0xd6: get version - case 0xd6: - (void)memcpy(resp, gitversion, sizeof(gitversion)); - resp_len = sizeof(gitversion) - 1U; - break; - - // **** 0xd8: reset ST - case 0xd8: - NVIC_SystemReset(); - break; - - // **** 0xe0: set motor speed - case 0xe0: - motor_set_speed((uint8_t)req->param1, (int8_t)req->param2); - break; - - // **** 0xe1: stop motor - case 0xe1: - motor_set_speed((uint8_t)req->param1, 0); - break; - - // **** 0xe2: get motor encoder state - case 0xe2: { - uint8_t motor = (uint8_t)req->param1; - int32_t position = motor_encoder_get_position(motor); - float rpm = motor_encoder_get_speed_rpm(motor); - int32_t rpm_milli = (int32_t)(rpm * 1000.0f); - (void)memcpy(resp, &position, sizeof(position)); - (void)memcpy(resp + sizeof(position), &rpm_milli, sizeof(rpm_milli)); - resp_len = (uint8_t)(sizeof(position) + sizeof(rpm_milli)); - break; - } - - // **** 0xe3: reset encoder position - case 0xe3: - motor_encoder_reset((uint8_t)req->param1); - break; - - // **** 0xe4: set motor target speed (rpm * 0.1) - case 0xe4: { - uint8_t motor = (uint8_t)req->param1; - float target_rpm = ((int16_t)req->param2) * 0.1f; - motor_speed_controller_set_target_rpm(motor, target_rpm); - break; - } - - // **** 0xdd: get healthpacket and CANPacket versions - case 0xdd: - resp[0] = HEALTH_PACKET_VERSION; - resp[1] = CAN_PACKET_VERSION; - resp[2] = CAN_HEALTH_PACKET_VERSION; - resp_len = 3U; - break; - - default: - // Ignore unhandled requests - break; - } - return resp_len; -} +#include "board/globals.h" \ No newline at end of file diff --git a/board/body/motor_common.h b/board/body/motor_common.h index c2fa0548938..3c8df5d39d0 100644 --- a/board/body/motor_common.h +++ b/board/body/motor_common.h @@ -10,6 +10,4 @@ typedef enum { BODY_MOTOR_RIGHT = 2U, } body_motor_id_e; -static inline bool body_motor_is_valid(uint8_t motor) { - return (motor > 0U) && (motor <= BODY_MOTOR_COUNT); -} +bool body_motor_is_valid(uint8_t motor); diff --git a/board/body/motor_control.c b/board/body/motor_control.c new file mode 100644 index 00000000000..119b4a868ad --- /dev/null +++ b/board/body/motor_control.c @@ -0,0 +1,256 @@ +#include +#include + +#include "board/body/motor_common.h" +#include "board/body/motor_control.h" +#include "board/body/motor_encoder.h" + +#include "board/drivers/drivers.h" + +// Motor pin map: +// M1 drive: PB8 -> TIM16_CH1, PB9 -> TIM17_CH1, PE2/PE3 enables +// M2 drive: PA2 -> TIM15_CH1, PA3 -> TIM15_CH2, PE8/PE9 enables + +#define PWM_TIMER_CLOCK_HZ 120000000U +#define PWM_FREQUENCY_HZ 5000U +#define PWM_PERCENT_MAX 100 +#define PWM_RELOAD_TICKS ((PWM_TIMER_CLOCK_HZ + (PWM_FREQUENCY_HZ / 2U)) / PWM_FREQUENCY_HZ) + +#define KP 0.25f +#define KI 0.5f +#define KD 0.008f +#define KFF 0.9f +#define MAX_RPM 100.0f +#define OUTPUT_MAX 100.0f +#define DEADBAND_RPM 1.0f +#define UPDATE_PERIOD_US 1000U + +typedef struct { + TIM_TypeDef *forward_timer; + uint8_t forward_channel; + TIM_TypeDef *reverse_timer; + uint8_t reverse_channel; + GPIO_TypeDef *pwm_port[2]; + uint8_t pwm_pin[2]; + uint8_t pwm_af[2]; + GPIO_TypeDef *enable_port[2]; + uint8_t enable_pin[2]; +} motor_pwm_config_t; + +static const motor_pwm_config_t motor_pwm_config[BODY_MOTOR_COUNT] = { + [BODY_MOTOR_LEFT - 1U] = { + TIM16, 1U, TIM17, 1U, + {GPIOB, GPIOB}, {8U, 9U}, {GPIO_AF1_TIM16, GPIO_AF1_TIM17}, + {GPIOE, GPIOE}, {2U, 3U}, + }, + [BODY_MOTOR_RIGHT - 1U] = { + TIM15, 2U, TIM15, 1U, + {GPIOA, GPIOA}, {2U, 3U}, {GPIO_AF4_TIM15, GPIO_AF4_TIM15}, + {GPIOE, GPIOE}, {8U, 9U}, + }, +}; + +typedef struct { + bool active; + float target_rpm; + float integral; + float previous_error; + float last_output; + uint32_t last_update_us; +} motor_speed_state_t; + +static inline float motor_absf(float value) { + return (value < 0.0f) ? -value : value; +} + +static inline float motor_clampf(float value, float min_value, float max_value) { + if (value < min_value) { + return min_value; + } + if (value > max_value) { + return max_value; + } + return value; +} + +static motor_speed_state_t motor_speed_states[BODY_MOTOR_COUNT]; + +static inline void motor_pwm_write(TIM_TypeDef *timer, uint8_t channel, uint8_t percentage) { + uint32_t period = (timer->ARR != 0U) ? timer->ARR : PWM_RELOAD_TICKS; + uint16_t comp = (uint16_t)((period * (uint32_t)percentage) / 100U); + if (channel == 1U) { + register_set(&(timer->CCR1), comp, 0xFFFFU); + } else if (channel == 2U) { + register_set(&(timer->CCR2), comp, 0xFFFFU); + } +} + +static inline motor_speed_state_t *motor_speed_state_get(uint8_t motor) { + return body_motor_is_valid(motor) ? &motor_speed_states[motor - 1U] : NULL; +} + +static inline void motor_speed_state_reset(motor_speed_state_t *state) { + state->active = false; + state->target_rpm = 0.0f; + state->integral = 0.0f; + state->previous_error = 0.0f; + state->last_output = 0.0f; + state->last_update_us = 0U; +} + +void motor_speed_controller_init(void) { + for (uint8_t i = 0U; i < BODY_MOTOR_COUNT; i++) { + motor_speed_state_reset(&motor_speed_states[i]); + } +} + +static void motor_speed_controller_disable(uint8_t motor) { + motor_speed_state_t *state = motor_speed_state_get(motor); + if (state == NULL) { + return; + } + motor_speed_state_reset(state); +} + +static inline void motor_write_enable(uint8_t motor_index, bool enable) { + const motor_pwm_config_t *cfg = &motor_pwm_config[motor_index]; + uint8_t level = enable ? 1U : 0U; + set_gpio_output(cfg->enable_port[0], cfg->enable_pin[0], level); + set_gpio_output(cfg->enable_port[1], cfg->enable_pin[1], level); +} + +void motor_init(void) { + register_set_bits(&(RCC->AHB4ENR), RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOEEN); + register_set_bits(&(RCC->APB2ENR), RCC_APB2ENR_TIM16EN | RCC_APB2ENR_TIM17EN | RCC_APB2ENR_TIM15EN); + + for (uint8_t i = 0U; i < BODY_MOTOR_COUNT; i++) { + const motor_pwm_config_t *cfg = &motor_pwm_config[i]; + motor_write_enable(i, false); + set_gpio_alternate(cfg->pwm_port[0], cfg->pwm_pin[0], cfg->pwm_af[0]); + set_gpio_alternate(cfg->pwm_port[1], cfg->pwm_pin[1], cfg->pwm_af[1]); + + pwm_init(cfg->forward_timer, cfg->forward_channel); + pwm_init(cfg->reverse_timer, cfg->reverse_channel); + + TIM_TypeDef *forward_timer = cfg->forward_timer; + register_set(&(forward_timer->PSC), 0U, 0xFFFFU); + register_set(&(forward_timer->ARR), PWM_RELOAD_TICKS, 0xFFFFU); + forward_timer->EGR |= TIM_EGR_UG; + register_set(&(forward_timer->BDTR), TIM_BDTR_MOE, 0xFFFFU); + + if (cfg->reverse_timer != cfg->forward_timer) { + TIM_TypeDef *reverse_timer = cfg->reverse_timer; + register_set(&(reverse_timer->PSC), 0U, 0xFFFFU); + register_set(&(reverse_timer->ARR), PWM_RELOAD_TICKS, 0xFFFFU); + reverse_timer->EGR |= TIM_EGR_UG; + register_set(&(reverse_timer->BDTR), TIM_BDTR_MOE, 0xFFFFU); + } + } +} + +static void motor_apply_pwm(uint8_t motor, int32_t speed_command) { + if (!body_motor_is_valid(motor)) { + return; + } + + int8_t speed = (int8_t)motor_clampf((float)speed_command, -(float)PWM_PERCENT_MAX, (float)PWM_PERCENT_MAX); + uint8_t pwm_value = (uint8_t)((speed < 0) ? -speed : speed); + uint8_t motor_index = motor - 1U; + motor_write_enable(motor_index, speed != 0); + const motor_pwm_config_t *cfg = &motor_pwm_config[motor_index]; + + if (speed > 0) { + motor_pwm_write(cfg->forward_timer, cfg->forward_channel, pwm_value); + motor_pwm_write(cfg->reverse_timer, cfg->reverse_channel, 0U); + } else if (speed < 0) { + motor_pwm_write(cfg->forward_timer, cfg->forward_channel, 0U); + motor_pwm_write(cfg->reverse_timer, cfg->reverse_channel, pwm_value); + } else { + motor_pwm_write(cfg->forward_timer, cfg->forward_channel, 0U); + motor_pwm_write(cfg->reverse_timer, cfg->reverse_channel, 0U); + } +} + +void motor_set_speed(uint8_t motor, int8_t speed) { + motor_speed_controller_disable(motor); + motor_apply_pwm(motor, (int32_t)speed); +} + +void motor_speed_controller_set_target_rpm(uint8_t motor, float target_rpm) { + motor_speed_state_t *state = motor_speed_state_get(motor); + if (state == NULL) { + return; + } + + target_rpm = motor_clampf(target_rpm, -MAX_RPM, MAX_RPM); + if (motor_absf(target_rpm) <= DEADBAND_RPM) { + motor_speed_controller_disable(motor); + motor_apply_pwm(motor, 0); + return; + } + + state->active = true; + state->target_rpm = target_rpm; + state->integral = 0.0f; + state->previous_error = target_rpm - motor_encoder_get_speed_rpm(motor); + state->last_output = 0.0f; + state->last_update_us = 0U; +} + +void motor_speed_controller_update(uint32_t now_us) { + for (uint8_t motor = BODY_MOTOR_LEFT; motor <= BODY_MOTOR_RIGHT; motor++) { + motor_speed_state_t *state = motor_speed_state_get(motor); + if (!state->active) { + continue; + } + + bool first_update = (state->last_update_us == 0U); + uint32_t dt_us = first_update ? UPDATE_PERIOD_US : (now_us - state->last_update_us); + if (!first_update && (dt_us < UPDATE_PERIOD_US)) { + continue; + } + + float measured_rpm = motor_encoder_get_speed_rpm(motor); + float error = state->target_rpm - measured_rpm; + + if ((motor_absf(state->target_rpm) <= DEADBAND_RPM) && (motor_absf(error) <= DEADBAND_RPM) && (motor_absf(measured_rpm) <= DEADBAND_RPM)) { + motor_speed_controller_disable(motor); + motor_apply_pwm(motor, 0); + continue; + } + + float dt_s = (float)dt_us * 1.0e-6f; + float control = KFF * state->target_rpm; + + if (dt_s > 0.0f) { + state->integral += error * dt_s; + float derivative = first_update ? 0.0f : (error - state->previous_error) / dt_s; + + control += (KP * error) + (KI * state->integral) + (KD * derivative); + } else { + state->integral = 0.0f; + control += KP * error; + } + + if ((state->target_rpm > 0.0f) && (control < 0.0f)) { + control = 0.0f; + state->integral = 0.0f; + } else if ((state->target_rpm < 0.0f) && (control > 0.0f)) { + control = 0.0f; + state->integral = 0.0f; + } + + control = motor_clampf(control, -OUTPUT_MAX, OUTPUT_MAX); + + int32_t command = (control >= 0.0f) ? (int32_t)(control + 0.5f) : (int32_t)(control - 0.5f); + motor_apply_pwm(motor, command); + + state->previous_error = error; + state->last_output = control; + state->last_update_us = now_us; + } +} + +inline bool body_motor_is_valid(uint8_t motor) { + return (motor > 0U) && (motor <= BODY_MOTOR_COUNT); +} diff --git a/board/body/motor_control.h b/board/body/motor_control.h index 8be9078b7fc..22b8144896f 100644 --- a/board/body/motor_control.h +++ b/board/body/motor_control.h @@ -6,6 +6,8 @@ #include "board/body/motor_common.h" #include "board/body/motor_encoder.h" +#include "board/drivers/drivers.h" + // Motor pin map: // M1 drive: PB8 -> TIM16_CH1, PB9 -> TIM17_CH1, PE2/PE3 enables // M2 drive: PA2 -> TIM15_CH1, PA3 -> TIM15_CH2, PE8/PE9 enables @@ -24,228 +26,8 @@ #define DEADBAND_RPM 1.0f #define UPDATE_PERIOD_US 1000U -typedef struct { - TIM_TypeDef *forward_timer; - uint8_t forward_channel; - TIM_TypeDef *reverse_timer; - uint8_t reverse_channel; - GPIO_TypeDef *pwm_port[2]; - uint8_t pwm_pin[2]; - uint8_t pwm_af[2]; - GPIO_TypeDef *enable_port[2]; - uint8_t enable_pin[2]; -} motor_pwm_config_t; - -static const motor_pwm_config_t motor_pwm_config[BODY_MOTOR_COUNT] = { - [BODY_MOTOR_LEFT - 1U] = { - TIM16, 1U, TIM17, 1U, - {GPIOB, GPIOB}, {8U, 9U}, {GPIO_AF1_TIM16, GPIO_AF1_TIM17}, - {GPIOE, GPIOE}, {2U, 3U}, - }, - [BODY_MOTOR_RIGHT - 1U] = { - TIM15, 2U, TIM15, 1U, - {GPIOA, GPIOA}, {2U, 3U}, {GPIO_AF4_TIM15, GPIO_AF4_TIM15}, - {GPIOE, GPIOE}, {8U, 9U}, - }, -}; - -typedef struct { - bool active; - float target_rpm; - float integral; - float previous_error; - float last_output; - uint32_t last_update_us; -} motor_speed_state_t; - -static inline float motor_absf(float value) { - return (value < 0.0f) ? -value : value; -} - -static inline float motor_clampf(float value, float min_value, float max_value) { - if (value < min_value) { - return min_value; - } - if (value > max_value) { - return max_value; - } - return value; -} - -static motor_speed_state_t motor_speed_states[BODY_MOTOR_COUNT]; - -static inline void motor_pwm_write(TIM_TypeDef *timer, uint8_t channel, uint8_t percentage) { - uint32_t period = (timer->ARR != 0U) ? timer->ARR : PWM_RELOAD_TICKS; - uint16_t comp = (uint16_t)((period * (uint32_t)percentage) / 100U); - if (channel == 1U) { - register_set(&(timer->CCR1), comp, 0xFFFFU); - } else if (channel == 2U) { - register_set(&(timer->CCR2), comp, 0xFFFFU); - } -} - -static inline motor_speed_state_t *motor_speed_state_get(uint8_t motor) { - return body_motor_is_valid(motor) ? &motor_speed_states[motor - 1U] : NULL; -} - -static inline void motor_speed_state_reset(motor_speed_state_t *state) { - state->active = false; - state->target_rpm = 0.0f; - state->integral = 0.0f; - state->previous_error = 0.0f; - state->last_output = 0.0f; - state->last_update_us = 0U; -} - -static void motor_speed_controller_init(void) { - for (uint8_t i = 0U; i < BODY_MOTOR_COUNT; i++) { - motor_speed_state_reset(&motor_speed_states[i]); - } -} - -static void motor_speed_controller_disable(uint8_t motor) { - motor_speed_state_t *state = motor_speed_state_get(motor); - if (state == NULL) { - return; - } - motor_speed_state_reset(state); -} - -static inline void motor_write_enable(uint8_t motor_index, bool enable) { - const motor_pwm_config_t *cfg = &motor_pwm_config[motor_index]; - uint8_t level = enable ? 1U : 0U; - set_gpio_output(cfg->enable_port[0], cfg->enable_pin[0], level); - set_gpio_output(cfg->enable_port[1], cfg->enable_pin[1], level); -} - -static void motor_init(void) { - register_set_bits(&(RCC->AHB4ENR), RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOEEN); - register_set_bits(&(RCC->APB2ENR), RCC_APB2ENR_TIM16EN | RCC_APB2ENR_TIM17EN | RCC_APB2ENR_TIM15EN); - - for (uint8_t i = 0U; i < BODY_MOTOR_COUNT; i++) { - const motor_pwm_config_t *cfg = &motor_pwm_config[i]; - motor_write_enable(i, false); - set_gpio_alternate(cfg->pwm_port[0], cfg->pwm_pin[0], cfg->pwm_af[0]); - set_gpio_alternate(cfg->pwm_port[1], cfg->pwm_pin[1], cfg->pwm_af[1]); - - pwm_init(cfg->forward_timer, cfg->forward_channel); - pwm_init(cfg->reverse_timer, cfg->reverse_channel); - - TIM_TypeDef *forward_timer = cfg->forward_timer; - register_set(&(forward_timer->PSC), 0U, 0xFFFFU); - register_set(&(forward_timer->ARR), PWM_RELOAD_TICKS, 0xFFFFU); - forward_timer->EGR |= TIM_EGR_UG; - register_set(&(forward_timer->BDTR), TIM_BDTR_MOE, 0xFFFFU); - - if (cfg->reverse_timer != cfg->forward_timer) { - TIM_TypeDef *reverse_timer = cfg->reverse_timer; - register_set(&(reverse_timer->PSC), 0U, 0xFFFFU); - register_set(&(reverse_timer->ARR), PWM_RELOAD_TICKS, 0xFFFFU); - reverse_timer->EGR |= TIM_EGR_UG; - register_set(&(reverse_timer->BDTR), TIM_BDTR_MOE, 0xFFFFU); - } - } -} - -static void motor_apply_pwm(uint8_t motor, int32_t speed_command) { - if (!body_motor_is_valid(motor)) { - return; - } - - int8_t speed = (int8_t)motor_clampf((float)speed_command, -(float)PWM_PERCENT_MAX, (float)PWM_PERCENT_MAX); - uint8_t pwm_value = (uint8_t)((speed < 0) ? -speed : speed); - uint8_t motor_index = motor - 1U; - motor_write_enable(motor_index, speed != 0); - const motor_pwm_config_t *cfg = &motor_pwm_config[motor_index]; - - if (speed > 0) { - motor_pwm_write(cfg->forward_timer, cfg->forward_channel, pwm_value); - motor_pwm_write(cfg->reverse_timer, cfg->reverse_channel, 0U); - } else if (speed < 0) { - motor_pwm_write(cfg->forward_timer, cfg->forward_channel, 0U); - motor_pwm_write(cfg->reverse_timer, cfg->reverse_channel, pwm_value); - } else { - motor_pwm_write(cfg->forward_timer, cfg->forward_channel, 0U); - motor_pwm_write(cfg->reverse_timer, cfg->reverse_channel, 0U); - } -} - -static inline void motor_set_speed(uint8_t motor, int8_t speed) { - motor_speed_controller_disable(motor); - motor_apply_pwm(motor, (int32_t)speed); -} - -static inline void motor_speed_controller_set_target_rpm(uint8_t motor, float target_rpm) { - motor_speed_state_t *state = motor_speed_state_get(motor); - if (state == NULL) { - return; - } - - target_rpm = motor_clampf(target_rpm, -MAX_RPM, MAX_RPM); - if (motor_absf(target_rpm) <= DEADBAND_RPM) { - motor_speed_controller_disable(motor); - motor_apply_pwm(motor, 0); - return; - } - - state->active = true; - state->target_rpm = target_rpm; - state->integral = 0.0f; - state->previous_error = target_rpm - motor_encoder_get_speed_rpm(motor); - state->last_output = 0.0f; - state->last_update_us = 0U; -} - -static inline void motor_speed_controller_update(uint32_t now_us) { - for (uint8_t motor = BODY_MOTOR_LEFT; motor <= BODY_MOTOR_RIGHT; motor++) { - motor_speed_state_t *state = motor_speed_state_get(motor); - if (!state->active) { - continue; - } - - bool first_update = (state->last_update_us == 0U); - uint32_t dt_us = first_update ? UPDATE_PERIOD_US : (now_us - state->last_update_us); - if (!first_update && (dt_us < UPDATE_PERIOD_US)) { - continue; - } - - float measured_rpm = motor_encoder_get_speed_rpm(motor); - float error = state->target_rpm - measured_rpm; - - if ((motor_absf(state->target_rpm) <= DEADBAND_RPM) && (motor_absf(error) <= DEADBAND_RPM) && (motor_absf(measured_rpm) <= DEADBAND_RPM)) { - motor_speed_controller_disable(motor); - motor_apply_pwm(motor, 0); - continue; - } - - float dt_s = (float)dt_us * 1.0e-6f; - float control = KFF * state->target_rpm; - - if (dt_s > 0.0f) { - state->integral += error * dt_s; - float derivative = first_update ? 0.0f : (error - state->previous_error) / dt_s; - - control += (KP * error) + (KI * state->integral) + (KD * derivative); - } else { - state->integral = 0.0f; - control += KP * error; - } - - if ((state->target_rpm > 0.0f) && (control < 0.0f)) { - control = 0.0f; - state->integral = 0.0f; - } else if ((state->target_rpm < 0.0f) && (control > 0.0f)) { - control = 0.0f; - state->integral = 0.0f; - } - - control = motor_clampf(control, -OUTPUT_MAX, OUTPUT_MAX); - - int32_t command = (control >= 0.0f) ? (int32_t)(control + 0.5f) : (int32_t)(control - 0.5f); - motor_apply_pwm(motor, command); - - state->previous_error = error; - state->last_output = control; - state->last_update_us = now_us; - } -} +void motor_speed_controller_init(void); +void motor_init(void); +void motor_set_speed(uint8_t motor, int8_t speed); +void motor_speed_controller_set_target_rpm(uint8_t motor, float target_rpm); +void motor_speed_controller_update(uint32_t now_us); diff --git a/board/body/motor_encoder.c b/board/body/motor_encoder.c new file mode 100644 index 00000000000..fe408ddbca5 --- /dev/null +++ b/board/body/motor_encoder.c @@ -0,0 +1,140 @@ +#include + +#include "motor_encoder.h" + +static const motor_encoder_config_t motor_encoder_config[BODY_MOTOR_COUNT] = { + [BODY_MOTOR_LEFT - 1U] = { + .timer = TIM4, + .pin_a_port = GPIOB, .pin_a = 6U, .pin_a_af = GPIO_AF2_TIM4, + .pin_b_port = GPIOB, .pin_b = 7U, .pin_b_af = GPIO_AF2_TIM4, + .direction = -1, + .counts_per_output_rev = 44U * 90U, + .min_dt_us = 250U, + .speed_alpha = 0.2f, + .filter = 3U, + }, + [BODY_MOTOR_RIGHT - 1U] = { + .timer = TIM3, + .pin_a_port = GPIOA, .pin_a = 6U, .pin_a_af = GPIO_AF2_TIM3, + .pin_b_port = GPIOA, .pin_b = 7U, .pin_b_af = GPIO_AF2_TIM3, + .direction = 1, + .counts_per_output_rev = 44U * 90U, + .min_dt_us = 250U, + .speed_alpha = 0.2f, + .filter = 3U, + }, +}; + +static motor_encoder_state_t motor_encoders[BODY_MOTOR_COUNT] = { + { .config = &motor_encoder_config[0] }, + { .config = &motor_encoder_config[1] }, +}; + +static void motor_encoder_configure_gpio(const motor_encoder_config_t *cfg) { + set_gpio_pullup(cfg->pin_a_port, cfg->pin_a, PULL_UP); + set_gpio_output_type(cfg->pin_a_port, cfg->pin_a, OUTPUT_TYPE_PUSH_PULL); + set_gpio_alternate(cfg->pin_a_port, cfg->pin_a, cfg->pin_a_af); + + set_gpio_pullup(cfg->pin_b_port, cfg->pin_b, PULL_UP); + set_gpio_output_type(cfg->pin_b_port, cfg->pin_b, OUTPUT_TYPE_PUSH_PULL); + set_gpio_alternate(cfg->pin_b_port, cfg->pin_b, cfg->pin_b_af); +} + +static void motor_encoder_configure_timer(motor_encoder_state_t *state) { + const motor_encoder_config_t *cfg = state->config; + TIM_TypeDef *timer = cfg->timer; + timer->CR1 = 0U; + timer->CR2 = 0U; + timer->SMCR = 0U; + timer->DIER = 0U; + timer->SR = 0U; + timer->CCMR1 = (TIM_CCMR1_CC1S_0) | (TIM_CCMR1_CC2S_0) | (cfg->filter << TIM_CCMR1_IC1F_Pos) | (cfg->filter << TIM_CCMR1_IC2F_Pos); + timer->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E; + timer->PSC = 0U; + timer->ARR = 0xFFFFU; + timer->CNT = 0U; + state->last_timer_count = 0U; + state->accumulated_count = 0; + state->last_speed_count = 0; + state->cached_speed_rps = 0.0f; + timer->SMCR = (TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1); + timer->CR1 = TIM_CR1_CEN; +} + +void motor_encoder_init(void) { + register_set_bits(&(RCC->APB1LENR), RCC_APB1LENR_TIM4EN | RCC_APB1LENR_TIM3EN); + register_set_bits(&(RCC->APB1LRSTR), RCC_APB1LRSTR_TIM4RST | RCC_APB1LRSTR_TIM3RST); + register_clear_bits(&(RCC->APB1LRSTR), RCC_APB1LRSTR_TIM4RST | RCC_APB1LRSTR_TIM3RST); + + for (uint8_t i = 0U; i < BODY_MOTOR_COUNT; i++) { + motor_encoder_state_t *state = &motor_encoders[i]; + const motor_encoder_config_t *cfg = state->config; + motor_encoder_configure_gpio(cfg); + motor_encoder_configure_timer(state); + state->last_speed_timestamp_us = 0U; + } +} + +static inline int32_t motor_encoder_refresh(motor_encoder_state_t *state) { + const motor_encoder_config_t *cfg = state->config; + TIM_TypeDef *timer = cfg->timer; + uint16_t raw = (uint16_t)timer->CNT; + int32_t delta = (int16_t)(raw - state->last_timer_count); + delta *= cfg->direction; + state->last_timer_count = raw; + state->accumulated_count += delta; + return state->accumulated_count; +} + +int32_t motor_encoder_get_position(uint8_t motor) { + if (!body_motor_is_valid(motor)) { + return 0; + } + motor_encoder_state_t *state = &motor_encoders[motor - 1U]; + return motor_encoder_refresh(state); +} + +void motor_encoder_reset(uint8_t motor) { + if (!body_motor_is_valid(motor)) { + return; + } + motor_encoder_state_t *state = &motor_encoders[motor - 1U]; + state->config->timer->CNT = 0U; + state->last_timer_count = 0U; + state->accumulated_count = 0; + state->last_speed_count = 0; + state->last_speed_timestamp_us = 0U; + state->cached_speed_rps = 0.0f; +} + +float motor_encoder_get_speed_rpm(uint8_t motor) { + if (!body_motor_is_valid(motor)) { + return 0.0f; + } + motor_encoder_state_t *state = &motor_encoders[motor - 1U]; + + const motor_encoder_config_t *cfg = state->config; + motor_encoder_refresh(state); + + uint32_t now = microsecond_timer_get(); + if (state->last_speed_timestamp_us == 0U) { + state->last_speed_timestamp_us = now; + state->last_speed_count = state->accumulated_count; + state->cached_speed_rps = 0.0f; + return 0.0f; + } + + uint32_t dt = now - state->last_speed_timestamp_us; + int32_t delta = state->accumulated_count - state->last_speed_count; + if ((dt < cfg->min_dt_us) || (delta == 0)) { + return state->cached_speed_rps * 60.0f; + } + + state->last_speed_count = state->accumulated_count; + state->last_speed_timestamp_us = now; + + float counts_per_second = ((float)delta * 1000000.0f) / (float)dt; + float new_speed_rps = (cfg->counts_per_output_rev != 0U) ? (counts_per_second / (float)cfg->counts_per_output_rev) : 0.0f; + state->cached_speed_rps += cfg->speed_alpha * (new_speed_rps - state->cached_speed_rps); + return state->cached_speed_rps * 60.0f; +} diff --git a/board/body/motor_encoder.h b/board/body/motor_encoder.h index 383e23ef592..f29a33f66dd 100644 --- a/board/body/motor_encoder.h +++ b/board/body/motor_encoder.h @@ -3,6 +3,7 @@ #include #include "board/body/motor_common.h" +#include "board/config.h" // Encoder pin map: // Left motor: PB6 -> TIM4_CH1, PB7 -> TIM4_CH2 @@ -32,139 +33,7 @@ typedef struct { float cached_speed_rps; } motor_encoder_state_t; -static const motor_encoder_config_t motor_encoder_config[BODY_MOTOR_COUNT] = { - [BODY_MOTOR_LEFT - 1U] = { - .timer = TIM4, - .pin_a_port = GPIOB, .pin_a = 6U, .pin_a_af = GPIO_AF2_TIM4, - .pin_b_port = GPIOB, .pin_b = 7U, .pin_b_af = GPIO_AF2_TIM4, - .direction = -1, - .counts_per_output_rev = 44U * 90U, - .min_dt_us = 250U, - .speed_alpha = 0.2f, - .filter = 3U, - }, - [BODY_MOTOR_RIGHT - 1U] = { - .timer = TIM3, - .pin_a_port = GPIOA, .pin_a = 6U, .pin_a_af = GPIO_AF2_TIM3, - .pin_b_port = GPIOA, .pin_b = 7U, .pin_b_af = GPIO_AF2_TIM3, - .direction = 1, - .counts_per_output_rev = 44U * 90U, - .min_dt_us = 250U, - .speed_alpha = 0.2f, - .filter = 3U, - }, -}; - -static motor_encoder_state_t motor_encoders[BODY_MOTOR_COUNT] = { - { .config = &motor_encoder_config[0] }, - { .config = &motor_encoder_config[1] }, -}; - -static void motor_encoder_configure_gpio(const motor_encoder_config_t *cfg) { - set_gpio_pullup(cfg->pin_a_port, cfg->pin_a, PULL_UP); - set_gpio_output_type(cfg->pin_a_port, cfg->pin_a, OUTPUT_TYPE_PUSH_PULL); - set_gpio_alternate(cfg->pin_a_port, cfg->pin_a, cfg->pin_a_af); - - set_gpio_pullup(cfg->pin_b_port, cfg->pin_b, PULL_UP); - set_gpio_output_type(cfg->pin_b_port, cfg->pin_b, OUTPUT_TYPE_PUSH_PULL); - set_gpio_alternate(cfg->pin_b_port, cfg->pin_b, cfg->pin_b_af); -} - -static void motor_encoder_configure_timer(motor_encoder_state_t *state) { - const motor_encoder_config_t *cfg = state->config; - TIM_TypeDef *timer = cfg->timer; - timer->CR1 = 0U; - timer->CR2 = 0U; - timer->SMCR = 0U; - timer->DIER = 0U; - timer->SR = 0U; - timer->CCMR1 = (TIM_CCMR1_CC1S_0) | (TIM_CCMR1_CC2S_0) | (cfg->filter << TIM_CCMR1_IC1F_Pos) | (cfg->filter << TIM_CCMR1_IC2F_Pos); - timer->CCER = TIM_CCER_CC1E | TIM_CCER_CC2E; - timer->PSC = 0U; - timer->ARR = 0xFFFFU; - timer->CNT = 0U; - state->last_timer_count = 0U; - state->accumulated_count = 0; - state->last_speed_count = 0; - state->cached_speed_rps = 0.0f; - timer->SMCR = (TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1); - timer->CR1 = TIM_CR1_CEN; -} - -static void motor_encoder_init(void) { - register_set_bits(&(RCC->APB1LENR), RCC_APB1LENR_TIM4EN | RCC_APB1LENR_TIM3EN); - register_set_bits(&(RCC->APB1LRSTR), RCC_APB1LRSTR_TIM4RST | RCC_APB1LRSTR_TIM3RST); - register_clear_bits(&(RCC->APB1LRSTR), RCC_APB1LRSTR_TIM4RST | RCC_APB1LRSTR_TIM3RST); - - for (uint8_t i = 0U; i < BODY_MOTOR_COUNT; i++) { - motor_encoder_state_t *state = &motor_encoders[i]; - const motor_encoder_config_t *cfg = state->config; - motor_encoder_configure_gpio(cfg); - motor_encoder_configure_timer(state); - state->last_speed_timestamp_us = 0U; - } -} - -static inline int32_t motor_encoder_refresh(motor_encoder_state_t *state) { - const motor_encoder_config_t *cfg = state->config; - TIM_TypeDef *timer = cfg->timer; - uint16_t raw = (uint16_t)timer->CNT; - int32_t delta = (int16_t)(raw - state->last_timer_count); - delta *= cfg->direction; - state->last_timer_count = raw; - state->accumulated_count += delta; - return state->accumulated_count; -} - -static inline int32_t motor_encoder_get_position(uint8_t motor) { - if (!body_motor_is_valid(motor)) { - return 0; - } - motor_encoder_state_t *state = &motor_encoders[motor - 1U]; - return motor_encoder_refresh(state); -} - -static void motor_encoder_reset(uint8_t motor) { - if (!body_motor_is_valid(motor)) { - return; - } - motor_encoder_state_t *state = &motor_encoders[motor - 1U]; - state->config->timer->CNT = 0U; - state->last_timer_count = 0U; - state->accumulated_count = 0; - state->last_speed_count = 0; - state->last_speed_timestamp_us = 0U; - state->cached_speed_rps = 0.0f; -} - -static float motor_encoder_get_speed_rpm(uint8_t motor) { - if (!body_motor_is_valid(motor)) { - return 0.0f; - } - motor_encoder_state_t *state = &motor_encoders[motor - 1U]; - - const motor_encoder_config_t *cfg = state->config; - motor_encoder_refresh(state); - - uint32_t now = microsecond_timer_get(); - if (state->last_speed_timestamp_us == 0U) { - state->last_speed_timestamp_us = now; - state->last_speed_count = state->accumulated_count; - state->cached_speed_rps = 0.0f; - return 0.0f; - } - - uint32_t dt = now - state->last_speed_timestamp_us; - int32_t delta = state->accumulated_count - state->last_speed_count; - if ((dt < cfg->min_dt_us) || (delta == 0)) { - return state->cached_speed_rps * 60.0f; - } - - state->last_speed_count = state->accumulated_count; - state->last_speed_timestamp_us = now; - - float counts_per_second = ((float)delta * 1000000.0f) / (float)dt; - float new_speed_rps = (cfg->counts_per_output_rev != 0U) ? (counts_per_second / (float)cfg->counts_per_output_rev) : 0.0f; - state->cached_speed_rps += cfg->speed_alpha * (new_speed_rps - state->cached_speed_rps); - return state->cached_speed_rps * 60.0f; -} +void motor_encoder_init(void); +int32_t motor_encoder_get_position(uint8_t motor); +void motor_encoder_reset(uint8_t motor); +float motor_encoder_get_speed_rpm(uint8_t motor); \ No newline at end of file diff --git a/board/body/stm32h7/board.c b/board/body/stm32h7/board.c new file mode 100644 index 00000000000..55026ddc3b6 --- /dev/null +++ b/board/body/stm32h7/board.c @@ -0,0 +1,10 @@ +#include "board.h" +#include "board/config.h" + +#ifndef PANDA_BODY +#error This should only be used on Panda Body! +#endif + +void detect_board_type(void) { + // Board type set explicitly in main() +} \ No newline at end of file diff --git a/board/body/stm32h7/board.h b/board/body/stm32h7/board.h index c063e4ddbb5..b9f9c9ef140 100644 --- a/board/body/stm32h7/board.h +++ b/board/body/stm32h7/board.h @@ -1,9 +1,3 @@ -#include "board/body/boards/board_declarations.h" -#include "board/body/boards/board_body.h" +#pragma once -extern board *current_board; -extern uint8_t hw_type; - -void detect_board_type(void) { - // Board type set explicitly in main() -} +#define HW_TYPE_BODY 0xB1U diff --git a/board/bootstub.c b/board/bootstub.c index a48f308ac7d..c62d2ed061b 100644 --- a/board/bootstub.c +++ b/board/bootstub.c @@ -2,33 +2,34 @@ #define MIN_VERSION 2 // ********************* Includes ********************* -#include "board/config.h" - -#include "board/drivers/led.h" -#include "board/drivers/pwm.h" -#include "board/drivers/usb.h" +#include +#include "board/config.h" #include "board/early_init.h" -#include "board/provision.h" +#include "board/drivers/drivers.h" #include "crypto/rsa.h" #include "crypto/sha.h" #include "board/obj/cert.h" -#include "board/obj/gitversion.h" -#include "board/flasher.h" +#include "board/print.h" +#include "board/drivers/drivers.h" + +#include "globals.h" // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck void __initialize_hardware_early(void) { early_initialization(); } -void fail(void) { - soft_flasher_start(); +void debug_ring_callback(uart_ring *ring) { + char rcv; + while (get_char(ring, &rcv)) { } // Intentionally disabled, no uart in bootstub } -// know where to sig check -extern void *_app_start[]; +static void fail(void) { + soft_flasher_start(); +} int main(void) { // Init interrupt table @@ -57,7 +58,7 @@ int main(void) { // verify version, last bytes in the signed area uint32_t vers[2] = {0}; - memcpy(&vers, ((void*)&_app_start[0]) + len - sizeof(vers), sizeof(vers)); + (void)memcpy(&vers, ((void*)&_app_start[0]) + len - sizeof(vers), sizeof(vers)); if (vers[0] != VERS_TAG || vers[1] < MIN_VERSION) { goto fail; } diff --git a/board/bootstub_declarations.h b/board/bootstub_declarations.h deleted file mode 100644 index 5cdec508e70..00000000000 --- a/board/bootstub_declarations.h +++ /dev/null @@ -1,18 +0,0 @@ -// ******************** Prototypes ******************** -void print(const char *a){ UNUSED(a); } -void puth(uint8_t i){ UNUSED(i); } -void puth2(uint8_t i){ UNUSED(i); } -void puth4(uint8_t i){ UNUSED(i); } -void hexdump(const void *a, int l){ UNUSED(a); UNUSED(l); } -typedef struct board board; -typedef struct harness_configuration harness_configuration; -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; -board *current_board; diff --git a/board/can_comms.h b/board/can_comms.c similarity index 83% rename from board/can_comms.h rename to board/can_comms.c index 99ee968b0a0..8890534bde0 100644 --- a/board/can_comms.h +++ b/board/can_comms.c @@ -1,22 +1,10 @@ -/* - CAN transactions to and from the host come in the form of - a certain number of CANPacket_t. The transaction is split - into multiple transfers or chunks. +#include "comms.h" +#include "drivers/drivers.h" +#include "utils.h" +#include "libc.h" +#include "can.h" - * comms_can_read outputs this buffer in chunks of a specified length. - chunks are always the given length, except the last one. - * comms_can_write reads in this buffer in chunks. - * both functions maintain an overflow buffer for a partial CANPacket_t that - spans multiple transfers/chunks. - * the overflow buffers are reset by a dedicated control transfer handler, - which is sent by the host on each start of a connection. -*/ - -typedef struct { - uint32_t ptr; - uint32_t tail_size; - uint8_t data[72]; -} asm_buffer; +#include "config.h" static asm_buffer can_read_buffer = {.ptr = 0U, .tail_size = 0U}; diff --git a/board/comms.h b/board/comms.h new file mode 100644 index 00000000000..7728ba5e791 --- /dev/null +++ b/board/comms.h @@ -0,0 +1,51 @@ +#pragma once + +#include +#include + +// ======================= CONTROL PACKET ======================= + +typedef struct { + uint8_t request; + uint16_t param1; + uint16_t param2; + uint16_t length; +} __attribute__((packed)) ControlPacket_t; + +int comms_control_handler(ControlPacket_t *req, uint8_t *resp); +void comms_endpoint2_write(const uint8_t *data, uint32_t len); + +// ======================= CAN COMMS ======================= + +/* + CAN transactions to and from the host come in the form of + a certain number of CANPacket_t. The transaction is split + into multiple transfers or chunks. + + * comms_can_read outputs this buffer in chunks of a specified length. + chunks are always the given length, except the last one. + * comms_can_write reads in this buffer in chunks. + * both functions maintain an overflow buffer for a partial CANPacket_t that + spans multiple transfers/chunks. + * the overflow buffers are reset by a dedicated control transfer handler, + which is sent by the host on each start of a connection. +*/ + +typedef struct { + uint32_t ptr; + uint32_t tail_size; + uint8_t data[72]; +} asm_buffer; + +int comms_can_read(uint8_t *data, uint32_t max_len); + +// send on CAN +void comms_can_write(const uint8_t *data, uint32_t len); +void comms_can_reset(void); + +void refresh_can_tx_slots_available(void); + +// ======================= MAIN COMMS ======================= + +void set_safety_mode(uint16_t mode, uint16_t param); +bool is_car_safety_mode(uint16_t mode); diff --git a/board/comms_definitions.h b/board/comms_definitions.h deleted file mode 100644 index 18a6d2f8134..00000000000 --- a/board/comms_definitions.h +++ /dev/null @@ -1,12 +0,0 @@ -typedef struct { - uint8_t request; - uint16_t param1; - uint16_t param2; - uint16_t length; -} __attribute__((packed)) ControlPacket_t; - -int comms_control_handler(ControlPacket_t *req, uint8_t *resp); -void comms_endpoint2_write(const uint8_t *data, uint32_t len); -void comms_can_write(const uint8_t *data, uint32_t len); -int comms_can_read(uint8_t *data, uint32_t max_len); -void comms_can_reset(void); diff --git a/board/config.h b/board/config.h index 1b7d938cc81..90a03529583 100644 --- a/board/config.h +++ b/board/config.h @@ -32,11 +32,44 @@ #endif #endif +#define HW_TYPE_UNKNOWN 0U +#define HW_TYPE_V2 2U +#define HW_TYPE_RED_PANDA 7U +#define HW_TYPE_TRES 9U +#define HW_TYPE_CUATRO 10U + +#ifdef PANDA + +// CAN modes +#define CAN_MODE_NORMAL 0U +#define CAN_MODE_OBD_CAN2 1U + +#elif defined(PANDA_JUNGLE) + +// CAN modes +#define CAN_MODE_NORMAL 0U +#define CAN_MODE_OBD_CAN2 3U + +// Harness states +#define HARNESS_ORIENTATION_NONE 0U +#define HARNESS_ORIENTATION_1 1U +#define HARNESS_ORIENTATION_2 2U + +#define SBU1 0U +#define SBU2 1U + +#elif defined(PANDA_BODY) +#elif defined(LIB_PANDA) +#else +#error Unknown board type +#endif + // platform includes #ifdef STM32H7 #include "board/stm32h7/stm32h7_config.h" #else - // TODO: uncomment this, cppcheck complains // building for tests - //#include "fake_stm.h" + #include "fake_stm.h" #endif + +void detect_board_type(void); \ No newline at end of file diff --git a/board/crc.h b/board/crc.h deleted file mode 100644 index 3e20fb09817..00000000000 --- a/board/crc.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -uint8_t crc_checksum(const uint8_t *dat, int len, const uint8_t poly) { - uint8_t crc = 0xFFU; - int i; - int j; - for (i = len - 1; i >= 0; i--) { - crc ^= dat[i]; - for (j = 0; j < 8; j++) { - if ((crc & 0x80U) != 0U) { - crc = (uint8_t)((crc << 1) ^ poly); - } - else { - crc <<= 1; - } - } - } - return crc; -} diff --git a/board/critical_declarations.h b/board/critical_declarations.h deleted file mode 100644 index 42211d46c38..00000000000 --- a/board/critical_declarations.h +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -// ********************* Critical section helpers ********************* -void enable_interrupts(void); -void disable_interrupts(void); - -extern uint8_t global_critical_depth; - -#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(); \ - } diff --git a/board/drivers/bootkick.h b/board/drivers/bootkick.c similarity index 97% rename from board/drivers/bootkick.h rename to board/drivers/bootkick.c index eab7da3ebc4..453cf56a8af 100644 --- a/board/drivers/bootkick.h +++ b/board/drivers/bootkick.c @@ -1,4 +1,7 @@ -#include "bootkick_declarations.h" +#include + +#include "drivers.h" +#include "board/globals.h" bool bootkick_reset_triggered = false; diff --git a/board/drivers/bootkick_declarations.h b/board/drivers/bootkick_declarations.h deleted file mode 100644 index 3b55b72ac66..00000000000 --- a/board/drivers/bootkick_declarations.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -extern bool bootkick_reset_triggered; - -void bootkick_tick(bool ignition, bool recent_heartbeat); diff --git a/board/drivers/can_common.h b/board/drivers/can_common.c similarity index 88% rename from board/drivers/can_common.h rename to board/drivers/can_common.c index 35c6702e807..5aceea539d2 100644 --- a/board/drivers/can_common.h +++ b/board/drivers/can_common.c @@ -1,4 +1,7 @@ -#include "can_common_declarations.h" +#include "board/config.h" +#include "drivers.h" + +#include "board/utils.h" uint32_t safety_tx_blocked = 0; uint32_t safety_rx_invalid = 0; @@ -15,25 +18,22 @@ bool can_silent = true; bool can_loopback = false; // ********************* instantiate queues ********************* -#define can_buffer(x, size) \ - static CANPacket_t elems_##x[size]; \ - extern can_ring can_##x; \ - can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = (size), .elems = (CANPacket_t *)&(elems_##x) }; - -#define CAN_RX_BUFFER_SIZE 4096U -#define CAN_TX_BUFFER_SIZE 416U - #ifdef STM32H7 // ITCM RAM and DTCM RAM are the fastest for Cortex-M7 core access -__attribute__((section(".axisram"))) can_buffer(rx_q, CAN_RX_BUFFER_SIZE) -__attribute__((section(".itcmram"))) can_buffer(tx1_q, CAN_TX_BUFFER_SIZE) -__attribute__((section(".itcmram"))) can_buffer(tx2_q, CAN_TX_BUFFER_SIZE) -#else // kept for PC -can_buffer(rx_q, CAN_RX_BUFFER_SIZE) -can_buffer(tx1_q, CAN_TX_BUFFER_SIZE) -can_buffer(tx2_q, CAN_TX_BUFFER_SIZE) +__attribute__((section(".axisram"))) static CANPacket_t elems_rx_q[CAN_RX_BUFFER_SIZE]; +__attribute__((section(".itcmram"))) static CANPacket_t elems_tx1_q[CAN_TX_BUFFER_SIZE]; +__attribute__((section(".itcmram"))) static CANPacket_t elems_tx2_q[CAN_TX_BUFFER_SIZE]; +#else +static CANPacket_t elems_rx_q[CAN_RX_BUFFER_SIZE]; +static CANPacket_t elems_tx1_q[CAN_TX_BUFFER_SIZE]; +static CANPacket_t elems_tx2_q[CAN_TX_BUFFER_SIZE]; #endif -can_buffer(tx3_q, CAN_TX_BUFFER_SIZE) +static CANPacket_t elems_tx3_q[CAN_TX_BUFFER_SIZE]; + +can_ring can_rx_q = { .w_ptr = 0, .r_ptr = 0, .fifo_size = CAN_RX_BUFFER_SIZE, .elems = elems_rx_q }; +can_ring can_tx1_q = { .w_ptr = 0, .r_ptr = 0, .fifo_size = CAN_TX_BUFFER_SIZE, .elems = elems_tx1_q }; +can_ring can_tx2_q = { .w_ptr = 0, .r_ptr = 0, .fifo_size = CAN_TX_BUFFER_SIZE, .elems = elems_tx2_q }; +can_ring can_tx3_q = { .w_ptr = 0, .r_ptr = 0, .fifo_size = CAN_TX_BUFFER_SIZE, .elems = elems_tx3_q }; // FIXME: // cppcheck-suppress misra-c2012-9.3 diff --git a/board/drivers/can_common_declarations.h b/board/drivers/can_common_declarations.h deleted file mode 100644 index 75580b7b640..00000000000 --- a/board/drivers/can_common_declarations.h +++ /dev/null @@ -1,70 +0,0 @@ -#pragma once - -#include "board/can.h" - -typedef struct { - volatile uint32_t w_ptr; - volatile uint32_t r_ptr; - uint32_t fifo_size; - CANPacket_t *elems; -} can_ring; - -typedef struct { - uint8_t bus_lookup; - uint8_t can_num_lookup; - int8_t forwarding_bus; - uint32_t can_speed; - uint32_t can_data_speed; - bool canfd_auto; - bool canfd_enabled; - bool brs_enabled; - bool canfd_non_iso; -} bus_config_t; - -extern uint32_t safety_tx_blocked; -extern uint32_t safety_rx_invalid; -extern uint32_t tx_buffer_overflow; -extern uint32_t rx_buffer_overflow; - -extern can_health_t can_health[PANDA_CAN_CNT]; - -// Ignition detected from CAN meessages -extern bool ignition_can; -extern uint32_t ignition_can_cnt; - -extern bool can_silent; -extern bool can_loopback; - -// ******************* functions prototypes ********************* -bool can_init(uint8_t can_number); -void process_can(uint8_t can_number); - -// ********************* instantiate queues ********************* -extern can_ring *can_queues[PANDA_CAN_CNT]; - -// helpers -#define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU) -#define BYTE_ARRAY_TO_WORD(dst32, src8) ((dst32) = 0[src8] | (1[src8] << 8U) | (2[src8] << 16U) | (3[src8] << 24U)) - -// ********************* interrupt safe queue ********************* -bool can_pop(can_ring *q, CANPacket_t *elem); -bool can_push(can_ring *q, const CANPacket_t *elem); -uint32_t can_slots_empty(const can_ring *q); -extern bus_config_t bus_config[PANDA_CAN_CNT]; - -#define CANIF_FROM_CAN_NUM(num) (cans[num]) -#define BUS_NUM_FROM_CAN_NUM(num) (bus_config[num].bus_lookup) -#define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup) - -void can_init_all(void); -void can_set_orientation(bool flipped); -#ifdef PANDA_JUNGLE -void can_set_forwarding(uint8_t from, uint8_t to); -#endif -void ignition_can_hook(CANPacket_t *to_push); -bool can_tx_check_min_slots_free(uint32_t min); -uint8_t calculate_checksum(const uint8_t *dat, uint32_t len); -void can_set_checksum(CANPacket_t *packet); -bool can_check_checksum(CANPacket_t *packet); -void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook); -bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len); diff --git a/board/drivers/clock_source.h b/board/drivers/clock_source.c similarity index 97% rename from board/drivers/clock_source.h rename to board/drivers/clock_source.c index 87d89ad063e..1b5e5efe456 100644 --- a/board/drivers/clock_source.h +++ b/board/drivers/clock_source.c @@ -1,4 +1,5 @@ -#include "clock_source_declarations.h" +#include "drivers.h" +#include "board/config.h" void clock_source_set_timer_params(uint16_t param1, uint16_t param2) { // Pulse length of each channel diff --git a/board/drivers/clock_source_declarations.h b/board/drivers/clock_source_declarations.h deleted file mode 100644 index d95eb961a0b..00000000000 --- a/board/drivers/clock_source_declarations.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#define CLOCK_SOURCE_PERIOD_MS 50U -#define CLOCK_SOURCE_PULSE_LEN_MS 2U - -void clock_source_set_timer_params(uint16_t param1, uint16_t param2); -void clock_source_init(bool enable_channel1); diff --git a/board/critical.h b/board/drivers/critical.c similarity index 56% rename from board/critical.h rename to board/drivers/critical.c index ae2d5c0a699..86cd78577d6 100644 --- a/board/critical.h +++ b/board/drivers/critical.c @@ -1,9 +1,8 @@ -#include "critical_declarations.h" - -// ********************* Critical section helpers ********************* +#include "board/config.h" +#include "board/drivers/drivers.h" uint8_t global_critical_depth = 0U; -static volatile bool interrupts_enabled = false; +volatile bool interrupts_enabled = false; void enable_interrupts(void) { interrupts_enabled = true; diff --git a/board/drivers/drivers.h b/board/drivers/drivers.h new file mode 100644 index 00000000000..82a3f97489f --- /dev/null +++ b/board/drivers/drivers.h @@ -0,0 +1,604 @@ +#pragma once + +#include +#include + +#include "board/config.h" +// ======================= CRITICAL SECTION ======================= + +extern uint8_t global_critical_depth; + +#ifndef ENTER_CRITICAL +#define ENTER_CRITICAL() \ + __disable_irq(); \ + global_critical_depth += 1U; +#endif + +#ifndef EXIT_CRITICAL +#define EXIT_CRITICAL() \ + global_critical_depth -= 1U; \ + if ((global_critical_depth == 0U) && interrupts_enabled) { \ + __enable_irq(); \ + } +#endif + +extern volatile bool interrupts_enabled; + +void enable_interrupts(void); +void disable_interrupts(void); + +// ======================= FAULTS ======================= + +#define FAULT_STATUS_NONE 0U +#define FAULT_STATUS_TEMPORARY 1U +#define FAULT_STATUS_PERMANENT 2U + +// Fault types, matches cereal.log.PandaState.FaultType +#define FAULT_RELAY_MALFUNCTION (1UL << 0) +#define FAULT_UNUSED_INTERRUPT_HANDLED (1UL << 1) +#define FAULT_INTERRUPT_RATE_CAN_1 (1UL << 2) +#define FAULT_INTERRUPT_RATE_CAN_2 (1UL << 3) +#define FAULT_INTERRUPT_RATE_CAN_3 (1UL << 4) +#define FAULT_INTERRUPT_RATE_TACH (1UL << 5) +#define FAULT_INTERRUPT_RATE_INTERRUPTS (1UL << 7) +#define FAULT_INTERRUPT_RATE_SPI_DMA (1UL << 8) +#define FAULT_INTERRUPT_RATE_USB (1UL << 15) +#define FAULT_REGISTER_DIVERGENT (1UL << 18) +#define FAULT_INTERRUPT_RATE_CLOCK_SOURCE (1UL << 20) +#define FAULT_INTERRUPT_RATE_TICK (1UL << 21) +#define FAULT_INTERRUPT_RATE_EXTI (1UL << 22) +#define FAULT_INTERRUPT_RATE_SPI (1UL << 23) +#define FAULT_INTERRUPT_RATE_UART_7 (1UL << 24) +#define FAULT_SIREN_MALFUNCTION (1UL << 25) +#define FAULT_HEARTBEAT_LOOP_WATCHDOG (1UL << 26) +#define FAULT_INTERRUPT_RATE_SOUND_DMA (1UL << 27) + +// Permanent faults +#define PERMANENT_FAULTS 0U + +extern uint8_t fault_status; +extern uint32_t faults; + +void fault_occurred(uint32_t fault); +void fault_recovered(uint32_t fault); + +#include "board/can.h" +#include "board/health.h" +#include "board/utils.h" +#include "opendbc/safety/declarations.h" + +// ======================= GPIO ======================= + +#define MODE_INPUT 0 +#define MODE_OUTPUT 1 +#define MODE_ALTERNATE 2 +#define MODE_ANALOG 3 + +#define PULL_NONE 0 +#define PULL_UP 1 +#define PULL_DOWN 2 + +#define OUTPUT_TYPE_PUSH_PULL 0U +#define OUTPUT_TYPE_OPEN_DRAIN 1U + +void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode); +void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled); +void set_gpio_output_type(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int output_type); +void set_gpio_alternate(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode); +void set_gpio_pullup(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode); +int get_gpio_input(const GPIO_TypeDef *GPIO, unsigned int pin); + +#ifdef PANDA_JUNGLE +typedef struct { + GPIO_TypeDef * const bank; + uint8_t pin; +} gpio_t; + +void gpio_set_all_output(gpio_t *pins, uint8_t num_pins, bool enabled); +void gpio_set_bitmask(gpio_t *pins, uint8_t num_pins, uint32_t bitmask); +#endif + +// Detection with internal pullup +bool detect_with_pull(GPIO_TypeDef *GPIO, int pin, int mode); + +// ======================= TIMERS ======================= + +void microsecond_timer_init(void); +uint32_t microsecond_timer_get(void); +void interrupt_timer_init(void); +void tick_timer_init(void); + +// ======================= PWM ======================= + +#define PWM_COUNTER_OVERFLOW 4800U // To get ~25kHz + +// TODO: Implement for 32-bit timers + +void pwm_init(TIM_TypeDef *TIM, uint8_t channel); +void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage); + +// ======================= REGISTERS ======================= + +// 10 bit hash with 23 as a prime +#define REGISTER_MAP_SIZE 0x3FFU +#define HASHING_PRIME 23U +#define CHECK_COLLISION(hash, addr) (((uint32_t) register_map[hash].address != 0U) && (register_map[hash].address != (addr))) + +typedef struct reg { + volatile uint32_t *address; + uint32_t value; + uint32_t check_mask; + bool logged_fault; +} reg; + +// Do not put bits in the check mask that get changed by the hardware +void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask); +// Set individual bits. Also add them to the check_mask. +// Do not use this to change bits that get reset by the hardware +void register_set_bits(volatile uint32_t *addr, uint32_t val); +// Clear individual bits. Also add them to the check_mask. +// Do not use this to clear bits that get set by the hardware +void register_clear_bits(volatile uint32_t *addr, uint32_t val); +// To be called periodically +void check_registers(void); +void init_registers(void); + +// ======================= INTERRUPTS ======================= + +typedef struct interrupt { + IRQn_Type irq_type; + void (*handler)(void); + uint32_t call_counter; + uint32_t call_rate; + 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); + +extern interrupt interrupts[NUM_INTERRUPTS]; + +#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate_max, rate_fault) \ + interrupts[irq_num].irq_type = (irq_num); \ + interrupts[irq_num].handler = (func_ptr); \ + interrupts[irq_num].call_counter = 0U; \ + interrupts[irq_num].call_rate = 0U; \ + interrupts[irq_num].max_call_rate = (call_rate_max); \ + interrupts[irq_num].call_rate_fault = (rate_fault); + +extern float interrupt_load; + +void handle_interrupt(IRQn_Type irq_type); +// Every second +void interrupt_timer_handler(void); +void init_interrupts(bool check_rate_limit); + +// ======================= UART ======================= + +// ***************************** Definitions ***************************** +#define FIFO_SIZE_INT 0x400U + +typedef struct uart_ring { + volatile uint16_t w_ptr_tx; + volatile uint16_t r_ptr_tx; + uint8_t *elems_tx; + uint32_t tx_fifo_size; + volatile uint16_t w_ptr_rx; + volatile uint16_t r_ptr_rx; + uint8_t *elems_rx; + uint32_t rx_fifo_size; + USART_TypeDef *uart; + void (*callback)(struct uart_ring*); + bool overwrite; +} uart_ring; + +// ***************************** Function prototypes ***************************** +void debug_ring_callback(uart_ring *ring); +void uart_tx_ring(uart_ring *q); +uart_ring *get_ring_by_number(int a); +// ************************* Low-level buffer functions ************************* +bool get_char(uart_ring *q, char *elem); +bool injectc(uart_ring *q, char elem); +bool put_char(uart_ring *q, char elem); +void clear_uart_buff(uart_ring *q); + +// ******************************** UART buffers ******************************** + +extern uart_ring uart_ring_debug; +extern uart_ring uart_ring_som_debug; + +// ======================= SPI ======================= + +#define SPI_TIMEOUT_US 10000U + +// got max rate from hitting a non-existent endpoint +// in a tight loop, plus some buffer +#define SPI_IRQ_RATE 16000U +#define SPI_BUF_SIZE 4096U + +#define SPI_CHECKSUM_START 0xABU +#define SPI_SYNC_BYTE 0x5AU +#define SPI_HACK 0x79U +#define SPI_DACK 0x85U +#define SPI_NACK 0x1FU +#define SPI_HEADER_SIZE 7U + +// SPI states +enum { + SPI_STATE_HEADER, + SPI_STATE_HEADER_ACK, + SPI_STATE_HEADER_NACK, + SPI_STATE_DATA_RX, + SPI_STATE_DATA_RX_ACK, + SPI_STATE_DATA_TX +}; + +extern uint16_t spi_error_count; + +void can_tx_comms_resume_spi(void); +void spi_init(void); +void spi_rx_done(void); +void spi_tx_done(bool reset); + +// ======================= USB ======================= + +// IRQs: OTG_FS + +typedef union { + uint16_t w; + struct BW { + uint8_t msb; + uint8_t lsb; + } + bw; +} uint16_t_uint8_t; + +typedef union _USB_Setup { + uint32_t d8[2]; + struct _SetupPkt_Struc + { + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t_uint8_t wValue; + uint16_t_uint8_t wIndex; + uint16_t_uint8_t wLength; + } b; +} USB_Setup_TypeDef; + +// **** supporting defines **** +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +#define USB_DESC_TYPE_DEVICE 0x01 +#define USB_DESC_TYPE_CONFIGURATION 0x02 +#define USB_DESC_TYPE_STRING 0x03 +#define USB_DESC_TYPE_INTERFACE 0x04 +#define USB_DESC_TYPE_ENDPOINT 0x05 +#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 +#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07 +#define USB_DESC_TYPE_BINARY_OBJECT_STORE 0x0f + +// offsets for configuration strings +#define STRING_OFFSET_LANGID 0x00 +#define STRING_OFFSET_IMANUFACTURER 0x01 +#define STRING_OFFSET_IPRODUCT 0x02 +#define STRING_OFFSET_ISERIAL 0x03 +#define STRING_OFFSET_ICONFIGURATION 0x04 +#define STRING_OFFSET_IINTERFACE 0x05 + +// WebUSB requests +#define WEBUSB_REQ_GET_URL 0x02 + +// WebUSB types +#define WEBUSB_DESC_TYPE_URL 0x03 +#define WEBUSB_URL_SCHEME_HTTPS 0x01 +#define WEBUSB_URL_SCHEME_HTTP 0x00 + +// WinUSB requests +#define WINUSB_REQ_GET_COMPATID_DESCRIPTOR 0x04 +#define WINUSB_REQ_GET_EXT_PROPS_OS 0x05 +#define WINUSB_REQ_GET_DESCRIPTOR 0x07 + +#define STS_GOUT_NAK 1 +#define STS_DATA_UPDT 2 +#define STS_XFER_COMP 3 +#define STS_SETUP_COMP 4 +#define STS_SETUP_UPDT 6 + +// for the repeating interfaces +#define DSCR_INTERFACE_LEN 9 +#define DSCR_ENDPOINT_LEN 7 +#define DSCR_CONFIG_LEN 9 +#define DSCR_DEVICE_LEN 18 + +// endpoint types +#define ENDPOINT_TYPE_CONTROL 0 +#define ENDPOINT_TYPE_ISO 1 +#define ENDPOINT_TYPE_BULK 2 +#define ENDPOINT_TYPE_INT 3 + +// These are arbitrary values used in bRequest +#define MS_VENDOR_CODE 0x20 +#define WEBUSB_VENDOR_CODE 0x30 + +// BOS constants +#define BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH 0x05 +#define BINARY_OBJECT_STORE_DESCRIPTOR 0x0F +#define WINUSB_PLATFORM_DESCRIPTOR_LENGTH 0x9E + +// Convert machine byte order to USB byte order +#define TOUSBORDER(num)\ + ((num) & 0xFFU), (((uint16_t)(num) >> 8) & 0xFFU) + +// take in string length and return the first 2 bytes of a string descriptor +#define STRING_DESCRIPTOR_HEADER(size)\ + (((((size) * 2) + 2) & 0xFF) | 0x0300) + +#define ENDPOINT_RCV 0x80 +#define ENDPOINT_SND 0x00 + +// ***************************** USB port ***************************** +void can_tx_comms_resume_usb(void); + +// ======================= FDCAN ======================= + +#define CAN_ACK_ERROR 3U + +typedef struct { + volatile uint32_t header[2]; + volatile uint32_t data_word[CANPACKET_DATA_SIZE_MAX/4U]; +} canfd_fifo; + +extern FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT]; + +void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number); +void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg); + +// ======================= CAN COMMON ======================= + +typedef struct { + volatile uint32_t w_ptr; + volatile uint32_t r_ptr; + uint32_t fifo_size; + CANPacket_t *elems; +} can_ring; + +typedef struct { + uint8_t bus_lookup; + uint8_t can_num_lookup; + int8_t forwarding_bus; + uint32_t can_speed; + uint32_t can_data_speed; + bool canfd_auto; + bool canfd_enabled; + bool brs_enabled; + bool canfd_non_iso; +} bus_config_t; + +extern uint32_t safety_tx_blocked; +extern uint32_t safety_rx_invalid; +extern uint32_t tx_buffer_overflow; +extern uint32_t rx_buffer_overflow; + +extern can_health_t can_health[PANDA_CAN_CNT]; + +// Ignition detected from CAN messages +extern bool ignition_can; +extern uint32_t ignition_can_cnt; + +extern bool can_silent; +extern bool can_loopback; + +// ******************* functions prototypes ********************* +bool can_init(uint8_t can_number); +void process_can(uint8_t can_number); + +// ********************* instantiate queues ********************* +extern can_ring *can_queues[PANDA_CAN_CNT]; + +// helpers +#define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU) +#define BYTE_ARRAY_TO_WORD(dst32, src8) ((dst32) = 0[src8] | (1[src8] << 8U) | (2[src8] << 16U) | (3[src8] << 24U)) + +// ********************* interrupt safe queue ********************* +bool can_pop(can_ring *q, CANPacket_t *elem); +bool can_push(can_ring *q, const CANPacket_t *elem); +uint32_t can_slots_empty(const can_ring *q); +void can_clear(can_ring *q); +extern bus_config_t bus_config[PANDA_CAN_CNT]; + +#define CANIF_FROM_CAN_NUM(num) (cans[num]) +#define BUS_NUM_FROM_CAN_NUM(num) (bus_config[num].bus_lookup) +#define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup) + +void can_init_all(void); +void can_set_orientation(bool flipped); +#ifdef PANDA_JUNGLE +void can_set_forwarding(uint8_t from, uint8_t to); +#endif +void ignition_can_hook(CANPacket_t *to_push); +bool can_tx_check_min_slots_free(uint32_t min); +uint8_t calculate_checksum(const uint8_t *dat, uint32_t len); +void can_set_checksum(CANPacket_t *packet); +bool can_check_checksum(CANPacket_t *packet); +void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook); +bool is_speed_valid(uint32_t speed, const uint32_t *all_speeds, uint8_t len); + +// ********************* instantiate queues ********************* + +#define CAN_RX_BUFFER_SIZE 4096U +#define CAN_TX_BUFFER_SIZE 416U + +extern can_ring can_rx_q; +extern can_ring can_tx1_q; +extern can_ring can_tx2_q; +extern can_ring can_tx3_q; + +// ======================= LED ======================= + +#define LED_RED 0U +#define LED_GREEN 1U +#define LED_BLUE 2U + +#define LED_PWM_POWER 2U + +void led_set(uint8_t color, bool enabled); +void led_init(void); + +// ======================= FAN ======================= + +struct fan_state_t { + uint16_t tach_counter; + uint16_t rpm; + uint8_t power; + float error_integral; + uint8_t cooldown_counter; +}; +extern struct fan_state_t fan_state; + +void fan_init(void); +void fan_set_power(uint8_t percentage); +// Call this at FAN_TICK_FREQ +void fan_tick(void); + +// ======================= ADC TYPES ======================= +// These types are used by harness and defined here to avoid circular includes + +typedef enum { + SAMPLETIME_1_CYCLE = 0, + SAMPLETIME_2_CYCLES = 1, + SAMPLETIME_8_CYCLES = 2, + SAMPLETIME_16_CYCLES = 3, + SAMPLETIME_32_CYCLES = 4, + SAMPLETIME_64_CYCLES = 5, + SAMPLETIME_387_CYCLES = 6, + SAMPLETIME_810_CYCLES = 7 +} adc_sample_time_t; + +typedef enum { + OVERSAMPLING_1 = 0, + OVERSAMPLING_2 = 1, + OVERSAMPLING_4 = 2, + OVERSAMPLING_8 = 3, + OVERSAMPLING_16 = 4, + OVERSAMPLING_32 = 5, + OVERSAMPLING_64 = 6, + OVERSAMPLING_128 = 7, + OVERSAMPLING_256 = 8, + OVERSAMPLING_512 = 9, + OVERSAMPLING_1024 = 10 +} adc_oversampling_t; + +typedef struct { + ADC_TypeDef *adc; + uint8_t channel; + adc_sample_time_t sample_time; + adc_oversampling_t oversampling; +} adc_signal_t; + +#define ADC_CHANNEL_DEFAULT(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_32_CYCLES, .oversampling = OVERSAMPLING_64} +#define VREFINT_CAL_ADDR ((uint16_t *)0x1FF1E860UL) + +void adc_init(ADC_TypeDef *adc); +uint16_t adc_get_raw(const adc_signal_t *signal); +uint16_t adc_get_mV(const adc_signal_t *signal); + +// ======================= HARNESS ======================= + +#define HARNESS_STATUS_NC 0U +#define HARNESS_STATUS_NORMAL 1U +#define HARNESS_STATUS_FLIPPED 2U + +struct harness_t { + uint8_t status; + uint16_t sbu1_voltage_mV; + uint16_t sbu2_voltage_mV; + bool relay_driven; + bool sbu_adc_lock; +}; + +struct harness_configuration { + GPIO_TypeDef * const GPIO_SBU1; + GPIO_TypeDef * const GPIO_SBU2; + GPIO_TypeDef * const GPIO_relay_SBU1; + GPIO_TypeDef * const GPIO_relay_SBU2; + const uint8_t pin_SBU1; + const uint8_t pin_SBU2; + const uint8_t pin_relay_SBU1; + const uint8_t pin_relay_SBU2; + const adc_signal_t adc_signal_SBU1; + const adc_signal_t adc_signal_SBU2; +}; + +typedef struct harness_configuration harness_configuration; + +// The ignition relay is only used for testing purposes +void set_intercept_relay(bool intercept, bool ignition_relay); +bool harness_check_ignition(void); +void harness_tick(void); +void harness_init(void); + +// ======================= BOOTKICK ======================= + +extern bool bootkick_reset_triggered; + +void bootkick_tick(bool ignition, bool recent_heartbeat); + +// ======================= CLOCK SOURCE ======================= + +#define CLOCK_SOURCE_PERIOD_MS 50U +#define CLOCK_SOURCE_PULSE_LEN_MS 2U + +void clock_source_set_timer_params(uint16_t param1, uint16_t param2); +void clock_source_init(bool enable_channel1); + +// ======================= FAKE SIREN ======================= + +#define CODEC_I2C_ADDR 0x10 + +void fake_i2c_siren_set(bool enabled); +void fake_siren_set(bool enabled); + +// ======================= SIMPLE WATCHDOG ======================= + +typedef struct simple_watchdog_state_t { + uint32_t fault; + uint32_t last_ts; + uint32_t threshold; +} simple_watchdog_state_t; + +void simple_watchdog_kick(void); +void simple_watchdog_init(uint32_t fault, uint32_t threshold); + +// ======================= POWER SAVING ======================= + +// WARNING: To stay in compliance with the SIL2 rules laid out in STM UM1840, we should never implement any of the available hardware low power modes. +// See rule: CoU_3 + +#define POWER_SAVE_STATUS_DISABLED 0 +#define POWER_SAVE_STATUS_ENABLED 1 + +extern int power_save_status; + +void set_power_save_state(int state); +void enable_can_transceivers(bool enabled); + +// ======================= FLASHER ======================= + +// from the linker script +#define APP_START_ADDRESS 0x8020000U + +// flasher state variables +extern uint32_t *prog_ptr; +extern bool unlocked; + +void soft_flasher_start(void); diff --git a/board/drivers/fake_siren.h b/board/drivers/fake_siren.c similarity index 95% rename from board/drivers/fake_siren.h rename to board/drivers/fake_siren.c index 3a4d8a36a57..a6f7282dcc0 100644 --- a/board/drivers/fake_siren.h +++ b/board/drivers/fake_siren.c @@ -1,8 +1,10 @@ -#include "board/stm32h7/lli2c.h" +#include "drivers.h" -#define CODEC_I2C_ADDR 0x10 +#include "board/stm32h7/lldrivers.h" +#include "board/globals.h" +#include "board/print.h" -void siren_tim7_init(void) { +static void siren_tim7_init(void) { // Init trigger timer (around 2.5kHz) register_set(&TIM7->PSC, 0U, 0xFFFFU); register_set(&TIM7->ARR, 133U, 0xFFFFU); @@ -12,7 +14,7 @@ void siren_tim7_init(void) { TIM7->CR1 |= TIM_CR1_CEN; } -void siren_dac_init(void) { +static void siren_dac_init(void) { DAC1->DHR8R1 = (1U << 7); DAC1->DHR8R2 = (1U << 7); register_set(&DAC1->MCR, 0U, 0xFFFFFFFFU); @@ -20,7 +22,7 @@ void siren_dac_init(void) { register_set_bits(&DAC1->CR, DAC_CR_EN1 | DAC_CR_EN2); } -void siren_dma_init(void) { +static void siren_dma_init(void) { // 1Vpp sine wave with 1V offset static const uint8_t fake_siren_lut[360] = { 134U, 135U, 137U, 138U, 139U, 140U, 141U, 143U, 144U, 145U, 146U, 148U, 149U, 150U, 151U, 152U, 154U, 155U, 156U, 157U, 158U, 159U, 160U, 162U, 163U, 164U, 165U, 166U, 167U, 168U, 169U, 170U, 171U, 172U, 174U, 175U, 176U, 177U, 177U, 178U, 179U, 180U, 181U, 182U, 183U, 184U, 185U, 186U, 186U, 187U, 188U, 189U, 190U, 190U, 191U, 192U, 193U, 193U, 194U, 195U, 195U, 196U, 196U, 197U, 197U, 198U, 199U, 199U, 199U, 200U, 200U, 201U, 201U, 202U, 202U, 202U, 203U, 203U, 203U, 203U, 204U, 204U, 204U, 204U, 204U, 204U, 204U, 205U, 205U, 205U, 205U, 205U, 205U, 205U, 204U, 204U, 204U, 204U, 204U, 204U, 204U, 203U, 203U, 203U, 203U, 202U, 202U, 202U, 201U, 201U, 200U, 200U, 199U, 199U, 199U, 198U, 197U, 197U, 196U, 196U, 195U, 195U, 194U, 193U, 193U, 192U, 191U, 190U, 190U, 189U, 188U, 187U, 186U, 186U, 185U, 184U, 183U, 182U, 181U, 180U, 179U, 178U, 177U, 177U, 176U, 175U, 174U, 172U, 171U, 170U, 169U, 168U, 167U, 166U, 165U, 164U, 163U, 162U, 160U, 159U, 158U, 157U, 156U, 155U, 154U, 152U, 151U, 150U, 149U, 148U, 146U, 145U, 144U, 143U, 141U, 140U, 139U, 138U, 137U, 135U, 134U, 133U, 132U, 130U, 129U, 128U, 127U, 125U, 124U, 123U, 122U, 121U, 119U, 118U, 117U, 116U, 115U, 113U, 112U, 111U, 110U, 109U, 108U, 106U, 105U, 104U, 103U, 102U, 101U, 100U, 99U, 98U, 97U, 96U, 95U, 94U, 93U, 92U, 91U, 90U, 89U, 88U, 87U, 86U, 85U, 84U, 83U, 82U, 82U, 81U, 80U, 79U, 78U, 78U, 77U, 76U, 76U, 75U, 74U, 74U, 73U, 72U, 72U, 71U, 71U, 70U, 70U, 69U, 69U, 68U, 68U, 67U, 67U, 67U, 66U, 66U, 66U, 65U, 65U, 65U, 65U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 63U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 64U, 65U, 65U, 65U, 65U, 66U, 66U, 66U, 67U, 67U, 67U, 68U, 68U, 69U, 69U, 70U, 70U, 71U, 71U, 72U, 72U, 73U, 74U, 74U, 75U, 76U, 76U, 77U, 78U, 78U, 79U, 80U, 81U, 82U, 82U, 83U, 84U, 85U, 86U, 87U, 88U, 89U, 90U, 91U, 92U, 93U, 94U, 95U, 96U, 97U, 98U, 99U, 100U, 101U, 102U, 103U, 104U, 105U, 106U, 108U, 109U, 110U, 111U, 112U, 113U, 115U, 116U, 117U, 118U, 119U, 121U, 122U, 123U, 124U, 125U, 127U, 128U, 129U, 130U, 132U, 133U }; // Setup DMAMUX (DAC_CH1_DMA as input) @@ -33,7 +35,7 @@ void siren_dma_init(void) { DMA1_Stream1->CR = (0b11UL << DMA_SxCR_PL_Pos) | DMA_SxCR_MINC | DMA_SxCR_CIRC | (1U << DMA_SxCR_DIR_Pos); } -void fake_siren_codec_enable(bool enabled) { +static void fake_siren_codec_enable(bool enabled) { if (enabled) { bool success = true; success &= i2c_set_reg_bits(I2C5, CODEC_I2C_ADDR, 0x2B, (1U << 1)); // Left speaker mix from INA1 diff --git a/board/drivers/fan.h b/board/drivers/fan.c similarity index 90% rename from board/drivers/fan.h rename to board/drivers/fan.c index f1041ce8563..20f55254d2b 100644 --- a/board/drivers/fan.h +++ b/board/drivers/fan.c @@ -1,4 +1,7 @@ -#include "fan_declarations.h" +#include "drivers.h" +#include "board/stm32h7/lldrivers.h" +#include "board/utils.h" +#include "board/globals.h" struct fan_state_t fan_state; @@ -26,6 +29,7 @@ void fan_tick(void) { fan_state.rpm = (fan_rpm_fast + (3U * fan_state.rpm)) / 4U; #ifdef DEBUG_FAN + // TODO: Broken since a2064b8 puth(fan_state.target_rpm); print(" "); puth(fan_rpm_fast); print(" "); puth(fan_state.power); diff --git a/board/drivers/fan_declarations.h b/board/drivers/fan_declarations.h deleted file mode 100644 index 3dd3e7cfabf..00000000000 --- a/board/drivers/fan_declarations.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -struct fan_state_t { - uint16_t tach_counter; - uint16_t rpm; - uint8_t power; - float error_integral; - uint8_t cooldown_counter; -}; -extern struct fan_state_t fan_state; - -void fan_set_power(uint8_t percentage); -void llfan_init(void); -void fan_init(void); -// Call this at FAN_TICK_FREQ -void fan_tick(void); diff --git a/board/faults.h b/board/drivers/faults.c similarity index 88% rename from board/faults.h rename to board/drivers/faults.c index 0fc9d2c5cfb..6e61a91b6d6 100644 --- a/board/faults.h +++ b/board/drivers/faults.c @@ -1,4 +1,6 @@ -#include "faults_declarations.h" +#include "board/config.h" +#include "board/drivers/drivers.h" +#include "board/print.h" uint8_t fault_status = FAULT_STATUS_NONE; uint32_t faults = 0U; diff --git a/board/drivers/fdcan.h b/board/drivers/fdcan.c similarity index 99% rename from board/drivers/fdcan.h rename to board/drivers/fdcan.c index 2aa64e97dcc..a33a93eee10 100644 --- a/board/drivers/fdcan.h +++ b/board/drivers/fdcan.c @@ -1,4 +1,6 @@ -#include "fdcan_declarations.h" +#include "drivers.h" + +#include "board/config.h" FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT] = {FDCAN1, FDCAN2, FDCAN3}; @@ -149,7 +151,7 @@ void process_can(uint8_t can_number) { // FDFDCANx_IT0 IRQ Handler (RX and errors) // blink blue when we are receiving CAN messages -void can_rx(uint8_t can_number) { +static void can_rx(uint8_t can_number) { FDCAN_GlobalTypeDef *FDCANx = CANIF_FROM_CAN_NUM(can_number); uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); diff --git a/board/drivers/fdcan_declarations.h b/board/drivers/fdcan_declarations.h deleted file mode 100644 index c77d1e31382..00000000000 --- a/board/drivers/fdcan_declarations.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "board/can.h" - -typedef struct { - volatile uint32_t header[2]; - volatile uint32_t data_word[CANPACKET_DATA_SIZE_MAX/4U]; -} canfd_fifo; - -extern FDCAN_GlobalTypeDef *cans[PANDA_CAN_CNT]; - -#define CAN_ACK_ERROR 3U - -void can_clear_send(FDCAN_GlobalTypeDef *FDCANx, uint8_t can_number); -void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg); - -void process_can(uint8_t can_number); -void can_rx(uint8_t can_number); -bool can_init(uint8_t can_number); diff --git a/board/flasher.h b/board/drivers/flasher.c similarity index 78% rename from board/flasher.h rename to board/drivers/flasher.c index f816abec900..792cec6f8f7 100644 --- a/board/flasher.h +++ b/board/drivers/flasher.c @@ -1,18 +1,24 @@ -// from the linker script -#define APP_START_ADDRESS 0x8020000U +#include "board/config.h" +#include "board/libc.h" +#include "board/stm32h7/lldrivers.h" +#include "board/drivers/drivers.h" +#include "board/print.h" + +#include "board/globals.h" +#include "board/provision.h" +#include "board/early_init.h" +#include "board/obj/gitversion.h" // flasher state variables uint32_t *prog_ptr = NULL; bool unlocked = false; -void spi_init(void); - -int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { +int comms_control_handler(ControlPacket_t * const req, uint8_t *resp) { int resp_len = 0; // flasher machine - memset(resp, 0, 4); - memcpy(resp+4, "\xde\xad\xd0\x0d", 4); + (void)memset(resp, 0, 4); + (void)memcpy(resp+4, "\xde\xad\xd0\x0d", 4); resp[0] = 0xff; resp[2] = req->request; resp[3] = ~req->request; @@ -55,8 +61,9 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { // **** 0xd0: fetch serial number case 0xd0: // addresses are OTP - if (req->param1 == 1) { - memcpy(resp, (void *)DEVICE_SERIAL_NUMBER_ADDRESS, 0x10); + if (req->param1 == 1u) { + volatile const uint8_t *deviceSerialPtr = (volatile const uint8_t *)DEVICE_SERIAL_NUMBER_ADDRESS; + memcpy(resp, (void *)deviceSerialPtr, 0x10); resp_len = 0x10; } else { get_provision_chunk(resp); @@ -77,12 +84,14 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; NVIC_SystemReset(); break; + default: + break; } break; // **** 0xd6: get version case 0xd6: COMPILE_TIME_ASSERT(sizeof(gitversion) <= USBPACKET_MAX_SIZE); - memcpy(resp, gitversion, sizeof(gitversion)); + (void)memcpy(resp, gitversion, sizeof(gitversion)); resp_len = sizeof(gitversion) - 1U; break; // **** 0xd8: reset ST @@ -90,6 +99,9 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { flush_write_buffer(); NVIC_SystemReset(); break; + default: + // Unknown request + break; } return resp_len; } @@ -109,8 +121,8 @@ void refresh_can_tx_slots_available(void) {} void comms_endpoint2_write(const uint8_t *data, uint32_t len) { led_set(LED_RED, 0); - for (uint32_t i = 0; i < len/4; i++) { - flash_write_word(prog_ptr, *(uint32_t*)(data+(i*4))); + for (uint32_t i = 0; i < len/4u; i++) { + flash_write_word(prog_ptr, *(uint32_t*)(data+(i*4u))); //*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr; prog_ptr++; diff --git a/board/drivers/gpio.h b/board/drivers/gpio.c similarity index 86% rename from board/drivers/gpio.h rename to board/drivers/gpio.c index aea604254e2..e806763ae45 100644 --- a/board/drivers/gpio.h +++ b/board/drivers/gpio.c @@ -1,14 +1,4 @@ -#define MODE_INPUT 0 -#define MODE_OUTPUT 1 -#define MODE_ALTERNATE 2 -#define MODE_ANALOG 3 - -#define PULL_NONE 0 -#define PULL_UP 1 -#define PULL_DOWN 2 - -#define OUTPUT_TYPE_PUSH_PULL 0U -#define OUTPUT_TYPE_OPEN_DRAIN 1U +#include "drivers.h" void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { ENTER_CRITICAL(); @@ -64,11 +54,6 @@ int get_gpio_input(const GPIO_TypeDef *GPIO, unsigned int pin) { } #ifdef PANDA_JUNGLE -typedef struct { - GPIO_TypeDef * const bank; - uint8_t pin; -} gpio_t; - void gpio_set_all_output(gpio_t *pins, uint8_t num_pins, bool enabled) { for (uint8_t i = 0; i < num_pins; i++) { set_gpio_output(pins[i].bank, pins[i].pin, enabled); @@ -87,7 +72,7 @@ void gpio_set_bitmask(gpio_t *pins, uint8_t num_pins, uint32_t bitmask) { bool detect_with_pull(GPIO_TypeDef *GPIO, int pin, int mode) { set_gpio_mode(GPIO, pin, MODE_INPUT); set_gpio_pullup(GPIO, pin, mode); - for (volatile int i=0; i + +#include "board/config.h" +#include "board/drivers/drivers.h" +#include "board/globals.h" +#include "board/print.h" // WARNING: To stay in compliance with the SIL2 rules laid out in STM UM1840, we should never implement any of the available hardware low power modes. // See rule: CoU_3 diff --git a/board/drivers/pwm.h b/board/drivers/pwm.c similarity index 96% rename from board/drivers/pwm.h rename to board/drivers/pwm.c index 3d0d73efdc6..89848cfbad7 100644 --- a/board/drivers/pwm.h +++ b/board/drivers/pwm.c @@ -1,4 +1,4 @@ -#define PWM_COUNTER_OVERFLOW 4800U // To get ~25kHz +#include "drivers.h" // TODO: Implement for 32-bit timers diff --git a/board/drivers/registers.h b/board/drivers/registers.c similarity index 96% rename from board/drivers/registers.h rename to board/drivers/registers.c index ce4be14a92a..84f910311e9 100644 --- a/board/drivers/registers.h +++ b/board/drivers/registers.c @@ -1,4 +1,7 @@ -#include "registers_declarations.h" +#include "board/config.h" +#include "drivers.h" +#include "board/libc.h" +#include "board/print.h" static reg register_map[REGISTER_MAP_SIZE]; diff --git a/board/drivers/registers_declarations.h b/board/drivers/registers_declarations.h deleted file mode 100644 index 90ee66df0df..00000000000 --- a/board/drivers/registers_declarations.h +++ /dev/null @@ -1,25 +0,0 @@ -#pragma once - -typedef struct reg { - volatile uint32_t *address; - uint32_t value; - uint32_t check_mask; - bool logged_fault; -} reg; - -// 10 bit hash with 23 as a prime -#define REGISTER_MAP_SIZE 0x3FFU -#define HASHING_PRIME 23U -#define CHECK_COLLISION(hash, addr) (((uint32_t) register_map[hash].address != 0U) && (register_map[hash].address != (addr))) - -// Do not put bits in the check mask that get changed by the hardware -void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask); -// Set individual bits. Also add them to the check_mask. -// Do not use this to change bits that get reset by the hardware -void register_set_bits(volatile uint32_t *addr, uint32_t val); -// Clear individual bits. Also add them to the check_mask. -// Do not use this to clear bits that get set by the hardware -void register_clear_bits(volatile uint32_t *addr, uint32_t val); -// To be called periodically -void check_registers(void); -void init_registers(void); diff --git a/board/drivers/simple_watchdog.h b/board/drivers/simple_watchdog.c similarity index 80% rename from board/drivers/simple_watchdog.h rename to board/drivers/simple_watchdog.c index f679cb19393..24c837620df 100644 --- a/board/drivers/simple_watchdog.h +++ b/board/drivers/simple_watchdog.c @@ -1,4 +1,10 @@ -#include "simple_watchdog_declarations.h" +#include + +#include "drivers.h" + +#include "board/utils.h" +#include "board/libc.h" +#include "board/print.h" static simple_watchdog_state_t wd_state; diff --git a/board/drivers/simple_watchdog_declarations.h b/board/drivers/simple_watchdog_declarations.h deleted file mode 100644 index 2bda71590ba..00000000000 --- a/board/drivers/simple_watchdog_declarations.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -typedef struct simple_watchdog_state_t { - uint32_t fault; - uint32_t last_ts; - uint32_t threshold; -} simple_watchdog_state_t; - -void simple_watchdog_kick(void); -void simple_watchdog_init(uint32_t fault, uint32_t threshold); diff --git a/board/drivers/spi.h b/board/drivers/spi.c similarity index 90% rename from board/drivers/spi.h rename to board/drivers/spi.c index d291fe06a8d..c8418ad7ebc 100644 --- a/board/drivers/spi.h +++ b/board/drivers/spi.c @@ -1,10 +1,12 @@ -#pragma once +#include "drivers.h" +#include "board/libc.h" +#include "board/config.h" +#include "board/print.h" -#include "board/drivers/spi_declarations.h" -#include "board/crc.h" +#include "board/globals.h" -uint8_t spi_buf_rx[SPI_BUF_SIZE]; -uint8_t spi_buf_tx[SPI_BUF_SIZE]; +// H7 DMA2 located in D2 domain, so we need to use SRAM1/SRAM2 +__attribute__((section(".sram12"))) static uint8_t spi_buf_rx[SPI_BUF_SIZE]; uint16_t spi_error_count = 0; @@ -13,6 +15,24 @@ static uint16_t spi_data_len_mosi; static bool spi_can_tx_ready = false; static const unsigned char version_text[] = "VERSION"; +static uint8_t crc_checksum(const uint8_t *dat, int len, const uint8_t poly) { + uint8_t crc = 0xFFU; + int i; + int j; + for (i = len - 1; i >= 0; i--) { + crc ^= dat[i]; + for (j = 0; j < 8; j++) { + if ((crc & 0x80U) != 0U) { + crc = (uint8_t)((crc << 1) ^ poly); + } + else { + crc <<= 1; + } + } + } + return crc; +} + static uint16_t spi_version_packet(uint8_t *out) { // this protocol version request is a stable portion of // the panda's SPI protocol. its contents match that of the @@ -81,6 +101,7 @@ void spi_rx_done(void) { bool checksum_valid = false; static uint8_t spi_endpoint; static uint16_t spi_data_len_miso; + __attribute__((section(".sram12"))) static uint8_t spi_buf_tx[SPI_BUF_SIZE]; // parse header spi_endpoint = spi_buf_rx[1]; diff --git a/board/drivers/spi_declarations.h b/board/drivers/spi_declarations.h deleted file mode 100644 index 23254f0e87a..00000000000 --- a/board/drivers/spi_declarations.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -#include "board/crc.h" - -#define SPI_TIMEOUT_US 10000U - -// got max rate from hitting a non-existent endpoint -// in a tight loop, plus some buffer -#define SPI_IRQ_RATE 16000U - -#define SPI_BUF_SIZE 4096U -// H7 DMA2 located in D2 domain, so we need to use SRAM1/SRAM2 -__attribute__((section(".sram12"))) extern uint8_t spi_buf_rx[SPI_BUF_SIZE]; -__attribute__((section(".sram12"))) extern uint8_t spi_buf_tx[SPI_BUF_SIZE]; - -#define SPI_CHECKSUM_START 0xABU -#define SPI_SYNC_BYTE 0x5AU -#define SPI_HACK 0x79U -#define SPI_DACK 0x85U -#define SPI_NACK 0x1FU - -// SPI states -enum { - SPI_STATE_HEADER, - SPI_STATE_HEADER_ACK, - SPI_STATE_HEADER_NACK, - SPI_STATE_DATA_RX, - SPI_STATE_DATA_RX_ACK, - SPI_STATE_DATA_TX -}; - -extern uint16_t spi_error_count; - -#define SPI_HEADER_SIZE 7U - -// low level SPI prototypes -void llspi_init(void); -void llspi_mosi_dma(uint8_t *addr, int len); -void llspi_miso_dma(uint8_t *addr, int len); - -void can_tx_comms_resume_spi(void); -void spi_init(void); -void spi_rx_done(void); -void spi_tx_done(bool reset); diff --git a/board/drivers/timers.h b/board/drivers/timers.c similarity index 95% rename from board/drivers/timers.h rename to board/drivers/timers.c index 4c046a2b49b..016e1072a3f 100644 --- a/board/drivers/timers.h +++ b/board/drivers/timers.c @@ -1,3 +1,6 @@ +#include "drivers.h" +#include "board/config.h" + static void timer_init(TIM_TypeDef *TIM, int psc) { register_set(&(TIM->PSC), (psc-1), 0xFFFFU); register_set(&(TIM->DIER), TIM_DIER_UIE, 0x5F5FU); diff --git a/board/drivers/uart.h b/board/drivers/uart.c similarity index 89% rename from board/drivers/uart.h rename to board/drivers/uart.c index aeacf84b851..004ee6ac417 100644 --- a/board/drivers/uart.h +++ b/board/drivers/uart.c @@ -1,11 +1,10 @@ -#include "uart_declarations.h" - -// ***************************** Definitions ***************************** +#include "board/config.h" +#include "drivers.h" +#include "board/print.h" #define UART_BUFFER(x, size_rx, size_tx, uart_ptr, callback_ptr, overwrite_mode) \ static uint8_t elems_rx_##x[size_rx]; \ static uint8_t elems_tx_##x[size_tx]; \ - extern uart_ring uart_ring_##x; \ uart_ring uart_ring_##x = { \ .w_ptr_tx = 0, \ .r_ptr_tx = 0, \ @@ -50,7 +49,9 @@ bool get_char(uart_ring *q, char *elem) { ENTER_CRITICAL(); if (q->w_ptr_rx != q->r_ptr_rx) { - if (elem != NULL) *elem = q->elems_rx[q->r_ptr_rx]; + if (elem != NULL) { + *elem = q->elems_rx[q->r_ptr_rx]; + } q->r_ptr_rx = (q->r_ptr_rx + 1U) % q->rx_fifo_size; ret = true; } @@ -113,7 +114,9 @@ void putch(const char a) { void print(const char *a) { for (const char *in = a; *in; in++) { - if (*in == '\n') putch('\r'); + if (*in == '\n') { + putch('\r'); + } putch(*in); } } @@ -130,16 +133,18 @@ void puth(unsigned int i) { } #if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG) -static void puth4(unsigned int i) { +void puth4(unsigned int i) { puthx(i, 4U); } #endif #if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG_USB) || defined(DEBUG_COMMS) -static void hexdump(const void *a, int l) { +void hexdump(const void *a, int l) { if (a != NULL) { for (int i=0; i < l; i++) { - if ((i != 0) && ((i & 0xf) == 0)) print("\n"); + if ((i != 0) && ((i & 0xf) == 0)) { + print("\n"); + } puthx(((const unsigned char*)a)[i], 2U); print(" "); } diff --git a/board/drivers/uart_declarations.h b/board/drivers/uart_declarations.h deleted file mode 100644 index 14ec26110f9..00000000000 --- a/board/drivers/uart_declarations.h +++ /dev/null @@ -1,39 +0,0 @@ -#pragma once - -// ***************************** Definitions ***************************** -#define FIFO_SIZE_INT 0x400U - -typedef struct uart_ring { - volatile uint16_t w_ptr_tx; - volatile uint16_t r_ptr_tx; - uint8_t *elems_tx; - uint32_t tx_fifo_size; - volatile uint16_t w_ptr_rx; - volatile uint16_t r_ptr_rx; - uint8_t *elems_rx; - uint32_t rx_fifo_size; - USART_TypeDef *uart; - void (*callback)(struct uart_ring*); - bool overwrite; -} uart_ring; - -// ***************************** Function prototypes ***************************** -void debug_ring_callback(uart_ring *ring); -void uart_tx_ring(uart_ring *q); -uart_ring *get_ring_by_number(int a); -// ************************* Low-level buffer functions ************************* -bool get_char(uart_ring *q, char *elem); -bool injectc(uart_ring *q, char elem); -bool put_char(uart_ring *q, char elem); -void clear_uart_buff(uart_ring *q); -// ************************ High-level debug functions ********************** -void putch(const char a); -void print(const char *a); -void puthx(uint32_t i, uint8_t len); -void puth(unsigned int i); -#if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG) -static void puth4(unsigned int i); -#endif -#if defined(DEBUG_SPI) || defined(DEBUG_USB) || defined(DEBUG_COMMS) -static void hexdump(const void *a, int l); -#endif diff --git a/board/drivers/usb.h b/board/drivers/usb.c similarity index 99% rename from board/drivers/usb.h rename to board/drivers/usb.c index d393d7e4d13..b39c69e715f 100644 --- a/board/drivers/usb.h +++ b/board/drivers/usb.c @@ -1,4 +1,10 @@ -#include "usb_declarations.h" + +#include + +#include "drivers.h" +#include "board/config.h" +#include "board/globals.h" +#include "board/print.h" static uint8_t response[USBPACKET_MAX_SIZE]; @@ -100,10 +106,10 @@ static void usb_reset(void) { // flush TX fifo USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH) {} // flush RX FIFO USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH) {} // no global NAK USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK; @@ -493,6 +499,7 @@ static void usb_setup(void) { break; default: USB_WritePacket_EP0(0, 0); + break; } break; default: @@ -508,7 +515,6 @@ static void usb_setup(void) { } - // ***************************** USB port ***************************** void usb_irqhandler(void) { @@ -607,7 +613,7 @@ void usb_irqhandler(void) { } } - /*if (gintsts & USB_OTG_GINTSTS_HPRTINT) { +#if 0 // host print("HPRT:"); puth(USBx_HOST_PORT->HPRT); @@ -617,7 +623,7 @@ void usb_irqhandler(void) { USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PCDET; } - }*/ +#endif if ((gintsts & USB_OTG_GINTSTS_BOUTNAKEFF) || (gintsts & USB_OTG_GINTSTS_GINAKEFF)) { // no global NAK, why is this getting set? diff --git a/board/drivers/usb_declarations.h b/board/drivers/usb_declarations.h deleted file mode 100644 index 379b162feb6..00000000000 --- a/board/drivers/usb_declarations.h +++ /dev/null @@ -1,111 +0,0 @@ -#pragma once - -// IRQs: OTG_FS - -typedef union { - uint16_t w; - struct BW { - uint8_t msb; - uint8_t lsb; - } - bw; -} uint16_t_uint8_t; - -typedef union _USB_Setup { - uint32_t d8[2]; - struct _SetupPkt_Struc - { - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t_uint8_t wValue; - uint16_t_uint8_t wIndex; - uint16_t_uint8_t wLength; - } b; -} USB_Setup_TypeDef; - -void usb_init(void); -void refresh_can_tx_slots_available(void); - -// **** supporting defines **** -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C - -#define USB_DESC_TYPE_DEVICE 0x01 -#define USB_DESC_TYPE_CONFIGURATION 0x02 -#define USB_DESC_TYPE_STRING 0x03 -#define USB_DESC_TYPE_INTERFACE 0x04 -#define USB_DESC_TYPE_ENDPOINT 0x05 -#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 -#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07 -#define USB_DESC_TYPE_BINARY_OBJECT_STORE 0x0f - -// offsets for configuration strings -#define STRING_OFFSET_LANGID 0x00 -#define STRING_OFFSET_IMANUFACTURER 0x01 -#define STRING_OFFSET_IPRODUCT 0x02 -#define STRING_OFFSET_ISERIAL 0x03 -#define STRING_OFFSET_ICONFIGURATION 0x04 -#define STRING_OFFSET_IINTERFACE 0x05 - -// WebUSB requests -#define WEBUSB_REQ_GET_URL 0x02 - -// WebUSB types -#define WEBUSB_DESC_TYPE_URL 0x03 -#define WEBUSB_URL_SCHEME_HTTPS 0x01 -#define WEBUSB_URL_SCHEME_HTTP 0x00 - -// WinUSB requests -#define WINUSB_REQ_GET_COMPATID_DESCRIPTOR 0x04 -#define WINUSB_REQ_GET_EXT_PROPS_OS 0x05 -#define WINUSB_REQ_GET_DESCRIPTOR 0x07 - -#define STS_GOUT_NAK 1 -#define STS_DATA_UPDT 2 -#define STS_XFER_COMP 3 -#define STS_SETUP_COMP 4 -#define STS_SETUP_UPDT 6 - -// for the repeating interfaces -#define DSCR_INTERFACE_LEN 9 -#define DSCR_ENDPOINT_LEN 7 -#define DSCR_CONFIG_LEN 9 -#define DSCR_DEVICE_LEN 18 - -// endpoint types -#define ENDPOINT_TYPE_CONTROL 0 -#define ENDPOINT_TYPE_ISO 1 -#define ENDPOINT_TYPE_BULK 2 -#define ENDPOINT_TYPE_INT 3 - -// These are arbitrary values used in bRequest -#define MS_VENDOR_CODE 0x20 -#define WEBUSB_VENDOR_CODE 0x30 - -// BOS constants -#define BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH 0x05 -#define BINARY_OBJECT_STORE_DESCRIPTOR 0x0F -#define WINUSB_PLATFORM_DESCRIPTOR_LENGTH 0x9E - -// Convert machine byte order to USB byte order -#define TOUSBORDER(num)\ - ((num) & 0xFFU), (((uint16_t)(num) >> 8) & 0xFFU) - -// take in string length and return the first 2 bytes of a string descriptor -#define STRING_DESCRIPTOR_HEADER(size)\ - (((((size) * 2) + 2) & 0xFF) | 0x0300) - -#define ENDPOINT_RCV 0x80 -#define ENDPOINT_SND 0x00 - -// ***************************** USB port ***************************** -void can_tx_comms_resume_usb(void); diff --git a/board/early_init.c b/board/early_init.c new file mode 100644 index 00000000000..4c159bf438f --- /dev/null +++ b/board/early_init.c @@ -0,0 +1,60 @@ +#include + +#include "board/config.h" +#include "early_init.h" +#include "drivers/drivers.h" +#include "globals.h" + +static void jump_to_bootloader(void) { + // do enter bootloader + enter_bootloader_mode = 0; + + bootloader_fcn_ptr bootloader_ptr = (bootloader_fcn_ptr)BOOTLOADER_ADDRESS; + bootloader_fcn bootloader = *bootloader_ptr; + + // jump to bootloader + enable_interrupts(); + bootloader(); + + // reset on exit + enter_bootloader_mode = BOOT_NORMAL; + NVIC_SystemReset(); +} + +void early_initialization(void) { + // Reset global critical depth + disable_interrupts(); + global_critical_depth = 0; + + // Init register and interrupt tables + init_registers(); + + // after it's been in the bootloader, things are initted differently, so we reset + if ((enter_bootloader_mode != BOOT_NORMAL) && + (enter_bootloader_mode != ENTER_BOOTLOADER_MAGIC) && + (enter_bootloader_mode != ENTER_SOFTLOADER_MAGIC)) { + enter_bootloader_mode = BOOT_NORMAL; + NVIC_SystemReset(); + } + + // if wrong chip, reboot + volatile unsigned int id = DBGMCU->IDCODE; + if ((id & 0xFFFU) != MCU_IDCODE) { + enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; + } + + // setup interrupt table + SCB->VTOR = (uint32_t)&g_pfnVectors; + + // early GPIOs float everything + early_gpio_float(); + + detect_board_type(); + + if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { + led_init(); + current_board->init_bootloader(); + led_set(LED_GREEN, 1); + jump_to_bootloader(); + } +} diff --git a/board/early_init.h b/board/early_init.h index d5131a42cfb..6db0a5d4b0d 100644 --- a/board/early_init.h +++ b/board/early_init.h @@ -1,3 +1,7 @@ +#pragma once + +#include + // Early bringup #define ENTER_BOOTLOADER_MAGIC 0xdeadbeefU #define ENTER_SOFTLOADER_MAGIC 0xdeadc0deU @@ -9,56 +13,5 @@ extern uint32_t enter_bootloader_mode; typedef void (*bootloader_fcn)(void); typedef bootloader_fcn *bootloader_fcn_ptr; -static void jump_to_bootloader(void) { - // do enter bootloader - enter_bootloader_mode = 0; - - bootloader_fcn_ptr bootloader_ptr = (bootloader_fcn_ptr)BOOTLOADER_ADDRESS; - bootloader_fcn bootloader = *bootloader_ptr; - - // jump to bootloader - enable_interrupts(); - bootloader(); - - // reset on exit - enter_bootloader_mode = BOOT_NORMAL; - NVIC_SystemReset(); -} - -void early_initialization(void) { - // Reset global critical depth - disable_interrupts(); - global_critical_depth = 0; - - // Init register and interrupt tables - init_registers(); - - // after it's been in the bootloader, things are initted differently, so we reset - if ((enter_bootloader_mode != BOOT_NORMAL) && - (enter_bootloader_mode != ENTER_BOOTLOADER_MAGIC) && - (enter_bootloader_mode != ENTER_SOFTLOADER_MAGIC)) { - enter_bootloader_mode = BOOT_NORMAL; - NVIC_SystemReset(); - } - - // if wrong chip, reboot - volatile unsigned int id = DBGMCU->IDCODE; - if ((id & 0xFFFU) != MCU_IDCODE) { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - } - - // setup interrupt table - SCB->VTOR = (uint32_t)&g_pfnVectors; - - // early GPIOs float everything - early_gpio_float(); - - detect_board_type(); - - if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { - led_init(); - current_board->init_bootloader(); - led_set(LED_GREEN, 1); - jump_to_bootloader(); - } -} +void early_initialization(void); +void __initialize_hardware_early(void); \ No newline at end of file diff --git a/board/fake_stm.c b/board/fake_stm.c new file mode 100644 index 00000000000..a80eef21aeb --- /dev/null +++ b/board/fake_stm.c @@ -0,0 +1,20 @@ +#include "fake_stm.h" + +#include + +void print(const char *a) { + printf("%s", a); +} + +void puth(unsigned int i) { + printf("%u", i); +} + +TIM_TypeDef timer; +TIM_TypeDef *MICROSECOND_TIMER = &timer; + +uint32_t microsecond_timer_get(void) { + return MICROSECOND_TIMER->CNT; +} + +void put_char(char c) {}; \ No newline at end of file diff --git a/board/fake_stm.h b/board/fake_stm.h index febf0544b76..11351493968 100644 --- a/board/fake_stm.h +++ b/board/fake_stm.h @@ -1,7 +1,11 @@ +#pragma once + +#ifdef STM32H7 +#error This code only makes sense on a non stm32h7 platform +#endif + // minimal code to fake a panda for tests -#include #include -#include #include "utils.h" @@ -10,24 +14,25 @@ #define ENTER_CRITICAL() 0 #define EXIT_CRITICAL() 0 -void print(const char *a) { - printf("%s", a); -} - -void puth(unsigned int i) { - printf("%u", i); -} +void print(const char *a); +void puth(unsigned int i); typedef struct { uint32_t CNT; } TIM_TypeDef; -TIM_TypeDef timer; -TIM_TypeDef *MICROSECOND_TIMER = &timer; -uint32_t microsecond_timer_get(void); +extern TIM_TypeDef timer; +extern TIM_TypeDef *MICROSECOND_TIMER; -uint32_t microsecond_timer_get(void) { - return MICROSECOND_TIMER->CNT; -} +uint32_t microsecond_timer_get(void); typedef uint32_t GPIO_TypeDef; +typedef int IRQn_Type; +typedef uint32_t ADC_TypeDef; +typedef uint32_t USART_TypeDef; +typedef uint32_t FDCAN_GlobalTypeDef; +typedef uint32_t SPI_TypeDef; +typedef uint32_t USB_OTG_GlobalTypeDef; +typedef uint32_t USB_OTG_DeviceTypeDef; + +#define NUM_INTERRUPTS 1 diff --git a/board/faults_declarations.h b/board/faults_declarations.h deleted file mode 100644 index 981e237566d..00000000000 --- a/board/faults_declarations.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#define FAULT_STATUS_NONE 0U -#define FAULT_STATUS_TEMPORARY 1U -#define FAULT_STATUS_PERMANENT 2U - -// Fault types, matches cereal.log.PandaState.FaultType -#define FAULT_RELAY_MALFUNCTION (1UL << 0) -#define FAULT_UNUSED_INTERRUPT_HANDLED (1UL << 1) -#define FAULT_INTERRUPT_RATE_CAN_1 (1UL << 2) -#define FAULT_INTERRUPT_RATE_CAN_2 (1UL << 3) -#define FAULT_INTERRUPT_RATE_CAN_3 (1UL << 4) -#define FAULT_INTERRUPT_RATE_TACH (1UL << 5) -#define FAULT_INTERRUPT_RATE_INTERRUPTS (1UL << 7) -#define FAULT_INTERRUPT_RATE_SPI_DMA (1UL << 8) -#define FAULT_INTERRUPT_RATE_USB (1UL << 15) -#define FAULT_REGISTER_DIVERGENT (1UL << 18) -#define FAULT_INTERRUPT_RATE_CLOCK_SOURCE (1UL << 20) -#define FAULT_INTERRUPT_RATE_TICK (1UL << 21) -#define FAULT_INTERRUPT_RATE_EXTI (1UL << 22) -#define FAULT_INTERRUPT_RATE_SPI (1UL << 23) -#define FAULT_INTERRUPT_RATE_UART_7 (1UL << 24) -#define FAULT_SIREN_MALFUNCTION (1UL << 25) -#define FAULT_HEARTBEAT_LOOP_WATCHDOG (1UL << 26) -#define FAULT_INTERRUPT_RATE_SOUND_DMA (1UL << 27) - -// Permanent faults -#define PERMANENT_FAULTS 0U - -extern uint8_t fault_status; -extern uint32_t faults; - -void fault_occurred(uint32_t fault); -void fault_recovered(uint32_t fault); diff --git a/board/globals.c b/board/globals.c new file mode 100644 index 00000000000..bb6a27e4e2b --- /dev/null +++ b/board/globals.c @@ -0,0 +1,6 @@ +#include "globals.h" + +uint8_t hw_type = 0; +board *current_board; +struct harness_t harness; +uint32_t uptime_cnt = 0; \ No newline at end of file diff --git a/board/globals.h b/board/globals.h new file mode 100644 index 00000000000..f27d8f84a85 --- /dev/null +++ b/board/globals.h @@ -0,0 +1,20 @@ +#pragma once + +#include + +#include "board/boards/boards.h" +#include "board/drivers/drivers.h" + +extern uint8_t hw_type; +extern struct board *current_board; +extern struct harness_t harness; +extern uint32_t uptime_cnt; +extern int _app_start[0xc000]; + +// heartbeat state +extern uint32_t heartbeat_counter; +extern bool heartbeat_lost; +extern bool heartbeat_disabled; // set over USB + + // siren state +extern bool siren_enabled; \ No newline at end of file diff --git a/board/health.h b/board/health.h index 9040edf5a1b..a7498118c07 100644 --- a/board/health.h +++ b/board/health.h @@ -1,3 +1,5 @@ +#pragma once + // When changing these structs, python/__init__.py needs to be kept up to date! #define HEALTH_PACKET_VERSION 17 diff --git a/board/jungle/boards/board_declarations.h b/board/jungle/boards/board_declarations.h index aad54dede70..a33b737dee0 100644 --- a/board/jungle/boards/board_declarations.h +++ b/board/jungle/boards/board_declarations.h @@ -1,60 +1,10 @@ -// ******************** Prototypes ******************** -typedef void (*board_init)(void); -typedef void (*board_board_tick)(void); -typedef bool (*board_get_button)(void); -typedef void (*board_init_bootloader)(void); -typedef void (*board_set_panda_power)(bool enabled); -typedef void (*board_set_panda_individual_power)(uint8_t port_num, bool enabled); -typedef void (*board_set_ignition)(bool enabled); -typedef void (*board_set_individual_ignition)(uint8_t bitmask); -typedef void (*board_set_harness_orientation)(uint8_t orientation); -typedef void (*board_set_can_mode)(uint8_t mode); -typedef void (*board_enable_can_transceiver)(uint8_t transceiver, bool enabled); -typedef void (*board_enable_header_pin)(uint8_t pin_num, bool enabled); -typedef float (*board_get_channel_power)(uint8_t channel); -typedef uint16_t (*board_get_sbu_mV)(uint8_t channel, uint8_t sbu); +#pragma once -struct board { - GPIO_TypeDef * const led_GPIO[3]; - const uint8_t led_pin[3]; - const uint8_t led_pwm_channels[3]; // leave at 0 to disable PWM - const uint16_t avdd_mV; - board_init init; - board_board_tick board_tick; - board_get_button get_button; - board_init_bootloader init_bootloader; - board_set_panda_power set_panda_power; - board_set_panda_individual_power set_panda_individual_power; - board_set_ignition set_ignition; - board_set_individual_ignition set_individual_ignition; - board_set_harness_orientation set_harness_orientation; - board_set_can_mode set_can_mode; - board_enable_can_transceiver enable_can_transceiver; - board_enable_header_pin enable_header_pin; - board_get_channel_power get_channel_power; - board_get_sbu_mV get_sbu_mV; +#include - // TODO: shouldn't need these - bool has_spi; -}; - -// ******************* Definitions ******************** -#define HW_TYPE_UNKNOWN 0U -#define HW_TYPE_V2 2U - -// CAN modes -#define CAN_MODE_NORMAL 0U -#define CAN_MODE_OBD_CAN2 3U - -// Harness states -#define HARNESS_ORIENTATION_NONE 0U -#define HARNESS_ORIENTATION_1 1U -#define HARNESS_ORIENTATION_2 2U - -#define SBU1 0U -#define SBU2 1U +#include "board/boards/boards.h" // ********************* Globals ********************** -uint8_t harness_orientation = HARNESS_ORIENTATION_NONE; -uint8_t can_mode = CAN_MODE_NORMAL; -uint8_t ignition = 0U; +extern uint8_t harness_orientation; +extern uint8_t can_mode; +extern uint8_t ignition; diff --git a/board/jungle/boards/board_v2.c b/board/jungle/boards/board_v2.c new file mode 100644 index 00000000000..314072ec1b4 --- /dev/null +++ b/board/jungle/boards/board_v2.c @@ -0,0 +1,246 @@ +#include "board/jungle/boards/board_v2.h" +#include "board/print.h" + +uint8_t harness_orientation = HARNESS_ORIENTATION_NONE; +uint8_t can_mode = CAN_MODE_NORMAL; +uint8_t ignition = 0U; + +void board_v2_set_harness_orientation(uint8_t orientation) { + switch (orientation) { + case HARNESS_ORIENTATION_NONE: + gpio_set_all_output(sbu1_ignition_pins, sizeof(sbu1_ignition_pins) / sizeof(gpio_t), false); + gpio_set_all_output(sbu1_relay_pins, sizeof(sbu1_relay_pins) / sizeof(gpio_t), false); + gpio_set_all_output(sbu2_ignition_pins, sizeof(sbu2_ignition_pins) / sizeof(gpio_t), false); + gpio_set_all_output(sbu2_relay_pins, sizeof(sbu2_relay_pins) / sizeof(gpio_t), false); + harness_orientation = orientation; + break; + case HARNESS_ORIENTATION_1: + gpio_set_all_output(sbu1_ignition_pins, sizeof(sbu1_ignition_pins) / sizeof(gpio_t), false); + gpio_set_all_output(sbu1_relay_pins, sizeof(sbu1_relay_pins) / sizeof(gpio_t), true); + gpio_set_bitmask(sbu2_ignition_pins, sizeof(sbu2_ignition_pins) / sizeof(gpio_t), ignition); + gpio_set_all_output(sbu2_relay_pins, sizeof(sbu2_relay_pins) / sizeof(gpio_t), false); + harness_orientation = orientation; + break; + case HARNESS_ORIENTATION_2: + gpio_set_bitmask(sbu1_ignition_pins, sizeof(sbu1_ignition_pins) / sizeof(gpio_t), ignition); + gpio_set_all_output(sbu1_relay_pins, sizeof(sbu1_relay_pins) / sizeof(gpio_t), false); + gpio_set_all_output(sbu2_ignition_pins, sizeof(sbu2_ignition_pins) / sizeof(gpio_t), false); + gpio_set_all_output(sbu2_relay_pins, sizeof(sbu2_relay_pins) / sizeof(gpio_t), true); + harness_orientation = orientation; + break; + default: + print("Tried to set an unsupported harness orientation: "); puth(orientation); print("\n"); + break; + } +} + +void board_v2_enable_can_transceiver(uint8_t transceiver, bool enabled) { + switch (transceiver) { + case 1U: + set_gpio_output(GPIOG, 11, !enabled); + break; + case 2U: + set_gpio_output(GPIOB, 3, !enabled); + break; + case 3U: + set_gpio_output(GPIOD, 7, !enabled); + break; + case 4U: + set_gpio_output(GPIOB, 4, !enabled); + break; + default: + print("Invalid CAN transceiver ("); puth(transceiver); print("): enabling failed\n"); + break; + } +} + +void board_v2_enable_header_pin(uint8_t pin_num, bool enabled) { + if (pin_num < 8U) { + set_gpio_output(GPIOG, pin_num, enabled); + } else { + print("Invalid pin number ("); puth(pin_num); print("): enabling failed\n"); + } +} + +void board_v2_set_can_mode(uint8_t mode) { + board_v2_enable_can_transceiver(2U, false); + board_v2_enable_can_transceiver(4U, false); + switch (mode) { + case CAN_MODE_NORMAL: + // B12,B13: disable normal mode + set_gpio_pullup(GPIOB, 12, PULL_NONE); + set_gpio_mode(GPIOB, 12, MODE_ANALOG); + + set_gpio_pullup(GPIOB, 13, PULL_NONE); + set_gpio_mode(GPIOB, 13, MODE_ANALOG); + + // B5,B6: FDCAN2 mode + set_gpio_pullup(GPIOB, 5, PULL_NONE); + set_gpio_alternate(GPIOB, 5, GPIO_AF9_FDCAN2); + + set_gpio_pullup(GPIOB, 6, PULL_NONE); + set_gpio_alternate(GPIOB, 6, GPIO_AF9_FDCAN2); + can_mode = CAN_MODE_NORMAL; + board_v2_enable_can_transceiver(2U, true); + break; + case CAN_MODE_OBD_CAN2: + // B5,B6: disable normal mode + set_gpio_pullup(GPIOB, 5, PULL_NONE); + set_gpio_mode(GPIOB, 5, MODE_ANALOG); + + set_gpio_pullup(GPIOB, 6, PULL_NONE); + set_gpio_mode(GPIOB, 6, MODE_ANALOG); + // B12,B13: FDCAN2 mode + set_gpio_pullup(GPIOB, 12, PULL_NONE); + set_gpio_alternate(GPIOB, 12, GPIO_AF9_FDCAN2); + + set_gpio_pullup(GPIOB, 13, PULL_NONE); + set_gpio_alternate(GPIOB, 13, GPIO_AF9_FDCAN2); + can_mode = CAN_MODE_OBD_CAN2; + board_v2_enable_can_transceiver(4U, true); + break; + default: + break; + } +} + +bool panda_power = false; +uint8_t panda_power_bitmask = 0U; +void board_v2_set_panda_power(bool enable) { + panda_power = enable; + gpio_set_all_output(power_pins, sizeof(power_pins) / sizeof(gpio_t), enable); + if (enable) { + panda_power_bitmask = 0xFFU; + } else { + panda_power_bitmask = 0U; + } +} + +void board_v2_set_panda_individual_power(uint8_t port_num, bool enable) { + port_num -= 1U; + if (port_num < 6U) { + panda_power_bitmask &= ~(1U << port_num); + panda_power_bitmask |= (enable ? 1U : 0U) << port_num; + } else { + print("Invalid port number ("); puth(port_num); print("): enabling failed\n"); + } + gpio_set_bitmask(power_pins, sizeof(power_pins) / sizeof(gpio_t), (uint32_t)panda_power_bitmask); +} + +bool board_v2_get_button(void) { + return get_gpio_input(GPIOG, 15); +} + +void board_v2_set_ignition(bool enabled) { + ignition = enabled ? 0xFFU : 0U; + board_v2_set_harness_orientation(harness_orientation); +} + +void board_v2_set_individual_ignition(uint8_t bitmask) { + ignition = bitmask; + board_v2_set_harness_orientation(harness_orientation); +} + +float board_v2_get_channel_power(uint8_t channel) { + float ret = 0.0f; + if ((channel >= 1U) && (channel <= 6U)) { + uint16_t readout = adc_get_mV(&(const adc_signal_t) ADC_CHANNEL(ADC1, channel - 1U)); // these are mapped nicely in hardware + ret = (((float) readout / 33e6) - 0.8e-6) / 52e-6 * 12.0f; + } else { + print("Invalid channel ("); puth(channel); print(")\n"); + } + return ret; +} + +uint16_t board_v2_get_sbu_mV(uint8_t channel, uint8_t sbu) { + uint16_t ret = 0U; + if ((channel >= 1U) && (channel <= 6U)) { + switch(sbu){ + case SBU1: + ret = adc_get_mV(&sbu1_channels[channel - 1U]); + break; + case SBU2: + ret = adc_get_mV(&sbu2_channels[channel - 1U]); + break; + default: + print("Invalid SBU ("); puth(sbu); print(")\n"); + break; + } + } else { + print("Invalid channel ("); puth(channel); print(")\n"); + } + return ret; +} + +void board_v2_init(void) { + common_init_gpio(); + + // Normal CAN mode + board_v2_set_can_mode(CAN_MODE_NORMAL); + + // Enable CAN transceivers + for(uint8_t i = 1; i <= 4; i++) { + board_v2_enable_can_transceiver(i, true); + } + + // Set to no harness orientation + board_v2_set_harness_orientation(HARNESS_ORIENTATION_NONE); + + // Enable panda power by default + board_v2_set_panda_power(true); + + // Current monitor channels + adc_init(ADC1); + register_set_bits(&SYSCFG->PMCR, SYSCFG_PMCR_PA0SO | SYSCFG_PMCR_PA1SO); // open up analog switches for PA0_C and PA1_C + set_gpio_mode(GPIOF, 11, MODE_ANALOG); + set_gpio_mode(GPIOA, 6, MODE_ANALOG); + set_gpio_mode(GPIOC, 4, MODE_ANALOG); + set_gpio_mode(GPIOB, 1, MODE_ANALOG); + + // SBU channels + adc_init(ADC3); + set_gpio_mode(GPIOC, 2, MODE_ANALOG); + set_gpio_mode(GPIOC, 3, MODE_ANALOG); + set_gpio_mode(GPIOF, 9, MODE_ANALOG); + set_gpio_mode(GPIOF, 7, MODE_ANALOG); + set_gpio_mode(GPIOF, 5, MODE_ANALOG); + set_gpio_mode(GPIOF, 3, MODE_ANALOG); + set_gpio_mode(GPIOF, 10, MODE_ANALOG); + set_gpio_mode(GPIOF, 8, MODE_ANALOG); + set_gpio_mode(GPIOF, 6, MODE_ANALOG); + set_gpio_mode(GPIOF, 4, MODE_ANALOG); + set_gpio_mode(GPIOC, 0, MODE_ANALOG); + set_gpio_mode(GPIOC, 1, MODE_ANALOG); + + // Header pins + set_gpio_mode(GPIOG, 0, MODE_OUTPUT); + set_gpio_mode(GPIOG, 1, MODE_OUTPUT); + set_gpio_mode(GPIOG, 2, MODE_OUTPUT); + set_gpio_mode(GPIOG, 3, MODE_OUTPUT); + set_gpio_mode(GPIOG, 4, MODE_OUTPUT); + set_gpio_mode(GPIOG, 5, MODE_OUTPUT); + set_gpio_mode(GPIOG, 6, MODE_OUTPUT); + set_gpio_mode(GPIOG, 7, MODE_OUTPUT); +} + +void board_v2_tick(void) {} + +board board_v2 = { + .avdd_mV = 3300U, + .init = &board_v2_init, + .init_bootloader = &board_v2_tick, + .led_GPIO = {GPIOE, GPIOE, GPIOE}, + .led_pin = {4, 3, 2}, + .board_tick = &board_v2_tick, + .get_button = &board_v2_get_button, + .set_panda_power = &board_v2_set_panda_power, + .set_panda_individual_power = &board_v2_set_panda_individual_power, + .set_ignition = &board_v2_set_ignition, + .set_individual_ignition = &board_v2_set_individual_ignition, + .set_harness_orientation = &board_v2_set_harness_orientation, + .set_can_mode = &board_v2_set_can_mode, + .enable_can_transceiver = &board_v2_enable_can_transceiver, + .enable_header_pin = &board_v2_enable_header_pin, + .get_channel_power = &board_v2_get_channel_power, + .get_sbu_mV = &board_v2_get_sbu_mV, +}; diff --git a/board/jungle/boards/board_v2.h b/board/jungle/boards/board_v2.h index 45f8fb92797..5830e7cfd47 100644 --- a/board/jungle/boards/board_v2.h +++ b/board/jungle/boards/board_v2.h @@ -1,7 +1,15 @@ +#pragma once + // ///////////////////////// // // Jungle board v2 (STM32H7) // // ///////////////////////// // +#include "board/drivers/drivers.h" + +#ifndef PANDA_JUNGLE +#error This should only be used on Panda Body! +#endif + #define ADC_CHANNEL(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_810_CYCLES, .oversampling = OVERSAMPLING_1} gpio_t power_pins[] = { @@ -66,243 +74,3 @@ const adc_signal_t sbu2_channels[] = { ADC_CHANNEL(ADC3, 9), ADC_CHANNEL(ADC3, 11), }; - -void board_v2_set_harness_orientation(uint8_t orientation) { - switch (orientation) { - case HARNESS_ORIENTATION_NONE: - gpio_set_all_output(sbu1_ignition_pins, sizeof(sbu1_ignition_pins) / sizeof(gpio_t), false); - gpio_set_all_output(sbu1_relay_pins, sizeof(sbu1_relay_pins) / sizeof(gpio_t), false); - gpio_set_all_output(sbu2_ignition_pins, sizeof(sbu2_ignition_pins) / sizeof(gpio_t), false); - gpio_set_all_output(sbu2_relay_pins, sizeof(sbu2_relay_pins) / sizeof(gpio_t), false); - harness_orientation = orientation; - break; - case HARNESS_ORIENTATION_1: - gpio_set_all_output(sbu1_ignition_pins, sizeof(sbu1_ignition_pins) / sizeof(gpio_t), false); - gpio_set_all_output(sbu1_relay_pins, sizeof(sbu1_relay_pins) / sizeof(gpio_t), true); - gpio_set_bitmask(sbu2_ignition_pins, sizeof(sbu2_ignition_pins) / sizeof(gpio_t), ignition); - gpio_set_all_output(sbu2_relay_pins, sizeof(sbu2_relay_pins) / sizeof(gpio_t), false); - harness_orientation = orientation; - break; - case HARNESS_ORIENTATION_2: - gpio_set_bitmask(sbu1_ignition_pins, sizeof(sbu1_ignition_pins) / sizeof(gpio_t), ignition); - gpio_set_all_output(sbu1_relay_pins, sizeof(sbu1_relay_pins) / sizeof(gpio_t), false); - gpio_set_all_output(sbu2_ignition_pins, sizeof(sbu2_ignition_pins) / sizeof(gpio_t), false); - gpio_set_all_output(sbu2_relay_pins, sizeof(sbu2_relay_pins) / sizeof(gpio_t), true); - harness_orientation = orientation; - break; - default: - print("Tried to set an unsupported harness orientation: "); puth(orientation); print("\n"); - break; - } -} - -void board_v2_enable_can_transceiver(uint8_t transceiver, bool enabled) { - switch (transceiver) { - case 1U: - set_gpio_output(GPIOG, 11, !enabled); - break; - case 2U: - set_gpio_output(GPIOB, 3, !enabled); - break; - case 3U: - set_gpio_output(GPIOD, 7, !enabled); - break; - case 4U: - set_gpio_output(GPIOB, 4, !enabled); - break; - default: - print("Invalid CAN transceiver ("); puth(transceiver); print("): enabling failed\n"); - break; - } -} - -void board_v2_enable_header_pin(uint8_t pin_num, bool enabled) { - if (pin_num < 8U) { - set_gpio_output(GPIOG, pin_num, enabled); - } else { - print("Invalid pin number ("); puth(pin_num); print("): enabling failed\n"); - } -} - -void board_v2_set_can_mode(uint8_t mode) { - board_v2_enable_can_transceiver(2U, false); - board_v2_enable_can_transceiver(4U, false); - switch (mode) { - case CAN_MODE_NORMAL: - // B12,B13: disable normal mode - set_gpio_pullup(GPIOB, 12, PULL_NONE); - set_gpio_mode(GPIOB, 12, MODE_ANALOG); - - set_gpio_pullup(GPIOB, 13, PULL_NONE); - set_gpio_mode(GPIOB, 13, MODE_ANALOG); - - // B5,B6: FDCAN2 mode - set_gpio_pullup(GPIOB, 5, PULL_NONE); - set_gpio_alternate(GPIOB, 5, GPIO_AF9_FDCAN2); - - set_gpio_pullup(GPIOB, 6, PULL_NONE); - set_gpio_alternate(GPIOB, 6, GPIO_AF9_FDCAN2); - can_mode = CAN_MODE_NORMAL; - board_v2_enable_can_transceiver(2U, true); - break; - case CAN_MODE_OBD_CAN2: - // B5,B6: disable normal mode - set_gpio_pullup(GPIOB, 5, PULL_NONE); - set_gpio_mode(GPIOB, 5, MODE_ANALOG); - - set_gpio_pullup(GPIOB, 6, PULL_NONE); - set_gpio_mode(GPIOB, 6, MODE_ANALOG); - // B12,B13: FDCAN2 mode - set_gpio_pullup(GPIOB, 12, PULL_NONE); - set_gpio_alternate(GPIOB, 12, GPIO_AF9_FDCAN2); - - set_gpio_pullup(GPIOB, 13, PULL_NONE); - set_gpio_alternate(GPIOB, 13, GPIO_AF9_FDCAN2); - can_mode = CAN_MODE_OBD_CAN2; - board_v2_enable_can_transceiver(4U, true); - break; - default: - break; - } -} - -bool panda_power = false; -uint8_t panda_power_bitmask = 0U; -void board_v2_set_panda_power(bool enable) { - panda_power = enable; - gpio_set_all_output(power_pins, sizeof(power_pins) / sizeof(gpio_t), enable); - if (enable) { - panda_power_bitmask = 0xFFU; - } else { - panda_power_bitmask = 0U; - } -} - -void board_v2_set_panda_individual_power(uint8_t port_num, bool enable) { - port_num -= 1U; - if (port_num < 6U) { - panda_power_bitmask &= ~(1U << port_num); - panda_power_bitmask |= (enable ? 1U : 0U) << port_num; - } else { - print("Invalid port number ("); puth(port_num); print("): enabling failed\n"); - } - gpio_set_bitmask(power_pins, sizeof(power_pins) / sizeof(gpio_t), (uint32_t)panda_power_bitmask); -} - -bool board_v2_get_button(void) { - return get_gpio_input(GPIOG, 15); -} - -void board_v2_set_ignition(bool enabled) { - ignition = enabled ? 0xFFU : 0U; - board_v2_set_harness_orientation(harness_orientation); -} - -void board_v2_set_individual_ignition(uint8_t bitmask) { - ignition = bitmask; - board_v2_set_harness_orientation(harness_orientation); -} - -float board_v2_get_channel_power(uint8_t channel) { - float ret = 0.0f; - if ((channel >= 1U) && (channel <= 6U)) { - uint16_t readout = adc_get_mV(&(const adc_signal_t) ADC_CHANNEL(ADC1, channel - 1U)); // these are mapped nicely in hardware - ret = (((float) readout / 33e6) - 0.8e-6) / 52e-6 * 12.0f; - } else { - print("Invalid channel ("); puth(channel); print(")\n"); - } - return ret; -} - -uint16_t board_v2_get_sbu_mV(uint8_t channel, uint8_t sbu) { - uint16_t ret = 0U; - if ((channel >= 1U) && (channel <= 6U)) { - switch(sbu){ - case SBU1: - ret = adc_get_mV(&sbu1_channels[channel - 1U]); - break; - case SBU2: - ret = adc_get_mV(&sbu2_channels[channel - 1U]); - break; - default: - print("Invalid SBU ("); puth(sbu); print(")\n"); - break; - } - } else { - print("Invalid channel ("); puth(channel); print(")\n"); - } - return ret; -} - -void board_v2_init(void) { - common_init_gpio(); - - // Normal CAN mode - board_v2_set_can_mode(CAN_MODE_NORMAL); - - // Enable CAN transceivers - for(uint8_t i = 1; i <= 4; i++) { - board_v2_enable_can_transceiver(i, true); - } - - // Set to no harness orientation - board_v2_set_harness_orientation(HARNESS_ORIENTATION_NONE); - - // Enable panda power by default - board_v2_set_panda_power(true); - - // Current monitor channels - adc_init(ADC1); - register_set_bits(&SYSCFG->PMCR, SYSCFG_PMCR_PA0SO | SYSCFG_PMCR_PA1SO); // open up analog switches for PA0_C and PA1_C - set_gpio_mode(GPIOF, 11, MODE_ANALOG); - set_gpio_mode(GPIOA, 6, MODE_ANALOG); - set_gpio_mode(GPIOC, 4, MODE_ANALOG); - set_gpio_mode(GPIOB, 1, MODE_ANALOG); - - // SBU channels - adc_init(ADC3); - set_gpio_mode(GPIOC, 2, MODE_ANALOG); - set_gpio_mode(GPIOC, 3, MODE_ANALOG); - set_gpio_mode(GPIOF, 9, MODE_ANALOG); - set_gpio_mode(GPIOF, 7, MODE_ANALOG); - set_gpio_mode(GPIOF, 5, MODE_ANALOG); - set_gpio_mode(GPIOF, 3, MODE_ANALOG); - set_gpio_mode(GPIOF, 10, MODE_ANALOG); - set_gpio_mode(GPIOF, 8, MODE_ANALOG); - set_gpio_mode(GPIOF, 6, MODE_ANALOG); - set_gpio_mode(GPIOF, 4, MODE_ANALOG); - set_gpio_mode(GPIOC, 0, MODE_ANALOG); - set_gpio_mode(GPIOC, 1, MODE_ANALOG); - - // Header pins - set_gpio_mode(GPIOG, 0, MODE_OUTPUT); - set_gpio_mode(GPIOG, 1, MODE_OUTPUT); - set_gpio_mode(GPIOG, 2, MODE_OUTPUT); - set_gpio_mode(GPIOG, 3, MODE_OUTPUT); - set_gpio_mode(GPIOG, 4, MODE_OUTPUT); - set_gpio_mode(GPIOG, 5, MODE_OUTPUT); - set_gpio_mode(GPIOG, 6, MODE_OUTPUT); - set_gpio_mode(GPIOG, 7, MODE_OUTPUT); -} - -void board_v2_tick(void) {} - -board board_v2 = { - .avdd_mV = 3300U, - .init = &board_v2_init, - .init_bootloader = &board_v2_tick, - .led_GPIO = {GPIOE, GPIOE, GPIOE}, - .led_pin = {4, 3, 2}, - .board_tick = &board_v2_tick, - .get_button = &board_v2_get_button, - .set_panda_power = &board_v2_set_panda_power, - .set_panda_individual_power = &board_v2_set_panda_individual_power, - .set_ignition = &board_v2_set_ignition, - .set_individual_ignition = &board_v2_set_individual_ignition, - .set_harness_orientation = &board_v2_set_harness_orientation, - .set_can_mode = &board_v2_set_can_mode, - .enable_can_transceiver = &board_v2_enable_can_transceiver, - .enable_header_pin = &board_v2_enable_header_pin, - .get_channel_power = &board_v2_get_channel_power, - .get_sbu_mV = &board_v2_get_sbu_mV, -}; diff --git a/board/jungle/main.c b/board/jungle/main.c index 7bac6d751b9..254a5c89371 100644 --- a/board/jungle/main.c +++ b/board/jungle/main.c @@ -3,9 +3,7 @@ #include "opendbc/safety/safety.h" -#include "board/drivers/led.h" -#include "board/drivers/pwm.h" -#include "board/drivers/usb.h" +#include "board/drivers/drivers.h" #include "board/early_init.h" #include "board/provision.h" @@ -13,15 +11,10 @@ #include "board/health.h" #include "board/jungle/jungle_health.h" -#include "board/drivers/can_common.h" - -#include "board/drivers/fdcan.h" - #include "board/obj/gitversion.h" -#include "board/can_comms.h" #include "board/jungle/main_comms.h" - +#include "board/print.h" // ********************* Serial debugging ********************* diff --git a/board/jungle/main_comms.c b/board/jungle/main_comms.c new file mode 100644 index 00000000000..43847a28a0d --- /dev/null +++ b/board/jungle/main_comms.c @@ -0,0 +1,272 @@ +#include "board/globals.h" +#include "board/config.h" +#include "board/jungle/main_comms.h" +#include "jungle_health.h" +#include "board/health.h" +#include "board/drivers/drivers.h" +#include "board/provision.h" +#include "board/early_init.h" +#include "board/obj/gitversion.h" +#include "board/stm32h7/lldrivers.h" +#include "board/libc.h" +#include "board/print.h" + +bool generated_can_traffic = false; + +static int get_jungle_health_pkt(void *dat) { + COMPILE_TIME_ASSERT(sizeof(struct jungle_health_t) <= USBPACKET_MAX_SIZE); + struct jungle_health_t * health = (struct jungle_health_t*)dat; + + health->uptime_pkt = uptime_cnt; + health->ch1_power = current_board->get_channel_power(1U); + health->ch2_power = current_board->get_channel_power(2U); + health->ch3_power = current_board->get_channel_power(3U); + health->ch4_power = current_board->get_channel_power(4U); + health->ch5_power = current_board->get_channel_power(5U); + health->ch6_power = current_board->get_channel_power(6U); + + health->ch1_sbu1_mV = current_board->get_sbu_mV(1U, SBU1); + health->ch1_sbu2_mV = current_board->get_sbu_mV(1U, SBU2); + health->ch2_sbu1_mV = current_board->get_sbu_mV(2U, SBU1); + health->ch2_sbu2_mV = current_board->get_sbu_mV(2U, SBU2); + health->ch3_sbu1_mV = current_board->get_sbu_mV(3U, SBU1); + health->ch3_sbu2_mV = current_board->get_sbu_mV(3U, SBU2); + health->ch4_sbu1_mV = current_board->get_sbu_mV(4U, SBU1); + health->ch4_sbu2_mV = current_board->get_sbu_mV(4U, SBU2); + health->ch5_sbu1_mV = current_board->get_sbu_mV(5U, SBU1); + health->ch5_sbu2_mV = current_board->get_sbu_mV(5U, SBU2); + health->ch6_sbu1_mV = current_board->get_sbu_mV(6U, SBU1); + health->ch6_sbu2_mV = current_board->get_sbu_mV(6U, SBU2); + + return sizeof(*health); +} + +// send on serial, first byte to select the ring +void comms_endpoint2_write(const uint8_t *data, uint32_t len) { + UNUSED(data); + UNUSED(len); +} + +int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { + unsigned int resp_len = 0; + uint32_t time; + +#ifdef DEBUG_COMMS + print("raw control request: "); hexdump(req, sizeof(ControlPacket_t)); print("\n"); + print("- request "); puth(req->request); print("\n"); + print("- param1 "); puth(req->param1); print("\n"); + print("- param2 "); puth(req->param2); print("\n"); +#endif + + switch (req->request) { + // **** 0xa0: Set panda power. + case 0xa0: + current_board->set_panda_power((req->param1 == 1U)); + break; + // **** 0xa1: Set harness orientation. + case 0xa1: + current_board->set_harness_orientation(req->param1); + break; + // **** 0xa2: Set ignition. + case 0xa2: + current_board->set_ignition((req->param1 == 1U)); + break; + // **** 0xa3: Set panda power per channel by bitmask. + case 0xa3: + current_board->set_panda_individual_power(req->param1, (req->param2 > 0U)); + break; + // **** 0xa4: Enable generated CAN traffic. + case 0xa4: + generated_can_traffic = (req->param1 > 0U); + break; + // **** 0xa8: get microsecond timer + case 0xa8: + time = microsecond_timer_get(); + resp[0] = (time & 0x000000FFU); + resp[1] = ((time & 0x0000FF00U) >> 8U); + resp[2] = ((time & 0x00FF0000U) >> 16U); + resp[3] = ((time & 0xFF000000U) >> 24U); + resp_len = 4U; + break; + // **** 0xc0: reset communications + case 0xc0: + comms_can_reset(); + break; + // **** 0xc1: get hardware type + case 0xc1: + resp[0] = hw_type; + resp_len = 1; + break; + // **** 0xc2: CAN health stats + case 0xc2: + COMPILE_TIME_ASSERT(sizeof(can_health_t) <= USBPACKET_MAX_SIZE); + if (req->param1 < 3U) { + update_can_health_pkt(req->param1, 0U); + can_health[req->param1].can_speed = (bus_config[req->param1].can_speed / 10U); + can_health[req->param1].can_data_speed = (bus_config[req->param1].can_data_speed / 10U); + can_health[req->param1].canfd_enabled = bus_config[req->param1].canfd_enabled; + can_health[req->param1].brs_enabled = bus_config[req->param1].brs_enabled; + can_health[req->param1].canfd_non_iso = bus_config[req->param1].canfd_non_iso; + resp_len = sizeof(can_health[req->param1]); + (void)memcpy(resp, &can_health[req->param1], resp_len); + } + break; + // **** 0xc3: fetch MCU UID + case 0xc3: + (void)memcpy(resp, ((uint8_t *)UID_BASE), 12); + resp_len = 12; + break; + // **** 0xd0: fetch serial (aka the provisioned dongle ID) + case 0xd0: + // addresses are OTP + if (req->param1 == 1U) { + (void)memcpy(resp, (uint8_t *)DEVICE_SERIAL_NUMBER_ADDRESS, 0x10); + resp_len = 0x10; + } else { + get_provision_chunk(resp); + resp_len = PROVISION_CHUNK_LEN; + } + break; + // **** 0xd1: enter bootloader mode + case 0xd1: + // this allows reflashing of the bootstub + switch (req->param1) { + case 0: + // only allow bootloader entry on debug builds + #ifdef ALLOW_DEBUG + print("-> entering bootloader\n"); + enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; + NVIC_SystemReset(); + #endif + break; + case 1: + print("-> entering softloader\n"); + enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; + NVIC_SystemReset(); + break; + default: + print("Bootloader mode invalid\n"); + break; + } + break; + // **** 0xd2: get health packet + case 0xd2: + resp_len = get_jungle_health_pkt(resp); + break; + // **** 0xd3: get first 64 bytes of signature + case 0xd3: + { + resp_len = 64; + char * code = (char*)_app_start; + int code_len = _app_start[0]; + (void)memcpy(resp, &code[code_len], resp_len); + } + break; + // **** 0xd4: get second 64 bytes of signature + case 0xd4: + { + resp_len = 64; + char * code = (char*)_app_start; + int code_len = _app_start[0]; + (void)memcpy(resp, &code[code_len + 64], resp_len); + } + break; + // **** 0xd6: get version + case 0xd6: + COMPILE_TIME_ASSERT(sizeof(gitversion) <= USBPACKET_MAX_SIZE); + (void)memcpy(resp, gitversion, sizeof(gitversion)); + resp_len = sizeof(gitversion) - 1U; + break; + // **** 0xd8: reset ST + case 0xd8: + NVIC_SystemReset(); + break; + // **** 0xdb: set OBD CAN multiplexing mode + case 0xdb: + if (req->param1 == 1U) { + // Enable OBD CAN + current_board->set_can_mode(CAN_MODE_OBD_CAN2); + } else { + // Disable OBD CAN + current_board->set_can_mode(CAN_MODE_NORMAL); + } + break; + // **** 0xdd: get healthpacket and CANPacket versions + case 0xdd: + resp[0] = JUNGLE_HEALTH_PACKET_VERSION; + resp[1] = CAN_PACKET_VERSION; + resp[2] = CAN_HEALTH_PACKET_VERSION; + resp_len = 3; + break; + // **** 0xde: set can bitrate + case 0xde: + if ((req->param1 < PANDA_CAN_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) { + bus_config[req->param1].can_speed = req->param2; + bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); + UNUSED(ret); + } + break; + // **** 0xe0: debug read + case 0xe0: + // read + while ((resp_len < MIN(req->length, USBPACKET_MAX_SIZE)) && get_char(get_ring_by_number(0), (char*)&resp[resp_len])) { + ++resp_len; + } + break; + // **** 0xe5: set CAN loopback (for testing) + case 0xe5: + can_loopback = (req->param1 > 0U); + can_init_all(); + break; + // **** 0xf1: Clear CAN ring buffer. + case 0xf1: + if (req->param1 == 0xFFFFU) { + print("Clearing CAN Rx queue\n"); + can_clear(&can_rx_q); + } else if (req->param1 < PANDA_CAN_CNT) { + print("Clearing CAN Tx queue\n"); + can_clear(can_queues[req->param1]); + } else { + print("Clearing CAN CAN ring buffer failed: wrong bus number\n"); + } + break; + // **** 0xf4: Set CAN transceiver enable pin + case 0xf4: + current_board->enable_can_transceiver(req->param1, req->param2 > 0U); + break; + // **** 0xf5: Set CAN silent mode + case 0xf5: + can_silent = (req->param1 > 0U); + can_init_all(); + break; + // **** 0xf7: enable/disable header pin by number + case 0xf7: + current_board->enable_header_pin(req->param1, req->param2 > 0U); + break; + // **** 0xf9: set CAN FD data bitrate + case 0xf9: + if ((req->param1 < PANDA_CAN_CNT) && + is_speed_valid(req->param2, data_speeds, sizeof(data_speeds)/sizeof(data_speeds[0]))) { + bus_config[req->param1].can_data_speed = req->param2; + bus_config[req->param1].canfd_enabled = (req->param2 >= bus_config[req->param1].can_speed); + bus_config[req->param1].brs_enabled = (req->param2 > bus_config[req->param1].can_speed); + bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); + UNUSED(ret); + } + break; + // **** 0xfc: set CAN FD non-ISO mode + case 0xfc: + if (req->param1 < PANDA_CAN_CNT) { + bus_config[req->param1].canfd_non_iso = (req->param2 != 0U); + bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); + UNUSED(ret); + } + break; + default: + print("NO HANDLER "); + puth(req->request); + print("\n"); + break; + } + return resp_len; +} diff --git a/board/jungle/main_comms.h b/board/jungle/main_comms.h index b19f799ad9e..62e2871bf6d 100644 --- a/board/jungle/main_comms.h +++ b/board/jungle/main_comms.h @@ -1,261 +1,6 @@ -extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used +#include "board/config.h" -bool generated_can_traffic = false; +#include "board/globals.h" -int get_jungle_health_pkt(void *dat) { - COMPILE_TIME_ASSERT(sizeof(struct jungle_health_t) <= USBPACKET_MAX_SIZE); - struct jungle_health_t * health = (struct jungle_health_t*)dat; - - health->uptime_pkt = uptime_cnt; - health->ch1_power = current_board->get_channel_power(1U); - health->ch2_power = current_board->get_channel_power(2U); - health->ch3_power = current_board->get_channel_power(3U); - health->ch4_power = current_board->get_channel_power(4U); - health->ch5_power = current_board->get_channel_power(5U); - health->ch6_power = current_board->get_channel_power(6U); - - health->ch1_sbu1_mV = current_board->get_sbu_mV(1U, SBU1); - health->ch1_sbu2_mV = current_board->get_sbu_mV(1U, SBU2); - health->ch2_sbu1_mV = current_board->get_sbu_mV(2U, SBU1); - health->ch2_sbu2_mV = current_board->get_sbu_mV(2U, SBU2); - health->ch3_sbu1_mV = current_board->get_sbu_mV(3U, SBU1); - health->ch3_sbu2_mV = current_board->get_sbu_mV(3U, SBU2); - health->ch4_sbu1_mV = current_board->get_sbu_mV(4U, SBU1); - health->ch4_sbu2_mV = current_board->get_sbu_mV(4U, SBU2); - health->ch5_sbu1_mV = current_board->get_sbu_mV(5U, SBU1); - health->ch5_sbu2_mV = current_board->get_sbu_mV(5U, SBU2); - health->ch6_sbu1_mV = current_board->get_sbu_mV(6U, SBU1); - health->ch6_sbu2_mV = current_board->get_sbu_mV(6U, SBU2); - - return sizeof(*health); -} - -// send on serial, first byte to select the ring -void comms_endpoint2_write(const uint8_t *data, uint32_t len) { - UNUSED(data); - UNUSED(len); -} - -int comms_control_handler(ControlPacket_t *req, uint8_t *resp) { - unsigned int resp_len = 0; - uint32_t time; - -#ifdef DEBUG_COMMS - print("raw control request: "); hexdump(req, sizeof(ControlPacket_t)); print("\n"); - print("- request "); puth(req->request); print("\n"); - print("- param1 "); puth(req->param1); print("\n"); - print("- param2 "); puth(req->param2); print("\n"); -#endif - - switch (req->request) { - // **** 0xa0: Set panda power. - case 0xa0: - current_board->set_panda_power((req->param1 == 1U)); - break; - // **** 0xa1: Set harness orientation. - case 0xa1: - current_board->set_harness_orientation(req->param1); - break; - // **** 0xa2: Set ignition. - case 0xa2: - current_board->set_ignition((req->param1 == 1U)); - break; - // **** 0xa3: Set panda power per channel by bitmask. - case 0xa3: - current_board->set_panda_individual_power(req->param1, (req->param2 > 0U)); - break; - // **** 0xa4: Enable generated CAN traffic. - case 0xa4: - generated_can_traffic = (req->param1 > 0U); - break; - // **** 0xa8: get microsecond timer - case 0xa8: - time = microsecond_timer_get(); - resp[0] = (time & 0x000000FFU); - resp[1] = ((time & 0x0000FF00U) >> 8U); - resp[2] = ((time & 0x00FF0000U) >> 16U); - resp[3] = ((time & 0xFF000000U) >> 24U); - resp_len = 4U; - break; - // **** 0xc0: reset communications - case 0xc0: - comms_can_reset(); - break; - // **** 0xc1: get hardware type - case 0xc1: - resp[0] = hw_type; - resp_len = 1; - break; - // **** 0xc2: CAN health stats - case 0xc2: - COMPILE_TIME_ASSERT(sizeof(can_health_t) <= USBPACKET_MAX_SIZE); - if (req->param1 < 3U) { - update_can_health_pkt(req->param1, 0U); - can_health[req->param1].can_speed = (bus_config[req->param1].can_speed / 10U); - can_health[req->param1].can_data_speed = (bus_config[req->param1].can_data_speed / 10U); - can_health[req->param1].canfd_enabled = bus_config[req->param1].canfd_enabled; - can_health[req->param1].brs_enabled = bus_config[req->param1].brs_enabled; - can_health[req->param1].canfd_non_iso = bus_config[req->param1].canfd_non_iso; - resp_len = sizeof(can_health[req->param1]); - (void)memcpy(resp, &can_health[req->param1], resp_len); - } - break; - // **** 0xc3: fetch MCU UID - case 0xc3: - (void)memcpy(resp, ((uint8_t *)UID_BASE), 12); - resp_len = 12; - break; - // **** 0xd0: fetch serial (aka the provisioned dongle ID) - case 0xd0: - // addresses are OTP - if (req->param1 == 1U) { - (void)memcpy(resp, (uint8_t *)DEVICE_SERIAL_NUMBER_ADDRESS, 0x10); - resp_len = 0x10; - } else { - get_provision_chunk(resp); - resp_len = PROVISION_CHUNK_LEN; - } - break; - // **** 0xd1: enter bootloader mode - case 0xd1: - // this allows reflashing of the bootstub - switch (req->param1) { - case 0: - // only allow bootloader entry on debug builds - #ifdef ALLOW_DEBUG - print("-> entering bootloader\n"); - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - #endif - break; - case 1: - print("-> entering softloader\n"); - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - NVIC_SystemReset(); - break; - default: - print("Bootloader mode invalid\n"); - break; - } - break; - // **** 0xd2: get health packet - case 0xd2: - resp_len = get_jungle_health_pkt(resp); - break; - // **** 0xd3: get first 64 bytes of signature - case 0xd3: - { - resp_len = 64; - char * code = (char*)_app_start; - int code_len = _app_start[0]; - (void)memcpy(resp, &code[code_len], resp_len); - } - break; - // **** 0xd4: get second 64 bytes of signature - case 0xd4: - { - resp_len = 64; - char * code = (char*)_app_start; - int code_len = _app_start[0]; - (void)memcpy(resp, &code[code_len + 64], resp_len); - } - break; - // **** 0xd6: get version - case 0xd6: - COMPILE_TIME_ASSERT(sizeof(gitversion) <= USBPACKET_MAX_SIZE); - (void)memcpy(resp, gitversion, sizeof(gitversion)); - resp_len = sizeof(gitversion) - 1U; - break; - // **** 0xd8: reset ST - case 0xd8: - NVIC_SystemReset(); - break; - // **** 0xdb: set OBD CAN multiplexing mode - case 0xdb: - if (req->param1 == 1U) { - // Enable OBD CAN - current_board->set_can_mode(CAN_MODE_OBD_CAN2); - } else { - // Disable OBD CAN - current_board->set_can_mode(CAN_MODE_NORMAL); - } - break; - // **** 0xdd: get healthpacket and CANPacket versions - case 0xdd: - resp[0] = JUNGLE_HEALTH_PACKET_VERSION; - resp[1] = CAN_PACKET_VERSION; - resp[2] = CAN_HEALTH_PACKET_VERSION; - resp_len = 3; - break; - // **** 0xde: set can bitrate - case 0xde: - if ((req->param1 < PANDA_CAN_CNT) && is_speed_valid(req->param2, speeds, sizeof(speeds)/sizeof(speeds[0]))) { - bus_config[req->param1].can_speed = req->param2; - bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); - UNUSED(ret); - } - break; - // **** 0xe0: debug read - case 0xe0: - // read - while ((resp_len < MIN(req->length, USBPACKET_MAX_SIZE)) && get_char(get_ring_by_number(0), (char*)&resp[resp_len])) { - ++resp_len; - } - break; - // **** 0xe5: set CAN loopback (for testing) - case 0xe5: - can_loopback = (req->param1 > 0U); - can_init_all(); - break; - // **** 0xf1: Clear CAN ring buffer. - case 0xf1: - if (req->param1 == 0xFFFFU) { - print("Clearing CAN Rx queue\n"); - can_clear(&can_rx_q); - } else if (req->param1 < PANDA_CAN_CNT) { - print("Clearing CAN Tx queue\n"); - can_clear(can_queues[req->param1]); - } else { - print("Clearing CAN CAN ring buffer failed: wrong bus number\n"); - } - break; - // **** 0xf4: Set CAN transceiver enable pin - case 0xf4: - current_board->enable_can_transceiver(req->param1, req->param2 > 0U); - break; - // **** 0xf5: Set CAN silent mode - case 0xf5: - can_silent = (req->param1 > 0U); - can_init_all(); - break; - // **** 0xf7: enable/disable header pin by number - case 0xf7: - current_board->enable_header_pin(req->param1, req->param2 > 0U); - break; - // **** 0xf9: set CAN FD data bitrate - case 0xf9: - if ((req->param1 < PANDA_CAN_CNT) && - is_speed_valid(req->param2, data_speeds, sizeof(data_speeds)/sizeof(data_speeds[0]))) { - bus_config[req->param1].can_data_speed = req->param2; - bus_config[req->param1].canfd_enabled = (req->param2 >= bus_config[req->param1].can_speed); - bus_config[req->param1].brs_enabled = (req->param2 > bus_config[req->param1].can_speed); - bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); - UNUSED(ret); - } - break; - // **** 0xfc: set CAN FD non-ISO mode - case 0xfc: - if (req->param1 < PANDA_CAN_CNT) { - bus_config[req->param1].canfd_non_iso = (req->param2 != 0U); - bool ret = can_init(CAN_NUM_FROM_BUS_NUM(req->param1)); - UNUSED(ret); - } - break; - default: - print("NO HANDLER "); - puth(req->request); - print("\n"); - break; - } - return resp_len; -} +extern bool generated_can_traffic; +extern bool panda_power; \ No newline at end of file diff --git a/board/jungle/stm32h7/board.c b/board/jungle/stm32h7/board.c new file mode 100644 index 00000000000..deeef0f010d --- /dev/null +++ b/board/jungle/stm32h7/board.c @@ -0,0 +1,13 @@ +#include "board.h" + +#ifndef PANDA_JUNGLE +#error This should only be used on Panda Jungle +#endif + +#include "board/globals.h" +#include "board/config.h" + +void detect_board_type(void) { + hw_type = HW_TYPE_V2; + current_board = &board_v2; +} diff --git a/board/jungle/stm32h7/board.h b/board/jungle/stm32h7/board.h index 760a70416ac..6061864e62e 100644 --- a/board/jungle/stm32h7/board.h +++ b/board/jungle/stm32h7/board.h @@ -1,9 +1,7 @@ #include "board/jungle/boards/board_declarations.h" -#include "board/stm32h7/lladc.h" -#include "board/jungle/boards/board_v2.h" +#include "board/stm32h7/lldrivers.h" -void detect_board_type(void) { - hw_type = HW_TYPE_V2; - current_board = &board_v2; -} +extern struct board board_v2; + +void detect_board_type(void); \ No newline at end of file diff --git a/board/libc.c b/board/libc.c new file mode 100644 index 00000000000..c8efae545cc --- /dev/null +++ b/board/libc.c @@ -0,0 +1,82 @@ +#include "libc.h" +#include "print.h" + +void delay(uint32_t a) { + // loop is 2.6x faster when 32-byte aligned (ART accelerator prefetches flash in 32-byte chunks) + volatile uint32_t i; + uint32_t n = a * 13U / 5U; + for (i = 0; i < n; i++) {} +} + +void assert_fatal(bool condition, const char *msg) { + if (!condition) { + print("ASSERT FAILED\n"); + print(msg); + while (1) { + // hang + } + } +} + +// cppcheck-suppress misra-c2012-8.7 +// cppcheck-suppress misra-c2012-21.2 +// cppcheck-suppress unusedFunction; Used in board/flasher.c, which is excluded from cppcheck +void *memset(void *str, int c, unsigned int n) { + uint8_t *s = str; + for (unsigned int i = 0; i < n; i++) { + *s = c; + s++; + } + return str; +} + +#define UNALIGNED(X, Y) \ + (((uint32_t)(X) & (sizeof(uint32_t) - 1U)) | ((uint32_t)(Y) & (sizeof(uint32_t) - 1U))) + +// cppcheck-suppress misra-c2012-21.2 +void *memcpy(void *dest, const void *src, unsigned int len) { + unsigned int n = len; + uint8_t *d8 = dest; + const uint8_t *s8 = src; + + if ((n >= 4U) && !UNALIGNED(s8, d8)) { + uint32_t *d32 = (uint32_t *)d8; // cppcheck-suppress misra-c2012-11.3 ; already checked that it's properly aligned + const uint32_t *s32 = (const uint32_t *)s8; // cppcheck-suppress misra-c2012-11.3 ; already checked that it's properly aligned + + while(n >= 16U) { + *d32 = *s32; d32++; s32++; + *d32 = *s32; d32++; s32++; + *d32 = *s32; d32++; s32++; + *d32 = *s32; d32++; s32++; + n -= 16U; + } + + while(n >= 4U) { + *d32 = *s32; d32++; s32++; + n -= 4U; + } + + d8 = (uint8_t *)d32; + s8 = (const uint8_t *)s32; + } + while (n-- > 0U) { + *d8 = *s8; d8++; s8++; + } + return dest; +} + +// cppcheck-suppress misra-c2012-21.2 +int memcmp(const void * ptr1, const void * ptr2, unsigned int num) { + int ret = 0; + const uint8_t *p1 = ptr1; + const uint8_t *p2 = ptr2; + for (unsigned int i = 0; i < num; i++) { + if (*p1 != *p2) { + ret = -1; + break; + } + p1++; + p2++; + } + return ret; +} diff --git a/board/libc.h b/board/libc.h index c5ea629fcef..a18d693d560 100644 --- a/board/libc.h +++ b/board/libc.h @@ -1,79 +1,18 @@ -// **** libc **** - -__attribute__((aligned(32), noinline)) void delay(uint32_t a) { - // loop is 2.6x faster when 32-byte aligned (ART accelerator prefetches flash in 32-byte chunks) - volatile uint32_t i; - uint32_t n = a * 13U / 5U; - for (i = 0; i < n; i++) {} -} +#pragma once -void assert_fatal(bool condition, const char *msg) { - if (!condition) { - print("ASSERT FAILED\n"); - print(msg); - while (1) { - // hang - } - } -} +#include +#include -// cppcheck-suppress misra-c2012-21.2 -void *memset(void *str, int c, unsigned int n) { - uint8_t *s = str; - for (unsigned int i = 0; i < n; i++) { - *s = c; - s++; - } - return str; -} +// **** libc **** #define UNALIGNED(X, Y) \ (((uint32_t)(X) & (sizeof(uint32_t) - 1U)) | ((uint32_t)(Y) & (sizeof(uint32_t) - 1U))) +__attribute__((aligned(32), noinline)) void delay(uint32_t a); +void assert_fatal(bool condition, const char *msg); // cppcheck-suppress misra-c2012-21.2 -void *memcpy(void *dest, const void *src, unsigned int len) { - unsigned int n = len; - uint8_t *d8 = dest; - const uint8_t *s8 = src; - - if ((n >= 4U) && !UNALIGNED(s8, d8)) { - uint32_t *d32 = (uint32_t *)d8; // cppcheck-suppress misra-c2012-11.3 ; already checked that it's properly aligned - const uint32_t *s32 = (const uint32_t *)s8; // cppcheck-suppress misra-c2012-11.3 ; already checked that it's properly aligned - - while(n >= 16U) { - *d32 = *s32; d32++; s32++; - *d32 = *s32; d32++; s32++; - *d32 = *s32; d32++; s32++; - *d32 = *s32; d32++; s32++; - n -= 16U; - } - - while(n >= 4U) { - *d32 = *s32; d32++; s32++; - n -= 4U; - } - - d8 = (uint8_t *)d32; - s8 = (const uint8_t *)s32; - } - while (n-- > 0U) { - *d8 = *s8; d8++; s8++; - } - return dest; -} - +void *memset(void *str, int c, unsigned int n); +// cppcheck-suppress misra-c2012-21.2 +void *memcpy(void *dest, const void *src, unsigned int len); // cppcheck-suppress misra-c2012-21.2 -int memcmp(const void * ptr1, const void * ptr2, unsigned int num) { - int ret = 0; - const uint8_t *p1 = ptr1; - const uint8_t *p2 = ptr2; - for (unsigned int i = 0; i < num; i++) { - if (*p1 != *p2) { - ret = -1; - break; - } - p1++; - p2++; - } - return ret; -} +int memcmp(const void * ptr1, const void * ptr2, unsigned int num); \ No newline at end of file diff --git a/board/main.c b/board/main.c index ac0fda9ba43..fcc45400488 100644 --- a/board/main.c +++ b/board/main.c @@ -1,30 +1,17 @@ // ********************* Includes ********************* #include "board/config.h" -#include "board/drivers/led.h" -#include "board/drivers/pwm.h" -#include "board/drivers/usb.h" -#include "board/drivers/simple_watchdog.h" -#include "board/drivers/bootkick.h" +#include "board/drivers/drivers.h" #include "board/early_init.h" -#include "board/provision.h" -#include "opendbc/safety/safety.h" - -#include "board/health.h" - -#include "board/drivers/can_common.h" - -#include "board/drivers/fdcan.h" +#include "board/libc.h" -#include "board/power_saving.h" - -#include "board/obj/gitversion.h" - -#include "board/can_comms.h" -#include "board/main_comms.h" +#include "board/globals.h" +#include "opendbc/safety/safety.h" +#include "board/print.h" +#include "board/comms.h" // ********************* Serial debugging ********************* @@ -99,6 +86,7 @@ bool is_car_safety_mode(uint16_t mode) { // cppcheck-suppress unusedFunction ; used in headers not included in cppcheck // cppcheck-suppress misra-c2012-8.4 +// cppcheck-suppress misra-c2012-8.7 void __initialize_hardware_early(void) { early_initialization(); } diff --git a/board/main_comms.h b/board/main_comms.c similarity index 97% rename from board/main_comms.h rename to board/main_comms.c index ce61f625dd8..68dba5e5ca3 100644 --- a/board/main_comms.h +++ b/board/main_comms.c @@ -1,8 +1,14 @@ -extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used +#include +#include + +#include "board/drivers/drivers.h" +#include "board/provision.h" +#include "board/early_init.h" +#include "board/obj/gitversion.h" +#include "board/globals.h" +#include "board/comms.h" +#include "board/print.h" -// Prototypes -void set_safety_mode(uint16_t mode, uint16_t param); -bool is_car_safety_mode(uint16_t mode); static int get_health_pkt(void *dat) { COMPILE_TIME_ASSERT(sizeof(struct health_t) <= USBPACKET_MAX_SIZE); diff --git a/board/main_declarations.h b/board/main_declarations.h deleted file mode 100644 index 52aaa6c10d9..00000000000 --- a/board/main_declarations.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once - -// ******************** Prototypes ******************** -void print(const char *a); -void puth(unsigned int i); -typedef struct board board; -typedef struct harness_configuration harness_configuration; -void pwm_init(TIM_TypeDef *TIM, uint8_t channel); -void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage); - -// ********************* Globals ********************** -extern uint8_t hw_type; -extern board *current_board; -extern uint32_t uptime_cnt; - -// heartbeat state -extern uint32_t heartbeat_counter; -extern bool heartbeat_lost; -extern bool heartbeat_disabled; - -// siren state -extern bool siren_enabled; diff --git a/board/main_definitions.h b/board/main_definitions.c similarity index 54% rename from board/main_definitions.h rename to board/main_definitions.c index 83c91090579..7507bd02a70 100644 --- a/board/main_definitions.h +++ b/board/main_definitions.c @@ -1,9 +1,7 @@ -#include "main_declarations.h" +#include +#include -// ********************* Globals ********************** -uint8_t hw_type = 0; -board *current_board; -uint32_t uptime_cnt = 0; +#include "globals.h" // heartbeat state uint32_t heartbeat_counter = 0; diff --git a/board/power_saving_declarations.h b/board/power_saving_declarations.h deleted file mode 100644 index 7a474a55949..00000000000 --- a/board/power_saving_declarations.h +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -// WARNING: To stay in compliance with the SIL2 rules laid out in STM UM1840, we should never implement any of the available hardware low power modes. -// See rule: CoU_3 - -#define POWER_SAVE_STATUS_DISABLED 0 -#define POWER_SAVE_STATUS_ENABLED 1 - -extern int power_save_status; - -void set_power_save_state(int state); diff --git a/board/print.h b/board/print.h new file mode 100644 index 00000000000..d6e6cb515a1 --- /dev/null +++ b/board/print.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +// ************************ High-level debug functions ********************** +void putch(const char a); +void print(const char *a); +void puthx(uint32_t i, uint8_t len); +void puth(unsigned int i); +#if defined(DEBUG_SPI) || defined(BOOTSTUB) || defined(DEBUG) +void puth4(unsigned int i); +#endif +#if defined(DEBUG_SPI) || defined(DEBUG_USB) || defined(DEBUG_COMMS) +void hexdump(const void *a, int l); +#endif \ No newline at end of file diff --git a/board/provision.c b/board/provision.c new file mode 100644 index 00000000000..fbe14b49999 --- /dev/null +++ b/board/provision.c @@ -0,0 +1,14 @@ +// this is where we manage the dongle ID assigned during our +// manufacturing. aside from this, there's a UID for the MCU + +#include "provision.h" +#include "config.h" + +void get_provision_chunk(uint8_t *resp) { + const unsigned char unprovisioned_text[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; + + (void)memcpy(resp, (uint8_t *)PROVISION_CHUNK_ADDRESS, PROVISION_CHUNK_LEN); + if (memcmp(resp, unprovisioned_text, 0x20) == 0) { + (void)memcpy(resp, "unprovisioned\x00\x00\x00testing123\x00\x00\xa3\xa6\x99\xec", 0x20); + } +} diff --git a/board/provision.h b/board/provision.h index d191e53f677..5c217a3de59 100644 --- a/board/provision.h +++ b/board/provision.h @@ -1,13 +1,8 @@ // this is where we manage the dongle ID assigned during our // manufacturing. aside from this, there's a UID for the MCU -#define PROVISION_CHUNK_LEN 0x20 +#include -void get_provision_chunk(uint8_t *resp) { - const unsigned char unprovisioned_text[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"; +#define PROVISION_CHUNK_LEN 0x20 - (void)memcpy(resp, (uint8_t *)PROVISION_CHUNK_ADDRESS, PROVISION_CHUNK_LEN); - if (memcmp(resp, unprovisioned_text, 0x20) == 0) { - (void)memcpy(resp, "unprovisioned\x00\x00\x00testing123\x00\x00\xa3\xa6\x99\xec", 0x20); - } -} +void get_provision_chunk(uint8_t *resp); \ No newline at end of file diff --git a/board/stm32h7/board.c b/board/stm32h7/board.c new file mode 100644 index 00000000000..e0a38a4156a --- /dev/null +++ b/board/stm32h7/board.c @@ -0,0 +1,37 @@ +#include + +#include "board/stm32h7/board.h" +#include "board/globals.h" +#include "board/boards/boards.h" +#include "board/print.h" + +void detect_board_type(void) { + // On STM32H7 pandas, we use two different sets of pins. + const uint8_t id1 = detect_with_pull(GPIOF, 7, PULL_UP) | + (detect_with_pull(GPIOF, 8, PULL_UP) << 1U) | + (detect_with_pull(GPIOF, 9, PULL_UP) << 2U) | + (detect_with_pull(GPIOF, 10, PULL_UP) << 3U); + + const uint8_t id2 = detect_with_pull(GPIOD, 4, PULL_UP) | + (detect_with_pull(GPIOD, 5, PULL_UP) << 1U) | + (detect_with_pull(GPIOD, 6, PULL_UP) << 2U) | + (detect_with_pull(GPIOD, 7, PULL_UP) << 3U); + + if (id2 == 3U) { + hw_type = HW_TYPE_CUATRO; + current_board = &board_cuatro; + } else if (id1 == 0U) { + hw_type = HW_TYPE_RED_PANDA; + current_board = &board_red; + } else if (id1 == 1U) { + // deprecated + //hw_type = HW_TYPE_RED_PANDA_V2; + hw_type = HW_TYPE_UNKNOWN; + } else if (id1 == 2U) { + hw_type = HW_TYPE_TRES; + current_board = &board_tres; + } else { + hw_type = HW_TYPE_UNKNOWN; + print("Hardware type is UNKNOWN!\n"); + } +} diff --git a/board/stm32h7/board.h b/board/stm32h7/board.h index 05c5c5e7155..129b8b893db 100644 --- a/board/stm32h7/board.h +++ b/board/stm32h7/board.h @@ -1,49 +1,8 @@ // ///////////////////////////////////////////////////////////// // // Hardware abstraction layer for all different supported boards // // ///////////////////////////////////////////////////////////// // -#include "board/boards/board_declarations.h" -#include "board/boards/unused_funcs.h" +// #include "board/boards/board_declarations.h" +#include "board/boards/boards.h" // ///// Board definition and detection ///// // -#include "board/stm32h7/lladc.h" -#include "board/drivers/harness.h" -#include "board/drivers/fan.h" -#include "board/stm32h7/llfan.h" -#include "board/stm32h7/sound.h" -#include "board/drivers/fake_siren.h" -#include "board/drivers/clock_source.h" -#include "board/boards/red.h" -#include "board/boards/tres.h" -#include "board/boards/cuatro.h" - - -void detect_board_type(void) { - // On STM32H7 pandas, we use two different sets of pins. - const uint8_t id1 = detect_with_pull(GPIOF, 7, PULL_UP) | - (detect_with_pull(GPIOF, 8, PULL_UP) << 1U) | - (detect_with_pull(GPIOF, 9, PULL_UP) << 2U) | - (detect_with_pull(GPIOF, 10, PULL_UP) << 3U); - - const uint8_t id2 = detect_with_pull(GPIOD, 4, PULL_UP) | - (detect_with_pull(GPIOD, 5, PULL_UP) << 1U) | - (detect_with_pull(GPIOD, 6, PULL_UP) << 2U) | - (detect_with_pull(GPIOD, 7, PULL_UP) << 3U); - - if (id2 == 3U) { - hw_type = HW_TYPE_CUATRO; - current_board = &board_cuatro; - } else if (id1 == 0U) { - hw_type = HW_TYPE_RED_PANDA; - current_board = &board_red; - } else if (id1 == 1U) { - // deprecated - //hw_type = HW_TYPE_RED_PANDA_V2; - hw_type = HW_TYPE_UNKNOWN; - } else if (id1 == 2U) { - hw_type = HW_TYPE_TRES; - current_board = &board_tres; - } else { - hw_type = HW_TYPE_UNKNOWN; - print("Hardware type is UNKNOWN!\n"); - } -} +#include "board/stm32h7/lldrivers.h" \ No newline at end of file diff --git a/board/stm32h7/clock.h b/board/stm32h7/clock.c similarity index 91% rename from board/stm32h7/clock.h rename to board/stm32h7/clock.c index 40ad06043e5..4e54ff40967 100644 --- a/board/stm32h7/clock.h +++ b/board/stm32h7/clock.c @@ -1,3 +1,6 @@ +#include "lldrivers.h" +#include "board/drivers/drivers.h" + /* HSE: 25MHz PLL1Q: 80MHz (for FDCAN) @@ -17,12 +20,6 @@ APB4 per: 60MHz PCLK1: 60MHz (for USART2,3,4,5,7,8) */ -typedef enum { - PACKAGE_UNKNOWN = 0, - PACKAGE_WITH_SMPS = 1, - PACKAGE_WITHOUT_SMPS = 2, -} PackageSMPSType; - // TODO: find a better way to distinguish between H725 (using SMPS) and H723 (lacking SMPS) // The package will do for now, since we have only used TFBGA100 for H723 static PackageSMPSType get_package_smps_type(void) { @@ -41,6 +38,7 @@ static PackageSMPSType get_package_smps_type(void) { break; default: ret = PACKAGE_UNKNOWN; + break; } return ret; } @@ -63,22 +61,22 @@ void clock_init(void) { } else if (package_smps == PACKAGE_WITH_SMPS) { register_set(&(PWR->CR3), PWR_CR3_SMPSEN, 0xFU); // powered only by SMPS } else { - while(true); // unknown package, let's hang here + while(true) {} // unknown package, let's hang here } // Set VOS level (VOS3 to 170Mhz, VOS2 to 300Mhz, VOS1 to 400Mhz, VOS0 to 550Mhz) register_set(&(PWR->D3CR), PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0, 0xC000U); //VOS1, needed for 80Mhz CAN FD - while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U); - while ((PWR->CSR1 & PWR_CSR1_ACTVOS) != (PWR->D3CR & PWR_D3CR_VOS)); // check that VOS level was actually set + while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U) {} + while ((PWR->CSR1 & PWR_CSR1_ACTVOS) != (PWR->D3CR & PWR_D3CR_VOS)) {} // check that VOS level was actually set // Configure Flash ACR register LATENCY and WRHIGHFREQ (VOS0 range!) register_set(&(FLASH->ACR), FLASH_ACR_LATENCY_2WS | 0x20U, 0x3FU); // VOS2, AXI 100MHz-150MHz // enable external oscillator HSE register_set_bits(&(RCC->CR), RCC_CR_HSEON); - while ((RCC->CR & RCC_CR_HSERDY) == 0U); + while ((RCC->CR & RCC_CR_HSERDY) == 0U) {} // enable internal HSI48 for USB FS kernel register_set_bits(&(RCC->CR), RCC_CR_HSI48ON); - while ((RCC->CR & RCC_CR_HSI48RDY) == 0U); + while ((RCC->CR & RCC_CR_HSI48RDY) == 0U) {} // Specify the frequency source for PLL1, divider for DIVM1, DIVM2, DIVM3 : HSE, 5, 5, 5 register_set(&(RCC->PLLCKSELR), RCC_PLLCKSELR_PLLSRC_HSE | RCC_PLLCKSELR_DIVM1_0 | RCC_PLLCKSELR_DIVM1_2 | RCC_PLLCKSELR_DIVM2_0 | RCC_PLLCKSELR_DIVM2_2 | RCC_PLLCKSELR_DIVM3_0 | RCC_PLLCKSELR_DIVM3_2, 0x3F3F3F3U); @@ -89,7 +87,7 @@ void clock_init(void) { register_set(&(RCC->PLLCFGR), RCC_PLLCFGR_PLL1RGE_2 | RCC_PLLCFGR_DIVP1EN | RCC_PLLCFGR_DIVQ1EN | RCC_PLLCFGR_DIVR1EN, 0x7000CU); // Enable PLL1 register_set_bits(&(RCC->CR), RCC_CR_PLL1ON); - while((RCC->CR & RCC_CR_PLL1RDY) == 0U); + while((RCC->CR & RCC_CR_PLL1RDY) == 0U) {} // *** PLL1 end *** //////////////OTHER CLOCKS//////////////////// @@ -102,7 +100,7 @@ void clock_init(void) { // Set SysClock source to PLL register_set(&(RCC->CFGR), RCC_CFGR_SW_PLL1, 0x7U); - while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL1); + while((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL1) {} //////////////END OTHER CLOCKS//////////////////// // Configure clock source for USB (HSI48) diff --git a/board/stm32h7/interrupt_handlers.h b/board/stm32h7/interrupt_handlers.c similarity index 98% rename from board/stm32h7/interrupt_handlers.h rename to board/stm32h7/interrupt_handlers.c index 8148021d697..3dfae6256f5 100644 --- a/board/stm32h7/interrupt_handlers.h +++ b/board/stm32h7/interrupt_handlers.c @@ -1,5 +1,6 @@ -// ********************* Bare interrupt handlers ********************* -// Interrupts for STM32H7x5 +#include "lldrivers.h" +#include "stm32h7_config.h" +#include "board/drivers/drivers.h" void WWDG_IRQHandler(void) {handle_interrupt(WWDG_IRQn);} void PVD_AVD_IRQHandler(void) {handle_interrupt(PVD_AVD_IRQn);} diff --git a/board/stm32h7/lladc.h b/board/stm32h7/lladc.c similarity index 88% rename from board/stm32h7/lladc.h rename to board/stm32h7/lladc.c index 0a7e983c9ef..8281bda1738 100644 --- a/board/stm32h7/lladc.h +++ b/board/stm32h7/lladc.c @@ -1,4 +1,7 @@ -#include "lladc_declarations.h" +#include "lldrivers.h" + +#include "board/libc.h" +#include "board/print.h" static uint32_t adc_avdd_mV = 0U; @@ -6,18 +9,18 @@ void adc_init(ADC_TypeDef *adc) { adc->CR &= ~(ADC_CR_ADEN); // Disable ADC adc->CR &= ~(ADC_CR_DEEPPWD); // Reset deep-power-down mode adc->CR |= ADC_CR_ADVREGEN; // Enable ADC regulator - while(!(adc->ISR & ADC_ISR_LDORDY) && (adc != ADC3)); + while(!(adc->ISR & ADC_ISR_LDORDY) && (adc != ADC3)) {} if (adc != ADC3) { adc->CR &= ~(ADC_CR_ADCALDIF); // Choose single-ended calibration adc->CR |= ADC_CR_ADCALLIN; // Lineriality calibration } adc->CR |= ADC_CR_ADCAL; // Start calibration - while((adc->CR & ADC_CR_ADCAL) != 0U); + while((adc->CR & ADC_CR_ADCAL) != 0U) {} adc->ISR |= ADC_ISR_ADRDY; adc->CR |= ADC_CR_ADEN; - while(!(adc->ISR & ADC_ISR_ADRDY)); + while(!(adc->ISR & ADC_ISR_ADRDY)) {} } uint16_t adc_get_raw(const adc_signal_t *signal) { @@ -40,11 +43,11 @@ uint16_t adc_get_raw(const adc_signal_t *signal) { // start conversion signal->adc->CR |= ADC_CR_ADSTART; - while (!(signal->adc->ISR & ADC_ISR_EOC)); + while (!(signal->adc->ISR & ADC_ISR_EOC)) {} uint16_t res = signal->adc->DR; - while (!(signal->adc->ISR & ADC_ISR_EOS)); + while (!(signal->adc->ISR & ADC_ISR_EOS)) {} signal->adc->ISR |= ADC_ISR_EOS; return res; diff --git a/board/stm32h7/lladc_declarations.h b/board/stm32h7/lladc_declarations.h deleted file mode 100644 index 979919c8c98..00000000000 --- a/board/stm32h7/lladc_declarations.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -typedef enum { - SAMPLETIME_1_CYCLE = 0, - SAMPLETIME_2_CYCLES = 1, - SAMPLETIME_8_CYCLES = 2, - SAMPLETIME_16_CYCLES = 3, - SAMPLETIME_32_CYCLES = 4, - SAMPLETIME_64_CYCLES = 5, - SAMPLETIME_387_CYCLES = 6, - SAMPLETIME_810_CYCLES = 7 -} adc_sample_time_t; - -typedef enum { - OVERSAMPLING_1 = 0, - OVERSAMPLING_2 = 1, - OVERSAMPLING_4 = 2, - OVERSAMPLING_8 = 3, - OVERSAMPLING_16 = 4, - OVERSAMPLING_32 = 5, - OVERSAMPLING_64 = 6, - OVERSAMPLING_128 = 7, - OVERSAMPLING_256 = 8, - OVERSAMPLING_512 = 9, - OVERSAMPLING_1024 = 10 -} adc_oversampling_t; - -typedef struct { - ADC_TypeDef *adc; - uint8_t channel; - adc_sample_time_t sample_time; - adc_oversampling_t oversampling; -} adc_signal_t; - -#define ADC_CHANNEL_DEFAULT(a, c) {.adc = (a), .channel = (c), .sample_time = SAMPLETIME_32_CYCLES, .oversampling = OVERSAMPLING_64} - -#define VREFINT_CAL_ADDR ((uint16_t *)0x1FF1E860UL) diff --git a/board/stm32h7/lldrivers.h b/board/stm32h7/lldrivers.h new file mode 100644 index 00000000000..deb3fec3796 --- /dev/null +++ b/board/stm32h7/lldrivers.h @@ -0,0 +1,314 @@ +#pragma once + +#include +#include + +#include "stm32h7_config.h" + +// ======================= CLOCK ======================= + +typedef enum { + PACKAGE_UNKNOWN = 0, + PACKAGE_WITH_SMPS = 1, + PACKAGE_WITHOUT_SMPS = 2, +} PackageSMPSType; + +// TODO: find a better way to distinguish between H725 (using SMPS) and H723 (lacking SMPS) +// The package will do for now, since we have only used TFBGA100 for H723 + +void clock_init(void); + +// ======================= PERIPHERALS ======================= + +void gpio_usb_init(void); +void gpio_spi_init(void); + +#ifdef BOOTSTUB +void gpio_usart2_init(void); +#endif + +void gpio_uart7_init(void); + +// Common GPIO initialization +void common_init_gpio(void); + +#ifdef BOOTSTUB +void flasher_peripherals_init(void); +#endif + +// Peripheral initialization +void peripherals_init(void); + +void enable_interrupt_timer(void); + +// ======================= LLFLASH ======================= + +bool flash_is_locked(void); +void flash_unlock(void); +bool flash_erase_sector(uint8_t sector, bool unlocked); +void flash_write_word(void *prog_ptr, uint32_t data); +void flush_write_buffer(void); + +// ======================= LLUART ======================= + +struct uart_ring; +// 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_init(struct uart_ring *q, unsigned int baud); + +// ======================= LLSPI ======================= + +// master -> panda DMA start +void llspi_mosi_dma(uint8_t *addr, int len); +// panda -> master DMA start +void llspi_miso_dma(uint8_t *addr, int len); +void llspi_init(void); + +// ======================= LLI2C ======================= + +// TODO: this driver relies heavily on polling, +// if we want it to be more async, we should use interrupts + +#define I2C_RETRY_COUNT 10U +#define I2C_TIMEOUT_US 100000U + +bool i2c_status_wait(const volatile uint32_t *reg, uint32_t mask, uint32_t val); +void i2c_reset(I2C_TypeDef *I2C); + +bool i2c_write_reg(I2C_TypeDef *I2C, uint8_t addr, uint8_t reg, uint8_t value); +bool i2c_read_reg(I2C_TypeDef *I2C, uint8_t addr, uint8_t reg, uint8_t *value); +bool i2c_set_reg_bits(I2C_TypeDef *I2C, uint8_t address, uint8_t regis, uint8_t bits); +bool i2c_clear_reg_bits(I2C_TypeDef *I2C, uint8_t address, uint8_t regis, uint8_t bits); +bool i2c_set_reg_mask(I2C_TypeDef *I2C, uint8_t address, uint8_t regis, uint8_t value, uint8_t mask); +void i2c_init(I2C_TypeDef *I2C); + +// ======================= LLFDCAN ======================= + +// SAE J2284-4 document specifies a bus-line network running at 2 Mbit/s +// SAE J2284-5 document specifies a point-to-point communication running at 5 Mbit/s + +#define CAN_PCLK 80000U // KHz, sourced from PLL1Q +#define BITRATE_PRESCALER 2U // Valid from 250Kbps to 5Mbps with 80Mhz clock +#define CAN_SP_NOMINAL 80U // 80% for both SAE J2284-4 and SAE J2284-5 +#define CAN_SP_DATA_2M 80U // 80% for SAE J2284-4 +#define CAN_SP_DATA_5M 75U // 75% for SAE J2284-5 +#define CAN_QUANTA(speed, prescaler) (CAN_PCLK / ((speed) / 10U * (prescaler))) +#define CAN_SEG1(tq, sp) (((tq) * (sp) / 100U)- 1U) +#define CAN_SEG2(tq, sp) ((tq) * (100U - (sp)) / 100U) + +// FDCAN core settings +#define FDCAN_START_ADDRESS 0x4000AC00UL +#define FDCAN_OFFSET 3384UL // bytes for each FDCAN module, equally +#define FDCAN_OFFSET_W 846UL // words for each FDCAN module, equally + +// FDCAN_RX_FIFO_0_EL_CNT + FDCAN_TX_FIFO_EL_CNT can't exceed 47 elements (47 * 72 bytes = 3,384 bytes) per FDCAN module + +// RX FIFO 0 +#define FDCAN_RX_FIFO_0_EL_CNT 46UL +#define FDCAN_RX_FIFO_0_HEAD_SIZE 8UL // bytes +#define FDCAN_RX_FIFO_0_DATA_SIZE 64UL // bytes +#define FDCAN_RX_FIFO_0_EL_SIZE (FDCAN_RX_FIFO_0_HEAD_SIZE + FDCAN_RX_FIFO_0_DATA_SIZE) +#define FDCAN_RX_FIFO_0_EL_W_SIZE (FDCAN_RX_FIFO_0_EL_SIZE / 4UL) +#define FDCAN_RX_FIFO_0_OFFSET 0UL + +// TX FIFO +#define FDCAN_TX_FIFO_EL_CNT 1UL +#define FDCAN_TX_FIFO_HEAD_SIZE 8UL // bytes +#define FDCAN_TX_FIFO_DATA_SIZE 64UL // bytes +#define FDCAN_TX_FIFO_EL_SIZE (FDCAN_TX_FIFO_HEAD_SIZE + FDCAN_TX_FIFO_DATA_SIZE) +#define FDCAN_TX_FIFO_OFFSET (FDCAN_RX_FIFO_0_OFFSET + (FDCAN_RX_FIFO_0_EL_CNT * FDCAN_RX_FIFO_0_EL_W_SIZE)) + +#define CAN_NAME_FROM_CANIF(CAN_DEV) (((CAN_DEV)==FDCAN1) ? "FDCAN1" : (((CAN_DEV) == FDCAN2) ? "FDCAN2" : "FDCAN3")) +#define CAN_NUM_FROM_CANIF(CAN_DEV) (((CAN_DEV)==FDCAN1) ? 0UL : (((CAN_DEV) == FDCAN2) ? 1UL : 2UL)) + +// kbps multiplied by 10 +#define SPEEDS_ARRAY_SIZE 8 +extern const uint32_t speeds[SPEEDS_ARRAY_SIZE]; +#define DATA_SPEEDS_ARRAY_SIZE 10 +extern const uint32_t data_speeds[DATA_SPEEDS_ARRAY_SIZE]; + +bool llcan_set_speed(FDCAN_GlobalTypeDef *FDCANx, uint32_t speed, uint32_t data_speed, bool non_iso, bool loopback, bool silent); +void llcan_irq_disable(const FDCAN_GlobalTypeDef *FDCANx); +void llcan_irq_enable(const FDCAN_GlobalTypeDef *FDCANx); +bool llcan_init(FDCAN_GlobalTypeDef *FDCANx); +void llcan_clear_send(FDCAN_GlobalTypeDef *FDCANx); + +// ======================= LLUSB ======================= + +extern USB_OTG_GlobalTypeDef *USBx; + +#define USBx_DEVICE ((USB_OTG_DeviceTypeDef *)((uint32_t)USBx + USB_OTG_DEVICE_BASE)) +#define USBx_INEP(i) ((USB_OTG_INEndpointTypeDef *)((uint32_t)USBx + USB_OTG_IN_ENDPOINT_BASE + ((i) * USB_OTG_EP_REG_SIZE))) +#define USBx_OUTEP(i) ((USB_OTG_OUTEndpointTypeDef *)((uint32_t)USBx + USB_OTG_OUT_ENDPOINT_BASE + ((i) * USB_OTG_EP_REG_SIZE))) +#define USBx_DFIFO(i) *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_FIFO_BASE + ((i) * USB_OTG_FIFO_SIZE)) +#define USBx_PCGCCTL *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_PCGCCTL_BASE) + +#define USBD_FS_TRDT_VALUE 6UL +#define USB_OTG_SPEED_FULL 3U +#define DCFG_FRAME_INTERVAL_80 0U + +void usb_irqhandler(void); +void usb_init(void); + +// ======================= LLFAN ======================= + +void llfan_init(void); + +// ======================= SOUND ======================= + +#define SOUND_RX_BUF_SIZE 1000U +#define SOUND_TX_BUF_SIZE (SOUND_RX_BUF_SIZE/2U) +#define MIC_RX_BUF_SIZE 512U +#define MIC_TX_BUF_SIZE (MIC_RX_BUF_SIZE * 2U) +#define SOUND_IDLE_TIMEOUT 4U +#define MIC_SKIP_BUFFERS 2U // Skip first 2 buffers (1024 samples = ~21ms at 48kHz) + +void sound_tick(void); +void sound_init_dac(void); +void sound_init(void); +void sound_stop_dac(void); + +// ======================= INTERRUPT HANDLERS ======================= +// Bare interrupt handlers for STM32H7x5 + +void WWDG_IRQHandler(void); +void PVD_AVD_IRQHandler(void); +void TAMP_STAMP_IRQHandler(void); +void RTC_WKUP_IRQHandler(void); +void FLASH_IRQHandler(void); +void RCC_IRQHandler(void); +void EXTI0_IRQHandler(void); +void EXTI1_IRQHandler(void); +void EXTI2_IRQHandler(void); +void EXTI3_IRQHandler(void); +void EXTI4_IRQHandler(void); +void DMA1_Stream0_IRQHandler(void); +void DMA1_Stream1_IRQHandler(void); +void DMA1_Stream2_IRQHandler(void); +void DMA1_Stream3_IRQHandler(void); +void DMA1_Stream4_IRQHandler(void); +void DMA1_Stream5_IRQHandler(void); +void DMA1_Stream6_IRQHandler(void); +void ADC_IRQHandler(void); +void FDCAN1_IT0_IRQHandler(void); +void FDCAN2_IT0_IRQHandler(void); +void FDCAN1_IT1_IRQHandler(void); +void FDCAN2_IT1_IRQHandler(void); +void EXTI9_5_IRQHandler(void); +void TIM1_BRK_IRQHandler(void); +void TIM1_UP_TIM10_IRQHandler(void); +void TIM1_TRG_COM_IRQHandler(void); +void TIM1_CC_IRQHandler(void); +void TIM2_IRQHandler(void); +void TIM3_IRQHandler(void); +void TIM4_IRQHandler(void); +void I2C1_EV_IRQHandler(void); +void I2C1_ER_IRQHandler(void); +void I2C2_EV_IRQHandler(void); +void I2C2_ER_IRQHandler(void); +void SPI1_IRQHandler(void); +void SPI2_IRQHandler(void); +void USART1_IRQHandler(void); +void USART2_IRQHandler(void); +void USART3_IRQHandler(void); +void EXTI15_10_IRQHandler(void); +void RTC_Alarm_IRQHandler(void); +void TIM8_BRK_TIM12_IRQHandler(void); +void TIM8_UP_TIM13_IRQHandler(void); +void TIM8_TRG_COM_TIM14_IRQHandler(void); +void TIM8_CC_IRQHandler(void); +void DMA1_Stream7_IRQHandler(void); +void FMC_IRQHandler(void); +void SDMMC1_IRQHandler(void); +void TIM5_IRQHandler(void); +void SPI3_IRQHandler(void); +void UART4_IRQHandler(void); +void UART5_IRQHandler(void); +void TIM6_DAC_IRQHandler(void); +void TIM7_IRQHandler(void); +void DMA2_Stream0_IRQHandler(void); +void DMA2_Stream1_IRQHandler(void); +void DMA2_Stream2_IRQHandler(void); +void DMA2_Stream3_IRQHandler(void); +void DMA2_Stream4_IRQHandler(void); +void ETH_IRQHandler(void); +void ETH_WKUP_IRQHandler(void); +void FDCAN_CAL_IRQHandler(void); +void DMA2_Stream5_IRQHandler(void); +void DMA2_Stream6_IRQHandler(void); +void DMA2_Stream7_IRQHandler(void); +void USART6_IRQHandler(void); +void I2C3_EV_IRQHandler(void); +void I2C3_ER_IRQHandler(void); +void OTG_HS_EP1_OUT_IRQHandler(void); +void OTG_HS_EP1_IN_IRQHandler(void); +void OTG_HS_WKUP_IRQHandler(void); +void OTG_HS_IRQHandler(void); +void DCMI_PSSI_IRQHandler(void); +void CRYP_IRQHandler(void); +void HASH_RNG_IRQHandler(void); +void FPU_IRQHandler(void); +void UART7_IRQHandler(void); +void UART8_IRQHandler(void); +void SPI4_IRQHandler(void); +void SPI5_IRQHandler(void); +void SPI6_IRQHandler(void); +void SAI1_IRQHandler(void); +void LTDC_IRQHandler(void); +void LTDC_ER_IRQHandler(void); +void DMA2D_IRQHandler(void); +void OCTOSPI1_IRQHandler(void); +void LPTIM1_IRQHandler(void); +void CEC_IRQHandler(void); +void I2C4_EV_IRQHandler(void); +void I2C4_ER_IRQHandler(void); +void SPDIF_RX_IRQHandler(void); +void DMAMUX1_OVR_IRQHandler(void); +void DFSDM1_FLT0_IRQHandler(void); +void DFSDM1_FLT1_IRQHandler(void); +void DFSDM1_FLT2_IRQHandler(void); +void DFSDM1_FLT3_IRQHandler(void); +void SWPMI1_IRQHandler(void); +void TIM15_IRQHandler(void); +void TIM16_IRQHandler(void); +void TIM17_IRQHandler(void); +void MDIOS_WKUP_IRQHandler(void); +void MDIOS_IRQHandler(void); +void MDMA_IRQHandler(void); +void SDMMC2_IRQHandler(void); +void HSEM1_IRQHandler(void); +void ADC3_IRQHandler(void); +void DMAMUX2_OVR_IRQHandler(void); +void BDMA_Channel0_IRQHandler(void); +void BDMA_Channel1_IRQHandler(void); +void BDMA_Channel2_IRQHandler(void); +void BDMA_Channel3_IRQHandler(void); +void BDMA_Channel4_IRQHandler(void); +void BDMA_Channel5_IRQHandler(void); +void BDMA_Channel6_IRQHandler(void); +void BDMA_Channel7_IRQHandler(void); +void COMP_IRQHandler(void); +void LPTIM2_IRQHandler(void); +void LPTIM3_IRQHandler(void); +void LPTIM4_IRQHandler(void); +void LPTIM5_IRQHandler(void); +void LPUART1_IRQHandler(void); +void CRS_IRQHandler(void); +void ECC_IRQHandler(void); +void SAI4_IRQHandler(void); +void DTS_IRQHandler(void); +void WAKEUP_PIN_IRQHandler(void); +void OCTOSPI2_IRQHandler(void); +void OTFDEC1_IRQHandler(void); +void OTFDEC2_IRQHandler(void); +void FMAC_IRQHandler(void); +void CORDIC_IRQHandler(void); +void UART9_IRQHandler(void); +void USART10_IRQHandler(void); +void I2C5_EV_IRQHandler(void); +void I2C5_ER_IRQHandler(void); +void FDCAN3_IT0_IRQHandler(void); +void FDCAN3_IT1_IRQHandler(void); +void TIM23_IRQHandler(void); +void TIM24_IRQHandler(void); diff --git a/board/stm32h7/llfan.h b/board/stm32h7/llfan.c similarity index 91% rename from board/stm32h7/llfan.h rename to board/stm32h7/llfan.c index 06309d0633f..1c2709dfc86 100644 --- a/board/stm32h7/llfan.h +++ b/board/stm32h7/llfan.c @@ -1,3 +1,7 @@ +#include "lldrivers.h" + +#include "board/drivers/drivers.h" + // TACH interrupt handler static void EXTI2_IRQ_Handler(void) { volatile unsigned int pr = EXTI->PR1 & (1U << 2); diff --git a/board/stm32h7/llfdcan.h b/board/stm32h7/llfdcan.c similarity index 98% rename from board/stm32h7/llfdcan.h rename to board/stm32h7/llfdcan.c index 64a40bd072e..94873cfd0ae 100644 --- a/board/stm32h7/llfdcan.h +++ b/board/stm32h7/llfdcan.c @@ -1,4 +1,5 @@ -#include "llfdcan_declarations.h" +#include "lldrivers.h" +#include "board/print.h" // kbps multiplied by 10 const uint32_t speeds[SPEEDS_ARRAY_SIZE] = {100U, 200U, 500U, 1000U, 1250U, 2500U, 5000U, 10000U}; @@ -8,7 +9,7 @@ static bool fdcan_request_init(FDCAN_GlobalTypeDef *FDCANx) { bool ret = true; // Exit from sleep mode FDCANx->CCCR &= ~(FDCAN_CCCR_CSR); - while ((FDCANx->CCCR & FDCAN_CCCR_CSA) == FDCAN_CCCR_CSA); + while ((FDCANx->CCCR & FDCAN_CCCR_CSA) == FDCAN_CCCR_CSA) {} // Request init uint32_t timeout_counter = 0U; diff --git a/board/stm32h7/llfdcan_declarations.h b/board/stm32h7/llfdcan_declarations.h deleted file mode 100644 index 793849011eb..00000000000 --- a/board/stm32h7/llfdcan_declarations.h +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -// SAE J2284-4 document specifies a bus-line network running at 2 Mbit/s -// SAE J2284-5 document specifies a point-to-point communication running at 5 Mbit/s - -#define CAN_PCLK 80000U // KHz, sourced from PLL1Q -#define BITRATE_PRESCALER 2U // Valid from 250Kbps to 5Mbps with 80Mhz clock -#define CAN_SP_NOMINAL 80U // 80% for both SAE J2284-4 and SAE J2284-5 -#define CAN_SP_DATA_2M 80U // 80% for SAE J2284-4 -#define CAN_SP_DATA_5M 75U // 75% for SAE J2284-5 -#define CAN_QUANTA(speed, prescaler) (CAN_PCLK / ((speed) / 10U * (prescaler))) -#define CAN_SEG1(tq, sp) (((tq) * (sp) / 100U)- 1U) -#define CAN_SEG2(tq, sp) ((tq) * (100U - (sp)) / 100U) - -// FDCAN core settings -#define FDCAN_START_ADDRESS 0x4000AC00UL -#define FDCAN_OFFSET 3384UL // bytes for each FDCAN module, equally -#define FDCAN_OFFSET_W 846UL // words for each FDCAN module, equally - -// FDCAN_RX_FIFO_0_EL_CNT + FDCAN_TX_FIFO_EL_CNT can't exceed 47 elements (47 * 72 bytes = 3,384 bytes) per FDCAN module - -// RX FIFO 0 -#define FDCAN_RX_FIFO_0_EL_CNT 46UL -#define FDCAN_RX_FIFO_0_HEAD_SIZE 8UL // bytes -#define FDCAN_RX_FIFO_0_DATA_SIZE 64UL // bytes -#define FDCAN_RX_FIFO_0_EL_SIZE (FDCAN_RX_FIFO_0_HEAD_SIZE + FDCAN_RX_FIFO_0_DATA_SIZE) -#define FDCAN_RX_FIFO_0_EL_W_SIZE (FDCAN_RX_FIFO_0_EL_SIZE / 4UL) -#define FDCAN_RX_FIFO_0_OFFSET 0UL - -// TX FIFO -#define FDCAN_TX_FIFO_EL_CNT 1UL -#define FDCAN_TX_FIFO_HEAD_SIZE 8UL // bytes -#define FDCAN_TX_FIFO_DATA_SIZE 64UL // bytes -#define FDCAN_TX_FIFO_EL_SIZE (FDCAN_TX_FIFO_HEAD_SIZE + FDCAN_TX_FIFO_DATA_SIZE) -#define FDCAN_TX_FIFO_OFFSET (FDCAN_RX_FIFO_0_OFFSET + (FDCAN_RX_FIFO_0_EL_CNT * FDCAN_RX_FIFO_0_EL_W_SIZE)) - -#define CAN_NAME_FROM_CANIF(CAN_DEV) (((CAN_DEV)==FDCAN1) ? "FDCAN1" : (((CAN_DEV) == FDCAN2) ? "FDCAN2" : "FDCAN3")) -#define CAN_NUM_FROM_CANIF(CAN_DEV) (((CAN_DEV)==FDCAN1) ? 0UL : (((CAN_DEV) == FDCAN2) ? 1UL : 2UL)) - - -void print(const char *a); - -// kbps multiplied by 10 -#define SPEEDS_ARRAY_SIZE 8 -extern const uint32_t speeds[SPEEDS_ARRAY_SIZE]; -#define DATA_SPEEDS_ARRAY_SIZE 10 -extern const uint32_t data_speeds[DATA_SPEEDS_ARRAY_SIZE]; - -bool llcan_set_speed(FDCAN_GlobalTypeDef *FDCANx, uint32_t speed, uint32_t data_speed, bool non_iso, bool loopback, bool silent); -void llcan_irq_disable(const FDCAN_GlobalTypeDef *FDCANx); -void llcan_irq_enable(const FDCAN_GlobalTypeDef *FDCANx); -bool llcan_init(FDCAN_GlobalTypeDef *FDCANx); -void llcan_clear_send(FDCAN_GlobalTypeDef *FDCANx); diff --git a/board/stm32h7/llflash.c b/board/stm32h7/llflash.c new file mode 100644 index 00000000000..60b936f6e5c --- /dev/null +++ b/board/stm32h7/llflash.c @@ -0,0 +1,38 @@ +#include "lldrivers.h" + +#include "stm32h7_config.h" + +bool flash_is_locked(void) { + return (FLASH->CR1 & FLASH_CR_LOCK); +} + +void flash_unlock(void) { + FLASH->KEYR1 = 0x45670123u; + FLASH->KEYR1 = 0xCDEF89ABu; +} + +bool flash_erase_sector(uint8_t sector, bool is_unlocked) { + // don't erase the bootloader(sector 0) + bool ret = false; + if ((sector != 0u) && (sector < 8u) && is_unlocked) { + FLASH->CR1 = ((uint32_t) sector << 8u) | FLASH_CR_SER; + FLASH->CR1 |= FLASH_CR_START; + while ((FLASH->SR1 & FLASH_SR_QW) != 0u) {} + ret = true; + } + return ret; +} + +void flash_write_word(void *prog_ptr, uint32_t data) { + uint32_t *pp = prog_ptr; + FLASH->CR1 |= FLASH_CR_PG; + *pp = data; + while ((FLASH->SR1 & FLASH_SR_QW) != 0u) {} +} + +void flush_write_buffer(void) { + if ((FLASH->SR1 & FLASH_SR_WBNE) != 0u) { + FLASH->CR1 |= FLASH_CR_FW; + while ((FLASH->SR1 & FLASH_CR_FW) != 0u) {} + } +} diff --git a/board/stm32h7/llflash.h b/board/stm32h7/llflash.h deleted file mode 100644 index b95011a9ed8..00000000000 --- a/board/stm32h7/llflash.h +++ /dev/null @@ -1,33 +0,0 @@ -bool flash_is_locked(void) { - return (FLASH->CR1 & FLASH_CR_LOCK); -} - -void flash_unlock(void) { - FLASH->KEYR1 = 0x45670123; - FLASH->KEYR1 = 0xCDEF89AB; -} - -bool flash_erase_sector(uint8_t sector, bool unlocked) { - // don't erase the bootloader(sector 0) - if (sector != 0 && sector < 8 && unlocked) { - FLASH->CR1 = (sector << 8) | FLASH_CR_SER; - FLASH->CR1 |= FLASH_CR_START; - while (FLASH->SR1 & FLASH_SR_QW); - return true; - } - return false; -} - -void flash_write_word(void *prog_ptr, uint32_t data) { - uint32_t *pp = prog_ptr; - FLASH->CR1 |= FLASH_CR_PG; - *pp = data; - while (FLASH->SR1 & FLASH_SR_QW); -} - -void flush_write_buffer(void) { - if (FLASH->SR1 & FLASH_SR_WBNE) { - FLASH->CR1 |= FLASH_CR_FW; - while (FLASH->SR1 & FLASH_CR_FW); - } -} diff --git a/board/stm32h7/lli2c.h b/board/stm32h7/lli2c.c similarity index 97% rename from board/stm32h7/lli2c.h rename to board/stm32h7/lli2c.c index 5d79beb653e..39029b6a96b 100644 --- a/board/stm32h7/lli2c.h +++ b/board/stm32h7/lli2c.c @@ -1,19 +1,21 @@ // TODO: this driver relies heavily on polling, // if we want it to be more async, we should use interrupts +#include "lldrivers.h" + #define I2C_RETRY_COUNT 10U #define I2C_TIMEOUT_US 100000U bool i2c_status_wait(const volatile uint32_t *reg, uint32_t mask, uint32_t val) { uint32_t start_time = microsecond_timer_get(); - while(((*reg & mask) != val) && (get_ts_elapsed(microsecond_timer_get(), start_time) < I2C_TIMEOUT_US)); + while(((*reg & mask) != val) && (get_ts_elapsed(microsecond_timer_get(), start_time) < I2C_TIMEOUT_US)) {} return ((*reg & mask) == val); } void i2c_reset(I2C_TypeDef *I2C) { // peripheral reset register_clear_bits(&I2C->CR1, I2C_CR1_PE); - while ((I2C->CR1 & I2C_CR1_PE) != 0U); + while ((I2C->CR1 & I2C_CR1_PE) != 0U) {} register_set_bits(&I2C->CR1, I2C_CR1_PE); } diff --git a/board/stm32h7/llspi.h b/board/stm32h7/llspi.c similarity index 98% rename from board/stm32h7/llspi.h rename to board/stm32h7/llspi.c index 05f8e22f9a8..0c0be02027f 100644 --- a/board/stm32h7/llspi.h +++ b/board/stm32h7/llspi.c @@ -1,3 +1,7 @@ +#include "lldrivers.h" + +#include "board/drivers/drivers.h" + // master -> panda DMA start void llspi_mosi_dma(uint8_t *addr, int len) { // disable DMA + SPI diff --git a/board/stm32h7/lluart.h b/board/stm32h7/lluart.c similarity index 97% rename from board/stm32h7/lluart.h rename to board/stm32h7/lluart.c index e18f1e9f6f3..bc2846b52a3 100644 --- a/board/stm32h7/lluart.h +++ b/board/stm32h7/lluart.c @@ -1,3 +1,6 @@ +#include "board/config.h" +#include "board/drivers/drivers.h" + static void uart_rx_ring(uart_ring *q){ // Do not read out directly if DMA enabled ENTER_CRITICAL(); diff --git a/board/stm32h7/llusb.h b/board/stm32h7/llusb.c similarity index 95% rename from board/stm32h7/llusb.h rename to board/stm32h7/llusb.c index f1bcf16ad5e..258f22a9f1e 100644 --- a/board/stm32h7/llusb.h +++ b/board/stm32h7/llusb.c @@ -1,4 +1,4 @@ -#include "llusb_declarations.h" +#include "lldrivers.h" USB_OTG_GlobalTypeDef *USBx = USB_OTG_HS; @@ -20,10 +20,10 @@ void usb_init(void) { USBx->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; delay(250000); // Wait for about 25ms (explicitly stated in H7 ref manual) // Wait for AHB master IDLE state. - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U) {} // Core Soft Reset USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST) {} // Activate the USB Transceiver USBx->GCCFG |= USB_OTG_GCCFG_PWRDWN; @@ -46,10 +46,10 @@ void usb_init(void) { // Flush FIFOs USBx->GRSTCTL = (USB_OTG_GRSTCTL_TXFFLSH | (0x10U << 6)); - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH) {} USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH); + while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH) {} // Clear all pending Device Interrupts USBx_DEVICE->DIEPMSK = 0U; diff --git a/board/stm32h7/llusb_declarations.h b/board/stm32h7/llusb_declarations.h deleted file mode 100644 index a11d3f52c6b..00000000000 --- a/board/stm32h7/llusb_declarations.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -extern USB_OTG_GlobalTypeDef *USBx; - -#define USBx_DEVICE ((USB_OTG_DeviceTypeDef *)((uint32_t)USBx + USB_OTG_DEVICE_BASE)) -#define USBx_INEP(i) ((USB_OTG_INEndpointTypeDef *)((uint32_t)USBx + USB_OTG_IN_ENDPOINT_BASE + ((i) * USB_OTG_EP_REG_SIZE))) -#define USBx_OUTEP(i) ((USB_OTG_OUTEndpointTypeDef *)((uint32_t)USBx + USB_OTG_OUT_ENDPOINT_BASE + ((i) * USB_OTG_EP_REG_SIZE))) -#define USBx_DFIFO(i) *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_FIFO_BASE + ((i) * USB_OTG_FIFO_SIZE)) -#define USBx_PCGCCTL *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_PCGCCTL_BASE) - -#define USBD_FS_TRDT_VALUE 6UL -#define USB_OTG_SPEED_FULL 3U -#define DCFG_FRAME_INTERVAL_80 0U - -void usb_irqhandler(void); -void usb_init(void); diff --git a/board/stm32h7/peripherals.h b/board/stm32h7/peripherals.c similarity index 98% rename from board/stm32h7/peripherals.h rename to board/stm32h7/peripherals.c index 8eb384307f3..3acc9b6189b 100644 --- a/board/stm32h7/peripherals.h +++ b/board/stm32h7/peripherals.c @@ -1,8 +1,7 @@ -#ifdef BOOTSTUB +#include "lldrivers.h" +#include "board/drivers/drivers.h" + void gpio_usb_init(void) { -#else -static void gpio_usb_init(void) { -#endif // A11,A12: USB set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG1_FS); set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG1_FS); diff --git a/board/stm32h7/sound.h b/board/stm32h7/sound.c similarity index 96% rename from board/stm32h7/sound.h rename to board/stm32h7/sound.c index f9445dde92b..2bb74be69b7 100644 --- a/board/stm32h7/sound.h +++ b/board/stm32h7/sound.c @@ -1,14 +1,13 @@ -#define SOUND_RX_BUF_SIZE 1000U -#define SOUND_TX_BUF_SIZE (SOUND_RX_BUF_SIZE/2U) -#define MIC_RX_BUF_SIZE 512U -#define MIC_TX_BUF_SIZE (MIC_RX_BUF_SIZE * 2U) +#include + +#include "board/globals.h" +#include "lldrivers.h" + __attribute__((section(".sram4"))) static uint16_t sound_rx_buf[2][SOUND_RX_BUF_SIZE]; __attribute__((section(".sram4"))) static uint16_t sound_tx_buf[2][SOUND_TX_BUF_SIZE]; __attribute__((section(".sram4"))) static uint32_t mic_rx_buf[2][MIC_RX_BUF_SIZE]; __attribute__((section(".sram4"))) static uint16_t mic_tx_buf[2][MIC_TX_BUF_SIZE]; -#define SOUND_IDLE_TIMEOUT 4U -#define MIC_SKIP_BUFFERS 2U // Skip first 2 buffers (1024 samples = ~21ms at 48kHz) static uint8_t sound_idle_count; static uint8_t mic_idle_count; static uint8_t mic_buffer_count; @@ -126,7 +125,7 @@ void sound_init_dac(void) { DMA1_Stream1->CR = DMA_SxCR_DBM | (0b11UL << DMA_SxCR_PL_Pos) | (0b01UL << DMA_SxCR_MSIZE_Pos) | (0b01UL << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC | (1U << DMA_SxCR_DIR_Pos); } -static void sound_stop_dac(void) { +void sound_stop_dac(void) { register_clear_bits(&BDMA_Channel0->CCR, BDMA_CCR_EN); BDMA->IFCR = 0xFFFFFFFFU; diff --git a/board/stm32h7/startup_stm32h7x5xx.s b/board/stm32h7/startup_stm32h7x5xx.s index 15015a11329..d24c5feb34b 100644 --- a/board/stm32h7/startup_stm32h7x5xx.s +++ b/board/stm32h7/startup_stm32h7x5xx.s @@ -343,6 +343,7 @@ g_pfnVectors: .weak SysTick_Handler .thumb_set SysTick_Handler,Default_Handler +/* Removed weak link to force linker error if missing .weak WWDG_IRQHandler .thumb_set WWDG_IRQHandler,Default_Handler @@ -417,10 +418,12 @@ g_pfnVectors: .weak TIM1_BRK_IRQHandler .thumb_set TIM1_BRK_IRQHandler,Default_Handler +*/ .weak TIM1_UP_IRQHandler .thumb_set TIM1_UP_IRQHandler,Default_Handler +/* Removed weak link to force linker error if missing .weak TIM1_TRG_COM_IRQHandler .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler @@ -763,5 +766,6 @@ g_pfnVectors: .weak TIM24_IRQHandler .thumb_set TIM24_IRQHandler,Default_Handler +*/ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/board/stm32h7/stm32h7_config.c b/board/stm32h7/stm32h7_config.c new file mode 100644 index 00000000000..309002443c0 --- /dev/null +++ b/board/stm32h7/stm32h7_config.c @@ -0,0 +1,8 @@ +#include "stm32h7_config.h" + +void early_gpio_float(void) { + RCC->AHB4ENR = RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOCEN | RCC_AHB4ENR_GPIODEN | RCC_AHB4ENR_GPIOEEN | RCC_AHB4ENR_GPIOFEN | RCC_AHB4ENR_GPIOGEN | RCC_AHB4ENR_GPIOHEN; + GPIOA->MODER = 0xAB000000U; GPIOB->MODER = 0; GPIOC->MODER = 0; GPIOD->MODER = 0; GPIOE->MODER = 0; GPIOF->MODER = 0; GPIOG->MODER = 0; GPIOH->MODER = 0; + GPIOA->ODR = 0; GPIOB->ODR = 0; GPIOC->ODR = 0; GPIOD->ODR = 0; GPIOE->ODR = 0; GPIOF->ODR = 0; GPIOG->ODR = 0; GPIOH->ODR = 0; + GPIOA->PUPDR = 0; GPIOB->PUPDR = 0; GPIOC->PUPDR = 0; GPIOD->PUPDR = 0; GPIOE->PUPDR = 0; GPIOF->PUPDR = 0; GPIOG->PUPDR = 0; GPIOH->PUPDR = 0; +} diff --git a/board/stm32h7/stm32h7_config.h b/board/stm32h7/stm32h7_config.h index 1a3b413620a..28be45a5f59 100644 --- a/board/stm32h7/stm32h7_config.h +++ b/board/stm32h7/stm32h7_config.h @@ -1,3 +1,5 @@ +#pragma once + #include "stm32h7xx.h" #include "stm32h7xx_hal_gpio_ex.h" #define MCU_IDCODE 0x483U @@ -44,30 +46,13 @@ separate IRQs for RX and TX. #define DEVICE_SERIAL_NUMBER_ADDRESS 0x080FFFC0U #include "board/can.h" -#include "board/comms_definitions.h" - -#ifndef BOOTSTUB - #include "board/main_definitions.h" -#else - #include "board/bootstub_declarations.h" -#endif +#include "board/comms.h" #include "board/libc.h" -#include "board/critical.h" -#include "board/faults.h" #include "board/utils.h" -#include "board/drivers/registers.h" -#include "board/drivers/interrupts.h" -#include "board/drivers/gpio.h" -#include "board/stm32h7/peripherals.h" -#include "board/stm32h7/interrupt_handlers.h" -#include "board/drivers/timers.h" - -#if !defined(BOOTSTUB) - #include "board/drivers/uart.h" - #include "board/stm32h7/lluart.h" -#endif +#include "board/drivers/drivers.h" +#include "board/stm32h7/lldrivers.h" #ifdef PANDA_JUNGLE #include "board/jungle/stm32h7/board.h" @@ -76,22 +61,5 @@ separate IRQs for RX and TX. #else #include "board/stm32h7/board.h" #endif -#include "board/stm32h7/clock.h" - -#ifdef BOOTSTUB - #include "board/stm32h7/llflash.h" -#else - #include "board/stm32h7/llfdcan.h" -#endif - -#include "board/stm32h7/llusb.h" - -#include "board/drivers/spi.h" -#include "board/stm32h7/llspi.h" -void early_gpio_float(void) { - RCC->AHB4ENR = RCC_AHB4ENR_GPIOAEN | RCC_AHB4ENR_GPIOBEN | RCC_AHB4ENR_GPIOCEN | RCC_AHB4ENR_GPIODEN | RCC_AHB4ENR_GPIOEEN | RCC_AHB4ENR_GPIOFEN | RCC_AHB4ENR_GPIOGEN | RCC_AHB4ENR_GPIOHEN; - GPIOA->MODER = 0xAB000000U; GPIOB->MODER = 0; GPIOC->MODER = 0; GPIOD->MODER = 0; GPIOE->MODER = 0; GPIOF->MODER = 0; GPIOG->MODER = 0; GPIOH->MODER = 0; - GPIOA->ODR = 0; GPIOB->ODR = 0; GPIOC->ODR = 0; GPIOD->ODR = 0; GPIOE->ODR = 0; GPIOF->ODR = 0; GPIOG->ODR = 0; GPIOH->ODR = 0; - GPIOA->PUPDR = 0; GPIOB->PUPDR = 0; GPIOC->PUPDR = 0; GPIOD->PUPDR = 0; GPIOE->PUPDR = 0; GPIOF->PUPDR = 0; GPIOG->PUPDR = 0; GPIOH->PUPDR = 0; -} +void early_gpio_float(void); \ No newline at end of file diff --git a/board/utils.c b/board/utils.c new file mode 100644 index 00000000000..6c31eec8193 --- /dev/null +++ b/board/utils.c @@ -0,0 +1,9 @@ +#include + +#include "utils.h" + +// compute the time elapsed (in microseconds) from 2 counter samples +// case where ts < ts_last is ok: overflow is properly re-casted into uint32_t +uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) { + return ts - ts_last; +} diff --git a/board/utils.h b/board/utils.h index f355ce8c2f2..30699a0f047 100644 --- a/board/utils.h +++ b/board/utils.h @@ -1,3 +1,5 @@ +#pragma once + // cppcheck-suppress-macro misra-c2012-1.2; allow __typeof__ extension #define MIN(a, b) ({ \ __typeof__ (a) _a = (a); \ @@ -42,6 +44,4 @@ // compute the time elapsed (in microseconds) from 2 counter samples // case where ts < ts_last is ok: overflow is properly re-casted into uint32_t -uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) { - return ts - ts_last; -} +uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last); \ No newline at end of file diff --git a/tests/libpanda/SConscript b/tests/libpanda/SConscript index a5bdd7ce745..381a3257677 100644 --- a/tests/libpanda/SConscript +++ b/tests/libpanda/SConscript @@ -20,6 +20,7 @@ env = Environment( '-std=gnu11', '-Wfatal-errors', '-Wno-pointer-to-int-cast', + "-DLIB_PANDA", ], CPPPATH=[".", "../../", "../../board/", opendbc.INCLUDE_PATH], ) @@ -34,5 +35,16 @@ if GetOption('ubsan'): env['CFLAGS'] += flags env['LINKFLAGS'] += flags -panda = env.SharedObject("panda.os", "panda.c") -libpanda = env.SharedLibrary("libpanda.so", [panda]) +shared = [ + "crypto/rsa.c", + "crypto/sha.c", + "board/can_comms.c", + "board/drivers/can_common.c", + "board/fake_stm.c", + "board/utils.c", +] + +c = ["panda.c"] + ["../../" + s for s in shared] + +objs = env.SharedObject(c) +libpanda = env.SharedLibrary("libpanda.so", objs) diff --git a/tests/libpanda/panda.c b/tests/libpanda/panda.c index 2d17d64e34c..8cd6e25a88d 100644 --- a/tests/libpanda/panda.c +++ b/tests/libpanda/panda.c @@ -12,17 +12,13 @@ void can_tx_comms_resume_usb(void) { }; void can_tx_comms_resume_spi(void) { }; #include "health.h" -#include "faults.h" #include "libc.h" -#include "boards/board_declarations.h" #include "opendbc/safety/safety.h" -#include "main_definitions.h" -#include "drivers/can_common.h" +#include "drivers/drivers.h" can_ring *rx_q = &can_rx_q; can_ring *tx1_q = &can_tx1_q; can_ring *tx2_q = &can_tx2_q; can_ring *tx3_q = &can_tx3_q; -#include "comms_definitions.h" -#include "can_comms.h" +#include "comms.h" diff --git a/tests/misra/checkers.txt b/tests/misra/checkers.txt index 44e6aa13f34..431970c9584 100644 --- a/tests/misra/checkers.txt +++ b/tests/misra/checkers.txt @@ -5,7 +5,7 @@ Cppcheck checkers list from test_misra.sh: TEST variant options: ---enable=all --disable=unusedFunction --addon=misra -DSTM32H7 -DSTM32H725xx -I /board/stm32h7/inc/ /board/main.c +--enable=all --addon=misra -DSTM32H7 -DSTM32H725xx -I /board/stm32h7/inc/ -DPANDA /board/boards/cuatro.c /board/boards/red.c /board/boards/tres.c /board/boards/unused_funcs.c /board/can_comms.c /board/critical.c /board/drivers/bootkick.c /board/drivers/can_common.c /board/drivers/clock_source.c /board/drivers/fake_siren.c /board/drivers/fan.c /board/drivers/fdcan.c /board/drivers/gpio.c /board/drivers/harness.c /board/drivers/interrupts.c /board/drivers/led.c /board/drivers/pwm.c /board/drivers/registers.c /board/drivers/simple_watchdog.c /board/drivers/spi.c /board/drivers/timers.c /board/drivers/uart.c /board/drivers/usb.c /board/early_init.c /board/faults.c /board/globals.c /board/libc.c /board/main.c /board/main_comms.c /board/main_definitions.c /board/power_saving.c /board/provision.c /board/stm32h7/board.c /board/stm32h7/clock.c /board/stm32h7/interrupt_handlers.c /board/stm32h7/lladc.c /board/stm32h7/llfan.c /board/stm32h7/llfdcan.c /board/stm32h7/lli2c.c /board/stm32h7/llspi.c /board/stm32h7/lluart.c /board/stm32h7/llusb.c /board/stm32h7/peripherals.c /board/stm32h7/sound.c /board/stm32h7/stm32h7_config.c /board/utils.c Critical errors @@ -194,7 +194,7 @@ Yes CheckType::checkSignConversion Yes CheckType::checkTooBigBitwiseShift Yes CheckUninitVar::check Yes CheckUninitVar::valueFlowUninit -No CheckUnusedFunctions::check require:unusedFunction +Yes CheckUnusedFunctions::check Yes CheckUnusedVar::checkFunctionVariableUsage Yes CheckUnusedVar::checkStructMemberUsage Yes CheckVaarg::va_list_usage diff --git a/tests/misra/suppressions.txt b/tests/misra/suppressions.txt index 4800a270bcb..be223dfceb8 100644 --- a/tests/misra/suppressions.txt +++ b/tests/misra/suppressions.txt @@ -13,7 +13,8 @@ misra-c2012-20.10 unmatchedSuppression # All interrupt handlers are defined, including ones we don't use -unusedFunction:*/interrupt_handlers*.h +unusedFunction:*/interrupt_handlers* +misra-c2012-8.7:*/interrupt_handlers.c # all of the below suppressions are from new checks introduced after updating # cppcheck from 2.5 -> 2.13. they are listed here to separate the update from diff --git a/tests/misra/test_misra.sh b/tests/misra/test_misra.sh index d7b9c6efdf8..7356b4e32cf 100755 --- a/tests/misra/test_misra.sh +++ b/tests/misra/test_misra.sh @@ -49,6 +49,7 @@ cppcheck() { -I $PANDA_DIR \ -I "$(arm-none-eabi-gcc -print-file-name=include)" \ -I $OPENDBC_ROOT \ + --suppress=misra-c2012-5.9:$OPENDBC_ROOT/* \ --suppressions-list=$DIR/suppressions.txt --suppress=*:*inc/* \ --suppress=*:*include/* --error-exitcode=2 --check-level=exhaustive --safety \ --platform=arm32-wchar_t4 $COMMON_DEFINES --checkers-report=$CHECKLIST.tmp \ @@ -64,14 +65,35 @@ cppcheck() { fi } -PANDA_OPTS="--enable=all --disable=unusedFunction --addon=misra" +PANDA_OPTS="--enable=all --addon=misra" printf "\n${GREEN}** PANDA H7 CODE **${NC}\n" -cppcheck $PANDA_OPTS -DSTM32H7 -DSTM32H725xx -I $PANDA_DIR/board/stm32h7/inc/ $PANDA_DIR/board/main.c -# unused needs to run globally -#printf "\n${GREEN}** UNUSED ALL CODE **${NC}\n" -#cppcheck --enable=unusedFunction --quiet $PANDA_DIR/board/ +IGNORED_PATHS=( + "$PANDA_DIR/board/obj" + "$PANDA_DIR/board/jungle" + "$PANDA_DIR/board/body" + "$PANDA_DIR/board/stm32h7/inc" + "$PANDA_DIR/board/fake_stm.h" + "$PANDA_DIR/board/fake_stm.c" + "$PANDA_DIR/board/flasher.h" + "$PANDA_DIR/board/flasher.c" + "$PANDA_DIR/board/bootstub.c" + "$PANDA_DIR/board/bootstub_declarations.h" + "$PANDA_DIR/board/stm32h7/llflash.h" + "$PANDA_DIR/board/stm32h7/llflash.c" +) + +# build the find prune expression +PRUNE_EXPR="" +for p in "${IGNORED_PATHS[@]}"; do + PRUNE_EXPR="$PRUNE_EXPR -path $p -prune -o" +done + +# find all .c files excluding ignored paths +C_FILES=$(eval "find $PANDA_DIR/board $PRUNE_EXPR -name '*.c' -print" | sort) + +cppcheck $PANDA_OPTS -DSTM32H7 -DSTM32H725xx -I $PANDA_DIR/board/stm32h7/inc/ -DPANDA $C_FILES printf "\n${GREEN}Success!${NC} took $SECONDS seconds\n" diff --git a/tests/misra/test_mutation.py b/tests/misra/test_mutation.py index c0d804863b8..724a8d7e0fc 100755 --- a/tests/misra/test_mutation.py +++ b/tests/misra/test_mutation.py @@ -15,10 +15,12 @@ 'board/jungle', 'board/body', 'board/stm32h7/inc', + 'board/fake_stm.c', 'board/fake_stm.h', # bootstub only files 'board/flasher.h', + 'board/flasher.c', 'board/bootstub.c', 'board/bootstub_declarations.h', 'board/stm32h7/llflash.h',