support can speed, and test it
parent
9f7bbcf487
commit
85c0940cf9
|
@ -1,3 +1 @@
|
||||||
""" Hack to support openpilot import scheme """
|
from .panda import Panda
|
||||||
|
|
||||||
from .panda import Panda, PandaHashMismatchException
|
|
||||||
|
|
54
board/can.h
54
board/can.h
|
@ -1,3 +1,47 @@
|
||||||
|
// assign CAN numbering
|
||||||
|
// bus num: Can bus number on ODB connector. Sent to/from USB
|
||||||
|
// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1)
|
||||||
|
// cans: Look up MCU can interface from bus number
|
||||||
|
// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc);
|
||||||
|
// bus_lookup: Translates from 'can number' to 'bus number'.
|
||||||
|
// can_num_lookup: Translates from 'bus number' to 'can number'.
|
||||||
|
// can_forwarding: Given a bus num, lookup bus num to forward to. -1 means no forward.
|
||||||
|
|
||||||
|
|
||||||
|
// NEO: Bus 1=CAN1 Bus 2=CAN2
|
||||||
|
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
|
||||||
|
#ifdef PANDA
|
||||||
|
CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3};
|
||||||
|
uint8_t bus_lookup[] = {0,1,2};
|
||||||
|
uint8_t can_num_lookup[] = {0,1,2}; //bus num -> can num
|
||||||
|
int8_t can_forwarding[] = {-1,-1,-1};
|
||||||
|
uint32_t can_speed[] = {5000, 5000, 5000}; // 500 kbps
|
||||||
|
#define CAN_MAX 3
|
||||||
|
#else
|
||||||
|
CAN_TypeDef *cans[] = {CAN2, CAN1};
|
||||||
|
uint8_t bus_lookup[] = {1,0};
|
||||||
|
uint8_t can_num_lookup[] = {1,0}; //bus num -> can num
|
||||||
|
int8_t can_forwarding[] = {-1,-1};
|
||||||
|
uint32_t can_speed[] = {5000, 5000};
|
||||||
|
#define CAN_MAX 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NO_ACTIVE_GMLAN -1
|
||||||
|
int active_gmlan_port_id = NO_ACTIVE_GMLAN;
|
||||||
|
|
||||||
|
#define CANIF_FROM_CAN_NUM(num) (cans[bus_lookup[num]])
|
||||||
|
#define CANIF_FROM_BUS_NUM(num) (cans[num])
|
||||||
|
#define BUS_NUM_FROM_CAN_NUM(num) (bus_lookup[num])
|
||||||
|
#define CAN_NUM_FROM_BUS_NUM(num) (can_num_lookup[num])
|
||||||
|
|
||||||
|
#define CAN_BUS_RET_FLAG 0x80
|
||||||
|
#define CAN_BUS_NUM_MASK 0x7F
|
||||||
|
|
||||||
|
#define CAN_PCLK 24000
|
||||||
|
// 333 = 33.3 kbps
|
||||||
|
// 5000 = 500 kbps
|
||||||
|
#define can_speed_to_prescaler(x) (CAN_PCLK / 16 * 10 / x)
|
||||||
|
|
||||||
void can_init(uint8_t bus_number) {
|
void can_init(uint8_t bus_number) {
|
||||||
CAN_TypeDef *CAN = CANIF_FROM_BUS_NUM(bus_number);
|
CAN_TypeDef *CAN = CANIF_FROM_BUS_NUM(bus_number);
|
||||||
set_can_enable(CAN, 1);
|
set_can_enable(CAN, 1);
|
||||||
|
@ -5,17 +49,9 @@ void can_init(uint8_t bus_number) {
|
||||||
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ;
|
CAN->MCR = CAN_MCR_TTCM | CAN_MCR_INRQ;
|
||||||
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
|
while((CAN->MSR & CAN_MSR_INAK) != CAN_MSR_INAK);
|
||||||
|
|
||||||
// http://www.bittiming.can-wiki.info/
|
|
||||||
// PCLK = 24 MHz
|
|
||||||
uint32_t pclk = 24000;
|
|
||||||
uint32_t num_time_quanta = 16;
|
|
||||||
|
|
||||||
// 500 kbps
|
|
||||||
uint32_t prescaler = pclk / num_time_quanta / 500;
|
|
||||||
|
|
||||||
// seg 1: 13 time quanta, seg 2: 2 time quanta
|
// seg 1: 13 time quanta, seg 2: 2 time quanta
|
||||||
CAN->BTR = (CAN_BTR_TS1_0 * 12) |
|
CAN->BTR = (CAN_BTR_TS1_0 * 12) |
|
||||||
CAN_BTR_TS2_0 | (prescaler - 1);
|
CAN_BTR_TS2_0 | (can_speed_to_prescaler(can_speed[bus_number]) - 1);
|
||||||
|
|
||||||
// silent loopback mode for debugging
|
// silent loopback mode for debugging
|
||||||
if (can_loopback) {
|
if (can_loopback) {
|
||||||
|
|
97
board/main.c
97
board/main.c
|
@ -7,39 +7,6 @@
|
||||||
#define COMPILE_TIME_ASSERT(pred) \
|
#define COMPILE_TIME_ASSERT(pred) \
|
||||||
switch(0){case 0:case pred:;}
|
switch(0){case 0:case pred:;}
|
||||||
|
|
||||||
// assign CAN numbering
|
|
||||||
// bus num: Can bus number on ODB connector. Sent to/from USB
|
|
||||||
// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1)
|
|
||||||
// cans: Look up MCU can interface from bus number
|
|
||||||
// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc);
|
|
||||||
// bus_lookup: Translates from 'can number' to 'bus number'.
|
|
||||||
// can_num_lookup: Translates from 'bus number' to 'can number'.
|
|
||||||
// can_forwarding: Given a bus num, lookup bus num to forward to. -1 means no forward.
|
|
||||||
|
|
||||||
// NEO: Bus 1=CAN1 Bus 2=CAN2
|
|
||||||
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
|
|
||||||
#ifdef PANDA
|
|
||||||
CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3};
|
|
||||||
uint8_t bus_lookup[] = {0,1,2};
|
|
||||||
uint8_t can_num_lookup[] = {0,1,2}; //bus num -> can num
|
|
||||||
int8_t can_forwarding[] = {-1,-1,-1};
|
|
||||||
#define CAN_MAX 3
|
|
||||||
#else
|
|
||||||
CAN_TypeDef *cans[] = {CAN2, CAN1};
|
|
||||||
uint8_t bus_lookup[] = {1,0};
|
|
||||||
uint8_t can_num_lookup[] = {1,0}; //bus num -> can num
|
|
||||||
int8_t can_forwarding[] = {-1,-1};
|
|
||||||
#define CAN_MAX 2
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define CANIF_FROM_CAN_NUM(num) (cans[bus_lookup[num]])
|
|
||||||
#define CANIF_FROM_BUS_NUM(num) (cans[num])
|
|
||||||
#define BUS_NUM_FROM_CAN_NUM(num) (bus_lookup[num])
|
|
||||||
#define CAN_NUM_FROM_BUS_NUM(num) (can_num_lookup[num])
|
|
||||||
|
|
||||||
#define CAN_BUS_RET_FLAG 0x80
|
|
||||||
#define CAN_BUS_NUM_MASK 0x7F
|
|
||||||
|
|
||||||
// *** end config ***
|
// *** end config ***
|
||||||
|
|
||||||
#include "obj/gitversion.h"
|
#include "obj/gitversion.h"
|
||||||
|
@ -312,21 +279,6 @@ void process_can(uint8_t can_number) {
|
||||||
CAN->TSR |= CAN_TSR_RQCP0;
|
CAN->TSR |= CAN_TSR_RQCP0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// send more, possible for these to not trigger?
|
|
||||||
|
|
||||||
|
|
||||||
void CAN1_TX_IRQHandler() {
|
|
||||||
process_can(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAN2_TX_IRQHandler() {
|
|
||||||
process_can(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAN3_TX_IRQHandler() {
|
|
||||||
process_can(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void send_can(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number);
|
void send_can(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number);
|
||||||
|
|
||||||
// CAN receive handlers
|
// CAN receive handlers
|
||||||
|
@ -372,39 +324,18 @@ void can_rx(uint8_t can_number) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAN1_RX0_IRQHandler() {
|
void CAN1_TX_IRQHandler() { process_can(0); }
|
||||||
//puts("CANRX1");
|
void CAN1_RX0_IRQHandler() { can_rx(0); }
|
||||||
//delay(10000);
|
void CAN1_SCE_IRQHandler() { can_sce(CAN1); }
|
||||||
can_rx(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAN2_RX0_IRQHandler() {
|
void CAN2_TX_IRQHandler() { process_can(1); }
|
||||||
//puts("CANRX0");
|
void CAN2_RX0_IRQHandler() { can_rx(1); }
|
||||||
//delay(10000);
|
void CAN2_SCE_IRQHandler() { can_sce(CAN2); }
|
||||||
can_rx(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAN3_RX0_IRQHandler() {
|
|
||||||
//puts("CANRX0");
|
|
||||||
//delay(10000);
|
|
||||||
can_rx(2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAN1_SCE_IRQHandler() {
|
|
||||||
//puts("CAN1_SCE\n");
|
|
||||||
can_sce(CAN1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CAN2_SCE_IRQHandler() {
|
|
||||||
//puts("CAN2_SCE\n");
|
|
||||||
can_sce(CAN2);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef CAN3
|
#ifdef CAN3
|
||||||
void CAN3_SCE_IRQHandler() {
|
void CAN3_TX_IRQHandler() { process_can(2); }
|
||||||
//puts("CAN3_SCE\n");
|
void CAN3_RX0_IRQHandler() { can_rx(2); }
|
||||||
can_sce(CAN3);
|
void CAN3_SCE_IRQHandler() { can_sce(CAN3); }
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
@ -603,6 +534,13 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
|
||||||
can_forwarding[setup->b.wValue.w] = -1;
|
can_forwarding[setup->b.wValue.w] = -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
// **** 0xde: set can bitrate
|
||||||
|
case 0xde:
|
||||||
|
if (setup->b.wValue.w < CAN_MAX) {
|
||||||
|
can_speed[setup->b.wValue.w] = setup->b.wIndex.w;
|
||||||
|
can_init(setup->b.wValue.w);
|
||||||
|
}
|
||||||
|
break;
|
||||||
// **** 0xe0: uart read
|
// **** 0xe0: uart read
|
||||||
case 0xe0:
|
case 0xe0:
|
||||||
ur = get_ring_by_number(setup->b.wValue.w);
|
ur = get_ring_by_number(setup->b.wValue.w);
|
||||||
|
@ -652,7 +590,8 @@ int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, int hardwired) {
|
||||||
can_loopback = (setup->b.wValue.w > 0);
|
can_loopback = (setup->b.wValue.w > 0);
|
||||||
can_init_all();
|
can_init_all();
|
||||||
break;
|
break;
|
||||||
case 0xf0: // k-line wValue pulse on uart2
|
// **** 0xf0: do k-line wValue pulse on uart2 for Acura
|
||||||
|
case 0xf0:
|
||||||
if (setup->b.wValue.w == 1) {
|
if (setup->b.wValue.w == 1) {
|
||||||
GPIOC->ODR &= ~(1 << 10);
|
GPIOC->ODR &= ~(1 << 10);
|
||||||
GPIOC->MODER &= ~GPIO_MODER_MODER10_1;
|
GPIOC->MODER &= ~GPIO_MODER_MODER10_1;
|
||||||
|
|
|
@ -10,12 +10,6 @@ import time
|
||||||
|
|
||||||
__version__ = '0.0.3'
|
__version__ = '0.0.3'
|
||||||
|
|
||||||
class PandaHashMismatchException(Exception):
|
|
||||||
def __init__(self, hash_, expected_hash):
|
|
||||||
super(PandaHashMismatchException, self).__init__(
|
|
||||||
"Hash '%s' did not match the expected hash '%s'"%\
|
|
||||||
(binascii.hexlify(hash_), binascii.hexlify(expected_hash)))
|
|
||||||
|
|
||||||
def parse_can_buffer(dat):
|
def parse_can_buffer(dat):
|
||||||
ret = []
|
ret = []
|
||||||
for j in range(0, len(dat), 0x10):
|
for j in range(0, len(dat), 0x10):
|
||||||
|
@ -153,8 +147,7 @@ class Panda(object):
|
||||||
def get_serial(self):
|
def get_serial(self):
|
||||||
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 0, 0, 0x20)
|
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xd0, 0, 0, 0x20)
|
||||||
hashsig, calc_hash = dat[0x1c:], hashlib.sha1(dat[0:0x1c]).digest()[0:4]
|
hashsig, calc_hash = dat[0x1c:], hashlib.sha1(dat[0:0x1c]).digest()[0:4]
|
||||||
if hashsig != calc_hash:
|
assert(hashsig == calc_hash)
|
||||||
raise PandaHashMismatchException(calc_hash, hashsig)
|
|
||||||
return [dat[0:0x10], dat[0x10:0x10+10]]
|
return [dat[0:0x10], dat[0x10:0x10+10]]
|
||||||
|
|
||||||
def get_secret(self):
|
def get_secret(self):
|
||||||
|
@ -179,6 +172,9 @@ class Panda(object):
|
||||||
# set can loopback mode for all buses
|
# set can loopback mode for all buses
|
||||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'')
|
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe5, int(enable), 0, b'')
|
||||||
|
|
||||||
|
def set_can_speed_kbps(self, bus, speed):
|
||||||
|
self._handle.controlWrite(Panda.REQUEST_OUT, 0xde, bus, int(speed*10), b'')
|
||||||
|
|
||||||
def set_uart_baud(self, uart, rate):
|
def set_uart_baud(self, uart, rate):
|
||||||
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe1, uart, rate, b'')
|
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe1, uart, rate, b'')
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
nosetests -s tests/automated/*.py
|
nosetests -x -s tests/automated/*.py
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import time
|
import time
|
||||||
from panda import Panda
|
from panda import Panda
|
||||||
|
from nose.tools import timed, assert_equal, assert_less
|
||||||
|
|
||||||
# must run first
|
# must run first
|
||||||
def test_build_download_connect():
|
def test_build_download_connect():
|
||||||
|
@ -27,11 +28,14 @@ def test_can_loopback():
|
||||||
# enable CAN loopback mode
|
# enable CAN loopback mode
|
||||||
p.set_can_loopback(True)
|
p.set_can_loopback(True)
|
||||||
|
|
||||||
|
# set bus 0 speed to 250
|
||||||
|
p.set_can_speed_kbps(0, 250)
|
||||||
|
|
||||||
# send a message on bus 0
|
# send a message on bus 0
|
||||||
p.can_send(0x1aa, "message", 0)
|
p.can_send(0x1aa, "message", 0)
|
||||||
|
|
||||||
# confirm receive both on loopback and send receipt
|
# confirm receive both on loopback and send receipt
|
||||||
time.sleep(0.1)
|
time.sleep(0.05)
|
||||||
r = p.can_recv()
|
r = p.can_recv()
|
||||||
sr = filter(lambda x: x[3] == 0x80, r)
|
sr = filter(lambda x: x[3] == 0x80, r)
|
||||||
lb = filter(lambda x: x[3] == 0, r)
|
lb = filter(lambda x: x[3] == 0, r)
|
||||||
|
@ -55,7 +59,38 @@ def test_safety_nooutput():
|
||||||
p.can_send(0x1aa, "message", 0)
|
p.can_send(0x1aa, "message", 0)
|
||||||
|
|
||||||
# confirm receive nothing
|
# confirm receive nothing
|
||||||
time.sleep(0.1)
|
time.sleep(0.05)
|
||||||
r = p.can_recv()
|
r = p.can_recv()
|
||||||
assert len(r) == 0
|
assert len(r) == 0
|
||||||
|
|
||||||
|
def test_throughput():
|
||||||
|
p = connect_wo_esp()
|
||||||
|
|
||||||
|
# enable output mode
|
||||||
|
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
|
||||||
|
|
||||||
|
# enable CAN loopback mode
|
||||||
|
p.set_can_loopback(True)
|
||||||
|
|
||||||
|
for speed in [100,250,500,1000]:
|
||||||
|
# set bus 0 speed to speed
|
||||||
|
p.set_can_speed_kbps(0, speed)
|
||||||
|
time.sleep(0.05)
|
||||||
|
|
||||||
|
st = time.time()
|
||||||
|
for i in range(100):
|
||||||
|
# send a message on bus 0
|
||||||
|
p.can_send(0x1aa, "message", 0)
|
||||||
|
r = []
|
||||||
|
while len(r) < 200 and (time.time() - st) < 3:
|
||||||
|
r.extend(p.can_recv())
|
||||||
|
assert_equal(len(r), 200)
|
||||||
|
et = (time.time()-st)*1000.0
|
||||||
|
mt = (20000.0/speed)
|
||||||
|
assert_less(et, mt)
|
||||||
|
print "loopback 100 messages at speed %d in %.2f ms < %.2f ms" % (speed, et, mt)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue