Skip to content

Commit

Permalink
CAN-FD non-ISO support (commaai#1082)
Browse files Browse the repository at this point in the history
CAN FD non-ISO support
  • Loading branch information
gregjhogan authored Oct 12, 2022
1 parent ffb3109 commit 2f3e282
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 66 deletions.
9 changes: 5 additions & 4 deletions board/drivers/can_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ typedef struct {
uint32_t can_data_speed;
bool canfd_enabled;
bool brs_enabled;
bool canfd_non_iso;
} bus_config_t;

uint32_t safety_tx_blocked = 0;
Expand Down Expand Up @@ -155,10 +156,10 @@ void can_clear(can_ring *q) {
// Helpers
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
bus_config_t bus_config[] = {
{ .bus_lookup = 0U, .can_num_lookup = 0U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .can_speed = 333U, .can_data_speed = 333U, .canfd_enabled = false, .brs_enabled = false },
{ .bus_lookup = 0U, .can_num_lookup = 0U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .can_speed = 333U, .can_data_speed = 333U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
};

#define CANIF_FROM_CAN_NUM(num) (cans[num])
Expand Down
1 change: 1 addition & 0 deletions board/drivers/fdcan.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ bool can_set_speed(uint8_t can_number) {
CANx,
bus_config[bus_number].can_speed,
bus_config[bus_number].can_data_speed,
bus_config[bus_number].canfd_non_iso,
can_loopback,
(unsigned int)(can_silent) & (1U << can_number)
);
Expand Down
3 changes: 2 additions & 1 deletion board/health.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ struct __attribute__((packed)) health_t {
uint8_t safety_rx_checks_invalid;
};

#define CAN_HEALTH_PACKET_VERSION 2
#define CAN_HEALTH_PACKET_VERSION 3
typedef struct __attribute__((packed)) {
uint8_t bus_off;
uint32_t bus_off_cnt;
Expand All @@ -50,4 +50,5 @@ typedef struct __attribute__((packed)) {
uint16_t can_data_speed;
uint8_t canfd_enabled;
uint8_t brs_enabled;
uint8_t canfd_non_iso;
} can_health_t;
19 changes: 10 additions & 9 deletions board/main_comms.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
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);
}
Expand Down Expand Up @@ -534,7 +535,7 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
heartbeat_disabled = true;
}
break;
// **** 0xde: set CAN FD data bitrate
// **** 0xf9: set CAN FD data bitrate
case 0xf9:
if ((req->param1 < CAN_CNT) &&
current_board->has_canfd &&
Expand All @@ -546,18 +547,18 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
UNUSED(ret);
}
break;
// **** 0xfa: check if CAN FD and BRS are enabled
case 0xfa:
if (req->param1 < CAN_CNT) {
resp[0] = bus_config[req->param1].canfd_enabled;
resp[1] = bus_config[req->param1].brs_enabled;
resp_len = 2;
}
break;
// **** 0xfb: allow highest power saving mode (stop) to be entered
case 0xfb:
deepsleep_allowed = true;
break;
// **** 0xfc: set CAN FD non-ISO mode
case 0xfc:
if ((req->param1 < CAN_CNT) && current_board->has_canfd) {
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:
puts("NO HANDLER ");
puth(req->request);
Expand Down
8 changes: 7 additions & 1 deletion board/stm32h7/llfdcan.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ bool fdcan_exit_init(FDCAN_GlobalTypeDef *CANx) {
return ret;
}

bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_speed, bool loopback, bool silent) {
bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_speed, bool non_iso, bool loopback, bool silent) {
UNUSED(speed);
bool ret = fdcan_request_init(CANx);

Expand All @@ -97,6 +97,7 @@ bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_sp
CANx->TEST &= ~(FDCAN_TEST_LBCK);
CANx->CCCR &= ~(FDCAN_CCCR_MON);
CANx->CCCR &= ~(FDCAN_CCCR_ASM);
CANx->CCCR &= ~(FDCAN_CCCR_NISO);

// TODO: add as a separate safety mode
// Enable ASM restricted operation(for debug or automatic bitrate switching)
Expand Down Expand Up @@ -130,6 +131,11 @@ bool llcan_set_speed(FDCAN_GlobalTypeDef *CANx, uint32_t speed, uint32_t data_sp

CANx->DBTP = (((sjw & 0xFU)-1U)<<FDCAN_DBTP_DSJW_Pos) | (((seg1 & 0x1FU)-1U)<<FDCAN_DBTP_DTSEG1_Pos) | (((seg2 & 0xFU)-1U)<<FDCAN_DBTP_DTSEG2_Pos) | (((prescaler & 0x1FU)-1U)<<FDCAN_DBTP_DBRP_Pos);

if (non_iso) {
// FD non-ISO mode
CANx->CCCR |= FDCAN_CCCR_NISO;
}

// Silent loopback is known as internal loopback in the docs
if (loopback) {
CANx->CCCR |= FDCAN_CCCR_TEST;
Expand Down
15 changes: 5 additions & 10 deletions python/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@ class Panda:

CAN_PACKET_VERSION = 2
HEALTH_PACKET_VERSION = 11
CAN_HEALTH_PACKET_VERSION = 2
CAN_HEALTH_PACKET_VERSION = 3
HEALTH_STRUCT = struct.Struct("<IIIIIIIIIBBBBBBHBBBHfBB")
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIHHBB")
CAN_HEALTH_STRUCT = struct.Struct("<BIBBBBBBBBIIIIIIHHBBB")

F2_DEVICES = (HW_TYPE_PEDAL, )
F4_DEVICES = (HW_TYPE_WHITE_PANDA, HW_TYPE_GREY_PANDA, HW_TYPE_BLACK_PANDA, HW_TYPE_UNO, HW_TYPE_DOS)
Expand Down Expand Up @@ -509,6 +509,7 @@ def can_health(self, can_number):
"can_data_speed": a[17],
"canfd_enabled": a[18],
"brs_enabled": a[19],
"canfd_non_iso": a[20],
}

# ******************* control *******************
Expand Down Expand Up @@ -626,14 +627,8 @@ def set_can_speed_kbps(self, bus, speed):
def set_can_data_speed_kbps(self, bus, speed):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xf9, bus, int(speed * 10), b'')

# CAN FD and BRS status
def get_canfd_status(self, bus):
dat = self._handle.controlRead(Panda.REQUEST_IN, 0xfa, bus, 0, 2)
if dat:
a = struct.unpack("BB", dat)
return (a[0], a[1])
else:
return (None, None)
def set_canfd_non_iso(self, bus, non_iso):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xfc, bus, int(non_iso), b'')

def set_uart_baud(self, uart, rate):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe4, uart, int(rate / 300), b'')
Expand Down
104 changes: 63 additions & 41 deletions tests/canfd/test_canfd.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,41 @@
#TODO: REMOVE, temporary list of CAN FD lengths, one in panda python lib MUST be used
DLC_TO_LEN = [0, 1, 2, 3, 4, 5, 6, 7, 8, 12, 16, 20, 24, 32, 48]

_panda_serials = []


def panda_init(serial, enable_canfd=False):
def panda_reset():
panda_serials = []

if JUNGLE_SERIAL:
panda_jungle = PandaJungle(JUNGLE_SERIAL)
panda_jungle.set_panda_power(False)
time.sleep(2)
panda_jungle.set_panda_power(True)
time.sleep(4)

for serial in Panda.list():
if serial not in H7_PANDAS_EXCLUDE:
p = Panda(serial=serial)
if p.get_type() in H7_HW_TYPES:
assert p.recover(timeout=30)
panda_serials.append(serial)
p.close()

if len(panda_serials) < 2:
print("Minimum two H7 type pandas should be connected.")
assert False

return panda_serials

def panda_init(serial, enable_canfd=False, enable_non_iso=False):
p = Panda(serial=serial)
p.set_power_save(False)
for bus in range(3):
if enable_canfd:
p.set_can_data_speed_kbps(bus, 2000)
if enable_non_iso:
p.set_canfd_non_iso(bus, True)
p.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
return p

if JUNGLE_SERIAL:
panda_jungle = PandaJungle(JUNGLE_SERIAL)
panda_jungle.set_panda_power(False)
time.sleep(2)
panda_jungle.set_panda_power(True)
time.sleep(4)

for serial in Panda.list():
if serial not in H7_PANDAS_EXCLUDE:
p = Panda(serial=serial)
if p.get_type() in H7_HW_TYPES:
assert p.recover(timeout=30)
_panda_serials.append(serial)
p.close()

if len(_panda_serials) < 2:
print("Minimum two H7 type pandas should be connected.")
assert False


def canfd_test(p_send, p_recv):
for _ in range(100):
sent_msgs = defaultdict(set)
Expand Down Expand Up @@ -78,27 +81,46 @@ def canfd_test(p_send, p_recv):
p_recv.set_safety_mode(Panda.SAFETY_SILENT)
p_send.set_power_save(True)
p_recv.set_power_save(True)
p_send.close()
p_recv.close()
print("Got all messages intact")


p_send = panda_init(_panda_serials[0], enable_canfd=False)
p_recv = panda_init(_panda_serials[1], enable_canfd=True)
def setup_test(enable_non_iso=False):
panda_serials = panda_reset()

p_send = panda_init(panda_serials[0], enable_canfd=False, enable_non_iso=enable_non_iso)
p_recv = panda_init(panda_serials[1], enable_canfd=True, enable_non_iso=enable_non_iso)

# Check that sending panda CAN FD and BRS are turned off
for bus in range(3):
health = p_send.can_health(bus)
assert not health["canfd_enabled"]
assert not health["brs_enabled"]
assert health["canfd_non_iso"] == enable_non_iso

# Receiving panda sends dummy CAN FD message that should enable CAN FD on sender side
for bus in range(3):
p_recv.can_send(0x200, b"dummymessage", bus)
p_recv.can_recv()

# Check if all tested buses on sending panda have swithed to CAN FD with BRS
for bus in range(3):
health = p_send.can_health(bus)
assert health["canfd_enabled"]
assert health["brs_enabled"]
assert health["canfd_non_iso"] == enable_non_iso

# Check that sending panda CAN FD and BRS are turned off
for bus in range(3):
canfd, brs = p_send.get_canfd_status(bus)
assert not canfd
assert not brs
return p_send, p_recv

# Receiving panda sends dummy CAN FD message that should enable CAN FD on sender side
for bus in range(3):
p_recv.can_send(0x200, b"dummymessage", bus)
p_recv.can_recv()
def main():
print("[TEST CAN-FD]")
p_send, p_recv = setup_test()
canfd_test(p_send, p_recv)

# Check if all tested buses on sending panda have swithed to CAN FD with BRS
for bus in range(3):
canfd, brs = p_send.get_canfd_status(bus)
assert canfd
assert brs
print("[TEST CAN-FD non-ISO]")
p_send, p_recv = setup_test(enable_non_iso=True)
canfd_test(p_send, p_recv)

canfd_test(p_send, p_recv)
if __name__ == "__main__":
main()

0 comments on commit 2f3e282

Please sign in to comment.