diff --git a/board/drivers/can.h b/board/drivers/can.h index 39958b03175ef2..da1226f3f3864f 100644 --- a/board/drivers/can.h +++ b/board/drivers/can.h @@ -372,6 +372,8 @@ void can_rx(uint8_t can_number) { } } +#ifndef CUSTOM_CAN_INTERRUPTS + void CAN1_TX_IRQHandler() { process_can(0); } void CAN1_RX0_IRQHandler() { can_rx(0); } void CAN1_SCE_IRQHandler() { can_sce(CAN1); } @@ -386,6 +388,8 @@ void CAN3_RX0_IRQHandler() { can_rx(2); } void CAN3_SCE_IRQHandler() { can_sce(CAN3); } #endif +#endif + void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) { if (safety_tx_hook(to_push)) { if (bus_number < BUS_MAX) { diff --git a/board/drivers/drivers.h b/board/drivers/drivers.h index ce1e860ceb8a80..d3409d60994eed 100644 --- a/board/drivers/drivers.h +++ b/board/drivers/drivers.h @@ -88,7 +88,7 @@ uint32_t adc_get(int channel); // ********************* DAC ********************* void dac_init(); -uint32_t dac_set(int channel, uint32_t value); +void dac_set(int channel, uint32_t value); // ********************* TIMER ********************* diff --git a/board/gpio.h b/board/gpio.h index 775a88df54c00c..7b2812e7b4a1e7 100644 --- a/board/gpio.h +++ b/board/gpio.h @@ -72,8 +72,15 @@ void clock_init() { RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE; #else - RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | - RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE; + #ifdef PEDAL + // comma pedal has a 16mhz crystal + RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | + RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE; + #else + // NEO board has a 8mhz crystal + RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | + RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE; + #endif #endif // start PLL @@ -132,8 +139,13 @@ void set_can_enable(CAN_TypeDef *CAN, int enabled) { // CAN1_EN set_gpio_output(GPIOC, 1, !enabled); #else - // CAN1_EN - set_gpio_output(GPIOB, 3, enabled); + #ifdef PEDAL + // CAN1_EN (not flipped) + set_gpio_output(GPIOB, 3, !enabled); + #else + // CAN1_EN + set_gpio_output(GPIOB, 3, enabled); + #endif #endif } else if (CAN == CAN2) { #ifdef PANDA @@ -285,6 +297,14 @@ void gpio_init() { set_gpio_mode(GPIOC, 2, MODE_ANALOG); set_gpio_mode(GPIOC, 3, MODE_ANALOG); +#ifdef PEDAL + // comma pedal has inputs on C0 and C1 + set_gpio_mode(GPIOC, 0, MODE_ANALOG); + set_gpio_mode(GPIOC, 1, MODE_ANALOG); + // DAC outputs on A4 and A5 + // apparently they don't need GPIO setup +#endif + // C8: FAN aka TIM3_CH4 set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); @@ -443,9 +463,10 @@ void early() { if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { + #ifdef PANDA set_esp_mode(ESP_DISABLED); + #endif set_led(LED_GREEN, 1); - jump_to_bootloader(); } diff --git a/board/pedal/.gitignore b/board/pedal/.gitignore new file mode 100644 index 00000000000000..94053f2925089b --- /dev/null +++ b/board/pedal/.gitignore @@ -0,0 +1 @@ +obj/* diff --git a/board/pedal/Makefile b/board/pedal/Makefile new file mode 100644 index 00000000000000..ed0ccbd3b031fc --- /dev/null +++ b/board/pedal/Makefile @@ -0,0 +1,32 @@ +# :set noet +PROJ_NAME = comma + +CFLAGS = -O2 -Wall -std=gnu11 +CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 +CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx +CFLAGS += -I ../inc -I ../ -nostdlib +CFLAGS += -T../stm32_flash.ld + +CC = arm-none-eabi-gcc +OBJCOPY = arm-none-eabi-objcopy +OBJDUMP = arm-none-eabi-objdump + +all: obj/$(PROJ_NAME).bin + #$(OBJDUMP) -d obj/$(PROJ_NAME).elf + dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D $< + +obj/main.o: main.c ../*.h + mkdir -p obj + $(CC) $(CFLAGS) -o $@ -c $< + +obj/startup_stm32f205xx.o: ../startup_stm32f205xx.s + mkdir -p obj + $(CC) $(CFLAGS) -o $@ -c $< + +obj/$(PROJ_NAME).bin: obj/startup_stm32f205xx.o obj/main.o + $(CC) $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ + $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf $@ + +clean: + rm -f obj/* + diff --git a/board/pedal/README b/board/pedal/README new file mode 100644 index 00000000000000..06a386b1e7fe64 --- /dev/null +++ b/board/pedal/README @@ -0,0 +1,6 @@ +This is the firmware for the comma pedal. It borrows a lot from panda. + +The comma pedal is a gas pedal interceptor for Honda/Acura. It allows you to "virtually" press the pedal. + +This is the open source software. Open source hardware coming soon. + diff --git a/board/pedal/main.c b/board/pedal/main.c new file mode 100644 index 00000000000000..d49f04601778f1 --- /dev/null +++ b/board/pedal/main.c @@ -0,0 +1,252 @@ +//#define DEBUG +//#define CAN_LOOPBACK_MODE +//#define USE_INTERNAL_OSC + +#define PEDAL + +#include "../config.h" + +#include "drivers/drivers.h" +#include "drivers/llgpio.h" +#include "gpio.h" + +#define CUSTOM_CAN_INTERRUPTS + +#include "libc.h" +#include "safety.h" +#include "drivers/adc.h" +#include "drivers/uart.h" +#include "drivers/dac.h" +#include "drivers/can.h" +#include "drivers/timer.h" + +#define CAN CAN1 + +//#define PEDAL_USB + +#ifdef PEDAL_USB + #include "drivers/usb.h" +#endif + +#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef +uint32_t enter_bootloader_mode; + +void __initialize_hardware_early() { + if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { + enter_bootloader_mode = 0; + void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *)0x1fff0004)); + bootloader(); + + // LOOP + while(1); + } +} + +// ********************* serial debugging ********************* + +void debug_ring_callback(uart_ring *ring) { + char rcv; + while (getc(ring, &rcv)) { + putc(ring, rcv); + } +} + +#ifdef PEDAL_USB + +int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) { return 0; } +void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {} +void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {} +void usb_cb_enumeration_complete() {} + +int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) { + int resp_len = 0; + uart_ring *ur = NULL; + switch (setup->b.bRequest) { + // **** 0xe0: uart read + case 0xe0: + ur = get_ring_by_number(setup->b.wValue.w); + if (!ur) break; + if (ur == &esp_ring) uart_dma_drain(); + // read + while ((resp_len < min(setup->b.wLength.w, MAX_RESP_LEN)) && + getc(ur, (char*)&resp[resp_len])) { + ++resp_len; + } + break; + } + return resp_len; +} + +#endif + +// ***************************** honda can checksum ***************************** + +int can_cksum(uint8_t *dat, int len, int addr, int idx) { + int i; + int s = 0; + for (i = 0; i < len; i++) { + s += (dat[i] >> 4); + s += dat[i] & 0xF; + } + s += (addr>>0)&0xF; + s += (addr>>4)&0xF; + s += (addr>>8)&0xF; + s += idx; + s = 8-s; + return s&0xF; +} + +// ***************************** can port ***************************** + +// addresses to be used on CAN +#define CAN_GAS_INPUT 0x200 +#define CAN_GAS_OUTPUT 0x201 + +void CAN1_TX_IRQHandler() { + // clear interrupt + CAN->TSR |= CAN_TSR_RQCP0; +} + +uint16_t gas_set = 0; +uint32_t timeout = 0; +uint32_t current_index = 0; + +void CAN1_RX0_IRQHandler() { + while (CAN->RF0R & CAN_RF0R_FMP0) { + #ifdef DEBUG + puts("CAN RX\n"); + #endif + uint32_t address = CAN->sFIFOMailBox[0].RIR>>21; + if (address == CAN_GAS_INPUT) { + uint8_t *dat = (uint8_t *)&CAN->sFIFOMailBox[0].RDLR; + uint16_t value = (dat[0] << 8) | dat[1]; + uint8_t index = (dat[2] >> 4) & 3; + if (can_cksum(dat, 2, CAN_GAS_INPUT, index) == (dat[2] & 0xF)) { + if (((current_index+1)&3) == index) { + // TODO: set and start timeout + #ifdef DEBUG + puts("setting gas "); + puth(value); + puts("\n"); + #endif + gas_set = value; + timeout = 0; + } + // TODO: better lockout? prevents same spam + current_index = index; + } + } + // next + CAN->RF0R |= CAN_RF0R_RFOM0; + } +} + +void CAN1_SCE_IRQHandler() { + can_sce(CAN); +} + +int pdl0 = 0, pdl1 = 0; +int pkt_idx = 0; + +int led_value = 0; + +void TIM3_IRQHandler() { + #ifdef DEBUG + puth(TIM3->CNT); + puts(" "); + puth(pdl0); + puts(" "); + puth(pdl1); + puts("\n"); + #endif + + // check timer for sending the user pedal and clearing the CAN + if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { + uint8_t *dat = (uint8_t *)&CAN->sTxMailBox[0].TDLR; + CAN->sTxMailBox[0].TDLR = (((pdl0>>8)&0xFF)<<0) | + (((pdl0>>0)&0xFF)<<8) | + (((pdl1>>8)&0xFF)<<16) | + (((pdl1>>0)&0xFF)<<24); + CAN->sTxMailBox[0].TDHR = can_cksum(dat, 4, CAN_GAS_OUTPUT, pkt_idx) | (pkt_idx << 4); + CAN->sTxMailBox[0].TDTR = 5; // len of packet is 4 + CAN->sTxMailBox[0].TIR = (CAN_GAS_OUTPUT << 21) | 1; + ++pkt_idx; + pkt_idx &= 3; + } else { + // old can packet hasn't sent! + // TODO: do something? + #ifdef DEBUG + puts("CAN MISS\n"); + #endif + } + + + // blink the LED + set_led(LED_GREEN, led_value); + led_value = !led_value; + + TIM3->SR = 0; + + // up timeout for gas set + timeout++; +} + +// ***************************** main code ***************************** + +void pedal() { + // read/write + pdl0 = adc_get(ADCCHAN_ACCEL0); + pdl1 = adc_get(ADCCHAN_ACCEL1); + + // write the pedal to the DAC + if (timeout < 10) { + dac_set(0, max(gas_set, pdl0)); + dac_set(1, max(gas_set*2, pdl1)); + } else { + dac_set(0, pdl0); + dac_set(1, pdl1); + } +} + +int main() { + __disable_irq(); + + // init devices + clock_init(); + periph_init(); + gpio_init(); + +#ifdef PEDAL_USB + // enable USB + usb_init(); +#endif + + // pedal stuff + dac_init(); + adc_init(); + + // init can + can_silent = ALL_CAN_LIVE; + can_init_all(); + + // 48mhz / 65536 ~= 732 + timer_init(TIM3, 15); + + // needed? + NVIC_EnableIRQ(CAN1_TX_IRQn); + NVIC_EnableIRQ(CAN1_RX0_IRQn); + NVIC_EnableIRQ(CAN1_SCE_IRQn); + + NVIC_EnableIRQ(TIM3_IRQn); + + puts("**** INTERRUPTS ON ****\n"); + __enable_irq(); + + // main pedal loop + while (1) { + pedal(); + } + + return 0; +} + diff --git a/tests/can_printer.py b/tests/can_printer.py index a74a548109269b..fe1ea42e79d4f4 100755 --- a/tests/can_printer.py +++ b/tests/can_printer.py @@ -28,7 +28,7 @@ def can_printer(): if sec_since_boot() - lp > 0.1: dd = chr(27) + "[2J" dd += "%5.2f\n" % (sec_since_boot() - start) - for k,v in sorted(zip(msgs.keys(), map(lambda x: x[-1].encode("hex"), msgs.values()))): + for k,v in sorted(zip(msgs.keys(), map(lambda x: str(x[-1]).encode("hex"), msgs.values()))): dd += "%s(%6d) %s\n" % ("%04X(%4d)" % (k,k),len(msgs[k]), v) print(dd) lp = sec_since_boot()