Compare commits

..

13 Commits

Author SHA1 Message Date
Maxime Desroches 8add72fc15
Merge 9e1e36167d into 5761ab58ea 2024-11-23 18:03:32 +09:00
Adeeb Shihadeh 5761ab58ea what was that doing there? 2024-11-22 19:33:04 -08:00
Willem Melching cfbc3ff835
Ensure auto switching FD is off in Python (#2087) 2024-11-22 10:29:11 -08:00
Maxime Desroches b770745342
ci: split MISRA linter and MISRA mutation (#2086)
* sep

* this
2024-11-21 11:48:02 -08:00
Adeeb Shihadeh 2fbf0c5ff8 fix indendation 2024-11-21 11:07:57 -08:00
Willem Melching 4a11d52e07
Control over FD flag of CAN messages (#2085)
* Control over FD flag of CAN messages

* misra
2024-11-21 11:04:09 -08:00
Maxime Desroches 998a639360
python: catch exceptions in DFU (#2084)
* try

* also this
2024-11-20 19:22:14 -08:00
Adeeb Shihadeh 422e3e0c0f
H7 sound: fix noise with empty stream (#2083)
fix noise

Co-authored-by: Comma Device <device@comma.ai>
2024-11-18 14:50:17 -08:00
Robbe Derks acc15afaa0
Fix sound playback artifacts (#2082)
this stays in sync

Co-authored-by: Comma Device <device@comma.ai>
2024-11-15 15:35:30 +01:00
Adeeb Shihadeh 742d961b07
Lower siren duration to 3s (#2080) 2024-11-14 17:05:44 -08:00
Robbe Derks a67f3650c8
Increase MISRA to 2min max (#2079)
increase to 2min max
2024-11-14 11:28:28 +01:00
Adeeb Shihadeh 39c966fb27
sound: little cleaner idle handling (#2078)
Co-authored-by: Comma Device <device@comma.ai>
2024-11-14 10:04:59 +01:00
Robbe Derks dec9223f97
cuatro sound (#1861)
* fake siren works

* this receives something

* microphone in SAI1 POC

* this receives audio again

* double buffer DMA?

* RX DMA works

* wip

* needs cleanup, but this plays

* cleanup of playback

* print mic

* deal with stereo in

* the DMA from SAI1 -> SAI4 doesn't work yet

* this puts mic data in a buf

* this gets sound to the 845

* wip: still garbage from the mic

* inefficient, but it does record the mic

* sine isn't used

* comment out mic for now

* fix misra

* remove mic

* more cleanup

* add amp enable/disable

* no more debug

* newline

---------

Co-authored-by: Comma Device <device@comma.ai>
2024-11-13 16:09:13 +01:00
28 changed files with 208 additions and 43 deletions

View File

@ -88,8 +88,8 @@ jobs:
scons -j$(nproc) ${{ matrix.flags }} && \
tests/safety/test.sh"
misra:
name: MISRA C:2012
misra_linter:
name: MISRA C:2012 Linter
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
@ -99,8 +99,19 @@ jobs:
- name: Build FW
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: Run MISRA C:2012 analysis
timeout-minutes: 1
timeout-minutes: 2
run: ${{ env.RUN }} "cd tests/misra && ./test_misra.sh"
misra_mutation:
name: MISRA C:2012 Mutation
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v2
- name: Build Docker image
run: eval "$BUILD"
- name: Build FW
run: ${{ env.RUN }} "scons -j$(nproc)"
- name: MISRA mutation tests
timeout-minutes: 5
run: ${{ env.RUN }} "cd tests/misra && pytest -n8 test_mutation.py"

View File

@ -182,5 +182,6 @@ board board_black = {
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
.read_som_gpio = unused_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -24,6 +24,7 @@ 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;
@ -49,6 +50,7 @@ struct board {
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 ********************

View File

@ -75,6 +75,10 @@ static void cuatro_set_siren(bool enabled){
beeper_enable(enabled);
}
static void cuatro_set_amp_enabled(bool enabled){
set_gpio_output(GPIOA, 5, enabled);
}
static void cuatro_init(void) {
red_chiplet_init();
@ -128,6 +132,17 @@ static void cuatro_init(void) {
// Beeper
set_gpio_alternate(GPIOD, 14, GPIO_AF2_TIM4);
beeper_init();
// Sound codec
cuatro_set_amp_enabled(false);
set_gpio_alternate(GPIOA, 2, GPIO_AF8_SAI4); // SAI4_SCK_B
set_gpio_alternate(GPIOC, 0, GPIO_AF8_SAI4); // SAI4_FS_B
set_gpio_alternate(GPIOD, 11, GPIO_AF10_SAI4); // SAI4_SD_A
set_gpio_alternate(GPIOE, 3, GPIO_AF8_SAI4); // SAI4_SD_B
set_gpio_alternate(GPIOE, 4, GPIO_AF2_SAI1); // SAI1_D2
set_gpio_alternate(GPIOE, 5, GPIO_AF2_SAI1); // SAI1_CK2
set_gpio_alternate(GPIOE, 6, GPIO_AF10_SAI4); // SAI4_MCLK_B
sound_init();
}
board board_cuatro = {
@ -153,5 +168,6 @@ board board_cuatro = {
.set_ir_power = tres_set_ir_power,
.set_siren = cuatro_set_siren,
.set_bootkick = cuatro_set_bootkick,
.read_som_gpio = tres_read_som_gpio
.read_som_gpio = tres_read_som_gpio,
.set_amp_enabled = cuatro_set_amp_enabled
};

View File

@ -211,5 +211,6 @@ board board_dos = {
.set_ir_power = dos_set_ir_power,
.set_siren = dos_set_siren,
.set_bootkick = dos_set_bootkick,
.read_som_gpio = dos_read_som_gpio
.read_som_gpio = dos_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -31,5 +31,6 @@ board board_grey = {
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
.read_som_gpio = unused_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -194,5 +194,6 @@ board board_red = {
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
.read_som_gpio = unused_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -97,5 +97,6 @@ board board_tres = {
.set_ir_power = tres_set_ir_power,
.set_siren = fake_siren_set,
.set_bootkick = tres_set_bootkick,
.read_som_gpio = tres_read_som_gpio
.read_som_gpio = tres_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -218,5 +218,6 @@ board board_uno = {
.set_ir_power = uno_set_ir_power,
.set_siren = unused_set_siren,
.set_bootkick = uno_set_bootkick,
.read_som_gpio = unused_read_som_gpio
.read_som_gpio = unused_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -26,3 +26,7 @@ void unused_set_bootkick(BootState state) {
bool unused_read_som_gpio(void) {
return false;
}
void unused_set_amp_enabled(bool enabled) {
UNUSED(enabled);
}

View File

@ -211,5 +211,6 @@ board board_white = {
.set_fan_enabled = unused_set_fan_enabled,
.set_ir_power = unused_set_ir_power,
.set_siren = unused_set_siren,
.read_som_gpio = unused_read_som_gpio
.read_som_gpio = unused_read_som_gpio,
.set_amp_enabled = unused_set_amp_enabled
};

View File

@ -13,7 +13,7 @@
#endif
typedef struct {
unsigned char reserved : 1;
unsigned char fd : 1;
unsigned char bus : 3;
unsigned char data_len_code : 4; // lookup length with dlc_to_len
unsigned char rejected : 1;

View File

@ -89,6 +89,7 @@ void process_can(uint8_t can_number) {
if ((CANx->TSR & CAN_TSR_RQCP0) == CAN_TSR_RQCP0) {
if ((CANx->TSR & CAN_TSR_TXOK0) == CAN_TSR_TXOK0) {
CANPacket_t to_push;
to_push.fd = 0U;
to_push.returned = 1U;
to_push.rejected = 0U;
to_push.extended = (CANx->sTxMailBox[0].TIR >> 2) & 0x1U;
@ -144,6 +145,7 @@ void can_rx(uint8_t can_number) {
// add to my fifo
CANPacket_t to_push;
to_push.fd = 0U;
to_push.returned = 0U;
to_push.rejected = 0U;
to_push.extended = (CANx->sFIFOMailBox[0].RIR >> 2) & 0x1U;
@ -159,6 +161,7 @@ void can_rx(uint8_t can_number) {
if (bus_fwd_num != -1) {
CANPacket_t to_send;
to_send.fd = 0U;
to_send.returned = 0U;
to_send.rejected = 0U;
to_send.extended = to_push.extended; // TXRQ

View File

@ -131,10 +131,10 @@ void can_clear(can_ring *q) {
// Helpers
// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3
bus_config_t bus_config[BUS_CONFIG_ARRAY_SIZE] = {
{ .bus_lookup = 0U, .can_num_lookup = 0U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .forwarding_bus = -1, .can_speed = 333U, .can_data_speed = 333U, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 0U, .can_num_lookup = 0U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 1U, .can_num_lookup = 1U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 2U, .can_num_lookup = 2U, .forwarding_bus = -1, .can_speed = 5000U, .can_data_speed = 20000U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
{ .bus_lookup = 0xFFU, .can_num_lookup = 0xFFU, .forwarding_bus = -1, .can_speed = 333U, .can_data_speed = 333U, .canfd_auto = false, .canfd_enabled = false, .brs_enabled = false, .canfd_non_iso = false },
};
void can_init_all(void) {

View File

@ -13,6 +13,7 @@ typedef struct {
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;

View File

@ -100,7 +100,11 @@ void process_can(uint8_t can_number) {
fifo = (canfd_fifo *)(TxFIFOSA + (tx_index * FDCAN_TX_FIFO_EL_SIZE));
fifo->header[0] = (to_send.extended << 30) | ((to_send.extended != 0U) ? (to_send.addr) : (to_send.addr << 18));
uint32_t canfd_enabled_header = bus_config[can_number].canfd_enabled ? (1UL << 21) : 0UL;
// If canfd_auto is set, outgoing packets will be automatically sent as CAN-FD if an incoming CAN-FD packet was seen
bool fd = bus_config[can_number].canfd_auto ? bus_config[can_number].canfd_enabled : (bool)(to_send.fd > 0U);
uint32_t canfd_enabled_header = fd ? (1UL << 21) : 0UL;
uint32_t brs_enabled_header = bus_config[can_number].brs_enabled ? (1UL << 20) : 0UL;
fifo->header[1] = (to_send.data_len_code << 16) | canfd_enabled_header | brs_enabled_header;
@ -115,6 +119,7 @@ void process_can(uint8_t can_number) {
// Send back to USB
CANPacket_t to_push;
to_push.fd = fd;
to_push.returned = 1U;
to_push.rejected = 0U;
to_push.extended = to_send.extended;
@ -168,6 +173,10 @@ void can_rx(uint8_t can_number) {
// getting address
fifo = (canfd_fifo *)(RxFIFO0SA + (rx_fifo_idx * FDCAN_RX_FIFO_0_EL_SIZE));
bool canfd_frame = ((fifo->header[1] >> 21) & 0x1U);
bool brs_frame = ((fifo->header[1] >> 20) & 0x1U);
to_push.fd = canfd_frame;
to_push.returned = 0U;
to_push.rejected = 0U;
to_push.extended = (fifo->header[0] >> 30) & 0x1U;
@ -175,9 +184,6 @@ void can_rx(uint8_t can_number) {
to_push.bus = bus_number;
to_push.data_len_code = ((fifo->header[1] >> 16) & 0xFU);
bool canfd_frame = ((fifo->header[1] >> 21) & 0x1U);
bool brs_frame = ((fifo->header[1] >> 20) & 0x1U);
uint8_t data_len_w = (dlc_to_len[to_push.data_len_code] / 4U);
data_len_w += ((dlc_to_len[to_push.data_len_code] % 4U) > 0U) ? 1U : 0U;
for (unsigned int i = 0; i < data_len_w; i++) {
@ -193,6 +199,7 @@ void can_rx(uint8_t can_number) {
if (bus_fwd_num != -1) {
CANPacket_t to_send;
to_send.fd = to_push.fd;
to_send.returned = 0U;
to_send.rejected = 0U;
to_send.extended = to_push.extended;

View File

@ -32,6 +32,7 @@
#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

View File

@ -158,6 +158,7 @@ static void tick_handler(void) {
usb_tick();
harness_tick();
simple_watchdog_kick();
sound_tick();
// re-init everything that uses harness status
if (harness.status != prev_harness_status) {
@ -240,7 +241,7 @@ static void tick_handler(void) {
print(" seconds. Safety is set to SILENT mode.\n");
if (controls_allowed_countdown > 0U) {
siren_countdown = 5U;
siren_countdown = 3U;
controls_allowed_countdown = 0U;
}

View File

@ -317,6 +317,10 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
case 0xe7:
set_power_save_state(req->param1);
break;
// **** 0xe8: set can-fd auto swithing mode
case 0xe8:
bus_config[req->param1].canfd_auto = req->param2 > 0U;
break;
// **** 0xf1: Clear CAN ring buffer.
case 0xf1:
if (req->param1 == 0xFFFFU) {

View File

@ -2,21 +2,15 @@
import os
import time
import subprocess
import argparse
from panda import Panda, PandaDFU
board_path = os.path.dirname(os.path.realpath(__file__))
if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument("--all", action="store_true", help="Recover all Panda devices")
args = parser.parse_args()
subprocess.check_call(f"scons -C {board_path}/.. -j$(nproc) {board_path}", shell=True)
serials = Panda.list() if args.all else [None]
for s in serials:
for s in Panda.list():
with Panda(serial=s) as p:
print(f"putting {p.get_usb_serial()} in DFU mode")
p.reset(enter_bootstub=True)

View File

@ -16,6 +16,9 @@
#include "boards/uno.h"
#include "boards/dos.h"
// Unused functions on F4
void sound_tick(void) {}
void detect_board_type(void) {
// SPI lines floating: white (TODO: is this reliable? Not really, we have to enable ESP/GPS to be able to detect this on the UART)
set_gpio_output(GPIOC, 14, 1);

View File

@ -12,6 +12,7 @@
#include "stm32h7/lldac.h"
#include "drivers/beeper.h"
#include "drivers/fake_siren.h"
#include "stm32h7/sound.h"
#include "drivers/clock_source.h"
#include "boards/red.h"
#include "boards/red_chiplet.h"

View File

@ -101,13 +101,14 @@ void peripherals_init(void) {
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOFEN;
RCC->AHB4ENR |= RCC_AHB4ENR_GPIOGEN;
// Enable CPU access to SRAM1 and SRAM2 (in domain D2) for DMA
// Enable CPU access to SRAMs for DMA
RCC->AHB2ENR |= RCC_AHB2ENR_SRAM1EN | RCC_AHB2ENR_SRAM2EN;
// Supplemental
RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN; // DAC DMA
RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; // SPI DMA
RCC->APB4ENR |= RCC_APB4ENR_SYSCFGEN;
RCC->AHB4ENR |= RCC_AHB4ENR_BDMAEN; // Audio DMA
// Connectivity
RCC->APB2ENR |= RCC_APB2ENR_SPI4EN; // SPI
@ -122,6 +123,9 @@ void peripherals_init(void) {
RCC->AHB1ENR |= RCC_AHB1ENR_ADC12EN; // Enable ADC12 clocks
RCC->APB1LENR |= RCC_APB1LENR_DAC12EN; // DAC
// Audio
RCC->APB4ENR |= RCC_APB4ENR_SAI4EN; // SAI4
// Timers
RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; // clock source timer
RCC->APB1LENR |= RCC_APB1LENR_TIM2EN; // main counter
@ -131,6 +135,7 @@ void peripherals_init(void) {
RCC->APB1LENR |= RCC_APB1LENR_TIM7EN; // DMA trigger timer
RCC->APB2ENR |= RCC_APB2ENR_TIM8EN; // tick timer
RCC->APB1LENR |= RCC_APB1LENR_TIM12EN; // slow loop
RCC->APB1LENR |= RCC_APB1LENR_TIM5EN; // sound trigger timer
#ifdef PANDA_JUNGLE
RCC->AHB3ENR |= RCC_AHB3ENR_SDMMC1EN; // SDMMC

94
board/stm32h7/sound.h Normal file
View File

@ -0,0 +1,94 @@
#define SOUND_RX_BUF_SIZE 2000U
#define SOUND_TX_BUF_SIZE (SOUND_RX_BUF_SIZE/2U)
__attribute__((section(".sram4"))) static uint16_t sound_rx_buf[2][SOUND_RX_BUF_SIZE];
static uint8_t sound_idle_count;
void sound_tick(void) {
if (sound_idle_count > 0U) {
sound_idle_count--;
if (sound_idle_count == 0U) {
current_board->set_amp_enabled(false);
}
}
}
// Playback processing
static void BDMA_Channel0_IRQ_Handler(void) {
__attribute__((section(".sram4"))) static uint16_t tx_buf[SOUND_TX_BUF_SIZE];
BDMA->IFCR |= BDMA_IFCR_CGIF0; // clear flag
uint8_t buf_idx = (((BDMA_Channel0->CCR & BDMA_CCR_CT) >> BDMA_CCR_CT_Pos) == 1U) ? 0U : 1U;
// process samples (shift to 12b and bias to be unsigned)
bool sound_playing = false;
for (uint16_t i=0U; i < SOUND_RX_BUF_SIZE; i += 2U) {
// since we are playing mono and receiving stereo, we take every other sample
tx_buf[i/2U] = ((sound_rx_buf[buf_idx][i] + (1UL << 14)) >> 3);
if (sound_rx_buf[buf_idx][i] > 0U) {
sound_playing = true;
}
}
// manage amp state
if (sound_playing) {
if (sound_idle_count == 0U) {
current_board->set_amp_enabled(true);
}
sound_idle_count = 4U;
}
sound_tick();
DMA1->LIFCR |= 0xF40;
DMA1_Stream1->CR &= ~DMA_SxCR_EN;
register_set(&DMA1_Stream1->M0AR, (uint32_t) tx_buf, 0xFFFFFFFFU);
DMA1_Stream1->NDTR = SOUND_TX_BUF_SIZE;
DMA1_Stream1->CR |= DMA_SxCR_EN;
}
void sound_init(void) {
REGISTER_INTERRUPT(BDMA_Channel0_IRQn, BDMA_Channel0_IRQ_Handler, 64U, FAULT_INTERRUPT_RATE_SOUND_DMA)
// Init DAC
register_set(&DAC1->MCR, 0U, 0xFFFFFFFFU);
register_set(&DAC1->CR, DAC_CR_TEN1 | (4U << DAC_CR_TSEL1_Pos) | DAC_CR_DMAEN1, 0xFFFFFFFFU);
register_set_bits(&DAC1->CR, DAC_CR_EN1);
// Setup DMAMUX (DAC_CH1_DMA as input)
register_set(&DMAMUX1_Channel1->CCR, 67U, DMAMUX_CxCR_DMAREQ_ID_Msk);
// Setup DMA
register_set(&DMA1_Stream1->PAR, (uint32_t) &(DAC1->DHR12R1), 0xFFFFFFFFU);
register_set(&DMA1_Stream1->FCR, 0U, 0x00000083U);
DMA1_Stream1->CR = (0b11UL << DMA_SxCR_PL_Pos) | (0b01UL << DMA_SxCR_MSIZE_Pos) | (0b01UL << DMA_SxCR_PSIZE_Pos) | DMA_SxCR_MINC | (1U << DMA_SxCR_DIR_Pos);
// Init trigger timer (little slower than 48kHz, pulled in sync by SAI4_FS_B)
register_set(&TIM5->PSC, 2600U, 0xFFFFU);
register_set(&TIM5->ARR, 100U, 0xFFFFFFFFU); // not important
register_set(&TIM5->AF1, (0b0010UL << TIM5_AF1_ETRSEL_Pos), TIM5_AF1_ETRSEL_Msk);
register_set(&TIM5->CR2, (0b010U << TIM_CR2_MMS_Pos), TIM_CR2_MMS_Msk);
register_set(&TIM5->SMCR, TIM_SMCR_ECE | (0b00111UL << TIM_SMCR_TS_Pos)| (0b0100UL << TIM_SMCR_SMS_Pos), 0x31FFF7U);
TIM5->CNT = 0U; TIM5->SR = 0U;
TIM5->CR1 |= TIM_CR1_CEN;
// stereo audio in
register_set(&SAI4_Block_B->CR1, SAI_xCR1_DMAEN | (0b00UL << SAI_xCR1_SYNCEN_Pos) | (0b100U << SAI_xCR1_DS_Pos) | (0b11U << SAI_xCR1_MODE_Pos), 0x0FFB3FEFU);
register_set(&SAI4_Block_B->CR2, (0b001U << SAI_xCR2_FTH_Pos), 0xFFFBU);
register_set(&SAI4_Block_B->FRCR, (31U << SAI_xFRCR_FRL_Pos), 0x7FFFFU);
register_set(&SAI4_Block_B->SLOTR, (0b11UL << SAI_xSLOTR_SLOTEN_Pos) | (1UL << SAI_xSLOTR_NBSLOT_Pos) | (0b01UL << SAI_xSLOTR_SLOTSZ_Pos), 0xFFFF0FDFU); // NBSLOT definition is vague
// init sound DMA (SAI4_B -> memory, double buffers)
register_set(&BDMA_Channel0->CPAR, (uint32_t) &(SAI4_Block_B->DR), 0xFFFFFFFFU);
register_set(&BDMA_Channel0->CM0AR, (uint32_t) sound_rx_buf[0], 0xFFFFFFFFU);
register_set(&BDMA_Channel0->CM1AR, (uint32_t) sound_rx_buf[1], 0xFFFFFFFFU);
BDMA_Channel0->CNDTR = SOUND_RX_BUF_SIZE;
register_set(&BDMA_Channel0->CCR, BDMA_CCR_DBM | (0b01UL << BDMA_CCR_MSIZE_Pos) | (0b01UL << BDMA_CCR_PSIZE_Pos) | BDMA_CCR_MINC | BDMA_CCR_CIRC | BDMA_CCR_TCIE, 0xFFFFU);
register_set(&DMAMUX2_Channel0->CCR, 16U, DMAMUX_CxCR_DMAREQ_ID_Msk); // SAI4_B_DMA
register_set_bits(&BDMA_Channel0->CCR, BDMA_CCR_EN);
// enable all initted blocks
register_set_bits(&SAI4_Block_B->CR1, SAI_xCR1_SAIEN);
NVIC_EnableIRQ(BDMA_Channel0_IRQn);
}

View File

@ -31,7 +31,7 @@ def calculate_checksum(data):
res ^= b
return res
def pack_can_buffer(arr):
def pack_can_buffer(arr, fd=False):
snds = [b'']
for address, dat, bus in arr:
assert len(dat) in LEN_TO_DLC
@ -41,7 +41,7 @@ def pack_can_buffer(arr):
data_len_code = LEN_TO_DLC[len(dat)]
header = bytearray(CANPACKET_HEAD_SIZE)
word_4b = address << 3 | extended << 2
header[0] = (data_len_code << 4) | (bus << 1)
header[0] = (data_len_code << 4) | (bus << 1) | int(fd)
header[1] = word_4b & 0xFF
header[2] = (word_4b >> 8) & 0xFF
header[3] = (word_4b >> 16) & 0xFF
@ -324,6 +324,10 @@ class Panda:
# reset comms
self.can_reset_communications()
# disable automatic CAN-FD switching
for bus in range(PANDA_BUS_CNT):
self.set_canfd_auto(bus, False)
# set CAN speed
for bus in range(PANDA_BUS_CNT):
self.set_can_speed_kbps(bus, self._can_speed_kbps)
@ -807,6 +811,9 @@ class Panda:
def set_canfd_non_iso(self, bus, non_iso):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xfc, bus, int(non_iso), b'')
def set_canfd_auto(self, bus, auto):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe8, bus, int(auto), b'')
def set_uart_baud(self, uart, rate):
self._handle.controlWrite(Panda.REQUEST_OUT, 0xe4, uart, int(rate / 300), b'')
@ -828,15 +835,15 @@ class Panda:
self._handle.controlWrite(Panda.REQUEST_OUT, 0xc0, 0, 0, b'')
@ensure_can_packet_version
def can_send_many(self, arr, timeout=CAN_SEND_TIMEOUT_MS):
snds = pack_can_buffer(arr)
def can_send_many(self, arr, *, fd=False, timeout=CAN_SEND_TIMEOUT_MS):
snds = pack_can_buffer(arr, fd=fd)
for tx in snds:
while len(tx) > 0:
bs = self._handle.bulkWrite(3, tx, timeout=timeout)
tx = tx[bs:]
def can_send(self, addr, dat, bus, timeout=CAN_SEND_TIMEOUT_MS):
self.can_send_many([[addr, dat, bus]], timeout=timeout)
def can_send(self, addr, dat, bus, *, fd=False, timeout=CAN_SEND_TIMEOUT_MS):
self.can_send_many([[addr, dat, bus]], fd=fd, timeout=timeout)
@ensure_can_packet_version
def can_recv(self):

View File

@ -100,11 +100,14 @@ class PandaDFU:
def st_serial_to_dfu_serial(st: str, mcu_type: McuType = McuType.F4):
if st is None or st == "none":
return None
try:
uid_base = struct.unpack("H" * 6, bytes.fromhex(st))
if mcu_type == McuType.H7:
return binascii.hexlify(struct.pack("!HHH", uid_base[1] + uid_base[5], uid_base[0] + uid_base[4], uid_base[3])).upper().decode("utf-8")
else:
return binascii.hexlify(struct.pack("!HHH", uid_base[1] + uid_base[5], uid_base[0] + uid_base[4] + 0xA, uid_base[3])).upper().decode("utf-8")
except struct.error:
return None
def get_mcu_type(self) -> McuType:
return self._mcu_type

View File

@ -402,7 +402,8 @@ class STBootloaderSPIHandle(BaseSTBootloaderHandle):
def get_chip_id(self) -> int:
r = self._cmd(0x02, read_bytes=3)
assert r[0] == 1 # response length - 1
if r[0] != 1: # response length - 1
raise PandaSpiException("incorrect response length")
return ((r[1] << 8) + r[2])
def go_cmd(self, address: int) -> None:

View File

@ -12,7 +12,7 @@ ffi = FFI()
ffi.cdef("""
typedef struct {
unsigned char reserved : 1;
unsigned char fd : 1;
unsigned char bus : 3;
unsigned char data_len_code : 4;
unsigned char rejected : 1;