openpilot v0.9.7 release

date: 2024-06-11T01:36:39
master commit: f8cb04e4a8
This commit is contained in:
Vehicle Researcher
2024-06-11 01:36:40 +00:00
parent fa724893fb
commit d64fb1838d
1014 changed files with 40763 additions and 16667 deletions
+138
View File
@@ -0,0 +1,138 @@
def docker_run(String step_label, int timeout_mins, String cmd) {
timeout(time: timeout_mins, unit: 'MINUTES') {
sh script: "docker run --rm --privileged \
--env PYTHONWARNINGS=error \
--volume /dev/bus/usb:/dev/bus/usb \
--volume /var/run/dbus:/var/run/dbus \
--workdir /tmp/openpilot/panda \
--net host \
${env.DOCKER_IMAGE_TAG} \
bash -c 'scons -j8 && ${cmd}'", \
label: step_label
}
}
def phone(String ip, String step_label, String cmd) {
withCredentials([file(credentialsId: 'id_rsa', variable: 'key_file')]) {
def ssh_cmd = """
ssh -tt -o StrictHostKeyChecking=no -i ${key_file} 'comma@${ip}' /usr/bin/bash <<'END'
set -e
source ~/.bash_profile
if [ -f /etc/profile ]; then
source /etc/profile
fi
export CI=1
export TEST_DIR=${env.TEST_DIR}
export SOURCE_DIR=${env.SOURCE_DIR}
export GIT_BRANCH=${env.GIT_BRANCH}
export GIT_COMMIT=${env.GIT_COMMIT}
export PYTHONPATH=${env.TEST_DIR}/../
export PYTHONWARNINGS=error
cd ${env.TEST_DIR} || true
${cmd}
exit 0
END"""
sh script: ssh_cmd, label: step_label
}
}
def phone_steps(String device_type, steps) {
lock(resource: "", label: device_type, inversePrecedence: true, variable: 'device_ip', quantity: 1) {
timeout(time: 20, unit: 'MINUTES') {
phone(device_ip, "git checkout", readFile("tests/setup_device_ci.sh"),)
steps.each { item ->
phone(device_ip, item[0], item[1])
}
}
}
}
pipeline {
agent any
environment {
CI = "1"
PYTHONWARNINGS= "error"
DOCKER_IMAGE_TAG = "panda:build-${env.GIT_COMMIT}"
TEST_DIR = "/data/panda"
SOURCE_DIR = "/data/panda_source/"
}
options {
timeout(time: 3, unit: 'HOURS')
disableConcurrentBuilds(abortPrevious: env.BRANCH_NAME != 'master')
}
stages {
stage('panda tests') {
parallel {
stage('test dos') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps {
phone_steps("panda-dos", [
["build", "scons -j4"],
["flash", "cd tests/ && ./reflash_internal_panda.py"],
["flash jungle", "cd board/jungle && ./flash.py"],
["test", "cd tests/hitl && HW_TYPES=6 pytest -n0 --durations=0 [2-9]*.py -k 'not test_send_recv'"],
])
}
}
stage('test tres') {
agent { docker { image 'ghcr.io/commaai/alpine-ssh'; args '--user=root' } }
steps {
phone_steps("panda-tres", [
["build", "scons -j4"],
["flash", "cd tests/ && ./reflash_internal_panda.py"],
["flash jungle", "cd board/jungle && ./flash.py"],
["test", "cd tests/hitl && HW_TYPES=9 pytest -n0 --durations=0 2*.py [5-9]*.py"],
])
}
}
stage ('Acquire resource locks') {
options {
lock(resource: "pandas")
}
stages {
stage('Build Docker Image') {
steps {
timeout(time: 20, unit: 'MINUTES') {
script {
sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD'
dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}")
}
}
}
}
stage('jungle tests') {
steps {
script {
retry (3) {
docker_run("reset hardware", 3, "python ./tests/hitl/reset_jungles.py")
}
}
}
}
stage('bootkick tests') {
steps {
script {
docker_run("test", 10, "pytest -n0 ./tests/som/test_bootkick.py")
}
}
}
}
}
}
}
}
}
+105
View File
@@ -0,0 +1,105 @@
# Welcome to panda
![panda tests](https://github.com/commaai/panda/workflows/tests/badge.svg)
![panda drivers](https://github.com/commaai/panda/workflows/drivers/badge.svg)
panda speaks CAN and CAN FD, and it runs on [STM32F413](https://www.st.com/resource/en/reference_manual/rm0430-stm32f413423-advanced-armbased-32bit-mcus-stmicroelectronics.pdf) and [STM32H725](https://www.st.com/resource/en/reference_manual/rm0468-stm32h723733-stm32h725735-and-stm32h730-value-line-advanced-armbased-32bit-mcus-stmicroelectronics.pdf).
## Directory structure
```
.
├── board # Code that runs on the STM32
├── drivers # Drivers (not needed for use with Python)
├── python # Python userspace library for interfacing with the panda
├── tests # Tests and helper programs for panda
```
## Safety Model
When a panda powers up, by default it's in `SAFETY_SILENT` mode. While in `SAFETY_SILENT` mode, the CAN buses are forced to be silent. In order to send messages, you have to select a safety mode. Some of safety modes (for example `SAFETY_ALLOUTPUT`) are disabled in release firmwares. In order to use them, compile and flash your own build.
Safety modes optionally support `controls_allowed`, which allows or blocks a subset of messages based on a customizable state in the board.
## Code Rigor
The panda firmware is written for its use in conjuction with [openpilot](https://github.com/commaai/openpilot). The panda firmware, through its safety model, provides and enforces the
[openpilot safety](https://github.com/commaai/openpilot/blob/master/docs/SAFETY.md). Due to its critical function, it's important that the application code rigor within the `board` folder is held to high standards.
These are the [CI regression tests](https://github.com/commaai/panda/actions) we have in place:
* A generic static code analysis is performed by [cppcheck](https://github.com/danmar/cppcheck/).
* In addition, [cppcheck](https://github.com/danmar/cppcheck/) has a specific addon to check for [MISRA C:2012](https://misra.org.uk/) violations. See [current coverage](https://github.com/commaai/panda/blob/master/tests/misra/coverage_table).
* Compiler options are relatively strict: the flags `-Wall -Wextra -Wstrict-prototypes -Werror` are enforced.
* The [safety logic](https://github.com/commaai/panda/tree/master/board/safety) is tested and verified by [unit tests](https://github.com/commaai/panda/tree/master/tests/safety) for each supported car variant.
to ensure that the behavior remains unchanged.
* A hardware-in-the-loop test verifies panda's functionalities on all active panda variants, including:
* additional safety model checks
* compiling and flashing the bootstub and app code
* receiving, sending, and forwarding CAN messages on all buses
* CAN loopback and latency tests through USB and SPI
The above tests are themselves tested by:
* a [mutation test](tests/misra/test_mutation.py) on the MISRA coverage
* 100% line coverage enforced on the safety unit tests
In addition, we run the [ruff linter](https://github.com/astral-sh/ruff) and [mypy](https://mypy-lang.org/) on panda's Python library.
## Usage
Setup dependencies:
```bash
# Ubuntu
sudo apt-get install dfu-util gcc-arm-none-eabi python3-pip libffi-dev git
# macOS
brew install --cask gcc-arm-embedded
brew install python3 dfu-util gcc@13
```
Clone panda repository and install:
``` bash
git clone https://github.com/commaai/panda.git
cd panda
# install dependencies
pip install -r requirements.txt
# install panda
python setup.py install
```
See [the Panda class](https://github.com/commaai/panda/blob/master/python/__init__.py) for how to interact with the panda.
For example, to receive CAN messages:
``` python
>>> from panda import Panda
>>> panda = Panda()
>>> panda.can_recv()
```
And to send one on bus 0:
``` python
>>> panda.set_safety_mode(Panda.SAFETY_ALLOUTPUT)
>>> panda.can_send(0x1aa, b'message', 0)
```
Note that you may have to setup [udev rules](https://github.com/commaai/panda/tree/master/drivers/linux) for Linux, such as
``` bash
sudo tee /etc/udev/rules.d/11-panda.rules <<EOF
SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddcc", MODE="0666"
SUBSYSTEM=="usb", ATTRS{idVendor}=="bbaa", ATTRS{idProduct}=="ddee", MODE="0666"
EOF
sudo udevadm control --reload-rules && sudo udevadm trigger
```
The panda jungle uses different udev rules. See [the repo](https://github.com/commaai/panda_jungle#udev-rules) for instructions.
## Software interface support
As a universal car interface, it should support every reasonable software interface.
- [Python library](https://github.com/commaai/panda/tree/master/python)
- [C++ library](https://github.com/commaai/openpilot/tree/master/selfdrive/boardd)
- [socketcan in kernel](https://github.com/commaai/panda/tree/master/drivers/linux) (alpha)
## Licensing
panda software is released under the MIT license unless otherwise specified.
+4 -4
View File
@@ -84,8 +84,6 @@ def build_project(project_name, project, extra_flags):
'..',
panda_root,
f"{panda_root}/board/",
f"{panda_root}/board/stm32fx/inc",
f"{panda_root}/board/stm32h7/inc",
]
env = Environment(
@@ -130,14 +128,15 @@ def build_project(project_name, project, extra_flags):
base_project_f4 = {
"MAIN": "main.c",
"STARTUP_FILE": File("./board/stm32fx/startup_stm32f413xx.s"),
"LINKER_SCRIPT": File("./board/stm32fx/stm32f4_flash.ld"),
"STARTUP_FILE": File("./board/stm32f4/startup_stm32f413xx.s"),
"LINKER_SCRIPT": File("./board/stm32f4/stm32f4_flash.ld"),
"APP_START_ADDRESS": "0x8004000",
"PROJECT_FLAGS": [
"-mcpu=cortex-m4",
"-mhard-float",
"-DSTM32F4",
"-DSTM32F413xx",
"-Iboard/stm32f4/inc",
"-mfpu=fpv4-sp-d16",
"-fsingle-precision-constant",
"-Os",
@@ -155,6 +154,7 @@ base_project_h7 = {
"-mhard-float",
"-DSTM32H7",
"-DSTM32H725xx",
"-Iboard/stm32h7/inc",
"-mfpu=fpv5-d16",
"-fsingle-precision-constant",
"-Os",
+28
View File
@@ -0,0 +1,28 @@
AddOption('--minimal',
action='store_false',
dest='extras',
default=True,
help='the minimum build. no tests, tools, etc.')
AddOption('--ubsan',
action='store_true',
help='turn on UBSan')
AddOption('--coverage',
action='store_true',
help='build with test coverage options')
AddOption('--compile_db',
action='store_true',
help='build clang compilation database')
env = Environment(
COMPILATIONDB_USE_ABSPATH=True,
tools=["default", "compilation_db"],
)
if GetOption('compile_db'):
env.CompilationDatabase("compile_commands.json")
# panda fw & test files
SConscript('SConscript')
+2 -10
View File
@@ -122,8 +122,6 @@ void black_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
black_enable_can_transceivers(true);
@@ -135,11 +133,6 @@ void black_init(void) {
// Set normal CAN mode
black_set_can_mode(CAN_MODE_NORMAL);
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
}
void black_init_bootloader(void) {
@@ -148,7 +141,7 @@ void black_init_bootloader(void) {
set_gpio_output(GPIOC, 12, 0);
}
const harness_configuration black_harness_config = {
harness_configuration black_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOC,
@@ -162,13 +155,12 @@ const harness_configuration black_harness_config = {
.adc_channel_SBU2 = 13
};
const board board_black = {
board board_black = {
.set_bootkick = unused_set_bootkick,
.harness_config = &black_harness_config,
.has_obd = true,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
+2 -5
View File
@@ -21,11 +21,10 @@ typedef void (*board_set_bootkick)(BootState state);
typedef bool (*board_read_som_gpio)(void);
struct board {
const harness_configuration *harness_config;
harness_configuration *harness_config;
const bool has_obd;
const bool has_spi;
const bool has_canfd;
const bool has_rtc_battery;
const uint16_t fan_max_rpm;
const uint16_t avdd_mV;
const bool fan_stall_recovery;
@@ -73,6 +72,4 @@ struct board {
// CAN modes
#define CAN_MODE_NORMAL 0U
#define CAN_MODE_GMLAN_CAN2 1U
#define CAN_MODE_GMLAN_CAN3 2U
#define CAN_MODE_OBD_CAN2 3U
#define CAN_MODE_OBD_CAN2 1U
+1 -2
View File
@@ -103,12 +103,11 @@ void cuatro_init(void) {
clock_source_init();
}
const board board_cuatro = {
board board_cuatro = {
.harness_config = &red_chiplet_harness_config,
.has_obd = true,
.has_spi = true,
.has_canfd = true,
.has_rtc_battery = true,
.fan_max_rpm = 6600U,
.avdd_mV = 1800U,
.fan_stall_recovery = false,
+2 -10
View File
@@ -147,8 +147,6 @@ void dos_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
dos_enable_can_transceivers(true);
@@ -164,16 +162,11 @@ void dos_init(void) {
// Set normal CAN mode
dos_set_can_mode(CAN_MODE_NORMAL);
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
// Init clock source (camera strobe) using PWM
clock_source_init();
}
const harness_configuration dos_harness_config = {
harness_configuration dos_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOC,
@@ -187,7 +180,7 @@ const harness_configuration dos_harness_config = {
.adc_channel_SBU2 = 13
};
const board board_dos = {
board board_dos = {
.harness_config = &dos_harness_config,
.has_obd = true,
#ifdef ENABLE_SPI
@@ -196,7 +189,6 @@ const board board_dos = {
.has_spi = false,
#endif
.has_canfd = false,
.has_rtc_battery = true,
.fan_max_rpm = 6500U,
.avdd_mV = 3300U,
.fan_stall_recovery = true,
+1 -2
View File
@@ -4,13 +4,12 @@
// Most hardware functionality is similar to white panda
const board board_grey = {
board board_grey = {
.set_bootkick = unused_set_bootkick,
.harness_config = &white_harness_config,
.has_obd = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
+2 -10
View File
@@ -140,8 +140,6 @@ void red_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
red_enable_can_transceivers(true);
@@ -153,14 +151,9 @@ void red_init(void) {
// Set normal CAN mode
red_set_can_mode(CAN_MODE_NORMAL);
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
}
const harness_configuration red_harness_config = {
harness_configuration red_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOA,
@@ -174,13 +167,12 @@ const harness_configuration red_harness_config = {
.adc_channel_SBU2 = 17 //ADC1_INP17
};
const board board_red = {
board board_red = {
.set_bootkick = unused_set_bootkick,
.harness_config = &red_harness_config,
.has_obd = true,
.has_spi = false,
.has_canfd = true,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
+1 -8
View File
@@ -119,8 +119,6 @@ void red_chiplet_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
red_chiplet_enable_can_transceivers(true);
@@ -132,14 +130,9 @@ void red_chiplet_init(void) {
// Set normal CAN mode
red_chiplet_set_can_mode(CAN_MODE_NORMAL);
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
}
const harness_configuration red_chiplet_harness_config = {
harness_configuration red_chiplet_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOA,
+2 -3
View File
@@ -33,7 +33,7 @@ void tres_init(void) {
// Enable USB 3.3V LDO for USB block
register_set_bits(&(PWR->CR3), PWR_CR3_USBREGEN);
register_set_bits(&(PWR->CR3), PWR_CR3_USB33DEN);
while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0);
while ((PWR->CR3 & PWR_CR3_USB33RDY) == 0U);
red_chiplet_init();
@@ -70,12 +70,11 @@ void tres_init(void) {
clock_source_init();
}
const board board_tres = {
board board_tres = {
.harness_config = &red_chiplet_harness_config,
.has_obd = true,
.has_spi = true,
.has_canfd = true,
.has_rtc_battery = true,
.fan_max_rpm = 6600U,
.avdd_mV = 1800U,
.fan_stall_recovery = false,
+2 -10
View File
@@ -147,8 +147,6 @@ void uno_init(void) {
// Initialize harness
harness_init();
// Initialize RTC
rtc_init();
// Enable CAN transceivers
uno_enable_can_transceivers(true);
@@ -161,11 +159,6 @@ void uno_init(void) {
// Set normal CAN mode
uno_set_can_mode(CAN_MODE_NORMAL);
// change CAN mapping when flipped
if (harness.status == HARNESS_STATUS_FLIPPED) {
can_flip_buses(0, 2);
}
// Switch to phone usb mode if harness connection is powered by less than 7V
if(white_read_voltage_mV() < 7000U){
uno_set_usb_switch(true);
@@ -184,7 +177,7 @@ void uno_init_bootloader(void) {
set_gpio_output(GPIOC, 12, 0);
}
const harness_configuration uno_harness_config = {
harness_configuration uno_harness_config = {
.has_harness = true,
.GPIO_SBU1 = GPIOC,
.GPIO_SBU2 = GPIOC,
@@ -198,12 +191,11 @@ const harness_configuration uno_harness_config = {
.adc_channel_SBU2 = 13
};
const board board_uno = {
board board_uno = {
.harness_config = &uno_harness_config,
.has_obd = true,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = true,
.fan_max_rpm = 5100U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
+17 -59
View File
@@ -66,61 +66,22 @@ void white_set_usb_power_mode(uint8_t mode){
}
void white_set_can_mode(uint8_t mode){
switch (mode) {
case CAN_MODE_NORMAL:
// B12,B13: disable GMLAN mode
set_gpio_mode(GPIOB, 12, MODE_INPUT);
set_gpio_mode(GPIOB, 13, MODE_INPUT);
if (mode == CAN_MODE_NORMAL) {
// B12,B13: disable GMLAN mode
set_gpio_mode(GPIOB, 12, MODE_INPUT);
set_gpio_mode(GPIOB, 13, MODE_INPUT);
// B3,B4: disable GMLAN mode
set_gpio_mode(GPIOB, 3, MODE_INPUT);
set_gpio_mode(GPIOB, 4, MODE_INPUT);
// B3,B4: disable GMLAN mode
set_gpio_mode(GPIOB, 3, MODE_INPUT);
set_gpio_mode(GPIOB, 4, MODE_INPUT);
// B5,B6: normal CAN2 mode
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
// B5,B6: normal CAN2 mode
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
// A8,A15: normal CAN3 mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
break;
case CAN_MODE_GMLAN_CAN2:
// B5,B6: disable CAN2 mode
set_gpio_mode(GPIOB, 5, MODE_INPUT);
set_gpio_mode(GPIOB, 6, MODE_INPUT);
// B3,B4: disable GMLAN mode
set_gpio_mode(GPIOB, 3, MODE_INPUT);
set_gpio_mode(GPIOB, 4, MODE_INPUT);
// B12,B13: GMLAN mode
set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2);
// A8,A15: normal CAN3 mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
break;
case CAN_MODE_GMLAN_CAN3:
// A8,A15: disable CAN3 mode
set_gpio_mode(GPIOA, 8, MODE_INPUT);
set_gpio_mode(GPIOA, 15, MODE_INPUT);
// B12,B13: disable GMLAN mode
set_gpio_mode(GPIOB, 12, MODE_INPUT);
set_gpio_mode(GPIOB, 13, MODE_INPUT);
// B3,B4: GMLAN mode
set_gpio_alternate(GPIOB, 3, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOB, 4, GPIO_AF11_CAN3);
// B5,B6: normal CAN2 mode
set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2);
set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2);
break;
default:
print("Tried to set unsupported CAN mode: "); puth(mode); print("\n");
break;
// A8,A15: normal CAN3 mode
set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3);
set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3);
}
}
@@ -168,8 +129,8 @@ void white_grey_init(void) {
0 1 high voltage wakeup
1 1 33kbit (normal)
*/
set_gpio_output(GPIOB, 14, 1);
set_gpio_output(GPIOB, 15, 1);
set_gpio_output(GPIOB, 14, 0);
set_gpio_output(GPIOB, 15, 0);
// B7: K-line enable
set_gpio_output(GPIOB, 7, 1);
@@ -187,8 +148,6 @@ void white_grey_init(void) {
set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3);
set_gpio_pullup(GPIOC, 11, PULL_UP);
// Initialize RTC
rtc_init();
// Enable CAN transceivers
white_enable_can_transceivers(true);
@@ -221,17 +180,16 @@ void white_grey_init_bootloader(void) {
set_gpio_output(GPIOC, 14, 0);
}
const harness_configuration white_harness_config = {
harness_configuration white_harness_config = {
.has_harness = false
};
const board board_white = {
board board_white = {
.set_bootkick = unused_set_bootkick,
.harness_config = &white_harness_config,
.has_obd = false,
.has_spi = false,
.has_canfd = false,
.has_rtc_battery = false,
.fan_max_rpm = 0U,
.avdd_mV = 3300U,
.fan_stall_recovery = false,
+1 -3
View File
@@ -6,8 +6,6 @@ void puth4(uint8_t i){ UNUSED(i); }
void hexdump(const void *a, int l){ UNUSED(a); UNUSED(l); }
typedef struct board board;
typedef struct harness_configuration harness_configuration;
// No CAN support on bootloader
void can_flip_buses(uint8_t bus1, uint8_t bus2){UNUSED(bus1); UNUSED(bus2);}
void pwm_init(TIM_TypeDef *TIM, uint8_t channel);
void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage);
// No UART support in bootloader
@@ -17,4 +15,4 @@ void uart_init(uart_ring *q, int baud) { UNUSED(q); UNUSED(baud); }
// ********************* Globals **********************
uint8_t hw_type = 0;
const board *current_board;
board *current_board;
+2 -2
View File
@@ -63,7 +63,7 @@ void comms_can_write(const uint8_t *data, uint32_t len) {
if (can_write_buffer.ptr != 0U) {
if (can_write_buffer.tail_size <= (len - pos)) {
// we have enough data to complete the buffer
CANPacket_t to_push;
CANPacket_t to_push = {0};
(void)memcpy(&can_write_buffer.data[can_write_buffer.ptr], &data[pos], can_write_buffer.tail_size);
can_write_buffer.ptr += can_write_buffer.tail_size;
pos += can_write_buffer.tail_size;
@@ -89,7 +89,7 @@ void comms_can_write(const uint8_t *data, uint32_t len) {
while (pos < len) {
uint32_t pckt_len = CANPACKET_HEAD_SIZE + dlc_to_len[(data[pos] >> 4U)];
if ((pos + pckt_len) <= len) {
CANPacket_t to_push;
CANPacket_t to_push = {0};
(void)memcpy(&to_push, &data[pos], pckt_len);
can_send(&to_push, to_push.bus, false);
pos += pckt_len;
+1 -1
View File
@@ -1,7 +1,7 @@
#pragma once
const uint8_t PANDA_CAN_CNT = 3U;
const uint8_t PANDA_BUS_CNT = 4U;
const uint8_t PANDA_BUS_CNT = 3U;
// bump this when changing the CAN packet
#define CAN_PACKET_VERSION 4
+1 -2
View File
@@ -11,7 +11,6 @@
//#define DEBUG_FAN
#define CAN_INIT_TIMEOUT_MS 500U
#define DEEPSLEEP_WAKEUP_DELAY 3U
#define USBPACKET_MAX_SIZE 0x40U
#define MAX_CAN_MSGS_PER_USB_BULK_TRANSFER 51U
#define MAX_CAN_MSGS_PER_SPI_BULK_TRANSFER 170U
@@ -37,7 +36,7 @@
#ifdef STM32H7
#include "stm32h7/stm32h7_config.h"
#elif defined(STM32F4)
#include "stm32fx/stm32fx_config.h"
#include "stm32f4/stm32f4_config.h"
#else
// TODO: uncomment this, cppcheck complains
// building for tests
+1 -1
View File
@@ -11,7 +11,7 @@ Connect an ST-Link V2 programmer to the SWD pins on the board. The pins that nee
Make sure you're using a genuine one for boards that do not have a 3.3V panda power rail. For example, the tres runs at 1.8V, which is not supported by the clones.
## Openocd
Install openocd. For Ubuntu 20.04, the one in the package manager works fine: `sudo apt install openocd`.
Install openocd. For Ubuntu 24.04, the one in the package manager works fine: `sudo apt install openocd`.
To run, use `./debug_f4.sh (TODO)` or `./debug_h7.sh` depending on the panda.
+1 -1
View File
@@ -29,7 +29,7 @@ void bootkick_tick(bool ignition, bool recent_heartbeat) {
* once BOOT_RESET is triggered, it stays until countdown is finished
*/
if (!bootkick_reset_triggered && (boot_state == BOOT_BOOTKICK) && (boot_state_prev == BOOT_STANDBY)) {
waiting_to_boot_countdown = 45U;
waiting_to_boot_countdown = 20U;
}
if (waiting_to_boot_countdown > 0U) {
bool serial_activity = uart_ring_som_debug.w_ptr_tx != bootkick_last_serial_ptr;
+3 -3
View File
@@ -48,7 +48,7 @@ void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
can_health[can_number].total_error_cnt += 1U;
// RX message lost due to FIFO overrun
if ((CANx->RF0R & (CAN_RF0R_FOVR0)) != 0) {
if ((CANx->RF0R & (CAN_RF0R_FOVR0)) != 0U) {
can_health[can_number].total_rx_lost_cnt += 1U;
CANx->RF0R &= ~(CAN_RF0R_FOVR0);
}
@@ -74,7 +74,7 @@ void process_can(uint8_t can_number) {
// check for empty mailbox
CANPacket_t to_send;
if ((CANx->TSR & (CAN_TSR_TERR0 | CAN_TSR_ALST0)) != 0) { // last TX failed due to error arbitration lost
if ((CANx->TSR & (CAN_TSR_TERR0 | CAN_TSR_ALST0)) != 0U) { // last TX failed due to error arbitration lost
can_health[can_number].total_tx_lost_cnt += 1U;
CANx->TSR |= (CAN_TSR_TERR0 | CAN_TSR_ALST0);
}
@@ -129,7 +129,7 @@ void can_rx(uint8_t can_number) {
CAN_TypeDef *CANx = CANIF_FROM_CAN_NUM(can_number);
uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number);
while ((CANx->RF0R & CAN_RF0R_FMP0) != 0) {
while ((CANx->RF0R & CAN_RF0R_FMP0) != 0U) {
can_health[can_number].total_rx_cnt += 1U;
// can is live
+15 -26
View File
@@ -20,7 +20,6 @@ uint32_t safety_tx_blocked = 0;
uint32_t safety_rx_invalid = 0;
uint32_t tx_buffer_overflow = 0;
uint32_t rx_buffer_overflow = 0;
uint32_t gmlan_send_errs = 0;
can_health_t can_health[] = {{0}, {0}, {0}};
@@ -54,7 +53,6 @@ void process_can(uint8_t can_number);
#define CAN_RX_BUFFER_SIZE 4096U
#define CAN_TX_BUFFER_SIZE 416U
#define GMLAN_TX_BUFFER_SIZE 416U
#ifdef STM32H7
// ITCM RAM and DTCM RAM are the fastest for Cortex-M7 core access
@@ -67,10 +65,10 @@ can_buffer(tx1_q, CAN_TX_BUFFER_SIZE)
can_buffer(tx2_q, CAN_TX_BUFFER_SIZE)
#endif
can_buffer(tx3_q, CAN_TX_BUFFER_SIZE)
can_buffer(txgmlan_q, GMLAN_TX_BUFFER_SIZE)
// FIXME:
// cppcheck-suppress misra-c2012-9.3
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q};
can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q};
// helpers
#define WORD_TO_BYTE_ARRAY(dst8, src32) 0[dst8] = ((src32) & 0xFFU); 1[dst8] = (((src32) >> 8U) & 0xFFU); 2[dst8] = (((src32) >> 16U) & 0xFFU); 3[dst8] = (((src32) >> 24U) & 0xFFU)
@@ -122,8 +120,6 @@ bool can_push(can_ring *q, const CANPacket_t *elem) {
print("can_tx2_q");
} else if (q == &can_tx3_q) {
print("can_tx3_q");
} else if (q == &can_txgmlan_q) {
print("can_txgmlan_q");
} else {
print("unknown");
}
@@ -157,7 +153,7 @@ void can_clear(can_ring *q) {
}
// assign CAN numbering
// bus num: Can bus number on ODB connector. Sent to/from USB
// bus num: CAN Bus numbers in panda, 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);
@@ -179,22 +175,20 @@ bus_config_t bus_config[] = {
#define CAN_NUM_FROM_BUS_NUM(num) (bus_config[num].can_num_lookup)
void can_init_all(void) {
bool ret = true;
for (uint8_t i=0U; i < PANDA_CAN_CNT; i++) {
if (!current_board->has_canfd) {
bus_config[i].can_data_speed = 0U;
}
can_clear(can_queues[i]);
ret &= can_init(i);
(void)can_init(i);
}
UNUSED(ret);
}
void can_flip_buses(uint8_t bus1, uint8_t bus2){
bus_config[bus1].bus_lookup = bus2;
bus_config[bus2].bus_lookup = bus1;
bus_config[bus1].can_num_lookup = bus2;
bus_config[bus2].can_num_lookup = bus1;
void can_set_orientation(bool flipped) {
bus_config[0].bus_lookup = flipped ? 2U : 0U;
bus_config[0].can_num_lookup = flipped ? 2U : 0U;
bus_config[2].bus_lookup = flipped ? 0U : 2U;
bus_config[2].can_num_lookup = flipped ? 0U : 2U;
}
void can_set_forwarding(uint8_t from, uint8_t to) {
@@ -203,10 +197,10 @@ void can_set_forwarding(uint8_t from, uint8_t to) {
void ignition_can_hook(CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
if (bus == 0) {
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
// GM exception
if ((addr == 0x1F1) && (len == 8)) {
// SystemPowerMode (2=Run, 3=Crank Request)
@@ -234,8 +228,7 @@ bool can_tx_check_min_slots_free(uint32_t min) {
return
(can_slots_empty(&can_tx1_q) >= min) &&
(can_slots_empty(&can_tx2_q) >= min) &&
(can_slots_empty(&can_tx3_q) >= min) &&
(can_slots_empty(&can_txgmlan_q) >= min);
(can_slots_empty(&can_tx3_q) >= min);
}
uint8_t calculate_checksum(const uint8_t *dat, uint32_t len) {
@@ -259,12 +252,8 @@ void can_send(CANPacket_t *to_push, uint8_t bus_number, bool skip_tx_hook) {
if (skip_tx_hook || safety_tx_hook(to_push) != 0) {
if (bus_number < PANDA_BUS_CNT) {
// add CAN packet to send queue
if ((bus_number == 3U) && (bus_config[3].can_num_lookup == 0xFFU)) {
gmlan_send_errs += bitbang_gmlan(to_push) ? 0U : 1U;
} else {
tx_buffer_overflow += can_push(can_queues[bus_number], to_push) ? 0U : 1U;
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
}
tx_buffer_overflow += can_push(can_queues[bus_number], to_push) ? 0U : 1U;
process_can(CAN_NUM_FROM_BUS_NUM(bus_number));
}
} else {
safety_tx_blocked += 1U;
+2 -2
View File
@@ -26,8 +26,8 @@ void clock_source_init(void) {
set_gpio_alternate(GPIOB, 15, GPIO_AF1_TIM1);
// Set PWM mode
register_set(&(TIM1->CCMR1), (0b110 << TIM_CCMR1_OC2M_Pos), 0xFFFFU);
register_set(&(TIM1->CCMR2), (0b110 << TIM_CCMR2_OC3M_Pos), 0xFFFFU);
register_set(&(TIM1->CCMR1), (0b110UL << TIM_CCMR1_OC2M_Pos), 0xFFFFU);
register_set(&(TIM1->CCMR2), (0b110UL << TIM_CCMR2_OC3M_Pos), 0xFFFFU);
// Enable output
register_set(&(TIM1->BDTR), TIM_BDTR_MOE, 0xFFFFU);
+3 -3
View File
@@ -59,13 +59,13 @@ void fake_siren_init(void) {
register_set(&DMA1_Stream1->PAR, (uint32_t) &(DAC1->DHR8R1), 0xFFFFFFFFU);
DMA1_Stream1->NDTR = sizeof(fake_siren_lut);
register_set(&DMA1_Stream1->FCR, 0U, 0x00000083U);
DMA1_Stream1->CR = (0b11 << DMA_SxCR_PL_Pos);
DMA1_Stream1->CR |= DMA_SxCR_MINC | DMA_SxCR_CIRC | (1 << DMA_SxCR_DIR_Pos);
DMA1_Stream1->CR = (0b11UL << DMA_SxCR_PL_Pos);
DMA1_Stream1->CR |= DMA_SxCR_MINC | DMA_SxCR_CIRC | (1U << DMA_SxCR_DIR_Pos);
// Init trigger timer (around 2.5kHz)
register_set(&TIM7->PSC, 0U, 0xFFFFU);
register_set(&TIM7->ARR, 133U, 0xFFFFU);
register_set(&TIM7->CR2, (0b10 << TIM_CR2_MMS_Pos), TIM_CR2_MMS_Msk);
register_set(&TIM7->CR2, (0b10U << TIM_CR2_MMS_Pos), TIM_CR2_MMS_Msk);
register_set(&TIM7->CR1, TIM_CR1_ARPE | TIM_CR1_URS, 0x088EU);
TIM7->SR = 0U;
TIM7->CR1 |= TIM_CR1_CEN;
+8 -8
View File
@@ -67,14 +67,14 @@ void update_can_health_pkt(uint8_t can_number, uint32_t ir_reg) {
FDCANx->IR |= (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L);
can_health[can_number].total_error_cnt += 1U;
// Check for RX FIFO overflow
if ((ir_reg & (FDCAN_IR_RF0L)) != 0) {
if ((ir_reg & (FDCAN_IR_RF0L)) != 0U) {
can_health[can_number].total_rx_lost_cnt += 1U;
}
// Cases:
// 1. while multiplexing between buses 1 and 3 we are getting ACK errors that overwhelm CAN core, by resetting it recovers faster
// 2. H7 gets stuck in bus off recovery state indefinitely
if ((((can_health[can_number].last_error == CAN_ACK_ERROR) || (can_health[can_number].last_data_error == CAN_ACK_ERROR)) && (can_health[can_number].transmit_error_cnt > 127U)) ||
((ir_reg & FDCAN_IR_BO) != 0)) {
((ir_reg & FDCAN_IR_BO) != 0U)) {
can_health[can_number].can_core_reset_cnt += 1U;
can_health[can_number].total_tx_lost_cnt += (FDCAN_TX_FIFO_EL_CNT - (FDCANx->TXFQS & FDCAN_TXFQS_TFFL)); // TX FIFO msgs will be lost after reset
llcan_clear_send(FDCANx);
@@ -93,7 +93,7 @@ void process_can(uint8_t can_number) {
FDCANx->IR |= FDCAN_IR_TFE; // Clear Tx FIFO Empty flag
if ((FDCANx->TXFQS & FDCAN_TXFQS_TFQF) == 0) {
if ((FDCANx->TXFQS & FDCAN_TXFQS_TFQF) == 0U) {
CANPacket_t to_send;
if (can_pop(can_queues[bus_number], &to_send)) {
if (can_check_checksum(&to_send)) {
@@ -101,7 +101,7 @@ void process_can(uint8_t can_number) {
uint32_t TxFIFOSA = FDCAN_START_ADDRESS + (can_number * FDCAN_OFFSET) + (FDCAN_RX_FIFO_0_EL_CNT * FDCAN_RX_FIFO_0_EL_SIZE);
// get the index of the next TX FIFO element (0 to FDCAN_TX_FIFO_EL_CNT - 1)
uint32_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1F;
uint32_t tx_index = (FDCANx->TXFQS >> FDCAN_TXFQS_TFQPI_Pos) & 0x1FU;
// only send if we have received a packet
canfd_fifo *fifo;
fifo = (canfd_fifo *)(TxFIFOSA + (tx_index * FDCAN_TX_FIFO_EL_SIZE));
@@ -126,7 +126,7 @@ void process_can(uint8_t can_number) {
to_push.rejected = 0U;
to_push.extended = to_send.extended;
to_push.addr = to_send.addr;
to_push.bus = to_send.bus;
to_push.bus = bus_number;
to_push.data_len_code = to_send.data_len_code;
(void)memcpy(to_push.data, to_send.data, dlc_to_len[to_push.data_len_code]);
can_set_checksum(&to_push);
@@ -153,14 +153,14 @@ void can_rx(uint8_t can_number) {
// Clear all new messages from Rx FIFO 0
FDCANx->IR |= FDCAN_IR_RF0N;
while((FDCANx->RXF0S & FDCAN_RXF0S_F0FL) != 0) {
while((FDCANx->RXF0S & FDCAN_RXF0S_F0FL) != 0U) {
can_health[can_number].total_rx_cnt += 1U;
// can is live
pending_can_live = 1;
// get the index of the next RX FIFO element (0 to FDCAN_RX_FIFO_0_EL_CNT - 1)
uint32_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3F);
uint32_t rx_fifo_idx = (uint8_t)((FDCANx->RXF0S >> FDCAN_RXF0S_F0GI_Pos) & 0x3FU);
// Recommended to offset get index by at least +1 if RX FIFO is in overwrite mode and full (datasheet)
if((FDCANx->RXF0S & FDCAN_RXF0S_F0F) == FDCAN_RXF0S_F0F) {
@@ -232,7 +232,7 @@ void can_rx(uint8_t can_number) {
}
// Error handling
if ((ir_reg & (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L)) != 0) {
if ((ir_reg & (FDCAN_IR_PED | FDCAN_IR_PEA | FDCAN_IR_EP | FDCAN_IR_BO | FDCAN_IR_RF0L)) != 0U) {
update_can_health_pkt(can_number, ir_reg);
}
}
-270
View File
@@ -1,270 +0,0 @@
#define GMLAN_TICKS_PER_SECOND 33300 //1sec @ 33.3kbps
#define GMLAN_TICKS_PER_TIMEOUT_TICKLE 500 //15ms @ 33.3kbps
#define GMLAN_HIGH 0 //0 is high on bus (dominant)
#define GMLAN_LOW 1 //1 is low on bus
#define DISABLED -1
#define BITBANG 0
#define GPIO_SWITCH 1
#define MAX_BITS_CAN_PACKET (200)
int gmlan_alt_mode = DISABLED;
// returns out_len
int do_bitstuff(char *out, const char *in, int in_len) {
int last_bit = -1;
int bit_cnt = 0;
int j = 0;
for (int i = 0; i < in_len; i++) {
char bit = in[i];
out[j] = bit;
j++;
// do the stuffing
if (bit == (char)last_bit) {
bit_cnt++;
if (bit_cnt == 5) {
// 5 in a row the same, do stuff
last_bit = !bit ? 1 : 0;
out[j] = last_bit;
j++;
bit_cnt = 1;
}
} else {
// this is a new bit
last_bit = (int)bit;
bit_cnt = 1;
}
}
return j;
}
int append_crc(char *in, int in_len) {
unsigned int crc = 0;
for (int i = 0; i < in_len; i++) {
crc <<= 1;
if (((unsigned int)(in[i]) ^ ((crc >> 15) & 1U)) != 0U) {
crc = crc ^ 0x4599U;
}
crc &= 0x7fffU;
}
int in_len_copy = in_len;
for (int i = 14; i >= 0; i--) {
in[in_len_copy] = (crc >> (unsigned int)(i)) & 1U;
in_len_copy++;
}
return in_len_copy;
}
int append_bits(char *in, int in_len, const char *app, int app_len) {
int in_len_copy = in_len;
for (int i = 0; i < app_len; i++) {
in[in_len_copy] = app[i];
in_len_copy++;
}
return in_len_copy;
}
int append_int(char *in, int in_len, int val, int val_len) {
int in_len_copy = in_len;
for (int i = val_len - 1; i >= 0; i--) {
in[in_len_copy] = ((unsigned int)(val) & (1U << (unsigned int)(i))) != 0U;
in_len_copy++;
}
return in_len_copy;
}
int get_bit_message(char *out, const CANPacket_t *to_bang) {
char pkt[MAX_BITS_CAN_PACKET];
char footer[] = {
1, // CRC delimiter
1, // ACK
1, // ACK delimiter
1,1,1,1,1,1,1, // EOF
1,1,1, // IFS
};
int len = 0;
// test packet
int dlc_len = GET_LEN(to_bang);
len = append_int(pkt, len, 0, 1); // Start-of-frame
if (to_bang->extended != 0U) {
// extended identifier
len = append_int(pkt, len, GET_ADDR(to_bang) >> 18, 11); // Identifier
len = append_int(pkt, len, 3, 2); // SRR+IDE
len = append_int(pkt, len, (GET_ADDR(to_bang)) & ((1UL << 18) - 1U), 18); // Identifier
len = append_int(pkt, len, 0, 3); // RTR+r1+r0
} else {
// standard identifier
len = append_int(pkt, len, GET_ADDR(to_bang), 11); // Identifier
len = append_int(pkt, len, 0, 3); // RTR+IDE+reserved
}
len = append_int(pkt, len, dlc_len, 4); // Data length code
// append data
for (int i = 0; i < dlc_len; i++) {
len = append_int(pkt, len, to_bang->data[i], 8);
}
// append crc
len = append_crc(pkt, len);
// do bitstuffing
len = do_bitstuff(out, pkt, len);
// append footer
len = append_bits(out, len, footer, sizeof(footer));
return len;
}
void TIM12_IRQ_Handler(void);
void setup_timer(void) {
// register interrupt
REGISTER_INTERRUPT(TIM8_BRK_TIM12_IRQn, TIM12_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN)
// setup
register_set(&(TIM12->PSC), (APB1_TIMER_FREQ-1U), 0xFFFFU); // Tick on 1 us
register_set(&(TIM12->CR1), TIM_CR1_CEN, 0x3FU); // Enable
register_set(&(TIM12->ARR), (30U-1U), 0xFFFFU); // 33.3 kbps
// in case it's disabled
NVIC_EnableIRQ(TIM8_BRK_TIM12_IRQn);
// run the interrupt
register_set(&(TIM12->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt
TIM12->SR = 0;
}
int gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE; //GMLAN transceiver times out every 17ms held high; tickle every 15ms
int can_timeout_counter = GMLAN_TICKS_PER_SECOND; //1 second
int inverted_bit_to_send = GMLAN_HIGH;
int gmlan_switch_below_timeout = -1;
int gmlan_switch_timeout_enable = 0;
void set_bitbanged_gmlan(int val) {
if (val != 0) {
register_set_bits(&(GPIOB->ODR), (1UL << 13));
} else {
register_clear_bits(&(GPIOB->ODR), (1UL << 13));
}
}
char pkt_stuffed[MAX_BITS_CAN_PACKET];
int gmlan_sending = -1;
int gmlan_sendmax = -1;
bool gmlan_send_ok = true;
int gmlan_silent_count = 0;
int gmlan_fail_count = 0;
#define REQUIRED_SILENT_TIME 10
#define MAX_FAIL_COUNT 10
void TIM12_IRQ_Handler(void) {
if (gmlan_alt_mode == BITBANG) {
if ((TIM12->SR & TIM_SR_UIF) && (gmlan_sendmax != -1)) {
int read = get_gpio_input(GPIOB, 12);
if (gmlan_silent_count < REQUIRED_SILENT_TIME) {
if (read == 0) {
gmlan_silent_count = 0;
} else {
gmlan_silent_count++;
}
} else {
bool retry = 0;
// in send loop
if ((gmlan_sending > 0) && // not first bit
((read == 0) && (pkt_stuffed[gmlan_sending-1] == (char)1)) && // bus wrongly dominant
(gmlan_sending != (gmlan_sendmax - 11))) { //not ack bit
print("GMLAN ERR: bus driven at ");
puth(gmlan_sending);
print("\n");
retry = 1;
} else if ((read == 1) && (gmlan_sending == (gmlan_sendmax - 11))) { // recessive during ACK
print("GMLAN ERR: didn't recv ACK\n");
retry = 1;
} else {
// do not retry
}
if (retry) {
// reset sender (retry after 7 silent)
set_bitbanged_gmlan(1); // recessive
gmlan_silent_count = 0;
gmlan_sending = 0;
gmlan_fail_count++;
if (gmlan_fail_count == MAX_FAIL_COUNT) {
print("GMLAN ERR: giving up send\n");
gmlan_send_ok = false;
}
} else {
set_bitbanged_gmlan(pkt_stuffed[gmlan_sending]);
gmlan_sending++;
}
}
if ((gmlan_sending == gmlan_sendmax) || (gmlan_fail_count == MAX_FAIL_COUNT)) {
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_INPUT);
register_clear_bits(&(TIM12->DIER), TIM_DIER_UIE); // No update interrupt
register_set(&(TIM12->CR1), 0U, 0x3FU); // Disable timer
gmlan_sendmax = -1; // exit
}
}
} else if (gmlan_alt_mode == GPIO_SWITCH) {
if ((TIM12->SR & TIM_SR_UIF) && (gmlan_switch_below_timeout != -1)) {
if ((can_timeout_counter == 0) && gmlan_switch_timeout_enable) {
//it has been more than 1 second since timeout was reset; disable timer and restore the GMLAN output
set_gpio_output(GPIOB, 13, GMLAN_LOW);
gmlan_switch_below_timeout = -1;
gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE;
gmlan_alt_mode = DISABLED;
}
else {
can_timeout_counter--;
if (gmlan_timeout_counter == 0) {
//Send a 1 (bus low) every 15ms to reset the GMLAN transceivers timeout
gmlan_timeout_counter = GMLAN_TICKS_PER_TIMEOUT_TICKLE;
set_gpio_output(GPIOB, 13, GMLAN_LOW);
}
else {
set_gpio_output(GPIOB, 13, inverted_bit_to_send);
gmlan_timeout_counter--;
}
}
}
} else {
// Invalid GMLAN mode. Do not put a print statement here, way too fast to keep up with
}
TIM12->SR = 0;
}
bool bitbang_gmlan(const CANPacket_t *to_bang) {
gmlan_send_ok = true;
gmlan_alt_mode = BITBANG;
#ifdef HW_TYPE_DOS
if (hw_type == HW_TYPE_DOS) {
if (gmlan_sendmax == -1) {
int len = get_bit_message(pkt_stuffed, to_bang);
gmlan_fail_count = 0;
gmlan_silent_count = 0;
gmlan_sending = 0;
gmlan_sendmax = len;
// setup for bitbang loop
set_bitbanged_gmlan(1); // recessive
set_gpio_mode(GPIOB, 13, MODE_OUTPUT);
// 33kbps
setup_timer();
}
}
#else
UNUSED(to_bang);
#endif
return gmlan_send_ok;
}
+3 -3
View File
@@ -11,7 +11,7 @@
#define OUTPUT_TYPE_OPEN_DRAIN 1U
typedef struct {
GPIO_TypeDef *bank;
GPIO_TypeDef * const bank;
uint8_t pin;
} gpio_t;
@@ -68,13 +68,13 @@ int get_gpio_input(const GPIO_TypeDef *GPIO, unsigned int pin) {
return (GPIO->IDR & (1UL << pin)) == (1UL << pin);
}
void gpio_set_all_output(const gpio_t *pins, uint8_t num_pins, bool enabled) {
void gpio_set_all_output(gpio_t *pins, uint8_t num_pins, bool enabled) {
for (uint8_t i = 0; i < num_pins; i++) {
set_gpio_output(pins[i].bank, pins[i].pin, enabled);
}
}
void gpio_set_bitmask(const gpio_t *pins, uint8_t num_pins, uint32_t bitmask) {
void gpio_set_bitmask(gpio_t *pins, uint8_t num_pins, uint32_t bitmask) {
for (uint8_t i = 0; i < num_pins; i++) {
set_gpio_output(pins[i].bank, pins[i].pin, (bitmask >> i) & 1U);
}
+10 -15
View File
@@ -13,16 +13,16 @@ struct harness_t harness;
struct harness_configuration {
const bool has_harness;
GPIO_TypeDef *GPIO_SBU1;
GPIO_TypeDef *GPIO_SBU2;
GPIO_TypeDef *GPIO_relay_SBU1;
GPIO_TypeDef *GPIO_relay_SBU2;
uint8_t pin_SBU1;
uint8_t pin_SBU2;
uint8_t pin_relay_SBU1;
uint8_t pin_relay_SBU2;
uint8_t adc_channel_SBU1;
uint8_t adc_channel_SBU2;
GPIO_TypeDef * const GPIO_SBU1;
GPIO_TypeDef * const GPIO_SBU2;
GPIO_TypeDef * const GPIO_relay_SBU1;
GPIO_TypeDef * const GPIO_relay_SBU2;
const uint8_t pin_SBU1;
const uint8_t pin_SBU2;
const uint8_t pin_relay_SBU1;
const uint8_t pin_relay_SBU2;
const uint8_t adc_channel_SBU1;
const uint8_t adc_channel_SBU2;
};
// The ignition relay is only used for testing purposes
@@ -117,11 +117,6 @@ void harness_tick(void) {
}
void harness_init(void) {
// delay such that the connection is fully made before trying orientation detection
current_board->set_led(LED_BLUE, true);
delay(10000000);
current_board->set_led(LED_BLUE, false);
// try to detect orientation
harness.status = harness_detect_orientation();
if (harness.status != HARNESS_STATUS_NC) {
+1 -1
View File
@@ -64,7 +64,7 @@ void handle_interrupt(IRQn_Type irq_type){
// Every second
void interrupt_timer_handler(void) {
if (INTERRUPT_TIMER->SR != 0) {
if (INTERRUPT_TIMER->SR != 0U) {
for (uint16_t i = 0U; i < NUM_INTERRUPTS; i++) {
// Log IRQ call rate faults
if (check_interrupt_rate && (interrupts[i].call_counter > interrupts[i].max_call_rate)) {
+2 -2
View File
@@ -44,13 +44,13 @@ void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask){
// Set individual bits. Also add them to the check_mask.
// Do not use this to change bits that get reset by the hardware
void register_set_bits(volatile uint32_t *addr, uint32_t val) {
return register_set(addr, val, val);
register_set(addr, val, val);
}
// Clear individual bits. Also add them to the check_mask.
// Do not use this to clear bits that get set by the hardware
void register_clear_bits(volatile uint32_t *addr, uint32_t val) {
return register_set(addr, (~val), val);
register_set(addr, (~val), val);
}
// To be called periodically
-79
View File
@@ -1,79 +0,0 @@
#define YEAR_OFFSET 2000U
typedef struct __attribute__((packed)) timestamp_t {
uint16_t year;
uint8_t month;
uint8_t day;
uint8_t weekday;
uint8_t hour;
uint8_t minute;
uint8_t second;
} timestamp_t;
uint8_t to_bcd(uint16_t value){
return (((value / 10U) & 0x0FU) << 4U) | ((value % 10U) & 0x0FU);
}
uint16_t from_bcd(uint8_t value){
return (((value & 0xF0U) >> 4U) * 10U) + (value & 0x0FU);
}
void rtc_set_time(timestamp_t time){
print("Setting RTC time\n");
// Disable write protection
disable_bdomain_protection();
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
// Enable initialization mode
register_set_bits(&(RTC->ISR), RTC_ISR_INIT);
while((RTC->ISR & RTC_ISR_INITF) == 0){}
// Set time
RTC->TR = (to_bcd(time.hour) << RTC_TR_HU_Pos) | (to_bcd(time.minute) << RTC_TR_MNU_Pos) | (to_bcd(time.second) << RTC_TR_SU_Pos);
RTC->DR = (to_bcd(time.year - YEAR_OFFSET) << RTC_DR_YU_Pos) | (time.weekday << RTC_DR_WDU_Pos) | (to_bcd(time.month) << RTC_DR_MU_Pos) | (to_bcd(time.day) << RTC_DR_DU_Pos);
// Set options
register_set(&(RTC->CR), 0U, 0xFCFFFFU);
// Disable initalization mode
register_clear_bits(&(RTC->ISR), RTC_ISR_INIT);
// Wait for synchronization
while((RTC->ISR & RTC_ISR_RSF) == 0){}
// Re-enable write protection
RTC->WPR = 0x00;
enable_bdomain_protection();
}
timestamp_t rtc_get_time(void){
timestamp_t result;
// Init with zero values in case there is no RTC running
result.year = 0U;
result.month = 0U;
result.day = 0U;
result.weekday = 0U;
result.hour = 0U;
result.minute = 0U;
result.second = 0U;
// Wait until the register sync flag is set
while((RTC->ISR & RTC_ISR_RSF) == 0){}
// Read time and date registers. Since our HSE > 7*LSE, this should be fine.
uint32_t time = RTC->TR;
uint32_t date = RTC->DR;
// Parse values
result.year = from_bcd((date & (RTC_DR_YT | RTC_DR_YU)) >> RTC_DR_YU_Pos) + YEAR_OFFSET;
result.month = from_bcd((date & (RTC_DR_MT | RTC_DR_MU)) >> RTC_DR_MU_Pos);
result.day = from_bcd((date & (RTC_DR_DT | RTC_DR_DU)) >> RTC_DR_DU_Pos);
result.weekday = ((date & RTC_DR_WDU) >> RTC_DR_WDU_Pos);
result.hour = from_bcd((time & (RTC_TR_HT | RTC_TR_HU)) >> RTC_TR_HU_Pos);
result.minute = from_bcd((time & (RTC_TR_MNT | RTC_TR_MNU)) >> RTC_TR_MNU_Pos);
result.second = from_bcd((time & (RTC_TR_ST | RTC_TR_SU)) >> RTC_TR_SU_Pos);
return result;
}
+7 -5
View File
@@ -43,7 +43,7 @@ uint16_t spi_data_len_miso;
uint16_t spi_checksum_error_count = 0;
bool spi_can_tx_ready = false;
const char version_text[] = "VERSION";
const unsigned char version_text[] = "VERSION";
#define SPI_HEADER_SIZE 7U
@@ -73,10 +73,8 @@ uint16_t spi_version_packet(uint8_t *out) {
uint16_t data_pos = 7U + 2U;
// write serial
#ifdef UID_BASE
(void)memcpy(&out[data_pos], ((uint8_t *)UID_BASE), 12);
data_len += 12U;
#endif
// HW type
out[data_pos + data_len] = hw_type;
@@ -154,7 +152,7 @@ void spi_rx_done(void) {
if (checksum_valid) {
if (spi_endpoint == 0U) {
if (spi_data_len_mosi >= sizeof(ControlPacket_t)) {
ControlPacket_t ctrl;
ControlPacket_t ctrl = {0};
(void)memcpy(&ctrl, &spi_buf_rx[SPI_HEADER_SIZE], sizeof(ControlPacket_t));
response_len = comms_control_handler(&ctrl, &spi_buf_tx[3]);
response_ack = true;
@@ -184,6 +182,10 @@ void spi_rx_done(void) {
} else {
print("SPI: did expect data for can_write\n");
}
} else if (spi_endpoint == 0xABU) {
// test endpoint, send max response length
response_len = spi_data_len_miso;
response_ack = true;
} else {
print("SPI: unexpected endpoint"); puth(spi_endpoint); print("\n");
}
@@ -232,7 +234,7 @@ void spi_rx_done(void) {
llspi_miso_dma(spi_buf_tx, response_len);
spi_state = next_rx_state;
if (!checksum_valid && (spi_checksum_error_count < __UINT16_MAX__)) {
if (!checksum_valid && (spi_checksum_error_count < UINT16_MAX)) {
spi_checksum_error_count += 1U;
}
}
+83 -102
View File
@@ -304,13 +304,6 @@ uint8_t binary_object_store_desc[] = {
MS_VENDOR_CODE, 0x00 // vendor code, no alternate enumeration
};
uint8_t webusb_url_descriptor[] = {
0x14, /* bLength */
WEBUSB_DESC_TYPE_URL, // bDescriptorType
WEBUSB_URL_SCHEME_HTTPS, // bScheme
'u', 's', 'b', 'p', 'a', 'n', 'd', 'a', '.', 'c', 'o', 'm', 'm', 'a', '.', 'a', 'i'
};
// WinUSB 2.0 descriptor. This is what modern systems use
// https://github.com/sowbug/weblight/blob/192ad7a0e903542e2aa28c607d98254a12a6399d/firmware/webusb.c
// http://janaxelson.com/files/ms_os_20_descriptors.c
@@ -364,10 +357,10 @@ int current_int0_alt_setting = 0;
void *USB_ReadPacket(void *dest, uint16_t len) {
uint32_t *dest_copy = (uint32_t *)dest;
uint32_t count32b = (len + 3U) / 4U;
uint32_t count32b = ((uint32_t)len + 3U) / 4U;
for (uint32_t i = 0; i < count32b; i++) {
*dest_copy = USBx_DFIFO(0);
*dest_copy = USBx_DFIFO(0U);
dest_copy++;
}
return ((void *)dest_copy);
@@ -379,9 +372,9 @@ void USB_WritePacket(const void *src, uint16_t len, uint32_t ep) {
hexdump(src, len);
#endif
uint32_t numpacket = (len + (USBPACKET_MAX_SIZE - 1U)) / USBPACKET_MAX_SIZE;
uint32_t numpacket = ((uint32_t)len + (USBPACKET_MAX_SIZE - 1U)) / USBPACKET_MAX_SIZE;
uint32_t count32b = 0;
count32b = (len + 3U) / 4U;
count32b = ((uint32_t)len + 3U) / 4U;
// TODO: revisit this
USBx_INEP(ep)->DIEPTSIZ = ((numpacket << 19) & USB_OTG_DIEPTSIZ_PKTCNT) |
@@ -414,7 +407,7 @@ void USB_WritePacket_EP0(uint8_t *src, uint16_t len) {
ep0_txlen = len - wplen;
USBx_DEVICE->DIEPEMPMSK |= 1;
} else {
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
}
@@ -431,8 +424,8 @@ void usb_reset(void) {
USBx_DEVICE->DOEPMSK = 0xFFFFFFFFU;
// clear interrupts
USBx_INEP(0)->DIEPINT = 0xFF;
USBx_OUTEP(0)->DOEPINT = 0xFF;
USBx_INEP(0U)->DIEPINT = 0xFF;
USBx_OUTEP(0U)->DOEPINT = 0xFF;
// unset the address
USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD;
@@ -458,7 +451,7 @@ void usb_reset(void) {
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK;
// ready to receive setup packets
USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (3U << 3);
USBx_OUTEP(0U)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (3U << 3);
}
char to_hex_char(uint8_t a) {
@@ -485,26 +478,26 @@ void usb_setup(void) {
switch (setup.b.bRequest) {
case USB_REQ_SET_CONFIGURATION:
// enable other endpoints, has to be here?
USBx_INEP(1)->DIEPCTL = (0x40U & USB_OTG_DIEPCTL_MPSIZ) | (2UL << 18) | (1UL << 22) |
USBx_INEP(1U)->DIEPCTL = (0x40U & USB_OTG_DIEPCTL_MPSIZ) | (2UL << 18) | (1UL << 22) |
USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DIEPCTL_USBAEP;
USBx_INEP(1)->DIEPINT = 0xFF;
USBx_INEP(1U)->DIEPINT = 0xFF;
USBx_OUTEP(2)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USBx_OUTEP(2U)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2U)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP;
USBx_OUTEP(2)->DOEPINT = 0xFF;
USBx_OUTEP(2U)->DOEPINT = 0xFF;
USBx_OUTEP(3)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USBx_OUTEP(3U)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3U)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2UL << 18) |
USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP;
USBx_OUTEP(3)->DOEPINT = 0xFF;
USBx_OUTEP(3U)->DOEPINT = 0xFF;
// mark ready to receive
USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(2U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(3U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_SET_ADDRESS:
// set now?
@@ -515,7 +508,7 @@ void usb_setup(void) {
#endif
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_GET_DESCRIPTOR:
@@ -527,17 +520,17 @@ void usb_setup(void) {
device_desc[13] = hw_type;
// setup transfer
USB_WritePacket(device_desc, MIN(sizeof(device_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
//print("D");
break;
case USB_DESC_TYPE_CONFIGURATION:
USB_WritePacket(configuration_desc, MIN(sizeof(configuration_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_DESC_TYPE_DEVICE_QUALIFIER:
USB_WritePacket(device_qualifier, MIN(sizeof(device_qualifier), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_DESC_TYPE_STRING:
switch (setup.b.wValue.bw.msb) {
@@ -551,23 +544,19 @@ void usb_setup(void) {
USB_WritePacket((uint8_t*)string_product_desc, MIN(sizeof(string_product_desc), setup.b.wLength.w), 0);
break;
case STRING_OFFSET_ISERIAL:
#ifdef UID_BASE
response[0] = 0x02 + (12 * 4);
response[1] = 0x03;
response[0] = 0x02 + (12 * 4);
response[1] = 0x03;
// 96 bits = 12 bytes
for (int i = 0; i < 12; i++){
uint8_t cc = ((uint8_t *)UID_BASE)[i];
response[2 + (i * 4)] = to_hex_char((cc >> 4) & 0xFU);
response[2 + (i * 4) + 1] = '\0';
response[2 + (i * 4) + 2] = to_hex_char((cc >> 0) & 0xFU);
response[2 + (i * 4) + 3] = '\0';
}
// 96 bits = 12 bytes
for (int i = 0; i < 12; i++){
uint8_t cc = ((uint8_t *)UID_BASE)[i];
response[2 + (i * 4)] = to_hex_char((cc >> 4) & 0xFU);
response[2 + (i * 4) + 1] = '\0';
response[2 + (i * 4) + 2] = to_hex_char((cc >> 0) & 0xFU);
response[2 + (i * 4) + 3] = '\0';
}
USB_WritePacket(response, MIN(response[0], setup.b.wLength.w), 0);
#else
USB_WritePacket((const uint8_t *)string_serial_desc, MIN(sizeof(string_serial_desc), setup.b.wLength.w), 0);
#endif
USB_WritePacket(response, MIN(response[0], setup.b.wLength.w), 0);
break;
case STRING_OFFSET_ICONFIGURATION:
USB_WritePacket((uint8_t*)string_configuration_desc, MIN(sizeof(string_configuration_desc), setup.b.wLength.w), 0);
@@ -580,16 +569,16 @@ void usb_setup(void) {
USB_WritePacket(0, 0, 0);
break;
}
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_DESC_TYPE_BINARY_OBJECT_STORE:
USB_WritePacket(binary_object_store_desc, MIN(sizeof(binary_object_store_desc), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
// nothing here?
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
}
break;
@@ -598,26 +587,18 @@ void usb_setup(void) {
response[0] = 0;
response[1] = 0;
USB_WritePacket((void*)&response, 2, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case USB_REQ_SET_INTERFACE:
// Store the alt setting number for IN EP behavior.
current_int0_alt_setting = setup.b.wValue.w;
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case WEBUSB_VENDOR_CODE:
switch (setup.b.wIndex.w) {
case WEBUSB_REQ_GET_URL:
USB_WritePacket(webusb_url_descriptor, MIN(sizeof(webusb_url_descriptor), setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
default:
// probably asking for allowed origins, which was removed from the spec
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
}
// probably asking for allowed origins, which was removed from the spec
USB_WritePacket(0, 0, 0);
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
break;
case MS_VENDOR_CODE:
switch (setup.b.wIndex.w) {
@@ -647,7 +628,7 @@ void usb_setup(void) {
// response pending if -1 was returned
if (resp_len != -1) {
USB_WritePacket(response, MIN(resp_len, setup.b.wLength.w), 0);
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
}
}
@@ -675,23 +656,23 @@ void usb_irqhandler(void) {
print(" USB interrupt!\n");
#endif
if ((gintsts & USB_OTG_GINTSTS_CIDSCHG) != 0) {
if ((gintsts & USB_OTG_GINTSTS_CIDSCHG) != 0U) {
print("connector ID status change\n");
}
if ((gintsts & USB_OTG_GINTSTS_USBRST) != 0) {
if ((gintsts & USB_OTG_GINTSTS_USBRST) != 0U) {
print("USB reset\n");
usb_reset();
}
if ((gintsts & USB_OTG_GINTSTS_ENUMDNE) != 0) {
if ((gintsts & USB_OTG_GINTSTS_ENUMDNE) != 0U) {
print("enumeration done");
// Full speed, ENUMSPD
//puth(USBx_DEVICE->DSTS);
print("\n");
}
if ((gintsts & USB_OTG_GINTSTS_OTGINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_OTGINT) != 0U) {
print("OTG int:");
puth(USBx->GOTGINT);
print("\n");
@@ -701,7 +682,7 @@ void usb_irqhandler(void) {
}
// RX FIFO first
if ((gintsts & USB_OTG_GINTSTS_RXFLVL) != 0) {
if ((gintsts & USB_OTG_GINTSTS_RXFLVL) != 0U) {
// 1. Read the Receive status pop register
volatile unsigned int rxst = USBx->GRXSTSP;
int status = (rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17;
@@ -767,7 +748,7 @@ void usb_irqhandler(void) {
USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK;
}
if ((gintsts & USB_OTG_GINTSTS_SRQINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_SRQINT) != 0U) {
// we want to do "A-device host negotiation protocol" since we are the A-device
/*print("start request\n");
puth(USBx->GOTGCTL);
@@ -778,76 +759,76 @@ void usb_irqhandler(void) {
}
// out endpoint hit
if ((gintsts & USB_OTG_GINTSTS_OEPINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_OEPINT) != 0U) {
#ifdef DEBUG_USB
print(" 0:");
puth(USBx_OUTEP(0)->DOEPINT);
puth(USBx_OUTEP(0U)->DOEPINT);
print(" 2:");
puth(USBx_OUTEP(2)->DOEPINT);
puth(USBx_OUTEP(2U)->DOEPINT);
print(" 3:");
puth(USBx_OUTEP(3)->DOEPINT);
puth(USBx_OUTEP(3U)->DOEPINT);
print(" ");
puth(USBx_OUTEP(3)->DOEPCTL);
puth(USBx_OUTEP(3U)->DOEPCTL);
print(" 4:");
puth(USBx_OUTEP(4)->DOEPINT);
print(" OUT ENDPOINT\n");
#endif
if ((USBx_OUTEP(2)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0) {
if ((USBx_OUTEP(2U)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0U) {
#ifdef DEBUG_USB
print(" OUT2 PACKET XFRC\n");
#endif
USBx_OUTEP(2)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(2U)->DOEPTSIZ = (1UL << 19) | 0x40U;
USBx_OUTEP(2U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
if ((USBx_OUTEP(3)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0) {
if ((USBx_OUTEP(3U)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0U) {
#ifdef DEBUG_USB
print(" OUT3 PACKET XFRC\n");
#endif
// NAK cleared by process_can (if tx buffers have room)
outep3_processing = false;
refresh_can_tx_slots_available();
} else if ((USBx_OUTEP(3)->DOEPINT & 0x2000) != 0) {
} else if ((USBx_OUTEP(3U)->DOEPINT & 0x2000U) != 0U) {
#ifdef DEBUG_USB
print(" OUT3 PACKET WTF\n");
#endif
// if NAK was set trigger this, unknown interrupt
// TODO: why was this here? fires when TX buffers when we can't clear NAK
// USBx_OUTEP(3)->DOEPTSIZ = (1U << 19) | 0x40U;
// USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
} else if ((USBx_OUTEP(3)->DOEPINT) != 0) {
// USBx_OUTEP(3U)->DOEPTSIZ = (1U << 19) | 0x40U;
// USBx_OUTEP(3U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
} else if ((USBx_OUTEP(3U)->DOEPINT) != 0U) {
#ifdef DEBUG_USB
print("OUTEP3 error ");
puth(USBx_OUTEP(3)->DOEPINT);
puth(USBx_OUTEP(3U)->DOEPINT);
print("\n");
#endif
} else {
// USBx_OUTEP(3)->DOEPINT is 0, ok to skip
// USBx_OUTEP(3U)->DOEPINT is 0, ok to skip
}
if ((USBx_OUTEP(0)->DOEPINT & USB_OTG_DIEPINT_XFRC) != 0) {
if ((USBx_OUTEP(0U)->DOEPINT & USB_OTG_DIEPINT_XFRC) != 0U) {
// ready for next packet
USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (1U << 3);
USBx_OUTEP(0U)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1UL << 19)) | (1U << 3);
}
// respond to setup packets
if ((USBx_OUTEP(0)->DOEPINT & USB_OTG_DOEPINT_STUP) != 0) {
if ((USBx_OUTEP(0U)->DOEPINT & USB_OTG_DOEPINT_STUP) != 0U) {
usb_setup();
}
USBx_OUTEP(0)->DOEPINT = USBx_OUTEP(0)->DOEPINT;
USBx_OUTEP(2)->DOEPINT = USBx_OUTEP(2)->DOEPINT;
USBx_OUTEP(3)->DOEPINT = USBx_OUTEP(3)->DOEPINT;
USBx_OUTEP(0U)->DOEPINT = USBx_OUTEP(0U)->DOEPINT;
USBx_OUTEP(2U)->DOEPINT = USBx_OUTEP(2U)->DOEPINT;
USBx_OUTEP(3U)->DOEPINT = USBx_OUTEP(3U)->DOEPINT;
}
// interrupt endpoint hit (Page 1221)
if ((gintsts & USB_OTG_GINTSTS_IEPINT) != 0) {
if ((gintsts & USB_OTG_GINTSTS_IEPINT) != 0U) {
#ifdef DEBUG_USB
print(" ");
puth(USBx_INEP(0)->DIEPINT);
puth(USBx_INEP(0U)->DIEPINT);
print(" ");
puth(USBx_INEP(1)->DIEPINT);
puth(USBx_INEP(1U)->DIEPINT);
print(" IN ENDPOINT\n");
#endif
@@ -867,7 +848,7 @@ void usb_irqhandler(void) {
switch (current_int0_alt_setting) {
case 0: ////// Bulk config
// *** IN token received when TxFIFO is empty
if ((USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) {
if ((USBx_INEP(1U)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0U) {
#ifdef DEBUG_USB
print(" IN PACKET QUEUE\n");
#endif
@@ -878,7 +859,7 @@ void usb_irqhandler(void) {
case 1: ////// Interrupt config
// *** IN token received when TxFIFO is empty
if ((USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) {
if ((USBx_INEP(1U)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0U) {
#ifdef DEBUG_USB
print(" IN PACKET QUEUE\n");
#endif
@@ -894,12 +875,12 @@ void usb_irqhandler(void) {
break;
}
if ((USBx_INEP(0)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) {
if ((USBx_INEP(0U)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0U) {
#ifdef DEBUG_USB
print(" IN PACKET QUEUE\n");
#endif
if ((ep0_txlen != 0U) && ((USBx_INEP(0)->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) >= 0x40U)) {
if ((ep0_txlen != 0U) && ((USBx_INEP(0U)->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) >= 0x40U)) {
uint16_t len = MIN(ep0_txlen, 0x40);
USB_WritePacket(ep0_txdata, len, 0);
ep0_txdata = &ep0_txdata[len];
@@ -907,14 +888,14 @@ void usb_irqhandler(void) {
if (ep0_txlen == 0U) {
ep0_txdata = NULL;
USBx_DEVICE->DIEPEMPMSK &= ~1;
USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
USBx_OUTEP(0U)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK;
}
}
}
// clear interrupts
USBx_INEP(0)->DIEPINT = USBx_INEP(0)->DIEPINT; // Why ep0?
USBx_INEP(1)->DIEPINT = USBx_INEP(1)->DIEPINT;
USBx_INEP(0U)->DIEPINT = USBx_INEP(0U)->DIEPINT; // Why ep0?
USBx_INEP(1U)->DIEPINT = USBx_INEP(1U)->DIEPINT;
}
// clear all interrupts we handled
@@ -927,9 +908,9 @@ void usb_irqhandler(void) {
void can_tx_comms_resume_usb(void) {
ENTER_CRITICAL();
if (!outep3_processing && (USBx_OUTEP(3)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) != 0) {
USBx_OUTEP(3)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
if (!outep3_processing && (USBx_OUTEP(3U)->DOEPCTL & USB_OTG_DOEPCTL_NAKSTS) != 0U) {
USBx_OUTEP(3U)->DOEPTSIZ = (32UL << 19) | 0x800U;
USBx_OUTEP(3U)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK;
}
EXIT_CRITICAL();
}
+6 -1
View File
@@ -6,10 +6,15 @@
extern void *g_pfnVectors;
extern uint32_t enter_bootloader_mode;
typedef void (*bootloader_fcn)(void);
typedef bootloader_fcn *bootloader_fcn_ptr;
void jump_to_bootloader(void) {
// do enter bootloader
enter_bootloader_mode = 0;
void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *)BOOTLOADER_ADDRESS));
bootloader_fcn_ptr bootloader_ptr = (bootloader_fcn_ptr)BOOTLOADER_ADDRESS;
bootloader_fcn bootloader = *bootloader_ptr;
// jump to bootloader
enable_interrupts();
+1 -1
View File
@@ -9,7 +9,7 @@
#define FAULT_INTERRUPT_RATE_CAN_2 (1UL << 3)
#define FAULT_INTERRUPT_RATE_CAN_3 (1UL << 4)
#define FAULT_INTERRUPT_RATE_TACH (1UL << 5)
#define FAULT_INTERRUPT_RATE_GMLAN (1UL << 6)
#define FAULT_INTERRUPT_RATE_GMLAN (1UL << 6) // deprecated
#define FAULT_INTERRUPT_RATE_INTERRUPTS (1UL << 7)
#define FAULT_INTERRUPT_RATE_SPI_DMA (1UL << 8)
#define FAULT_INTERRUPT_RATE_SPI_CS (1UL << 9)
+1
View File
@@ -15,3 +15,4 @@ if __name__ == "__main__":
print("flashing", s)
with Panda(serial=s) as p:
p.flash()
exit(1 if len(serials) == 0 else 0)
+1 -2
View File
@@ -1,6 +1,6 @@
// When changing these structs, python/__init__.py needs to be kept up to date!
#define HEALTH_PACKET_VERSION 15
#define HEALTH_PACKET_VERSION 16
struct __attribute__((packed)) health_t {
uint32_t uptime_pkt;
uint32_t voltage_pkt;
@@ -9,7 +9,6 @@ struct __attribute__((packed)) health_t {
uint32_t safety_rx_invalid_pkt;
uint32_t tx_buffer_overflow_pkt;
uint32_t rx_buffer_overflow_pkt;
uint32_t gmlan_send_errs_pkt;
uint32_t faults_pkt;
uint8_t ignition_line_pkt;
uint8_t ignition_can_pkt;
+10 -2
View File
@@ -2,7 +2,6 @@
import os
import struct
from functools import wraps
from typing import Optional
from panda import Panda, PandaDFU
from panda.python.constants import McuType
@@ -57,7 +56,7 @@ class PandaJungle(Panda):
fn = os.path.join(FW_PATH, self._mcu_type.config.app_fn.replace("panda", "panda_jungle"))
super().flash(fn=fn, code=code, reconnect=reconnect)
def recover(self, timeout: Optional[int] = 60, reset: bool = True) -> bool:
def recover(self, timeout: int | None = 60, reset: bool = True) -> bool:
dfu_serial = self.get_dfu_serial()
if reset:
@@ -81,6 +80,12 @@ class PandaJungle(Panda):
return McuType.F4
elif hw_type in PandaJungle.H7_DEVICES:
return McuType.H7
else:
# have to assume F4, see comment in Panda.connect
# initially Jungle V1 has HW type: bytearray(b'')
if hw_type == b'' or self._assume_f4_mcu:
return McuType.F4
raise ValueError(f"unknown HW type: {hw_type}")
def up_to_date(self, fn=None) -> bool:
@@ -143,6 +148,9 @@ class PandaJungle(Panda):
def set_can_silent(self, silent):
self._handle.controlWrite(PandaJungle.REQUEST_OUT, 0xf5, int(silent), 0, b'')
def set_generated_can(self, enabled):
self._handle.controlWrite(PandaJungle.REQUEST_OUT, 0xa4, int(enabled), 0, b'')
# ******************* serial *******************
def debug_read(self):
@@ -49,8 +49,6 @@ struct board {
// CAN modes
#define CAN_MODE_NORMAL 0U
#define CAN_MODE_GMLAN_CAN2 1U
#define CAN_MODE_GMLAN_CAN3 2U
#define CAN_MODE_OBD_CAN2 3U
// Harness states
+1 -1
View File
@@ -157,7 +157,7 @@ void board_v1_init(void) {
void board_v1_tick(void) {}
const board board_v1 = {
board board_v1 = {
.has_canfd = false,
.has_sbu_sense = false,
.avdd_mV = 3300U,
+8 -8
View File
@@ -2,7 +2,7 @@
// Jungle board v2 (STM32H7) //
// ///////////////////////// //
const gpio_t power_pins[] = {
gpio_t power_pins[] = {
{.bank = GPIOA, .pin = 0},
{.bank = GPIOA, .pin = 1},
{.bank = GPIOF, .pin = 12},
@@ -11,7 +11,7 @@ const gpio_t power_pins[] = {
{.bank = GPIOB, .pin = 2},
};
const gpio_t sbu1_ignition_pins[] = {
gpio_t sbu1_ignition_pins[] = {
{.bank = GPIOD, .pin = 0},
{.bank = GPIOD, .pin = 5},
{.bank = GPIOD, .pin = 12},
@@ -20,7 +20,7 @@ const gpio_t sbu1_ignition_pins[] = {
{.bank = GPIOE, .pin = 9},
};
const gpio_t sbu1_relay_pins[] = {
gpio_t sbu1_relay_pins[] = {
{.bank = GPIOD, .pin = 1},
{.bank = GPIOD, .pin = 6},
{.bank = GPIOD, .pin = 11},
@@ -29,7 +29,7 @@ const gpio_t sbu1_relay_pins[] = {
{.bank = GPIOE, .pin = 10},
};
const gpio_t sbu2_ignition_pins[] = {
gpio_t sbu2_ignition_pins[] = {
{.bank = GPIOD, .pin = 3},
{.bank = GPIOD, .pin = 8},
{.bank = GPIOD, .pin = 9},
@@ -38,7 +38,7 @@ const gpio_t sbu2_ignition_pins[] = {
{.bank = GPIOE, .pin = 11},
};
const gpio_t sbu2_relay_pins[] = {
gpio_t sbu2_relay_pins[] = {
{.bank = GPIOD, .pin = 4},
{.bank = GPIOD, .pin = 10},
{.bank = GPIOD, .pin = 13},
@@ -47,7 +47,7 @@ const gpio_t sbu2_relay_pins[] = {
{.bank = GPIOE, .pin = 12},
};
const adc_channel_t sbu1_channels[] = {
adc_channel_t sbu1_channels[] = {
{.adc = ADC3, .channel = 12},
{.adc = ADC3, .channel = 2},
{.adc = ADC3, .channel = 4},
@@ -56,7 +56,7 @@ const adc_channel_t sbu1_channels[] = {
{.adc = ADC3, .channel = 10},
};
const adc_channel_t sbu2_channels[] = {
adc_channel_t sbu2_channels[] = {
{.adc = ADC1, .channel = 13},
{.adc = ADC3, .channel = 3},
{.adc = ADC3, .channel = 5},
@@ -307,7 +307,7 @@ void board_v2_init(void) {
void board_v2_tick(void) {}
const board board_v2 = {
board board_v2 = {
.has_canfd = true,
.has_sbu_sense = true,
.avdd_mV = 3300U,
+2
View File
@@ -15,3 +15,5 @@ if __name__ == "__main__":
print("flashing", s)
with PandaJungle(serial=s) as p:
p.flash()
exit(1 if len(serials) == 0 else 0)
+33 -2
View File
@@ -2,7 +2,6 @@
#include "board/config.h"
#include "board/safety.h"
#include "board/drivers/gmlan_alt.h"
#include "board/drivers/pwm.h"
#include "board/drivers/usb.h"
@@ -53,6 +52,14 @@ uint32_t loop_counter = 0U;
uint16_t button_press_cnt = 0U;
void tick_handler(void) {
if (TICK_TIMER->SR != 0) {
if (generated_can_traffic) {
for (int i = 0; i < 3; i++) {
if (can_health[i].transmit_error_cnt >= 128) {
(void)llcan_init(CANIF_FROM_CAN_NUM(i));
}
}
}
// tick drivers at 8Hz
usb_tick();
@@ -194,8 +201,32 @@ int main(void) {
#endif
// LED should keep on blinking all the time
uint64_t cnt = 0;
uint32_t cnt = 0;
for (cnt=0;;cnt++) {
if (generated_can_traffic) {
// fill up all the queues
can_ring *qs[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q};
for (int j = 0; j < 3; j++) {
for (uint16_t n = 0U; n < can_slots_empty(qs[j]); n++) {
uint16_t i = cnt % 100U;
CANPacket_t to_send;
to_send.returned = 0U;
to_send.rejected = 0U;
to_send.extended = 0U;
to_send.addr = 0x200U + i;
to_send.bus = i % 3U;
to_send.data_len_code = i % 8U;
(void)memcpy(to_send.data, "\xff\xff\xff\xff\xff\xff\xff\xff", dlc_to_len[to_send.data_len_code]);
can_set_checksum(&to_send);
can_send(&to_send, to_send.bus, true);
}
}
delay(1000);
continue;
}
// useful for debugging, fade breaks = panda is overloaded
for (uint32_t fade = 0U; fade < MAX_LED_FADE; fade += 1U) {
current_board->set_led(LED_RED, true);
+7 -1
View File
@@ -1,5 +1,7 @@
extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used
bool generated_can_traffic = false;
int get_jungle_health_pkt(void *dat) {
COMPILE_TIME_ASSERT(sizeof(struct jungle_health_t) <= USBPACKET_MAX_SIZE);
struct jungle_health_t * health = (struct jungle_health_t*)dat;
@@ -58,10 +60,14 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
case 0xa2:
current_board->set_ignition((req->param1 == 1U));
break;
// **** 0xa0: Set panda power per channel by bitmask.
// **** 0xa3: Set panda power per channel by bitmask.
case 0xa3:
current_board->set_panda_individual_power(req->param1, (req->param2 > 0U));
break;
// **** 0xa4: Enable generated CAN traffic.
case 0xa4:
generated_can_traffic = (req->param1 > 0U);
break;
// **** 0xa8: get microsecond timer
case 0xa8:
time = microsecond_timer_get();
+1
View File
@@ -24,3 +24,4 @@ if __name__ == "__main__":
for s in dfu_serials:
print("flashing", s)
PandaJungleDFU(s).recover()
exit(1 if len(dfu_serials) == 0 else 0)
+1 -1
View File
@@ -4,6 +4,6 @@ from panda import PandaJungle
if __name__ == "__main__":
for p in PandaJungle.list():
pp = PandaJungle(p)
print("%s: %s" % (pp.get_serial()[0], pp.get_version()))
print(f"{pp.get_serial()[0]}: {pp.get_version()}")
+18 -52
View File
@@ -3,7 +3,6 @@
#include "drivers/pwm.h"
#include "drivers/usb.h"
#include "drivers/gmlan_alt.h"
#include "drivers/simple_watchdog.h"
#include "drivers/bootkick.h"
@@ -34,7 +33,6 @@
bool check_started(void) {
bool started = current_board->check_ignition() || ignition_can;
ignition_seen |= started;
return started;
}
@@ -99,6 +97,9 @@ void set_safety_mode(uint16_t mode, uint16_t param) {
heartbeat_counter = 0U;
heartbeat_lost = false;
if (current_board->has_obd) {
// Clear any pending messages in the can core (i.e. sending while comma power is unplugged)
// TODO: rewrite using hardware queues rather than fifo to cancel specific messages
llcan_clear_send(CANIF_FROM_CAN_NUM(1));
if (param == 0U) {
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
} else {
@@ -145,8 +146,10 @@ void __attribute__ ((noinline)) enable_fpu(void) {
// called at 8Hz
uint8_t loop_counter = 0U;
uint8_t prev_harness_status = HARNESS_STATUS_NC;
void tick_handler(void) {
if (TICK_TIMER->SR != 0) {
if (TICK_TIMER->SR != 0U) {
// siren
current_board->set_siren((loop_counter & 1U) && (siren_enabled || (siren_countdown > 0U)));
@@ -156,6 +159,17 @@ void tick_handler(void) {
harness_tick();
simple_watchdog_kick();
// re-init everything that uses harness status
if (harness.status != prev_harness_status) {
prev_harness_status = harness.status;
can_set_orientation(harness.status == HARNESS_STATUS_FLIPPED);
// re-init everything that uses harness status
can_init_all();
set_safety_mode(current_safety_mode, current_safety_param);
set_power_save_state(power_save_status);
}
// decimated to 1Hz
if (loop_counter == 0U) {
can_live = pending_can_live;
@@ -187,7 +201,7 @@ void tick_handler(void) {
bootkick_tick(check_started(), recent_heartbeat);
// increase heartbeat counter and cap it at the uint32 limit
if (heartbeat_counter < __UINT32_MAX__) {
if (heartbeat_counter < UINT32_MAX) {
heartbeat_counter += 1U;
}
@@ -280,38 +294,6 @@ void tick_handler(void) {
TICK_TIMER->SR = 0;
}
void EXTI_IRQ_Handler(void) {
if (check_exti_irq()) {
exti_irq_clear();
clock_init();
set_power_save_state(POWER_SAVE_STATUS_DISABLED);
deepsleep_allowed = false;
heartbeat_counter = 0U;
usb_soft_disconnect(false);
NVIC_EnableIRQ(TICK_TIMER_IRQ);
}
}
uint8_t rtc_counter = 0;
void RTC_WKUP_IRQ_Handler(void) {
exti_irq_clear();
clock_init();
rtc_counter++;
if ((rtc_counter % 2U) == 0U) {
current_board->set_led(LED_BLUE, false);
} else {
current_board->set_led(LED_BLUE, true);
}
if (rtc_counter == __UINT8_MAX__) {
rtc_counter = 1U;
}
}
int main(void) {
// Init interrupt table
init_interrupts(true);
@@ -413,22 +395,6 @@ int main(void) {
}
#endif
} else {
if (deepsleep_allowed && !usb_enumerated && !check_started() && ignition_seen && (heartbeat_counter > 20U)) {
usb_soft_disconnect(true);
fan_set_power(0U);
NVIC_DisableIRQ(TICK_TIMER_IRQ);
delay(512000U);
// Init IRQs for CAN transceiver and ignition line
exti_irq_init();
// Init RTC Wakeup event on EXTI22
REGISTER_INTERRUPT(RTC_WKUP_IRQn, RTC_WKUP_IRQ_Handler, 10U, FAULT_INTERRUPT_RATE_EXTI)
rtc_wakeup_init();
// STOP mode
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
}
__WFI();
SCB->SCR &= ~SCB_SCR_SLEEPDEEP_Msk;
}
+2 -60
View File
@@ -21,7 +21,6 @@ int get_health_pkt(void *dat) {
health->safety_rx_invalid_pkt = safety_rx_invalid;
health->tx_buffer_overflow_pkt = tx_buffer_overflow;
health->rx_buffer_overflow_pkt = rx_buffer_overflow;
health->gmlan_send_errs_pkt = gmlan_send_errs;
health->car_harness_status_pkt = harness.status;
health->safety_mode_pkt = (uint8_t)(current_safety_mode);
health->safety_param_pkt = current_safety_param;
@@ -48,12 +47,6 @@ int get_health_pkt(void *dat) {
return sizeof(*health);
}
int get_rtc_pkt(void *dat) {
timestamp_t t = rtc_get_time();
(void)memcpy(dat, &t, sizeof(t));
return sizeof(t);
}
// send on serial, first byte to select the ring
void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
uart_ring *ur = get_ring_by_number(data[0]);
@@ -71,7 +64,6 @@ void comms_endpoint2_write(const uint8_t *data, uint32_t len) {
int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
unsigned int resp_len = 0;
uart_ring *ur = NULL;
timestamp_t t;
uint32_t time;
#ifdef DEBUG_COMMS
@@ -82,52 +74,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
#endif
switch (req->request) {
// **** 0xa0: get rtc time
case 0xa0:
resp_len = get_rtc_pkt(resp);
break;
// **** 0xa1: set rtc year
case 0xa1:
t = rtc_get_time();
t.year = req->param1;
rtc_set_time(t);
break;
// **** 0xa2: set rtc month
case 0xa2:
t = rtc_get_time();
t.month = req->param1;
rtc_set_time(t);
break;
// **** 0xa3: set rtc day
case 0xa3:
t = rtc_get_time();
t.day = req->param1;
rtc_set_time(t);
break;
// **** 0xa4: set rtc weekday
case 0xa4:
t = rtc_get_time();
t.weekday = req->param1;
rtc_set_time(t);
break;
// **** 0xa5: set rtc hour
case 0xa5:
t = rtc_get_time();
t.hour = req->param1;
rtc_set_time(t);
break;
// **** 0xa6: set rtc minute
case 0xa6:
t = rtc_get_time();
t.minute = req->param1;
rtc_set_time(t);
break;
// **** 0xa7: set rtc second
case 0xa7:
t = rtc_get_time();
t.second = req->param1;
rtc_set_time(t);
break;
// **** 0xa8: get microsecond timer
case 0xa8:
time = microsecond_timer_get();
@@ -264,9 +210,9 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
case 0xd8:
NVIC_SystemReset();
break;
// **** 0xdb: set GMLAN (white/grey) or OBD CAN (black) multiplexing mode
// **** 0xdb: set OBD CAN multiplexing mode
case 0xdb:
if(current_board->has_obd){
if (current_board->has_obd) {
if (req->param1 == 1U) {
// Enable OBD CAN
current_board->set_can_mode(CAN_MODE_OBD_CAN2);
@@ -428,10 +374,6 @@ int comms_control_handler(ControlPacket_t *req, uint8_t *resp) {
UNUSED(ret);
}
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 < PANDA_CAN_CNT) && current_board->has_canfd) {
+1 -6
View File
@@ -6,13 +6,12 @@ void puth4(unsigned int i);
void hexdump(const void *a, int l);
typedef struct board board;
typedef struct harness_configuration harness_configuration;
void can_flip_buses(uint8_t bus1, uint8_t bus2);
void pwm_init(TIM_TypeDef *TIM, uint8_t channel);
void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage);
// ********************* Globals **********************
uint8_t hw_type = 0;
const board *current_board;
board *current_board;
uint32_t uptime_cnt = 0;
bool green_led_enabled = false;
@@ -21,10 +20,6 @@ uint32_t heartbeat_counter = 0;
bool heartbeat_lost = false;
bool heartbeat_disabled = false; // set over USB
// Enter deep sleep mode
bool deepsleep_allowed = false;
bool ignition_seen = false;
// siren state
bool siren_enabled = false;
uint32_t siren_countdown = 0; // siren plays while countdown > 0
+1 -1
View File
@@ -3,7 +3,7 @@
#define PROVISION_CHUNK_LEN 0x20
const char unprovisioned_text[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
const unsigned char unprovisioned_text[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
void get_provision_chunk(uint8_t *resp) {
(void)memcpy(resp, (uint8_t *)PROVISION_CHUNK_ADDRESS, PROVISION_CHUNK_LEN);
+1
View File
@@ -24,3 +24,4 @@ if __name__ == "__main__":
for s in dfu_serials:
print("flashing", s)
PandaDFU(s).recover()
exit(1 if len(dfu_serials) == 0 else 0)
-6
View File
@@ -327,8 +327,6 @@ int set_safety_hooks(uint16_t mode, uint16_t param) {
// reset state set by safety mode
safety_mode_cnt = 0U;
relay_malfunction = false;
enable_gas_interceptor = false;
gas_interceptor_prev = 0;
gas_pressed = false;
gas_pressed_prev = false;
brake_pressed = false;
@@ -543,10 +541,6 @@ bool longitudinal_brake_checks(int desired_brake, const LongitudinalLimits limit
return violation;
}
bool longitudinal_interceptor_checks(const CANPacket_t *to_send) {
return !get_longitudinal_allowed() && (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1));
}
// Safety checks for torque-based steering commands
bool steer_torque_cmd_checks(int desired_torque, int steer_req, const SteeringLimits limits) {
bool violation = false;
+3 -2
View File
@@ -123,11 +123,12 @@ RxCheck chrysler_ram_hd_rx_checks[] = {
const uint32_t CHRYSLER_PARAM_RAM_DT = 1U; // set for Ram DT platform
const uint32_t CHRYSLER_PARAM_RAM_HD = 2U; // set for Ram HD platform
enum {
typedef enum {
CHRYSLER_RAM_DT,
CHRYSLER_RAM_HD,
CHRYSLER_PACIFICA, // plus Jeep
} chrysler_platform = CHRYSLER_PACIFICA;
} ChryslerPlatform;
ChryslerPlatform chrysler_platform = CHRYSLER_PACIFICA;
const ChryslerAddrs *chrysler_addrs = &CHRYSLER_ADDRS;
static uint32_t chrysler_get_checksum(const CANPacket_t *to_push) {
+4 -10
View File
@@ -59,8 +59,10 @@ const CanMsg FORD_CANFD_LONG_TX_MSGS[] = {
// this may be the cause of blocked messages
RxCheck ford_rx_checks[] = {
{.msg = {{FORD_BrakeSysFeatures, 0, 8, .check_checksum = true, .max_counter = 15U, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
// TODO: FORD_EngVehicleSpThrottle2 has a counter that skips by 2, understand and enable counter check
{.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .check_checksum = true, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
// FORD_EngVehicleSpThrottle2 has a counter that either randomly skips or by 2, likely ECU bug
// Some hybrid models also experience a bug where this checksum mismatches for one or two frames under heavy acceleration with ACC
// It has been confirmed that the Bronco Sport's camera only disallows ACC for bad quality flags, not counters or checksums, so we match that
{.msg = {{FORD_EngVehicleSpThrottle2, 0, 8, .check_checksum = false, .quality_flag=true, .frequency = 50U}, { 0 }, { 0 }}},
{.msg = {{FORD_Yaw_Data_FD1, 0, 8, .check_checksum = true, .max_counter = 255U, .quality_flag=true, .frequency = 100U}, { 0 }, { 0 }}},
// These messages have no counter or checksum
{.msg = {{FORD_EngBrakeData, 0, 8, .frequency = 10U}, { 0 }, { 0 }}},
@@ -90,9 +92,6 @@ static uint32_t ford_get_checksum(const CANPacket_t *to_push) {
if (addr == FORD_BrakeSysFeatures) {
// Signal: VehVActlBrk_No_Cs
chksum = GET_BYTE(to_push, 3);
} else if (addr == FORD_EngVehicleSpThrottle2) {
// Signal: VehVActlEng_No_Cs
chksum = GET_BYTE(to_push, 1);
} else if (addr == FORD_Yaw_Data_FD1) {
// Signal: VehRollYawW_No_Cs
chksum = GET_BYTE(to_push, 4);
@@ -110,11 +109,6 @@ static uint32_t ford_compute_checksum(const CANPacket_t *to_push) {
chksum += GET_BYTE(to_push, 2) >> 6; // VehVActlBrk_D_Qf
chksum += (GET_BYTE(to_push, 2) >> 2) & 0xFU; // VehVActlBrk_No_Cnt
chksum = 0xFFU - chksum;
} else if (addr == FORD_EngVehicleSpThrottle2) {
chksum += (GET_BYTE(to_push, 2) >> 3) & 0xFU; // VehVActlEng_No_Cnt
chksum += (GET_BYTE(to_push, 4) >> 5) & 0x3U; // VehVActlEng_D_Qf
chksum += GET_BYTE(to_push, 6) + GET_BYTE(to_push, 7); // Veh_V_ActlEng
chksum = 0xFFU - chksum;
} else if (addr == FORD_Yaw_Data_FD1) {
chksum += GET_BYTE(to_push, 0) + GET_BYTE(to_push, 1); // VehRol_W_Actl
chksum += GET_BYTE(to_push, 2) + GET_BYTE(to_push, 3); // VehYaw_W_Actl
+6 -3
View File
@@ -29,8 +29,7 @@ const int GM_STANDSTILL_THRSLD = 10; // 0.311kph
const CanMsg GM_ASCM_TX_MSGS[] = {{0x180, 0, 4}, {0x409, 0, 7}, {0x40A, 0, 7}, {0x2CB, 0, 8}, {0x370, 0, 6}, // pt bus
{0xA1, 1, 7}, {0x306, 1, 8}, {0x308, 1, 7}, {0x310, 1, 2}, // obs bus
{0x315, 2, 5}, // ch bus
{0x104c006c, 3, 3}, {0x10400060, 3, 5}}; // gmlan
{0x315, 2, 5}}; // ch bus
const CanMsg GM_CAM_TX_MSGS[] = {{0x180, 0, 4}, // pt bus
{0x1E1, 2, 7}, {0x184, 2, 8}}; // camera bus
@@ -60,7 +59,11 @@ enum {
GM_BTN_CANCEL = 6,
};
enum {GM_ASCM, GM_CAM} gm_hw = GM_ASCM;
typedef enum {
GM_ASCM,
GM_CAM
} GmHardware;
GmHardware gm_hw = GM_ASCM;
bool gm_cam_long = false;
bool gm_pcm_cruise = false;
+12 -62
View File
@@ -1,16 +1,9 @@
const CanMsg HONDA_N_TX_MSGS[] = {{0xE4, 0, 5}, {0x194, 0, 4}, {0x1FA, 0, 8}, {0x30C, 0, 8}, {0x33D, 0, 5}};
const CanMsg HONDA_N_INTERCEPTOR_TX_MSGS[] = {{0xE4, 0, 5}, {0x194, 0, 4}, {0x1FA, 0, 8}, {0x200, 0, 6}, {0x30C, 0, 8}, {0x33D, 0, 5}};
const CanMsg HONDA_BOSCH_TX_MSGS[] = {{0xE4, 0, 5}, {0xE5, 0, 8}, {0x296, 1, 4}, {0x33D, 0, 5}, {0x33DA, 0, 5}, {0x33DB, 0, 8}}; // Bosch
const CanMsg HONDA_BOSCH_LONG_TX_MSGS[] = {{0xE4, 1, 5}, {0x1DF, 1, 8}, {0x1EF, 1, 8}, {0x1FA, 1, 8}, {0x30C, 1, 8}, {0x33D, 1, 5}, {0x33DA, 1, 5}, {0x33DB, 1, 8}, {0x39F, 1, 8}, {0x18DAB0F1, 1, 8}}; // Bosch w/ gas and brakes
const CanMsg HONDA_RADARLESS_TX_MSGS[] = {{0xE4, 0, 5}, {0x296, 2, 4}, {0x33D, 0, 8}}; // Bosch radarless
const CanMsg HONDA_RADARLESS_LONG_TX_MSGS[] = {{0xE4, 0, 5}, {0x33D, 0, 8}, {0x1C8, 0, 8}, {0x30C, 0, 8}}; // Bosch radarless w/ gas and brakes
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
// Threshold calculated from DBC gains: round(((83.3 / 0.253984064) + (83.3 / 0.126992032)) / 2) = 492
const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 492;
#define HONDA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks
const LongitudinalLimits HONDA_BOSCH_LONG_LIMITS = {
.max_accel = 200, // accel is used for brakes
.min_accel = -350,
@@ -47,11 +40,6 @@ RxCheck honda_common_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
};
RxCheck honda_common_interceptor_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
RxCheck honda_common_alt_brake_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(0)
HONDA_ALT_BRAKE_ADDR_CHECK(0)
@@ -62,11 +50,6 @@ RxCheck honda_nidec_alt_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
};
RxCheck honda_nidec_alt_interceptor_rx_checks[] = {
HONDA_COMMON_NO_SCM_FEEDBACK_RX_CHECKS(0)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
// Bosch has pt on bus 1, verified 0x1A6 does not exist
RxCheck honda_bosch_rx_checks[] = {
HONDA_COMMON_RX_CHECKS(1)
@@ -81,7 +64,6 @@ const uint16_t HONDA_PARAM_ALT_BRAKE = 1;
const uint16_t HONDA_PARAM_BOSCH_LONG = 2;
const uint16_t HONDA_PARAM_NIDEC_ALT = 4;
const uint16_t HONDA_PARAM_RADARLESS = 8;
const uint16_t HONDA_PARAM_GAS_INTERCEPTOR = 16;
enum {
HONDA_BTN_NONE = 0,
@@ -97,7 +79,8 @@ bool honda_alt_brake_msg = false;
bool honda_fwd_brake = false;
bool honda_bosch_long = false;
bool honda_bosch_radarless = false;
enum {HONDA_NIDEC, HONDA_BOSCH} honda_hw = HONDA_NIDEC;
typedef enum {HONDA_NIDEC, HONDA_BOSCH} HondaHw;
HondaHw honda_hw = HONDA_NIDEC;
int honda_get_pt_bus(void) {
@@ -127,26 +110,15 @@ static uint32_t honda_compute_checksum(const CANPacket_t *to_push) {
}
static uint8_t honda_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t cnt = 0U;
if (addr == 0x201) {
// Signal: COUNTER_PEDAL
cnt = GET_BYTE(to_push, 4) & 0x0FU;
} else {
int counter_byte = GET_LEN(to_push) - 1U;
cnt = (GET_BYTE(to_push, counter_byte) >> 4U) & 0x3U;
}
return cnt;
int counter_byte = GET_LEN(to_push) - 1U;
return (GET_BYTE(to_push, counter_byte) >> 4U) & 0x3U;
}
static void honda_rx_hook(const CANPacket_t *to_push) {
const bool pcm_cruise = ((honda_hw == HONDA_BOSCH) && !honda_bosch_long) || \
((honda_hw == HONDA_NIDEC) && !enable_gas_interceptor);
const bool pcm_cruise = ((honda_hw == HONDA_BOSCH) && !honda_bosch_long) || (honda_hw == HONDA_NIDEC);
int pt_bus = honda_get_pt_bus();
int addr = GET_ADDR(to_push);
int len = GET_LEN(to_push);
int bus = GET_BUS(to_push);
// sample speed
@@ -218,17 +190,8 @@ static void honda_rx_hook(const CANPacket_t *to_push) {
}
}
// length check because bosch hardware also uses this id (0x201 w/ len = 8)
if ((addr == 0x201) && (len == 6) && enable_gas_interceptor) {
int gas_interceptor = HONDA_GET_INTERCEPTOR(to_push);
gas_pressed = gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD;
gas_interceptor_prev = gas_interceptor;
}
if (!enable_gas_interceptor) {
if (addr == 0x17C) {
gas_pressed = GET_BYTE(to_push, 0) != 0U;
}
if (addr == 0x17C) {
gas_pressed = GET_BYTE(to_push, 0) != 0U;
}
// disable stock Honda AEB in alternative experience
@@ -346,13 +309,6 @@ static bool honda_tx_hook(const CANPacket_t *to_send) {
}
}
// GAS: safety check (interceptor)
if (addr == 0x200) {
if (longitudinal_interceptor_checks(to_send)) {
tx = false;
}
}
// FORCE CANCEL: safety check only relevant when spamming the cancel button in Bosch HW
// ensuring that only the cancel button press is sent (VAL 2) when controls are off.
// This avoids unintended engagements while still allowing resume spam
@@ -380,24 +336,18 @@ static safety_config honda_nidec_init(uint16_t param) {
honda_alt_brake_msg = false;
honda_bosch_long = false;
honda_bosch_radarless = false;
enable_gas_interceptor = GET_FLAG(param, HONDA_PARAM_GAS_INTERCEPTOR);
safety_config ret;
bool enable_nidec_alt = GET_FLAG(param, HONDA_PARAM_NIDEC_ALT);
if (enable_nidec_alt) {
enable_gas_interceptor ? SET_RX_CHECKS(honda_nidec_alt_interceptor_rx_checks, ret) : \
SET_RX_CHECKS(honda_nidec_alt_rx_checks, ret);
} else {
enable_gas_interceptor ? SET_RX_CHECKS(honda_common_interceptor_rx_checks, ret) : \
SET_RX_CHECKS(honda_common_rx_checks, ret);
}
if (enable_gas_interceptor) {
SET_TX_MSGS(HONDA_N_INTERCEPTOR_TX_MSGS, ret);
if (enable_nidec_alt) {
SET_RX_CHECKS(honda_nidec_alt_rx_checks, ret);
} else {
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
SET_RX_CHECKS(honda_common_rx_checks, ret);
}
SET_TX_MSGS(HONDA_N_TX_MSGS, ret);
return ret;
}
+1 -2
View File
@@ -70,11 +70,10 @@ static void mazda_rx_hook(const CANPacket_t *to_push) {
static bool mazda_tx_hook(const CANPacket_t *to_send) {
bool tx = true;
int addr = GET_ADDR(to_send);
int bus = GET_BUS(to_send);
// Check if msg is sent on the main BUS
if (bus == MAZDA_MAIN) {
int addr = GET_ADDR(to_send);
// steer cmd checks
if (addr == MAZDA_LKAS) {
+1 -1
View File
@@ -28,7 +28,7 @@ const LongitudinalLimits SUBARU_LONG_LIMITS = {
.max_brake = 600, // approx -3.5 m/s^2
.min_transmission_rpm = 0,
.max_transmission_rpm = 2400,
.max_transmission_rpm = 3600,
};
#define MSG_SUBARU_Brake_Status 0x13c
+23 -8
View File
@@ -19,6 +19,7 @@ const LongitudinalLimits TESLA_LONG_LIMITS = {
const int TESLA_FLAG_POWERTRAIN = 1;
const int TESLA_FLAG_LONGITUDINAL_CONTROL = 2;
const int TESLA_FLAG_RAVEN = 4;
const CanMsg TESLA_TX_MSGS[] = {
{0x488, 0, 4}, // DAS_steeringControl
@@ -41,6 +42,16 @@ RxCheck tesla_rx_checks[] = {
{.msg = {{0x318, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, // GTW_carState
};
RxCheck tesla_raven_rx_checks[] = {
{.msg = {{0x2b9, 2, 8, .frequency = 25U}, { 0 }, { 0 }}}, // DAS_control
{.msg = {{0x131, 2, 8, .frequency = 100U}, { 0 }, { 0 }}}, // EPAS3P_sysStatus
{.msg = {{0x108, 0, 8, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque1
{.msg = {{0x118, 0, 6, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque2
{.msg = {{0x20a, 0, 8, .frequency = 50U}, { 0 }, { 0 }}}, // BrakeMessage
{.msg = {{0x368, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, // DI_state
{.msg = {{0x318, 0, 8, .frequency = 10U}, { 0 }, { 0 }}}, // GTW_carState
};
RxCheck tesla_pt_rx_checks[] = {
{.msg = {{0x106, 0, 8, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque1
{.msg = {{0x116, 0, 6, .frequency = 100U}, { 0 }, { 0 }}}, // DI_torque2
@@ -51,6 +62,7 @@ RxCheck tesla_pt_rx_checks[] = {
bool tesla_longitudinal = false;
bool tesla_powertrain = false; // Are we the second panda intercepting the powertrain bus?
bool tesla_raven = false;
bool tesla_stock_aeb = false;
@@ -58,16 +70,16 @@ static void tesla_rx_hook(const CANPacket_t *to_push) {
int bus = GET_BUS(to_push);
int addr = GET_ADDR(to_push);
if(bus == 0) {
if (!tesla_powertrain) {
if(addr == 0x370) {
// Steering angle: (0.1 * val) - 819.2 in deg.
// Store it 1/10 deg to match steering request
int angle_meas_new = (((GET_BYTE(to_push, 4) & 0x3FU) << 8) | GET_BYTE(to_push, 5)) - 8192U;
update_sample(&angle_meas, angle_meas_new);
}
if (!tesla_powertrain) {
if((!tesla_raven && (addr == 0x370) && (bus == 0)) || (tesla_raven && (addr == 0x131) && (bus == 2))) {
// Steering angle: (0.1 * val) - 819.2 in deg.
// Store it 1/10 deg to match steering request
int angle_meas_new = (((GET_BYTE(to_push, 4) & 0x3FU) << 8) | GET_BYTE(to_push, 5)) - 8192U;
update_sample(&angle_meas, angle_meas_new);
}
}
if(bus == 0) {
if(addr == (tesla_powertrain ? 0x116 : 0x118)) {
// Vehicle speed: ((0.05 * val) - 25) * MPH_TO_MPS
float speed = (((((GET_BYTE(to_push, 3) & 0x0FU) << 8) | (GET_BYTE(to_push, 2))) * 0.05) - 25) * 0.447;
@@ -206,12 +218,15 @@ static int tesla_fwd_hook(int bus_num, int addr) {
static safety_config tesla_init(uint16_t param) {
tesla_powertrain = GET_FLAG(param, TESLA_FLAG_POWERTRAIN);
tesla_longitudinal = GET_FLAG(param, TESLA_FLAG_LONGITUDINAL_CONTROL);
tesla_raven = GET_FLAG(param, TESLA_FLAG_RAVEN);
tesla_stock_aeb = false;
safety_config ret;
if (tesla_powertrain) {
ret = BUILD_SAFETY_CFG(tesla_pt_rx_checks, TESLA_PT_TX_MSGS);
} else if (tesla_raven) {
ret = BUILD_SAFETY_CFG(tesla_raven_rx_checks, TESLA_TX_MSGS);
} else {
ret = BUILD_SAFETY_CFG(tesla_rx_checks, TESLA_TX_MSGS);
}
+4 -69
View File
@@ -37,12 +37,6 @@ const LongitudinalLimits TOYOTA_LONG_LIMITS = {
.min_accel = -3500, // -3.5 m/s2
};
// panda interceptor threshold needs to be equivalent to openpilot threshold to avoid controls mismatches
// If thresholds are mismatched then it is possible for panda to see the gas fall and rise while openpilot is in the pre-enabled state
// Threshold calculated from DBC gains: round((((15 + 75.555) / 0.159375) + ((15 + 151.111) / 0.159375)) / 2) = 805
const int TOYOTA_GAS_INTERCEPTOR_THRSLD = 805;
#define TOYOTA_GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + (GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2U) // avg between 2 tracks
// Stock longitudinal
#define TOYOTA_COMMON_TX_MSGS \
{0x2E4, 0, 5}, {0x191, 0, 8}, {0x412, 0, 8}, {0x343, 0, 8}, {0x1D2, 0, 8}, /* LKAS + LTA + ACC & PCM cancel cmds */ \
@@ -62,11 +56,6 @@ const CanMsg TOYOTA_LONG_TX_MSGS[] = {
TOYOTA_COMMON_LONG_TX_MSGS
};
const CanMsg TOYOTA_INTERCEPTOR_TX_MSGS[] = {
TOYOTA_COMMON_LONG_TX_MSGS
{0x200, 0, 6}, // gas interceptor
};
#define TOYOTA_COMMON_RX_CHECKS(lta) \
{.msg = {{ 0xaa, 0, 8, .check_checksum = false, .frequency = 83U}, { 0 }, { 0 }}}, \
{.msg = {{0x260, 0, 8, .check_checksum = true, .quality_flag = (lta), .frequency = 50U}, { 0 }, { 0 }}}, \
@@ -78,21 +67,11 @@ RxCheck toyota_lka_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(false)
};
RxCheck toyota_lka_interceptor_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(false)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
// Check the quality flag for angle measurement when using LTA, since it's not set on TSS-P cars
RxCheck toyota_lta_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(true)
};
RxCheck toyota_lta_interceptor_rx_checks[] = {
TOYOTA_COMMON_RX_CHECKS(true)
{.msg = {{0x201, 0, 6, .check_checksum = false, .max_counter = 15U, .frequency = 50U}, { 0 }, { 0 }}},
};
// safety param flags
// first byte is for EPS factor, second is for flags
const uint32_t TOYOTA_PARAM_OFFSET = 8U;
@@ -100,7 +79,6 @@ const uint32_t TOYOTA_EPS_FACTOR = (1UL << TOYOTA_PARAM_OFFSET) - 1U;
const uint32_t TOYOTA_PARAM_ALT_BRAKE = 1UL << TOYOTA_PARAM_OFFSET;
const uint32_t TOYOTA_PARAM_STOCK_LONGITUDINAL = 2UL << TOYOTA_PARAM_OFFSET;
const uint32_t TOYOTA_PARAM_LTA = 4UL << TOYOTA_PARAM_OFFSET;
const uint32_t TOYOTA_PARAM_GAS_INTERCEPTOR = 8UL << TOYOTA_PARAM_OFFSET;
bool toyota_alt_brake = false;
bool toyota_stock_longitudinal = false;
@@ -122,17 +100,6 @@ static uint32_t toyota_get_checksum(const CANPacket_t *to_push) {
return (uint8_t)(GET_BYTE(to_push, checksum_byte));
}
static uint8_t toyota_get_counter(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
uint8_t cnt = 0U;
if (addr == 0x201) {
// Signal: COUNTER_PEDAL
cnt = GET_BYTE(to_push, 4) & 0x0FU;
}
return cnt;
}
static bool toyota_get_quality_flag_valid(const CANPacket_t *to_push) {
int addr = GET_ADDR(to_push);
@@ -185,9 +152,7 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
pcm_cruise_check(cruise_engaged);
// sample gas pedal
if (!enable_gas_interceptor) {
gas_pressed = !GET_BIT(to_push, 4U);
}
gas_pressed = !GET_BIT(to_push, 4U);
}
// sample speed
@@ -210,15 +175,6 @@ static void toyota_rx_hook(const CANPacket_t *to_push) {
brake_pressed = GET_BIT(to_push, bit);
}
// sample gas interceptor
if ((addr == 0x201) && enable_gas_interceptor) {
int gas_interceptor = TOYOTA_GET_INTERCEPTOR(to_push);
gas_pressed = gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRSLD;
// TODO: remove this, only left in for gas_interceptor_prev test
gas_interceptor_prev = gas_interceptor;
}
bool stock_ecu_detected = addr == 0x2E4; // STEERING_LKA
if (!toyota_stock_longitudinal && (addr == 0x343)) {
stock_ecu_detected = true; // ACC_CONTROL
@@ -234,14 +190,6 @@ static bool toyota_tx_hook(const CANPacket_t *to_send) {
// Check if msg is sent on BUS 0
if (bus == 0) {
// GAS PEDAL: safety check
if (addr == 0x200) {
if (longitudinal_interceptor_checks(to_send)) {
tx = false;
}
}
// ACCEL: safety check on byte 1-2
if (addr == 0x343) {
int desired_accel = (GET_BYTE(to_send, 0) << 8) | GET_BYTE(to_send, 1);
@@ -357,29 +305,17 @@ static safety_config toyota_init(uint16_t param) {
toyota_alt_brake = GET_FLAG(param, TOYOTA_PARAM_ALT_BRAKE);
toyota_stock_longitudinal = GET_FLAG(param, TOYOTA_PARAM_STOCK_LONGITUDINAL);
toyota_lta = GET_FLAG(param, TOYOTA_PARAM_LTA);
enable_gas_interceptor = GET_FLAG(param, TOYOTA_PARAM_GAS_INTERCEPTOR);
toyota_dbc_eps_torque_factor = param & TOYOTA_EPS_FACTOR;
// Gas interceptor should not be used if openpilot is not controlling longitudinal
if (toyota_stock_longitudinal) {
enable_gas_interceptor = false;
}
safety_config ret;
if (toyota_stock_longitudinal) {
SET_TX_MSGS(TOYOTA_TX_MSGS, ret);
} else {
enable_gas_interceptor ? SET_TX_MSGS(TOYOTA_INTERCEPTOR_TX_MSGS, ret) : \
SET_TX_MSGS(TOYOTA_LONG_TX_MSGS, ret);
SET_TX_MSGS(TOYOTA_LONG_TX_MSGS, ret);
}
if (enable_gas_interceptor) {
toyota_lta ? SET_RX_CHECKS(toyota_lta_interceptor_rx_checks, ret) : \
SET_RX_CHECKS(toyota_lka_interceptor_rx_checks, ret);
} else {
toyota_lta ? SET_RX_CHECKS(toyota_lta_rx_checks, ret) : \
SET_RX_CHECKS(toyota_lka_rx_checks, ret);
}
toyota_lta ? SET_RX_CHECKS(toyota_lta_rx_checks, ret) : \
SET_RX_CHECKS(toyota_lka_rx_checks, ret);
return ret;
}
@@ -413,6 +349,5 @@ const safety_hooks toyota_hooks = {
.fwd = toyota_fwd_hook,
.get_checksum = toyota_get_checksum,
.compute_checksum = toyota_compute_checksum,
.get_counter = toyota_get_counter,
.get_quality_flag_valid = toyota_get_quality_flag_valid,
};
+1 -1
View File
@@ -185,7 +185,7 @@ static bool volkswagen_pq_tx_hook(const CANPacket_t *to_send) {
}
uint32_t hca_status = ((GET_BYTE(to_send, 1) >> 4) & 0xFU);
bool steer_req = (hca_status == 5U);
bool steer_req = ((hca_status == 5U) || (hca_status == 7U));
if (steer_torque_cmd_checks(desired_torque, steer_req, VOLKSWAGEN_PQ_STEERING_LIMITS)) {
tx = false;
+1 -4
View File
@@ -2,7 +2,7 @@
#define GET_BIT(msg, b) ((bool)!!(((msg)->data[((b) / 8U)] >> ((b) % 8U)) & 0x1U))
#define GET_BYTE(msg, b) ((msg)->data[(b)])
#define GET_FLAG(value, mask) (((__typeof__(mask))(value) & (mask)) == (mask))
#define GET_FLAG(value, mask) (((__typeof__(mask))(value) & (mask)) == (mask)) // cppcheck-suppress misra-c2012-1.2; allow __typeof__
#define BUILD_SAFETY_CFG(rx, tx) ((safety_config){(rx), (sizeof((rx)) / sizeof((rx)[0])), \
(tx), (sizeof((tx)) / sizeof((tx)[0]))})
@@ -203,7 +203,6 @@ bool longitudinal_speed_checks(int desired_speed, const LongitudinalLimits limit
bool longitudinal_gas_checks(int desired_gas, const LongitudinalLimits limits);
bool longitudinal_transmission_rpm_checks(int desired_transmission_rpm, const LongitudinalLimits limits);
bool longitudinal_brake_checks(int desired_brake, const LongitudinalLimits limits);
bool longitudinal_interceptor_checks(const CANPacket_t *to_send);
void pcm_cruise_check(bool cruise_engaged);
void safety_tick(const safety_config *safety_config);
@@ -211,8 +210,6 @@ void safety_tick(const safety_config *safety_config);
// This can be set by the safety hooks
bool controls_allowed = false;
bool relay_malfunction = false;
bool enable_gas_interceptor = false;
int gas_interceptor_prev = 0;
bool gas_pressed = false;
bool gas_pressed_prev = false;
bool brake_pressed = false;
@@ -5,12 +5,10 @@
#include "boards/unused_funcs.h"
// ///// Board definition and detection ///// //
#include "stm32fx/lladc.h"
#include "stm32f4/lladc.h"
#include "drivers/harness.h"
#include "drivers/fan.h"
#include "stm32fx/llfan.h"
#include "stm32fx/llrtc.h"
#include "drivers/rtc.h"
#include "stm32f4/llfan.h"
#include "drivers/clock_source.h"
#include "boards/white.h"
#include "boards/grey.h"
@@ -1,7 +1,7 @@
void clock_init(void) {
// enable external oscillator
register_set_bits(&(RCC->CR), RCC_CR_HSEON);
while ((RCC->CR & RCC_CR_HSERDY) == 0);
while ((RCC->CR & RCC_CR_HSERDY) == 0U);
// divide things
// AHB = 96MHz
@@ -20,7 +20,7 @@ void clock_init(void) {
// start PLL
register_set_bits(&(RCC->CR), RCC_CR_PLLON);
while ((RCC->CR & RCC_CR_PLLRDY) == 0);
while ((RCC->CR & RCC_CR_PLLRDY) == 0U);
// Configure Flash prefetch, Instruction cache, Data cache and wait state
// *** without this, it breaks ***
@@ -5,7 +5,7 @@ void uart_tx_ring(uart_ring *q){
// Send out next byte of TX buffer
if (q->w_ptr_tx != q->r_ptr_tx) {
// Only send if transmit register is empty (aka last byte has been sent)
if ((q->uart->SR & USART_SR_TXE) != 0) {
if ((q->uart->SR & USART_SR_TXE) != 0U) {
q->uart->DR = q->elems_tx[q->r_ptr_tx]; // This clears TXE
q->r_ptr_tx = (q->r_ptr_tx + 1U) % q->tx_fifo_size;
}
@@ -46,7 +46,7 @@ void uart_rx_ring(uart_ring *q){
}
void uart_send_break(uart_ring *u) {
while ((u->uart->CR1 & USART_CR1_SBK) != 0);
while ((u->uart->CR1 & USART_CR1_SBK) != 0U);
u->uart->CR1 |= USART_CR1_SBK;
}
@@ -8,7 +8,7 @@ USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS;
#define USBx_PCGCCTL *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_PCGCCTL_BASE)
#define USBD_FS_TRDT_VALUE 5UL
#define USB_OTG_SPEED_FULL 3
#define USB_OTG_SPEED_FULL 3UL
void usb_irqhandler(void);
@@ -27,7 +27,7 @@ void usb_init(void) {
// full speed PHY, do reset and remove power down
/*puth(USBx->GRSTCTL);
print(" resetting PHY\n");*/
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0);
while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0U);
//print("AHB idle\n");
// reset PHY here
@@ -83,7 +83,6 @@ void peripherals_init(void) {
RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; // k-line init
RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // interrupt timer
RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; // slow loop
RCC->APB1ENR |= RCC_APB1ENR_TIM12EN; // gmlan_alt
}
void enable_interrupt_timer(void) {
@@ -1,5 +1,5 @@
#include "stm32fx/inc/stm32f4xx.h"
#include "stm32fx/inc/stm32f4xx_hal_gpio_ex.h"
#include "stm32f4/inc/stm32f4xx.h"
#include "stm32f4/inc/stm32f4xx_hal_gpio_ex.h"
#define MCU_IDCODE 0x463U
// from the linker script
@@ -50,32 +50,28 @@
#include "drivers/registers.h"
#include "drivers/interrupts.h"
#include "drivers/gpio.h"
#include "stm32fx/peripherals.h"
#include "stm32fx/interrupt_handlers.h"
#include "stm32f4/peripherals.h"
#include "stm32f4/interrupt_handlers.h"
#include "drivers/timers.h"
#include "stm32fx/board.h"
#include "stm32fx/clock.h"
#include "stm32f4/board.h"
#include "stm32f4/clock.h"
#include "drivers/watchdog.h"
#include "drivers/spi.h"
#include "stm32fx/llspi.h"
#include "stm32f4/llspi.h"
#if !defined(BOOTSTUB)
#include "drivers/uart.h"
#include "stm32fx/lluart.h"
#endif
#if defined(PANDA) && !defined(BOOTSTUB)
#include "stm32fx/llexti.h"
#include "stm32f4/lluart.h"
#endif
#ifdef BOOTSTUB
#include "stm32fx/llflash.h"
#include "stm32f4/llflash.h"
#else
#include "stm32fx/llbxcan.h"
#include "stm32f4/llbxcan.h"
#endif
#include "stm32fx/llusb.h"
#include "stm32f4/llusb.h"
void early_gpio_float(void) {
RCC->AHB1ENR = RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN;
File diff suppressed because it is too large Load Diff
-56
View File
@@ -1,56 +0,0 @@
void EXTI_IRQ_Handler(void);
void exti_irq_init(void) {
SYSCFG->EXTICR[2] &= ~(SYSCFG_EXTICR3_EXTI8_Msk);
if (harness.status == HARNESS_STATUS_FLIPPED) {
// CAN2_RX
current_board->enable_can_transceiver(3U, false);
SYSCFG->EXTICR[2] |= (SYSCFG_EXTICR3_EXTI8_PA);
// IRQ on falling edge for PC3 (SBU2, EXTI3)
SYSCFG->EXTICR[0] &= ~(SYSCFG_EXTICR1_EXTI3_Msk);
SYSCFG->EXTICR[0] |= (SYSCFG_EXTICR1_EXTI3_PC);
EXTI->IMR |= EXTI_IMR_MR3;
EXTI->RTSR &= ~EXTI_RTSR_TR3; // rising edge
EXTI->FTSR |= EXTI_FTSR_TR3; // falling edge
REGISTER_INTERRUPT(EXTI3_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI3_IRQn);
} else {
// CAN0_RX
current_board->enable_can_transceiver(1U, false);
SYSCFG->EXTICR[2] |= (SYSCFG_EXTICR3_EXTI8_PB);
// IRQ on falling edge for PC0 (SBU1, EXTI0)
SYSCFG->EXTICR[0] &= ~(SYSCFG_EXTICR1_EXTI0_Msk);
SYSCFG->EXTICR[0] |= (SYSCFG_EXTICR1_EXTI0_PC);
EXTI->IMR |= EXTI_IMR_MR0;
EXTI->RTSR &= ~EXTI_RTSR_TR0; // rising edge
EXTI->FTSR |= EXTI_FTSR_TR0; // falling edge
REGISTER_INTERRUPT(EXTI0_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI0_IRQn);
}
// CAN0 or CAN2 IRQ on falling edge (EXTI8)
EXTI->IMR |= EXTI_IMR_MR8;
EXTI->RTSR &= ~EXTI_RTSR_TR8; // rising edge
EXTI->FTSR |= EXTI_FTSR_TR8; // falling edge
REGISTER_INTERRUPT(EXTI9_5_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
bool check_exti_irq(void) {
return ((EXTI->PR & EXTI_PR_PR8) || (EXTI->PR & EXTI_PR_PR3) || (EXTI->PR & EXTI_PR_PR0));
}
void exti_irq_clear(void) {
// Clear pending bits
EXTI->PR |= EXTI_PR_PR8;
EXTI->PR |= EXTI_PR_PR0;
EXTI->PR |= EXTI_PR_PR3;
EXTI->PR |= EXTI_PR_PR22;
// Disable all active EXTI IRQs
EXTI->IMR &= ~EXTI_IMR_MR8;
EXTI->IMR &= ~EXTI_IMR_MR0;
EXTI->IMR &= ~EXTI_IMR_MR3;
EXTI->IMR &= ~EXTI_IMR_MR22;
}
-69
View File
@@ -1,69 +0,0 @@
void enable_bdomain_protection(void) {
register_clear_bits(&(PWR->CR), PWR_CR_DBP);
}
void disable_bdomain_protection(void) {
register_set_bits(&(PWR->CR), PWR_CR_DBP);
}
void rtc_init(void){
uint32_t bdcr_opts = RCC_BDCR_RTCEN;
uint32_t bdcr_mask = (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL);
if (current_board->has_rtc_battery) {
bdcr_opts |= (RCC_BDCR_RTCSEL_0 | RCC_BDCR_LSEON);
bdcr_mask |= (RCC_BDCR_LSEMOD | RCC_BDCR_LSEBYP | RCC_BDCR_LSEON);
} else {
bdcr_opts |= RCC_BDCR_RTCSEL_1;
RCC->CSR |= RCC_CSR_LSION;
while((RCC->CSR & RCC_CSR_LSIRDY) == 0){}
}
// Initialize RTC module and clock if not done already.
if((RCC->BDCR & bdcr_mask) != bdcr_opts){
print("Initializing RTC\n");
// Reset backup domain
register_set_bits(&(RCC->BDCR), RCC_BDCR_BDRST);
// Disable write protection
disable_bdomain_protection();
// Clear backup domain reset
register_clear_bits(&(RCC->BDCR), RCC_BDCR_BDRST);
// Set RTC options
register_set(&(RCC->BDCR), bdcr_opts, bdcr_mask);
// Enable write protection
enable_bdomain_protection();
}
}
void rtc_wakeup_init(void) {
EXTI->IMR |= EXTI_IMR_MR22;
EXTI->RTSR |= EXTI_RTSR_TR22; // rising edge
EXTI->FTSR &= ~EXTI_FTSR_TR22; // falling edge
NVIC_DisableIRQ(RTC_WKUP_IRQn);
// Disable write protection
disable_bdomain_protection();
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
RTC->CR &= ~RTC_CR_WUTE;
while((RTC->ISR & RTC_ISR_WUTWF) == 0){}
RTC->CR &= ~RTC_CR_WUTIE;
RTC->ISR &= ~RTC_ISR_WUTF;
//PWR->CR |= PWR_CR_CWUF;
RTC->WUTR = DEEPSLEEP_WAKEUP_DELAY;
// Wakeup timer interrupt enable, wakeup timer enable, select 1Hz rate
RTC->CR |= RTC_CR_WUTE | RTC_CR_WUTIE | RTC_CR_WUCKSEL_2;
// Re-enable write protection
RTC->WPR = 0x00;
enable_bdomain_protection();
NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
-2
View File
@@ -9,10 +9,8 @@
#include "drivers/harness.h"
#include "drivers/fan.h"
#include "stm32h7/llfan.h"
#include "stm32h7/llrtc.h"
#include "stm32h7/lldac.h"
#include "drivers/fake_siren.h"
#include "drivers/rtc.h"
#include "drivers/clock_source.h"
#include "boards/red.h"
#include "boards/red_chiplet.h"
+6 -4
View File
@@ -21,20 +21,22 @@ void clock_init(void) {
// Set power mode to direct SMPS power supply(depends on the board layout)
#ifndef STM32H723
register_set(&(PWR->CR3), PWR_CR3_SMPSEN, 0xFU); // powered only by SMPS
#else
register_set(&(PWR->CR3), PWR_CR3_LDOEN, 0xFU);
#endif
// Set VOS level (VOS3 to 170Mhz, VOS2 to 300Mhz, VOS1 to 400Mhz, VOS0 to 550Mhz)
register_set(&(PWR->D3CR), PWR_D3CR_VOS_1 | PWR_D3CR_VOS_0, 0xC000U); //VOS1, needed for 80Mhz CAN FD
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0);
while ((PWR->CSR1 & PWR_CSR1_ACTVOSRDY) == 0U);
while ((PWR->CSR1 & PWR_CSR1_ACTVOS) != (PWR->D3CR & PWR_D3CR_VOS)); // check that VOS level was actually set
// Configure Flash ACR register LATENCY and WRHIGHFREQ (VOS0 range!)
register_set(&(FLASH->ACR), FLASH_ACR_LATENCY_2WS | 0x20U, 0x3FU); // VOS2, AXI 100MHz-150MHz
// enable external oscillator HSE
register_set_bits(&(RCC->CR), RCC_CR_HSEON);
while ((RCC->CR & RCC_CR_HSERDY) == 0);
while ((RCC->CR & RCC_CR_HSERDY) == 0U);
// enable internal HSI48 for USB FS kernel
register_set_bits(&(RCC->CR), RCC_CR_HSI48ON);
while ((RCC->CR & RCC_CR_HSI48RDY) == 0);
while ((RCC->CR & RCC_CR_HSI48RDY) == 0U);
// Specify the frequency source for PLL1, divider for DIVM1, DIVM2, DIVM3 : HSE, 5, 5, 5
register_set(&(RCC->PLLCKSELR), RCC_PLLCKSELR_PLLSRC_HSE | RCC_PLLCKSELR_DIVM1_0 | RCC_PLLCKSELR_DIVM1_2 | RCC_PLLCKSELR_DIVM2_0 | RCC_PLLCKSELR_DIVM2_2 | RCC_PLLCKSELR_DIVM3_0 | RCC_PLLCKSELR_DIVM3_2, 0x3F3F3F3U);
@@ -45,7 +47,7 @@ void clock_init(void) {
register_set(&(RCC->PLLCFGR), RCC_PLLCFGR_PLL1RGE_2 | RCC_PLLCFGR_DIVP1EN | RCC_PLLCFGR_DIVQ1EN | RCC_PLLCFGR_DIVR1EN, 0x7000CU);
// Enable PLL1
register_set_bits(&(RCC->CR), RCC_CR_PLL1ON);
while((RCC->CR & RCC_CR_PLL1RDY) == 0);
while((RCC->CR & RCC_CR_PLL1RDY) == 0U);
// *** PLL1 end ***
//////////////OTHER CLOCKS////////////////////
+273
View File
@@ -0,0 +1,273 @@
/******************************************************************************
* @file mpu_armv7.h
* @brief CMSIS MPU API for Armv7-M MPU
* @version V5.1.0
* @date 08. March 2019
******************************************************************************/
/*
* Copyright (c) 2017-2019 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined (__clang__)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef ARM_MPU_ARMV7_H
#define ARM_MPU_ARMV7_H
#define ARM_MPU_REGION_SIZE_32B ((uint8_t)0x04U) ///!< MPU Region Size 32 Bytes
#define ARM_MPU_REGION_SIZE_64B ((uint8_t)0x05U) ///!< MPU Region Size 64 Bytes
#define ARM_MPU_REGION_SIZE_128B ((uint8_t)0x06U) ///!< MPU Region Size 128 Bytes
#define ARM_MPU_REGION_SIZE_256B ((uint8_t)0x07U) ///!< MPU Region Size 256 Bytes
#define ARM_MPU_REGION_SIZE_512B ((uint8_t)0x08U) ///!< MPU Region Size 512 Bytes
#define ARM_MPU_REGION_SIZE_1KB ((uint8_t)0x09U) ///!< MPU Region Size 1 KByte
#define ARM_MPU_REGION_SIZE_2KB ((uint8_t)0x0AU) ///!< MPU Region Size 2 KBytes
#define ARM_MPU_REGION_SIZE_4KB ((uint8_t)0x0BU) ///!< MPU Region Size 4 KBytes
#define ARM_MPU_REGION_SIZE_8KB ((uint8_t)0x0CU) ///!< MPU Region Size 8 KBytes
#define ARM_MPU_REGION_SIZE_16KB ((uint8_t)0x0DU) ///!< MPU Region Size 16 KBytes
#define ARM_MPU_REGION_SIZE_32KB ((uint8_t)0x0EU) ///!< MPU Region Size 32 KBytes
#define ARM_MPU_REGION_SIZE_64KB ((uint8_t)0x0FU) ///!< MPU Region Size 64 KBytes
#define ARM_MPU_REGION_SIZE_128KB ((uint8_t)0x10U) ///!< MPU Region Size 128 KBytes
#define ARM_MPU_REGION_SIZE_256KB ((uint8_t)0x11U) ///!< MPU Region Size 256 KBytes
#define ARM_MPU_REGION_SIZE_512KB ((uint8_t)0x12U) ///!< MPU Region Size 512 KBytes
#define ARM_MPU_REGION_SIZE_1MB ((uint8_t)0x13U) ///!< MPU Region Size 1 MByte
#define ARM_MPU_REGION_SIZE_2MB ((uint8_t)0x14U) ///!< MPU Region Size 2 MBytes
#define ARM_MPU_REGION_SIZE_4MB ((uint8_t)0x15U) ///!< MPU Region Size 4 MBytes
#define ARM_MPU_REGION_SIZE_8MB ((uint8_t)0x16U) ///!< MPU Region Size 8 MBytes
#define ARM_MPU_REGION_SIZE_16MB ((uint8_t)0x17U) ///!< MPU Region Size 16 MBytes
#define ARM_MPU_REGION_SIZE_32MB ((uint8_t)0x18U) ///!< MPU Region Size 32 MBytes
#define ARM_MPU_REGION_SIZE_64MB ((uint8_t)0x19U) ///!< MPU Region Size 64 MBytes
#define ARM_MPU_REGION_SIZE_128MB ((uint8_t)0x1AU) ///!< MPU Region Size 128 MBytes
#define ARM_MPU_REGION_SIZE_256MB ((uint8_t)0x1BU) ///!< MPU Region Size 256 MBytes
#define ARM_MPU_REGION_SIZE_512MB ((uint8_t)0x1CU) ///!< MPU Region Size 512 MBytes
#define ARM_MPU_REGION_SIZE_1GB ((uint8_t)0x1DU) ///!< MPU Region Size 1 GByte
#define ARM_MPU_REGION_SIZE_2GB ((uint8_t)0x1EU) ///!< MPU Region Size 2 GBytes
#define ARM_MPU_REGION_SIZE_4GB ((uint8_t)0x1FU) ///!< MPU Region Size 4 GBytes
#define ARM_MPU_AP_NONE 0U ///!< MPU Access Permission no access
#define ARM_MPU_AP_PRIV 1U ///!< MPU Access Permission privileged access only
#define ARM_MPU_AP_URO 2U ///!< MPU Access Permission unprivileged access read-only
#define ARM_MPU_AP_FULL 3U ///!< MPU Access Permission full access
#define ARM_MPU_AP_PRO 5U ///!< MPU Access Permission privileged access read-only
#define ARM_MPU_AP_RO 6U ///!< MPU Access Permission read-only access
/** MPU Region Base Address Register Value
*
* \param Region The region to be configured, number 0 to 15.
* \param BaseAddress The base address for the region.
*/
#define ARM_MPU_RBAR(Region, BaseAddress) \
(((BaseAddress) & MPU_RBAR_ADDR_Msk) | \
((Region) & MPU_RBAR_REGION_Msk) | \
(MPU_RBAR_VALID_Msk))
/**
* MPU Memory Access Attributes
*
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
* \param IsShareable Region is shareable between multiple bus masters.
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
*/
#define ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable) \
((((TypeExtField) << MPU_RASR_TEX_Pos) & MPU_RASR_TEX_Msk) | \
(((IsShareable) << MPU_RASR_S_Pos) & MPU_RASR_S_Msk) | \
(((IsCacheable) << MPU_RASR_C_Pos) & MPU_RASR_C_Msk) | \
(((IsBufferable) << MPU_RASR_B_Pos) & MPU_RASR_B_Msk))
/**
* MPU Region Attribute and Size Register Value
*
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
* \param AccessAttributes Memory access attribution, see \ref ARM_MPU_ACCESS_.
* \param SubRegionDisable Sub-region disable field.
* \param Size Region size of the region to be configured, for example 4K, 8K.
*/
#define ARM_MPU_RASR_EX(DisableExec, AccessPermission, AccessAttributes, SubRegionDisable, Size) \
((((DisableExec) << MPU_RASR_XN_Pos) & MPU_RASR_XN_Msk) | \
(((AccessPermission) << MPU_RASR_AP_Pos) & MPU_RASR_AP_Msk) | \
(((AccessAttributes) & (MPU_RASR_TEX_Msk | MPU_RASR_S_Msk | MPU_RASR_C_Msk | MPU_RASR_B_Msk))) | \
(((SubRegionDisable) << MPU_RASR_SRD_Pos) & MPU_RASR_SRD_Msk) | \
(((Size) << MPU_RASR_SIZE_Pos) & MPU_RASR_SIZE_Msk) | \
(((MPU_RASR_ENABLE_Msk))))
/**
* MPU Region Attribute and Size Register Value
*
* \param DisableExec Instruction access disable bit, 1= disable instruction fetches.
* \param AccessPermission Data access permissions, allows you to configure read/write access for User and Privileged mode.
* \param TypeExtField Type extension field, allows you to configure memory access type, for example strongly ordered, peripheral.
* \param IsShareable Region is shareable between multiple bus masters.
* \param IsCacheable Region is cacheable, i.e. its value may be kept in cache.
* \param IsBufferable Region is bufferable, i.e. using write-back caching. Cacheable but non-bufferable regions use write-through policy.
* \param SubRegionDisable Sub-region disable field.
* \param Size Region size of the region to be configured, for example 4K, 8K.
*/
#define ARM_MPU_RASR(DisableExec, AccessPermission, TypeExtField, IsShareable, IsCacheable, IsBufferable, SubRegionDisable, Size) \
ARM_MPU_RASR_EX(DisableExec, AccessPermission, ARM_MPU_ACCESS_(TypeExtField, IsShareable, IsCacheable, IsBufferable), SubRegionDisable, Size)
/**
* MPU Memory Access Attribute for strongly ordered memory.
* - TEX: 000b
* - Shareable
* - Non-cacheable
* - Non-bufferable
*/
#define ARM_MPU_ACCESS_ORDERED ARM_MPU_ACCESS_(0U, 1U, 0U, 0U)
/**
* MPU Memory Access Attribute for device memory.
* - TEX: 000b (if shareable) or 010b (if non-shareable)
* - Shareable or non-shareable
* - Non-cacheable
* - Bufferable (if shareable) or non-bufferable (if non-shareable)
*
* \param IsShareable Configures the device memory as shareable or non-shareable.
*/
#define ARM_MPU_ACCESS_DEVICE(IsShareable) ((IsShareable) ? ARM_MPU_ACCESS_(0U, 1U, 0U, 1U) : ARM_MPU_ACCESS_(2U, 0U, 0U, 0U))
/**
* MPU Memory Access Attribute for normal memory.
* - TEX: 1BBb (reflecting outer cacheability rules)
* - Shareable or non-shareable
* - Cacheable or non-cacheable (reflecting inner cacheability rules)
* - Bufferable or non-bufferable (reflecting inner cacheability rules)
*
* \param OuterCp Configures the outer cache policy.
* \param InnerCp Configures the inner cache policy.
* \param IsShareable Configures the memory as shareable or non-shareable.
*/
#define ARM_MPU_ACCESS_NORMAL(OuterCp, InnerCp, IsShareable) ARM_MPU_ACCESS_((4U | (OuterCp)), IsShareable, ((InnerCp) & 2U), ((InnerCp) & 1U))
/**
* MPU Memory Access Attribute non-cacheable policy.
*/
#define ARM_MPU_CACHEP_NOCACHE 0U
/**
* MPU Memory Access Attribute write-back, write and read allocate policy.
*/
#define ARM_MPU_CACHEP_WB_WRA 1U
/**
* MPU Memory Access Attribute write-through, no write allocate policy.
*/
#define ARM_MPU_CACHEP_WT_NWA 2U
/**
* MPU Memory Access Attribute write-back, no write allocate policy.
*/
#define ARM_MPU_CACHEP_WB_NWA 3U
/**
* Struct for a single MPU Region
*/
typedef struct {
uint32_t RBAR; //!< The region base address register value (RBAR)
uint32_t RASR; //!< The region attribute and size register value (RASR) \ref MPU_RASR
} ARM_MPU_Region_t;
/** Enable the MPU.
* \param MPU_Control Default access permissions for unconfigured regions.
*/
__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
{
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
#endif
__DSB();
__ISB();
}
/** Disable the MPU.
*/
__STATIC_INLINE void ARM_MPU_Disable(void)
{
__DMB();
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
#endif
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
}
/** Clear and disable the given MPU region.
* \param rnr Region number to be cleared.
*/
__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
{
MPU->RNR = rnr;
MPU->RASR = 0U;
}
/** Configure an MPU region.
* \param rbar Value for RBAR register.
* \param rsar Value for RSAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rbar, uint32_t rasr)
{
MPU->RBAR = rbar;
MPU->RASR = rasr;
}
/** Configure the given MPU region.
* \param rnr Region number to be configured.
* \param rbar Value for RBAR register.
* \param rsar Value for RSAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegionEx(uint32_t rnr, uint32_t rbar, uint32_t rasr)
{
MPU->RNR = rnr;
MPU->RBAR = rbar;
MPU->RASR = rasr;
}
/** Memcopy with strictly ordered memory access, e.g. for register targets.
* \param dst Destination data is copied to.
* \param src Source data is copied from.
* \param len Amount of data words to be copied.
*/
__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
{
uint32_t i;
for (i = 0U; i < len; ++i)
{
dst[i] = src[i];
}
}
/** Load the given number of MPU regions from a table.
* \param table Pointer to the MPU configuration table.
* \param cnt Amount of regions to be configured.
*/
__STATIC_INLINE void ARM_MPU_Load(ARM_MPU_Region_t const* table, uint32_t cnt)
{
const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
while (cnt > MPU_TYPE_RALIASES) {
ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), MPU_TYPE_RALIASES*rowWordSize);
table += MPU_TYPE_RALIASES;
cnt -= MPU_TYPE_RALIASES;
}
ARM_MPU_OrderedMemcpy(&(MPU->RBAR), &(table->RBAR), cnt*rowWordSize);
}
#endif
-346
View File
@@ -1,346 +0,0 @@
/******************************************************************************
* @file mpu_armv8.h
* @brief CMSIS MPU API for Armv8-M and Armv8.1-M MPU
* @version V5.1.0
* @date 08. March 2019
******************************************************************************/
/*
* Copyright (c) 2017-2019 Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the License); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an AS IS BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#if defined ( __ICCARM__ )
#pragma system_include /* treat file as system include file for MISRA check */
#elif defined (__clang__)
#pragma clang system_header /* treat file as system include file */
#endif
#ifndef ARM_MPU_ARMV8_H
#define ARM_MPU_ARMV8_H
/** \brief Attribute for device memory (outer only) */
#define ARM_MPU_ATTR_DEVICE ( 0U )
/** \brief Attribute for non-cacheable, normal memory */
#define ARM_MPU_ATTR_NON_CACHEABLE ( 4U )
/** \brief Attribute for normal memory (outer and inner)
* \param NT Non-Transient: Set to 1 for non-transient data.
* \param WB Write-Back: Set to 1 to use write-back update policy.
* \param RA Read Allocation: Set to 1 to use cache allocation on read miss.
* \param WA Write Allocation: Set to 1 to use cache allocation on write miss.
*/
#define ARM_MPU_ATTR_MEMORY_(NT, WB, RA, WA) \
(((NT & 1U) << 3U) | ((WB & 1U) << 2U) | ((RA & 1U) << 1U) | (WA & 1U))
/** \brief Device memory type non Gathering, non Re-ordering, non Early Write Acknowledgement */
#define ARM_MPU_ATTR_DEVICE_nGnRnE (0U)
/** \brief Device memory type non Gathering, non Re-ordering, Early Write Acknowledgement */
#define ARM_MPU_ATTR_DEVICE_nGnRE (1U)
/** \brief Device memory type non Gathering, Re-ordering, Early Write Acknowledgement */
#define ARM_MPU_ATTR_DEVICE_nGRE (2U)
/** \brief Device memory type Gathering, Re-ordering, Early Write Acknowledgement */
#define ARM_MPU_ATTR_DEVICE_GRE (3U)
/** \brief Memory Attribute
* \param O Outer memory attributes
* \param I O == ARM_MPU_ATTR_DEVICE: Device memory attributes, else: Inner memory attributes
*/
#define ARM_MPU_ATTR(O, I) (((O & 0xFU) << 4U) | (((O & 0xFU) != 0U) ? (I & 0xFU) : ((I & 0x3U) << 2U)))
/** \brief Normal memory non-shareable */
#define ARM_MPU_SH_NON (0U)
/** \brief Normal memory outer shareable */
#define ARM_MPU_SH_OUTER (2U)
/** \brief Normal memory inner shareable */
#define ARM_MPU_SH_INNER (3U)
/** \brief Memory access permissions
* \param RO Read-Only: Set to 1 for read-only memory.
* \param NP Non-Privileged: Set to 1 for non-privileged memory.
*/
#define ARM_MPU_AP_(RO, NP) (((RO & 1U) << 1U) | (NP & 1U))
/** \brief Region Base Address Register value
* \param BASE The base address bits [31:5] of a memory region. The value is zero extended. Effective address gets 32 byte aligned.
* \param SH Defines the Shareability domain for this memory region.
* \param RO Read-Only: Set to 1 for a read-only memory region.
* \param NP Non-Privileged: Set to 1 for a non-privileged memory region.
* \oaram XN eXecute Never: Set to 1 for a non-executable memory region.
*/
#define ARM_MPU_RBAR(BASE, SH, RO, NP, XN) \
((BASE & MPU_RBAR_BASE_Msk) | \
((SH << MPU_RBAR_SH_Pos) & MPU_RBAR_SH_Msk) | \
((ARM_MPU_AP_(RO, NP) << MPU_RBAR_AP_Pos) & MPU_RBAR_AP_Msk) | \
((XN << MPU_RBAR_XN_Pos) & MPU_RBAR_XN_Msk))
/** \brief Region Limit Address Register value
* \param LIMIT The limit address bits [31:5] for this memory region. The value is one extended.
* \param IDX The attribute index to be associated with this memory region.
*/
#define ARM_MPU_RLAR(LIMIT, IDX) \
((LIMIT & MPU_RLAR_LIMIT_Msk) | \
((IDX << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk) | \
(MPU_RLAR_EN_Msk))
#if defined(MPU_RLAR_PXN_Pos)
/** \brief Region Limit Address Register with PXN value
* \param LIMIT The limit address bits [31:5] for this memory region. The value is one extended.
* \param PXN Privileged execute never. Defines whether code can be executed from this privileged region.
* \param IDX The attribute index to be associated with this memory region.
*/
#define ARM_MPU_RLAR_PXN(LIMIT, PXN, IDX) \
((LIMIT & MPU_RLAR_LIMIT_Msk) | \
((PXN << MPU_RLAR_PXN_Pos) & MPU_RLAR_PXN_Msk) | \
((IDX << MPU_RLAR_AttrIndx_Pos) & MPU_RLAR_AttrIndx_Msk) | \
(MPU_RLAR_EN_Msk))
#endif
/**
* Struct for a single MPU Region
*/
typedef struct {
uint32_t RBAR; /*!< Region Base Address Register value */
uint32_t RLAR; /*!< Region Limit Address Register value */
} ARM_MPU_Region_t;
/** Enable the MPU.
* \param MPU_Control Default access permissions for unconfigured regions.
*/
__STATIC_INLINE void ARM_MPU_Enable(uint32_t MPU_Control)
{
MPU->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
#endif
__DSB();
__ISB();
}
/** Disable the MPU.
*/
__STATIC_INLINE void ARM_MPU_Disable(void)
{
__DMB();
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
#endif
MPU->CTRL &= ~MPU_CTRL_ENABLE_Msk;
}
#ifdef MPU_NS
/** Enable the Non-secure MPU.
* \param MPU_Control Default access permissions for unconfigured regions.
*/
__STATIC_INLINE void ARM_MPU_Enable_NS(uint32_t MPU_Control)
{
MPU_NS->CTRL = MPU_Control | MPU_CTRL_ENABLE_Msk;
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB_NS->SHCSR |= SCB_SHCSR_MEMFAULTENA_Msk;
#endif
__DSB();
__ISB();
}
/** Disable the Non-secure MPU.
*/
__STATIC_INLINE void ARM_MPU_Disable_NS(void)
{
__DMB();
#ifdef SCB_SHCSR_MEMFAULTENA_Msk
SCB_NS->SHCSR &= ~SCB_SHCSR_MEMFAULTENA_Msk;
#endif
MPU_NS->CTRL &= ~MPU_CTRL_ENABLE_Msk;
}
#endif
/** Set the memory attribute encoding to the given MPU.
* \param mpu Pointer to the MPU to be configured.
* \param idx The attribute index to be set [0-7]
* \param attr The attribute value to be set.
*/
__STATIC_INLINE void ARM_MPU_SetMemAttrEx(MPU_Type* mpu, uint8_t idx, uint8_t attr)
{
const uint8_t reg = idx / 4U;
const uint32_t pos = ((idx % 4U) * 8U);
const uint32_t mask = 0xFFU << pos;
if (reg >= (sizeof(mpu->MAIR) / sizeof(mpu->MAIR[0]))) {
return; // invalid index
}
mpu->MAIR[reg] = ((mpu->MAIR[reg] & ~mask) | ((attr << pos) & mask));
}
/** Set the memory attribute encoding.
* \param idx The attribute index to be set [0-7]
* \param attr The attribute value to be set.
*/
__STATIC_INLINE void ARM_MPU_SetMemAttr(uint8_t idx, uint8_t attr)
{
ARM_MPU_SetMemAttrEx(MPU, idx, attr);
}
#ifdef MPU_NS
/** Set the memory attribute encoding to the Non-secure MPU.
* \param idx The attribute index to be set [0-7]
* \param attr The attribute value to be set.
*/
__STATIC_INLINE void ARM_MPU_SetMemAttr_NS(uint8_t idx, uint8_t attr)
{
ARM_MPU_SetMemAttrEx(MPU_NS, idx, attr);
}
#endif
/** Clear and disable the given MPU region of the given MPU.
* \param mpu Pointer to MPU to be used.
* \param rnr Region number to be cleared.
*/
__STATIC_INLINE void ARM_MPU_ClrRegionEx(MPU_Type* mpu, uint32_t rnr)
{
mpu->RNR = rnr;
mpu->RLAR = 0U;
}
/** Clear and disable the given MPU region.
* \param rnr Region number to be cleared.
*/
__STATIC_INLINE void ARM_MPU_ClrRegion(uint32_t rnr)
{
ARM_MPU_ClrRegionEx(MPU, rnr);
}
#ifdef MPU_NS
/** Clear and disable the given Non-secure MPU region.
* \param rnr Region number to be cleared.
*/
__STATIC_INLINE void ARM_MPU_ClrRegion_NS(uint32_t rnr)
{
ARM_MPU_ClrRegionEx(MPU_NS, rnr);
}
#endif
/** Configure the given MPU region of the given MPU.
* \param mpu Pointer to MPU to be used.
* \param rnr Region number to be configured.
* \param rbar Value for RBAR register.
* \param rlar Value for RLAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegionEx(MPU_Type* mpu, uint32_t rnr, uint32_t rbar, uint32_t rlar)
{
mpu->RNR = rnr;
mpu->RBAR = rbar;
mpu->RLAR = rlar;
}
/** Configure the given MPU region.
* \param rnr Region number to be configured.
* \param rbar Value for RBAR register.
* \param rlar Value for RLAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegion(uint32_t rnr, uint32_t rbar, uint32_t rlar)
{
ARM_MPU_SetRegionEx(MPU, rnr, rbar, rlar);
}
#ifdef MPU_NS
/** Configure the given Non-secure MPU region.
* \param rnr Region number to be configured.
* \param rbar Value for RBAR register.
* \param rlar Value for RLAR register.
*/
__STATIC_INLINE void ARM_MPU_SetRegion_NS(uint32_t rnr, uint32_t rbar, uint32_t rlar)
{
ARM_MPU_SetRegionEx(MPU_NS, rnr, rbar, rlar);
}
#endif
/** Memcopy with strictly ordered memory access, e.g. for register targets.
* \param dst Destination data is copied to.
* \param src Source data is copied from.
* \param len Amount of data words to be copied.
*/
__STATIC_INLINE void ARM_MPU_OrderedMemcpy(volatile uint32_t* dst, const uint32_t* __RESTRICT src, uint32_t len)
{
uint32_t i;
for (i = 0U; i < len; ++i)
{
dst[i] = src[i];
}
}
/** Load the given number of MPU regions from a table to the given MPU.
* \param mpu Pointer to the MPU registers to be used.
* \param rnr First region number to be configured.
* \param table Pointer to the MPU configuration table.
* \param cnt Amount of regions to be configured.
*/
__STATIC_INLINE void ARM_MPU_LoadEx(MPU_Type* mpu, uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt)
{
const uint32_t rowWordSize = sizeof(ARM_MPU_Region_t)/4U;
if (cnt == 1U) {
mpu->RNR = rnr;
ARM_MPU_OrderedMemcpy(&(mpu->RBAR), &(table->RBAR), rowWordSize);
} else {
uint32_t rnrBase = rnr & ~(MPU_TYPE_RALIASES-1U);
uint32_t rnrOffset = rnr % MPU_TYPE_RALIASES;
mpu->RNR = rnrBase;
while ((rnrOffset + cnt) > MPU_TYPE_RALIASES) {
uint32_t c = MPU_TYPE_RALIASES - rnrOffset;
ARM_MPU_OrderedMemcpy(&(mpu->RBAR)+(rnrOffset*2U), &(table->RBAR), c*rowWordSize);
table += c;
cnt -= c;
rnrOffset = 0U;
rnrBase += MPU_TYPE_RALIASES;
mpu->RNR = rnrBase;
}
ARM_MPU_OrderedMemcpy(&(mpu->RBAR)+(rnrOffset*2U), &(table->RBAR), cnt*rowWordSize);
}
}
/** Load the given number of MPU regions from a table.
* \param rnr First region number to be configured.
* \param table Pointer to the MPU configuration table.
* \param cnt Amount of regions to be configured.
*/
__STATIC_INLINE void ARM_MPU_Load(uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt)
{
ARM_MPU_LoadEx(MPU, rnr, table, cnt);
}
#ifdef MPU_NS
/** Load the given number of MPU regions from a table to the Non-secure MPU.
* \param rnr First region number to be configured.
* \param table Pointer to the MPU configuration table.
* \param cnt Amount of regions to be configured.
*/
__STATIC_INLINE void ARM_MPU_Load_NS(uint32_t rnr, ARM_MPU_Region_t const* table, uint32_t cnt)
{
ARM_MPU_LoadEx(MPU_NS, rnr, table, cnt);
}
#endif
#endif
+4 -4
View File
@@ -7,7 +7,7 @@ void adc_init(void) {
ADC1->CR &= ~(ADC_CR_ADCALDIF); // Choose single-ended calibration
ADC1->CR |= ADC_CR_ADCALLIN; // Lineriality calibration
ADC1->CR |= ADC_CR_ADCAL; // Start calibrtation
while((ADC1->CR & ADC_CR_ADCAL) != 0);
while((ADC1->CR & ADC_CR_ADCAL) != 0U);
ADC1->ISR |= ADC_ISR_ADRDY;
ADC1->CR |= ADC_CR_ADEN;
@@ -17,11 +17,11 @@ void adc_init(void) {
uint16_t adc_get_raw(uint8_t channel) {
uint16_t res = 0U;
ADC1->SQR1 &= ~(ADC_SQR1_L);
ADC1->SQR1 = ((uint32_t) channel << 6U);
ADC1->SQR1 = (uint32_t)channel << 6U;
ADC1->SMPR1 = (0x2U << (channel * 3U));
ADC1->SMPR1 = 0x2UL << (channel * 3UL);
ADC1->PCSEL_RES0 = (0x1UL << channel);
ADC1->CFGR2 = (127U << ADC_CFGR2_OVSR_Pos) | (0x7U << ADC_CFGR2_OVSS_Pos) | ADC_CFGR2_ROVSE;
ADC1->CFGR2 = (127UL << ADC_CFGR2_OVSR_Pos) | (0x7U << ADC_CFGR2_OVSS_Pos) | ADC_CFGR2_ROVSE;
ADC1->CR |= ADC_CR_ADSTART;
while (!(ADC1->ISR & ADC_ISR_EOC));
-63
View File
@@ -1,63 +0,0 @@
void EXTI_IRQ_Handler(void);
void exti_irq_init(void) {
if (harness.status == HARNESS_STATUS_FLIPPED) {
// CAN2_RX IRQ on falling edge (EXTI10)
current_board->enable_can_transceiver(3U, false);
SYSCFG->EXTICR[2] &= ~(SYSCFG_EXTICR3_EXTI10_Msk);
SYSCFG->EXTICR[2] |= (SYSCFG_EXTICR3_EXTI10_PG);
EXTI->IMR1 |= EXTI_IMR1_IM10;
EXTI->RTSR1 &= ~EXTI_RTSR1_TR10; // rising edge
EXTI->FTSR1 |= EXTI_FTSR1_TR10; // falling edge
// IRQ on falling edge for PA1 (SBU2, EXTI1)
SYSCFG->EXTICR[0] &= ~(SYSCFG_EXTICR1_EXTI1_Msk);
SYSCFG->EXTICR[0] |= (SYSCFG_EXTICR1_EXTI1_PA);
EXTI->IMR1 |= EXTI_IMR1_IM1;
EXTI->RTSR1 &= ~EXTI_RTSR1_TR1; // rising edge
EXTI->FTSR1 |= EXTI_FTSR1_TR1; // falling edge
REGISTER_INTERRUPT(EXTI1_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI1_IRQn);
REGISTER_INTERRUPT(EXTI15_10_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI15_10_IRQn);
} else {
// CAN0_RX IRQ on falling edge (EXTI8)
current_board->enable_can_transceiver(1U, false);
SYSCFG->EXTICR[2] &= ~(SYSCFG_EXTICR3_EXTI8_Msk);
SYSCFG->EXTICR[2] |= (SYSCFG_EXTICR3_EXTI8_PB);
EXTI->IMR1 |= EXTI_IMR1_IM8;
EXTI->RTSR1 &= ~EXTI_RTSR1_TR8; // rising edge
EXTI->FTSR1 |= EXTI_FTSR1_TR8; // falling edge
// IRQ on falling edge for PC4 (SBU1, EXTI4)
SYSCFG->EXTICR[1] &= ~(SYSCFG_EXTICR2_EXTI4_Msk);
SYSCFG->EXTICR[1] |= (SYSCFG_EXTICR2_EXTI4_PC);
EXTI->IMR1 |= EXTI_IMR1_IM4;
EXTI->RTSR1 &= ~EXTI_RTSR1_TR4; // rising edge
EXTI->FTSR1 |= EXTI_FTSR1_TR4; // falling edge
REGISTER_INTERRUPT(EXTI4_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI4_IRQn);
REGISTER_INTERRUPT(EXTI9_5_IRQn, EXTI_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_EXTI)
NVIC_EnableIRQ(EXTI9_5_IRQn);
}
}
bool check_exti_irq(void) {
return ((EXTI->PR1 & EXTI_PR1_PR8) || (EXTI->PR1 & EXTI_PR1_PR10) || (EXTI->PR1 & EXTI_PR1_PR1) || (EXTI->PR1 & EXTI_PR1_PR4));
}
void exti_irq_clear(void) {
// Clear pending bits
EXTI->PR1 |= EXTI_PR1_PR8;
EXTI->PR1 |= EXTI_PR1_PR10;
EXTI->PR1 |= EXTI_PR1_PR4;
EXTI->PR1 |= EXTI_PR1_PR1; // works
EXTI->PR1 |= EXTI_PR1_PR19; // works
// Disable all active EXTI IRQs
EXTI->IMR1 &= ~EXTI_IMR1_IM8;
EXTI->IMR1 &= ~EXTI_IMR1_IM10;
EXTI->IMR1 &= ~EXTI_IMR1_IM4;
EXTI->IMR1 &= ~EXTI_IMR1_IM1;
EXTI->IMR1 &= ~EXTI_IMR1_IM19;
}
+4 -4
View File
@@ -55,7 +55,7 @@ bool fdcan_request_init(FDCAN_GlobalTypeDef *FDCANx) {
// Request init
uint32_t timeout_counter = 0U;
FDCANx->CCCR |= FDCAN_CCCR_INIT;
while ((FDCANx->CCCR & FDCAN_CCCR_INIT) == 0) {
while ((FDCANx->CCCR & FDCAN_CCCR_INIT) == 0U) {
// Delay for about 1ms
delay(10000);
timeout_counter++;
@@ -73,7 +73,7 @@ bool fdcan_exit_init(FDCAN_GlobalTypeDef *FDCANx) {
FDCANx->CCCR &= ~(FDCAN_CCCR_INIT);
uint32_t timeout_counter = 0U;
while ((FDCANx->CCCR & FDCAN_CCCR_INIT) != 0) {
while ((FDCANx->CCCR & FDCAN_CCCR_INIT) != 0U) {
// Delay for about 1ms
delay(10000);
timeout_counter++;
@@ -118,7 +118,7 @@ bool llcan_set_speed(FDCAN_GlobalTypeDef *FDCANx, uint32_t speed, uint32_t data_
uint32_t seg2 = CAN_SEG2(tq, sp);
uint8_t sjw = MIN(127U, seg2);
FDCANx->NBTP = (((sjw & 0x7FU)-1U)<<FDCAN_NBTP_NSJW_Pos) | (((seg1 & 0xFFU)-1U)<<FDCAN_NBTP_NTSEG1_Pos) | (((seg2 & 0x7FU)-1U)<<FDCAN_NBTP_NTSEG2_Pos) | (((prescaler & 0x1FFU)-1U)<<FDCAN_NBTP_NBRP_Pos);
FDCANx->NBTP = (((sjw & 0x7FUL)-1U)<<FDCAN_NBTP_NSJW_Pos) | (((seg1 & 0xFFU)-1U)<<FDCAN_NBTP_NTSEG1_Pos) | (((seg2 & 0x7FU)-1U)<<FDCAN_NBTP_NTSEG2_Pos) | (((prescaler & 0x1FFUL)-1U)<<FDCAN_NBTP_NBRP_Pos);
// Set the data bit timing values
if (data_speed == 50000U) {
@@ -131,7 +131,7 @@ bool llcan_set_speed(FDCAN_GlobalTypeDef *FDCANx, uint32_t speed, uint32_t data_
seg2 = CAN_SEG2(tq, sp);
sjw = MIN(15U, seg2);
FDCANx->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);
FDCANx->DBTP = (((sjw & 0xFUL)-1U)<<FDCAN_DBTP_DSJW_Pos) | (((seg1 & 0x1FU)-1U)<<FDCAN_DBTP_DTSEG1_Pos) | (((seg2 & 0xFU)-1U)<<FDCAN_DBTP_DTSEG2_Pos) | (((prescaler & 0x1FUL)-1U)<<FDCAN_DBTP_DBRP_Pos);
if (non_iso) {
// FD non-ISO mode
+5 -5
View File
@@ -16,10 +16,10 @@ bool i2c_write_reg(I2C_TypeDef *I2C, uint8_t addr, uint8_t reg, uint8_t value) {
bool ret = false;
for(uint32_t i=0U; i<10U; i++) {
register_clear_bits(&I2C->CR2, I2C_CR2_ADD10);
I2C->CR2 = ((addr << 1U) & I2C_CR2_SADD_Msk);
I2C->CR2 = ((uint32_t)addr << 1U) & I2C_CR2_SADD_Msk;
register_clear_bits(&I2C->CR2, I2C_CR2_RD_WRN);
register_set_bits(&I2C->CR2, I2C_CR2_AUTOEND);
I2C->CR2 |= (2 << I2C_CR2_NBYTES_Pos);
I2C->CR2 |= 2UL << I2C_CR2_NBYTES_Pos;
I2C->CR2 |= I2C_CR2_START;
if(!i2c_status_wait(&I2C->CR2, I2C_CR2_START, 0U)) {
@@ -61,10 +61,10 @@ bool i2c_read_reg(I2C_TypeDef *I2C, uint8_t addr, uint8_t reg, uint8_t *value) {
bool ret = false;
for(uint32_t i=0U; i<10U; i++) {
register_clear_bits(&I2C->CR2, I2C_CR2_ADD10);
I2C->CR2 = ((addr << 1U) & I2C_CR2_SADD_Msk);
I2C->CR2 = ((uint32_t)addr << 1U) & I2C_CR2_SADD_Msk;
register_clear_bits(&I2C->CR2, I2C_CR2_RD_WRN);
register_clear_bits(&I2C->CR2, I2C_CR2_AUTOEND);
I2C->CR2 |= (1 << I2C_CR2_NBYTES_Pos);
I2C->CR2 |= 1UL << I2C_CR2_NBYTES_Pos;
I2C->CR2 |= I2C_CR2_START;
if(!i2c_status_wait(&I2C->CR2, I2C_CR2_START, 0U)) {
@@ -92,7 +92,7 @@ bool i2c_read_reg(I2C_TypeDef *I2C, uint8_t addr, uint8_t reg, uint8_t *value) {
I2C->TXDR = reg;
// Restart
I2C->CR2 = (((addr << 1) | 0x1U) & I2C_CR2_SADD_Msk) | (1U << I2C_CR2_NBYTES_Pos) | I2C_CR2_RD_WRN | I2C_CR2_START;
I2C->CR2 = (((addr << 1) | 0x1U) & I2C_CR2_SADD_Msk) | (1UL << I2C_CR2_NBYTES_Pos) | I2C_CR2_RD_WRN | I2C_CR2_START;
ret = i2c_status_wait(&I2C->CR2, I2C_CR2_START, 0U);
if(!ret) {
goto end;
-69
View File
@@ -1,69 +0,0 @@
void enable_bdomain_protection(void) {
register_clear_bits(&(PWR->CR1), PWR_CR1_DBP);
}
void disable_bdomain_protection(void) {
register_set_bits(&(PWR->CR1), PWR_CR1_DBP);
}
void rtc_init(void){
uint32_t bdcr_opts = RCC_BDCR_RTCEN;
uint32_t bdcr_mask = (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL);
if (current_board->has_rtc_battery) {
bdcr_opts |= (RCC_BDCR_LSEDRV_1 | RCC_BDCR_RTCSEL_0 | RCC_BDCR_LSEON);
bdcr_mask |= (RCC_BDCR_LSEDRV | RCC_BDCR_LSEBYP | RCC_BDCR_LSEON);
} else {
bdcr_opts |= RCC_BDCR_RTCSEL_1;
RCC->CSR |= RCC_CSR_LSION;
while((RCC->CSR & RCC_CSR_LSIRDY) == 0){}
}
// Initialize RTC module and clock if not done already.
if((RCC->BDCR & bdcr_mask) != bdcr_opts){
print("Initializing RTC\n");
// Reset backup domain
register_set_bits(&(RCC->BDCR), RCC_BDCR_BDRST);
// Disable write protection
disable_bdomain_protection();
// Clear backup domain reset
register_clear_bits(&(RCC->BDCR), RCC_BDCR_BDRST);
// Set RTC options
register_set(&(RCC->BDCR), bdcr_opts, bdcr_mask);
// Enable write protection
enable_bdomain_protection();
}
}
void rtc_wakeup_init(void) {
EXTI->IMR1 |= EXTI_IMR1_IM19;
EXTI->RTSR1 |= EXTI_RTSR1_TR19; // rising edge
EXTI->FTSR1 &= ~EXTI_FTSR1_TR19; // falling edge
NVIC_DisableIRQ(RTC_WKUP_IRQn);
// Disable write protection
disable_bdomain_protection();
RTC->WPR = 0xCA;
RTC->WPR = 0x53;
RTC->CR &= ~RTC_CR_WUTE;
while((RTC->ISR & RTC_ISR_WUTWF) == 0){}
RTC->CR &= ~RTC_CR_WUTIE;
RTC->ISR &= ~RTC_ISR_WUTF;
//PWR->CR1 |= PWR_CR1_CWUF;
RTC->WUTR = DEEPSLEEP_WAKEUP_DELAY;
// Wakeup timer interrupt enable, wakeup timer enable, select 1Hz rate
RTC->CR |= RTC_CR_WUTE | RTC_CR_WUTIE | RTC_CR_WUCKSEL_2;
// Re-enable write protection
RTC->WPR = 0x00;
enable_bdomain_protection();
NVIC_EnableIRQ(RTC_WKUP_IRQn);
}
+1 -1
View File
@@ -71,7 +71,7 @@ void SPI4_IRQ_Handler(void) {
// clear flag
SPI4->IFCR |= (0x1FFU << 3U);
if (spi_tx_dma_done && ((SPI4->SR & SPI_SR_TXC) != 0)) {
if (spi_tx_dma_done && ((SPI4->SR & SPI_SR_TXC) != 0U)) {
spi_tx_dma_done = false;
spi_tx_done(false);
}

Some files were not shown because too many files have changed in this diff Show More