Skip to content

Commit fbcc872

Browse files
authored
Merge pull request #92 from commaai/pedal
Pedal
2 parents 08f464c + 8a6f44b commit fbcc872

File tree

8 files changed

+323
-7
lines changed

8 files changed

+323
-7
lines changed

board/drivers/can.h

+4
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,8 @@ void can_rx(uint8_t can_number) {
372372
}
373373
}
374374

375+
#ifndef CUSTOM_CAN_INTERRUPTS
376+
375377
void CAN1_TX_IRQHandler() { process_can(0); }
376378
void CAN1_RX0_IRQHandler() { can_rx(0); }
377379
void CAN1_SCE_IRQHandler() { can_sce(CAN1); }
@@ -386,6 +388,8 @@ void CAN3_RX0_IRQHandler() { can_rx(2); }
386388
void CAN3_SCE_IRQHandler() { can_sce(CAN3); }
387389
#endif
388390

391+
#endif
392+
389393
void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number) {
390394
if (safety_tx_hook(to_push)) {
391395
if (bus_number < BUS_MAX) {

board/drivers/drivers.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ uint32_t adc_get(int channel);
8888
// ********************* DAC *********************
8989

9090
void dac_init();
91-
uint32_t dac_set(int channel, uint32_t value);
91+
void dac_set(int channel, uint32_t value);
9292

9393

9494
// ********************* TIMER *********************

board/gpio.h

+26-5
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,15 @@ void clock_init() {
7272
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
7373
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
7474
#else
75-
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
76-
RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE;
75+
#ifdef PEDAL
76+
// comma pedal has a 16mhz crystal
77+
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
78+
RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE;
79+
#else
80+
// NEO board has a 8mhz crystal
81+
RCC->PLLCFGR = RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 |
82+
RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLSRC_HSE;
83+
#endif
7784
#endif
7885

7986
// start PLL
@@ -132,8 +139,13 @@ void set_can_enable(CAN_TypeDef *CAN, int enabled) {
132139
// CAN1_EN
133140
set_gpio_output(GPIOC, 1, !enabled);
134141
#else
135-
// CAN1_EN
136-
set_gpio_output(GPIOB, 3, enabled);
142+
#ifdef PEDAL
143+
// CAN1_EN (not flipped)
144+
set_gpio_output(GPIOB, 3, !enabled);
145+
#else
146+
// CAN1_EN
147+
set_gpio_output(GPIOB, 3, enabled);
148+
#endif
137149
#endif
138150
} else if (CAN == CAN2) {
139151
#ifdef PANDA
@@ -285,6 +297,14 @@ void gpio_init() {
285297
set_gpio_mode(GPIOC, 2, MODE_ANALOG);
286298
set_gpio_mode(GPIOC, 3, MODE_ANALOG);
287299

300+
#ifdef PEDAL
301+
// comma pedal has inputs on C0 and C1
302+
set_gpio_mode(GPIOC, 0, MODE_ANALOG);
303+
set_gpio_mode(GPIOC, 1, MODE_ANALOG);
304+
// DAC outputs on A4 and A5
305+
// apparently they don't need GPIO setup
306+
#endif
307+
288308
// C8: FAN aka TIM3_CH4
289309
set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3);
290310

@@ -443,9 +463,10 @@ void early() {
443463

444464

445465
if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) {
466+
#ifdef PANDA
446467
set_esp_mode(ESP_DISABLED);
468+
#endif
447469
set_led(LED_GREEN, 1);
448-
449470
jump_to_bootloader();
450471
}
451472

board/pedal/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
obj/*

board/pedal/Makefile

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# :set noet
2+
PROJ_NAME = comma
3+
4+
CFLAGS = -O2 -Wall -std=gnu11
5+
CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3
6+
CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx
7+
CFLAGS += -I ../inc -I ../ -nostdlib
8+
CFLAGS += -T../stm32_flash.ld
9+
10+
CC = arm-none-eabi-gcc
11+
OBJCOPY = arm-none-eabi-objcopy
12+
OBJDUMP = arm-none-eabi-objdump
13+
14+
all: obj/$(PROJ_NAME).bin
15+
#$(OBJDUMP) -d obj/$(PROJ_NAME).elf
16+
dfu-util -d 0483:df11 -a 0 -s 0x08000000:leave -D $<
17+
18+
obj/main.o: main.c ../*.h
19+
mkdir -p obj
20+
$(CC) $(CFLAGS) -o $@ -c $<
21+
22+
obj/startup_stm32f205xx.o: ../startup_stm32f205xx.s
23+
mkdir -p obj
24+
$(CC) $(CFLAGS) -o $@ -c $<
25+
26+
obj/$(PROJ_NAME).bin: obj/startup_stm32f205xx.o obj/main.o
27+
$(CC) $(CFLAGS) -o obj/$(PROJ_NAME).elf $^
28+
$(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf $@
29+
30+
clean:
31+
rm -f obj/*
32+

board/pedal/README

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
This is the firmware for the comma pedal. It borrows a lot from panda.
2+
3+
The comma pedal is a gas pedal interceptor for Honda/Acura. It allows you to "virtually" press the pedal.
4+
5+
This is the open source software. Open source hardware coming soon.
6+

board/pedal/main.c

+252
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
//#define DEBUG
2+
//#define CAN_LOOPBACK_MODE
3+
//#define USE_INTERNAL_OSC
4+
5+
#define PEDAL
6+
7+
#include "../config.h"
8+
9+
#include "drivers/drivers.h"
10+
#include "drivers/llgpio.h"
11+
#include "gpio.h"
12+
13+
#define CUSTOM_CAN_INTERRUPTS
14+
15+
#include "libc.h"
16+
#include "safety.h"
17+
#include "drivers/adc.h"
18+
#include "drivers/uart.h"
19+
#include "drivers/dac.h"
20+
#include "drivers/can.h"
21+
#include "drivers/timer.h"
22+
23+
#define CAN CAN1
24+
25+
//#define PEDAL_USB
26+
27+
#ifdef PEDAL_USB
28+
#include "drivers/usb.h"
29+
#endif
30+
31+
#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef
32+
uint32_t enter_bootloader_mode;
33+
34+
void __initialize_hardware_early() {
35+
if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) {
36+
enter_bootloader_mode = 0;
37+
void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *)0x1fff0004));
38+
bootloader();
39+
40+
// LOOP
41+
while(1);
42+
}
43+
}
44+
45+
// ********************* serial debugging *********************
46+
47+
void debug_ring_callback(uart_ring *ring) {
48+
char rcv;
49+
while (getc(ring, &rcv)) {
50+
putc(ring, rcv);
51+
}
52+
}
53+
54+
#ifdef PEDAL_USB
55+
56+
int usb_cb_ep1_in(uint8_t *usbdata, int len, int hardwired) { return 0; }
57+
void usb_cb_ep2_out(uint8_t *usbdata, int len, int hardwired) {}
58+
void usb_cb_ep3_out(uint8_t *usbdata, int len, int hardwired) {}
59+
void usb_cb_enumeration_complete() {}
60+
61+
int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
62+
int resp_len = 0;
63+
uart_ring *ur = NULL;
64+
switch (setup->b.bRequest) {
65+
// **** 0xe0: uart read
66+
case 0xe0:
67+
ur = get_ring_by_number(setup->b.wValue.w);
68+
if (!ur) break;
69+
if (ur == &esp_ring) uart_dma_drain();
70+
// read
71+
while ((resp_len < min(setup->b.wLength.w, MAX_RESP_LEN)) &&
72+
getc(ur, (char*)&resp[resp_len])) {
73+
++resp_len;
74+
}
75+
break;
76+
}
77+
return resp_len;
78+
}
79+
80+
#endif
81+
82+
// ***************************** honda can checksum *****************************
83+
84+
int can_cksum(uint8_t *dat, int len, int addr, int idx) {
85+
int i;
86+
int s = 0;
87+
for (i = 0; i < len; i++) {
88+
s += (dat[i] >> 4);
89+
s += dat[i] & 0xF;
90+
}
91+
s += (addr>>0)&0xF;
92+
s += (addr>>4)&0xF;
93+
s += (addr>>8)&0xF;
94+
s += idx;
95+
s = 8-s;
96+
return s&0xF;
97+
}
98+
99+
// ***************************** can port *****************************
100+
101+
// addresses to be used on CAN
102+
#define CAN_GAS_INPUT 0x200
103+
#define CAN_GAS_OUTPUT 0x201
104+
105+
void CAN1_TX_IRQHandler() {
106+
// clear interrupt
107+
CAN->TSR |= CAN_TSR_RQCP0;
108+
}
109+
110+
uint16_t gas_set = 0;
111+
uint32_t timeout = 0;
112+
uint32_t current_index = 0;
113+
114+
void CAN1_RX0_IRQHandler() {
115+
while (CAN->RF0R & CAN_RF0R_FMP0) {
116+
#ifdef DEBUG
117+
puts("CAN RX\n");
118+
#endif
119+
uint32_t address = CAN->sFIFOMailBox[0].RIR>>21;
120+
if (address == CAN_GAS_INPUT) {
121+
uint8_t *dat = (uint8_t *)&CAN->sFIFOMailBox[0].RDLR;
122+
uint16_t value = (dat[0] << 8) | dat[1];
123+
uint8_t index = (dat[2] >> 4) & 3;
124+
if (can_cksum(dat, 2, CAN_GAS_INPUT, index) == (dat[2] & 0xF)) {
125+
if (((current_index+1)&3) == index) {
126+
// TODO: set and start timeout
127+
#ifdef DEBUG
128+
puts("setting gas ");
129+
puth(value);
130+
puts("\n");
131+
#endif
132+
gas_set = value;
133+
timeout = 0;
134+
}
135+
// TODO: better lockout? prevents same spam
136+
current_index = index;
137+
}
138+
}
139+
// next
140+
CAN->RF0R |= CAN_RF0R_RFOM0;
141+
}
142+
}
143+
144+
void CAN1_SCE_IRQHandler() {
145+
can_sce(CAN);
146+
}
147+
148+
int pdl0 = 0, pdl1 = 0;
149+
int pkt_idx = 0;
150+
151+
int led_value = 0;
152+
153+
void TIM3_IRQHandler() {
154+
#ifdef DEBUG
155+
puth(TIM3->CNT);
156+
puts(" ");
157+
puth(pdl0);
158+
puts(" ");
159+
puth(pdl1);
160+
puts("\n");
161+
#endif
162+
163+
// check timer for sending the user pedal and clearing the CAN
164+
if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) {
165+
uint8_t *dat = (uint8_t *)&CAN->sTxMailBox[0].TDLR;
166+
CAN->sTxMailBox[0].TDLR = (((pdl0>>8)&0xFF)<<0) |
167+
(((pdl0>>0)&0xFF)<<8) |
168+
(((pdl1>>8)&0xFF)<<16) |
169+
(((pdl1>>0)&0xFF)<<24);
170+
CAN->sTxMailBox[0].TDHR = can_cksum(dat, 4, CAN_GAS_OUTPUT, pkt_idx) | (pkt_idx << 4);
171+
CAN->sTxMailBox[0].TDTR = 5; // len of packet is 4
172+
CAN->sTxMailBox[0].TIR = (CAN_GAS_OUTPUT << 21) | 1;
173+
++pkt_idx;
174+
pkt_idx &= 3;
175+
} else {
176+
// old can packet hasn't sent!
177+
// TODO: do something?
178+
#ifdef DEBUG
179+
puts("CAN MISS\n");
180+
#endif
181+
}
182+
183+
184+
// blink the LED
185+
set_led(LED_GREEN, led_value);
186+
led_value = !led_value;
187+
188+
TIM3->SR = 0;
189+
190+
// up timeout for gas set
191+
timeout++;
192+
}
193+
194+
// ***************************** main code *****************************
195+
196+
void pedal() {
197+
// read/write
198+
pdl0 = adc_get(ADCCHAN_ACCEL0);
199+
pdl1 = adc_get(ADCCHAN_ACCEL1);
200+
201+
// write the pedal to the DAC
202+
if (timeout < 10) {
203+
dac_set(0, max(gas_set, pdl0));
204+
dac_set(1, max(gas_set*2, pdl1));
205+
} else {
206+
dac_set(0, pdl0);
207+
dac_set(1, pdl1);
208+
}
209+
}
210+
211+
int main() {
212+
__disable_irq();
213+
214+
// init devices
215+
clock_init();
216+
periph_init();
217+
gpio_init();
218+
219+
#ifdef PEDAL_USB
220+
// enable USB
221+
usb_init();
222+
#endif
223+
224+
// pedal stuff
225+
dac_init();
226+
adc_init();
227+
228+
// init can
229+
can_silent = ALL_CAN_LIVE;
230+
can_init_all();
231+
232+
// 48mhz / 65536 ~= 732
233+
timer_init(TIM3, 15);
234+
235+
// needed?
236+
NVIC_EnableIRQ(CAN1_TX_IRQn);
237+
NVIC_EnableIRQ(CAN1_RX0_IRQn);
238+
NVIC_EnableIRQ(CAN1_SCE_IRQn);
239+
240+
NVIC_EnableIRQ(TIM3_IRQn);
241+
242+
puts("**** INTERRUPTS ON ****\n");
243+
__enable_irq();
244+
245+
// main pedal loop
246+
while (1) {
247+
pedal();
248+
}
249+
250+
return 0;
251+
}
252+

tests/can_printer.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def can_printer():
2828
if sec_since_boot() - lp > 0.1:
2929
dd = chr(27) + "[2J"
3030
dd += "%5.2f\n" % (sec_since_boot() - start)
31-
for k,v in sorted(zip(msgs.keys(), map(lambda x: x[-1].encode("hex"), msgs.values()))):
31+
for k,v in sorted(zip(msgs.keys(), map(lambda x: str(x[-1]).encode("hex"), msgs.values()))):
3232
dd += "%s(%6d) %s\n" % ("%04X(%4d)" % (k,k),len(msgs[k]), v)
3333
print(dd)
3434
lp = sec_since_boot()

0 commit comments

Comments
 (0)