29 Commits

Author SHA1 Message Date
f3603870fa Implement reboot to new image 2022-08-12 17:10:57 +02:00
fc6fbd083d WIP CAN flashing support 2022-08-12 17:10:57 +02:00
bda583b94c Add persist RAM area for passing data across resets; implement booting from a partition specified in the persist RAM area 2022-08-12 17:10:06 +02:00
f29c4d182e Deduplicate and improve linker scripts 2022-04-28 21:08:02 +02:00
6fae8ef918 Resolve location of interrupt vector table at link time 2022-04-28 21:08:02 +02:00
62967fe497 Make bobbycar-protocol library less useless 2022-04-28 21:08:02 +02:00
c0401ffd32 Stop trying to please CMake 2022-04-28 21:08:02 +02:00
4376dceb23 Organize defines in ab_boot.h better 2022-04-28 21:08:02 +02:00
9fa8b64e81 Add bootloader for A/B update support 2022-04-28 21:08:02 +02:00
1161ed6c42 Add Id Iq currents 2022-04-26 23:14:40 +02:00
e60c2fa6d2 Added error logging for ci 2022-03-16 18:13:47 +01:00
5ebd6e6779 Added CI
Added a build ci to see if new commits still work
2022-03-16 18:01:47 +01:00
70ef49418b add more hall configs 2022-02-03 21:17:51 +01:00
96a6424baa add new configs for hall 2022-02-03 21:10:31 +01:00
6436fecd85 add new hall sensor configs 2022-02-03 21:08:08 +01:00
3b4e67d740 fixed iMotMax and fieldWeakMax overflow (with ~40A) 2021-09-17 17:35:10 +02:00
c21ad44f9c Fixed compiler warnings 2021-06-28 10:47:14 +02:00
abe066df79 New protocol with more sorts of currents 2021-06-28 10:35:05 +02:00
da24c84835 Update README.md 2021-06-03 21:38:55 +02:00
7ed695dace Updated README with new flash build targets 2021-05-30 02:55:53 +02:00
c194308080 Added greyhash build config 2021-05-30 02:54:29 +02:00
3e768dbdef Multiple build configs in CMake 2021-05-30 02:45:37 +02:00
e2b823c901 Added feedc0de front/back configurations in CMakeLists.txt 2021-05-29 00:01:03 +02:00
0b661709da Can communication (#9)
* First tries with can

* More implementations

* More registers

* More implementations

* Moved canbus registers into protocol submodule

* CAN finishing work

* Implemented debug utilities

* back/front board compile time defines

* More compile defines

* Fixed disable mosfets stuck

* More improvements

* More refactorings

* Cleanups

* Cleanups

* Updated merged protocol
2021-05-23 17:54:44 +02:00
a88af55928 More cleanups 2021-05-14 21:56:47 +02:00
274466e017 More cleanups and improvements 2021-05-14 21:31:12 +02:00
94ded84e82 Formatting fixes 2021-05-14 21:16:34 +02:00
57e57a07bb Buzzer freq fix 2021-05-14 20:51:01 +02:00
6ec3740aaf HUART2 and HUART3 usable now 2021-05-14 20:46:59 +02:00
21 changed files with 1972 additions and 469 deletions

43
.github/workflows/workflow.yml vendored Normal file
View File

@ -0,0 +1,43 @@
name: CI
on:
push:
release:
types:
- created
# pull_request:
# types: [opened, synchronize, reopened]
# checkout, install make and try to build
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
config: [motortest, motortest_peter, feedcode-front, feedcode-back, greyhash]
steps:
- uses: actions/checkout@v2
with:
submodules: 'true'
- name: Install make
run: |
sudo apt update -y
sudo apt install -y binutils-arm-none-eabi gcc-arm-none-eabi libnewlib-arm-none-eabi cmake make
- name: Build
id: build
continue-on-error: true
run: |
cmake -DCMAKE_BUILD_TYPE=Release .
make -j$(nproc) ${{ matrix.config }}
# github artifacts
- name: Upload logs if failed
if: ${{ steps.build.outcome == 'failure' }}
uses: actions/upload-artifact@v2.2.4
with:
path: |
./CMakeFiles/CMakeOutput.log
./CMakeFiles/CMakeError.log

View File

@ -10,14 +10,22 @@ SET(CMAKE_SYSTEM_NAME Generic)
set(COMMON_FLAGS "-mcpu=cortex-m3 -mthumb -Wall -fdata-sections -ffunction-sections")
set(CMAKE_ASM_FLAGS "${COMMON_FLAGS} -x assembler-with-cpp")
set(CMAKE_C_FLAGS "${COMMON_FLAGS} -std=gnu11")
set(CMAKE_CXX_FLAGS "${COMMON_FLAGS} -std=c++17")
set(CMAKE_C_FLAGS "${COMMON_FLAGS}")
set(CMAKE_CXX_FLAGS "${COMMON_FLAGS}")
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 20)
set(COMMON_LINKER_FLAGS "-specs=nosys.specs -T${CMAKE_SOURCE_DIR}/STM32F103RCTx_FLASH.ld -lc -lm -lnosys -lstdc++ -Wl,--gc-sections -Wl,-Map=${CMAKE_BINARY_DIR}/hover.map,--cref")
set(CMAKE_EXE_LINKER_FLAGS "${COMMON_LINKER_FLAGS}")
set(CMAKE_SHARED_LINKER_FLAGS "${COMMON_LINKER_FLAGS}")
set(A_FIRMWARE_LINKER_FLAGS "-T${CMAKE_SOURCE_DIR}/ld/app_a.ld")
set(B_FIRMWARE_LINKER_FLAGS "-T${CMAKE_SOURCE_DIR}/ld/app_b.ld")
set(AB_BOOT_FIRMWARE_LINKER_FLAGS "-T${CMAKE_SOURCE_DIR}/ld/ab_boot.ld")
set(COMMON_LINKER_FLAGS -specs=nosys.specs -lc -lm -lnosys -lstdc++ -Wl,--gc-sections "-Wl,-Map=${CMAKE_BINARY_DIR}/hover.map,--cref"
-T${CMAKE_SOURCE_DIR}/ld/STM32F103RCTx_FLASH.ld)
set(A_FIRMWARE_APP_BASE 0x08002000)
set(B_FIRMWARE_APP_BASE 0x08020800)
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
project(bobbycar-controller-firmware ASM C CXX)
@ -30,15 +38,9 @@ include_directories(
STM32CubeF1/Drivers/CMSIS/Device/ST/STM32F1xx/Include
STM32CubeF1/Drivers/CMSIS/Include
bobbycar-foc-model
bobbycar-protocol
)
#add_definitions(-DMOTOR_TEST)
#add_definitions(-DFEATURE_IGNORE_OTHER_MOTOR)
add_definitions(-DFEATURE_BUTTON)
#add_definitions(-DPETERS_PLATINE)
add_executable(firmware.elf
add_library(stm32_hal STATIC
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal.c
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_flash.c
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_pwr.c
@ -54,40 +56,184 @@ add_executable(firmware.elf
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_adc.c
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_uart.c
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_dma.c
STM32CubeF1/Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_can.c
startup_stm32f103xe.s
)
add_library(emanuel_foc_model STATIC
bobbycar-foc-model/BLDC_controller.h
bobbycar-foc-model/BLDC_controller.c
bobbycar-foc-model/BLDC_controller_data.c
bobbycar-foc-model/rtwtypes.h
)
bobbycar-protocol/protocol.h
add_library(bobbycar-protocol INTERFACE)
target_include_directories(bobbycar-protocol INTERFACE bobbycar-protocol)
startup_stm32f103xe.s
system_stm32f1xx.c
set(COMMON_SOURCES
config.h
defines.h
main.cpp
system_stm32f1xx.c
persist/persist.c
)
add_custom_command(OUTPUT firmware.hex
COMMAND arm-none-eabi-objcopy -O ihex firmware.elf firmware.hex
DEPENDS firmware.elf)
#
# motor test
#
add_executable(motortest.elf ${COMMON_SOURCES})
target_link_options(motortest.elf PRIVATE ${COMMON_LINKER_FLAGS} ${A_FIRMWARE_LINKER_FLAGS})
target_link_libraries(motortest.elf stm32_hal emanuel_foc_model bobbycar-protocol)
target_compile_options(motortest.elf PRIVATE
-DMOTOR_TEST
-DFEATURE_IGNORE_OTHER_MOTOR
# -DHALL_BCA
# -DPWM_FREQ_12KHZ
# -DFEATURE_BUTTON
# -DPETERS_PLATINE
# -DHUART2
# -DHUART3
# -DFEATURE_SERIAL_CONTROL
# -DFEATURE_SERIAL_FEEDBACK
# -DLOG_TO_SERIAL
# -DFEATURE_CAN
# -DCAN_LOG_UNKNOWN_ADDR
# -DIS_BACK
)
add_custom_command(OUTPUT motortest.hex COMMAND arm-none-eabi-objcopy -O ihex motortest.elf motortest.hex DEPENDS motortest.elf)
add_custom_command(OUTPUT motortest.bin COMMAND arm-none-eabi-objcopy -O binary -S motortest.elf motortest.bin DEPENDS motortest.elf)
add_custom_target(motortest ALL SOURCES motortest.hex motortest.bin)
add_custom_target(flash-motortest COMMAND st-flash --reset write motortest.bin ${A_FIRMWARE_APP_BASE} SOURCES motortest.bin DEPENDS motortest.bin)
add_custom_command(OUTPUT firmware.bin
COMMAND arm-none-eabi-objcopy -O binary -S firmware.elf firmware.bin
DEPENDS firmware.elf)
#
# motor test peter
#
add_executable(motortest_peter.elf ${COMMON_SOURCES})
target_link_options(motortest_peter.elf PRIVATE ${COMMON_LINKER_FLAGS} ${A_FIRMWARE_LINKER_FLAGS})
target_link_libraries(motortest_peter.elf stm32_hal emanuel_foc_model bobbycar-protocol)
target_compile_options(motortest_peter.elf PRIVATE
#-DMOTOR_TEST
-DFEATURE_IGNORE_OTHER_MOTOR
-DHALL_ABC
# -DPWM_FREQ_12KHZ
# -DFEATURE_BUTTON
-DPETERS_PLATINE
# -DFEATURE_INVERT_HALL
# -DHUART2
# -DHUART3
# -DFEATURE_SERIAL_CONTROL
# -DFEATURE_SERIAL_FEEDBACK
# -DLOG_TO_SERIAL
-DFEATURE_CAN
# -DCAN_LOG_UNKNOWN_ADDR
-DIS_BACK
)
add_custom_command(OUTPUT motortest_peter.hex COMMAND arm-none-eabi-objcopy -O ihex motortest_peter.elf motortest_peter.hex DEPENDS motortest_peter.elf)
add_custom_command(OUTPUT motortest_peter.bin COMMAND arm-none-eabi-objcopy -O binary -S motortest_peter.elf motortest_peter.bin DEPENDS motortest_peter.elf)
add_custom_target(motortest_peter ALL SOURCES motortest_peter.hex motortest_peter.bin)
add_custom_target(flash-motortest_peter COMMAND st-flash --reset write motortest_peter.bin ${A_FIRMWARE_APP_BASE} SOURCES motortest_peter.bin DEPENDS motortest_peter.bin)
add_custom_target(firmware ALL
SOURCES firmware.hex firmware.bin)
add_custom_target(flash
COMMAND st-flash --reset write firmware.bin 0x8000000
SOURCES firmware.bin)
#
# feedc0de front
#
add_executable(feedcode-front.elf ${COMMON_SOURCES})
target_link_options(feedcode-front.elf PRIVATE ${COMMON_LINKER_FLAGS} ${A_FIRMWARE_LINKER_FLAGS})
target_link_libraries(feedcode-front.elf stm32_hal emanuel_foc_model bobbycar-protocol)
target_compile_options(feedcode-front.elf PRIVATE
# -DMOTOR_TEST
-DFEATURE_IGNORE_OTHER_MOTOR
-DHALL_BCA
# -DPWM_FREQ_12KHZ
# -DFEATURE_BUTTON
-DPETERS_PLATINE
# -DHUART2
# -DHUART3
# -DFEATURE_SERIAL_CONTROL
# -DFEATURE_SERIAL_FEEDBACK
# -DLOG_TO_SERIAL
-DFEATURE_CAN
# -DCAN_LOG_UNKNOWN_ADDR
# -DIS_BACK
)
add_custom_command(OUTPUT feedcode-front.hex COMMAND arm-none-eabi-objcopy -O ihex feedcode-front.elf feedcode-front.hex DEPENDS feedcode-front.elf)
add_custom_command(OUTPUT feedcode-front.bin COMMAND arm-none-eabi-objcopy -O binary -S feedcode-front.elf feedcode-front.bin DEPENDS feedcode-front.elf)
add_custom_target(feedcode-front ALL SOURCES feedcode-front.hex feedcode-front.bin)
add_custom_target(flash-feedcode-front COMMAND st-flash --reset write feedcode-front.bin ${A_FIRMWARE_APP_BASE} SOURCES feedcode-front.bin DEPENDS feedcode-front.bin)
#
# feedc0de back
#
add_executable(feedcode-back.elf ${COMMON_SOURCES})
target_link_options(feedcode-back.elf PRIVATE ${COMMON_LINKER_FLAGS} ${A_FIRMWARE_LINKER_FLAGS})
target_link_libraries(feedcode-back.elf stm32_hal emanuel_foc_model bobbycar-protocol)
target_compile_options(feedcode-back.elf PRIVATE
# -DMOTOR_TEST
-DFEATURE_IGNORE_OTHER_MOTOR
# -DHALL_BCA
# -DPWM_FREQ_12KHZ
# -DFEATURE_BUTTON
-DPETERS_PLATINE
# -DHUART2
# -DHUART3
# -DFEATURE_SERIAL_CONTROL
# -DFEATURE_SERIAL_FEEDBACK
# -DLOG_TO_SERIAL
-DFEATURE_CAN
# -DCAN_LOG_UNKNOWN_ADDR
-DIS_BACK
)
add_custom_command(OUTPUT feedcode-back.hex COMMAND arm-none-eabi-objcopy -O ihex feedcode-back.elf feedcode-back.hex DEPENDS feedcode-back.elf)
add_custom_command(OUTPUT feedcode-back.bin COMMAND arm-none-eabi-objcopy -O binary -S feedcode-back.elf feedcode-back.bin DEPENDS feedcode-back.elf)
add_custom_target(feedcode-back ALL SOURCES feedcode-back.hex feedcode-back.bin)
add_custom_target(flash-feedcode-back COMMAND st-flash --reset write feedcode-back.bin ${A_FIRMWARE_APP_BASE} SOURCES feedcode-back.bin DEPENDS feedcode-back.bin)
#
# greyhash
#
add_executable(greyhash.elf ${COMMON_SOURCES})
target_link_options(greyhash.elf PRIVATE ${COMMON_LINKER_FLAGS} ${A_FIRMWARE_LINKER_FLAGS})
target_link_libraries(greyhash.elf stm32_hal emanuel_foc_model bobbycar-protocol)
target_compile_options(greyhash.elf PRIVATE
# -DMOTOR_TEST
-DFEATURE_IGNORE_OTHER_MOTOR
# -DHALL_BCA
-DPWM_FREQ_12KHZ
# -DFEATURE_BUTTON
-DPETERS_PLATINE
# -DHUART2
-DHUART3
-DFEATURE_SERIAL_CONTROL
-DFEATURE_SERIAL_FEEDBACK
# -DLOG_TO_SERIAL
# -DFEATURE_CAN
# -DCAN_LOG_UNKNOWN_ADDR
# -DIS_BACK
)
add_custom_command(OUTPUT greyhash.hex COMMAND arm-none-eabi-objcopy -O ihex greyhash.elf greyhash.hex DEPENDS greyhash.elf)
add_custom_command(OUTPUT greyhash.bin COMMAND arm-none-eabi-objcopy -O binary -S greyhash.elf greyhash.bin DEPENDS greyhash.elf)
add_custom_target(greyhash ALL SOURCES greyhash.hex greyhash.bin)
add_custom_target(flash-greyhash COMMAND st-flash --reset write greyhash.bin ${A_FIRMWARE_APP_BASE} SOURCES greyhash.bin DEPENDS greyhash.bin)
add_executable(ab_boot.elf
ab_boot/ab_boot.c
system_stm32f1xx.c
persist/persist.c
)
target_link_options(ab_boot.elf PRIVATE ${COMMON_LINKER_FLAGS} ${AB_BOOT_FIRMWARE_LINKER_FLAGS})
target_link_libraries(ab_boot.elf stm32_hal)
target_compile_options(ab_boot.elf PRIVATE )
add_custom_command(OUTPUT ab_boot.hex COMMAND arm-none-eabi-objcopy -O ihex ab_boot.elf ab_boot.hex DEPENDS ab_boot.elf)
add_custom_command(OUTPUT ab_boot.bin COMMAND arm-none-eabi-objcopy -O binary -S ab_boot.elf ab_boot.bin DEPENDS ab_boot.elf)
add_custom_target(ab_boot ALL SOURCES ab_boot.hex ab_boot.bin)
add_custom_target(flash-boot COMMAND st-flash --reset write ab_boot.bin 0x08000000 SOURCES ab_boot.bin DEPENDS ab_boot.bin)
# util targets
add_custom_target(debug
COMMAND openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg)
add_custom_target(unlock0
COMMAND openocd -f interface/stlink-v2.cfg -f target/stm32f1x.cfg -c init -c "reset halt" -c "stm32f1x unlock 0")
add_custom_target(unlock1

View File

@ -8,6 +8,7 @@ sudo pacman -Sy --noconfirm \
arm-none-eabi-gdb \
arm-none-eabi-newlib \
cmake \
make \
openocd \
stlink
@ -15,7 +16,10 @@ git clone --recursive git@github.com:bobbycar-graz/bobbycar-controller-firmware.
cd bobbycar-controller-firmware/
cmake -DCMAKE_BUILD_TYPE=Release .
make unlock0 # needed only once per board
make flash
make flash-motortest
make flash-feedc0de-front
make flash-feedc0de-back
make flash-greyhash
```
## Hardware

51
ab_boot/ab_boot.c Normal file
View File

@ -0,0 +1,51 @@
#include <stdint.h>
#include <stdbool.h>
#include "stm32f1xx_hal.h"
#include "ab_boot.h"
#include "persist/persist.h"
static inline void __attribute__((noreturn)) boot_image(uint32_t sp, uint32_t entry) {
asm volatile(
" mov sp, %0 \n"
" blx %1 \n"
"1: b 1b \n"
:
: "r" (sp), "r" (entry)
);
__builtin_unreachable();
}
static bool is_valid_boot_address(uint32_t *bootp)
{
return (uint32_t)bootp >= FLASH_START &&
(uint32_t)bootp < FLASH_END &&
((uint32_t)bootp & 3) == 0;
}
int main()
{
struct ab_boot_config *flash_config = (struct ab_boot_config *)CONFIG_START;
struct ab_boot_config *config = NULL;
if (is_persist_valid() &&
is_valid_boot_address(persist.ab_boot_config.boot_partition))
{
// Invalidate persist
persist.checksum = 0;
config = &persist.ab_boot_config;
}
else if (is_valid_boot_address(flash_config->boot_partition))
{
config = flash_config;
}
uint32_t *bootp;
if (config)
bootp = config->boot_partition;
else
bootp = (uint32_t *)APP_A_START;
uint32_t sp = bootp[0];
uint32_t entry = bootp[1];
boot_image(sp, entry);
}

21
ab_boot/ab_boot.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include <stdint.h>
#define FLASH_START 0x08000000
#define AB_BOOT_SIZE 0x00002000
#define APP_A_START 0x08002000
#define APP_B_START 0x08020800
// 122 KiB
#define APP_SIZE 0x1e800
#define CONFIG_START 0x0803f800
#define CONFIG_SIZE 0x800
#define FLASH_END 0x08040000
struct ab_boot_config
{
uint32_t *boot_partition;
};

View File

@ -1,17 +1,11 @@
#pragma once
#ifdef PETERS_PLATINE
#ifdef PWM_FREQ_12KHZ
#define PWM_FREQ 12000 // PWM frequency in Hz
#else
#define PWM_FREQ 16000 // PWM frequency in Hz
#endif
#define DEAD_TIME 48 // PWM deadtime
//#ifdef MOTOR_TEST
// #define DELAY_IN_MAIN_LOOP 10
//#else
#define DELAY_IN_MAIN_LOOP 5
//#endif
#define TIMEOUT 5 // number of wrong / missing input commands before emergency off
#define A2BIT_CONV 50 // A to bit for current conversion on ADC. Example: 1 A = 50, 2 A = 100, etc
// ADC conversion time definitions
@ -50,13 +44,7 @@
#define BAT_CALIB_REAL_VOLTAGE 3970 // input voltage measured by multimeter (multiplied by 100). For example 43.00 V * 100 = 4300
#define BAT_CALIB_ADC 1492 // adc-value measured by mainboard (value nr 5 on UART debug output)
#define BAT_CELLS 10 // battery number of cells. Normal Hoverboard battery: 10s
#define BAT_LOW_LVL1_ENABLE 0 // to beep or not to beep, 1 or 0
#define BAT_LOW_LVL2_ENABLE 1 // to beep or not to beep, 1 or 0
#define BAT_LOW_LVL1 (360 * BAT_CELLS * BAT_CALIB_ADC) / BAT_CALIB_REAL_VOLTAGE // gently beeps at this voltage level. [V*100/cell]. In this case 3.60 V/cell
#define BAT_LOW_LVL2 (350 * BAT_CELLS * BAT_CALIB_ADC) / BAT_CALIB_REAL_VOLTAGE // your battery is almost empty. Charge now! [V*100/cell]. In this case 3.50 V/cell
#define BAT_LOW_DEAD (337 * BAT_CELLS * BAT_CALIB_ADC) / BAT_CALIB_REAL_VOLTAGE // undervoltage poweroff. (while not driving) [V*100/cell]. In this case 3.37 V/cell
#define BAT_CELLS 12 // battery number of cells. Normal Hoverboard battery: 10s
/* Board overheat detection: the sensor is inside the STM/GD chip.
* It is very inaccurate without calibration (up to 45°C). So only enable this funcion after calibration!
@ -70,13 +58,6 @@
#define TEMP_CAL_LOW_DEG_C 358 // temperature 1: measured temperature [°C * 10]. Here 35.8 °C
#define TEMP_CAL_HIGH_ADC 1588 // temperature 2: ADC value
#define TEMP_CAL_HIGH_DEG_C 489 // temperature 2: measured temperature [°C * 10]. Here 48.9 °C
#define TEMP_WARNING_ENABLE 0 // to beep or not to beep, 1 or 0, DO NOT ACTIVITE WITHOUT CALIBRATION!
#define TEMP_WARNING 600 // annoying fast beeps [°C * 10]. Here 60.0 °C
#define TEMP_POWEROFF_ENABLE 0 // to poweroff or not to poweroff, 1 or 0, DO NOT ACTIVITE WITHOUT CALIBRATION!
#define TEMP_POWEROFF 650 // overheat poweroff. (while not driving) [°C * 10]. Here 65.0 °C
#define INACTIVITY_TIMEOUT 8 // minutes of not driving until poweroff. it is not very precise.
// ############################### INPUT ###############################

5
config_partition.h Normal file
View File

@ -0,0 +1,5 @@
#include "ab_boot/ab_boot.h"
struct config_partition {
struct ab_boot_config ab_boot_config;
};

View File

@ -23,33 +23,90 @@
#include "stm32f1xx_hal.h"
#ifdef PETERS_PLATINE
#ifdef HALL_CAB
#define LEFT_HALL_U_PIN GPIO_PIN_11
#define LEFT_HALL_V_PIN GPIO_PIN_12
#define LEFT_HALL_W_PIN GPIO_PIN_10
#elif HALL_CBA
#define LEFT_HALL_U_PIN GPIO_PIN_11
#define LEFT_HALL_V_PIN GPIO_PIN_10
#define LEFT_HALL_W_PIN GPIO_PIN_12
#elif HALL_BAC
#define LEFT_HALL_U_PIN GPIO_PIN_10
#define LEFT_HALL_V_PIN GPIO_PIN_12
#define LEFT_HALL_W_PIN GPIO_PIN_11
#elif HALL_BCA
#define LEFT_HALL_U_PIN GPIO_PIN_10
#define LEFT_HALL_V_PIN GPIO_PIN_11
#define LEFT_HALL_W_PIN GPIO_PIN_12
#elif HALL_ABC
#define LEFT_HALL_U_PIN GPIO_PIN_12
#define LEFT_HALL_V_PIN GPIO_PIN_10
#define LEFT_HALL_W_PIN GPIO_PIN_11
#else //HALL_ACB
#define LEFT_HALL_U_PIN GPIO_PIN_12
#define LEFT_HALL_V_PIN GPIO_PIN_11
#define LEFT_HALL_W_PIN GPIO_PIN_10
#endif
#define LEFT_HALL_U_PORT GPIOC
#define LEFT_HALL_V_PORT GPIOC
#define LEFT_HALL_W_PORT GPIOC
#ifdef HALL_CAB
#define RIGHT_HALL_U_PIN GPIO_PIN_6
#define RIGHT_HALL_V_PIN GPIO_PIN_5
#define RIGHT_HALL_W_PIN GPIO_PIN_7
#elif HALL_CBA
#define RIGHT_HALL_U_PIN GPIO_PIN_6
#define RIGHT_HALL_V_PIN GPIO_PIN_7
#define RIGHT_HALL_W_PIN GPIO_PIN_5
#elif HALL_BAC
#define RIGHT_HALL_U_PIN GPIO_PIN_7
#define RIGHT_HALL_V_PIN GPIO_PIN_5
#define RIGHT_HALL_W_PIN GPIO_PIN_6
#elif HALL_BCA
#define RIGHT_HALL_U_PIN GPIO_PIN_7
#define RIGHT_HALL_V_PIN GPIO_PIN_6
#define RIGHT_HALL_W_PIN GPIO_PIN_5
#elif HALL_ABC
#define RIGHT_HALL_U_PIN GPIO_PIN_5
#define RIGHT_HALL_V_PIN GPIO_PIN_7
#define RIGHT_HALL_W_PIN GPIO_PIN_6
#else //HALL_ACB
#define RIGHT_HALL_U_PIN GPIO_PIN_5
#define RIGHT_HALL_V_PIN GPIO_PIN_6
#define RIGHT_HALL_W_PIN GPIO_PIN_7
#endif
#define RIGHT_HALL_U_PORT GPIOB
#define RIGHT_HALL_V_PORT GPIOB
#define RIGHT_HALL_W_PORT GPIOB
#else
#ifdef HALL_BCA
#define LEFT_HALL_U_PIN GPIO_PIN_7
#define LEFT_HALL_V_PIN GPIO_PIN_6
#define LEFT_HALL_W_PIN GPIO_PIN_5
#else
#define LEFT_HALL_U_PIN GPIO_PIN_5
#define LEFT_HALL_V_PIN GPIO_PIN_6
#define LEFT_HALL_W_PIN GPIO_PIN_7
#endif
#define LEFT_HALL_U_PORT GPIOB
#define LEFT_HALL_V_PORT GPIOB
#define LEFT_HALL_W_PORT GPIOB
#ifdef HALL_BCA
#define RIGHT_HALL_U_PIN GPIO_PIN_12
#define RIGHT_HALL_V_PIN GPIO_PIN_11
#define RIGHT_HALL_W_PIN GPIO_PIN_10
#else
#define RIGHT_HALL_U_PIN GPIO_PIN_10
#define RIGHT_HALL_V_PIN GPIO_PIN_11
#define RIGHT_HALL_W_PIN GPIO_PIN_12
#endif
#define RIGHT_HALL_U_PORT GPIOC
#define RIGHT_HALL_V_PORT GPIOC

96
flasher/CANFlasher.hpp Normal file
View File

@ -0,0 +1,96 @@
#include <cstddef>
#include <cstdint>
#include "Flasher.hpp"
namespace can_flasher {
namespace {
flasher::Result handle_start(uint8_t *data, size_t length) {
uintptr_t address;
if (length != sizeof(address))
return flasher::Result::InvalidParameter;
memcpy(&address, data, sizeof(address));
return flasher::start(address);
}
flasher::Result handle_write(uint8_t *data, size_t length) {
return flasher::write(data, length);
}
}
void handle(uint8_t *data, size_t length) {
using enum flasher::State;
if (length < 1) {
flasher::flasher_state_callback(flasher::get_state(), flasher::Result::InvalidParameter, 0);
return;
}
flasher::State target_state = (flasher::State)*data;
data += 1;
length -= 1;
flasher::Result result;
switch (target_state) {
case Idle:
flasher::init();
result = flasher::Result::Success;
break;
case Erasing:
result = handle_start(data, length);
break;
case Writing:
result = handle_write(data, length);
break;
default:
result = flasher::Result::InvalidParameter;
}
flasher::flasher_state_callback(flasher::get_state(), result, 0);
}
constexpr size_t FeedbackSize =
sizeof(flasher::State) + sizeof(flasher::Result) + sizeof(uint32_t);
static_assert(FeedbackSize <= 8);
struct {
uint32_t last_sent;
std::atomic<bool> updated;
bool valid;
uint8_t data[FeedbackSize];
} feedback;
void generate_feedback(flasher::State state, flasher::Result result, uint32_t arg) {
uint8_t *ptr = feedback.data;
std::memcpy(ptr, &state, sizeof(state));
ptr += sizeof(state);
std::memcpy(ptr, &result, sizeof(result));
ptr += sizeof(result);
std::memcpy(ptr, &arg, sizeof(arg));
// this works because poll_feedback can't interrupt us
feedback.updated.store(true);
}
bool poll_feedback(uint32_t now, uint8_t *out) {
if (feedback.updated.load() ||
(feedback.valid && now - feedback.last_sent >= 500)) {
feedback.valid = true;
do {
feedback.updated.store(false);
std::memcpy(out, feedback.data, sizeof(feedback.data));
// this works because we cannot interrupt generate_feedback
} while (feedback.updated.load());
feedback.last_sent = now;
return true;
}
return false;
}
}
namespace flasher {
void flasher_state_callback(flasher::State state, flasher::Result result, uint32_t arg) {
can_flasher::generate_feedback(state, result, arg);
}
}

203
flasher/Flasher.hpp Normal file
View File

@ -0,0 +1,203 @@
#pragma once
#include <cstdint>
#include <cstring>
#include "stm32f1xx_hal.h"
#include "ab_boot/ab_boot.h"
#include "stm32f1xx_hal_def.h"
#include "stm32f1xx_hal_flash.h"
#include "stm32f1xx_hal_flash_ex.h"
namespace flasher {
enum class State : uint8_t {
Idle,
Erasing,
Waiting,
Writing,
Error
};
namespace {
enum class FlashRegion {
Invalid,
Bootloader,
AppA,
AppB,
Config
};
FlashRegion region_for_address(uintptr_t address) {
using enum FlashRegion;
if (address >= FLASH_START && address < APP_A_START) {
return Bootloader;
} else if (address >= APP_A_START && address < (APP_A_START + APP_SIZE)) {
return AppA;
} else if (address >= APP_B_START && address < (APP_B_START + APP_SIZE)) {
return AppB;
} else if (address >= CONFIG_START && address < (CONFIG_START + CONFIG_SIZE)) {
return Config;
}
return Invalid;
}
size_t region_size(FlashRegion region) {
using enum FlashRegion;
switch (region) {
case Bootloader:
return AB_BOOT_SIZE;
case AppA:
case AppB:
return APP_SIZE;
case Config:
return CONFIG_SIZE;
default:
return 0;
}
}
bool is_valid_start_address(uint32_t address) {
return address == FLASH_START || address == APP_A_START ||
address == APP_B_START || address == CONFIG_START;
}
static State state_;
static FlashRegion region_;
static uintptr_t address_;
static uint8_t write_size_;
}
enum class Result : uint8_t {
Success,
RegionNotAllowed,
InvalidParameter,
InvalidState,
WriteError,
InProgress
};
void flasher_state_callback(State state, Result result, uint32_t arg);
void init() {
state_ = State::Idle;
region_ = FlashRegion::Invalid;
address_ = 0;
write_size_ = 0;
HAL_FLASH_Lock();
}
Result start(uintptr_t address) {
if (state_ != State::Idle)
return Result::InvalidState;
if (!is_valid_start_address(address)) {
return Result::InvalidParameter;
}
FlashRegion flashed_region = region_for_address(address);
FlashRegion running_region = region_for_address((uintptr_t)&start);
if (flashed_region == FlashRegion::Invalid) {
return Result::InvalidParameter;
}
if (flashed_region == running_region) {
// prohibit flashing the currently running app
return Result::RegionNotAllowed;
}
size_t size = region_size(flashed_region);
FLASH_EraseInitTypeDef ferase = {
.TypeErase = FLASH_TYPEERASE_PAGES,
.PageAddress = address,
.NbPages = size / FLASH_PAGE_SIZE
};
HAL_FLASH_Unlock();
if (HAL_FLASHEx_Erase_IT(&ferase) != HAL_OK) {
return Result::WriteError;
}
state_ = State::Erasing;
region_ = flashed_region;
address_ = address;
return Result::InProgress;
}
Result write(uint8_t *data, uint8_t length) {
if (state_ != State::Waiting)
return Result::InvalidState;
uint32_t program_type;
switch (length) {
case 2:
program_type = FLASH_PROC_PROGRAMHALFWORD;
break;
case 4:
program_type = FLASH_PROC_PROGRAMWORD;
break;
case 8:
program_type = FLASH_PROC_PROGRAMDOUBLEWORD;
break;
default:
return Result::InvalidParameter;
}
uint64_t data_int = 0;
memcpy(&data_int, data, length);
if (HAL_FLASH_Program_IT(program_type, address_, data_int) != HAL_OK)
return Result::WriteError;
state_ = State::Writing;
write_size_ = length;
return Result::InProgress;
}
State get_state() {
return state_;
}
void flash_callback(bool success) {
using enum State;
// Ignore if we are in Idle state, could be the result of
// a cancelled operation.
if (state_ == Idle)
return;
if (success) {
switch (state_) {
case Writing:
case Erasing:
address_ += write_size_;
flasher_state_callback(state_, Result::Success, address_);
state_ = Waiting;
write_size_ = 0;
break;
default:
// Spurious callback
HAL_FLASH_Lock();
state_ = Error;
}
} else {
switch (state_) {
case Writing:
case Erasing:
flasher_state_callback(state_, Result::WriteError, address_);
[[fallthrough]];
default:
// Spurious callback
HAL_FLASH_Lock();
state_ = Error;
}
}
}
}

View File

@ -32,8 +32,6 @@
/* Entry Point */
ENTRY(Reset_Handler)
/* Highest address of the user mode stack */
_estack = 0x2000C000; /* end of RAM */
/* Generate a link error if heap and stack don't fit into RAM */
_Min_Heap_Size = 0x200; /* required amount of heap */
_Min_Stack_Size = 0x400; /* required amount of stack */
@ -41,8 +39,10 @@ _Min_Stack_Size = 0x400; /* required amount of stack */
/* Specify the memory areas */
MEMORY
{
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 48K
FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 256K
RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 47K
PERSIST (rw) : ORIGIN = 0x2000BC00, LENGTH = 1K
FLASH (rx) : ORIGIN = _App_Base, LENGTH = _App_Length
CONFIG(r) : ORIGIN = 0x0803f800, LENGTH = 2K
}
/* Define output sections */
@ -114,7 +114,7 @@ SECTIONS
_sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */
.data :
.data :
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start */
@ -125,7 +125,7 @@ SECTIONS
_edata = .; /* define a global symbol at data end */
} >RAM AT> FLASH
/* Uninitialized data section */
. = ALIGN(4);
.bss :
@ -153,7 +153,16 @@ SECTIONS
. = ALIGN(8);
} >RAM
/* Highest address of the user mode stack */
_estack = ORIGIN(RAM) + LENGTH(RAM); /* end of RAM area */
.persist :
{
. = ALIGN(4);
persist = .;
. += LENGTH(PERSIST);
_epersist = .;
} > PERSIST
/* Remove information from the standard libraries */
/DISCARD/ :
@ -165,5 +174,3 @@ SECTIONS
.ARM.attributes 0 : { *(.ARM.attributes) }
}

2
ld/ab_boot.ld Normal file
View File

@ -0,0 +1,2 @@
_App_Base = 0x08000000;
_App_Length = 8K;

2
ld/app_a.ld Normal file
View File

@ -0,0 +1,2 @@
_App_Base = 0x08002000;
_App_Length = 122K;

2
ld/app_b.ld Normal file
View File

@ -0,0 +1,2 @@
_App_Base = 0x08020800;
_App_Length = 122K;

1642
main.cpp

File diff suppressed because it is too large Load Diff

10
persist/persist.c Normal file
View File

@ -0,0 +1,10 @@
#include <assert.h>
#include "persist.h"
#include "ab_boot/ab_boot.h"
// keep this in sync with the linker script
#define PERSIST_SIZE 1024
extern struct persist_data persist;
static_assert(sizeof(persist) < PERSIST_SIZE);

39
persist/persist.h Normal file
View File

@ -0,0 +1,39 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "ab_boot/ab_boot.h"
struct persist_data {
struct ab_boot_config ab_boot_config;
uint32_t checksum;
};
extern struct persist_data persist;
static inline uint32_t calculate_persist_checksum() {
uint32_t checksum = 0;
uint32_t *pd = (uint32_t *)&persist;
for (int i = 0; i < (sizeof(persist) - 4) / 4; i++) {
checksum += pd[i];
checksum = (checksum >> 3) | (checksum << 29);
}
checksum = ~checksum;
return checksum;
}
static inline void update_persist_checksum() {
persist.checksum = calculate_persist_checksum();
}
static inline bool is_persist_valid() {
return calculate_persist_checksum() == persist.checksum;
}
static inline void request_boot_image(uint32_t *bootp) {
persist.ab_boot_config.boot_partition = bootp;
update_persist_checksum();
}

View File

@ -36,7 +36,7 @@ extern "C" {
*/
#define HAL_MODULE_ENABLED
#define HAL_ADC_MODULE_ENABLED
/* #define HAL_CAN_MODULE_ENABLED */
#define HAL_CAN_MODULE_ENABLED
/* #define HAL_CAN_LEGACY_MODULE_ENABLED */
/* #define HAL_CEC_MODULE_ENABLED */
#define HAL_CORTEX_MODULE_ENABLED
@ -129,7 +129,7 @@ extern "C" {
#define PREFETCH_ENABLE 1U
#define USE_HAL_ADC_REGISTER_CALLBACKS 0U /* ADC register callback disabled */
#define USE_HAL_CAN_REGISTER_CALLBACKS 0U /* CAN register callback disabled */
#define USE_HAL_CAN_REGISTER_CALLBACKS 1 /* CAN register callback disabled */
#define USE_HAL_CEC_REGISTER_CALLBACKS 0U /* CEC register callback disabled */
#define USE_HAL_DAC_REGISTER_CALLBACKS 0U /* DAC register callback disabled */
#define USE_HAL_ETH_REGISTER_CALLBACKS 0U /* ETH register callback disabled */

View File

@ -110,10 +110,10 @@
/*!< Uncomment the following line if you need to relocate your vector Table in
Internal SRAM. */
/* #define VECT_TAB_SRAM */
#define VECT_TAB_OFFSET 0x00000000U /*!< Vector Table base offset field. \
extern unsigned int g_pfnVectors[];
#define VECT_TAB_OFFSET ((unsigned int)g_pfnVectors) /*!< Vector Table base offset field. \
This value must be a multiple of 0x200. */
/**
* @}
*/