From ab415aa5faa3865a78006148e90ea7972d8639d1 Mon Sep 17 00:00:00 2001 From: Vehicle Researcher Date: Wed, 15 Jan 2020 14:04:40 -0800 Subject: [PATCH] Remove old panda subtree --- panda/.circleci/config.yml | 118 - panda/.dockerignore | 3 - panda/.gitignore | 17 - panda/Dockerfile | 83 - panda/Jenkinsfile | 80 - panda/LICENSE | 7 - panda/README.md | 121 - panda/TODO | 31 - panda/UPDATING.md | 9 - panda/VERSION | 1 - panda/__init__.py | 1 - panda/board/Makefile | 8 - panda/board/README.md | 36 - panda/board/__init__.py | 0 panda/board/board.h | 94 - panda/board/board_declarations.h | 74 - panda/board/boards/black.h | 239 - panda/board/boards/common.h | 84 - panda/board/boards/grey.h | 30 - panda/board/boards/pedal.h | 117 - panda/board/boards/uno.h | 281 - panda/board/boards/white.h | 347 - panda/board/bootstub.c | 124 - panda/board/build.mk | 84 - panda/board/config.h | 45 - panda/board/critical.h | 23 - panda/board/drivers/adc.h | 38 - panda/board/drivers/can.h | 448 - panda/board/drivers/clock.h | 40 - panda/board/drivers/dac.h | 20 - panda/board/drivers/fan.h | 39 - panda/board/drivers/gmlan_alt.h | 288 - panda/board/drivers/harness.h | 105 - panda/board/drivers/interrupts.h | 164 - panda/board/drivers/llcan.h | 98 - panda/board/drivers/llgpio.h | 65 - panda/board/drivers/pwm.h | 56 - panda/board/drivers/registers.h | 81 - panda/board/drivers/rtc.h | 108 - panda/board/drivers/spi.h | 131 - panda/board/drivers/timer.h | 7 - panda/board/drivers/uart.h | 440 - panda/board/drivers/usb.h | 1016 -- panda/board/faults.h | 49 - panda/board/get_sdk.sh | 3 - panda/board/get_sdk_mac.sh | 5 - panda/board/gpio.h | 76 - panda/board/inc/cmsis_compiler.h | 284 - panda/board/inc/cmsis_gcc.h | 2169 --- panda/board/inc/cmsis_version.h | 40 - panda/board/inc/core_cm3.h | 1938 -- panda/board/inc/core_cm4.h | 2125 --- panda/board/inc/mpu_armv7.h | 273 - panda/board/inc/stm32f205xx.h | 7666 -------- panda/board/inc/stm32f2xx.h | 209 - panda/board/inc/stm32f2xx_hal_def.h | 181 - panda/board/inc/stm32f2xx_hal_gpio_ex.h | 299 - panda/board/inc/stm32f413xx.h | 14995 ---------------- panda/board/inc/stm32f4xx.h | 271 - panda/board/inc/stm32f4xx_hal_def.h | 214 - panda/board/inc/stm32f4xx_hal_gpio_ex.h | 1591 -- panda/board/inc/system_stm32f2xx.h | 122 - panda/board/inc/system_stm32f4xx.h | 124 - panda/board/libc.h | 42 - panda/board/main.c | 872 - panda/board/main_declarations.h | 15 - panda/board/obj/.placeholder | 0 panda/board/obj/panda.bin.signed | Bin 31564 -> 0 bytes panda/board/pedal/.gitignore | 1 - panda/board/pedal/Makefile | 67 - panda/board/pedal/README | 28 - panda/board/pedal/main.c | 352 - panda/board/pedal/main_declarations.h | 11 - panda/board/pedal/obj/.gitkeep | 0 panda/board/power_saving.h | 60 - panda/board/provision.h | 13 - panda/board/safety.h | 234 - panda/board/safety/safety_cadillac.h | 124 - panda/board/safety/safety_chrysler.h | 140 - panda/board/safety/safety_defaults.h | 65 - panda/board/safety/safety_elm327.h | 42 - panda/board/safety/safety_ford.h | 113 - panda/board/safety/safety_gm.h | 222 - panda/board/safety/safety_gm_ascm.h | 44 - panda/board/safety/safety_honda.h | 276 - panda/board/safety/safety_hyundai.h | 143 - panda/board/safety/safety_mazda.h | 149 - panda/board/safety/safety_subaru.h | 144 - panda/board/safety/safety_tesla.h | 213 - panda/board/safety/safety_toyota.h | 228 - panda/board/safety/safety_toyota_ipas.h | 168 - panda/board/safety/safety_volkswagen.h | 177 - panda/board/safety_declarations.h | 64 - panda/board/spi_flasher.h | 340 - panda/board/startup_stm32f205xx.s | 511 - panda/board/startup_stm32f413xx.s | 583 - panda/board/stm32_flash.ld | 165 - panda/board/tests/test_rsa.c | 35 - panda/board/tools/dfu-util-aarch64 | Bin 116048 -> 0 bytes panda/board/tools/dfu-util-aarch64-linux | Bin 159256 -> 0 bytes panda/board/tools/dfu-util-x86_64-linux | Bin 152156 -> 0 bytes panda/board/tools/enter_download_mode.py | 33 - panda/boardesp/.gitignore | 8 - panda/boardesp/ELM327.md | 101 - panda/boardesp/Makefile | 74 - panda/boardesp/README.md | 22 - panda/boardesp/elm327.c | 1578 -- panda/boardesp/get_sdk.sh | 12 - panda/boardesp/get_sdk_ci.sh | 6 - panda/boardesp/get_sdk_mac.sh | 32 - panda/boardesp/include/espmissingincludes.h | 78 - panda/boardesp/obj/.placeholder | 0 panda/boardesp/proxy.c | 373 - panda/boardesp/python2_make.py | 4 - panda/boardesp/user_config.h | 0 panda/boardesp/webserver.c | 380 - panda/buy.png | Bin 12200 -> 0 bytes panda/certs/debug | 15 - panda/certs/debug.pub | 1 - panda/certs/debugesp | 15 - panda/certs/debugesp.pub | 1 - panda/certs/release.pub | 1 - panda/certs/releaseesp.pub | 1 - panda/common/version.mk | 20 - panda/crypto/getcertheader.py | 45 - panda/crypto/hash-internal.h | 63 - panda/crypto/rsa.c | 294 - panda/crypto/rsa.h | 58 - panda/crypto/sha.c | 179 - panda/crypto/sha.h | 51 - panda/crypto/sign.py | 37 - panda/crypto/stdint.h | 4 - panda/docs/guide.pdf | Bin 2873505 -> 0 bytes panda/drivers/linux/.gitignore | 6 - panda/drivers/linux/Makefile | 18 - panda/drivers/linux/README.md | 19 - panda/drivers/linux/dkms.conf | 6 - panda/drivers/linux/panda.c | 616 - panda/drivers/linux/test/Makefile | 2 - panda/drivers/linux/test/main.c | 120 - panda/drivers/linux/test/run.sh | 4 - panda/drivers/windows/.gitignore | 306 - .../drivers/windows/ECUsim CLI/ECUsim CLI.cpp | 38 - .../windows/ECUsim CLI/ECUsim CLI.vcxproj | 178 - .../ECUsim CLI/ECUsim CLI.vcxproj.filters | 36 - panda/drivers/windows/ECUsim CLI/stdafx.cpp | 8 - panda/drivers/windows/ECUsim CLI/stdafx.h | 15 - panda/drivers/windows/ECUsim CLI/targetver.h | 8 - .../windows/ECUsim DLL/ECUsim DLL.vcxproj | 197 - .../ECUsim DLL/ECUsim DLL.vcxproj.filters | 42 - panda/drivers/windows/ECUsim DLL/ECUsim.cpp | 261 - panda/drivers/windows/ECUsim DLL/ECUsim.h | 50 - panda/drivers/windows/ECUsim DLL/dllmain.cpp | 19 - panda/drivers/windows/ECUsim DLL/stdafx.cpp | 8 - panda/drivers/windows/ECUsim DLL/stdafx.h | 16 - panda/drivers/windows/ECUsim DLL/targetver.h | 8 - panda/drivers/windows/README.md | 144 - panda/drivers/windows/docs/Message_Size.png | Bin 57389 -> 0 bytes panda/drivers/windows/docs/RxBits_defs.jpg | Bin 356832 -> 0 bytes panda/drivers/windows/docs/RxBits_valid.png | Bin 114419 -> 0 bytes .../drivers/windows/docs/bus_init_signla.png | Bin 109347 -> 0 bytes .../drivers/windows/docs/connection_flags.png | Bin 57588 -> 0 bytes .../drivers/windows/docs/iso15765_ioctls.png | Bin 45301 -> 0 bytes panda/drivers/windows/docs/message_send.png | Bin 95451 -> 0 bytes .../windows/docs/msg_filter_passfail.png | Bin 111538 -> 0 bytes panda/drivers/windows/docs/other notes.txt | 347 - panda/drivers/windows/docs/read_msg_flags.png | Bin 68261 -> 0 bytes panda/drivers/windows/docs/reginfo.txt | 2 - .../drivers/windows/docs/start_msg_filter.png | Bin 71232 -> 0 bytes .../windows/docs/start_msg_filter2.png | Bin 70796 -> 0 bytes .../windows/docs/start_msg_filter3.png | Bin 46516 -> 0 bytes .../windows/docs/start_msg_filter4.png | Bin 46333 -> 0 bytes panda/drivers/windows/docs/timeout_info.txt | 42 - .../panda Driver Package.vcxproj | 99 - .../panda Driver Package.vcxproj.filters | 14 - .../windows/panda Driver Package/panda.inf | Bin 4242 -> 0 bytes panda/drivers/windows/panda.ico | Bin 97642 -> 0 bytes panda/drivers/windows/panda.sln | 92 - panda/drivers/windows/panda/dllmain.cpp | 19 - panda/drivers/windows/panda/main.cpp | 79 - panda/drivers/windows/panda/panda.ico | Bin 97642 -> 0 bytes panda/drivers/windows/panda/panda.rc | Bin 5150 -> 0 bytes panda/drivers/windows/panda/panda.vcxproj | 189 - .../windows/panda/panda.vcxproj.filters | 43 - panda/drivers/windows/panda/resource.h | Bin 898 -> 0 bytes panda/drivers/windows/panda/stdafx.cpp | 8 - panda/drivers/windows/panda/stdafx.h | 19 - .../pandaJ2534DLL Test/ECUsim_tests.cpp | 87 - .../windows/pandaJ2534DLL Test/Loader4.cpp | 240 - .../windows/pandaJ2534DLL Test/Loader4.h | 55 - .../pandaJ2534DLL Test/TestHelpers.cpp | 254 - .../windows/pandaJ2534DLL Test/TestHelpers.h | 48 - .../windows/pandaJ2534DLL Test/Timer.cpp | 21 - .../windows/pandaJ2534DLL Test/Timer.h | 20 - .../pandaJ2534DLL Test/j2534_tests.cpp | 1602 -- .../pandaJ2534DLL Test.vcxproj | 122 - .../pandaJ2534DLL Test.vcxproj.filters | 63 - .../pandaJ2534DLL Test/panda_tests.cpp | 187 - .../windows/pandaJ2534DLL Test/stdafx.cpp | 8 - .../windows/pandaJ2534DLL Test/stdafx.h | 14 - .../windows/pandaJ2534DLL Test/targetver.h | 8 - panda/drivers/windows/pandaJ2534DLL/Action.h | 57 - .../windows/pandaJ2534DLL/J2534Connection.cpp | 283 - .../windows/pandaJ2534DLL/J2534Connection.h | 141 - .../pandaJ2534DLL/J2534Connection_CAN.cpp | 41 - .../pandaJ2534DLL/J2534Connection_CAN.h | 43 - .../J2534Connection_ISO15765.cpp | 232 - .../pandaJ2534DLL/J2534Connection_ISO15765.h | 65 - .../windows/pandaJ2534DLL/J2534Frame.h | 48 - .../pandaJ2534DLL/J2534MessageFilter.cpp | 104 - .../pandaJ2534DLL/J2534MessageFilter.h | 47 - .../windows/pandaJ2534DLL/J2534_v0404.h | 428 - .../pandaJ2534DLL/J2534register_x64.reg | Bin 1056 -> 0 bytes .../windows/pandaJ2534DLL/MessagePeriodic.cpp | 30 - .../windows/pandaJ2534DLL/MessagePeriodic.h | 33 - .../drivers/windows/pandaJ2534DLL/MessageRx.h | 61 - .../drivers/windows/pandaJ2534DLL/MessageTx.h | 25 - .../pandaJ2534DLL/MessageTxTimeout.cpp | 43 - .../windows/pandaJ2534DLL/MessageTxTimeout.h | 52 - .../windows/pandaJ2534DLL/MessageTx_CAN.cpp | 44 - .../windows/pandaJ2534DLL/MessageTx_CAN.h | 33 - .../pandaJ2534DLL/MessageTx_ISO15765.cpp | 180 - .../pandaJ2534DLL/MessageTx_ISO15765.h | 54 - .../pandaJ2534DLL/PandaJ2534Device.cpp | 238 - .../windows/pandaJ2534DLL/PandaJ2534Device.h | 83 - panda/drivers/windows/pandaJ2534DLL/Timer.cpp | 17 - panda/drivers/windows/pandaJ2534DLL/Timer.h | 18 - .../pandaJ2534DLL/constants_ISO15765.h | 20 - .../drivers/windows/pandaJ2534DLL/dllmain.cpp | 22 - panda/drivers/windows/pandaJ2534DLL/dllmain.h | 4 - .../windows/pandaJ2534DLL/pandaJ2534DLL.cpp | 430 - .../windows/pandaJ2534DLL/pandaJ2534DLL.rc | Bin 4630 -> 0 bytes .../pandaJ2534DLL/pandaJ2534DLL.vcxproj | 148 - .../pandaJ2534DLL.vcxproj.filters | 155 - .../drivers/windows/pandaJ2534DLL/resource.h | 14 - .../drivers/windows/pandaJ2534DLL/stdafx.cpp | 8 - panda/drivers/windows/pandaJ2534DLL/stdafx.h | 14 - .../windows/pandaJ2534DLL/synchronize.h | 56 - .../drivers/windows/pandaJ2534DLL/targetver.h | 13 - panda/drivers/windows/panda_install.nsi | 214 - .../windows/panda_playground/ReadMe.txt | 40 - .../panda_playground/panda_playground.cpp | 86 - .../panda_playground/panda_playground.vcxproj | 191 - .../panda_playground.vcxproj.filters | 45 - .../windows/panda_playground/stdafx.cpp | 8 - .../drivers/windows/panda_playground/stdafx.h | 17 - .../windows/panda_playground/targetver.h | 8 - panda/drivers/windows/panda_remove.ico | Bin 95950 -> 0 bytes panda/drivers/windows/panda_shared/device.cpp | 169 - panda/drivers/windows/panda_shared/device.h | 32 - panda/drivers/windows/panda_shared/panda.cpp | 522 - panda/drivers/windows/panda_shared/panda.h | 237 - .../panda_shared/panda_shared.vcxitems | 25 - .../drivers/windows/panda_shared/targetver.h | 13 - panda/drivers/windows/redist/.gitignore | 2 - panda/drivers/windows/redist/README.md | 7 - .../windows/redist/vscruntimeinfo.nsh.sample | 13 - .../windows/test certs/commaaiCertStore.pvk | Bin 1196 -> 0 bytes .../windows/test certs/commaaicert.cer | Bin 756 -> 0 bytes panda/examples/__init__.py | 0 panda/examples/can_bit_transition.md | 25 - panda/examples/can_bit_transition.py | 85 - panda/examples/can_logger.py | 53 - panda/examples/can_unique.md | 103 - panda/examples/can_unique.py | 91 - panda/examples/get_panda_password.py | 21 - panda/examples/query_fw_versions.py | 77 - panda/examples/query_vin_and_stats.py | 60 - panda/examples/tesla_tester.py | 61 - panda/panda.png | Bin 72509 -> 0 bytes panda/python/__init__.py | 655 - panda/python/dfu.py | 119 - panda/python/esptool.py | 1314 -- panda/python/flash_release.py | 95 - panda/python/isotp.py | 137 - panda/python/serial.py | 27 - panda/python/uds.py | 798 - panda/python/update.py | 45 - panda/release/.gitignore | 1 - panda/release/make_release.sh | 41 - panda/release/ota_release.sh | 18 - panda/requirements.txt | 11 - panda/run_automated_tests.sh | 21 - panda/setup.cfg | 2 - panda/setup.py | 65 - panda/tests/__init__.py | 0 panda/tests/all_wifi_test.py | 29 - panda/tests/automated/0_builds.py | 8 - panda/tests/automated/1_program.py | 34 - panda/tests/automated/2_health.py | 44 - panda/tests/automated/3_usb_to_can.py | 205 - panda/tests/automated/4_wifi.py | 60 - panda/tests/automated/5_wifi_functionality.py | 69 - panda/tests/automated/6_wifi_udp.py | 73 - panda/tests/automated/7_can_loopback.py | 202 - panda/tests/automated/__init__.py | 0 panda/tests/automated/helpers.py | 218 - panda/tests/automated/timeout.py | 25 - panda/tests/automated/wifi_helpers.py | 85 - panda/tests/black_loopback_test.py | 122 - panda/tests/black_white_loopback_test.py | 163 - panda/tests/black_white_relay_endurance.py | 169 - panda/tests/black_white_relay_test.py | 142 - panda/tests/build/Dockerfile | 31 - panda/tests/can_printer.py | 39 - panda/tests/debug_console.py | 49 - .../development/register_hashmap_spread.py | 50 - panda/tests/disable_esp.py | 4 - panda/tests/echo.py | 35 - panda/tests/elm_car_simulator.py | 325 - panda/tests/elm_throughput.py | 46 - panda/tests/elm_wifi.py | 667 - panda/tests/fan_test.py | 17 - panda/tests/flashing_loop.sh | 9 - panda/tests/get_version.py | 9 - panda/tests/gmbitbang/recv.py | 16 - panda/tests/gmbitbang/rigol.py | 36 - panda/tests/gmbitbang/test.py | 33 - panda/tests/gmbitbang/test_one.py | 23 - panda/tests/gmbitbang/test_packer.c | 32 - panda/tests/gps_stability_test.py | 165 - panda/tests/health_test.py | 19 - panda/tests/ir_test.py | 17 - panda/tests/language/Dockerfile | 17 - panda/tests/language/LICENSE | 201 - panda/tests/language/list.txt | 451 - panda/tests/language/test_language.py | 28 - panda/tests/linter_python/.pylintrc | 585 - panda/tests/linter_python/Dockerfile | 19 - panda/tests/linter_python/flake8_panda.sh | 8 - panda/tests/linter_python/pylint_panda.sh | 11 - panda/tests/location_listener.py | 47 - panda/tests/loopback_test.py | 127 - panda/tests/misra/.gitignore | 1 - panda/tests/misra/Dockerfile | 19 - panda/tests/misra/coverage_table | 143 - panda/tests/misra/suppressions.txt | 8 - panda/tests/misra/test_misra.sh | 55 - panda/tests/pedal/enter_canloader.py | 75 - panda/tests/read_st_flash.sh | 6 - panda/tests/read_winusb_descriptors.py | 29 - panda/tests/rtc_test.py | 13 - panda/tests/safety/Dockerfile | 20 - panda/tests/safety/Makefile | 18 - panda/tests/safety/__init__.py | 0 panda/tests/safety/common.py | 36 - panda/tests/safety/libpandasafety_py.py | 105 - panda/tests/safety/test.c | 364 - panda/tests/safety/test.sh | 18 - panda/tests/safety/test_cadillac.py | 184 - panda/tests/safety/test_chrysler.py | 186 - panda/tests/safety/test_gm.py | 288 - panda/tests/safety/test_honda.py | 277 - panda/tests/safety/test_honda_bosch.py | 49 - panda/tests/safety/test_hyundai.py | 202 - panda/tests/safety/test_subaru.py | 186 - panda/tests/safety/test_toyota.py | 301 - panda/tests/safety/test_toyota_ipas.py | 240 - panda/tests/safety/test_volkswagen.py | 232 - panda/tests/safety_replay/Dockerfile | 34 - panda/tests/safety_replay/__init__.py | 0 panda/tests/safety_replay/helpers.py | 90 - panda/tests/safety_replay/install_capnp.sh | 10 - panda/tests/safety_replay/replay_drive.py | 65 - .../safety_replay/requirements_extra.txt | 4 - .../tests/safety_replay/test_safety_replay.py | 41 - panda/tests/spam_can.py | 23 - panda/tests/standalone_test.py | 38 - panda/tests/throughput_test.py | 64 - panda/tests/tucan_loopback.py | 125 - 370 files changed, 69920 deletions(-) delete mode 100644 panda/.circleci/config.yml delete mode 100644 panda/.dockerignore delete mode 100644 panda/.gitignore delete mode 100644 panda/Dockerfile delete mode 100644 panda/Jenkinsfile delete mode 100644 panda/LICENSE delete mode 100644 panda/README.md delete mode 100644 panda/TODO delete mode 100644 panda/UPDATING.md delete mode 100644 panda/VERSION delete mode 100644 panda/__init__.py delete mode 100644 panda/board/Makefile delete mode 100644 panda/board/README.md delete mode 100644 panda/board/__init__.py delete mode 100644 panda/board/board.h delete mode 100644 panda/board/board_declarations.h delete mode 100644 panda/board/boards/black.h delete mode 100644 panda/board/boards/common.h delete mode 100644 panda/board/boards/grey.h delete mode 100644 panda/board/boards/pedal.h delete mode 100644 panda/board/boards/uno.h delete mode 100644 panda/board/boards/white.h delete mode 100644 panda/board/bootstub.c delete mode 100644 panda/board/build.mk delete mode 100644 panda/board/config.h delete mode 100644 panda/board/critical.h delete mode 100644 panda/board/drivers/adc.h delete mode 100644 panda/board/drivers/can.h delete mode 100644 panda/board/drivers/clock.h delete mode 100644 panda/board/drivers/dac.h delete mode 100644 panda/board/drivers/fan.h delete mode 100644 panda/board/drivers/gmlan_alt.h delete mode 100644 panda/board/drivers/harness.h delete mode 100644 panda/board/drivers/interrupts.h delete mode 100644 panda/board/drivers/llcan.h delete mode 100644 panda/board/drivers/llgpio.h delete mode 100644 panda/board/drivers/pwm.h delete mode 100644 panda/board/drivers/registers.h delete mode 100644 panda/board/drivers/rtc.h delete mode 100644 panda/board/drivers/spi.h delete mode 100644 panda/board/drivers/timer.h delete mode 100644 panda/board/drivers/uart.h delete mode 100644 panda/board/drivers/usb.h delete mode 100644 panda/board/faults.h delete mode 100755 panda/board/get_sdk.sh delete mode 100755 panda/board/get_sdk_mac.sh delete mode 100644 panda/board/gpio.h delete mode 100644 panda/board/inc/cmsis_compiler.h delete mode 100644 panda/board/inc/cmsis_gcc.h delete mode 100644 panda/board/inc/cmsis_version.h delete mode 100644 panda/board/inc/core_cm3.h delete mode 100644 panda/board/inc/core_cm4.h delete mode 100644 panda/board/inc/mpu_armv7.h delete mode 100644 panda/board/inc/stm32f205xx.h delete mode 100644 panda/board/inc/stm32f2xx.h delete mode 100644 panda/board/inc/stm32f2xx_hal_def.h delete mode 100644 panda/board/inc/stm32f2xx_hal_gpio_ex.h delete mode 100644 panda/board/inc/stm32f413xx.h delete mode 100644 panda/board/inc/stm32f4xx.h delete mode 100644 panda/board/inc/stm32f4xx_hal_def.h delete mode 100644 panda/board/inc/stm32f4xx_hal_gpio_ex.h delete mode 100644 panda/board/inc/system_stm32f2xx.h delete mode 100644 panda/board/inc/system_stm32f4xx.h delete mode 100644 panda/board/libc.h delete mode 100644 panda/board/main.c delete mode 100644 panda/board/main_declarations.h delete mode 100644 panda/board/obj/.placeholder delete mode 100644 panda/board/obj/panda.bin.signed delete mode 100644 panda/board/pedal/.gitignore delete mode 100644 panda/board/pedal/Makefile delete mode 100644 panda/board/pedal/README delete mode 100644 panda/board/pedal/main.c delete mode 100644 panda/board/pedal/main_declarations.h delete mode 100644 panda/board/pedal/obj/.gitkeep delete mode 100644 panda/board/power_saving.h delete mode 100644 panda/board/provision.h delete mode 100644 panda/board/safety.h delete mode 100644 panda/board/safety/safety_cadillac.h delete mode 100644 panda/board/safety/safety_chrysler.h delete mode 100644 panda/board/safety/safety_defaults.h delete mode 100644 panda/board/safety/safety_elm327.h delete mode 100644 panda/board/safety/safety_ford.h delete mode 100644 panda/board/safety/safety_gm.h delete mode 100644 panda/board/safety/safety_gm_ascm.h delete mode 100644 panda/board/safety/safety_honda.h delete mode 100644 panda/board/safety/safety_hyundai.h delete mode 100644 panda/board/safety/safety_mazda.h delete mode 100644 panda/board/safety/safety_subaru.h delete mode 100644 panda/board/safety/safety_tesla.h delete mode 100644 panda/board/safety/safety_toyota.h delete mode 100644 panda/board/safety/safety_toyota_ipas.h delete mode 100644 panda/board/safety/safety_volkswagen.h delete mode 100644 panda/board/safety_declarations.h delete mode 100644 panda/board/spi_flasher.h delete mode 100644 panda/board/startup_stm32f205xx.s delete mode 100644 panda/board/startup_stm32f413xx.s delete mode 100644 panda/board/stm32_flash.ld delete mode 100644 panda/board/tests/test_rsa.c delete mode 100755 panda/board/tools/dfu-util-aarch64 delete mode 100755 panda/board/tools/dfu-util-aarch64-linux delete mode 100755 panda/board/tools/dfu-util-x86_64-linux delete mode 100755 panda/board/tools/enter_download_mode.py delete mode 100644 panda/boardesp/.gitignore delete mode 100644 panda/boardesp/ELM327.md delete mode 100644 panda/boardesp/Makefile delete mode 100644 panda/boardesp/README.md delete mode 100644 panda/boardesp/elm327.c delete mode 100755 panda/boardesp/get_sdk.sh delete mode 100755 panda/boardesp/get_sdk_ci.sh delete mode 100755 panda/boardesp/get_sdk_mac.sh delete mode 100644 panda/boardesp/include/espmissingincludes.h delete mode 100644 panda/boardesp/obj/.placeholder delete mode 100644 panda/boardesp/proxy.c delete mode 100644 panda/boardesp/python2_make.py delete mode 100644 panda/boardesp/user_config.h delete mode 100644 panda/boardesp/webserver.c delete mode 100644 panda/buy.png delete mode 100644 panda/certs/debug delete mode 100644 panda/certs/debug.pub delete mode 100644 panda/certs/debugesp delete mode 100644 panda/certs/debugesp.pub delete mode 100644 panda/certs/release.pub delete mode 100644 panda/certs/releaseesp.pub delete mode 100644 panda/common/version.mk delete mode 100755 panda/crypto/getcertheader.py delete mode 100644 panda/crypto/hash-internal.h delete mode 100644 panda/crypto/rsa.c delete mode 100644 panda/crypto/rsa.h delete mode 100644 panda/crypto/sha.c delete mode 100644 panda/crypto/sha.h delete mode 100755 panda/crypto/sign.py delete mode 100644 panda/crypto/stdint.h delete mode 100644 panda/docs/guide.pdf delete mode 100644 panda/drivers/linux/.gitignore delete mode 100644 panda/drivers/linux/Makefile delete mode 100644 panda/drivers/linux/README.md delete mode 100644 panda/drivers/linux/dkms.conf delete mode 100644 panda/drivers/linux/panda.c delete mode 100644 panda/drivers/linux/test/Makefile delete mode 100644 panda/drivers/linux/test/main.c delete mode 100755 panda/drivers/linux/test/run.sh delete mode 100644 panda/drivers/windows/.gitignore delete mode 100644 panda/drivers/windows/ECUsim CLI/ECUsim CLI.cpp delete mode 100644 panda/drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj delete mode 100644 panda/drivers/windows/ECUsim CLI/ECUsim CLI.vcxproj.filters delete mode 100644 panda/drivers/windows/ECUsim CLI/stdafx.cpp delete mode 100644 panda/drivers/windows/ECUsim CLI/stdafx.h delete mode 100644 panda/drivers/windows/ECUsim CLI/targetver.h delete mode 100644 panda/drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj delete mode 100644 panda/drivers/windows/ECUsim DLL/ECUsim DLL.vcxproj.filters delete mode 100644 panda/drivers/windows/ECUsim DLL/ECUsim.cpp delete mode 100644 panda/drivers/windows/ECUsim DLL/ECUsim.h delete mode 100644 panda/drivers/windows/ECUsim DLL/dllmain.cpp delete mode 100644 panda/drivers/windows/ECUsim DLL/stdafx.cpp delete mode 100644 panda/drivers/windows/ECUsim DLL/stdafx.h delete mode 100644 panda/drivers/windows/ECUsim DLL/targetver.h delete mode 100644 panda/drivers/windows/README.md delete mode 100644 panda/drivers/windows/docs/Message_Size.png delete mode 100644 panda/drivers/windows/docs/RxBits_defs.jpg delete mode 100644 panda/drivers/windows/docs/RxBits_valid.png delete mode 100644 panda/drivers/windows/docs/bus_init_signla.png delete mode 100644 panda/drivers/windows/docs/connection_flags.png delete mode 100644 panda/drivers/windows/docs/iso15765_ioctls.png delete mode 100644 panda/drivers/windows/docs/message_send.png delete mode 100644 panda/drivers/windows/docs/msg_filter_passfail.png delete mode 100644 panda/drivers/windows/docs/other notes.txt delete mode 100644 panda/drivers/windows/docs/read_msg_flags.png delete mode 100644 panda/drivers/windows/docs/reginfo.txt delete mode 100644 panda/drivers/windows/docs/start_msg_filter.png delete mode 100644 panda/drivers/windows/docs/start_msg_filter2.png delete mode 100644 panda/drivers/windows/docs/start_msg_filter3.png delete mode 100644 panda/drivers/windows/docs/start_msg_filter4.png delete mode 100644 panda/drivers/windows/docs/timeout_info.txt delete mode 100644 panda/drivers/windows/panda Driver Package/panda Driver Package.vcxproj delete mode 100644 panda/drivers/windows/panda Driver Package/panda Driver Package.vcxproj.filters delete mode 100644 panda/drivers/windows/panda Driver Package/panda.inf delete mode 100644 panda/drivers/windows/panda.ico delete mode 100644 panda/drivers/windows/panda.sln delete mode 100644 panda/drivers/windows/panda/dllmain.cpp delete mode 100644 panda/drivers/windows/panda/main.cpp delete mode 100644 panda/drivers/windows/panda/panda.ico delete mode 100644 panda/drivers/windows/panda/panda.rc delete mode 100644 panda/drivers/windows/panda/panda.vcxproj delete mode 100644 panda/drivers/windows/panda/panda.vcxproj.filters delete mode 100644 panda/drivers/windows/panda/resource.h delete mode 100644 panda/drivers/windows/panda/stdafx.cpp delete mode 100644 panda/drivers/windows/panda/stdafx.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/ECUsim_tests.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/Loader4.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/Loader4.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/TestHelpers.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/TestHelpers.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/Timer.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/Timer.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/j2534_tests.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/pandaJ2534DLL Test.vcxproj.filters delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/panda_tests.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/stdafx.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/stdafx.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL Test/targetver.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/Action.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Connection.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Connection.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Connection_CAN.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Connection_CAN.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Connection_ISO15765.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Connection_ISO15765.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534Frame.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534MessageFilter.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534MessageFilter.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534_v0404.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/J2534register_x64.reg delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessagePeriodic.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessagePeriodic.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageRx.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTx.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTxTimeout.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTxTimeout.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTx_CAN.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTx_CAN.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTx_ISO15765.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/MessageTx_ISO15765.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/PandaJ2534Device.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/PandaJ2534Device.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/Timer.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/Timer.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/constants_ISO15765.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/dllmain.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/dllmain.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.rc delete mode 100644 panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.vcxproj delete mode 100644 panda/drivers/windows/pandaJ2534DLL/pandaJ2534DLL.vcxproj.filters delete mode 100644 panda/drivers/windows/pandaJ2534DLL/resource.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/stdafx.cpp delete mode 100644 panda/drivers/windows/pandaJ2534DLL/stdafx.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/synchronize.h delete mode 100644 panda/drivers/windows/pandaJ2534DLL/targetver.h delete mode 100644 panda/drivers/windows/panda_install.nsi delete mode 100644 panda/drivers/windows/panda_playground/ReadMe.txt delete mode 100644 panda/drivers/windows/panda_playground/panda_playground.cpp delete mode 100644 panda/drivers/windows/panda_playground/panda_playground.vcxproj delete mode 100644 panda/drivers/windows/panda_playground/panda_playground.vcxproj.filters delete mode 100644 panda/drivers/windows/panda_playground/stdafx.cpp delete mode 100644 panda/drivers/windows/panda_playground/stdafx.h delete mode 100644 panda/drivers/windows/panda_playground/targetver.h delete mode 100644 panda/drivers/windows/panda_remove.ico delete mode 100644 panda/drivers/windows/panda_shared/device.cpp delete mode 100644 panda/drivers/windows/panda_shared/device.h delete mode 100644 panda/drivers/windows/panda_shared/panda.cpp delete mode 100644 panda/drivers/windows/panda_shared/panda.h delete mode 100644 panda/drivers/windows/panda_shared/panda_shared.vcxitems delete mode 100644 panda/drivers/windows/panda_shared/targetver.h delete mode 100644 panda/drivers/windows/redist/.gitignore delete mode 100644 panda/drivers/windows/redist/README.md delete mode 100644 panda/drivers/windows/redist/vscruntimeinfo.nsh.sample delete mode 100644 panda/drivers/windows/test certs/commaaiCertStore.pvk delete mode 100644 panda/drivers/windows/test certs/commaaicert.cer delete mode 100644 panda/examples/__init__.py delete mode 100644 panda/examples/can_bit_transition.md delete mode 100755 panda/examples/can_bit_transition.py delete mode 100755 panda/examples/can_logger.py delete mode 100644 panda/examples/can_unique.md delete mode 100755 panda/examples/can_unique.py delete mode 100644 panda/examples/get_panda_password.py delete mode 100755 panda/examples/query_fw_versions.py delete mode 100755 panda/examples/query_vin_and_stats.py delete mode 100644 panda/examples/tesla_tester.py delete mode 100644 panda/panda.png delete mode 100644 panda/python/__init__.py delete mode 100644 panda/python/dfu.py delete mode 100755 panda/python/esptool.py delete mode 100755 panda/python/flash_release.py delete mode 100644 panda/python/isotp.py delete mode 100644 panda/python/serial.py delete mode 100644 panda/python/uds.py delete mode 100755 panda/python/update.py delete mode 100644 panda/release/.gitignore delete mode 100755 panda/release/make_release.sh delete mode 100755 panda/release/ota_release.sh delete mode 100644 panda/requirements.txt delete mode 100755 panda/run_automated_tests.sh delete mode 100644 panda/setup.cfg delete mode 100644 panda/setup.py delete mode 100644 panda/tests/__init__.py delete mode 100755 panda/tests/all_wifi_test.py delete mode 100644 panda/tests/automated/0_builds.py delete mode 100644 panda/tests/automated/1_program.py delete mode 100644 panda/tests/automated/2_health.py delete mode 100644 panda/tests/automated/3_usb_to_can.py delete mode 100644 panda/tests/automated/4_wifi.py delete mode 100644 panda/tests/automated/5_wifi_functionality.py delete mode 100644 panda/tests/automated/6_wifi_udp.py delete mode 100644 panda/tests/automated/7_can_loopback.py delete mode 100644 panda/tests/automated/__init__.py delete mode 100644 panda/tests/automated/helpers.py delete mode 100644 panda/tests/automated/timeout.py delete mode 100644 panda/tests/automated/wifi_helpers.py delete mode 100755 panda/tests/black_loopback_test.py delete mode 100755 panda/tests/black_white_loopback_test.py delete mode 100755 panda/tests/black_white_relay_endurance.py delete mode 100755 panda/tests/black_white_relay_test.py delete mode 100644 panda/tests/build/Dockerfile delete mode 100755 panda/tests/can_printer.py delete mode 100755 panda/tests/debug_console.py delete mode 100755 panda/tests/development/register_hashmap_spread.py delete mode 100755 panda/tests/disable_esp.py delete mode 100755 panda/tests/echo.py delete mode 100755 panda/tests/elm_car_simulator.py delete mode 100755 panda/tests/elm_throughput.py delete mode 100644 panda/tests/elm_wifi.py delete mode 100755 panda/tests/fan_test.py delete mode 100755 panda/tests/flashing_loop.sh delete mode 100755 panda/tests/get_version.py delete mode 100755 panda/tests/gmbitbang/recv.py delete mode 100755 panda/tests/gmbitbang/rigol.py delete mode 100755 panda/tests/gmbitbang/test.py delete mode 100755 panda/tests/gmbitbang/test_one.py delete mode 100644 panda/tests/gmbitbang/test_packer.c delete mode 100755 panda/tests/gps_stability_test.py delete mode 100755 panda/tests/health_test.py delete mode 100755 panda/tests/ir_test.py delete mode 100644 panda/tests/language/Dockerfile delete mode 100644 panda/tests/language/LICENSE delete mode 100644 panda/tests/language/list.txt delete mode 100755 panda/tests/language/test_language.py delete mode 100644 panda/tests/linter_python/.pylintrc delete mode 100644 panda/tests/linter_python/Dockerfile delete mode 100755 panda/tests/linter_python/flake8_panda.sh delete mode 100755 panda/tests/linter_python/pylint_panda.sh delete mode 100755 panda/tests/location_listener.py delete mode 100755 panda/tests/loopback_test.py delete mode 100644 panda/tests/misra/.gitignore delete mode 100644 panda/tests/misra/Dockerfile delete mode 100644 panda/tests/misra/coverage_table delete mode 100644 panda/tests/misra/suppressions.txt delete mode 100755 panda/tests/misra/test_misra.sh delete mode 100755 panda/tests/pedal/enter_canloader.py delete mode 100755 panda/tests/read_st_flash.sh delete mode 100644 panda/tests/read_winusb_descriptors.py delete mode 100755 panda/tests/rtc_test.py delete mode 100644 panda/tests/safety/Dockerfile delete mode 100644 panda/tests/safety/Makefile delete mode 100644 panda/tests/safety/__init__.py delete mode 100644 panda/tests/safety/common.py delete mode 100644 panda/tests/safety/libpandasafety_py.py delete mode 100644 panda/tests/safety/test.c delete mode 100755 panda/tests/safety/test.sh delete mode 100644 panda/tests/safety/test_cadillac.py delete mode 100755 panda/tests/safety/test_chrysler.py delete mode 100644 panda/tests/safety/test_gm.py delete mode 100755 panda/tests/safety/test_honda.py delete mode 100755 panda/tests/safety/test_honda_bosch.py delete mode 100644 panda/tests/safety/test_hyundai.py delete mode 100644 panda/tests/safety/test_subaru.py delete mode 100644 panda/tests/safety/test_toyota.py delete mode 100644 panda/tests/safety/test_toyota_ipas.py delete mode 100644 panda/tests/safety/test_volkswagen.py delete mode 100644 panda/tests/safety_replay/Dockerfile delete mode 100644 panda/tests/safety_replay/__init__.py delete mode 100644 panda/tests/safety_replay/helpers.py delete mode 100755 panda/tests/safety_replay/install_capnp.sh delete mode 100755 panda/tests/safety_replay/replay_drive.py delete mode 100644 panda/tests/safety_replay/requirements_extra.txt delete mode 100755 panda/tests/safety_replay/test_safety_replay.py delete mode 100755 panda/tests/spam_can.py delete mode 100755 panda/tests/standalone_test.py delete mode 100755 panda/tests/throughput_test.py delete mode 100755 panda/tests/tucan_loopback.py diff --git a/panda/.circleci/config.yml b/panda/.circleci/config.yml deleted file mode 100644 index a4ae26efe5..0000000000 --- a/panda/.circleci/config.yml +++ /dev/null @@ -1,118 +0,0 @@ -version: 2 -jobs: - safety: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_safety -f tests/safety/Dockerfile ." - - run: - name: Run safety test - command: | - docker run panda_safety /bin/bash -c "cd /panda/tests/safety; PYTHONPATH=/ ./test.sh" - - misra-c2012: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_misra -f tests/misra/Dockerfile ." - - run: - name: Run Misra C 2012 test - command: | - mkdir /tmp/misra - docker run -v /tmp/misra:/tmp/misra panda_misra /bin/bash -c "cd /panda/tests/misra; ./test_misra.sh" - - store_artifacts: - name: Store cppcheck test output - path: /tmp/misra/cppcheck_output.txt - - store_artifacts: - name: Store misra test output - path: /tmp/misra/misra_output.txt - - build: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_build -f tests/build/Dockerfile ." - - run: - name: Test python package installer - command: | - docker run panda_build /bin/bash -c "cd /panda; python setup.py install" - - run: - name: Build Panda STM image - command: | - docker run panda_build /bin/bash -c "cd /panda/board; make bin" - - run: - name: Build Panda STM bootstub image - command: | - docker run panda_build /bin/bash -c "cd /panda/board; make obj/bootstub.panda.bin" - - run: - name: Build Pedal STM image - command: | - docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/comma.bin" - - run: - name: Build Pedal STM bootstub image - command: | - docker run panda_build /bin/bash -c "cd /panda/board/pedal; make obj/bootstub.bin" - - run: - name: Build ESP image - command: | - docker run panda_build /bin/bash -c "cd /panda/boardesp; ./get_sdk.sh; make user1.bin" - - safety_replay: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t panda_safety_replay -f tests/safety_replay/Dockerfile ." - - run: - name: Replay drives - command: | - docker run panda_safety_replay /bin/bash -c "cd /openpilot/panda/tests/safety_replay; PYTHONPATH=/openpilot ./test_safety_replay.py" - - language_check: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t language_check -f tests/language/Dockerfile ." - - run: - name: Check code for bad language - command: | - docker run language_check /bin/bash -c "cd /panda/tests/language; ./test_language.py" - - linter_python: - machine: - docker_layer_caching: true - steps: - - checkout - - run: - name: Build image - command: "docker build -t linter_python -f tests/linter_python/Dockerfile ." - - run: - name: Run linter python test - command: | - docker run linter_python /bin/bash -c "cd /panda/tests/linter_python; PYTHONPATH=/ ./flake8_panda.sh" - docker run linter_python /bin/bash -c "cd /panda/tests/linter_python; PYTHONPATH=/ ./pylint_panda.sh" - -workflows: - version: 2 - main: - jobs: - - safety - - misra-c2012 - - build - - safety_replay - - language_check - - linter_python diff --git a/panda/.dockerignore b/panda/.dockerignore deleted file mode 100644 index f04ae5c0aa..0000000000 --- a/panda/.dockerignore +++ /dev/null @@ -1,3 +0,0 @@ -.git -.DS_Store -boardesp/esp-open-sdk diff --git a/panda/.gitignore b/panda/.gitignore deleted file mode 100644 index 397996a0bc..0000000000 --- a/panda/.gitignore +++ /dev/null @@ -1,17 +0,0 @@ -*.pyc -.*.swp -.*.swo -*.o -*.so -*.d -*.dump -a.out -*~ -.#* -dist/ -pandacan.egg-info/ -board/obj/ -examples/output.csv -.DS_Store -.vscode -nosetests.xml diff --git a/panda/Dockerfile b/panda/Dockerfile deleted file mode 100644 index fa020ad059..0000000000 --- a/panda/Dockerfile +++ /dev/null @@ -1,83 +0,0 @@ -FROM ubuntu:16.04 -ENV PYTHONUNBUFFERED 1 - -RUN apt-get update && apt-get install -y \ - autoconf \ - automake \ - bash \ - bison \ - bzip2 \ - curl \ - dfu-util \ - flex \ - g++ \ - gawk \ - gcc \ - git \ - gperf \ - help2man \ - iputils-ping \ - libbz2-dev \ - libexpat-dev \ - libffi-dev \ - libssl-dev \ - libstdc++-arm-none-eabi-newlib \ - libtool \ - libtool-bin \ - libusb-1.0-0 \ - locales \ - make \ - ncurses-dev \ - network-manager \ - python-dev \ - python-serial \ - sed \ - texinfo \ - unrar-free \ - unzip \ - wget \ - build-essential \ - python-dev \ - python-pip \ - screen \ - vim \ - wget \ - wireless-tools \ - zlib1g-dev - -RUN sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && locale-gen -ENV LANG en_US.UTF-8 -ENV LANGUAGE en_US:en -ENV LC_ALL en_US.UTF-8 - -RUN curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash - -ENV PATH="/root/.pyenv/bin:/root/.pyenv/shims:${PATH}" -RUN pyenv install 3.7.3 -RUN pyenv install 2.7.12 -RUN pyenv global 3.7.3 -RUN pyenv rehash - -RUN pip install --upgrade pip==18.0 - -COPY requirements.txt /tmp/ -RUN pip install -r /tmp/requirements.txt - -RUN mkdir -p /home/batman -ENV HOME /home/batman - -ENV PYTHONPATH /tmp:$PYTHONPATH - -COPY ./boardesp/get_sdk_ci.sh /tmp/panda/boardesp/ -COPY ./boardesp/python2_make.py /tmp/panda/boardesp/ - -COPY ./panda_jungle /tmp/panda_jungle - -RUN useradd --system -s /sbin/nologin pandauser -RUN mkdir -p /tmp/panda/boardesp/esp-open-sdk -RUN chown pandauser /tmp/panda/boardesp/esp-open-sdk -USER pandauser -RUN cd /tmp/panda/boardesp && ./get_sdk_ci.sh -USER root - -ADD ./panda.tar.gz /tmp/panda diff --git a/panda/Jenkinsfile b/panda/Jenkinsfile deleted file mode 100644 index 61068a4865..0000000000 --- a/panda/Jenkinsfile +++ /dev/null @@ -1,80 +0,0 @@ -pipeline { - agent any - environment { - AUTHOR = """${sh( - returnStdout: true, - script: "git --no-pager show -s --format='%an' ${GIT_COMMIT}" - ).trim()}""" - - DOCKER_IMAGE_TAG = "panda:build-${env.GIT_COMMIT}" - DOCKER_NAME = "panda-test-${env.GIT_COMMIT}" - } - stages { - stage('Build Docker Image') { - steps { - timeout(time: 60, unit: 'MINUTES') { - script { - try { - sh 'cp -R /home/batman/panda_jungle .' - } catch (err) { - echo "Folder already exists" - } - sh 'git archive -v -o panda.tar.gz --format=tar.gz HEAD' - dockerImage = docker.build("${env.DOCKER_IMAGE_TAG}") - } - } - } - } - stage('Test Dev Build (no WIFI)') { - steps { - lock(resource: "Pandas", inversePrecedence: true, quantity: 1){ - timeout(time: 60, unit: 'MINUTES') { - script { - sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'cd /tmp/panda; SKIPWIFI=1 ./run_automated_tests.sh'" - sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_dev_nowifi.xml" - sh "docker rm ${env.DOCKER_NAME}" - } - } - } - } - } - stage('Test EON Build') { - steps { - lock(resource: "Pandas", inversePrecedence: true, quantity: 1){ - timeout(time: 60, unit: 'MINUTES') { - script { - sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'touch /EON; cd /tmp/panda; ./run_automated_tests.sh'" - sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_eon.xml" - sh "docker rm ${env.DOCKER_NAME}" - } - } - } - } - } -/* - stage('Test Dev Build (WIFI)') { - steps { - lock(resource: "Pandas", inversePrecedence: true, quantity: 1){ - timeout(time: 60, unit: 'MINUTES') { - script { - sh "docker run --name ${env.DOCKER_NAME} --privileged --volume /dev/bus/usb:/dev/bus/usb --volume /var/run/dbus:/var/run/dbus --net host ${env.DOCKER_IMAGE_TAG} bash -c 'cd /tmp/panda; ./run_automated_tests.sh'" - sh "docker cp ${env.DOCKER_NAME}:/tmp/panda/nosetests.xml test_results_dev.xml" - sh "docker rm ${env.DOCKER_NAME}" - } - } - } - } - } -*/ - } - post { - failure { - script { - sh "docker rm ${env.DOCKER_NAME} || true" - } - } - always { - junit "test_results*.xml" - } - } -} diff --git a/panda/LICENSE b/panda/LICENSE deleted file mode 100644 index 8a6c6976b7..0000000000 --- a/panda/LICENSE +++ /dev/null @@ -1,7 +0,0 @@ -Copyright (c) 2016, Comma.ai, Inc. - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/panda/README.md b/panda/README.md deleted file mode 100644 index ea0df2a19c..0000000000 --- a/panda/README.md +++ /dev/null @@ -1,121 +0,0 @@ -Welcome to panda -====== - -[panda](http://github.com/commaai/panda) is the nicest universal car interface ever. - - - - - -It supports 3x CAN, 2x LIN, and 1x GMLAN. It also charges a phone. On the computer side, it has both USB and Wi-Fi. - -It uses an [STM32F413](http://www.st.com/en/microcontrollers/stm32f413-423.html?querycriteria=productId=LN2004) for low level stuff and an [ESP8266](https://en.wikipedia.org/wiki/ESP8266) for Wi-Fi. They are connected over high speed SPI, so the panda is actually capable of dumping the full contents of the busses over Wi-Fi, unlike every other dongle on amazon. ELM327 is weak, panda is strong. - -It is 2nd gen hardware, reusing code and parts from the [NEO](https://github.com/commaai/neo) interface board. - -[![CircleCI](https://circleci.com/gh/commaai/panda.svg?style=svg)](https://circleci.com/gh/commaai/panda) - -Usage (Python) ------- - -To install the library: -``` -# pip install pandacan -``` - -See [this class](https://github.com/commaai/panda/blob/master/python/__init__.py#L80) for how to interact with the panda. - -For example, to receive CAN messages: -``` ->>> from panda import Panda ->>> panda = Panda() ->>> panda.can_recv() -``` -And to send one on bus 0: -``` ->>> panda.can_send(0x1aa, "message", 0) -``` -Find user made scripts on the [wiki](https://community.comma.ai/wiki/index.php/Panda_scripts) - -Note that you may have to setup [udev rules](https://community.comma.ai/wiki/index.php/Panda#Linux_udev_rules) for Linux, such as -``` -sudo -i -echo 'SUBSYSTEMS=="usb", ATTR{idVendor}=="bbaa", ATTR{idProduct}=="ddcc", MODE:="0666"' > /etc/udev/rules.d/11-panda.rules -exit -``` - -Usage (JavaScript) -------- - -See [PandaJS](https://github.com/commaai/pandajs) - - -Software interface support ------- - -As a universal car interface, it should support every reasonable software interface. - -- [User space](https://github.com/commaai/panda/tree/master/python) -- [socketcan in kernel](https://github.com/commaai/panda/tree/master/drivers/linux) (alpha) -- [ELM327](https://github.com/commaai/panda/blob/master/boardesp/elm327.c) -- [Windows J2534](https://github.com/commaai/panda/tree/master/drivers/windows) - -Directory structure ------- - -- board -- Code that runs on the STM32 -- boardesp -- Code that runs on the ESP8266 -- drivers -- Drivers (not needed for use with python) -- python   -- Python userspace library for interfacing with the panda -- tests -- Tests and helper programs for panda - -Programming (over USB) ------- - -[Programming the Board (STM32)](board/README.md) - -[Programming the ESP](boardesp/README.md) - - -Debugging ------- - -To print out the serial console from the STM32, run tests/debug_console.py - -To print out the serial console from the ESP8266, run PORT=1 tests/debug_console.py - -Safety Model ------- - -When a panda powers up, by default it's in `SAFETY_SILENT` mode. While in `SAFETY_SILENT` mode, the buses are also forced to be silent. In order to send messages, you have to select a safety mode. Currently, setting safety modes is only supported over USB. - -Safety modes optionally supports `controls_allowed`, which allows or blocks a subset of messages based on a customizable state in the board. - -Code Rigor ------- -When compiled from an [EON Dev Kit](https://comma.ai/shop/products/eon-gold-dashcam-devkit), the panda FW is configured and optimized (at compile time) for its use in -conjuction with [openpilot](https://github.com/commaai/openpilot). The panda FW, through its safety model, provides and enforces the -[openpilot Safety](https://github.com/commaai/openpilot/blob/devel/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://circleci.com/gh/commaai/panda) 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://www.misra.org.uk/MISRAHome/MISRAC2012/tabid/196/Default.aspx) 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 on board and pedal makefiles. -* 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. -* A recorded drive for each supported car variant is [replayed through the safety logic](https://github.com/commaai/panda/tree/master/tests/safety_replay) -to ensure that the behavior remains unchanged. -* An internal Hardware-in-the-loop test, which currently only runs on pull requests opened by comma.ai's organization members, verifies the following functionalities: - * compiling the code in various configuration and flashing it both through USB and WiFi. - * Receiving, sending and forwarding CAN messages on all buses, over USB and WiFi. - -In addition, we run [Pylint](https://www.pylint.org/) and [Flake8](https://github.com/PyCQA/flake8) linters on all python files within the panda repo. - -Hardware ------- - -Check out the hardware [guide](https://github.com/commaai/panda/blob/master/docs/guide.pdf) - -Licensing ------- - -panda software is released under the MIT license unless otherwise specified. diff --git a/panda/TODO b/panda/TODO deleted file mode 100644 index 4e4a355154..0000000000 --- a/panda/TODO +++ /dev/null @@ -1,31 +0,0 @@ -** Projects ** - -== ELM327 Emulator == - -Write an elm327 emulator in boardesp/elm327.c and make it work with Torque - -You'll find a start at this in the "elm327" branch. - -== socketcan Kernel Driver == - -Write a kernel driver version of lib/panda.py that exposes the Panda on socketcan and makes it work with those tools. - -You may want to switch to interrupt endpoint first. Should LIN be exposed as a serial interface? - -== Windows J2534 DLL == - -Write a Windows DLL that exposes the J2534 API. - -Will make the Panda work with car diagnostic software. - - -** Refactors ** - -== USB Interrupt Endpoint == - -Switch USB to use an interrupt endpoint instead of a bulk endpoint for can recv - -== WebSocket Support == - -Add CAN streaming over WebSocket to the ELM code in addition to the UDP pipe. - diff --git a/panda/UPDATING.md b/panda/UPDATING.md deleted file mode 100644 index ab60f88ac8..0000000000 --- a/panda/UPDATING.md +++ /dev/null @@ -1,9 +0,0 @@ -# Updating your panda - -Panda should update automatically via the [openpilot](http://openpilot.comma.ai/). - -On Linux or Mac OSX, you can manually update it using: -``` -sudo pip install --upgrade pandacan` -PYTHONPATH="" sudo python -c "import panda; panda.flash_release()"` -``` diff --git a/panda/VERSION b/panda/VERSION deleted file mode 100644 index b7c8e167db..0000000000 --- a/panda/VERSION +++ /dev/null @@ -1 +0,0 @@ -v1.7.0 \ No newline at end of file diff --git a/panda/__init__.py b/panda/__init__.py deleted file mode 100644 index 5374d5a9ab..0000000000 --- a/panda/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .python import Panda, PandaWifiStreaming, PandaDFU, ESPROM, CesantaFlasher, flash_release, BASEDIR, ensure_st_up_to_date, build_st, PandaSerial # noqa: F401 diff --git a/panda/board/Makefile b/panda/board/Makefile deleted file mode 100644 index adeba0479a..0000000000 --- a/panda/board/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -PROJ_NAME = panda -CFLAGS = -g -Wall -Wextra -Wstrict-prototypes -Werror - -CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m4 -CFLAGS += -mhard-float -DSTM32F4 -DSTM32F413xx -mfpu=fpv4-sp-d16 -fsingle-precision-constant -STARTUP_FILE = startup_stm32f413xx - -include build.mk diff --git a/panda/board/README.md b/panda/board/README.md deleted file mode 100644 index 7151bfbf93..0000000000 --- a/panda/board/README.md +++ /dev/null @@ -1,36 +0,0 @@ -Dependencies --------- - -**Mac** - -``` -xcode-select --install -./get_sdk_mac.sh -``` - -**Debian / Ubuntu** - -``` -./get_sdk.sh -``` - - -Programming ----- - -**Panda** - -``` -make -``` - -Troubleshooting ----- - -If your panda will not flash and is quickly blinking a single Green LED, use: -``` -make recover -``` - - -[dfu-util](http://github.com/dsigma/dfu-util.git) for flashing diff --git a/panda/board/__init__.py b/panda/board/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/panda/board/board.h b/panda/board/board.h deleted file mode 100644 index 30e1fa4d17..0000000000 --- a/panda/board/board.h +++ /dev/null @@ -1,94 +0,0 @@ -// ///////////////////////////////////////////////////////////// // -// Hardware abstraction layer for all different supported boards // -// ///////////////////////////////////////////////////////////// // -#include "board_declarations.h" -#include "boards/common.h" - -// ///// Board definition and detection ///// // -#include "drivers/harness.h" -#ifdef PANDA - #include "drivers/fan.h" - #include "drivers/rtc.h" - #include "boards/white.h" - #include "boards/grey.h" - #include "boards/black.h" - #include "boards/uno.h" -#else - #include "boards/pedal.h" -#endif - -void detect_board_type(void) { - #ifdef PANDA - // SPI lines floating: white (TODO: is this reliable? Not really, we have to enable ESP/GPS to be able to detect this on the UART) - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 1); - if((detect_with_pull(GPIOA, 4, PULL_DOWN)) || (detect_with_pull(GPIOA, 5, PULL_DOWN)) || (detect_with_pull(GPIOA, 6, PULL_DOWN)) || (detect_with_pull(GPIOA, 7, PULL_DOWN))){ - hw_type = HW_TYPE_WHITE_PANDA; - current_board = &board_white; - } else if(detect_with_pull(GPIOA, 13, PULL_DOWN)) { // Rev AB deprecated, so no pullup means black. In REV C, A13 is pulled up to 5V with a 10K - hw_type = HW_TYPE_GREY_PANDA; - current_board = &board_grey; - } else if(!detect_with_pull(GPIOB, 15, PULL_UP)) { - hw_type = HW_TYPE_UNO; - current_board = &board_uno; - } else { - hw_type = HW_TYPE_BLACK_PANDA; - current_board = &board_black; - } - #else - #ifdef PEDAL - hw_type = HW_TYPE_PEDAL; - current_board = &board_pedal; - #else - hw_type = HW_TYPE_UNKNOWN; - puts("Hardware type is UNKNOWN!\n"); - #endif - #endif -} - - -// ///// Configuration detection ///// // -bool has_external_debug_serial = 0; -bool is_entering_bootmode = 0; - -void detect_configuration(void) { - // detect if external serial debugging is present - has_external_debug_serial = detect_with_pull(GPIOA, 3, PULL_DOWN); - - #ifdef PANDA - if(hw_type == HW_TYPE_WHITE_PANDA) { - // check if the ESP is trying to put me in boot mode - is_entering_bootmode = !detect_with_pull(GPIOB, 0, PULL_UP); - } else { - is_entering_bootmode = 0; - } - #else - is_entering_bootmode = 0; - #endif -} - -// ///// Board functions ///// // -// TODO: Make these config options in the board struct -bool board_has_gps(void) { - return ((hw_type == HW_TYPE_GREY_PANDA) || (hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO)); -} - -bool board_has_gmlan(void) { - return ((hw_type == HW_TYPE_WHITE_PANDA) || (hw_type == HW_TYPE_GREY_PANDA)); -} - -bool board_has_obd(void) { - return ((hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO)); -} - -bool board_has_lin(void) { - return ((hw_type == HW_TYPE_WHITE_PANDA) || (hw_type == HW_TYPE_GREY_PANDA)); -} - -bool board_has_rtc(void) { - return (hw_type == HW_TYPE_UNO); -} - -bool board_has_relay(void) { - return ((hw_type == HW_TYPE_BLACK_PANDA) || (hw_type == HW_TYPE_UNO)); -} diff --git a/panda/board/board_declarations.h b/panda/board/board_declarations.h deleted file mode 100644 index d973551baf..0000000000 --- a/panda/board/board_declarations.h +++ /dev/null @@ -1,74 +0,0 @@ -// ******************** Prototypes ******************** -typedef void (*board_init)(void); -typedef void (*board_enable_can_transciever)(uint8_t transciever, bool enabled); -typedef void (*board_enable_can_transcievers)(bool enabled); -typedef void (*board_set_led)(uint8_t color, bool enabled); -typedef void (*board_set_usb_power_mode)(uint8_t mode); -typedef void (*board_set_esp_gps_mode)(uint8_t mode); -typedef void (*board_set_can_mode)(uint8_t mode); -typedef void (*board_usb_power_mode_tick)(uint32_t uptime); -typedef bool (*board_check_ignition)(void); -typedef uint32_t (*board_read_current)(void); -typedef void (*board_set_ir_power)(uint8_t percentage); -typedef void (*board_set_fan_power)(uint8_t percentage); -typedef void (*board_set_phone_power)(bool enabled); - -struct board { - const char *board_type; - const harness_configuration *harness_config; - board_init init; - board_enable_can_transciever enable_can_transciever; - board_enable_can_transcievers enable_can_transcievers; - board_set_led set_led; - board_set_usb_power_mode set_usb_power_mode; - board_set_esp_gps_mode set_esp_gps_mode; - board_set_can_mode set_can_mode; - board_usb_power_mode_tick usb_power_mode_tick; - board_check_ignition check_ignition; - board_read_current read_current; - board_set_ir_power set_ir_power; - board_set_fan_power set_fan_power; - board_set_phone_power set_phone_power; -}; - -// ******************* Definitions ******************** -// These should match the enums in cereal/log.capnp and __init__.py -#define HW_TYPE_UNKNOWN 0U -#define HW_TYPE_WHITE_PANDA 1U -#define HW_TYPE_GREY_PANDA 2U -#define HW_TYPE_BLACK_PANDA 3U -#define HW_TYPE_PEDAL 4U -#define HW_TYPE_UNO 5U - -// LED colors -#define LED_RED 0U -#define LED_GREEN 1U -#define LED_BLUE 2U - -// USB power modes (from cereal.log.health) -#define USB_POWER_NONE 0U -#define USB_POWER_CLIENT 1U -#define USB_POWER_CDP 2U -#define USB_POWER_DCP 3U - -// ESP modes -#define ESP_GPS_DISABLED 0U -#define ESP_GPS_ENABLED 1U -#define ESP_GPS_BOOTMODE 2U - -// 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 - -// ********************* Globals ********************** -uint8_t usb_power_mode = USB_POWER_NONE; - -// ************ Board function prototypes ************* -bool board_has_gps(void); -bool board_has_gmlan(void); -bool board_has_obd(void); -bool board_has_lin(void); -bool board_has_rtc(void); -bool board_has_relay(void); \ No newline at end of file diff --git a/panda/board/boards/black.h b/panda/board/boards/black.h deleted file mode 100644 index 7165aa6cbb..0000000000 --- a/panda/board/boards/black.h +++ /dev/null @@ -1,239 +0,0 @@ -// ///////////////////// // -// Black Panda + Harness // -// ///////////////////// // - -void black_enable_can_transciever(uint8_t transciever, bool enabled) { - switch (transciever){ - case 1U: - set_gpio_output(GPIOC, 1, !enabled); - break; - case 2U: - set_gpio_output(GPIOC, 13, !enabled); - break; - case 3U: - set_gpio_output(GPIOA, 0, !enabled); - break; - case 4U: - set_gpio_output(GPIOB, 10, !enabled); - break; - default: - puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); - break; - } -} - -void black_enable_can_transcievers(bool enabled) { - uint8_t t1 = enabled ? 1U : 2U; // leave transciever 1 enabled to detect CAN ignition - for(uint8_t i=t1; i<=4U; i++) { - black_enable_can_transciever(i, enabled); - } -} - -void black_set_led(uint8_t color, bool enabled) { - switch (color){ - case LED_RED: - set_gpio_output(GPIOC, 9, !enabled); - break; - case LED_GREEN: - set_gpio_output(GPIOC, 7, !enabled); - break; - case LED_BLUE: - set_gpio_output(GPIOC, 6, !enabled); - break; - default: - break; - } -} - -void black_set_gps_load_switch(bool enabled) { - set_gpio_output(GPIOC, 12, enabled); -} - -void black_set_usb_load_switch(bool enabled) { - set_gpio_output(GPIOB, 1, !enabled); -} - -void black_set_usb_power_mode(uint8_t mode) { - bool valid = false; - switch (mode) { - case USB_POWER_CLIENT: - black_set_usb_load_switch(false); - valid = true; - break; - case USB_POWER_CDP: - black_set_usb_load_switch(true); - valid = true; - break; - default: - puts("Invalid USB power mode\n"); - break; - } - if (valid) { - usb_power_mode = mode; - } -} - -void black_set_esp_gps_mode(uint8_t mode) { - switch (mode) { - case ESP_GPS_DISABLED: - // GPS OFF - set_gpio_output(GPIOC, 14, 0); - set_gpio_output(GPIOC, 5, 0); - break; - case ESP_GPS_ENABLED: - // GPS ON - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 1); - break; - case ESP_GPS_BOOTMODE: - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 0); - break; - default: - puts("Invalid ESP/GPS mode\n"); - break; - } -} - -void black_set_can_mode(uint8_t mode){ - switch (mode) { - case CAN_MODE_NORMAL: - case CAN_MODE_OBD_CAN2: - if ((bool)(mode == CAN_MODE_NORMAL) != (bool)(car_harness_status == HARNESS_STATUS_NORMAL)) { - // B12,B13: disable OBD mode - set_gpio_mode(GPIOB, 12, MODE_INPUT); - set_gpio_mode(GPIOB, 13, MODE_INPUT); - - // B5,B6: normal CAN2 mode - set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); - } else { - // B5,B6: disable normal CAN2 mode - set_gpio_mode(GPIOB, 5, MODE_INPUT); - set_gpio_mode(GPIOB, 6, MODE_INPUT); - - // B12,B13: OBD mode - set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); - } - break; - default: - puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); - break; - } -} - -void black_usb_power_mode_tick(uint32_t uptime){ - UNUSED(uptime); - // Not applicable -} - -bool black_check_ignition(void){ - // ignition is checked through harness - return harness_check_ignition(); -} - -uint32_t black_read_current(void){ - // No current sense on black panda - return 0U; -} - -void black_set_ir_power(uint8_t percentage){ - UNUSED(percentage); -} - -void black_set_fan_power(uint8_t percentage){ - UNUSED(percentage); -} - -void black_set_phone_power(bool enabled){ - UNUSED(enabled); -} - -void black_init(void) { - common_init_gpio(); - - // A8,A15: normal CAN3 mode - set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); - set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); - - // C0: OBD_SBU1 (orientation detection) - // C3: OBD_SBU2 (orientation detection) - set_gpio_mode(GPIOC, 0, MODE_ANALOG); - set_gpio_mode(GPIOC, 3, MODE_ANALOG); - - // Set default state of GPS - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - - // C10: OBD_SBU1_RELAY (harness relay driving output) - // C11: OBD_SBU2_RELAY (harness relay driving output) - set_gpio_mode(GPIOC, 10, MODE_OUTPUT); - set_gpio_mode(GPIOC, 11, MODE_OUTPUT); - set_gpio_output_type(GPIOC, 10, OUTPUT_TYPE_OPEN_DRAIN); - set_gpio_output_type(GPIOC, 11, OUTPUT_TYPE_OPEN_DRAIN); - set_gpio_output(GPIOC, 10, 1); - set_gpio_output(GPIOC, 11, 1); - - // Turn on GPS load switch. - black_set_gps_load_switch(true); - - // Turn on USB load switch. - black_set_usb_load_switch(true); - - // Set right power mode - black_set_usb_power_mode(USB_POWER_CDP); - - // Initialize harness - harness_init(); - - // Enable CAN transcievers - black_enable_can_transcievers(true); - - // Disable LEDs - black_set_led(LED_RED, false); - black_set_led(LED_GREEN, false); - black_set_led(LED_BLUE, false); - - // Set normal CAN mode - black_set_can_mode(CAN_MODE_NORMAL); - - // flip CAN0 and CAN2 if we are flipped - if (car_harness_status == HARNESS_STATUS_NORMAL) { - can_flip_buses(0, 2); - } - - // init multiplexer - can_set_obd(car_harness_status, false); -} - -const harness_configuration black_harness_config = { - .has_harness = true, - .GPIO_SBU1 = GPIOC, - .GPIO_SBU2 = GPIOC, - .GPIO_relay_normal = GPIOC, - .GPIO_relay_flipped = GPIOC, - .pin_SBU1 = 0, - .pin_SBU2 = 3, - .pin_relay_normal = 10, - .pin_relay_flipped = 11, - .adc_channel_SBU1 = 10, - .adc_channel_SBU2 = 13 -}; - -const board board_black = { - .board_type = "Black", - .harness_config = &black_harness_config, - .init = black_init, - .enable_can_transciever = black_enable_can_transciever, - .enable_can_transcievers = black_enable_can_transcievers, - .set_led = black_set_led, - .set_usb_power_mode = black_set_usb_power_mode, - .set_esp_gps_mode = black_set_esp_gps_mode, - .set_can_mode = black_set_can_mode, - .usb_power_mode_tick = black_usb_power_mode_tick, - .check_ignition = black_check_ignition, - .read_current = black_read_current, - .set_fan_power = black_set_fan_power, - .set_ir_power = black_set_ir_power, - .set_phone_power = black_set_phone_power -}; diff --git a/panda/board/boards/common.h b/panda/board/boards/common.h deleted file mode 100644 index d0a4908763..0000000000 --- a/panda/board/boards/common.h +++ /dev/null @@ -1,84 +0,0 @@ -#ifdef STM32F4 - #include "stm32f4xx_hal_gpio_ex.h" -#else - #include "stm32f2xx_hal_gpio_ex.h" -#endif - -// Common GPIO initialization -void common_init_gpio(void){ - // TODO: Is this block actually doing something??? - // pull low to hold ESP in reset?? - // enable OTG out tied to ground - GPIOA->ODR = 0; - GPIOB->ODR = 0; - GPIOA->PUPDR = 0; - GPIOB->AFR[0] = 0; - GPIOB->AFR[1] = 0; - - // C2: Voltage sense line - set_gpio_mode(GPIOC, 2, MODE_ANALOG); - - // A11,A12: USB - set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG_FS); - set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS); - GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; - - // A9,A10: USART 1 for talking to the ESP / GPS - set_gpio_alternate(GPIOA, 9, GPIO_AF7_USART1); - set_gpio_alternate(GPIOA, 10, GPIO_AF7_USART1); - - // B8,B9: CAN 1 - #ifdef STM32F4 - set_gpio_alternate(GPIOB, 8, GPIO_AF8_CAN1); - set_gpio_alternate(GPIOB, 9, GPIO_AF8_CAN1); - #else - set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1); - set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1); - #endif -} - -// Peripheral initialization -void peripherals_init(void){ - // enable GPIOB, UART2, CAN, USB clock - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOBEN; - RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN; - RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN; - - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; - RCC->APB1ENR |= RCC_APB1ENR_USART2EN; - RCC->APB1ENR |= RCC_APB1ENR_USART3EN; - #ifdef PANDA - RCC->APB1ENR |= RCC_APB1ENR_UART5EN; - #endif - RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; - RCC->APB1ENR |= RCC_APB1ENR_CAN2EN; - #ifdef CAN3 - RCC->APB1ENR |= RCC_APB1ENR_CAN3EN; - #endif - RCC->APB1ENR |= RCC_APB1ENR_DACEN; - RCC->APB1ENR |= RCC_APB1ENR_TIM2EN; // main counter - RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; // pedal and fan PWM - RCC->APB1ENR |= RCC_APB1ENR_TIM4EN; // gmlan_alt and IR PWM - //RCC->APB1ENR |= RCC_APB1ENR_TIM5EN; - RCC->APB1ENR |= RCC_APB1ENR_TIM6EN; // interrupt timer - RCC->APB1ENR |= RCC_APB1ENR_PWREN; // for RTC config - RCC->APB2ENR |= RCC_APB2ENR_USART1EN; - RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; - //RCC->APB2ENR |= RCC_APB2ENR_TIM1EN; - RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; - RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; - RCC->APB2ENR |= RCC_APB2ENR_SYSCFGEN; - RCC->APB2ENR |= RCC_APB2ENR_TIM9EN; // slow loop -} - -// Detection with internal pullup -#define PULL_EFFECTIVE_DELAY 10 -bool detect_with_pull(GPIO_TypeDef *GPIO, int pin, int mode) { - set_gpio_mode(GPIO, pin, MODE_INPUT); - set_gpio_pullup(GPIO, pin, mode); - for (volatile int i=0; iset_esp_gps_mode(ESP_GPS_ENABLED); -} - -const board board_grey = { - .board_type = "Grey", - .harness_config = &white_harness_config, - .init = grey_init, - .enable_can_transciever = white_enable_can_transciever, - .enable_can_transcievers = white_enable_can_transcievers, - .set_led = white_set_led, - .set_usb_power_mode = white_set_usb_power_mode, - .set_esp_gps_mode = white_set_esp_gps_mode, - .set_can_mode = white_set_can_mode, - .usb_power_mode_tick = white_usb_power_mode_tick, - .check_ignition = white_check_ignition, - .read_current = white_read_current, - .set_fan_power = white_set_fan_power, - .set_ir_power = white_set_ir_power, - .set_phone_power = white_set_phone_power -}; \ No newline at end of file diff --git a/panda/board/boards/pedal.h b/panda/board/boards/pedal.h deleted file mode 100644 index c67d39151d..0000000000 --- a/panda/board/boards/pedal.h +++ /dev/null @@ -1,117 +0,0 @@ -// ///// // -// Pedal // -// ///// // - -void pedal_enable_can_transciever(uint8_t transciever, bool enabled) { - switch (transciever){ - case 1: - set_gpio_output(GPIOB, 3, !enabled); - break; - default: - puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); - break; - } -} - -void pedal_enable_can_transcievers(bool enabled) { - pedal_enable_can_transciever(1U, enabled); -} - -void pedal_set_led(uint8_t color, bool enabled) { - switch (color){ - case LED_RED: - set_gpio_output(GPIOB, 10, !enabled); - break; - case LED_GREEN: - set_gpio_output(GPIOB, 11, !enabled); - break; - default: - break; - } -} - -void pedal_set_usb_power_mode(uint8_t mode){ - usb_power_mode = mode; - puts("Trying to set USB power mode on pedal. This is not supported.\n"); -} - -void pedal_set_esp_gps_mode(uint8_t mode) { - UNUSED(mode); - puts("Trying to set ESP/GPS mode on pedal. This is not supported.\n"); -} - -void pedal_set_can_mode(uint8_t mode){ - switch (mode) { - case CAN_MODE_NORMAL: - break; - default: - puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); - break; - } -} - -void pedal_usb_power_mode_tick(uint32_t uptime){ - UNUSED(uptime); - // Not applicable -} - -bool pedal_check_ignition(void){ - // not supported on pedal - return false; -} - -uint32_t pedal_read_current(void){ - // No current sense on pedal - return 0U; -} - -void pedal_set_ir_power(uint8_t percentage){ - UNUSED(percentage); -} - -void pedal_set_fan_power(uint8_t percentage){ - UNUSED(percentage); -} - -void pedal_set_phone_power(bool enabled){ - UNUSED(enabled); -} - -void pedal_init(void) { - common_init_gpio(); - - // C0, C1: Throttle inputs - set_gpio_mode(GPIOC, 0, MODE_ANALOG); - set_gpio_mode(GPIOC, 1, MODE_ANALOG); - // DAC outputs on A4 and A5 - // apparently they don't need GPIO setup - - // Enable transciever - pedal_enable_can_transcievers(true); - - // Disable LEDs - pedal_set_led(LED_RED, false); - pedal_set_led(LED_GREEN, false); -} - -const harness_configuration pedal_harness_config = { - .has_harness = false -}; - -const board board_pedal = { - .board_type = "Pedal", - .harness_config = &pedal_harness_config, - .init = pedal_init, - .enable_can_transciever = pedal_enable_can_transciever, - .enable_can_transcievers = pedal_enable_can_transcievers, - .set_led = pedal_set_led, - .set_usb_power_mode = pedal_set_usb_power_mode, - .set_esp_gps_mode = pedal_set_esp_gps_mode, - .set_can_mode = pedal_set_can_mode, - .usb_power_mode_tick = pedal_usb_power_mode_tick, - .check_ignition = pedal_check_ignition, - .read_current = pedal_read_current, - .set_fan_power = pedal_set_fan_power, - .set_ir_power = pedal_set_ir_power, - .set_phone_power = pedal_set_phone_power -}; \ No newline at end of file diff --git a/panda/board/boards/uno.h b/panda/board/boards/uno.h deleted file mode 100644 index 1545a3f2db..0000000000 --- a/panda/board/boards/uno.h +++ /dev/null @@ -1,281 +0,0 @@ -// ///////////// // -// Uno + Harness // -// ///////////// // -#define BOOTKICK_TIME 3U -uint8_t bootkick_timer = 0U; - -void uno_enable_can_transciever(uint8_t transciever, bool enabled) { - switch (transciever){ - case 1U: - set_gpio_output(GPIOC, 1, !enabled); - break; - case 2U: - set_gpio_output(GPIOC, 13, !enabled); - break; - case 3U: - set_gpio_output(GPIOA, 0, !enabled); - break; - case 4U: - set_gpio_output(GPIOB, 10, !enabled); - break; - default: - puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); - break; - } -} - -void uno_enable_can_transcievers(bool enabled) { - for(uint8_t i=1U; i<=4U; i++){ - uno_enable_can_transciever(i, enabled); - } -} - -void uno_set_led(uint8_t color, bool enabled) { - switch (color){ - case LED_RED: - set_gpio_output(GPIOC, 9, !enabled); - break; - case LED_GREEN: - set_gpio_output(GPIOC, 7, !enabled); - break; - case LED_BLUE: - set_gpio_output(GPIOC, 6, !enabled); - break; - default: - break; - } -} - -void uno_set_gps_load_switch(bool enabled) { - set_gpio_output(GPIOC, 12, enabled); -} - -void uno_set_bootkick(bool enabled){ - set_gpio_output(GPIOB, 14, !enabled); -} - -void uno_bootkick(void) { - bootkick_timer = BOOTKICK_TIME; - uno_set_bootkick(true); -} - -void uno_set_phone_power(bool enabled){ - set_gpio_output(GPIOB, 4, enabled); -} - -void uno_set_usb_power_mode(uint8_t mode) { - bool valid = false; - switch (mode) { - case USB_POWER_CLIENT: - uno_set_phone_power(false); - valid = true; - break; - case USB_POWER_CDP: - uno_set_phone_power(true); - uno_bootkick(); - valid = true; - break; - default: - puts("Invalid USB power mode\n"); - break; - } - if (valid) { - usb_power_mode = mode; - } -} - -void uno_set_esp_gps_mode(uint8_t mode) { - switch (mode) { - case ESP_GPS_DISABLED: - // GPS OFF - set_gpio_output(GPIOB, 1, 0); - set_gpio_output(GPIOC, 5, 0); - uno_set_gps_load_switch(false); - break; - case ESP_GPS_ENABLED: - // GPS ON - set_gpio_output(GPIOB, 1, 1); - set_gpio_output(GPIOC, 5, 1); - uno_set_gps_load_switch(true); - break; - case ESP_GPS_BOOTMODE: - set_gpio_output(GPIOB, 1, 1); - set_gpio_output(GPIOC, 5, 0); - uno_set_gps_load_switch(true); - break; - default: - puts("Invalid ESP/GPS mode\n"); - break; - } -} - -void uno_set_can_mode(uint8_t mode){ - switch (mode) { - case CAN_MODE_NORMAL: - case CAN_MODE_OBD_CAN2: - if ((bool)(mode == CAN_MODE_NORMAL) != (bool)(car_harness_status == HARNESS_STATUS_NORMAL)) { - // B12,B13: disable OBD mode - set_gpio_mode(GPIOB, 12, MODE_INPUT); - set_gpio_mode(GPIOB, 13, MODE_INPUT); - - // B5,B6: normal CAN2 mode - set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); - } else { - // B5,B6: disable normal CAN2 mode - set_gpio_mode(GPIOB, 5, MODE_INPUT); - set_gpio_mode(GPIOB, 6, MODE_INPUT); - - // B12,B13: OBD mode - set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); - } - break; - default: - puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); - break; - } -} - -void uno_usb_power_mode_tick(uint32_t uptime){ - UNUSED(uptime); - if(bootkick_timer != 0U){ - bootkick_timer--; - } else { - uno_set_bootkick(false); - } -} - -bool uno_check_ignition(void){ - // ignition is checked through harness - return harness_check_ignition(); -} - -void uno_set_usb_switch(bool phone){ - set_gpio_output(GPIOB, 3, phone); -} - -void uno_set_ir_power(uint8_t percentage){ - pwm_set(TIM4, 2, percentage); -} - -void uno_set_fan_power(uint8_t percentage){ - // Enable fan power only if percentage is non-zero. - set_gpio_output(GPIOA, 1, (percentage != 0U)); - fan_set_power(percentage); -} - -uint32_t uno_read_current(void){ - // No current sense on Uno - return 0U; -} - -void uno_init(void) { - common_init_gpio(); - - // A8,A15: normal CAN3 mode - set_gpio_alternate(GPIOA, 8, GPIO_AF11_CAN3); - set_gpio_alternate(GPIOA, 15, GPIO_AF11_CAN3); - - // C0: OBD_SBU1 (orientation detection) - // C3: OBD_SBU2 (orientation detection) - set_gpio_mode(GPIOC, 0, MODE_ANALOG); - set_gpio_mode(GPIOC, 3, MODE_ANALOG); - - // Set default state of GPS - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - - // C10: OBD_SBU1_RELAY (harness relay driving output) - // C11: OBD_SBU2_RELAY (harness relay driving output) - set_gpio_mode(GPIOC, 10, MODE_OUTPUT); - set_gpio_mode(GPIOC, 11, MODE_OUTPUT); - set_gpio_output_type(GPIOC, 10, OUTPUT_TYPE_OPEN_DRAIN); - set_gpio_output_type(GPIOC, 11, OUTPUT_TYPE_OPEN_DRAIN); - set_gpio_output(GPIOC, 10, 1); - set_gpio_output(GPIOC, 11, 1); - - // C8: FAN PWM aka TIM3_CH3 - set_gpio_alternate(GPIOC, 8, GPIO_AF2_TIM3); - - // Turn on GPS load switch. - uno_set_gps_load_switch(true); - - // Turn on phone regulator - uno_set_phone_power(true); - - // Initialize IR PWM and set to 0% - set_gpio_alternate(GPIOB, 7, GPIO_AF2_TIM4); - pwm_init(TIM4, 2); - uno_set_ir_power(0U); - - // Initialize fan and set to 0% - fan_init(); - uno_set_fan_power(0U); - - // Initialize harness - harness_init(); - - // Initialize RTC - rtc_init(); - - // Enable CAN transcievers - uno_enable_can_transcievers(true); - - // Disable LEDs - uno_set_led(LED_RED, false); - uno_set_led(LED_GREEN, false); - uno_set_led(LED_BLUE, false); - - // Set normal CAN mode - uno_set_can_mode(CAN_MODE_NORMAL); - - // flip CAN0 and CAN2 if we are flipped - if (car_harness_status == HARNESS_STATUS_NORMAL) { - can_flip_buses(0, 2); - } - - // init multiplexer - can_set_obd(car_harness_status, false); - - // Switch to phone usb mode if harness connection is powered by less than 7V - if(adc_get_voltage() < 7000U){ - uno_set_usb_switch(true); - } else { - uno_set_usb_switch(false); - } - - // Bootkick phone - uno_bootkick(); -} - -const harness_configuration uno_harness_config = { - .has_harness = true, - .GPIO_SBU1 = GPIOC, - .GPIO_SBU2 = GPIOC, - .GPIO_relay_normal = GPIOC, - .GPIO_relay_flipped = GPIOC, - .pin_SBU1 = 0, - .pin_SBU2 = 3, - .pin_relay_normal = 10, - .pin_relay_flipped = 11, - .adc_channel_SBU1 = 10, - .adc_channel_SBU2 = 13 -}; - -const board board_uno = { - .board_type = "Uno", - .harness_config = &uno_harness_config, - .init = uno_init, - .enable_can_transciever = uno_enable_can_transciever, - .enable_can_transcievers = uno_enable_can_transcievers, - .set_led = uno_set_led, - .set_usb_power_mode = uno_set_usb_power_mode, - .set_esp_gps_mode = uno_set_esp_gps_mode, - .set_can_mode = uno_set_can_mode, - .usb_power_mode_tick = uno_usb_power_mode_tick, - .check_ignition = uno_check_ignition, - .read_current = uno_read_current, - .set_fan_power = uno_set_fan_power, - .set_ir_power = uno_set_ir_power, - .set_phone_power = uno_set_phone_power -}; diff --git a/panda/board/boards/white.h b/panda/board/boards/white.h deleted file mode 100644 index 1be0702f94..0000000000 --- a/panda/board/boards/white.h +++ /dev/null @@ -1,347 +0,0 @@ -// /////////// // -// White Panda // -// /////////// // - -void white_enable_can_transciever(uint8_t transciever, bool enabled) { - switch (transciever){ - case 1U: - set_gpio_output(GPIOC, 1, !enabled); - break; - case 2U: - set_gpio_output(GPIOC, 13, !enabled); - break; - case 3U: - set_gpio_output(GPIOA, 0, !enabled); - break; - default: - puts("Invalid CAN transciever ("); puth(transciever); puts("): enabling failed\n"); - break; - } -} - -void white_enable_can_transcievers(bool enabled) { - uint8_t t1 = enabled ? 1U : 2U; // leave transciever 1 enabled to detect CAN ignition - for(uint8_t i=t1; i<=3U; i++) { - white_enable_can_transciever(i, enabled); - } -} - -void white_set_led(uint8_t color, bool enabled) { - switch (color){ - case LED_RED: - set_gpio_output(GPIOC, 9, !enabled); - break; - case LED_GREEN: - set_gpio_output(GPIOC, 7, !enabled); - break; - case LED_BLUE: - set_gpio_output(GPIOC, 6, !enabled); - break; - default: - break; - } -} - -void white_set_usb_power_mode(uint8_t mode){ - bool valid_mode = true; - switch (mode) { - case USB_POWER_CLIENT: - // B2,A13: set client mode - set_gpio_output(GPIOB, 2, 0); - set_gpio_output(GPIOA, 13, 1); - break; - case USB_POWER_CDP: - // B2,A13: set CDP mode - set_gpio_output(GPIOB, 2, 1); - set_gpio_output(GPIOA, 13, 1); - break; - case USB_POWER_DCP: - // B2,A13: set DCP mode on the charger (breaks USB!) - set_gpio_output(GPIOB, 2, 0); - set_gpio_output(GPIOA, 13, 0); - break; - default: - valid_mode = false; - puts("Invalid usb power mode\n"); - break; - } - - if (valid_mode) { - usb_power_mode = mode; - } -} - -void white_set_esp_gps_mode(uint8_t mode) { - switch (mode) { - case ESP_GPS_DISABLED: - // ESP OFF - set_gpio_output(GPIOC, 14, 0); - set_gpio_output(GPIOC, 5, 0); - break; -#ifndef EON - case ESP_GPS_ENABLED: - // ESP ON - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 1); - break; -#endif - case ESP_GPS_BOOTMODE: - set_gpio_output(GPIOC, 14, 1); - set_gpio_output(GPIOC, 5, 0); - break; - default: - puts("Invalid ESP/GPS mode\n"); - break; - } -} - -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); - - // 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); - - // 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: - puts("Tried to set unsupported CAN mode: "); puth(mode); puts("\n"); - break; - } -} - -uint32_t white_read_current(void){ - return adc_get(ADCCHAN_CURRENT); -} - -uint32_t marker = 0; -void white_usb_power_mode_tick(uint32_t uptime){ - - // on EON or BOOTSTUB, no state machine -#if !defined(BOOTSTUB) && !defined(EON) - #define CURRENT_THRESHOLD 0xF00U - #define CLICKS 5U // 5 seconds to switch modes - - uint32_t current = white_read_current(); - - // ~0x9a = 500 ma - // puth(current); puts("\n"); - - switch (usb_power_mode) { - case USB_POWER_CLIENT: - if ((uptime - marker) >= CLICKS) { - if (!is_enumerated) { - puts("USBP: didn't enumerate, switching to CDP mode\n"); - // switch to CDP - white_set_usb_power_mode(USB_POWER_CDP); - marker = uptime; - } - } - // keep resetting the timer if it's enumerated - if (is_enumerated) { - marker = uptime; - } - break; - case USB_POWER_CDP: - // been CLICKS clicks since we switched to CDP - if ((uptime - marker) >= CLICKS) { - // measure current draw, if positive and no enumeration, switch to DCP - if (!is_enumerated && (current < CURRENT_THRESHOLD)) { - puts("USBP: no enumeration with current draw, switching to DCP mode\n"); - white_set_usb_power_mode(USB_POWER_DCP); - marker = uptime; - } - } - // keep resetting the timer if there's no current draw in CDP - if (current >= CURRENT_THRESHOLD) { - marker = uptime; - } - break; - case USB_POWER_DCP: - // been at least CLICKS clicks since we switched to DCP - if ((uptime - marker) >= CLICKS) { - // if no current draw, switch back to CDP - if (current >= CURRENT_THRESHOLD) { - puts("USBP: no current draw, switching back to CDP mode\n"); - white_set_usb_power_mode(USB_POWER_CDP); - marker = uptime; - } - } - // keep resetting the timer if there's current draw in DCP - if (current < CURRENT_THRESHOLD) { - marker = uptime; - } - break; - default: - puts("USB power mode invalid\n"); // set_usb_power_mode prevents assigning invalid values - break; - } -#else - UNUSED(uptime); -#endif -} - -void white_set_ir_power(uint8_t percentage){ - UNUSED(percentage); -} - -void white_set_fan_power(uint8_t percentage){ - UNUSED(percentage); -} - -bool white_check_ignition(void){ - // ignition is on PA1 - return !get_gpio_input(GPIOA, 1); -} - -void white_set_phone_power(bool enabled){ - UNUSED(enabled); -} - -void white_grey_common_init(void) { - common_init_gpio(); - - // C3: current sense - set_gpio_mode(GPIOC, 3, MODE_ANALOG); - - // A1: started_alt - set_gpio_pullup(GPIOA, 1, PULL_UP); - - // A2, A3: USART 2 for debugging - set_gpio_alternate(GPIOA, 2, GPIO_AF7_USART2); - set_gpio_alternate(GPIOA, 3, GPIO_AF7_USART2); - - // A4, A5, A6, A7: SPI - set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1); - - // B12: GMLAN, ignition sense, pull up - set_gpio_pullup(GPIOB, 12, PULL_UP); - - /* GMLAN mode pins: - M0(B15) M1(B14) mode - ======================= - 0 0 sleep - 1 0 100kbit - 0 1 high voltage wakeup - 1 1 33kbit (normal) - */ - set_gpio_output(GPIOB, 14, 1); - set_gpio_output(GPIOB, 15, 1); - - // B7: K-line enable - set_gpio_output(GPIOB, 7, 1); - - // C12, D2: Setup K-line (UART5) - set_gpio_alternate(GPIOC, 12, GPIO_AF8_UART5); - set_gpio_alternate(GPIOD, 2, GPIO_AF8_UART5); - set_gpio_pullup(GPIOD, 2, PULL_UP); - - // L-line enable - set_gpio_output(GPIOA, 14, 1); - - // C10, C11: L-Line setup (USART3) - set_gpio_alternate(GPIOC, 10, GPIO_AF7_USART3); - set_gpio_alternate(GPIOC, 11, GPIO_AF7_USART3); - set_gpio_pullup(GPIOC, 11, PULL_UP); - - // Enable CAN transcievers - white_enable_can_transcievers(true); - - // Disable LEDs - white_set_led(LED_RED, false); - white_set_led(LED_GREEN, false); - white_set_led(LED_BLUE, false); - - // Set normal CAN mode - white_set_can_mode(CAN_MODE_NORMAL); - - // Init usb power mode - uint32_t voltage = adc_get_voltage(); - // Init in CDP mode only if panda is powered by 12V. - // Otherwise a PC would not be able to flash a standalone panda with EON build - if (voltage > 8000U) { // 8V threshold - white_set_usb_power_mode(USB_POWER_CDP); - } else { - white_set_usb_power_mode(USB_POWER_CLIENT); - } -} - -void white_init(void) { - white_grey_common_init(); - - // Set default state of ESP - #ifdef EON - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); - #else - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - #endif -} - -const harness_configuration white_harness_config = { - .has_harness = false -}; - -const board board_white = { - .board_type = "White", - .harness_config = &white_harness_config, - .init = white_init, - .enable_can_transciever = white_enable_can_transciever, - .enable_can_transcievers = white_enable_can_transcievers, - .set_led = white_set_led, - .set_usb_power_mode = white_set_usb_power_mode, - .set_esp_gps_mode = white_set_esp_gps_mode, - .set_can_mode = white_set_can_mode, - .usb_power_mode_tick = white_usb_power_mode_tick, - .check_ignition = white_check_ignition, - .read_current = white_read_current, - .set_fan_power = white_set_fan_power, - .set_ir_power = white_set_ir_power, - .set_phone_power = white_set_phone_power -}; diff --git a/panda/board/bootstub.c b/panda/board/bootstub.c deleted file mode 100644 index 1521b53240..0000000000 --- a/panda/board/bootstub.c +++ /dev/null @@ -1,124 +0,0 @@ -#define BOOTSTUB - -#define VERS_TAG 0x53524556 -#define MIN_VERSION 2 - -#include "config.h" -#include "obj/gitversion.h" - -#ifdef STM32F4 - #define PANDA - #include "stm32f4xx.h" - #include "stm32f4xx_hal_gpio_ex.h" -#else - #include "stm32f2xx.h" - #include "stm32f2xx_hal_gpio_ex.h" -#endif - -// ******************** Prototypes ******************** -void puts(const char *a){ UNUSED(a); } -void puth(unsigned int i){ UNUSED(i); } -void puth2(unsigned int i){ UNUSED(i); } -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 can_set_obd(int harness_orientation, bool obd){UNUSED(harness_orientation); UNUSED(obd);} - -// ********************* Globals ********************** -int hw_type = 0; -const board *current_board; - -// ********************* Includes ********************* -#include "libc.h" -#include "provision.h" -#include "critical.h" -#include "faults.h" - -#include "drivers/registers.h" -#include "drivers/interrupts.h" -#include "drivers/clock.h" -#include "drivers/llgpio.h" -#include "drivers/adc.h" -#include "drivers/pwm.h" - -#include "board.h" - -#include "gpio.h" - -#include "drivers/spi.h" -#include "drivers/usb.h" -//#include "drivers/uart.h" - -#include "crypto/rsa.h" -#include "crypto/sha.h" - -#include "obj/cert.h" - -#include "spi_flasher.h" - -void __initialize_hardware_early(void) { - early(); -} - -void fail(void) { - soft_flasher_start(); -} - -// know where to sig check -extern void *_app_start[]; - -// FIXME: sometimes your panda will fail flashing and will quickly blink a single Green LED -// BOUNTY: $200 coupon on shop.comma.ai or $100 check. - -int main(void) { - // Init interrupt table - init_interrupts(true); - - disable_interrupts(); - clock_init(); - detect_configuration(); - detect_board_type(); - - if (enter_bootloader_mode == ENTER_SOFTLOADER_MAGIC) { - enter_bootloader_mode = 0; - soft_flasher_start(); - } - - // validate length - int len = (int)_app_start[0]; - if ((len < 8) || (len > (0x1000000 - 0x4000 - 4 - RSANUMBYTES))) goto fail; - - // compute SHA hash - uint8_t digest[SHA_DIGEST_SIZE]; - SHA_hash(&_app_start[1], len-4, digest); - - // verify version, last bytes in the signed area - uint32_t vers[2] = {0}; - memcpy(&vers, ((void*)&_app_start[0]) + len - sizeof(vers), sizeof(vers)); - if (vers[0] != VERS_TAG || vers[1] < MIN_VERSION) { - goto fail; - } - - // verify RSA signature - if (RSA_verify(&release_rsa_key, ((void*)&_app_start[0]) + len, RSANUMBYTES, digest, SHA_DIGEST_SIZE)) { - goto good; - } - - // allow debug if built from source -#ifdef ALLOW_DEBUG - if (RSA_verify(&debug_rsa_key, ((void*)&_app_start[0]) + len, RSANUMBYTES, digest, SHA_DIGEST_SIZE)) { - goto good; - } -#endif - -// here is a failure -fail: - fail(); - return 0; -good: - // jump to flash - ((void(*)(void)) _app_start[1])(); - return 0; -} - diff --git a/panda/board/build.mk b/panda/board/build.mk deleted file mode 100644 index 21daf53ad0..0000000000 --- a/panda/board/build.mk +++ /dev/null @@ -1,84 +0,0 @@ -CFLAGS += -I inc -I ../ -nostdlib -fno-builtin -std=gnu11 -Os - -CFLAGS += -Tstm32_flash.ld - -DFU_UTIL = "dfu-util" - -# Compile fast charge (DCP) only not on EON -ifeq (,$(wildcard /EON)) - BUILDER = DEV -else - CFLAGS += "-DEON" - BUILDER = EON - DFU_UTIL = "tools/dfu-util-aarch64" -endif - -CC = arm-none-eabi-gcc -OBJCOPY = arm-none-eabi-objcopy -OBJDUMP = arm-none-eabi-objdump - -ifeq ($(RELEASE),1) - CERT = ../../pandaextra/certs/release -else - # enable the debug cert - CERT = ../certs/debug - CFLAGS += "-DALLOW_DEBUG" -endif - - -DEPDIR = generated_dependencies -$(shell mkdir -p -m 777 $(DEPDIR) >/dev/null) -DEPFLAGS = -MT $@ -MMD -MP -MF $(DEPDIR)/$*.Td -POSTCOMPILE = @mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d && touch $@ - -# this no longer pushes the bootstub -flash: obj/$(PROJ_NAME).bin - PYTHONPATH=../ python3 -c "from python import Panda; Panda().flash('obj/$(PROJ_NAME).bin')" - -ota: obj/$(PROJ_NAME).bin - curl http://192.168.0.10/stupdate --upload-file $< - -bin: obj/$(PROJ_NAME).bin - -# this flashes everything -recover: obj/bootstub.$(PROJ_NAME).bin obj/$(PROJ_NAME).bin - -PYTHONPATH=../ python3 -c "from python import Panda; Panda().reset(enter_bootloader=True)" - sleep 1.0 - $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08004000 -D obj/$(PROJ_NAME).bin - $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.$(PROJ_NAME).bin - -include ../common/version.mk - -obj/cert.h: ../crypto/getcertheader.py - ../crypto/getcertheader.py ../certs/debug.pub ../certs/release.pub > $@ - -obj/%.$(PROJ_NAME).o: %.c obj/gitversion.h obj/cert.h $(DEPDIR)/%.d - $(CC) $(DEPFLAGS) $(CFLAGS) -o $@ -c $< - $(POSTCOMPILE) - -obj/%.$(PROJ_NAME).o: ../crypto/%.c - $(CC) $(CFLAGS) -o $@ -c $< - -obj/$(STARTUP_FILE).o: $(STARTUP_FILE).s - $(CC) $(CFLAGS) -o $@ -c $< - -obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.$(PROJ_NAME).o - # hack - $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ - $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin - SETLEN=1 ../crypto/sign.py obj/code.bin $@ $(CERT) - @BINSIZE=$$(du -b "obj/$(PROJ_NAME).bin" | cut -f 1) ; \ - if [ $$BINSIZE -ge 49152 ]; then echo "ERROR obj/$(PROJ_NAME).bin is too big!"; exit 1; fi; - -obj/bootstub.$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/bootstub.$(PROJ_NAME).o obj/sha.$(PROJ_NAME).o obj/rsa.$(PROJ_NAME).o - $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ - $(OBJCOPY) -v -O binary obj/bootstub.$(PROJ_NAME).elf $@ - -$(DEPDIR)/%.d: ; -.PRECIOUS: $(DEPDIR)/%.d - -include $(wildcard $(patsubst %,$(DEPDIR)/%.d,$(basename $(wildcard *.c)))) - -clean: - @$(RM) obj/* - @rm -rf $(DEPDIR) diff --git a/panda/board/config.h b/panda/board/config.h deleted file mode 100644 index 15096b69fa..0000000000 --- a/panda/board/config.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef PANDA_CONFIG_H -#define PANDA_CONFIG_H - -//#define DEBUG -//#define DEBUG_UART -//#define DEBUG_USB -//#define DEBUG_SPI -//#define DEBUG_FAULTS - -#ifdef STM32F4 - #define PANDA - #include "stm32f4xx.h" -#else - #include "stm32f2xx.h" -#endif - -#define USB_VID 0xbbaaU - -#ifdef BOOTSTUB -#define USB_PID 0xddeeU -#else -#define USB_PID 0xddccU -#endif - -#include -#define NULL ((void*)0) -#define COMPILE_TIME_ASSERT(pred) ((void)sizeof(char[1 - (2 * ((int)(!(pred))))])) - -#define MIN(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - (_a < _b) ? _a : _b; }) - -#define MAX(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - (_a > _b) ? _a : _b; }) - -#define MAX_RESP_LEN 0x40U - -// Around (1Mbps / 8 bits/byte / 12 bytes per message) -#define CAN_INTERRUPT_RATE 12000U - -#endif - diff --git a/panda/board/critical.h b/panda/board/critical.h deleted file mode 100644 index c8cf52c7a1..0000000000 --- a/panda/board/critical.h +++ /dev/null @@ -1,23 +0,0 @@ -// ********************* Critical section helpers ********************* -volatile bool interrupts_enabled = false; - -void enable_interrupts(void) { - interrupts_enabled = true; - __enable_irq(); -} - -void disable_interrupts(void) { - interrupts_enabled = false; - __disable_irq(); -} - -uint8_t global_critical_depth = 0U; -#define ENTER_CRITICAL() \ - __disable_irq(); \ - global_critical_depth += 1U; - -#define EXIT_CRITICAL() \ - global_critical_depth -= 1U; \ - if ((global_critical_depth == 0U) && interrupts_enabled) { \ - __enable_irq(); \ - } diff --git a/panda/board/drivers/adc.h b/panda/board/drivers/adc.h deleted file mode 100644 index 358497adbf..0000000000 --- a/panda/board/drivers/adc.h +++ /dev/null @@ -1,38 +0,0 @@ -// ACCEL1 = ADC10 -// ACCEL2 = ADC11 -// VOLT_S = ADC12 -// CURR_S = ADC13 - -#define ADCCHAN_ACCEL0 10 -#define ADCCHAN_ACCEL1 11 -#define ADCCHAN_VOLTAGE 12 -#define ADCCHAN_CURRENT 13 - -void adc_init(void) { - register_set(&(ADC->CCR), ADC_CCR_TSVREFE | ADC_CCR_VBATE, 0xC30000U); - register_set(&(ADC1->CR2), ADC_CR2_ADON, 0xFF7F0F03U); - register_set(&(ADC1->SMPR1), ADC_SMPR1_SMP12 | ADC_SMPR1_SMP13, 0x7FFFFFFU); -} - -uint32_t adc_get(unsigned int channel) { - // Select channel - register_set(&(ADC1->JSQR), (channel << 15U), 0x3FFFFFU); - - // Start conversion - ADC1->SR &= ~(ADC_SR_JEOC); - ADC1->CR2 |= ADC_CR2_JSWSTART; - while (!(ADC1->SR & ADC_SR_JEOC)); - - return ADC1->JDR1; -} - -uint32_t adc_get_voltage(void) { - // REVC has a 10, 1 (1/11) voltage divider - // Here is the calculation for the scale (s) - // ADCV = VIN_S * (1/11) * (4095/3.3) - // RETVAL = ADCV * s = VIN_S*1000 - // s = 1000/((4095/3.3)*(1/11)) = 8.8623046875 - - // Avoid needing floating point math, so output in mV - return (adc_get(ADCCHAN_VOLTAGE) * 8862U) / 1000U; -} diff --git a/panda/board/drivers/can.h b/panda/board/drivers/can.h deleted file mode 100644 index 07895e3e08..0000000000 --- a/panda/board/drivers/can.h +++ /dev/null @@ -1,448 +0,0 @@ -// IRQs: CAN1_TX, CAN1_RX0, CAN1_SCE -// CAN2_TX, CAN2_RX0, CAN2_SCE -// CAN3_TX, CAN3_RX0, CAN3_SCE - -typedef struct { - volatile uint32_t w_ptr; - volatile uint32_t r_ptr; - uint32_t fifo_size; - CAN_FIFOMailBox_TypeDef *elems; -} can_ring; - -#define CAN_BUS_RET_FLAG 0x80U -#define CAN_BUS_NUM_MASK 0x7FU - -#define BUS_MAX 4U - -uint32_t can_send_errs = 0; -uint32_t can_fwd_errs = 0; -uint32_t gmlan_send_errs = 0; -extern int can_live, pending_can_live; - -// must reinit after changing these -extern int can_loopback, can_silent; -extern uint32_t can_speed[4]; - -void can_set_forwarding(int from, int to); - -void can_init(uint8_t can_number); -void can_init_all(void); -void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number, bool skip_tx_hook); -bool can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem); - -// Ignition detected from CAN meessages -bool ignition_can = false; -uint32_t ignition_can_cnt = 0U; - -// end API - -#define ALL_CAN_SILENT 0xFF -#define ALL_CAN_LIVE 0 - -int can_live = 0, pending_can_live = 0, can_loopback = 0, can_silent = ALL_CAN_SILENT; - -// ********************* instantiate queues ********************* - -#define can_buffer(x, size) \ - CAN_FIFOMailBox_TypeDef elems_##x[size]; \ - can_ring can_##x = { .w_ptr = 0, .r_ptr = 0, .fifo_size = size, .elems = (CAN_FIFOMailBox_TypeDef *)&elems_##x }; - -can_buffer(rx_q, 0x1000) -can_buffer(tx1_q, 0x100) -can_buffer(tx2_q, 0x100) -can_buffer(tx3_q, 0x100) -can_buffer(txgmlan_q, 0x100) -can_ring *can_queues[] = {&can_tx1_q, &can_tx2_q, &can_tx3_q, &can_txgmlan_q}; - -// global CAN stats -int can_rx_cnt = 0; -int can_tx_cnt = 0; -int can_txd_cnt = 0; -int can_err_cnt = 0; -int can_overflow_cnt = 0; - -// ********************* interrupt safe queue ********************* - -bool can_pop(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { - bool ret = 0; - - ENTER_CRITICAL(); - if (q->w_ptr != q->r_ptr) { - *elem = q->elems[q->r_ptr]; - if ((q->r_ptr + 1U) == q->fifo_size) { - q->r_ptr = 0; - } else { - q->r_ptr += 1U; - } - ret = 1; - } - EXIT_CRITICAL(); - - return ret; -} - -bool can_push(can_ring *q, CAN_FIFOMailBox_TypeDef *elem) { - bool ret = false; - uint32_t next_w_ptr; - - ENTER_CRITICAL(); - if ((q->w_ptr + 1U) == q->fifo_size) { - next_w_ptr = 0; - } else { - next_w_ptr = q->w_ptr + 1U; - } - if (next_w_ptr != q->r_ptr) { - q->elems[q->w_ptr] = *elem; - q->w_ptr = next_w_ptr; - ret = true; - } - EXIT_CRITICAL(); - if (!ret) { - can_overflow_cnt++; - #ifdef DEBUG - puts("can_push failed!\n"); - #endif - } - return ret; -} - -void can_clear(can_ring *q) { - ENTER_CRITICAL(); - q->w_ptr = 0; - q->r_ptr = 0; - EXIT_CRITICAL(); -} - -// assign CAN numbering -// bus num: Can bus number on ODB connector. Sent to/from USB -// Min: 0; Max: 127; Bit 7 marks message as receipt (bus 129 is receipt for but 1) -// cans: Look up MCU can interface from bus number -// can number: numeric lookup for MCU CAN interfaces (0 = CAN1, 1 = CAN2, etc); -// bus_lookup: Translates from 'can number' to 'bus number'. -// can_num_lookup: Translates from 'bus number' to 'can number'. -// can_forwarding: Given a bus num, lookup bus num to forward to. -1 means no forward. - -// Panda: Bus 0=CAN1 Bus 1=CAN2 Bus 2=CAN3 -CAN_TypeDef *cans[] = {CAN1, CAN2, CAN3}; -uint8_t bus_lookup[] = {0,1,2}; -uint8_t can_num_lookup[] = {0,1,2,-1}; -int8_t can_forwarding[] = {-1,-1,-1,-1}; -uint32_t can_speed[] = {5000, 5000, 5000, 333}; -#define CAN_MAX 3U - -#define CANIF_FROM_CAN_NUM(num) (cans[num]) -#define CAN_NUM_FROM_CANIF(CAN) ((CAN)==CAN1 ? 0 : ((CAN) == CAN2 ? 1 : 2)) -#define CAN_NAME_FROM_CANIF(CAN) ((CAN)==CAN1 ? "CAN1" : ((CAN) == CAN2 ? "CAN2" : "CAN3")) -#define BUS_NUM_FROM_CAN_NUM(num) (bus_lookup[num]) -#define CAN_NUM_FROM_BUS_NUM(num) (can_num_lookup[num]) - -void process_can(uint8_t can_number); - -void can_set_speed(uint8_t can_number) { - CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); - uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); - - if (!llcan_set_speed(CAN, can_speed[bus_number], can_loopback, (unsigned int)(can_silent) & (1U << can_number))) { - puts("CAN init FAILED!!!!!\n"); - puth(can_number); puts(" "); - puth(BUS_NUM_FROM_CAN_NUM(can_number)); puts("\n"); - } -} - -void can_init_all(void) { - for (uint8_t i=0U; i < CAN_MAX; i++) { - can_init(i); - } -} - -void can_flip_buses(uint8_t bus1, uint8_t bus2){ - bus_lookup[bus1] = bus2; - bus_lookup[bus2] = bus1; - can_num_lookup[bus1] = bus2; - can_num_lookup[bus2] = bus1; -} - -// TODO: Cleanup with new abstraction -void can_set_gmlan(uint8_t bus) { - if(board_has_gmlan()){ - // first, disable GMLAN on prev bus - uint8_t prev_bus = can_num_lookup[3]; - if (bus != prev_bus) { - switch (prev_bus) { - case 1: - case 2: - puts("Disable GMLAN on CAN"); - puth(prev_bus + 1U); - puts("\n"); - current_board->set_can_mode(CAN_MODE_NORMAL); - bus_lookup[prev_bus] = prev_bus; - can_num_lookup[prev_bus] = prev_bus; - can_num_lookup[3] = -1; - can_init(prev_bus); - break; - default: - // GMLAN was not set on either BUS 1 or 2 - break; - } - } - - // now enable GMLAN on the new bus - switch (bus) { - case 1: - case 2: - puts("Enable GMLAN on CAN"); - puth(bus + 1U); - puts("\n"); - current_board->set_can_mode((bus == 1U) ? CAN_MODE_GMLAN_CAN2 : CAN_MODE_GMLAN_CAN3); - bus_lookup[bus] = 3; - can_num_lookup[bus] = -1; - can_num_lookup[3] = bus; - can_init(bus); - break; - case 0xFF: //-1 unsigned - break; - default: - puts("GMLAN can only be set on CAN2 or CAN3\n"); - break; - } - } else { - puts("GMLAN not available on black panda\n"); - } -} - -// TODO: remove -void can_set_obd(uint8_t harness_orientation, bool obd){ - if(obd){ - puts("setting CAN2 to be OBD\n"); - } else { - puts("setting CAN2 to be normal\n"); - } - if(board_has_obd()){ - if(obd != (bool)(harness_orientation == HARNESS_STATUS_NORMAL)){ - // B5,B6: disable normal mode - set_gpio_mode(GPIOB, 5, MODE_INPUT); - set_gpio_mode(GPIOB, 6, MODE_INPUT); - // B12,B13: CAN2 mode - set_gpio_alternate(GPIOB, 12, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 13, GPIO_AF9_CAN2); - } else { - // B5,B6: CAN2 mode - set_gpio_alternate(GPIOB, 5, GPIO_AF9_CAN2); - set_gpio_alternate(GPIOB, 6, GPIO_AF9_CAN2); - // B12,B13: disable normal mode - set_gpio_mode(GPIOB, 12, MODE_INPUT); - set_gpio_mode(GPIOB, 13, MODE_INPUT); - } - } else { - puts("OBD CAN not available on this board\n"); - } -} - -// CAN error -void can_sce(CAN_TypeDef *CAN) { - ENTER_CRITICAL(); - - #ifdef DEBUG - if (CAN==CAN1) puts("CAN1: "); - if (CAN==CAN2) puts("CAN2: "); - #ifdef CAN3 - if (CAN==CAN3) puts("CAN3: "); - #endif - puts("MSR:"); - puth(CAN->MSR); - puts(" TSR:"); - puth(CAN->TSR); - puts(" RF0R:"); - puth(CAN->RF0R); - puts(" RF1R:"); - puth(CAN->RF1R); - puts(" ESR:"); - puth(CAN->ESR); - puts("\n"); - #endif - - can_err_cnt += 1; - llcan_clear_send(CAN); - EXIT_CRITICAL(); -} - -// ***************************** CAN ***************************** - -void process_can(uint8_t can_number) { - if (can_number != 0xffU) { - - ENTER_CRITICAL(); - - CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); - uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); - - // check for empty mailbox - CAN_FIFOMailBox_TypeDef to_send; - if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { - // add successfully transmitted message to my fifo - if ((CAN->TSR & CAN_TSR_RQCP0) == CAN_TSR_RQCP0) { - can_txd_cnt += 1; - - if ((CAN->TSR & CAN_TSR_TXOK0) == CAN_TSR_TXOK0) { - CAN_FIFOMailBox_TypeDef to_push; - to_push.RIR = CAN->sTxMailBox[0].TIR; - to_push.RDTR = (CAN->sTxMailBox[0].TDTR & 0xFFFF000FU) | ((CAN_BUS_RET_FLAG | bus_number) << 4); - to_push.RDLR = CAN->sTxMailBox[0].TDLR; - to_push.RDHR = CAN->sTxMailBox[0].TDHR; - can_send_errs += can_push(&can_rx_q, &to_push) ? 0U : 1U; - } - - if ((CAN->TSR & CAN_TSR_TERR0) == CAN_TSR_TERR0) { - #ifdef DEBUG - puts("CAN TX ERROR!\n"); - #endif - } - - if ((CAN->TSR & CAN_TSR_ALST0) == CAN_TSR_ALST0) { - #ifdef DEBUG - puts("CAN TX ARBITRATION LOST!\n"); - #endif - } - - // clear interrupt - // careful, this can also be cleared by requesting a transmission - CAN->TSR |= CAN_TSR_RQCP0; - } - - if (can_pop(can_queues[bus_number], &to_send)) { - can_tx_cnt += 1; - // only send if we have received a packet - CAN->sTxMailBox[0].TDLR = to_send.RDLR; - CAN->sTxMailBox[0].TDHR = to_send.RDHR; - CAN->sTxMailBox[0].TDTR = to_send.RDTR; - CAN->sTxMailBox[0].TIR = to_send.RIR; - } - } - - EXIT_CRITICAL(); - } -} - -void ignition_can_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - int len = GET_LEN(to_push); - - ignition_can_cnt = 0U; // reset counter - - if (bus == 0) { - // GM exception - if ((addr == 0x1F1) && (len == 8)) { - //Bit 5 is ignition "on" - ignition_can = (GET_BYTE(to_push, 0) & 0x20) != 0; - } - // Tesla exception - if ((addr == 0x348) && (len == 8)) { - // GTW_status - ignition_can = (GET_BYTE(to_push, 0) & 0x1) != 0; - } - // Cadillac exception - if ((addr == 0x160) && (len == 5)) { - // this message isn't all zeros when ignition is on - ignition_can = GET_BYTES_04(to_push) != 0; - } - } -} - -// CAN receive handlers -// blink blue when we are receiving CAN messages -void can_rx(uint8_t can_number) { - CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); - uint8_t bus_number = BUS_NUM_FROM_CAN_NUM(can_number); - while ((CAN->RF0R & CAN_RF0R_FMP0) != 0) { - can_rx_cnt += 1; - - // can is live - pending_can_live = 1; - - // add to my fifo - CAN_FIFOMailBox_TypeDef to_push; - to_push.RIR = CAN->sFIFOMailBox[0].RIR; - to_push.RDTR = CAN->sFIFOMailBox[0].RDTR; - to_push.RDLR = CAN->sFIFOMailBox[0].RDLR; - to_push.RDHR = CAN->sFIFOMailBox[0].RDHR; - - // modify RDTR for our API - to_push.RDTR = (to_push.RDTR & 0xFFFF000F) | (bus_number << 4); - - // forwarding (panda only) - int bus_fwd_num = (can_forwarding[bus_number] != -1) ? can_forwarding[bus_number] : safety_fwd_hook(bus_number, &to_push); - if (bus_fwd_num != -1) { - CAN_FIFOMailBox_TypeDef to_send; - to_send.RIR = to_push.RIR | 1; // TXRQ - to_send.RDTR = to_push.RDTR; - to_send.RDLR = to_push.RDLR; - to_send.RDHR = to_push.RDHR; - can_send(&to_send, bus_fwd_num, true); - } - - safety_rx_hook(&to_push); - ignition_can_hook(&to_push); - - current_board->set_led(LED_BLUE, true); - can_send_errs += can_push(&can_rx_q, &to_push) ? 0U : 1U; - - // next - CAN->RF0R |= CAN_RF0R_RFOM0; - } -} - -void CAN1_TX_IRQ_Handler(void) { process_can(0); } -void CAN1_RX0_IRQ_Handler(void) { can_rx(0); } -void CAN1_SCE_IRQ_Handler(void) { can_sce(CAN1); } - -void CAN2_TX_IRQ_Handler(void) { process_can(1); } -void CAN2_RX0_IRQ_Handler(void) { can_rx(1); } -void CAN2_SCE_IRQ_Handler(void) { can_sce(CAN2); } - -void CAN3_TX_IRQ_Handler(void) { process_can(2); } -void CAN3_RX0_IRQ_Handler(void) { can_rx(2); } -void CAN3_SCE_IRQ_Handler(void) { can_sce(CAN3); } - -void can_send(CAN_FIFOMailBox_TypeDef *to_push, uint8_t bus_number, bool skip_tx_hook) { - if (skip_tx_hook || safety_tx_hook(to_push) != 0) { - if (bus_number < BUS_MAX) { - // add CAN packet to send queue - // bus number isn't passed through - to_push->RDTR &= 0xF; - if ((bus_number == 3U) && (can_num_lookup[3] == 0xFFU)) { - gmlan_send_errs += bitbang_gmlan(to_push) ? 0U : 1U; - } else { - can_fwd_errs += can_push(can_queues[bus_number], to_push) ? 0U : 1U; - process_can(CAN_NUM_FROM_BUS_NUM(bus_number)); - } - } - } -} - -void can_set_forwarding(int from, int to) { - can_forwarding[from] = to; -} - -void can_init(uint8_t can_number) { - REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN2_TX_IRQn, CAN2_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2) - REGISTER_INTERRUPT(CAN2_RX0_IRQn, CAN2_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2) - REGISTER_INTERRUPT(CAN2_SCE_IRQn, CAN2_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_2) - REGISTER_INTERRUPT(CAN3_TX_IRQn, CAN3_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3) - REGISTER_INTERRUPT(CAN3_RX0_IRQn, CAN3_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3) - REGISTER_INTERRUPT(CAN3_SCE_IRQn, CAN3_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_3) - - if (can_number != 0xffU) { - CAN_TypeDef *CAN = CANIF_FROM_CAN_NUM(can_number); - can_set_speed(can_number); - - llcan_init(CAN); - - // in case there are queued up messages - process_can(can_number); - } -} - diff --git a/panda/board/drivers/clock.h b/panda/board/drivers/clock.h deleted file mode 100644 index b75692438e..0000000000 --- a/panda/board/drivers/clock.h +++ /dev/null @@ -1,40 +0,0 @@ -void clock_init(void) { - // enable external oscillator - register_set_bits(&(RCC->CR), RCC_CR_HSEON); - while ((RCC->CR & RCC_CR_HSERDY) == 0); - - // divide things - register_set(&(RCC->CFGR), RCC_CFGR_HPRE_DIV1 | RCC_CFGR_PPRE2_DIV2 | RCC_CFGR_PPRE1_DIV4, 0xFF7FFCF3U); - - // 16mhz crystal - register_set(&(RCC->PLLCFGR), RCC_PLLCFGR_PLLQ_2 | RCC_PLLCFGR_PLLM_3 | RCC_PLLCFGR_PLLN_6 | RCC_PLLCFGR_PLLN_5 | RCC_PLLCFGR_PLLSRC_HSE, 0x7F437FFFU); - - // start PLL - register_set_bits(&(RCC->CR), RCC_CR_PLLON); - while ((RCC->CR & RCC_CR_PLLRDY) == 0); - - // Configure Flash prefetch, Instruction cache, Data cache and wait state - // *** without this, it breaks *** - register_set(&(FLASH->ACR), FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS, 0x1F0FU); - - // switch to PLL - register_set_bits(&(RCC->CFGR), RCC_CFGR_SW_PLL); - while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL); - - // *** running on PLL *** -} - -void watchdog_init(void) { - // setup watchdog - IWDG->KR = 0x5555U; - register_set(&(IWDG->PR), 0x0U, 0x7U); // divider/4 - - // 0 = 0.125 ms, let's have a 50ms watchdog - register_set(&(IWDG->RLR), (400U-1U), 0xFFFU); - IWDG->KR = 0xCCCCU; -} - -void watchdog_feed(void) { - IWDG->KR = 0xAAAAU; -} - diff --git a/panda/board/drivers/dac.h b/panda/board/drivers/dac.h deleted file mode 100644 index 4bdb16100c..0000000000 --- a/panda/board/drivers/dac.h +++ /dev/null @@ -1,20 +0,0 @@ -void puth(unsigned int i); -void puts(const char *a); - -void dac_init(void) { - // No buffers required since we have an opamp - register_set(&(DAC->DHR12R1), 0U, 0xFFFU); - register_set(&(DAC->DHR12R2), 0U, 0xFFFU); - register_set(&(DAC->CR), DAC_CR_EN1 | DAC_CR_EN2, 0x3FFF3FFFU); -} - -void dac_set(int channel, uint32_t value) { - if (channel == 0) { - register_set(&(DAC->DHR12R1), value, 0xFFFU); - } else if (channel == 1) { - register_set(&(DAC->DHR12R2), value, 0xFFFU); - } else { - puts("Failed to set DAC: invalid channel value: 0x"); puth(value); puts("\n"); - } -} - diff --git a/panda/board/drivers/fan.h b/panda/board/drivers/fan.h deleted file mode 100644 index 2f10e5ca8d..0000000000 --- a/panda/board/drivers/fan.h +++ /dev/null @@ -1,39 +0,0 @@ -void fan_set_power(uint8_t percentage){ - pwm_set(TIM3, 3, percentage); -} - -uint16_t fan_tach_counter = 0U; -uint16_t fan_rpm = 0U; - -// Can be way more acurate than this, but this is probably good enough for our purposes. - -// Call this every second -void fan_tick(void){ - // 4 interrupts per rotation - fan_rpm = fan_tach_counter * 15U; - fan_tach_counter = 0U; -} - -// TACH interrupt handler -void EXTI2_IRQ_Handler(void) { - volatile unsigned int pr = EXTI->PR & (1U << 2); - if ((pr & (1U << 2)) != 0U) { - fan_tach_counter++; - } - EXTI->PR = (1U << 2); -} - -void fan_init(void){ - // 5000RPM * 4 tach edges / 60 seconds - REGISTER_INTERRUPT(EXTI2_IRQn, EXTI2_IRQ_Handler, 700U, FAULT_INTERRUPT_RATE_TACH) - - // Init PWM speed control - pwm_init(TIM3, 3); - - // Init TACH interrupt - register_set(&(SYSCFG->EXTICR[0]), SYSCFG_EXTICR1_EXTI2_PD, 0xF00U); - register_set_bits(&(EXTI->IMR), (1U << 2)); - register_set_bits(&(EXTI->RTSR), (1U << 2)); - register_set_bits(&(EXTI->FTSR), (1U << 2)); - NVIC_EnableIRQ(EXTI2_IRQn); -} \ No newline at end of file diff --git a/panda/board/drivers/gmlan_alt.h b/panda/board/drivers/gmlan_alt.h deleted file mode 100644 index 6d4ba12b8c..0000000000 --- a/panda/board/drivers/gmlan_alt.h +++ /dev/null @@ -1,288 +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, 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 == last_bit) { - bit_cnt++; - if (bit_cnt == 5) { - // 5 in a row the same, do stuff - last_bit = !bit; - out[j] = last_bit; - j++; - bit_cnt = 1; - } - } else { - // this is a new bit - last_bit = 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, 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, CAN_FIFOMailBox_TypeDef *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 = to_bang->RDTR & 0xF; - len = append_int(pkt, len, 0, 1); // Start-of-frame - - if ((to_bang->RIR & 4) != 0) { - // extended identifier - len = append_int(pkt, len, to_bang->RIR >> 21, 11); // Identifier - len = append_int(pkt, len, 3, 2); // SRR+IDE - len = append_int(pkt, len, (to_bang->RIR >> 3) & ((1U << 18) - 1U), 18); // Identifier - len = append_int(pkt, len, 0, 3); // RTR+r1+r0 - } else { - // standard identifier - len = append_int(pkt, len, to_bang->RIR >> 21, 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++) { - unsigned char dat = ((unsigned char *)(&(to_bang->RDLR)))[i]; - len = append_int(pkt, len, dat, 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 setup_timer4(void) { - // setup - register_set(&(TIM4->PSC), (48-1), 0xFFFFU); // Tick on 1 us - register_set(&(TIM4->CR1), TIM_CR1_CEN, 0x3FU); // Enable - register_set(&(TIM4->ARR), (30-1), 0xFFFFU); // 33.3 kbps - - // in case it's disabled - NVIC_EnableIRQ(TIM4_IRQn); - - // run the interrupt - register_set(&(TIM4->DIER), TIM_DIER_UIE, 0x5F5FU); // Update interrupt - TIM4->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 gmlan_switch_init(int timeout_enable) { - gmlan_switch_timeout_enable = timeout_enable; - gmlan_alt_mode = GPIO_SWITCH; - gmlan_switch_below_timeout = 1; - set_gpio_mode(GPIOB, 13, MODE_OUTPUT); - - setup_timer4(); - - inverted_bit_to_send = GMLAN_LOW; //We got initialized, set the output low -} - -void set_gmlan_digital_output(int to_set) { - inverted_bit_to_send = to_set; - /* - puts("Writing "); - puth(inverted_bit_to_send); - puts("\n"); - */ -} - -void reset_gmlan_switch_timeout(void) { - can_timeout_counter = GMLAN_TICKS_PER_SECOND; - gmlan_switch_below_timeout = 1; - gmlan_alt_mode = GPIO_SWITCH; -} - -void set_bitbanged_gmlan(int val) { - if (val != 0) { - register_set_bits(&(GPIOB->ODR), (1U << 13)); - } else { - register_clear_bits(&(GPIOB->ODR), (1U << 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 TIM4_IRQ_Handler(void) { - if (gmlan_alt_mode == BITBANG) { - if ((TIM4->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] == 1)) && // bus wrongly dominant - (gmlan_sending != (gmlan_sendmax - 11))) { //not ack bit - puts("GMLAN ERR: bus driven at "); - puth(gmlan_sending); - puts("\n"); - retry = 1; - } else if ((read == 1) && (gmlan_sending == (gmlan_sendmax - 11))) { // recessive during ACK - puts("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) { - puts("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(&(TIM4->DIER), TIM_DIER_UIE); // No update interrupt - register_set(&(TIM4->CR1), 0U, 0x3FU); // Disable timer - gmlan_sendmax = -1; // exit - } - } - TIM4->SR = 0; - } else if (gmlan_alt_mode == GPIO_SWITCH) { - if ((TIM4->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--; - } - } - } - TIM4->SR = 0; - } else { - puts("invalid gmlan_alt_mode\n"); - } -} - -bool bitbang_gmlan(CAN_FIFOMailBox_TypeDef *to_bang) { - gmlan_send_ok = true; - gmlan_alt_mode = BITBANG; - - 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 - REGISTER_INTERRUPT(TIM4_IRQn, TIM4_IRQ_Handler, 40000U, FAULT_INTERRUPT_RATE_GMLAN) - setup_timer4(); - } - return gmlan_send_ok; -} - diff --git a/panda/board/drivers/harness.h b/panda/board/drivers/harness.h deleted file mode 100644 index c996bff0b2..0000000000 --- a/panda/board/drivers/harness.h +++ /dev/null @@ -1,105 +0,0 @@ -uint8_t car_harness_status = 0U; -#define HARNESS_STATUS_NC 0U -#define HARNESS_STATUS_NORMAL 1U -#define HARNESS_STATUS_FLIPPED 2U - -// Threshold voltage (mV) for either of the SBUs to be below before deciding harness is connected -#define HARNESS_CONNECTED_THRESHOLD 2500U - -struct harness_configuration { - const bool has_harness; - GPIO_TypeDef *GPIO_SBU1; - GPIO_TypeDef *GPIO_SBU2; - GPIO_TypeDef *GPIO_relay_normal; - GPIO_TypeDef *GPIO_relay_flipped; - uint8_t pin_SBU1; - uint8_t pin_SBU2; - uint8_t pin_relay_normal; - uint8_t pin_relay_flipped; - uint8_t adc_channel_SBU1; - uint8_t adc_channel_SBU2; -}; - -// this function will be the API for tici -void set_intercept_relay(bool intercept) { - if (car_harness_status != HARNESS_STATUS_NC) { - if (intercept) { - puts("switching harness to intercept (relay on)\n"); - } else { - puts("switching harness to passthrough (relay off)\n"); - } - - if(car_harness_status == HARNESS_STATUS_NORMAL){ - set_gpio_output(current_board->harness_config->GPIO_relay_normal, current_board->harness_config->pin_relay_normal, !intercept); - } else { - set_gpio_output(current_board->harness_config->GPIO_relay_flipped, current_board->harness_config->pin_relay_flipped, !intercept); - } - } -} - -bool harness_check_ignition(void) { - bool ret = false; - switch(car_harness_status){ - case HARNESS_STATUS_NORMAL: - ret = !get_gpio_input(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2); - break; - case HARNESS_STATUS_FLIPPED: - ret = !get_gpio_input(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1); - break; - default: - break; - } - return ret; -} - -uint8_t harness_detect_orientation(void) { - uint8_t ret = HARNESS_STATUS_NC; - - #ifndef BOOTSTUB - uint32_t sbu1_voltage = adc_get(current_board->harness_config->adc_channel_SBU1); - uint32_t sbu2_voltage = adc_get(current_board->harness_config->adc_channel_SBU2); - - // Detect connection and orientation - if((sbu1_voltage < HARNESS_CONNECTED_THRESHOLD) || (sbu2_voltage < HARNESS_CONNECTED_THRESHOLD)){ - if (sbu1_voltage < sbu2_voltage) { - // orientation normal - ret = HARNESS_STATUS_NORMAL; - } else { - // orientation flipped - ret = HARNESS_STATUS_FLIPPED; - } - } - #endif - - return ret; -} - -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 - uint8_t ret = harness_detect_orientation(); - if (ret != HARNESS_STATUS_NC) { - puts("detected car harness with orientation "); puth2(ret); puts("\n"); - car_harness_status = ret; - - // set the SBU lines to be inputs before using the relay. The lines are not 5V tolerant in ADC mode! - set_gpio_mode(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1, MODE_INPUT); - set_gpio_mode(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2, MODE_INPUT); - - // now we have orientation, set pin ignition detection - if(car_harness_status == HARNESS_STATUS_NORMAL){ - set_gpio_mode(current_board->harness_config->GPIO_SBU2, current_board->harness_config->pin_SBU2, MODE_INPUT); - } else { - set_gpio_mode(current_board->harness_config->GPIO_SBU1, current_board->harness_config->pin_SBU1, MODE_INPUT); - } - - // keep busses connected by default - set_intercept_relay(false); - } else { - puts("failed to detect car harness!\n"); - } -} diff --git a/panda/board/drivers/interrupts.h b/panda/board/drivers/interrupts.h deleted file mode 100644 index f15c441ab0..0000000000 --- a/panda/board/drivers/interrupts.h +++ /dev/null @@ -1,164 +0,0 @@ -typedef struct interrupt { - IRQn_Type irq_type; - void (*handler)(void); - uint32_t call_counter; - uint32_t max_call_rate; // Call rate is defined as the amount of calls each second - uint32_t call_rate_fault; -} interrupt; - -void unused_interrupt_handler(void) { - // Something is wrong if this handler is called! - puts("Unused interrupt handler called!\n"); - fault_occurred(FAULT_UNUSED_INTERRUPT_HANDLED); -} - -#define NUM_INTERRUPTS 102U // There are 102 external interrupt sources (see stm32f413.h) -interrupt interrupts[NUM_INTERRUPTS]; - -#define REGISTER_INTERRUPT(irq_num, func_ptr, call_rate, rate_fault) \ - interrupts[irq_num].irq_type = irq_num; \ - interrupts[irq_num].handler = func_ptr; \ - interrupts[irq_num].call_counter = 0U; \ - interrupts[irq_num].max_call_rate = call_rate; \ - interrupts[irq_num].call_rate_fault = rate_fault; - -bool check_interrupt_rate = false; - -void handle_interrupt(IRQn_Type irq_type){ - interrupts[irq_type].call_counter++; - interrupts[irq_type].handler(); - - // Check that the interrupts don't fire too often - if(check_interrupt_rate && (interrupts[irq_type].call_counter > interrupts[irq_type].max_call_rate)){ - puts("Interrupt 0x"); puth(irq_type); puts(" fired too often (0x"); puth(interrupts[irq_type].call_counter); puts("/s)!\n"); - fault_occurred(interrupts[irq_type].call_rate_fault); - } -} - -// Reset interrupt counter every second -void TIM6_DAC_IRQ_Handler(void) { - if (TIM6->SR != 0) { - for(uint16_t i=0U; iSR = 0; -} - -void init_interrupts(bool check_rate_limit){ - check_interrupt_rate = check_rate_limit; - - for(uint16_t i=0U; iAPB1ENR), RCC_APB1ENR_TIM6EN); // Enable interrupt timer peripheral - REGISTER_INTERRUPT(TIM6_DAC_IRQn, TIM6_DAC_IRQ_Handler, 1, FAULT_INTERRUPT_RATE_INTERRUPTS) - register_set(&(TIM6->PSC), (732-1), 0xFFFFU); - register_set(&(TIM6->DIER), TIM_DIER_UIE, 0x5F5FU); - register_set(&(TIM6->CR1), TIM_CR1_CEN, 0x3FU); - TIM6->SR = 0; - NVIC_EnableIRQ(TIM6_DAC_IRQn); -} - -// ********************* Bare interrupt handlers ********************* -// Only implemented the STM32F413 interrupts for now, the STM32F203 specific ones do not fall into the scope of SIL2 - -void WWDG_IRQHandler(void) {handle_interrupt(WWDG_IRQn);} -void PVD_IRQHandler(void) {handle_interrupt(PVD_IRQn);} -void TAMP_STAMP_IRQHandler(void) {handle_interrupt(TAMP_STAMP_IRQn);} -void RTC_WKUP_IRQHandler(void) {handle_interrupt(RTC_WKUP_IRQn);} -void FLASH_IRQHandler(void) {handle_interrupt(FLASH_IRQn);} -void RCC_IRQHandler(void) {handle_interrupt(RCC_IRQn);} -void EXTI0_IRQHandler(void) {handle_interrupt(EXTI0_IRQn);} -void EXTI1_IRQHandler(void) {handle_interrupt(EXTI1_IRQn);} -void EXTI2_IRQHandler(void) {handle_interrupt(EXTI2_IRQn);} -void EXTI3_IRQHandler(void) {handle_interrupt(EXTI3_IRQn);} -void EXTI4_IRQHandler(void) {handle_interrupt(EXTI4_IRQn);} -void DMA1_Stream0_IRQHandler(void) {handle_interrupt(DMA1_Stream0_IRQn);} -void DMA1_Stream1_IRQHandler(void) {handle_interrupt(DMA1_Stream1_IRQn);} -void DMA1_Stream2_IRQHandler(void) {handle_interrupt(DMA1_Stream2_IRQn);} -void DMA1_Stream3_IRQHandler(void) {handle_interrupt(DMA1_Stream3_IRQn);} -void DMA1_Stream4_IRQHandler(void) {handle_interrupt(DMA1_Stream4_IRQn);} -void DMA1_Stream5_IRQHandler(void) {handle_interrupt(DMA1_Stream5_IRQn);} -void DMA1_Stream6_IRQHandler(void) {handle_interrupt(DMA1_Stream6_IRQn);} -void ADC_IRQHandler(void) {handle_interrupt(ADC_IRQn);} -void CAN1_TX_IRQHandler(void) {handle_interrupt(CAN1_TX_IRQn);} -void CAN1_RX0_IRQHandler(void) {handle_interrupt(CAN1_RX0_IRQn);} -void CAN1_RX1_IRQHandler(void) {handle_interrupt(CAN1_RX1_IRQn);} -void CAN1_SCE_IRQHandler(void) {handle_interrupt(CAN1_SCE_IRQn);} -void EXTI9_5_IRQHandler(void) {handle_interrupt(EXTI9_5_IRQn);} -void TIM1_BRK_TIM9_IRQHandler(void) {handle_interrupt(TIM1_BRK_TIM9_IRQn);} -void TIM1_UP_TIM10_IRQHandler(void) {handle_interrupt(TIM1_UP_TIM10_IRQn);} -void TIM1_TRG_COM_TIM11_IRQHandler(void) {handle_interrupt(TIM1_TRG_COM_TIM11_IRQn);} -void TIM1_CC_IRQHandler(void) {handle_interrupt(TIM1_CC_IRQn);} -void TIM2_IRQHandler(void) {handle_interrupt(TIM2_IRQn);} -void TIM3_IRQHandler(void) {handle_interrupt(TIM3_IRQn);} -void TIM4_IRQHandler(void) {handle_interrupt(TIM4_IRQn);} -void I2C1_EV_IRQHandler(void) {handle_interrupt(I2C1_EV_IRQn);} -void I2C1_ER_IRQHandler(void) {handle_interrupt(I2C1_ER_IRQn);} -void I2C2_EV_IRQHandler(void) {handle_interrupt(I2C2_EV_IRQn);} -void I2C2_ER_IRQHandler(void) {handle_interrupt(I2C2_ER_IRQn);} -void SPI1_IRQHandler(void) {handle_interrupt(SPI1_IRQn);} -void SPI2_IRQHandler(void) {handle_interrupt(SPI2_IRQn);} -void USART1_IRQHandler(void) {handle_interrupt(USART1_IRQn);} -void USART2_IRQHandler(void) {handle_interrupt(USART2_IRQn);} -void USART3_IRQHandler(void) {handle_interrupt(USART3_IRQn);} -void EXTI15_10_IRQHandler(void) {handle_interrupt(EXTI15_10_IRQn);} -void RTC_Alarm_IRQHandler(void) {handle_interrupt(RTC_Alarm_IRQn);} -void OTG_FS_WKUP_IRQHandler(void) {handle_interrupt(OTG_FS_WKUP_IRQn);} -void TIM8_BRK_TIM12_IRQHandler(void) {handle_interrupt(TIM8_BRK_TIM12_IRQn);} -void TIM8_UP_TIM13_IRQHandler(void) {handle_interrupt(TIM8_UP_TIM13_IRQn);} -void TIM8_TRG_COM_TIM14_IRQHandler(void) {handle_interrupt(TIM8_TRG_COM_TIM14_IRQn);} -void TIM8_CC_IRQHandler(void) {handle_interrupt(TIM8_CC_IRQn);} -void DMA1_Stream7_IRQHandler(void) {handle_interrupt(DMA1_Stream7_IRQn);} -void FSMC_IRQHandler(void) {handle_interrupt(FSMC_IRQn);} -void SDIO_IRQHandler(void) {handle_interrupt(SDIO_IRQn);} -void TIM5_IRQHandler(void) {handle_interrupt(TIM5_IRQn);} -void SPI3_IRQHandler(void) {handle_interrupt(SPI3_IRQn);} -void UART4_IRQHandler(void) {handle_interrupt(UART4_IRQn);} -void UART5_IRQHandler(void) {handle_interrupt(UART5_IRQn);} -void TIM6_DAC_IRQHandler(void) {handle_interrupt(TIM6_DAC_IRQn);} -void TIM7_IRQHandler(void) {handle_interrupt(TIM7_IRQn);} -void DMA2_Stream0_IRQHandler(void) {handle_interrupt(DMA2_Stream0_IRQn);} -void DMA2_Stream1_IRQHandler(void) {handle_interrupt(DMA2_Stream1_IRQn);} -void DMA2_Stream2_IRQHandler(void) {handle_interrupt(DMA2_Stream2_IRQn);} -void DMA2_Stream3_IRQHandler(void) {handle_interrupt(DMA2_Stream3_IRQn);} -void DMA2_Stream4_IRQHandler(void) {handle_interrupt(DMA2_Stream4_IRQn);} -void CAN2_TX_IRQHandler(void) {handle_interrupt(CAN2_TX_IRQn);} -void CAN2_RX0_IRQHandler(void) {handle_interrupt(CAN2_RX0_IRQn);} -void CAN2_RX1_IRQHandler(void) {handle_interrupt(CAN2_RX1_IRQn);} -void CAN2_SCE_IRQHandler(void) {handle_interrupt(CAN2_SCE_IRQn);} -void OTG_FS_IRQHandler(void) {handle_interrupt(OTG_FS_IRQn);} -void DMA2_Stream5_IRQHandler(void) {handle_interrupt(DMA2_Stream5_IRQn);} -void DMA2_Stream6_IRQHandler(void) {handle_interrupt(DMA2_Stream6_IRQn);} -void DMA2_Stream7_IRQHandler(void) {handle_interrupt(DMA2_Stream7_IRQn);} -void USART6_IRQHandler(void) {handle_interrupt(USART6_IRQn);} -void I2C3_EV_IRQHandler(void) {handle_interrupt(I2C3_EV_IRQn);} -void I2C3_ER_IRQHandler(void) {handle_interrupt(I2C3_ER_IRQn);} -#ifdef STM32F4 - void DFSDM1_FLT0_IRQHandler(void) {handle_interrupt(DFSDM1_FLT0_IRQn);} - void DFSDM1_FLT1_IRQHandler(void) {handle_interrupt(DFSDM1_FLT1_IRQn);} - void CAN3_TX_IRQHandler(void) {handle_interrupt(CAN3_TX_IRQn);} - void CAN3_RX0_IRQHandler(void) {handle_interrupt(CAN3_RX0_IRQn);} - void CAN3_RX1_IRQHandler(void) {handle_interrupt(CAN3_RX1_IRQn);} - void CAN3_SCE_IRQHandler(void) {handle_interrupt(CAN3_SCE_IRQn);} - void RNG_IRQHandler(void) {handle_interrupt(RNG_IRQn);} - void FPU_IRQHandler(void) {handle_interrupt(FPU_IRQn);} - void UART7_IRQHandler(void) {handle_interrupt(UART7_IRQn);} - void UART8_IRQHandler(void) {handle_interrupt(UART8_IRQn);} - void SPI4_IRQHandler(void) {handle_interrupt(SPI4_IRQn);} - void SPI5_IRQHandler(void) {handle_interrupt(SPI5_IRQn);} - void SAI1_IRQHandler(void) {handle_interrupt(SAI1_IRQn);} - void UART9_IRQHandler(void) {handle_interrupt(UART9_IRQn);} - void UART10_IRQHandler(void) {handle_interrupt(UART10_IRQn);} - void QUADSPI_IRQHandler(void) {handle_interrupt(QUADSPI_IRQn);} - void FMPI2C1_EV_IRQHandler(void) {handle_interrupt(FMPI2C1_EV_IRQn);} - void FMPI2C1_ER_IRQHandler(void) {handle_interrupt(FMPI2C1_ER_IRQn);} - void LPTIM1_IRQHandler(void) {handle_interrupt(LPTIM1_IRQn);} - void DFSDM2_FLT0_IRQHandler(void) {handle_interrupt(DFSDM2_FLT0_IRQn);} - void DFSDM2_FLT1_IRQHandler(void) {handle_interrupt(DFSDM2_FLT1_IRQn);} - void DFSDM2_FLT2_IRQHandler(void) {handle_interrupt(DFSDM2_FLT2_IRQn);} - void DFSDM2_FLT3_IRQHandler(void) {handle_interrupt(DFSDM2_FLT3_IRQn);} -#endif \ No newline at end of file diff --git a/panda/board/drivers/llcan.h b/panda/board/drivers/llcan.h deleted file mode 100644 index 4cd9b4b5ab..0000000000 --- a/panda/board/drivers/llcan.h +++ /dev/null @@ -1,98 +0,0 @@ -// this is needed for 1 mbps support -#define CAN_QUANTA 8U -#define CAN_SEQ1 6 // roundf(quanta * 0.875f) - 1; -#define CAN_SEQ2 1 // roundf(quanta * 0.125f); - -#define CAN_PCLK 24000U -// 333 = 33.3 kbps -// 5000 = 500 kbps -#define can_speed_to_prescaler(x) (CAN_PCLK / CAN_QUANTA * 10U / (x)) - -#define GET_BUS(msg) (((msg)->RDTR >> 4) & 0xFF) -#define GET_LEN(msg) ((msg)->RDTR & 0xF) -#define GET_ADDR(msg) ((((msg)->RIR & 4) != 0) ? ((msg)->RIR >> 3) : ((msg)->RIR >> 21)) -#define GET_BYTE(msg, b) (((int)(b) > 3) ? (((msg)->RDHR >> (8U * ((unsigned int)(b) % 4U))) & 0XFFU) : (((msg)->RDLR >> (8U * (unsigned int)(b))) & 0xFFU)) -#define GET_BYTES_04(msg) ((msg)->RDLR) -#define GET_BYTES_48(msg) ((msg)->RDHR) - -void puts(const char *a); - -bool llcan_set_speed(CAN_TypeDef *CAN_obj, uint32_t speed, bool loopback, bool silent) { - // initialization mode - register_set(&(CAN_obj->MCR), CAN_MCR_TTCM | CAN_MCR_INRQ, 0x180FFU); - while((CAN_obj->MSR & CAN_MSR_INAK) != CAN_MSR_INAK); - - // set time quanta from defines - register_set(&(CAN_obj->BTR), ((CAN_BTR_TS1_0 * (CAN_SEQ1-1)) | - (CAN_BTR_TS2_0 * (CAN_SEQ2-1)) | - (can_speed_to_prescaler(speed) - 1U)), 0xC37F03FFU); - - // silent loopback mode for debugging - if (loopback) { - register_set_bits(&(CAN_obj->BTR), CAN_BTR_SILM | CAN_BTR_LBKM); - } - if (silent) { - register_set_bits(&(CAN_obj->BTR), CAN_BTR_SILM); - } - - // reset - register_set(&(CAN_obj->MCR), CAN_MCR_TTCM | CAN_MCR_ABOM, 0x180FFU); - - #define CAN_TIMEOUT 1000000 - int tmp = 0; - bool ret = false; - while(((CAN_obj->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (tmp < CAN_TIMEOUT)) tmp++; - if (tmp < CAN_TIMEOUT) { - ret = true; - } - - return ret; -} - -void llcan_init(CAN_TypeDef *CAN_obj) { - // Enter init mode - register_set_bits(&(CAN_obj->FMR), CAN_FMR_FINIT); - - // Wait for INAK bit to be set - while(((CAN_obj->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)) {} - - // no mask - // For some weird reason some of these registers do not want to set properly on CAN2 and CAN3. Probably something to do with the single/dual mode and their different filters. - CAN_obj->sFilterRegister[0].FR1 = 0U; - CAN_obj->sFilterRegister[0].FR2 = 0U; - CAN_obj->sFilterRegister[14].FR1 = 0U; - CAN_obj->sFilterRegister[14].FR2 = 0U; - CAN_obj->FA1R |= 1U | (1U << 14); - - // Exit init mode, do not wait - register_clear_bits(&(CAN_obj->FMR), CAN_FMR_FINIT); - - // enable certain CAN interrupts - register_set_bits(&(CAN_obj->IER), CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_WKUIE); - - if (CAN_obj == CAN1) { - NVIC_EnableIRQ(CAN1_TX_IRQn); - NVIC_EnableIRQ(CAN1_RX0_IRQn); - NVIC_EnableIRQ(CAN1_SCE_IRQn); - } else if (CAN_obj == CAN2) { - NVIC_EnableIRQ(CAN2_TX_IRQn); - NVIC_EnableIRQ(CAN2_RX0_IRQn); - NVIC_EnableIRQ(CAN2_SCE_IRQn); -#ifdef CAN3 - } else if (CAN_obj == CAN3) { - NVIC_EnableIRQ(CAN3_TX_IRQn); - NVIC_EnableIRQ(CAN3_RX0_IRQn); - NVIC_EnableIRQ(CAN3_SCE_IRQn); -#endif - } else { - puts("Invalid CAN: initialization failed\n"); - } -} - -void llcan_clear_send(CAN_TypeDef *CAN_obj) { - CAN_obj->TSR |= CAN_TSR_ABRQ0; - register_clear_bits(&(CAN_obj->MSR), CAN_MSR_ERRI); - // cppcheck-suppress selfAssignment ; needed to clear the register - CAN_obj->MSR = CAN_obj->MSR; -} - diff --git a/panda/board/drivers/llgpio.h b/panda/board/drivers/llgpio.h deleted file mode 100644 index 0bd58c3b8a..0000000000 --- a/panda/board/drivers/llgpio.h +++ /dev/null @@ -1,65 +0,0 @@ -#define MODE_INPUT 0 -#define MODE_OUTPUT 1 -#define MODE_ALTERNATE 2 -#define MODE_ANALOG 3 - -#define PULL_NONE 0 -#define PULL_UP 1 -#define PULL_DOWN 2 - -#define OUTPUT_TYPE_PUSH_PULL 0U -#define OUTPUT_TYPE_OPEN_DRAIN 1U - -void set_gpio_mode(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { - ENTER_CRITICAL(); - uint32_t tmp = GPIO->MODER; - tmp &= ~(3U << (pin * 2U)); - tmp |= (mode << (pin * 2U)); - register_set(&(GPIO->MODER), tmp, 0xFFFFFFFFU); - EXIT_CRITICAL(); -} - -void set_gpio_output(GPIO_TypeDef *GPIO, unsigned int pin, bool enabled) { - ENTER_CRITICAL(); - if (enabled) { - register_set_bits(&(GPIO->ODR), (1U << pin)); - } else { - register_clear_bits(&(GPIO->ODR), (1U << pin)); - } - set_gpio_mode(GPIO, pin, MODE_OUTPUT); - EXIT_CRITICAL(); -} - -void set_gpio_output_type(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int output_type){ - ENTER_CRITICAL(); - if(output_type == OUTPUT_TYPE_OPEN_DRAIN) { - register_set_bits(&(GPIO->OTYPER), (1U << pin)); - } else { - register_clear_bits(&(GPIO->OTYPER), (1U << pin)); - } - EXIT_CRITICAL(); -} - -void set_gpio_alternate(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { - ENTER_CRITICAL(); - uint32_t tmp = GPIO->AFR[pin >> 3U]; - tmp &= ~(0xFU << ((pin & 7U) * 4U)); - tmp |= mode << ((pin & 7U) * 4U); - register_set(&(GPIO->AFR[pin >> 3]), tmp, 0xFFFFFFFFU); - set_gpio_mode(GPIO, pin, MODE_ALTERNATE); - EXIT_CRITICAL(); -} - -void set_gpio_pullup(GPIO_TypeDef *GPIO, unsigned int pin, unsigned int mode) { - ENTER_CRITICAL(); - uint32_t tmp = GPIO->PUPDR; - tmp &= ~(3U << (pin * 2U)); - tmp |= (mode << (pin * 2U)); - register_set(&(GPIO->PUPDR), tmp, 0xFFFFFFFFU); - EXIT_CRITICAL(); -} - -int get_gpio_input(GPIO_TypeDef *GPIO, unsigned int pin) { - return (GPIO->IDR & (1U << pin)) == (1U << pin); -} - diff --git a/panda/board/drivers/pwm.h b/panda/board/drivers/pwm.h deleted file mode 100644 index c3709200c1..0000000000 --- a/panda/board/drivers/pwm.h +++ /dev/null @@ -1,56 +0,0 @@ -#define PWM_COUNTER_OVERFLOW 2000U // To get ~50kHz - -// TODO: Implement for 32-bit timers - -void pwm_init(TIM_TypeDef *TIM, uint8_t channel){ - // Enable timer and auto-reload - register_set(&(TIM->CR1), TIM_CR1_CEN | TIM_CR1_ARPE, 0x3FU); - - // Set channel as PWM mode 1 and enable output - switch(channel){ - case 1U: - register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC1M_2 | TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC1E); - break; - case 2U: - register_set_bits(&(TIM->CCMR1), (TIM_CCMR1_OC2M_2 | TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC2E); - break; - case 3U: - register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC3M_2 | TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC3E); - break; - case 4U: - register_set_bits(&(TIM->CCMR2), (TIM_CCMR2_OC4M_2 | TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4PE)); - register_set_bits(&(TIM->CCER), TIM_CCER_CC4E); - break; - default: - break; - } - - // Set max counter value - register_set(&(TIM->ARR), PWM_COUNTER_OVERFLOW, 0xFFFFU); - - // Update registers and clear counter - TIM->EGR |= TIM_EGR_UG; -} - -void pwm_set(TIM_TypeDef *TIM, uint8_t channel, uint8_t percentage){ - uint16_t comp_value = (((uint16_t) percentage * PWM_COUNTER_OVERFLOW) / 100U); - switch(channel){ - case 1U: - register_set(&(TIM->CCR1), comp_value, 0xFFFFU); - break; - case 2U: - register_set(&(TIM->CCR2), comp_value, 0xFFFFU); - break; - case 3U: - register_set(&(TIM->CCR3), comp_value, 0xFFFFU); - break; - case 4U: - register_set(&(TIM->CCR4), comp_value, 0xFFFFU); - break; - default: - break; - } -} \ No newline at end of file diff --git a/panda/board/drivers/registers.h b/panda/board/drivers/registers.h deleted file mode 100644 index 76748295d9..0000000000 --- a/panda/board/drivers/registers.h +++ /dev/null @@ -1,81 +0,0 @@ - -typedef struct reg { - volatile uint32_t *address; - uint32_t value; - uint32_t check_mask; -} reg; - -// 10 bit hash with 23 as a prime -#define REGISTER_MAP_SIZE 0x3FFU -#define HASHING_PRIME 23U -#define CHECK_COLLISION(hash, addr) (((uint32_t) register_map[hash].address != 0U) && (register_map[hash].address != addr)) - -reg register_map[REGISTER_MAP_SIZE]; - -// Hash spread in first and second iterations seems to be reasonable. -// See: tests/development/register_hashmap_spread.py -// Also, check the collision warnings in the debug output, and minimize those. -uint16_t hash_addr(uint32_t input){ - return (((input >> 16U) ^ ((((input + 1U) & 0xFFFFU) * HASHING_PRIME) & 0xFFFFU)) & REGISTER_MAP_SIZE); -} - -// Do not put bits in the check mask that get changed by the hardware -void register_set(volatile uint32_t *addr, uint32_t val, uint32_t mask){ - ENTER_CRITICAL() - // Set bits in register that are also in the mask - (*addr) = ((*addr) & (~mask)) | (val & mask); - - // Add these values to the map - uint16_t hash = hash_addr((uint32_t) addr); - uint16_t tries = REGISTER_MAP_SIZE; - while(CHECK_COLLISION(hash, addr) && (tries > 0U)) { hash = hash_addr((uint32_t) hash); tries--;} - if (tries != 0U){ - register_map[hash].address = addr; - register_map[hash].value = (register_map[hash].value & (~mask)) | (val & mask); - register_map[hash].check_mask |= mask; - } else { - #ifdef DEBUG_FAULTS - puts("Hash collision: address 0x"); puth((uint32_t) addr); puts("!\n"); - #endif - } - EXIT_CRITICAL() -} - -// 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); -} - -// 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); -} - -// To be called periodically -void check_registers(void){ - for(uint16_t i=0U; i> 4U) * 10U) + (value & 0x0FU); -} - -void rtc_init(void){ - if(board_has_rtc()){ - // Initialize RTC module and clock if not done already. - if((RCC->BDCR & RCC_BDCR_MASK) != RCC_BDCR_OPTIONS){ - puts("Initializing RTC\n"); - // Reset backup domain - register_set_bits(&(RCC->BDCR), RCC_BDCR_BDRST); - - // Disable write protection - register_set_bits(&(PWR->CR), PWR_CR_DBP); - - // Clear backup domain reset - register_clear_bits(&(RCC->BDCR), RCC_BDCR_BDRST); - - // Set RTC options - register_set(&(RCC->BDCR), RCC_BDCR_OPTIONS, RCC_BDCR_MASK); - - // Enable write protection - register_clear_bits(&(PWR->CR), PWR_CR_DBP); - } - } -} - -void rtc_set_time(timestamp_t time){ - if(board_has_rtc()){ - puts("Setting RTC time\n"); - - // Disable write protection - register_set_bits(&(PWR->CR), PWR_CR_DBP); - 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; - register_clear_bits(&(PWR->CR), PWR_CR_DBP); - } -} - -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; - - if(board_has_rtc()){ - // 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; -} \ No newline at end of file diff --git a/panda/board/drivers/spi.h b/panda/board/drivers/spi.h deleted file mode 100644 index 29963b6bdf..0000000000 --- a/panda/board/drivers/spi.h +++ /dev/null @@ -1,131 +0,0 @@ -// IRQs: DMA2_Stream2, DMA2_Stream3, EXTI4 - -void spi_init(void); -int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out); - -// end API - -#define SPI_BUF_SIZE 256 -uint8_t spi_buf[SPI_BUF_SIZE]; -int spi_buf_count = 0; -int spi_total_count = 0; - -void spi_tx_dma(void *addr, int len) { - // disable DMA - register_clear_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN); - register_clear_bits(&(DMA2_Stream3->CR), DMA_SxCR_EN); - - // DMA2, stream 3, channel 3 - register_set(&(DMA2_Stream3->M0AR), (uint32_t)addr, 0xFFFFFFFFU); - DMA2_Stream3->NDTR = len; - register_set(&(DMA2_Stream3->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU); - - // channel3, increment memory, memory -> periph, enable - register_set(&(DMA2_Stream3->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_DIR_0 | DMA_SxCR_EN), 0x1E077EFEU); - delay(0); - register_set_bits(&(DMA2_Stream3->CR), DMA_SxCR_TCIE); - - register_set_bits(&(SPI1->CR2), SPI_CR2_TXDMAEN); - - // signal data is ready by driving low - // esp must be configured as input by this point - set_gpio_output(GPIOB, 0, 0); -} - -void spi_rx_dma(void *addr, int len) { - // disable DMA - register_clear_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN); - register_clear_bits(&(DMA2_Stream2->CR), DMA_SxCR_EN); - - // drain the bus - volatile uint8_t dat = SPI1->DR; - (void)dat; - - // DMA2, stream 2, channel 3 - register_set(&(DMA2_Stream2->M0AR), (uint32_t)addr, 0xFFFFFFFFU); - DMA2_Stream2->NDTR = len; - register_set(&(DMA2_Stream2->PAR), (uint32_t)&(SPI1->DR), 0xFFFFFFFFU); - - // channel3, increment memory, periph -> memory, enable - register_set(&(DMA2_Stream2->CR), (DMA_SxCR_CHSEL_1 | DMA_SxCR_CHSEL_0 | DMA_SxCR_MINC | DMA_SxCR_EN), 0x1E077EFEU); - delay(0); - register_set_bits(&(DMA2_Stream2->CR), DMA_SxCR_TCIE); - - register_set_bits(&(SPI1->CR2), SPI_CR2_RXDMAEN); -} - -// ***************************** SPI IRQs ***************************** -// can't go on the stack cause it's DMAed -uint8_t spi_tx_buf[0x44]; - -// SPI RX -void DMA2_Stream2_IRQ_Handler(void) { - int *resp_len = (int*)spi_tx_buf; - (void)memset(spi_tx_buf, 0xaa, 0x44); - *resp_len = spi_cb_rx(spi_buf, 0x14, spi_tx_buf+4); - #ifdef DEBUG_SPI - puts("SPI write: "); - puth(*resp_len); - puts("\n"); - #endif - spi_tx_dma(spi_tx_buf, *resp_len + 4); - - // ack - DMA2->LIFCR = DMA_LIFCR_CTCIF2; -} - -// SPI TX -void DMA2_Stream3_IRQ_Handler(void) { - #ifdef DEBUG_SPI - puts("SPI handshake\n"); - #endif - - // reset handshake back to pull up - set_gpio_mode(GPIOB, 0, MODE_INPUT); - set_gpio_pullup(GPIOB, 0, PULL_UP); - - // ack - DMA2->LIFCR = DMA_LIFCR_CTCIF3; -} - -void EXTI4_IRQ_Handler(void) { - volatile unsigned int pr = EXTI->PR & (1U << 4); - #ifdef DEBUG_SPI - puts("exti4\n"); - #endif - // SPI CS falling - if ((pr & (1U << 4)) != 0U) { - spi_total_count = 0; - spi_rx_dma(spi_buf, 0x14); - } - EXTI->PR = pr; -} - -// ***************************** SPI init ***************************** -void spi_init(void) { - // Max SPI clock the ESP can produce is 80MHz. At buffer size of 256 bytes, that's a max of about 40k buffers per second - REGISTER_INTERRUPT(DMA2_Stream2_IRQn, DMA2_Stream2_IRQ_Handler, 50000U, FAULT_INTERRUPT_RATE_SPI_DMA) - REGISTER_INTERRUPT(DMA2_Stream3_IRQn, DMA2_Stream3_IRQ_Handler, 50000U, FAULT_INTERRUPT_RATE_SPI_DMA) - REGISTER_INTERRUPT(EXTI4_IRQn, EXTI4_IRQ_Handler, 50000U, FAULT_INTERRUPT_RATE_SPI_CS) // TODO: Figure out if this is a reasonable limit - - //puts("SPI init\n"); - register_set(&(SPI1->CR1), SPI_CR1_SPE, 0xFFFFU); - - // enable SPI interrupts - //SPI1->CR2 = SPI_CR2_RXNEIE | SPI_CR2_ERRIE | SPI_CR2_TXEIE; - register_set(&(SPI1->CR2), SPI_CR2_RXNEIE, 0xF7U); - - NVIC_EnableIRQ(DMA2_Stream2_IRQn); - NVIC_EnableIRQ(DMA2_Stream3_IRQn); - //NVIC_EnableIRQ(SPI1_IRQn); - - // reset handshake back to pull up - set_gpio_mode(GPIOB, 0, MODE_INPUT); - set_gpio_pullup(GPIOB, 0, PULL_UP); - - // setup interrupt on falling edge of SPI enable (on PA4) - register_set(&(SYSCFG->EXTICR[2]), SYSCFG_EXTICR2_EXTI4_PA, 0xFFFFU); - register_set_bits(&(EXTI->IMR), (1U << 4)); - register_set_bits(&(EXTI->FTSR), (1U << 4)); - NVIC_EnableIRQ(EXTI4_IRQn); -} \ No newline at end of file diff --git a/panda/board/drivers/timer.h b/panda/board/drivers/timer.h deleted file mode 100644 index d7aa7e8811..0000000000 --- a/panda/board/drivers/timer.h +++ /dev/null @@ -1,7 +0,0 @@ -void timer_init(TIM_TypeDef *TIM, int psc) { - register_set(&(TIM->PSC), (psc-1), 0xFFFFU); - register_set(&(TIM->DIER), TIM_DIER_UIE, 0x5F5FU); - register_set(&(TIM->CR1), TIM_CR1_CEN, 0x3FU); - TIM->SR = 0; -} - diff --git a/panda/board/drivers/uart.h b/panda/board/drivers/uart.h deleted file mode 100644 index da45803001..0000000000 --- a/panda/board/drivers/uart.h +++ /dev/null @@ -1,440 +0,0 @@ -// IRQs: USART1, USART2, USART3, UART5 - -// ***************************** Definitions ***************************** -#define FIFO_SIZE_INT 0x400U -#define FIFO_SIZE_DMA 0x1000U - -typedef struct uart_ring { - volatile uint16_t w_ptr_tx; - volatile uint16_t r_ptr_tx; - uint8_t *elems_tx; - uint32_t tx_fifo_size; - volatile uint16_t w_ptr_rx; - volatile uint16_t r_ptr_rx; - uint8_t *elems_rx; - uint32_t rx_fifo_size; - USART_TypeDef *uart; - void (*callback)(struct uart_ring*); - bool dma_rx; -} uart_ring; - -#define UART_BUFFER(x, size_rx, size_tx, uart_ptr, callback_ptr, rx_dma) \ - uint8_t elems_rx_##x[size_rx]; \ - uint8_t elems_tx_##x[size_tx]; \ - uart_ring uart_ring_##x = { \ - .w_ptr_tx = 0, \ - .r_ptr_tx = 0, \ - .elems_tx = ((uint8_t *)&elems_tx_##x), \ - .tx_fifo_size = size_tx, \ - .w_ptr_rx = 0, \ - .r_ptr_rx = 0, \ - .elems_rx = ((uint8_t *)&elems_rx_##x), \ - .rx_fifo_size = size_rx, \ - .uart = uart_ptr, \ - .callback = callback_ptr, \ - .dma_rx = rx_dma \ - }; - - -// ***************************** Function prototypes ***************************** -void uart_init(uart_ring *q, int baud); - -bool getc(uart_ring *q, char *elem); -bool putc(uart_ring *q, char elem); - -void puts(const char *a); -void puth(unsigned int i); -void hexdump(const void *a, int l); - -void debug_ring_callback(uart_ring *ring); - -// ******************************** UART buffers ******************************** - -// esp_gps = USART1 -UART_BUFFER(esp_gps, FIFO_SIZE_DMA, FIFO_SIZE_INT, USART1, NULL, true) - -// lin1, K-LINE = UART5 -// lin2, L-LINE = USART3 -UART_BUFFER(lin1, FIFO_SIZE_INT, FIFO_SIZE_INT, UART5, NULL, false) -UART_BUFFER(lin2, FIFO_SIZE_INT, FIFO_SIZE_INT, USART3, NULL, false) - -// debug = USART2 -UART_BUFFER(debug, FIFO_SIZE_INT, FIFO_SIZE_INT, USART2, debug_ring_callback, false) - -uart_ring *get_ring_by_number(int a) { - uart_ring *ring = NULL; - switch(a) { - case 0: - ring = &uart_ring_debug; - break; - case 1: - ring = &uart_ring_esp_gps; - break; - case 2: - ring = &uart_ring_lin1; - break; - case 3: - ring = &uart_ring_lin2; - break; - default: - ring = NULL; - break; - } - return ring; -} - -// ***************************** Interrupt handlers ***************************** - -void uart_tx_ring(uart_ring *q){ - ENTER_CRITICAL(); - // 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) { - 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; - } - - // Enable TXE interrupt if there is still data to be sent - if(q->r_ptr_tx != q->w_ptr_tx){ - q->uart->CR1 |= USART_CR1_TXEIE; - } else { - q->uart->CR1 &= ~USART_CR1_TXEIE; - } - } - EXIT_CRITICAL(); -} - -void uart_rx_ring(uart_ring *q){ - // Do not read out directly if DMA enabled - if (q->dma_rx == false) { - ENTER_CRITICAL(); - - // Read out RX buffer - uint8_t c = q->uart->DR; // This read after reading SR clears a bunch of interrupts - - uint16_t next_w_ptr = (q->w_ptr_rx + 1U) % q->rx_fifo_size; - // Do not overwrite buffer data - if (next_w_ptr != q->r_ptr_rx) { - q->elems_rx[q->w_ptr_rx] = c; - q->w_ptr_rx = next_w_ptr; - if (q->callback != NULL) { - q->callback(q); - } - } - - EXIT_CRITICAL(); - } -} - -// This function should be called on: -// * Half-transfer DMA interrupt -// * Full-transfer DMA interrupt -// * UART IDLE detection -uint32_t prev_w_index = 0; -void dma_pointer_handler(uart_ring *q, uint32_t dma_ndtr) { - ENTER_CRITICAL(); - uint32_t w_index = (q->rx_fifo_size - dma_ndtr); - - // Check for new data - if (w_index != prev_w_index){ - // Check for overflow - if ( - ((prev_w_index < q->r_ptr_rx) && (q->r_ptr_rx <= w_index)) || // No rollover - ((w_index < prev_w_index) && ((q->r_ptr_rx <= w_index) || (prev_w_index < q->r_ptr_rx))) // Rollover - ){ - // We lost data. Set the new read pointer to the oldest byte still available - q->r_ptr_rx = (w_index + 1U) % q->rx_fifo_size; - } - - // Set write pointer - q->w_ptr_rx = w_index; - } - - prev_w_index = w_index; - EXIT_CRITICAL(); -} - -// This read after reading SR clears all error interrupts. We don't want compiler warnings, nor optimizations -#define UART_READ_DR(uart) volatile uint8_t t = (uart)->DR; UNUSED(t); - -void uart_interrupt_handler(uart_ring *q) { - ENTER_CRITICAL(); - - // Read UART status. This is also the first step necessary in clearing most interrupts - uint32_t status = q->uart->SR; - - // If RXNE is set, perform a read. This clears RXNE, ORE, IDLE, NF and FE - if((status & USART_SR_RXNE) != 0U){ - uart_rx_ring(q); - } - - // Detect errors and clear them - uint32_t err = (status & USART_SR_ORE) | (status & USART_SR_NE) | (status & USART_SR_FE) | (status & USART_SR_PE); - if(err != 0U){ - #ifdef DEBUG_UART - puts("Encountered UART error: "); puth(err); puts("\n"); - #endif - UART_READ_DR(q->uart) - } - // Send if necessary - uart_tx_ring(q); - - // Run DMA pointer handler if the line is idle - if(q->dma_rx && (status & USART_SR_IDLE)){ - // Reset IDLE flag - UART_READ_DR(q->uart) - - if(q == &uart_ring_esp_gps){ - dma_pointer_handler(&uart_ring_esp_gps, DMA2_Stream5->NDTR); - } else { - #ifdef DEBUG_UART - puts("No IDLE dma_pointer_handler implemented for this UART."); - #endif - } - } - - EXIT_CRITICAL(); -} - -void USART1_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_esp_gps); } -void USART2_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_debug); } -void USART3_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin2); } -void UART5_IRQ_Handler(void) { uart_interrupt_handler(&uart_ring_lin1); } - -void DMA2_Stream5_IRQ_Handler(void) { - ENTER_CRITICAL(); - - // Handle errors - if((DMA2->HISR & DMA_HISR_TEIF5) || (DMA2->HISR & DMA_HISR_DMEIF5) || (DMA2->HISR & DMA_HISR_FEIF5)){ - #ifdef DEBUG_UART - puts("Encountered UART DMA error. Clearing and restarting DMA...\n"); - #endif - - // Clear flags - DMA2->HIFCR = DMA_HIFCR_CTEIF5 | DMA_HIFCR_CDMEIF5 | DMA_HIFCR_CFEIF5; - - // Re-enable the DMA if necessary - DMA2_Stream5->CR |= DMA_SxCR_EN; - } - - // Re-calculate write pointer and reset flags - dma_pointer_handler(&uart_ring_esp_gps, DMA2_Stream5->NDTR); - DMA2->HIFCR = DMA_HIFCR_CTCIF5 | DMA_HIFCR_CHTIF5; - - EXIT_CRITICAL(); -} - -// ***************************** Hardware setup ***************************** - -void dma_rx_init(uart_ring *q) { - // Initialization is UART-dependent - if(q == &uart_ring_esp_gps){ - // DMA2, stream 5, channel 4 - - // Disable FIFO mode (enable direct) - DMA2_Stream5->FCR &= ~DMA_SxFCR_DMDIS; - - // Setup addresses - DMA2_Stream5->PAR = (uint32_t)&(USART1->DR); // Source - DMA2_Stream5->M0AR = (uint32_t)q->elems_rx; // Destination - DMA2_Stream5->NDTR = q->rx_fifo_size; // Number of bytes to copy - - // Circular, Increment memory, byte size, periph -> memory, enable - // Transfer complete, half transfer, transfer error and direct mode error interrupt enable - DMA2_Stream5->CR = DMA_SxCR_CHSEL_2 | DMA_SxCR_MINC | DMA_SxCR_CIRC | DMA_SxCR_HTIE | DMA_SxCR_TCIE | DMA_SxCR_TEIE | DMA_SxCR_DMEIE | DMA_SxCR_EN; - - // Enable DMA receiver in UART - q->uart->CR3 |= USART_CR3_DMAR; - - // Enable UART IDLE interrupt - q->uart->CR1 |= USART_CR1_IDLEIE; - - // Enable interrupt - NVIC_EnableIRQ(DMA2_Stream5_IRQn); - } else { - puts("Tried to initialize RX DMA for an unsupported UART\n"); - } -} - -#define __DIV(_PCLK_, _BAUD_) (((_PCLK_) * 25U) / (4U * (_BAUD_))) -#define __DIVMANT(_PCLK_, _BAUD_) (__DIV((_PCLK_), (_BAUD_)) / 100U) -#define __DIVFRAQ(_PCLK_, _BAUD_) ((((__DIV((_PCLK_), (_BAUD_)) - (__DIVMANT((_PCLK_), (_BAUD_)) * 100U)) * 16U) + 50U) / 100U) -#define __USART_BRR(_PCLK_, _BAUD_) ((__DIVMANT((_PCLK_), (_BAUD_)) << 4) | (__DIVFRAQ((_PCLK_), (_BAUD_)) & 0x0FU)) - -void uart_set_baud(USART_TypeDef *u, unsigned int baud) { - if (u == USART1) { - // USART1 is on APB2 - u->BRR = __USART_BRR(48000000U, baud); - } else { - u->BRR = __USART_BRR(24000000U, baud); - } -} - -void uart_init(uart_ring *q, int baud) { - // Register interrupts (max data rate: 115200 baud) - REGISTER_INTERRUPT(USART1_IRQn, USART1_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_1) - REGISTER_INTERRUPT(USART2_IRQn, USART2_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_2) - REGISTER_INTERRUPT(USART3_IRQn, USART3_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_3) - REGISTER_INTERRUPT(UART5_IRQn, UART5_IRQ_Handler, 150000U, FAULT_INTERRUPT_RATE_UART_5) - REGISTER_INTERRUPT(DMA2_Stream5_IRQn, DMA2_Stream5_IRQ_Handler, 100U, FAULT_INTERRUPT_RATE_UART_DMA) // Called twice per buffer - - // Set baud and enable peripheral with TX and RX mode - uart_set_baud(q->uart, baud); - q->uart->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; - - // Enable UART interrupts - if(q->uart == USART1){ - NVIC_EnableIRQ(USART1_IRQn); - } else if (q->uart == USART2){ - NVIC_EnableIRQ(USART2_IRQn); - } else if (q->uart == USART3){ - NVIC_EnableIRQ(USART3_IRQn); - } else if (q->uart == UART5){ - NVIC_EnableIRQ(UART5_IRQn); - } else { - // UART not used. Skip enabling interrupts - } - - // Initialise RX DMA if used - if(q->dma_rx){ - dma_rx_init(q); - } -} - -// ************************* Low-level buffer functions ************************* - -bool getc(uart_ring *q, char *elem) { - bool ret = false; - - ENTER_CRITICAL(); - if (q->w_ptr_rx != q->r_ptr_rx) { - if (elem != NULL) *elem = q->elems_rx[q->r_ptr_rx]; - q->r_ptr_rx = (q->r_ptr_rx + 1U) % q->rx_fifo_size; - ret = true; - } - EXIT_CRITICAL(); - - return ret; -} - -bool injectc(uart_ring *q, char elem) { - int ret = false; - uint16_t next_w_ptr; - - ENTER_CRITICAL(); - next_w_ptr = (q->w_ptr_rx + 1U) % q->tx_fifo_size; - if (next_w_ptr != q->r_ptr_rx) { - q->elems_rx[q->w_ptr_rx] = elem; - q->w_ptr_rx = next_w_ptr; - ret = true; - } - EXIT_CRITICAL(); - - return ret; -} - -bool putc(uart_ring *q, char elem) { - bool ret = false; - uint16_t next_w_ptr; - - ENTER_CRITICAL(); - next_w_ptr = (q->w_ptr_tx + 1U) % q->tx_fifo_size; - if (next_w_ptr != q->r_ptr_tx) { - q->elems_tx[q->w_ptr_tx] = elem; - q->w_ptr_tx = next_w_ptr; - ret = true; - } - EXIT_CRITICAL(); - - uart_tx_ring(q); - - return ret; -} - -// Seems dangerous to use (might lock CPU if called with interrupts disabled f.e.) -// TODO: Remove? Not used anyways -void uart_flush(uart_ring *q) { - while (q->w_ptr_tx != q->r_ptr_tx) { - __WFI(); - } -} - -void uart_flush_sync(uart_ring *q) { - // empty the TX buffer - while (q->w_ptr_tx != q->r_ptr_tx) { - uart_tx_ring(q); - } -} - -void uart_send_break(uart_ring *u) { - while ((u->uart->CR1 & USART_CR1_SBK) != 0); - u->uart->CR1 |= USART_CR1_SBK; -} - -void clear_uart_buff(uart_ring *q) { - ENTER_CRITICAL(); - q->w_ptr_tx = 0; - q->r_ptr_tx = 0; - q->w_ptr_rx = 0; - q->r_ptr_rx = 0; - EXIT_CRITICAL(); -} - -// ************************ High-level debug functions ********************** -void putch(const char a) { - if (has_external_debug_serial) { - // assuming debugging is important if there's external serial connected - while (!putc(&uart_ring_debug, a)); - - } else { - // misra-c2012-17.7: serial debug function, ok to ignore output - (void)injectc(&uart_ring_debug, a); - } -} - -void puts(const char *a) { - for (const char *in = a; *in; in++) { - if (*in == '\n') putch('\r'); - putch(*in); - } -} - -void putui(uint32_t i) { - uint32_t i_copy = i; - char str[11]; - uint8_t idx = 10; - str[idx] = '\0'; - idx--; - do { - str[idx] = (i_copy % 10U) + 0x30U; - idx--; - i_copy /= 10; - } while (i_copy != 0U); - puts(&str[idx + 1U]); -} - -void puth(unsigned int i) { - char c[] = "0123456789abcdef"; - for (int pos = 28; pos != -4; pos -= 4) { - putch(c[(i >> (unsigned int)(pos)) & 0xFU]); - } -} - -void puth2(unsigned int i) { - char c[] = "0123456789abcdef"; - for (int pos = 4; pos != -4; pos -= 4) { - putch(c[(i >> (unsigned int)(pos)) & 0xFU]); - } -} - -void hexdump(const void *a, int l) { - if (a != NULL) { - for (int i=0; i < l; i++) { - if ((i != 0) && ((i & 0xf) == 0)) puts("\n"); - puth2(((const unsigned char*)a)[i]); - puts(" "); - } - } - puts("\n"); -} diff --git a/panda/board/drivers/usb.h b/panda/board/drivers/usb.h deleted file mode 100644 index a970194ffd..0000000000 --- a/panda/board/drivers/usb.h +++ /dev/null @@ -1,1016 +0,0 @@ -// IRQs: OTG_FS - -typedef union { - uint16_t w; - struct BW { - uint8_t msb; - uint8_t lsb; - } - bw; -} -uint16_t_uint8_t; - -typedef union _USB_Setup { - uint32_t d8[2]; - struct _SetupPkt_Struc - { - uint8_t bmRequestType; - uint8_t bRequest; - uint16_t_uint8_t wValue; - uint16_t_uint8_t wIndex; - uint16_t_uint8_t wLength; - } b; -} -USB_Setup_TypeDef; - -void usb_init(void); -int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired); -int usb_cb_ep1_in(void *usbdata, int len, bool hardwired); -void usb_cb_ep2_out(void *usbdata, int len, bool hardwired); -void usb_cb_ep3_out(void *usbdata, int len, bool hardwired); -void usb_cb_enumeration_complete(void); - -// **** supporting defines **** - -typedef struct -{ - __IO uint32_t HPRT; -} -USB_OTG_HostPortTypeDef; - -USB_OTG_GlobalTypeDef *USBx = USB_OTG_FS; - -#define USBx_HOST ((USB_OTG_HostTypeDef *)((uint32_t)USBx + USB_OTG_HOST_BASE)) -#define USBx_HOST_PORT ((USB_OTG_HostPortTypeDef *)((uint32_t)USBx + USB_OTG_HOST_PORT_BASE)) -#define USBx_DEVICE ((USB_OTG_DeviceTypeDef *)((uint32_t)USBx + USB_OTG_DEVICE_BASE)) -#define USBx_INEP(i) ((USB_OTG_INEndpointTypeDef *)((uint32_t)USBx + USB_OTG_IN_ENDPOINT_BASE + ((i) * USB_OTG_EP_REG_SIZE))) -#define USBx_OUTEP(i) ((USB_OTG_OUTEndpointTypeDef *)((uint32_t)USBx + USB_OTG_OUT_ENDPOINT_BASE + ((i) * USB_OTG_EP_REG_SIZE))) -#define USBx_DFIFO(i) *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_FIFO_BASE + ((i) * USB_OTG_FIFO_SIZE)) -#define USBx_PCGCCTL *(__IO uint32_t *)((uint32_t)USBx + USB_OTG_PCGCCTL_BASE) - -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 0x05 -#define USB_REQ_GET_DESCRIPTOR 0x06 -#define USB_REQ_SET_DESCRIPTOR 0x07 -#define USB_REQ_GET_CONFIGURATION 0x08 -#define USB_REQ_SET_CONFIGURATION 0x09 -#define USB_REQ_GET_INTERFACE 0x0A -#define USB_REQ_SET_INTERFACE 0x0B -#define USB_REQ_SYNCH_FRAME 0x0C - -#define USB_DESC_TYPE_DEVICE 0x01 -#define USB_DESC_TYPE_CONFIGURATION 0x02 -#define USB_DESC_TYPE_STRING 0x03 -#define USB_DESC_TYPE_INTERFACE 0x04 -#define USB_DESC_TYPE_ENDPOINT 0x05 -#define USB_DESC_TYPE_DEVICE_QUALIFIER 0x06 -#define USB_DESC_TYPE_OTHER_SPEED_CONFIGURATION 0x07 -#define USB_DESC_TYPE_BINARY_OBJECT_STORE 0x0f - -// offsets for configuration strings -#define STRING_OFFSET_LANGID 0x00 -#define STRING_OFFSET_IMANUFACTURER 0x01 -#define STRING_OFFSET_IPRODUCT 0x02 -#define STRING_OFFSET_ISERIAL 0x03 -#define STRING_OFFSET_ICONFIGURATION 0x04 -#define STRING_OFFSET_IINTERFACE 0x05 - -// WebUSB requests -#define WEBUSB_REQ_GET_URL 0x02 - -// WebUSB types -#define WEBUSB_DESC_TYPE_URL 0x03 -#define WEBUSB_URL_SCHEME_HTTPS 0x01 -#define WEBUSB_URL_SCHEME_HTTP 0x00 - -// WinUSB requests -#define WINUSB_REQ_GET_COMPATID_DESCRIPTOR 0x04 -#define WINUSB_REQ_GET_EXT_PROPS_OS 0x05 -#define WINUSB_REQ_GET_DESCRIPTOR 0x07 - -#define STS_GOUT_NAK 1 -#define STS_DATA_UPDT 2 -#define STS_XFER_COMP 3 -#define STS_SETUP_COMP 4 -#define STS_SETUP_UPDT 6 - -#define USBD_FS_TRDT_VALUE 5U - -#define USB_OTG_SPEED_FULL 3 - -uint8_t resp[MAX_RESP_LEN]; - -// for the repeating interfaces -#define DSCR_INTERFACE_LEN 9 -#define DSCR_ENDPOINT_LEN 7 -#define DSCR_CONFIG_LEN 9 -#define DSCR_DEVICE_LEN 18 - -// endpoint types -#define ENDPOINT_TYPE_CONTROL 0 -#define ENDPOINT_TYPE_ISO 1 -#define ENDPOINT_TYPE_BULK 2 -#define ENDPOINT_TYPE_INT 3 - -// These are arbitrary values used in bRequest -#define MS_VENDOR_CODE 0x20 -#define WEBUSB_VENDOR_CODE 0x30 - -// BOS constants -#define BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH 0x05 -#define BINARY_OBJECT_STORE_DESCRIPTOR 0x0F -#define WINUSB_PLATFORM_DESCRIPTOR_LENGTH 0x9E - -// Convert machine byte order to USB byte order -#define TOUSBORDER(num)\ - ((num) & 0xFFU), (((num) >> 8) & 0xFFU) - -// take in string length and return the first 2 bytes of a string descriptor -#define STRING_DESCRIPTOR_HEADER(size)\ - (((((size) * 2) + 2) & 0xFF) | 0x0300) - -uint8_t device_desc[] = { - DSCR_DEVICE_LEN, USB_DESC_TYPE_DEVICE, //Length, Type - 0x10, 0x02, // bcdUSB max version of USB supported (2.1) - 0xFF, 0xFF, 0xFF, 0x40, // Class, Subclass, Protocol, Max Packet Size - TOUSBORDER(USB_VID), // idVendor - TOUSBORDER(USB_PID), // idProduct -#ifdef STM32F4 - 0x00, 0x23, // bcdDevice -#else - 0x00, 0x22, // bcdDevice -#endif - 0x01, 0x02, // Manufacturer, Product - 0x03, 0x01 // Serial Number, Num Configurations -}; - -uint8_t device_qualifier[] = { - 0x0a, USB_DESC_TYPE_DEVICE_QUALIFIER, //Length, Type - 0x10, 0x02, // bcdUSB max version of USB supported (2.1) - 0xFF, 0xFF, 0xFF, 0x40, // bDeviceClass, bDeviceSubClass, bDeviceProtocol, bMaxPacketSize0 - 0x01, 0x00 // bNumConfigurations, bReserved -}; - -#define ENDPOINT_RCV 0x80 -#define ENDPOINT_SND 0x00 - -uint8_t configuration_desc[] = { - DSCR_CONFIG_LEN, USB_DESC_TYPE_CONFIGURATION, // Length, Type, - TOUSBORDER(0x0045U), // Total Len (uint16) - 0x01, 0x01, STRING_OFFSET_ICONFIGURATION, // Num Interface, Config Value, Configuration - 0xc0, 0x32, // Attributes, Max Power - // interface 0 ALT 0 - DSCR_INTERFACE_LEN, USB_DESC_TYPE_INTERFACE, // Length, Type - 0x00, 0x00, 0x03, // Index, Alt Index idx, Endpoint count - 0XFF, 0xFF, 0xFF, // Class, Subclass, Protocol - 0x00, // Interface - // endpoint 1, read CAN - DSCR_ENDPOINT_LEN, USB_DESC_TYPE_ENDPOINT, // Length, Type - ENDPOINT_RCV | 1, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type - TOUSBORDER(0x0040U), // Max Packet (0x0040) - 0x00, // Polling Interval (NA) - // endpoint 2, send serial - DSCR_ENDPOINT_LEN, USB_DESC_TYPE_ENDPOINT, // Length, Type - ENDPOINT_SND | 2, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type - TOUSBORDER(0x0040U), // Max Packet (0x0040) - 0x00, // Polling Interval - // endpoint 3, send CAN - DSCR_ENDPOINT_LEN, USB_DESC_TYPE_ENDPOINT, // Length, Type - ENDPOINT_SND | 3, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type - TOUSBORDER(0x0040U), // Max Packet (0x0040) - 0x00, // Polling Interval - // interface 0 ALT 1 - DSCR_INTERFACE_LEN, USB_DESC_TYPE_INTERFACE, // Length, Type - 0x00, 0x01, 0x03, // Index, Alt Index idx, Endpoint count - 0XFF, 0xFF, 0xFF, // Class, Subclass, Protocol - 0x00, // Interface - // endpoint 1, read CAN - DSCR_ENDPOINT_LEN, USB_DESC_TYPE_ENDPOINT, // Length, Type - ENDPOINT_RCV | 1, ENDPOINT_TYPE_INT, // Endpoint Num/Direction, Type - TOUSBORDER(0x0040U), // Max Packet (0x0040) - 0x05, // Polling Interval (5 frames) - // endpoint 2, send serial - DSCR_ENDPOINT_LEN, USB_DESC_TYPE_ENDPOINT, // Length, Type - ENDPOINT_SND | 2, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type - TOUSBORDER(0x0040U), // Max Packet (0x0040) - 0x00, // Polling Interval - // endpoint 3, send CAN - DSCR_ENDPOINT_LEN, USB_DESC_TYPE_ENDPOINT, // Length, Type - ENDPOINT_SND | 3, ENDPOINT_TYPE_BULK, // Endpoint Num/Direction, Type - TOUSBORDER(0x0040U), // Max Packet (0x0040) - 0x00, // Polling Interval -}; - -// STRING_DESCRIPTOR_HEADER is for uint16 string descriptors -// it takes in a string length, which is bytes/2 because unicode -uint16_t string_language_desc[] = { - STRING_DESCRIPTOR_HEADER(1), - 0x0409 // american english -}; - -// these strings are all uint16's so that we don't need to spam ,0 after every character -uint16_t string_manufacturer_desc[] = { - STRING_DESCRIPTOR_HEADER(8), - 'c', 'o', 'm', 'm', 'a', '.', 'a', 'i' -}; - -uint16_t string_product_desc[] = { - STRING_DESCRIPTOR_HEADER(5), - 'p', 'a', 'n', 'd', 'a' -}; - -// default serial number when we're not a panda -uint16_t string_serial_desc[] = { - STRING_DESCRIPTOR_HEADER(4), - 'n', 'o', 'n', 'e' -}; - -// a string containing the default configuration index -uint16_t string_configuration_desc[] = { - STRING_DESCRIPTOR_HEADER(2), - '0', '1' // "01" -}; - -// WCID (auto install WinUSB driver) -// https://github.com/pbatard/libwdi/wiki/WCID-Devices -// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/winusb-installation#automatic-installation-of--winusb-without-an-inf-file -// WinUSB 1.0 descriptors, this is mostly used by Windows XP -uint8_t string_238_desc[] = { - 0x12, USB_DESC_TYPE_STRING, // bLength, bDescriptorType - 'M',0, 'S',0, 'F',0, 'T',0, '1',0, '0',0, '0',0, // qwSignature (MSFT100) - MS_VENDOR_CODE, 0x00 // bMS_VendorCode, bPad -}; -uint8_t winusb_ext_compatid_os_desc[] = { - 0x28, 0x00, 0x00, 0x00, // dwLength - 0x00, 0x01, // bcdVersion - 0x04, 0x00, // wIndex - 0x01, // bCount - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Reserved - 0x00, // bFirstInterfaceNumber - 0x00, // Reserved - 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatible ID (WINUSB) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // subcompatible ID (none) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Reserved -}; -uint8_t winusb_ext_prop_os_desc[] = { - 0x8e, 0x00, 0x00, 0x00, // dwLength - 0x00, 0x01, // bcdVersion - 0x05, 0x00, // wIndex - 0x01, 0x00, // wCount - // first property - 0x84, 0x00, 0x00, 0x00, // dwSize - 0x01, 0x00, 0x00, 0x00, // dwPropertyDataType - 0x28, 0x00, // wPropertyNameLength - 'D',0, 'e',0, 'v',0, 'i',0, 'c',0, 'e',0, 'I',0, 'n',0, 't',0, 'e',0, 'r',0, 'f',0, 'a',0, 'c',0, 'e',0, 'G',0, 'U',0, 'I',0, 'D',0, 0, 0, // bPropertyName (DeviceInterfaceGUID) - 0x4e, 0x00, 0x00, 0x00, // dwPropertyDataLength - '{',0, 'c',0, 'c',0, 'e',0, '5',0, '2',0, '9',0, '1',0, 'c',0, '-',0, 'a',0, '6',0, '9',0, 'f',0, '-',0, '4',0 ,'9',0 ,'9',0 ,'5',0 ,'-',0, 'a',0, '4',0, 'c',0, '2',0, '-',0, '2',0, 'a',0, 'e',0, '5',0, '7',0, 'a',0, '5',0, '1',0, 'a',0, 'd',0, 'e',0, '9',0, '}',0, 0, 0, // bPropertyData ({CCE5291C-A69F-4995-A4C2-2AE57A51ADE9}) -}; - -/* -Binary Object Store descriptor used to expose WebUSB (and more WinUSB) metadata -comments are from the wicg spec -References used: - https://wicg.github.io/webusb/#webusb-platform-capability-descriptor - https://github.com/sowbug/weblight/blob/192ad7a0e903542e2aa28c607d98254a12a6399d/firmware/webusb.c - https://os.mbed.com/users/larsgk/code/USBDevice_WebUSB/file/1d8a6665d607/WebUSBDevice/ - -*/ -uint8_t binary_object_store_desc[] = { - // BOS header - BINARY_OBJECT_STORE_DESCRIPTOR_LENGTH, // bLength, this is only the length of the header - BINARY_OBJECT_STORE_DESCRIPTOR, // bDescriptorType - 0x39, 0x00, // wTotalLength (LSB, MSB) - 0x02, // bNumDeviceCaps (WebUSB + WinUSB) - - // ------------------------------------------------- - // WebUSB descriptor - // header - 0x18, // bLength, Size of this descriptor. Must be set to 24. - 0x10, // bDescriptorType, DEVICE CAPABILITY descriptor - 0x05, // bDevCapabilityType, PLATFORM capability - 0x00, // bReserved, This field is reserved and shall be set to zero. - - // PlatformCapabilityUUID, Must be set to {3408b638-09a9-47a0-8bfd-a0768815b665}. - 0x38, 0xB6, 0x08, 0x34, - 0xA9, 0x09, 0xA0, 0x47, - 0x8B, 0xFD, 0xA0, 0x76, - 0x88, 0x15, 0xB6, 0x65, - // - - 0x00, 0x01, // bcdVersion, Protocol version supported. Must be set to 0x0100. - WEBUSB_VENDOR_CODE, // bVendorCode, bRequest value used for issuing WebUSB requests. - // there used to be a concept of "allowed origins", but it was removed from the spec - // it was intended to be a security feature, but then the entire security model relies on domain ownership - // https://github.com/WICG/webusb/issues/49 - // other implementations use various other indexed to leverate this no-longer-valid feature. we wont. - // the spec says we *must* reply to index 0x03 with the url, so we'll hint that that's the right index - 0x03, // iLandingPage, URL descriptor index of the device’s landing page. - - // ------------------------------------------------- - // WinUSB descriptor - // header - 0x1C, // Descriptor size (28 bytes) - 0x10, // Descriptor type (Device Capability) - 0x05, // Capability type (Platform) - 0x00, // Reserved - - // MS OS 2.0 Platform Capability ID (D8DD60DF-4589-4CC7-9CD2-659D9E648A9F) - // Indicates the device supports the Microsoft OS 2.0 descriptor - 0xDF, 0x60, 0xDD, 0xD8, - 0x89, 0x45, 0xC7, 0x4C, - 0x9C, 0xD2, 0x65, 0x9D, - 0x9E, 0x64, 0x8A, 0x9F, - - 0x00, 0x00, 0x03, 0x06, // Windows version, currently set to 8.1 (0x06030000) - - WINUSB_PLATFORM_DESCRIPTOR_LENGTH, 0x00, // MS OS 2.0 descriptor size (word) - 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 -// https://books.google.com/books?id=pkefBgAAQBAJ&pg=PA353&lpg=PA353 -uint8_t winusb_20_desc[WINUSB_PLATFORM_DESCRIPTOR_LENGTH] = { - // Microsoft OS 2.0 descriptor set header (table 10) - 0x0A, 0x00, // Descriptor size (10 bytes) - 0x00, 0x00, // MS OS 2.0 descriptor set header - - 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) - WINUSB_PLATFORM_DESCRIPTOR_LENGTH, 0x00, // Total size of MS OS 2.0 descriptor set - - // Microsoft OS 2.0 compatible ID descriptor - 0x14, 0x00, // Descriptor size (20 bytes) - 0x03, 0x00, // MS OS 2.0 compatible ID descriptor - 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // compatible ID (WINUSB) - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Sub-compatible ID - - // Registry property descriptor - 0x80, 0x00, // Descriptor size (130 bytes) - 0x04, 0x00, // Registry Property descriptor - 0x01, 0x00, // Strings are null-terminated Unicode - 0x28, 0x00, // Size of Property Name (40 bytes) "DeviceInterfaceGUID" - - // bPropertyName (DeviceInterfaceGUID) - 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, - 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, - 'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00, - - 0x4E, 0x00, // Size of Property Data (78 bytes) - - // Vendor-defined property data: {CCE5291C-A69F-4995-A4C2-2AE57A51ADE9} - '{', 0x00, 'c', 0x00, 'c', 0x00, 'e', 0x00, '5', 0x00, '2', 0x00, '9', 0x00, '1', 0x00, // 16 - 'c', 0x00, '-', 0x00, 'a', 0x00, '6', 0x00, '9', 0x00, 'f', 0x00, '-', 0x00, '4', 0x00, // 32 - '9', 0x00, '9', 0x00, '5', 0x00, '-', 0x00, 'a', 0x00, '4', 0x00, 'c', 0x00, '2', 0x00, // 48 - '-', 0x00, '2', 0x00, 'a', 0x00, 'e', 0x00, '5', 0x00, '7', 0x00, 'a', 0x00, '5', 0x00, // 64 - '1', 0x00, 'a', 0x00, 'd', 0x00, 'e', 0x00, '9', 0x00, '}', 0x00, 0x00, 0x00 // 78 bytes -}; - -// current packet -USB_Setup_TypeDef setup; -uint8_t usbdata[0x100]; -uint8_t* ep0_txdata = NULL; -uint16_t ep0_txlen = 0; - -// Store the current interface alt setting. -int current_int0_alt_setting = 0; - -// packet read and write - -void *USB_ReadPacket(void *dest, uint16_t len) { - uint32_t *dest_copy = (uint32_t *)dest; - uint32_t count32b = (len + 3U) / 4U; - - for (uint32_t i = 0; i < count32b; i++) { - *dest_copy = USBx_DFIFO(0); - dest_copy++; - } - return ((void *)dest_copy); -} - -void USB_WritePacket(const void *src, uint16_t len, uint32_t ep) { - #ifdef DEBUG_USB - puts("writing "); - hexdump(src, len); - #endif - - uint8_t numpacket = (len + (MAX_RESP_LEN - 1U)) / MAX_RESP_LEN; - uint32_t count32b = 0; - count32b = (len + 3U) / 4U; - - // TODO: revisit this - USBx_INEP(ep)->DIEPTSIZ = ((numpacket << 19) & USB_OTG_DIEPTSIZ_PKTCNT) | - (len & USB_OTG_DIEPTSIZ_XFRSIZ); - USBx_INEP(ep)->DIEPCTL |= (USB_OTG_DIEPCTL_CNAK | USB_OTG_DIEPCTL_EPENA); - - // load the FIFO - const uint32_t *src_copy = (const uint32_t *)src; - for (uint32_t i = 0; i < count32b; i++) { - USBx_DFIFO(ep) = *src_copy; - src_copy++; - } -} - -// IN EP 0 TX FIFO has a max size of 127 bytes (much smaller than the rest) -// so use TX FIFO empty interrupt to send larger amounts of data -void USB_WritePacket_EP0(uint8_t *src, uint16_t len) { - #ifdef DEBUG_USB - puts("writing "); - hexdump(src, len); - #endif - - uint16_t wplen = MIN(len, 0x40); - USB_WritePacket(src, wplen, 0); - - if (wplen < len) { - ep0_txdata = &src[wplen]; - ep0_txlen = len - wplen; - USBx_DEVICE->DIEPEMPMSK |= 1; - } else { - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - } -} - -void usb_reset(void) { - // unmask endpoint interrupts, so many sets - USBx_DEVICE->DAINT = 0xFFFFFFFF; - USBx_DEVICE->DAINTMSK = 0xFFFFFFFF; - //USBx_DEVICE->DOEPMSK = (USB_OTG_DOEPMSK_STUPM | USB_OTG_DOEPMSK_XFRCM | USB_OTG_DOEPMSK_EPDM); - //USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM | USB_OTG_DIEPMSK_ITTXFEMSK); - //USBx_DEVICE->DIEPMSK = (USB_OTG_DIEPMSK_TOM | USB_OTG_DIEPMSK_XFRCM | USB_OTG_DIEPMSK_EPDM); - - // all interrupts for debugging - USBx_DEVICE->DIEPMSK = 0xFFFFFFFF; - USBx_DEVICE->DOEPMSK = 0xFFFFFFFF; - - // clear interrupts - USBx_INEP(0)->DIEPINT = 0xFF; - USBx_OUTEP(0)->DOEPINT = 0xFF; - - // unset the address - USBx_DEVICE->DCFG &= ~USB_OTG_DCFG_DAD; - - // set up USB FIFOs - // RX start address is fixed to 0 - USBx->GRXFSIZ = 0x40; - - // 0x100 to offset past GRXFSIZ - USBx->DIEPTXF0_HNPTXFSIZ = (0x40U << 16) | 0x40U; - - // EP1, massive - USBx->DIEPTXF[0] = (0x40U << 16) | 0x80U; - - // flush TX fifo - USBx->GRSTCTL = USB_OTG_GRSTCTL_TXFFLSH | USB_OTG_GRSTCTL_TXFNUM_4; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_TXFFLSH) == USB_OTG_GRSTCTL_TXFFLSH); - // flush RX FIFO - USBx->GRSTCTL = USB_OTG_GRSTCTL_RXFFLSH; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_RXFFLSH) == USB_OTG_GRSTCTL_RXFFLSH); - - // no global NAK - USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGINAK; - - // ready to receive setup packets - USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1U << 19)) | (3U << 3); -} - -char to_hex_char(int a) { - char ret; - if (a < 10) { - ret = '0' + a; - } else { - ret = 'a' + (a - 10); - } - return ret; -} - -void usb_setup(void) { - int resp_len; - // setup packet is ready - 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) | (2U << 18) | (1U << 22) | - USB_OTG_DIEPCTL_SD0PID_SEVNFRM | USB_OTG_DIEPCTL_USBAEP; - USBx_INEP(1)->DIEPINT = 0xFF; - - USBx_OUTEP(2)->DOEPTSIZ = (1U << 19) | 0x40U; - USBx_OUTEP(2)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2U << 18) | - USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP; - USBx_OUTEP(2)->DOEPINT = 0xFF; - - USBx_OUTEP(3)->DOEPTSIZ = (1U << 19) | 0x40U; - USBx_OUTEP(3)->DOEPCTL = (0x40U & USB_OTG_DOEPCTL_MPSIZ) | (2U << 18) | - USB_OTG_DOEPCTL_SD0PID_SEVNFRM | USB_OTG_DOEPCTL_USBAEP; - USBx_OUTEP(3)->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; - - USB_WritePacket(0, 0, 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - break; - case USB_REQ_SET_ADDRESS: - // set now? - USBx_DEVICE->DCFG |= ((setup.b.wValue.w & 0x7fU) << 4); - - #ifdef DEBUG_USB - puts(" set address\n"); - #endif - - // TODO: this isn't enumeration complete - // moved here to work better on OS X - usb_cb_enumeration_complete(); - - USB_WritePacket(0, 0, 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - - break; - case USB_REQ_GET_DESCRIPTOR: - switch (setup.b.wValue.bw.lsb) { - case USB_DESC_TYPE_DEVICE: - //puts(" writing device descriptor\n"); - - // setup transfer - USB_WritePacket(device_desc, MIN(sizeof(device_desc), setup.b.wLength.w), 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - - //puts("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; - 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; - break; - case USB_DESC_TYPE_STRING: - switch (setup.b.wValue.bw.msb) { - case STRING_OFFSET_LANGID: - USB_WritePacket((uint8_t*)string_language_desc, MIN(sizeof(string_language_desc), setup.b.wLength.w), 0); - break; - case STRING_OFFSET_IMANUFACTURER: - USB_WritePacket((uint8_t*)string_manufacturer_desc, MIN(sizeof(string_manufacturer_desc), setup.b.wLength.w), 0); - break; - case STRING_OFFSET_IPRODUCT: - 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 - resp[0] = 0x02 + (12 * 4); - resp[1] = 0x03; - - // 96 bits = 12 bytes - for (int i = 0; i < 12; i++){ - uint8_t cc = ((uint8_t *)UID_BASE)[i]; - resp[2 + (i * 4) + 0] = to_hex_char((cc >> 4) & 0xFU); - resp[2 + (i * 4) + 1] = '\0'; - resp[2 + (i * 4) + 2] = to_hex_char((cc >> 0) & 0xFU); - resp[2 + (i * 4) + 3] = '\0'; - } - - USB_WritePacket(resp, MIN(resp[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 - break; - case STRING_OFFSET_ICONFIGURATION: - USB_WritePacket((uint8_t*)string_configuration_desc, MIN(sizeof(string_configuration_desc), setup.b.wLength.w), 0); - break; - case 238: - USB_WritePacket((uint8_t*)string_238_desc, MIN(sizeof(string_238_desc), setup.b.wLength.w), 0); - break; - default: - // nothing - USB_WritePacket(0, 0, 0); - break; - } - USBx_OUTEP(0)->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; - break; - default: - // nothing here? - USB_WritePacket(0, 0, 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - break; - } - break; - case USB_REQ_GET_STATUS: - // empty resp? - resp[0] = 0; - resp[1] = 0; - USB_WritePacket((void*)&resp, 2, 0); - USBx_OUTEP(0)->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; - 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; - } - break; - case MS_VENDOR_CODE: - switch (setup.b.wIndex.w) { - // winusb 2.0 descriptor from BOS - case WINUSB_REQ_GET_DESCRIPTOR: - USB_WritePacket_EP0((uint8_t*)winusb_20_desc, MIN(sizeof(winusb_20_desc), setup.b.wLength.w)); - break; - // Extended Compat ID OS Descriptor - case WINUSB_REQ_GET_COMPATID_DESCRIPTOR: - USB_WritePacket_EP0((uint8_t*)winusb_ext_compatid_os_desc, MIN(sizeof(winusb_ext_compatid_os_desc), setup.b.wLength.w)); - break; - // Extended Properties OS Descriptor - case WINUSB_REQ_GET_EXT_PROPS_OS: - USB_WritePacket_EP0((uint8_t*)winusb_ext_prop_os_desc, MIN(sizeof(winusb_ext_prop_os_desc), setup.b.wLength.w)); - break; - default: - USB_WritePacket_EP0(0, 0); - } - break; - default: - resp_len = usb_cb_control_msg(&setup, resp, 1); - USB_WritePacket(resp, MIN(resp_len, setup.b.wLength.w), 0); - USBx_OUTEP(0)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - } -} - - - -// ***************************** USB port ***************************** - -void usb_irqhandler(void) { - //USBx->GINTMSK = 0; - - unsigned int gintsts = USBx->GINTSTS; - unsigned int gotgint = USBx->GOTGINT; - unsigned int daint = USBx_DEVICE->DAINT; - - // gintsts SUSPEND? 04008428 - #ifdef DEBUG_USB - puth(gintsts); - puts(" "); - /*puth(USBx->GCCFG); - puts(" ");*/ - puth(gotgint); - puts(" ep "); - puth(daint); - puts(" USB interrupt!\n"); - #endif - - if ((gintsts & USB_OTG_GINTSTS_CIDSCHG) != 0) { - puts("connector ID status change\n"); - } - - if ((gintsts & USB_OTG_GINTSTS_ESUSP) != 0) { - puts("ESUSP detected\n"); - } - - if ((gintsts & USB_OTG_GINTSTS_USBRST) != 0) { - puts("USB reset\n"); - usb_reset(); - } - - if ((gintsts & USB_OTG_GINTSTS_ENUMDNE) != 0) { - puts("enumeration done"); - // Full speed, ENUMSPD - //puth(USBx_DEVICE->DSTS); - puts("\n"); - } - - if ((gintsts & USB_OTG_GINTSTS_OTGINT) != 0) { - puts("OTG int:"); - puth(USBx->GOTGINT); - puts("\n"); - - // getting ADTOCHG - //USBx->GOTGINT = USBx->GOTGINT; - } - - // RX FIFO first - if ((gintsts & USB_OTG_GINTSTS_RXFLVL) != 0) { - // 1. Read the Receive status pop register - volatile unsigned int rxst = USBx->GRXSTSP; - int status = (rxst & USB_OTG_GRXSTSP_PKTSTS) >> 17; - - #ifdef DEBUG_USB - puts(" RX FIFO:"); - puth(rxst); - puts(" status: "); - puth(status); - puts(" len: "); - puth((rxst & USB_OTG_GRXSTSP_BCNT) >> 4); - puts("\n"); - #endif - - if (status == STS_DATA_UPDT) { - int endpoint = (rxst & USB_OTG_GRXSTSP_EPNUM); - int len = (rxst & USB_OTG_GRXSTSP_BCNT) >> 4; - (void)USB_ReadPacket(&usbdata, len); - #ifdef DEBUG_USB - puts(" data "); - puth(len); - puts("\n"); - hexdump(&usbdata, len); - #endif - - if (endpoint == 2) { - usb_cb_ep2_out(usbdata, len, 1); - } - - if (endpoint == 3) { - usb_cb_ep3_out(usbdata, len, 1); - } - } else if (status == STS_SETUP_UPDT) { - (void)USB_ReadPacket(&setup, 8); - #ifdef DEBUG_USB - puts(" setup "); - hexdump(&setup, 8); - puts("\n"); - #endif - } else { - // status is neither STS_DATA_UPDT or STS_SETUP_UPDT, skip - } - } - - /*if (gintsts & USB_OTG_GINTSTS_HPRTINT) { - // host - puts("HPRT:"); - puth(USBx_HOST_PORT->HPRT); - puts("\n"); - if (USBx_HOST_PORT->HPRT & USB_OTG_HPRT_PCDET) { - USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PRST; - USBx_HOST_PORT->HPRT |= USB_OTG_HPRT_PCDET; - } - - }*/ - - if ((gintsts & USB_OTG_GINTSTS_BOUTNAKEFF) || (gintsts & USB_OTG_GINTSTS_GINAKEFF)) { - // no global NAK, why is this getting set? - #ifdef DEBUG_USB - puts("GLOBAL NAK\n"); - #endif - USBx_DEVICE->DCTL |= USB_OTG_DCTL_CGONAK | USB_OTG_DCTL_CGINAK; - } - - if ((gintsts & USB_OTG_GINTSTS_SRQINT) != 0) { - // we want to do "A-device host negotiation protocol" since we are the A-device - /*puts("start request\n"); - puth(USBx->GOTGCTL); - puts("\n");*/ - //USBx->GUSBCFG |= USB_OTG_GUSBCFG_FDMOD; - //USBx_HOST_PORT->HPRT = USB_OTG_HPRT_PPWR | USB_OTG_HPRT_PENA; - //USBx->GOTGCTL |= USB_OTG_GOTGCTL_SRQ; - } - - // out endpoint hit - if ((gintsts & USB_OTG_GINTSTS_OEPINT) != 0) { - #ifdef DEBUG_USB - puts(" 0:"); - puth(USBx_OUTEP(0)->DOEPINT); - puts(" 2:"); - puth(USBx_OUTEP(2)->DOEPINT); - puts(" 3:"); - puth(USBx_OUTEP(3)->DOEPINT); - puts(" "); - puth(USBx_OUTEP(3)->DOEPCTL); - puts(" 4:"); - puth(USBx_OUTEP(4)->DOEPINT); - puts(" OUT ENDPOINT\n"); - #endif - - if ((USBx_OUTEP(2)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0) { - #ifdef DEBUG_USB - puts(" OUT2 PACKET XFRC\n"); - #endif - USBx_OUTEP(2)->DOEPTSIZ = (1U << 19) | 0x40U; - USBx_OUTEP(2)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; - } - - if ((USBx_OUTEP(3)->DOEPINT & USB_OTG_DOEPINT_XFRC) != 0) { - #ifdef DEBUG_USB - puts(" OUT3 PACKET XFRC\n"); - #endif - USBx_OUTEP(3)->DOEPTSIZ = (1U << 19) | 0x40U; - USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_EPENA | USB_OTG_DOEPCTL_CNAK; - } else if ((USBx_OUTEP(3)->DOEPINT & 0x2000) != 0) { - #ifdef DEBUG_USB - puts(" OUT3 PACKET WTF\n"); - #endif - // if NAK was set trigger this, unknown interrupt - USBx_OUTEP(3)->DOEPTSIZ = (1U << 19) | 0x40U; - USBx_OUTEP(3)->DOEPCTL |= USB_OTG_DOEPCTL_CNAK; - } else if ((USBx_OUTEP(3)->DOEPINT) != 0) { - puts("OUTEP3 error "); - puth(USBx_OUTEP(3)->DOEPINT); - puts("\n"); - } else { - // USBx_OUTEP(3)->DOEPINT is 0, ok to skip - } - - if ((USBx_OUTEP(0)->DOEPINT & USB_OTG_DIEPINT_XFRC) != 0) { - // ready for next packet - USBx_OUTEP(0)->DOEPTSIZ = USB_OTG_DOEPTSIZ_STUPCNT | (USB_OTG_DOEPTSIZ_PKTCNT & (1U << 19)) | (1U << 3); - } - - // respond to setup packets - if ((USBx_OUTEP(0)->DOEPINT & USB_OTG_DOEPINT_STUP) != 0) { - 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; - } - - // interrupt endpoint hit (Page 1221) - if ((gintsts & USB_OTG_GINTSTS_IEPINT) != 0) { - #ifdef DEBUG_USB - puts(" "); - puth(USBx_INEP(0)->DIEPINT); - puts(" "); - puth(USBx_INEP(1)->DIEPINT); - puts(" IN ENDPOINT\n"); - #endif - - // Should likely check the EP of the IN request even if there is - // only one IN endpoint. - - // No need to set NAK in OTG_DIEPCTL0 when nothing to send, - // Appears USB core automatically sets NAK. WritePacket clears it. - - // Handle the two interface alternate settings. Setting 0 has EP1 - // as bulk. Setting 1 has EP1 as interrupt. The code to handle - // these two EP variations are very similar and can be - // restructured for smaller code footprint. Keeping split out for - // now for clarity. - - //TODO add default case. Should it NAK? - 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) { - #ifdef DEBUG_USB - puts(" IN PACKET QUEUE\n"); - #endif - // TODO: always assuming max len, can we get the length? - USB_WritePacket((void *)resp, usb_cb_ep1_in(resp, 0x40, 1), 1); - } - break; - - case 1: ////// Interrupt config - // *** IN token received when TxFIFO is empty - if ((USBx_INEP(1)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) { - #ifdef DEBUG_USB - puts(" IN PACKET QUEUE\n"); - #endif - // TODO: always assuming max len, can we get the length? - int len = usb_cb_ep1_in(resp, 0x40, 1); - if (len > 0) { - USB_WritePacket((void *)resp, len, 1); - } - } - break; - default: - puts("current_int0_alt_setting value invalid\n"); - break; - } - - if ((USBx_INEP(0)->DIEPINT & USB_OTG_DIEPMSK_ITTXFEMSK) != 0) { - #ifdef DEBUG_USB - puts(" IN PACKET QUEUE\n"); - #endif - - if ((ep0_txlen != 0U) && ((USBx_INEP(0)->DTXFSTS & USB_OTG_DTXFSTS_INEPTFSAV) >= 0x40U)) { - uint16_t len = MIN(ep0_txlen, 0x40); - USB_WritePacket(ep0_txdata, len, 0); - ep0_txdata = &ep0_txdata[len]; - ep0_txlen -= len; - if (ep0_txlen == 0U) { - ep0_txdata = NULL; - USBx_DEVICE->DIEPEMPMSK &= ~1; - USBx_OUTEP(0)->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; - } - - // clear all interrupts we handled - USBx_DEVICE->DAINT = daint; - USBx->GOTGINT = gotgint; - USBx->GINTSTS = gintsts; - - //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); -} - -void OTG_FS_IRQ_Handler(void) { - NVIC_DisableIRQ(OTG_FS_IRQn); - //__disable_irq(); - usb_irqhandler(); - //__enable_irq(); - NVIC_EnableIRQ(OTG_FS_IRQn); -} - -// ***************************** USB init ***************************** - -void usb_init(void) { - REGISTER_INTERRUPT(OTG_FS_IRQn, OTG_FS_IRQ_Handler, 1500000U, FAULT_INTERRUPT_RATE_USB) //TODO: Find out a better rate limit for USB. Now it's the 1.5MB/s rate - - // full speed PHY, do reset and remove power down - /*puth(USBx->GRSTCTL); - puts(" resetting PHY\n");*/ - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_AHBIDL) == 0); - //puts("AHB idle\n"); - - // reset PHY here - USBx->GRSTCTL |= USB_OTG_GRSTCTL_CSRST; - while ((USBx->GRSTCTL & USB_OTG_GRSTCTL_CSRST) == USB_OTG_GRSTCTL_CSRST); - //puts("reset done\n"); - - // internal PHY, force device mode - USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_FDMOD; - - // slowest timings - USBx->GUSBCFG |= ((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT); - - // power up the PHY -#ifdef STM32F4 - USBx->GCCFG = USB_OTG_GCCFG_PWRDWN; - - //USBx->GCCFG |= USB_OTG_GCCFG_VBDEN | USB_OTG_GCCFG_SDEN |USB_OTG_GCCFG_PDEN | USB_OTG_GCCFG_DCDEN; - - /* B-peripheral session valid override enable*/ - USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOVAL; - USBx->GOTGCTL |= USB_OTG_GOTGCTL_BVALOEN; -#else - USBx->GCCFG = USB_OTG_GCCFG_PWRDWN | USB_OTG_GCCFG_NOVBUSSENS; -#endif - - // be a device, slowest timings - //USBx->GUSBCFG = USB_OTG_GUSBCFG_FDMOD | USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL; - //USBx->GUSBCFG |= (uint32_t)((USBD_FS_TRDT_VALUE << 10) & USB_OTG_GUSBCFG_TRDT); - //USBx->GUSBCFG = USB_OTG_GUSBCFG_PHYSEL | USB_OTG_GUSBCFG_TRDT | USB_OTG_GUSBCFG_TOCAL; - - // **** for debugging, doesn't seem to work **** - //USBx->GUSBCFG |= USB_OTG_GUSBCFG_CTXPKT; - - // reset PHY clock - USBx_PCGCCTL = 0; - - // enable the fancy OTG things - // DCFG_FRAME_INTERVAL_80 is 0 - //USBx->GUSBCFG |= USB_OTG_GUSBCFG_HNPCAP | USB_OTG_GUSBCFG_SRPCAP; - USBx_DEVICE->DCFG |= USB_OTG_SPEED_FULL | USB_OTG_DCFG_NZLSOHSK; - - //USBx_DEVICE->DCFG = USB_OTG_DCFG_NZLSOHSK | USB_OTG_DCFG_DSPD; - //USBx_DEVICE->DCFG = USB_OTG_DCFG_DSPD; - - // clear pending interrupts - USBx->GINTSTS = 0xBFFFFFFFU; - - // setup USB interrupts - // all interrupts except TXFIFO EMPTY - //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM | USB_OTG_GINTSTS_SOF | USB_OTG_GINTSTS_EOPF); - //USBx->GINTMSK = 0xFFFFFFFF & ~(USB_OTG_GINTMSK_NPTXFEM | USB_OTG_GINTMSK_PTXFEM); - USBx->GINTMSK = USB_OTG_GINTMSK_USBRST | USB_OTG_GINTMSK_ENUMDNEM | USB_OTG_GINTMSK_OTGINT | - USB_OTG_GINTMSK_RXFLVLM | USB_OTG_GINTMSK_GONAKEFFM | USB_OTG_GINTMSK_GINAKEFFM | - USB_OTG_GINTMSK_OEPINT | USB_OTG_GINTMSK_IEPINT | USB_OTG_GINTMSK_USBSUSPM | - USB_OTG_GINTMSK_CIDSCHGM | USB_OTG_GINTMSK_SRQIM | USB_OTG_GINTMSK_MMISM; - - USBx->GAHBCFG = USB_OTG_GAHBCFG_GINT; - - // DCTL startup value is 2 on new chip, 0 on old chip - USBx_DEVICE->DCTL = 0; - - // enable the IRQ - NVIC_EnableIRQ(OTG_FS_IRQn); -} \ No newline at end of file diff --git a/panda/board/faults.h b/panda/board/faults.h deleted file mode 100644 index aa5db341b5..0000000000 --- a/panda/board/faults.h +++ /dev/null @@ -1,49 +0,0 @@ -#define FAULT_STATUS_NONE 0U -#define FAULT_STATUS_TEMPORARY 1U -#define FAULT_STATUS_PERMANENT 2U - -// Fault types -#define FAULT_RELAY_MALFUNCTION (1U << 0) -#define FAULT_UNUSED_INTERRUPT_HANDLED (1U << 1) -#define FAULT_INTERRUPT_RATE_CAN_1 (1U << 2) -#define FAULT_INTERRUPT_RATE_CAN_2 (1U << 3) -#define FAULT_INTERRUPT_RATE_CAN_3 (1U << 4) -#define FAULT_INTERRUPT_RATE_TACH (1U << 5) -#define FAULT_INTERRUPT_RATE_GMLAN (1U << 6) -#define FAULT_INTERRUPT_RATE_INTERRUPTS (1U << 7) -#define FAULT_INTERRUPT_RATE_SPI_DMA (1U << 8) -#define FAULT_INTERRUPT_RATE_SPI_CS (1U << 9) -#define FAULT_INTERRUPT_RATE_UART_1 (1U << 10) -#define FAULT_INTERRUPT_RATE_UART_2 (1U << 11) -#define FAULT_INTERRUPT_RATE_UART_3 (1U << 12) -#define FAULT_INTERRUPT_RATE_UART_5 (1U << 13) -#define FAULT_INTERRUPT_RATE_UART_DMA (1U << 14) -#define FAULT_INTERRUPT_RATE_USB (1U << 15) -#define FAULT_INTERRUPT_RATE_TIM1 (1U << 16) -#define FAULT_INTERRUPT_RATE_TIM3 (1U << 17) -#define FAULT_REGISTER_DIVERGENT (1U << 18) - -// Permanent faults -#define PERMANENT_FAULTS 0U - -uint8_t fault_status = FAULT_STATUS_NONE; -uint32_t faults = 0U; - -void fault_occurred(uint32_t fault) { - faults |= fault; - if((PERMANENT_FAULTS & fault) != 0U){ - puts("Permanent fault occurred: 0x"); puth(fault); puts("\n"); - fault_status = FAULT_STATUS_PERMANENT; - } else { - puts("Temporary fault occurred: 0x"); puth(fault); puts("\n"); - fault_status = FAULT_STATUS_TEMPORARY; - } -} - -void fault_recovered(uint32_t fault) { - if((PERMANENT_FAULTS & fault) == 0U){ - faults &= ~fault; - } else { - puts("Cannot recover from a permanent fault!\n"); - } -} \ No newline at end of file diff --git a/panda/board/get_sdk.sh b/panda/board/get_sdk.sh deleted file mode 100755 index 3a009a5a13..0000000000 --- a/panda/board/get_sdk.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash -sudo apt-get install gcc-arm-none-eabi python-pip -sudo pip install libusb1 pycrypto requests diff --git a/panda/board/get_sdk_mac.sh b/panda/board/get_sdk_mac.sh deleted file mode 100755 index a0a919f7d8..0000000000 --- a/panda/board/get_sdk_mac.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -# Need formula for gcc -brew tap ArmMbed/homebrew-formulae -brew install python dfu-util arm-none-eabi-gcc -pip install --user libusb1 pycrypto requests diff --git a/panda/board/gpio.h b/panda/board/gpio.h deleted file mode 100644 index 2b937eced4..0000000000 --- a/panda/board/gpio.h +++ /dev/null @@ -1,76 +0,0 @@ -// Early bringup -#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef -#define ENTER_SOFTLOADER_MAGIC 0xdeadc0de -#define BOOT_NORMAL 0xdeadb111 - -extern void *g_pfnVectors; -extern uint32_t enter_bootloader_mode; - -void jump_to_bootloader(void) { - // do enter bootloader - enter_bootloader_mode = 0; - void (*bootloader)(void) = (void (*)(void)) (*((uint32_t *)0x1fff0004)); - - // jump to bootloader - bootloader(); - - // reset on exit - enter_bootloader_mode = BOOT_NORMAL; - NVIC_SystemReset(); -} - -void early(void) { - // Reset global critical depth - global_critical_depth = 0; - - // Init register and interrupt tables - init_registers(); - - // neccesary for DFU flashing on a non-power cycled white panda - enable_interrupts(); - - // after it's been in the bootloader, things are initted differently, so we reset - if ((enter_bootloader_mode != BOOT_NORMAL) && - (enter_bootloader_mode != ENTER_BOOTLOADER_MAGIC) && - (enter_bootloader_mode != ENTER_SOFTLOADER_MAGIC)) { - enter_bootloader_mode = BOOT_NORMAL; - NVIC_SystemReset(); - } - - // if wrong chip, reboot - volatile unsigned int id = DBGMCU->IDCODE; - #ifdef STM32F4 - if ((id & 0xFFFU) != 0x463U) { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - } - #else - if ((id & 0xFFFU) != 0x411U) { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - } - #endif - - // setup interrupt table - SCB->VTOR = (uint32_t)&g_pfnVectors; - - // early GPIOs float everything - RCC->AHB1ENR = RCC_AHB1ENR_GPIOAEN | RCC_AHB1ENR_GPIOBEN | RCC_AHB1ENR_GPIOCEN; - - GPIOA->MODER = 0; GPIOB->MODER = 0; GPIOC->MODER = 0; - GPIOA->ODR = 0; GPIOB->ODR = 0; GPIOC->ODR = 0; - GPIOA->PUPDR = 0; GPIOB->PUPDR = 0; GPIOC->PUPDR = 0; - - detect_configuration(); - detect_board_type(); - - if (enter_bootloader_mode == ENTER_BOOTLOADER_MAGIC) { - #ifdef PANDA - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); - #endif - current_board->set_led(LED_GREEN, 1); - jump_to_bootloader(); - } - - if (is_entering_bootmode) { - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - } -} \ No newline at end of file diff --git a/panda/board/inc/cmsis_compiler.h b/panda/board/inc/cmsis_compiler.h deleted file mode 100644 index d0f39eef67..0000000000 --- a/panda/board/inc/cmsis_compiler.h +++ /dev/null @@ -1,284 +0,0 @@ -/**************************************************************************//** - * @file cmsis_compiler.h - * @brief CMSIS compiler generic header file - * @version V5.1.0 - * @date 09. October 2018 - ******************************************************************************/ -/* - * Copyright (c) 2009-2018 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. - */ - -#ifndef __CMSIS_COMPILER_H -#define __CMSIS_COMPILER_H - -#include - -/* - * Arm Compiler 4/5 - */ -#if defined ( __CC_ARM ) - #include "cmsis_armcc.h" - - -/* - * Arm Compiler 6.6 LTM (armclang) - */ -#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) && (__ARMCC_VERSION < 6100100) - #include "cmsis_armclang_ltm.h" - - /* - * Arm Compiler above 6.10.1 (armclang) - */ -#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6100100) - #include "cmsis_armclang.h" - - -/* - * GNU Compiler - */ -#elif defined ( __GNUC__ ) - #include "cmsis_gcc.h" - - -/* - * IAR Compiler - */ -#elif defined ( __ICCARM__ ) - #include - - -/* - * TI Arm Compiler - */ -#elif defined ( __TI_ARM__ ) - #include - - #ifndef __ASM - #define __ASM __asm - #endif - #ifndef __INLINE - #define __INLINE inline - #endif - #ifndef __STATIC_INLINE - #define __STATIC_INLINE static inline - #endif - #ifndef __STATIC_FORCEINLINE - #define __STATIC_FORCEINLINE __STATIC_INLINE - #endif - #ifndef __NO_RETURN - #define __NO_RETURN __attribute__((noreturn)) - #endif - #ifndef __USED - #define __USED __attribute__((used)) - #endif - #ifndef __WEAK - #define __WEAK __attribute__((weak)) - #endif - #ifndef __PACKED - #define __PACKED __attribute__((packed)) - #endif - #ifndef __PACKED_STRUCT - #define __PACKED_STRUCT struct __attribute__((packed)) - #endif - #ifndef __PACKED_UNION - #define __PACKED_UNION union __attribute__((packed)) - #endif - #ifndef __UNALIGNED_UINT32 /* deprecated */ - struct __attribute__((packed)) T_UINT32 { uint32_t v; }; - #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) - #endif - #ifndef __UNALIGNED_UINT16_WRITE - __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; - #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void*)(addr))->v) = (val)) - #endif - #ifndef __UNALIGNED_UINT16_READ - __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; - #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) - #endif - #ifndef __UNALIGNED_UINT32_WRITE - __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; - #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) - #endif - #ifndef __UNALIGNED_UINT32_READ - __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; - #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) - #endif - #ifndef __ALIGNED - #define __ALIGNED(x) __attribute__((aligned(x))) - #endif - #ifndef __RESTRICT - #define __RESTRICT __restrict - #endif - #ifndef __COMPILER_BARRIER - #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. - #define __COMPILER_BARRIER() (void)0 - #endif - - -/* - * TASKING Compiler - */ -#elif defined ( __TASKING__ ) - /* - * The CMSIS functions have been implemented as intrinsics in the compiler. - * Please use "carm -?i" to get an up to date list of all intrinsics, - * Including the CMSIS ones. - */ - - #ifndef __ASM - #define __ASM __asm - #endif - #ifndef __INLINE - #define __INLINE inline - #endif - #ifndef __STATIC_INLINE - #define __STATIC_INLINE static inline - #endif - #ifndef __STATIC_FORCEINLINE - #define __STATIC_FORCEINLINE __STATIC_INLINE - #endif - #ifndef __NO_RETURN - #define __NO_RETURN __attribute__((noreturn)) - #endif - #ifndef __USED - #define __USED __attribute__((used)) - #endif - #ifndef __WEAK - #define __WEAK __attribute__((weak)) - #endif - #ifndef __PACKED - #define __PACKED __packed__ - #endif - #ifndef __PACKED_STRUCT - #define __PACKED_STRUCT struct __packed__ - #endif - #ifndef __PACKED_UNION - #define __PACKED_UNION union __packed__ - #endif - #ifndef __UNALIGNED_UINT32 /* deprecated */ - struct __packed__ T_UINT32 { uint32_t v; }; - #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) - #endif - #ifndef __UNALIGNED_UINT16_WRITE - __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; - #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) - #endif - #ifndef __UNALIGNED_UINT16_READ - __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; - #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) - #endif - #ifndef __UNALIGNED_UINT32_WRITE - __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; - #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) - #endif - #ifndef __UNALIGNED_UINT32_READ - __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; - #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) - #endif - #ifndef __ALIGNED - #define __ALIGNED(x) __align(x) - #endif - #ifndef __RESTRICT - #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. - #define __RESTRICT - #endif - #ifndef __COMPILER_BARRIER - #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. - #define __COMPILER_BARRIER() (void)0 - #endif - - -/* - * COSMIC Compiler - */ -#elif defined ( __CSMC__ ) - #include - - #ifndef __ASM - #define __ASM _asm - #endif - #ifndef __INLINE - #define __INLINE inline - #endif - #ifndef __STATIC_INLINE - #define __STATIC_INLINE static inline - #endif - #ifndef __STATIC_FORCEINLINE - #define __STATIC_FORCEINLINE __STATIC_INLINE - #endif - #ifndef __NO_RETURN - // NO RETURN is automatically detected hence no warning here - #define __NO_RETURN - #endif - #ifndef __USED - #warning No compiler specific solution for __USED. __USED is ignored. - #define __USED - #endif - #ifndef __WEAK - #define __WEAK __weak - #endif - #ifndef __PACKED - #define __PACKED @packed - #endif - #ifndef __PACKED_STRUCT - #define __PACKED_STRUCT @packed struct - #endif - #ifndef __PACKED_UNION - #define __PACKED_UNION @packed union - #endif - #ifndef __UNALIGNED_UINT32 /* deprecated */ - @packed struct T_UINT32 { uint32_t v; }; - #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) - #endif - #ifndef __UNALIGNED_UINT16_WRITE - __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; - #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) - #endif - #ifndef __UNALIGNED_UINT16_READ - __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; - #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) - #endif - #ifndef __UNALIGNED_UINT32_WRITE - __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; - #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) - #endif - #ifndef __UNALIGNED_UINT32_READ - __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; - #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) - #endif - #ifndef __ALIGNED - #warning No compiler specific solution for __ALIGNED. __ALIGNED is ignored. - #define __ALIGNED(x) - #endif - #ifndef __RESTRICT - #warning No compiler specific solution for __RESTRICT. __RESTRICT is ignored. - #define __RESTRICT - #endif - #ifndef __COMPILER_BARRIER - #warning No compiler specific solution for __COMPILER_BARRIER. __COMPILER_BARRIER is ignored. - #define __COMPILER_BARRIER() (void)0 - #endif - - -#else - #error Unknown compiler. -#endif - - -#endif /* __CMSIS_COMPILER_H */ - - diff --git a/panda/board/inc/cmsis_gcc.h b/panda/board/inc/cmsis_gcc.h deleted file mode 100644 index 3589d18b24..0000000000 --- a/panda/board/inc/cmsis_gcc.h +++ /dev/null @@ -1,2169 +0,0 @@ -/**************************************************************************//** - * @file cmsis_gcc.h - * @brief CMSIS compiler GCC header file - * @version V5.2.0 - * @date 08. May 2019 - ******************************************************************************/ -/* - * Copyright (c) 2009-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. - */ - -#ifndef __CMSIS_GCC_H -#define __CMSIS_GCC_H - -/* ignore some GCC warnings */ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-conversion" -#pragma GCC diagnostic ignored "-Wconversion" -#pragma GCC diagnostic ignored "-Wunused-parameter" - -/* Fallback for __has_builtin */ -#ifndef __has_builtin - #define __has_builtin(x) (0) -#endif - -/* CMSIS compiler specific defines */ -#ifndef __ASM - #define __ASM __asm -#endif -#ifndef __INLINE - #define __INLINE inline -#endif -#ifndef __STATIC_INLINE - #define __STATIC_INLINE static inline -#endif -#ifndef __STATIC_FORCEINLINE - #define __STATIC_FORCEINLINE __attribute__((always_inline)) static inline -#endif -#ifndef __NO_RETURN - #define __NO_RETURN __attribute__((__noreturn__)) -#endif -#ifndef __USED - #define __USED __attribute__((used)) -#endif -#ifndef __WEAK - #define __WEAK __attribute__((weak)) -#endif -#ifndef __PACKED - #define __PACKED __attribute__((packed, aligned(1))) -#endif -#ifndef __PACKED_STRUCT - #define __PACKED_STRUCT struct __attribute__((packed, aligned(1))) -#endif -#ifndef __PACKED_UNION - #define __PACKED_UNION union __attribute__((packed, aligned(1))) -#endif -#ifndef __UNALIGNED_UINT32 /* deprecated */ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpacked" - #pragma GCC diagnostic ignored "-Wattributes" - struct __attribute__((packed)) T_UINT32 { uint32_t v; }; - #pragma GCC diagnostic pop - #define __UNALIGNED_UINT32(x) (((struct T_UINT32 *)(x))->v) -#endif -#ifndef __UNALIGNED_UINT16_WRITE - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpacked" - #pragma GCC diagnostic ignored "-Wattributes" - __PACKED_STRUCT T_UINT16_WRITE { uint16_t v; }; - #pragma GCC diagnostic pop - #define __UNALIGNED_UINT16_WRITE(addr, val) (void)((((struct T_UINT16_WRITE *)(void *)(addr))->v) = (val)) -#endif -#ifndef __UNALIGNED_UINT16_READ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpacked" - #pragma GCC diagnostic ignored "-Wattributes" - __PACKED_STRUCT T_UINT16_READ { uint16_t v; }; - #pragma GCC diagnostic pop - #define __UNALIGNED_UINT16_READ(addr) (((const struct T_UINT16_READ *)(const void *)(addr))->v) -#endif -#ifndef __UNALIGNED_UINT32_WRITE - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpacked" - #pragma GCC diagnostic ignored "-Wattributes" - __PACKED_STRUCT T_UINT32_WRITE { uint32_t v; }; - #pragma GCC diagnostic pop - #define __UNALIGNED_UINT32_WRITE(addr, val) (void)((((struct T_UINT32_WRITE *)(void *)(addr))->v) = (val)) -#endif -#ifndef __UNALIGNED_UINT32_READ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wpacked" - #pragma GCC diagnostic ignored "-Wattributes" - __PACKED_STRUCT T_UINT32_READ { uint32_t v; }; - #pragma GCC diagnostic pop - #define __UNALIGNED_UINT32_READ(addr) (((const struct T_UINT32_READ *)(const void *)(addr))->v) -#endif -#ifndef __ALIGNED - #define __ALIGNED(x) __attribute__((aligned(x))) -#endif -#ifndef __RESTRICT - #define __RESTRICT __restrict -#endif -#ifndef __COMPILER_BARRIER - #define __COMPILER_BARRIER() __ASM volatile("":::"memory") -#endif - -/* ######################### Startup and Lowlevel Init ######################## */ - -#ifndef __PROGRAM_START - -/** - \brief Initializes data and bss sections - \details This default implementations initialized all data and additional bss - sections relying on .copy.table and .zero.table specified properly - in the used linker script. - - */ -__STATIC_FORCEINLINE __NO_RETURN void __cmsis_start(void) -{ - extern void _start(void) __NO_RETURN; - - typedef struct { - uint32_t const* src; - uint32_t* dest; - uint32_t wlen; - } __copy_table_t; - - typedef struct { - uint32_t* dest; - uint32_t wlen; - } __zero_table_t; - - extern const __copy_table_t __copy_table_start__; - extern const __copy_table_t __copy_table_end__; - extern const __zero_table_t __zero_table_start__; - extern const __zero_table_t __zero_table_end__; - - for (__copy_table_t const* pTable = &__copy_table_start__; pTable < &__copy_table_end__; ++pTable) { - for(uint32_t i=0u; iwlen; ++i) { - pTable->dest[i] = pTable->src[i]; - } - } - - for (__zero_table_t const* pTable = &__zero_table_start__; pTable < &__zero_table_end__; ++pTable) { - for(uint32_t i=0u; iwlen; ++i) { - pTable->dest[i] = 0u; - } - } - - _start(); -} - -#define __PROGRAM_START __cmsis_start -#endif - -#ifndef __INITIAL_SP -#define __INITIAL_SP __StackTop -#endif - -#ifndef __STACK_LIMIT -#define __STACK_LIMIT __StackLimit -#endif - -#ifndef __VECTOR_TABLE -#define __VECTOR_TABLE __Vectors -#endif - -#ifndef __VECTOR_TABLE_ATTRIBUTE -#define __VECTOR_TABLE_ATTRIBUTE __attribute((used, section(".vectors"))) -#endif - -/* ########################### Core Function Access ########################### */ -/** \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions - @{ - */ - -/** - \brief Enable IRQ Interrupts - \details Enables IRQ interrupts by clearing the I-bit in the CPSR. - Can only be executed in Privileged modes. - */ -__STATIC_FORCEINLINE void __enable_irq(void) -{ - __ASM volatile ("cpsie i" : : : "memory"); -} - - -/** - \brief Disable IRQ Interrupts - \details Disables IRQ interrupts by setting the I-bit in the CPSR. - Can only be executed in Privileged modes. - */ -__STATIC_FORCEINLINE void __disable_irq(void) -{ - __ASM volatile ("cpsid i" : : : "memory"); -} - - -/** - \brief Get Control Register - \details Returns the content of the Control Register. - \return Control Register value - */ -__STATIC_FORCEINLINE uint32_t __get_CONTROL(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, control" : "=r" (result) ); - return(result); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Control Register (non-secure) - \details Returns the content of the non-secure Control Register when in secure mode. - \return non-secure Control Register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_CONTROL_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, control_ns" : "=r" (result) ); - return(result); -} -#endif - - -/** - \brief Set Control Register - \details Writes the given value to the Control Register. - \param [in] control Control Register value to set - */ -__STATIC_FORCEINLINE void __set_CONTROL(uint32_t control) -{ - __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Control Register (non-secure) - \details Writes the given value to the non-secure Control Register when in secure state. - \param [in] control Control Register value to set - */ -__STATIC_FORCEINLINE void __TZ_set_CONTROL_NS(uint32_t control) -{ - __ASM volatile ("MSR control_ns, %0" : : "r" (control) : "memory"); -} -#endif - - -/** - \brief Get IPSR Register - \details Returns the content of the IPSR Register. - \return IPSR Register value - */ -__STATIC_FORCEINLINE uint32_t __get_IPSR(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); - return(result); -} - - -/** - \brief Get APSR Register - \details Returns the content of the APSR Register. - \return APSR Register value - */ -__STATIC_FORCEINLINE uint32_t __get_APSR(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, apsr" : "=r" (result) ); - return(result); -} - - -/** - \brief Get xPSR Register - \details Returns the content of the xPSR Register. - \return xPSR Register value - */ -__STATIC_FORCEINLINE uint32_t __get_xPSR(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); - return(result); -} - - -/** - \brief Get Process Stack Pointer - \details Returns the current value of the Process Stack Pointer (PSP). - \return PSP Register value - */ -__STATIC_FORCEINLINE uint32_t __get_PSP(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, psp" : "=r" (result) ); - return(result); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Process Stack Pointer (non-secure) - \details Returns the current value of the non-secure Process Stack Pointer (PSP) when in secure state. - \return PSP Register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_PSP_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, psp_ns" : "=r" (result) ); - return(result); -} -#endif - - -/** - \brief Set Process Stack Pointer - \details Assigns the given value to the Process Stack Pointer (PSP). - \param [in] topOfProcStack Process Stack Pointer value to set - */ -__STATIC_FORCEINLINE void __set_PSP(uint32_t topOfProcStack) -{ - __ASM volatile ("MSR psp, %0" : : "r" (topOfProcStack) : ); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Process Stack Pointer (non-secure) - \details Assigns the given value to the non-secure Process Stack Pointer (PSP) when in secure state. - \param [in] topOfProcStack Process Stack Pointer value to set - */ -__STATIC_FORCEINLINE void __TZ_set_PSP_NS(uint32_t topOfProcStack) -{ - __ASM volatile ("MSR psp_ns, %0" : : "r" (topOfProcStack) : ); -} -#endif - - -/** - \brief Get Main Stack Pointer - \details Returns the current value of the Main Stack Pointer (MSP). - \return MSP Register value - */ -__STATIC_FORCEINLINE uint32_t __get_MSP(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, msp" : "=r" (result) ); - return(result); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Main Stack Pointer (non-secure) - \details Returns the current value of the non-secure Main Stack Pointer (MSP) when in secure state. - \return MSP Register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_MSP_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, msp_ns" : "=r" (result) ); - return(result); -} -#endif - - -/** - \brief Set Main Stack Pointer - \details Assigns the given value to the Main Stack Pointer (MSP). - \param [in] topOfMainStack Main Stack Pointer value to set - */ -__STATIC_FORCEINLINE void __set_MSP(uint32_t topOfMainStack) -{ - __ASM volatile ("MSR msp, %0" : : "r" (topOfMainStack) : ); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Main Stack Pointer (non-secure) - \details Assigns the given value to the non-secure Main Stack Pointer (MSP) when in secure state. - \param [in] topOfMainStack Main Stack Pointer value to set - */ -__STATIC_FORCEINLINE void __TZ_set_MSP_NS(uint32_t topOfMainStack) -{ - __ASM volatile ("MSR msp_ns, %0" : : "r" (topOfMainStack) : ); -} -#endif - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Stack Pointer (non-secure) - \details Returns the current value of the non-secure Stack Pointer (SP) when in secure state. - \return SP Register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_SP_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, sp_ns" : "=r" (result) ); - return(result); -} - - -/** - \brief Set Stack Pointer (non-secure) - \details Assigns the given value to the non-secure Stack Pointer (SP) when in secure state. - \param [in] topOfStack Stack Pointer value to set - */ -__STATIC_FORCEINLINE void __TZ_set_SP_NS(uint32_t topOfStack) -{ - __ASM volatile ("MSR sp_ns, %0" : : "r" (topOfStack) : ); -} -#endif - - -/** - \brief Get Priority Mask - \details Returns the current state of the priority mask bit from the Priority Mask Register. - \return Priority Mask value - */ -__STATIC_FORCEINLINE uint32_t __get_PRIMASK(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, primask" : "=r" (result) :: "memory"); - return(result); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Priority Mask (non-secure) - \details Returns the current state of the non-secure priority mask bit from the Priority Mask Register when in secure state. - \return Priority Mask value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_PRIMASK_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, primask_ns" : "=r" (result) :: "memory"); - return(result); -} -#endif - - -/** - \brief Set Priority Mask - \details Assigns the given value to the Priority Mask Register. - \param [in] priMask Priority Mask - */ -__STATIC_FORCEINLINE void __set_PRIMASK(uint32_t priMask) -{ - __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Priority Mask (non-secure) - \details Assigns the given value to the non-secure Priority Mask Register when in secure state. - \param [in] priMask Priority Mask - */ -__STATIC_FORCEINLINE void __TZ_set_PRIMASK_NS(uint32_t priMask) -{ - __ASM volatile ("MSR primask_ns, %0" : : "r" (priMask) : "memory"); -} -#endif - - -#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) -/** - \brief Enable FIQ - \details Enables FIQ interrupts by clearing the F-bit in the CPSR. - Can only be executed in Privileged modes. - */ -__STATIC_FORCEINLINE void __enable_fault_irq(void) -{ - __ASM volatile ("cpsie f" : : : "memory"); -} - - -/** - \brief Disable FIQ - \details Disables FIQ interrupts by setting the F-bit in the CPSR. - Can only be executed in Privileged modes. - */ -__STATIC_FORCEINLINE void __disable_fault_irq(void) -{ - __ASM volatile ("cpsid f" : : : "memory"); -} - - -/** - \brief Get Base Priority - \details Returns the current value of the Base Priority register. - \return Base Priority register value - */ -__STATIC_FORCEINLINE uint32_t __get_BASEPRI(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, basepri" : "=r" (result) ); - return(result); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Base Priority (non-secure) - \details Returns the current value of the non-secure Base Priority register when in secure state. - \return Base Priority register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_BASEPRI_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, basepri_ns" : "=r" (result) ); - return(result); -} -#endif - - -/** - \brief Set Base Priority - \details Assigns the given value to the Base Priority register. - \param [in] basePri Base Priority value to set - */ -__STATIC_FORCEINLINE void __set_BASEPRI(uint32_t basePri) -{ - __ASM volatile ("MSR basepri, %0" : : "r" (basePri) : "memory"); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Base Priority (non-secure) - \details Assigns the given value to the non-secure Base Priority register when in secure state. - \param [in] basePri Base Priority value to set - */ -__STATIC_FORCEINLINE void __TZ_set_BASEPRI_NS(uint32_t basePri) -{ - __ASM volatile ("MSR basepri_ns, %0" : : "r" (basePri) : "memory"); -} -#endif - - -/** - \brief Set Base Priority with condition - \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, - or the new value increases the BASEPRI priority level. - \param [in] basePri Base Priority value to set - */ -__STATIC_FORCEINLINE void __set_BASEPRI_MAX(uint32_t basePri) -{ - __ASM volatile ("MSR basepri_max, %0" : : "r" (basePri) : "memory"); -} - - -/** - \brief Get Fault Mask - \details Returns the current value of the Fault Mask register. - \return Fault Mask register value - */ -__STATIC_FORCEINLINE uint32_t __get_FAULTMASK(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); - return(result); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Fault Mask (non-secure) - \details Returns the current value of the non-secure Fault Mask register when in secure state. - \return Fault Mask register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_FAULTMASK_NS(void) -{ - uint32_t result; - - __ASM volatile ("MRS %0, faultmask_ns" : "=r" (result) ); - return(result); -} -#endif - - -/** - \brief Set Fault Mask - \details Assigns the given value to the Fault Mask register. - \param [in] faultMask Fault Mask value to set - */ -__STATIC_FORCEINLINE void __set_FAULTMASK(uint32_t faultMask) -{ - __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Fault Mask (non-secure) - \details Assigns the given value to the non-secure Fault Mask register when in secure state. - \param [in] faultMask Fault Mask value to set - */ -__STATIC_FORCEINLINE void __TZ_set_FAULTMASK_NS(uint32_t faultMask) -{ - __ASM volatile ("MSR faultmask_ns, %0" : : "r" (faultMask) : "memory"); -} -#endif - -#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ - - -#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ - (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) - -/** - \brief Get Process Stack Pointer Limit - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence zero is returned always in non-secure - mode. - - \details Returns the current value of the Process Stack Pointer Limit (PSPLIM). - \return PSPLIM Register value - */ -__STATIC_FORCEINLINE uint32_t __get_PSPLIM(void) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ - (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) - // without main extensions, the non-secure PSPLIM is RAZ/WI - return 0U; -#else - uint32_t result; - __ASM volatile ("MRS %0, psplim" : "=r" (result) ); - return result; -#endif -} - -#if (defined (__ARM_FEATURE_CMSE) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Process Stack Pointer Limit (non-secure) - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence zero is returned always. - - \details Returns the current value of the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. - \return PSPLIM Register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_PSPLIM_NS(void) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) - // without main extensions, the non-secure PSPLIM is RAZ/WI - return 0U; -#else - uint32_t result; - __ASM volatile ("MRS %0, psplim_ns" : "=r" (result) ); - return result; -#endif -} -#endif - - -/** - \brief Set Process Stack Pointer Limit - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence the write is silently ignored in non-secure - mode. - - \details Assigns the given value to the Process Stack Pointer Limit (PSPLIM). - \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set - */ -__STATIC_FORCEINLINE void __set_PSPLIM(uint32_t ProcStackPtrLimit) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ - (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) - // without main extensions, the non-secure PSPLIM is RAZ/WI - (void)ProcStackPtrLimit; -#else - __ASM volatile ("MSR psplim, %0" : : "r" (ProcStackPtrLimit)); -#endif -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Process Stack Pointer (non-secure) - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence the write is silently ignored. - - \details Assigns the given value to the non-secure Process Stack Pointer Limit (PSPLIM) when in secure state. - \param [in] ProcStackPtrLimit Process Stack Pointer Limit value to set - */ -__STATIC_FORCEINLINE void __TZ_set_PSPLIM_NS(uint32_t ProcStackPtrLimit) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) - // without main extensions, the non-secure PSPLIM is RAZ/WI - (void)ProcStackPtrLimit; -#else - __ASM volatile ("MSR psplim_ns, %0\n" : : "r" (ProcStackPtrLimit)); -#endif -} -#endif - - -/** - \brief Get Main Stack Pointer Limit - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence zero is returned always in non-secure - mode. - - \details Returns the current value of the Main Stack Pointer Limit (MSPLIM). - \return MSPLIM Register value - */ -__STATIC_FORCEINLINE uint32_t __get_MSPLIM(void) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ - (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) - // without main extensions, the non-secure MSPLIM is RAZ/WI - return 0U; -#else - uint32_t result; - __ASM volatile ("MRS %0, msplim" : "=r" (result) ); - return result; -#endif -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Get Main Stack Pointer Limit (non-secure) - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence zero is returned always. - - \details Returns the current value of the non-secure Main Stack Pointer Limit(MSPLIM) when in secure state. - \return MSPLIM Register value - */ -__STATIC_FORCEINLINE uint32_t __TZ_get_MSPLIM_NS(void) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) - // without main extensions, the non-secure MSPLIM is RAZ/WI - return 0U; -#else - uint32_t result; - __ASM volatile ("MRS %0, msplim_ns" : "=r" (result) ); - return result; -#endif -} -#endif - - -/** - \brief Set Main Stack Pointer Limit - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence the write is silently ignored in non-secure - mode. - - \details Assigns the given value to the Main Stack Pointer Limit (MSPLIM). - \param [in] MainStackPtrLimit Main Stack Pointer Limit value to set - */ -__STATIC_FORCEINLINE void __set_MSPLIM(uint32_t MainStackPtrLimit) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) && \ - (!defined (__ARM_FEATURE_CMSE) || (__ARM_FEATURE_CMSE < 3))) - // without main extensions, the non-secure MSPLIM is RAZ/WI - (void)MainStackPtrLimit; -#else - __ASM volatile ("MSR msplim, %0" : : "r" (MainStackPtrLimit)); -#endif -} - - -#if (defined (__ARM_FEATURE_CMSE ) && (__ARM_FEATURE_CMSE == 3)) -/** - \brief Set Main Stack Pointer Limit (non-secure) - Devices without ARMv8-M Main Extensions (i.e. Cortex-M23) lack the non-secure - Stack Pointer Limit register hence the write is silently ignored. - - \details Assigns the given value to the non-secure Main Stack Pointer Limit (MSPLIM) when in secure state. - \param [in] MainStackPtrLimit Main Stack Pointer value to set - */ -__STATIC_FORCEINLINE void __TZ_set_MSPLIM_NS(uint32_t MainStackPtrLimit) -{ -#if (!(defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1))) - // without main extensions, the non-secure MSPLIM is RAZ/WI - (void)MainStackPtrLimit; -#else - __ASM volatile ("MSR msplim_ns, %0" : : "r" (MainStackPtrLimit)); -#endif -} -#endif - -#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ - (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ - - -/** - \brief Get FPSCR - \details Returns the current value of the Floating Point Status/Control register. - \return Floating Point Status/Control register value - */ -__STATIC_FORCEINLINE uint32_t __get_FPSCR(void) -{ -#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ - (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) -#if __has_builtin(__builtin_arm_get_fpscr) -// Re-enable using built-in when GCC has been fixed -// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) - /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ - return __builtin_arm_get_fpscr(); -#else - uint32_t result; - - __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); - return(result); -#endif -#else - return(0U); -#endif -} - - -/** - \brief Set FPSCR - \details Assigns the given value to the Floating Point Status/Control register. - \param [in] fpscr Floating Point Status/Control value to set - */ -__STATIC_FORCEINLINE void __set_FPSCR(uint32_t fpscr) -{ -#if ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ - (defined (__FPU_USED ) && (__FPU_USED == 1U)) ) -#if __has_builtin(__builtin_arm_set_fpscr) -// Re-enable using built-in when GCC has been fixed -// || (__GNUC__ > 7) || (__GNUC__ == 7 && __GNUC_MINOR__ >= 2) - /* see https://gcc.gnu.org/ml/gcc-patches/2017-04/msg00443.html */ - __builtin_arm_set_fpscr(fpscr); -#else - __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc", "memory"); -#endif -#else - (void)fpscr; -#endif -} - - -/*@} end of CMSIS_Core_RegAccFunctions */ - - -/* ########################## Core Instruction Access ######################### */ -/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface - Access to dedicated instructions - @{ -*/ - -/* Define macros for porting to both thumb1 and thumb2. - * For thumb1, use low register (r0-r7), specified by constraint "l" - * Otherwise, use general registers, specified by constraint "r" */ -#if defined (__thumb__) && !defined (__thumb2__) -#define __CMSIS_GCC_OUT_REG(r) "=l" (r) -#define __CMSIS_GCC_RW_REG(r) "+l" (r) -#define __CMSIS_GCC_USE_REG(r) "l" (r) -#else -#define __CMSIS_GCC_OUT_REG(r) "=r" (r) -#define __CMSIS_GCC_RW_REG(r) "+r" (r) -#define __CMSIS_GCC_USE_REG(r) "r" (r) -#endif - -/** - \brief No Operation - \details No Operation does nothing. This instruction can be used for code alignment purposes. - */ -#define __NOP() __ASM volatile ("nop") - -/** - \brief Wait For Interrupt - \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. - */ -#define __WFI() __ASM volatile ("wfi") - - -/** - \brief Wait For Event - \details Wait For Event is a hint instruction that permits the processor to enter - a low-power state until one of a number of events occurs. - */ -#define __WFE() __ASM volatile ("wfe") - - -/** - \brief Send Event - \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. - */ -#define __SEV() __ASM volatile ("sev") - - -/** - \brief Instruction Synchronization Barrier - \details Instruction Synchronization Barrier flushes the pipeline in the processor, - so that all instructions following the ISB are fetched from cache or memory, - after the instruction has been completed. - */ -__STATIC_FORCEINLINE void __ISB(void) -{ - __ASM volatile ("isb 0xF":::"memory"); -} - - -/** - \brief Data Synchronization Barrier - \details Acts as a special kind of Data Memory Barrier. - It completes when all explicit memory accesses before this instruction complete. - */ -__STATIC_FORCEINLINE void __DSB(void) -{ - __ASM volatile ("dsb 0xF":::"memory"); -} - - -/** - \brief Data Memory Barrier - \details Ensures the apparent order of the explicit memory operations before - and after the instruction, without ensuring their completion. - */ -__STATIC_FORCEINLINE void __DMB(void) -{ - __ASM volatile ("dmb 0xF":::"memory"); -} - - -/** - \brief Reverse byte order (32 bit) - \details Reverses the byte order in unsigned integer value. For example, 0x12345678 becomes 0x78563412. - \param [in] value Value to reverse - \return Reversed value - */ -__STATIC_FORCEINLINE uint32_t __REV(uint32_t value) -{ -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) - return __builtin_bswap32(value); -#else - uint32_t result; - - __ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return result; -#endif -} - - -/** - \brief Reverse byte order (16 bit) - \details Reverses the byte order within each halfword of a word. For example, 0x12345678 becomes 0x34127856. - \param [in] value Value to reverse - \return Reversed value - */ -__STATIC_FORCEINLINE uint32_t __REV16(uint32_t value) -{ - uint32_t result; - - __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return result; -} - - -/** - \brief Reverse byte order (16 bit) - \details Reverses the byte order in a 16-bit value and returns the signed 16-bit result. For example, 0x0080 becomes 0x8000. - \param [in] value Value to reverse - \return Reversed value - */ -__STATIC_FORCEINLINE int16_t __REVSH(int16_t value) -{ -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - return (int16_t)__builtin_bswap16(value); -#else - int16_t result; - - __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return result; -#endif -} - - -/** - \brief Rotate Right in unsigned value (32 bit) - \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. - \param [in] op1 Value to rotate - \param [in] op2 Number of Bits to rotate - \return Rotated value - */ -__STATIC_FORCEINLINE uint32_t __ROR(uint32_t op1, uint32_t op2) -{ - op2 %= 32U; - if (op2 == 0U) - { - return op1; - } - return (op1 >> op2) | (op1 << (32U - op2)); -} - - -/** - \brief Breakpoint - \details Causes the processor to enter Debug state. - Debug tools can use this to investigate system state when the instruction at a particular address is reached. - \param [in] value is ignored by the processor. - If required, a debugger can use it to store additional information about the breakpoint. - */ -#define __BKPT(value) __ASM volatile ("bkpt "#value) - - -/** - \brief Reverse bit order of value - \details Reverses the bit order of the given value. - \param [in] value Value to reverse - \return Reversed value - */ -__STATIC_FORCEINLINE uint32_t __RBIT(uint32_t value) -{ - uint32_t result; - -#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) - __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); -#else - uint32_t s = (4U /*sizeof(v)*/ * 8U) - 1U; /* extra shift needed at end */ - - result = value; /* r will be reversed bits of v; first get LSB of v */ - for (value >>= 1U; value != 0U; value >>= 1U) - { - result <<= 1U; - result |= value & 1U; - s--; - } - result <<= s; /* shift when v's highest bits are zero */ -#endif - return result; -} - - -/** - \brief Count leading zeros - \details Counts the number of leading zeros of a data value. - \param [in] value Value to count the leading zeros - \return number of leading zeros in value - */ -__STATIC_FORCEINLINE uint8_t __CLZ(uint32_t value) -{ - /* Even though __builtin_clz produces a CLZ instruction on ARM, formally - __builtin_clz(0) is undefined behaviour, so handle this case specially. - This guarantees ARM-compatible results if happening to compile on a non-ARM - target, and ensures the compiler doesn't decide to activate any - optimisations using the logic "value was passed to __builtin_clz, so it - is non-zero". - ARM GCC 7.3 and possibly earlier will optimise this test away, leaving a - single CLZ instruction. - */ - if (value == 0U) - { - return 32U; - } - return __builtin_clz(value); -} - - -#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ - (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) -/** - \brief LDR Exclusive (8 bit) - \details Executes a exclusive LDR instruction for 8 bit value. - \param [in] ptr Pointer to data - \return value of type uint8_t at (*ptr) - */ -__STATIC_FORCEINLINE uint8_t __LDREXB(volatile uint8_t *addr) -{ - uint32_t result; - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); -#else - /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not - accepted by assembler. So has to use following less efficient pattern. - */ - __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); -#endif - return ((uint8_t) result); /* Add explicit type cast here */ -} - - -/** - \brief LDR Exclusive (16 bit) - \details Executes a exclusive LDR instruction for 16 bit values. - \param [in] ptr Pointer to data - \return value of type uint16_t at (*ptr) - */ -__STATIC_FORCEINLINE uint16_t __LDREXH(volatile uint16_t *addr) -{ - uint32_t result; - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); -#else - /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not - accepted by assembler. So has to use following less efficient pattern. - */ - __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); -#endif - return ((uint16_t) result); /* Add explicit type cast here */ -} - - -/** - \brief LDR Exclusive (32 bit) - \details Executes a exclusive LDR instruction for 32 bit values. - \param [in] ptr Pointer to data - \return value of type uint32_t at (*ptr) - */ -__STATIC_FORCEINLINE uint32_t __LDREXW(volatile uint32_t *addr) -{ - uint32_t result; - - __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); - return(result); -} - - -/** - \brief STR Exclusive (8 bit) - \details Executes a exclusive STR instruction for 8 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - \return 0 Function succeeded - \return 1 Function failed - */ -__STATIC_FORCEINLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) -{ - uint32_t result; - - __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); - return(result); -} - - -/** - \brief STR Exclusive (16 bit) - \details Executes a exclusive STR instruction for 16 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - \return 0 Function succeeded - \return 1 Function failed - */ -__STATIC_FORCEINLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) -{ - uint32_t result; - - __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); - return(result); -} - - -/** - \brief STR Exclusive (32 bit) - \details Executes a exclusive STR instruction for 32 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - \return 0 Function succeeded - \return 1 Function failed - */ -__STATIC_FORCEINLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) -{ - uint32_t result; - - __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); - return(result); -} - - -/** - \brief Remove the exclusive lock - \details Removes the exclusive lock which is created by LDREX. - */ -__STATIC_FORCEINLINE void __CLREX(void) -{ - __ASM volatile ("clrex" ::: "memory"); -} - -#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ - (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ - - -#if ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) -/** - \brief Signed Saturate - \details Saturates a signed value. - \param [in] ARG1 Value to be saturated - \param [in] ARG2 Bit position to saturate to (1..32) - \return Saturated value - */ -#define __SSAT(ARG1,ARG2) \ -__extension__ \ -({ \ - int32_t __RES, __ARG1 = (ARG1); \ - __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ - __RES; \ - }) - - -/** - \brief Unsigned Saturate - \details Saturates an unsigned value. - \param [in] ARG1 Value to be saturated - \param [in] ARG2 Bit position to saturate to (0..31) - \return Saturated value - */ -#define __USAT(ARG1,ARG2) \ - __extension__ \ -({ \ - uint32_t __RES, __ARG1 = (ARG1); \ - __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ - __RES; \ - }) - - -/** - \brief Rotate Right with Extend (32 bit) - \details Moves each bit of a bitstring right by one bit. - The carry input is shifted in at the left end of the bitstring. - \param [in] value Value to rotate - \return Rotated value - */ -__STATIC_FORCEINLINE uint32_t __RRX(uint32_t value) -{ - uint32_t result; - - __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); - return(result); -} - - -/** - \brief LDRT Unprivileged (8 bit) - \details Executes a Unprivileged LDRT instruction for 8 bit value. - \param [in] ptr Pointer to data - \return value of type uint8_t at (*ptr) - */ -__STATIC_FORCEINLINE uint8_t __LDRBT(volatile uint8_t *ptr) -{ - uint32_t result; - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*ptr) ); -#else - /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not - accepted by assembler. So has to use following less efficient pattern. - */ - __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); -#endif - return ((uint8_t) result); /* Add explicit type cast here */ -} - - -/** - \brief LDRT Unprivileged (16 bit) - \details Executes a Unprivileged LDRT instruction for 16 bit values. - \param [in] ptr Pointer to data - \return value of type uint16_t at (*ptr) - */ -__STATIC_FORCEINLINE uint16_t __LDRHT(volatile uint16_t *ptr) -{ - uint32_t result; - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) - __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*ptr) ); -#else - /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not - accepted by assembler. So has to use following less efficient pattern. - */ - __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (ptr) : "memory" ); -#endif - return ((uint16_t) result); /* Add explicit type cast here */ -} - - -/** - \brief LDRT Unprivileged (32 bit) - \details Executes a Unprivileged LDRT instruction for 32 bit values. - \param [in] ptr Pointer to data - \return value of type uint32_t at (*ptr) - */ -__STATIC_FORCEINLINE uint32_t __LDRT(volatile uint32_t *ptr) -{ - uint32_t result; - - __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*ptr) ); - return(result); -} - - -/** - \brief STRT Unprivileged (8 bit) - \details Executes a Unprivileged STRT instruction for 8 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - */ -__STATIC_FORCEINLINE void __STRBT(uint8_t value, volatile uint8_t *ptr) -{ - __ASM volatile ("strbt %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); -} - - -/** - \brief STRT Unprivileged (16 bit) - \details Executes a Unprivileged STRT instruction for 16 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - */ -__STATIC_FORCEINLINE void __STRHT(uint16_t value, volatile uint16_t *ptr) -{ - __ASM volatile ("strht %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); -} - - -/** - \brief STRT Unprivileged (32 bit) - \details Executes a Unprivileged STRT instruction for 32 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - */ -__STATIC_FORCEINLINE void __STRT(uint32_t value, volatile uint32_t *ptr) -{ - __ASM volatile ("strt %1, %0" : "=Q" (*ptr) : "r" (value) ); -} - -#else /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ - -/** - \brief Signed Saturate - \details Saturates a signed value. - \param [in] value Value to be saturated - \param [in] sat Bit position to saturate to (1..32) - \return Saturated value - */ -__STATIC_FORCEINLINE int32_t __SSAT(int32_t val, uint32_t sat) -{ - if ((sat >= 1U) && (sat <= 32U)) - { - const int32_t max = (int32_t)((1U << (sat - 1U)) - 1U); - const int32_t min = -1 - max ; - if (val > max) - { - return max; - } - else if (val < min) - { - return min; - } - } - return val; -} - -/** - \brief Unsigned Saturate - \details Saturates an unsigned value. - \param [in] value Value to be saturated - \param [in] sat Bit position to saturate to (0..31) - \return Saturated value - */ -__STATIC_FORCEINLINE uint32_t __USAT(int32_t val, uint32_t sat) -{ - if (sat <= 31U) - { - const uint32_t max = ((1U << sat) - 1U); - if (val > (int32_t)max) - { - return max; - } - else if (val < 0) - { - return 0U; - } - } - return (uint32_t)val; -} - -#endif /* ((defined (__ARM_ARCH_7M__ ) && (__ARM_ARCH_7M__ == 1)) || \ - (defined (__ARM_ARCH_7EM__ ) && (__ARM_ARCH_7EM__ == 1)) || \ - (defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) ) */ - - -#if ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ - (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) -/** - \brief Load-Acquire (8 bit) - \details Executes a LDAB instruction for 8 bit value. - \param [in] ptr Pointer to data - \return value of type uint8_t at (*ptr) - */ -__STATIC_FORCEINLINE uint8_t __LDAB(volatile uint8_t *ptr) -{ - uint32_t result; - - __ASM volatile ("ldab %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint8_t) result); -} - - -/** - \brief Load-Acquire (16 bit) - \details Executes a LDAH instruction for 16 bit values. - \param [in] ptr Pointer to data - \return value of type uint16_t at (*ptr) - */ -__STATIC_FORCEINLINE uint16_t __LDAH(volatile uint16_t *ptr) -{ - uint32_t result; - - __ASM volatile ("ldah %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint16_t) result); -} - - -/** - \brief Load-Acquire (32 bit) - \details Executes a LDA instruction for 32 bit values. - \param [in] ptr Pointer to data - \return value of type uint32_t at (*ptr) - */ -__STATIC_FORCEINLINE uint32_t __LDA(volatile uint32_t *ptr) -{ - uint32_t result; - - __ASM volatile ("lda %0, %1" : "=r" (result) : "Q" (*ptr) ); - return(result); -} - - -/** - \brief Store-Release (8 bit) - \details Executes a STLB instruction for 8 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - */ -__STATIC_FORCEINLINE void __STLB(uint8_t value, volatile uint8_t *ptr) -{ - __ASM volatile ("stlb %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); -} - - -/** - \brief Store-Release (16 bit) - \details Executes a STLH instruction for 16 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - */ -__STATIC_FORCEINLINE void __STLH(uint16_t value, volatile uint16_t *ptr) -{ - __ASM volatile ("stlh %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); -} - - -/** - \brief Store-Release (32 bit) - \details Executes a STL instruction for 32 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - */ -__STATIC_FORCEINLINE void __STL(uint32_t value, volatile uint32_t *ptr) -{ - __ASM volatile ("stl %1, %0" : "=Q" (*ptr) : "r" ((uint32_t)value) ); -} - - -/** - \brief Load-Acquire Exclusive (8 bit) - \details Executes a LDAB exclusive instruction for 8 bit value. - \param [in] ptr Pointer to data - \return value of type uint8_t at (*ptr) - */ -__STATIC_FORCEINLINE uint8_t __LDAEXB(volatile uint8_t *ptr) -{ - uint32_t result; - - __ASM volatile ("ldaexb %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint8_t) result); -} - - -/** - \brief Load-Acquire Exclusive (16 bit) - \details Executes a LDAH exclusive instruction for 16 bit values. - \param [in] ptr Pointer to data - \return value of type uint16_t at (*ptr) - */ -__STATIC_FORCEINLINE uint16_t __LDAEXH(volatile uint16_t *ptr) -{ - uint32_t result; - - __ASM volatile ("ldaexh %0, %1" : "=r" (result) : "Q" (*ptr) ); - return ((uint16_t) result); -} - - -/** - \brief Load-Acquire Exclusive (32 bit) - \details Executes a LDA exclusive instruction for 32 bit values. - \param [in] ptr Pointer to data - \return value of type uint32_t at (*ptr) - */ -__STATIC_FORCEINLINE uint32_t __LDAEX(volatile uint32_t *ptr) -{ - uint32_t result; - - __ASM volatile ("ldaex %0, %1" : "=r" (result) : "Q" (*ptr) ); - return(result); -} - - -/** - \brief Store-Release Exclusive (8 bit) - \details Executes a STLB exclusive instruction for 8 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - \return 0 Function succeeded - \return 1 Function failed - */ -__STATIC_FORCEINLINE uint32_t __STLEXB(uint8_t value, volatile uint8_t *ptr) -{ - uint32_t result; - - __ASM volatile ("stlexb %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); - return(result); -} - - -/** - \brief Store-Release Exclusive (16 bit) - \details Executes a STLH exclusive instruction for 16 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - \return 0 Function succeeded - \return 1 Function failed - */ -__STATIC_FORCEINLINE uint32_t __STLEXH(uint16_t value, volatile uint16_t *ptr) -{ - uint32_t result; - - __ASM volatile ("stlexh %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); - return(result); -} - - -/** - \brief Store-Release Exclusive (32 bit) - \details Executes a STL exclusive instruction for 32 bit values. - \param [in] value Value to store - \param [in] ptr Pointer to location - \return 0 Function succeeded - \return 1 Function failed - */ -__STATIC_FORCEINLINE uint32_t __STLEX(uint32_t value, volatile uint32_t *ptr) -{ - uint32_t result; - - __ASM volatile ("stlex %0, %2, %1" : "=&r" (result), "=Q" (*ptr) : "r" ((uint32_t)value) ); - return(result); -} - -#endif /* ((defined (__ARM_ARCH_8M_MAIN__ ) && (__ARM_ARCH_8M_MAIN__ == 1)) || \ - (defined (__ARM_ARCH_8M_BASE__ ) && (__ARM_ARCH_8M_BASE__ == 1)) ) */ - -/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ - - -/* ################### Compiler specific Intrinsics ########################### */ -/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics - Access to dedicated SIMD instructions - @{ -*/ - -#if (defined (__ARM_FEATURE_DSP) && (__ARM_FEATURE_DSP == 1)) - -__STATIC_FORCEINLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - - -__STATIC_FORCEINLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - - -__STATIC_FORCEINLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SASX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __QASX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UASX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __USAX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) -{ - uint32_t result; - - __ASM volatile ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); - return(result); -} - -#define __SSAT16(ARG1,ARG2) \ -({ \ - int32_t __RES, __ARG1 = (ARG1); \ - __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ - __RES; \ - }) - -#define __USAT16(ARG1,ARG2) \ -({ \ - uint32_t __RES, __ARG1 = (ARG1); \ - __ASM ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ - __RES; \ - }) - -__STATIC_FORCEINLINE uint32_t __UXTB16(uint32_t op1) -{ - uint32_t result; - - __ASM volatile ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SXTB16(uint32_t op1) -{ - uint32_t result; - - __ASM volatile ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) -{ - uint32_t result; - - __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) -{ - uint32_t result; - - __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); - return(result); -} - -__STATIC_FORCEINLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) -{ - union llreg_u{ - uint32_t w32[2]; - uint64_t w64; - } llr; - llr.w64 = acc; - -#ifndef __ARMEB__ /* Little endian */ - __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); -#else /* Big endian */ - __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); -#endif - - return(llr.w64); -} - -__STATIC_FORCEINLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) -{ - union llreg_u{ - uint32_t w32[2]; - uint64_t w64; - } llr; - llr.w64 = acc; - -#ifndef __ARMEB__ /* Little endian */ - __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); -#else /* Big endian */ - __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); -#endif - - return(llr.w64); -} - -__STATIC_FORCEINLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) -{ - uint32_t result; - - __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); - return(result); -} - -__STATIC_FORCEINLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) -{ - uint32_t result; - - __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); - return(result); -} - -__STATIC_FORCEINLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) -{ - union llreg_u{ - uint32_t w32[2]; - uint64_t w64; - } llr; - llr.w64 = acc; - -#ifndef __ARMEB__ /* Little endian */ - __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); -#else /* Big endian */ - __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); -#endif - - return(llr.w64); -} - -__STATIC_FORCEINLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) -{ - union llreg_u{ - uint32_t w32[2]; - uint64_t w64; - } llr; - llr.w64 = acc; - -#ifndef __ARMEB__ /* Little endian */ - __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); -#else /* Big endian */ - __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); -#endif - - return(llr.w64); -} - -__STATIC_FORCEINLINE uint32_t __SEL (uint32_t op1, uint32_t op2) -{ - uint32_t result; - - __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE int32_t __QADD( int32_t op1, int32_t op2) -{ - int32_t result; - - __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -__STATIC_FORCEINLINE int32_t __QSUB( int32_t op1, int32_t op2) -{ - int32_t result; - - __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); - return(result); -} - -#if 0 -#define __PKHBT(ARG1,ARG2,ARG3) \ -({ \ - uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ - __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ - __RES; \ - }) - -#define __PKHTB(ARG1,ARG2,ARG3) \ -({ \ - uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ - if (ARG3 == 0) \ - __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ - else \ - __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ - __RES; \ - }) -#endif - -#define __PKHBT(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0x0000FFFFUL) | \ - ((((uint32_t)(ARG2)) << (ARG3)) & 0xFFFF0000UL) ) - -#define __PKHTB(ARG1,ARG2,ARG3) ( ((((uint32_t)(ARG1)) ) & 0xFFFF0000UL) | \ - ((((uint32_t)(ARG2)) >> (ARG3)) & 0x0000FFFFUL) ) - -__STATIC_FORCEINLINE int32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) -{ - int32_t result; - - __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); - return(result); -} - -#endif /* (__ARM_FEATURE_DSP == 1) */ -/*@} end of group CMSIS_SIMD_intrinsics */ - - -#pragma GCC diagnostic pop - -#endif /* __CMSIS_GCC_H */ - diff --git a/panda/board/inc/cmsis_version.h b/panda/board/inc/cmsis_version.h deleted file mode 100644 index bf57cf3e80..0000000000 --- a/panda/board/inc/cmsis_version.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************//** - * @file cmsis_version.h - * @brief CMSIS Core(M) Version definitions - * @version V5.0.3 - * @date 24. June 2019 - ******************************************************************************/ -/* - * Copyright (c) 2009-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 __CMSIS_VERSION_H -#define __CMSIS_VERSION_H - -/* CMSIS Version definitions */ -#define __CM_CMSIS_VERSION_MAIN ( 5U) /*!< [31:16] CMSIS Core(M) main version */ -#define __CM_CMSIS_VERSION_SUB ( 3U) /*!< [15:0] CMSIS Core(M) sub version */ -#define __CM_CMSIS_VERSION ((__CM_CMSIS_VERSION_MAIN << 16U) | \ - __CM_CMSIS_VERSION_SUB ) /*!< CMSIS Core(M) version number */ -#endif - diff --git a/panda/board/inc/core_cm3.h b/panda/board/inc/core_cm3.h deleted file mode 100644 index 0918c5eb4c..0000000000 --- a/panda/board/inc/core_cm3.h +++ /dev/null @@ -1,1938 +0,0 @@ -/**************************************************************************//** - * @file core_cm3.h - * @brief CMSIS Cortex-M3 Core Peripheral Access Layer Header File - * @version V5.1.0 - * @date 13. March 2019 - ******************************************************************************/ -/* - * Copyright (c) 2009-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 __CORE_CM3_H_GENERIC -#define __CORE_CM3_H_GENERIC - -#include - -#ifdef __cplusplus - extern "C" { -#endif - -/** - \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions - CMSIS violates the following MISRA-C:2004 rules: - - \li Required Rule 8.5, object/function definition in header file.
- Function definitions in header files are used to allow 'inlining'. - - \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
- Unions are used for effective representation of core registers. - - \li Advisory Rule 19.7, Function-like macro defined.
- Function-like macros are used to allow more efficient code. - */ - - -/******************************************************************************* - * CMSIS definitions - ******************************************************************************/ -/** - \ingroup Cortex_M3 - @{ - */ - -#include "cmsis_version.h" - -/* CMSIS CM3 definitions */ -#define __CM3_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ -#define __CM3_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ -#define __CM3_CMSIS_VERSION ((__CM3_CMSIS_VERSION_MAIN << 16U) | \ - __CM3_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ - -#define __CORTEX_M (3U) /*!< Cortex-M Core */ - -/** __FPU_USED indicates whether an FPU is used or not. - This core does not support an FPU at all -*/ -#define __FPU_USED 0U - -#if defined ( __CC_ARM ) - #if defined __TARGET_FPU_VFP - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_FP - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#elif defined ( __GNUC__ ) - #if defined (__VFP_FP__) && !defined(__SOFTFP__) - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#elif defined ( __ICCARM__ ) - #if defined __ARMVFP__ - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#elif defined ( __TI_ARM__ ) - #if defined __TI_VFP_SUPPORT__ - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#elif defined ( __TASKING__ ) - #if defined __FPU_VFP__ - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#elif defined ( __CSMC__ ) - #if ( __CSMC__ & 0x400U) - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #endif - -#endif - -#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ - - -#ifdef __cplusplus -} -#endif - -#endif /* __CORE_CM3_H_GENERIC */ - -#ifndef __CMSIS_GENERIC - -#ifndef __CORE_CM3_H_DEPENDANT -#define __CORE_CM3_H_DEPENDANT - -#ifdef __cplusplus - extern "C" { -#endif - -/* check device defines and use defaults */ -#if defined __CHECK_DEVICE_DEFINES - #ifndef __CM3_REV - #define __CM3_REV 0x0200U - #warning "__CM3_REV not defined in device header file; using default!" - #endif - - #ifndef __MPU_PRESENT - #define __MPU_PRESENT 0U - #warning "__MPU_PRESENT not defined in device header file; using default!" - #endif - - #ifndef __NVIC_PRIO_BITS - #define __NVIC_PRIO_BITS 3U - #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" - #endif - - #ifndef __Vendor_SysTickConfig - #define __Vendor_SysTickConfig 0U - #warning "__Vendor_SysTickConfig not defined in device header file; using default!" - #endif -#endif - -/* IO definitions (access restrictions to peripheral registers) */ -/** - \defgroup CMSIS_glob_defs CMSIS Global Defines - - IO Type Qualifiers are used - \li to specify the access to peripheral variables. - \li for automatic generation of peripheral register debug information. -*/ -#ifdef __cplusplus - #define __I volatile /*!< Defines 'read only' permissions */ -#else - #define __I volatile const /*!< Defines 'read only' permissions */ -#endif -#define __O volatile /*!< Defines 'write only' permissions */ -#define __IO volatile /*!< Defines 'read / write' permissions */ - -/* following defines should be used for structure members */ -#define __IM volatile const /*! Defines 'read only' structure member permissions */ -#define __OM volatile /*! Defines 'write only' structure member permissions */ -#define __IOM volatile /*! Defines 'read / write' structure member permissions */ - -/*@} end of group Cortex_M3 */ - - - -/******************************************************************************* - * Register Abstraction - Core Register contain: - - Core Register - - Core NVIC Register - - Core SCB Register - - Core SysTick Register - - Core Debug Register - - Core MPU Register - ******************************************************************************/ -/** - \defgroup CMSIS_core_register Defines and Type Definitions - \brief Type definitions and defines for Cortex-M processor based devices. -*/ - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_CORE Status and Control Registers - \brief Core Register type definitions. - @{ - */ - -/** - \brief Union type to access the Application Program Status Register (APSR). - */ -typedef union -{ - struct - { - uint32_t _reserved0:27; /*!< bit: 0..26 Reserved */ - uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ - uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ - uint32_t C:1; /*!< bit: 29 Carry condition code flag */ - uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ - uint32_t N:1; /*!< bit: 31 Negative condition code flag */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} APSR_Type; - -/* APSR Register Definitions */ -#define APSR_N_Pos 31U /*!< APSR: N Position */ -#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ - -#define APSR_Z_Pos 30U /*!< APSR: Z Position */ -#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ - -#define APSR_C_Pos 29U /*!< APSR: C Position */ -#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ - -#define APSR_V_Pos 28U /*!< APSR: V Position */ -#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ - -#define APSR_Q_Pos 27U /*!< APSR: Q Position */ -#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ - - -/** - \brief Union type to access the Interrupt Program Status Register (IPSR). - */ -typedef union -{ - struct - { - uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} IPSR_Type; - -/* IPSR Register Definitions */ -#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ -#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ - - -/** - \brief Union type to access the Special-Purpose Program Status Registers (xPSR). - */ -typedef union -{ - struct - { - uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:1; /*!< bit: 9 Reserved */ - uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ - uint32_t _reserved1:8; /*!< bit: 16..23 Reserved */ - uint32_t T:1; /*!< bit: 24 Thumb bit */ - uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ - uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ - uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ - uint32_t C:1; /*!< bit: 29 Carry condition code flag */ - uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ - uint32_t N:1; /*!< bit: 31 Negative condition code flag */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} xPSR_Type; - -/* xPSR Register Definitions */ -#define xPSR_N_Pos 31U /*!< xPSR: N Position */ -#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ - -#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ -#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ - -#define xPSR_C_Pos 29U /*!< xPSR: C Position */ -#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ - -#define xPSR_V_Pos 28U /*!< xPSR: V Position */ -#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ - -#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ -#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ - -#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ -#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ - -#define xPSR_T_Pos 24U /*!< xPSR: T Position */ -#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ - -#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ -#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ - -#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ -#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ - - -/** - \brief Union type to access the Control Registers (CONTROL). - */ -typedef union -{ - struct - { - uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ - uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ - uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} CONTROL_Type; - -/* CONTROL Register Definitions */ -#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ -#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ - -#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ -#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ - -/*@} end of group CMSIS_CORE */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) - \brief Type definitions for the NVIC Registers - @{ - */ - -/** - \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). - */ -typedef struct -{ - __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ - uint32_t RESERVED0[24U]; - __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RESERVED1[24U]; - __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ - uint32_t RESERVED2[24U]; - __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ - uint32_t RESERVED3[24U]; - __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ - uint32_t RESERVED4[56U]; - __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ - uint32_t RESERVED5[644U]; - __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ -} NVIC_Type; - -/* Software Triggered Interrupt Register Definitions */ -#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ -#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ - -/*@} end of group CMSIS_NVIC */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_SCB System Control Block (SCB) - \brief Type definitions for the System Control Block Registers - @{ - */ - -/** - \brief Structure type to access the System Control Block (SCB). - */ -typedef struct -{ - __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ - __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ - __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ - __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ - __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ - __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ - __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ - __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ - __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ - __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ - __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ - __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ - __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ - __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ - __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ - __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ - __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ - __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ - __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ - uint32_t RESERVED0[5U]; - __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ -} SCB_Type; - -/* SCB CPUID Register Definitions */ -#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ -#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ - -#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ -#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ - -#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ -#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ - -#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ -#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ - -#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ -#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ - -/* SCB Interrupt Control State Register Definitions */ -#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ -#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ - -#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ -#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ - -#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ -#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ - -#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ -#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ - -#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ -#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ - -#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ -#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ - -#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ -#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ - -#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ -#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ - -#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ -#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ - -#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ -#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ - -/* SCB Vector Table Offset Register Definitions */ -#if defined (__CM3_REV) && (__CM3_REV < 0x0201U) /* core r2p1 */ -#define SCB_VTOR_TBLBASE_Pos 29U /*!< SCB VTOR: TBLBASE Position */ -#define SCB_VTOR_TBLBASE_Msk (1UL << SCB_VTOR_TBLBASE_Pos) /*!< SCB VTOR: TBLBASE Mask */ - -#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ -#define SCB_VTOR_TBLOFF_Msk (0x3FFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ -#else -#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ -#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ -#endif - -/* SCB Application Interrupt and Reset Control Register Definitions */ -#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ -#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ - -#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ -#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ - -#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ -#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ - -#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ -#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ - -#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ -#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ - -#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ -#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ - -#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ -#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ - -/* SCB System Control Register Definitions */ -#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ -#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ - -#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ -#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ - -#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ -#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ - -/* SCB Configuration Control Register Definitions */ -#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ -#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ - -#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ -#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ - -#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ -#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ - -#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ -#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ - -#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ -#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ - -#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ -#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ - -/* SCB System Handler Control and State Register Definitions */ -#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ -#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ - -#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ -#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ - -#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ -#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ - -#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ -#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ - -#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ -#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ - -#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ -#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ - -#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ -#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ - -#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ -#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ - -#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ -#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ - -#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ -#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ - -#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ -#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ - -#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ -#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ - -#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ -#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ - -#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ -#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ - -/* SCB Configurable Fault Status Register Definitions */ -#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ -#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ - -#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ -#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ - -#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ -#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ - -/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ -#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ -#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ - -#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ -#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ - -#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ -#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ - -#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ -#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ - -#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ -#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ - -/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ -#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ -#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ - -#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ -#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ - -#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ -#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ - -#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ -#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ - -#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ -#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ - -#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ -#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ - -/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ -#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ -#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ - -#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ -#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ - -#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ -#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ - -#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ -#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ - -#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ -#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ - -#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ -#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ - -/* SCB Hard Fault Status Register Definitions */ -#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ -#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ - -#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ -#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ - -#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ -#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ - -/* SCB Debug Fault Status Register Definitions */ -#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ -#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ - -#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ -#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ - -#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ -#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ - -#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ -#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ - -#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ -#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ - -/*@} end of group CMSIS_SCB */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) - \brief Type definitions for the System Control and ID Register not in the SCB - @{ - */ - -/** - \brief Structure type to access the System Control and ID Register not in the SCB. - */ -typedef struct -{ - uint32_t RESERVED0[1U]; - __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ -#if defined (__CM3_REV) && (__CM3_REV >= 0x200U) - __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ -#else - uint32_t RESERVED1[1U]; -#endif -} SCnSCB_Type; - -/* Interrupt Controller Type Register Definitions */ -#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ -#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ - -/* Auxiliary Control Register Definitions */ -#if defined (__CM3_REV) && (__CM3_REV >= 0x200U) -#define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ -#define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ - -#define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ -#define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ - -#define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ -#define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ - -#define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ -#define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ - -#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ -#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ -#endif - -/*@} end of group CMSIS_SCnotSCB */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_SysTick System Tick Timer (SysTick) - \brief Type definitions for the System Timer Registers. - @{ - */ - -/** - \brief Structure type to access the System Timer (SysTick). - */ -typedef struct -{ - __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ - __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ - __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ - __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ -} SysTick_Type; - -/* SysTick Control / Status Register Definitions */ -#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ -#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ - -#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ -#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ - -#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ -#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ - -#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ -#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ - -/* SysTick Reload Register Definitions */ -#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ -#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ - -/* SysTick Current Register Definitions */ -#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ -#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ - -/* SysTick Calibration Register Definitions */ -#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ -#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ - -#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ -#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ - -#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ -#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ - -/*@} end of group CMSIS_SysTick */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) - \brief Type definitions for the Instrumentation Trace Macrocell (ITM) - @{ - */ - -/** - \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). - */ -typedef struct -{ - __OM union - { - __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ - __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ - __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ - } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ - uint32_t RESERVED0[864U]; - __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ - uint32_t RESERVED1[15U]; - __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ - uint32_t RESERVED2[15U]; - __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[32U]; - uint32_t RESERVED4[43U]; - __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ - __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ - uint32_t RESERVED5[6U]; - __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ - __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ - __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ - __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ - __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ - __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ - __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ - __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ - __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ - __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ - __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ - __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ -} ITM_Type; - -/* ITM Trace Privilege Register Definitions */ -#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ -#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ - -/* ITM Trace Control Register Definitions */ -#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ -#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ - -#define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ -#define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ - -#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ -#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ - -#define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ -#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ - -#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ -#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ - -#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ -#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ - -#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ -#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ - -#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ -#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ - -#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ -#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ - -/* ITM Lock Status Register Definitions */ -#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ -#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ - -#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ -#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ - -#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ -#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ - -/*@}*/ /* end of group CMSIS_ITM */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) - \brief Type definitions for the Data Watchpoint and Trace (DWT) - @{ - */ - -/** - \brief Structure type to access the Data Watchpoint and Trace Register (DWT). - */ -typedef struct -{ - __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ - __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ - __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ - __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ - __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ - __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ - __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ - __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ - __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ - __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ - __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ - uint32_t RESERVED0[1U]; - __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ - __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ - __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ - uint32_t RESERVED1[1U]; - __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ - __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ - __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ - uint32_t RESERVED2[1U]; - __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ - __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ - __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ -} DWT_Type; - -/* DWT Control Register Definitions */ -#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ -#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ - -#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ -#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ - -#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ -#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ - -#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ -#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ - -#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ -#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ - -#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ -#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ - -#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ -#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ - -#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ -#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ - -#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ -#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ - -#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ -#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ - -#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ -#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ - -#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ -#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ - -#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ -#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ - -#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ -#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ - -#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ -#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ - -#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ -#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ - -#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ -#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ - -#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ -#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ - -/* DWT CPI Count Register Definitions */ -#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ -#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ - -/* DWT Exception Overhead Count Register Definitions */ -#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ -#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ - -/* DWT Sleep Count Register Definitions */ -#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ -#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ - -/* DWT LSU Count Register Definitions */ -#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ -#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ - -/* DWT Folded-instruction Count Register Definitions */ -#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ -#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ - -/* DWT Comparator Mask Register Definitions */ -#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ -#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ - -/* DWT Comparator Function Register Definitions */ -#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ -#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ - -#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ -#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ - -#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ -#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ - -#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ -#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ - -#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ -#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ - -#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ -#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ - -#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ -#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ - -#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ -#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ - -#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ -#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ - -/*@}*/ /* end of group CMSIS_DWT */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_TPI Trace Port Interface (TPI) - \brief Type definitions for the Trace Port Interface (TPI) - @{ - */ - -/** - \brief Structure type to access the Trace Port Interface Register (TPI). - */ -typedef struct -{ - __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ - __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ - uint32_t RESERVED0[2U]; - __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ - uint32_t RESERVED1[55U]; - __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ - uint32_t RESERVED2[131U]; - __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ - __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ - __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ - uint32_t RESERVED3[759U]; - __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ - __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ - __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ - uint32_t RESERVED4[1U]; - __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ - __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ - __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ - uint32_t RESERVED5[39U]; - __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ - __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ - uint32_t RESERVED7[8U]; - __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ - __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ -} TPI_Type; - -/* TPI Asynchronous Clock Prescaler Register Definitions */ -#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ -#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ - -/* TPI Selected Pin Protocol Register Definitions */ -#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ -#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ - -/* TPI Formatter and Flush Status Register Definitions */ -#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ -#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ - -#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ -#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ - -#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ -#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ - -#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ -#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ - -/* TPI Formatter and Flush Control Register Definitions */ -#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ -#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ - -#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ -#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ - -/* TPI TRIGGER Register Definitions */ -#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ -#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ - -/* TPI Integration ETM Data Register Definitions (FIFO0) */ -#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ -#define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ - -#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ -#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ - -#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ -#define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ - -#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ -#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ - -#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ -#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ - -#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ -#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ - -#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ -#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ - -/* TPI ITATBCTR2 Register Definitions */ -#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ -#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ - -#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ -#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ - -/* TPI Integration ITM Data Register Definitions (FIFO1) */ -#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ -#define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ - -#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ -#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ - -#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ -#define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ - -#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ -#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ - -#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ -#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ - -#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ -#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ - -#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ -#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ - -/* TPI ITATBCTR0 Register Definitions */ -#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ -#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ - -#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ -#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ - -/* TPI Integration Mode Control Register Definitions */ -#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ -#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ - -/* TPI DEVID Register Definitions */ -#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ -#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ - -#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ -#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ - -#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ -#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ - -#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ -#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ - -#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ -#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ - -#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ -#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ - -/* TPI DEVTYPE Register Definitions */ -#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ -#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ - -#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ -#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ - -/*@}*/ /* end of group CMSIS_TPI */ - - -#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_MPU Memory Protection Unit (MPU) - \brief Type definitions for the Memory Protection Unit (MPU) - @{ - */ - -/** - \brief Structure type to access the Memory Protection Unit (MPU). - */ -typedef struct -{ - __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ - __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ - __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ - __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ - __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ - __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ - __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ - __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ - __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ - __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ - __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ -} MPU_Type; - -#define MPU_TYPE_RALIASES 4U - -/* MPU Type Register Definitions */ -#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ -#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ - -#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ -#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ - -#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ -#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ - -/* MPU Control Register Definitions */ -#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ -#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ - -#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ -#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ - -#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ -#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ - -/* MPU Region Number Register Definitions */ -#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ -#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ - -/* MPU Region Base Address Register Definitions */ -#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ -#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ - -#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ -#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ - -#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ -#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ - -/* MPU Region Attribute and Size Register Definitions */ -#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ -#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ - -#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ -#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ - -#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ -#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ - -#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ -#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ - -#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ -#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ - -#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ -#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ - -#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ -#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ - -#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ -#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ - -#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ -#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ - -#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ -#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ - -/*@} end of group CMSIS_MPU */ -#endif - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) - \brief Type definitions for the Core Debug Registers - @{ - */ - -/** - \brief Structure type to access the Core Debug Register (CoreDebug). - */ -typedef struct -{ - __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ - __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ - __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ - __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ -} CoreDebug_Type; - -/* Debug Halting Control and Status Register Definitions */ -#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ -#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ - -#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ -#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ - -#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ -#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ - -#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ -#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ - -#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ -#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ - -#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ -#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ - -#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ -#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ - -#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ -#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ - -#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ -#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ - -#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ -#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ - -#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ -#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ - -#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ -#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ - -/* Debug Core Register Selector Register Definitions */ -#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ -#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ - -#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ -#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ - -/* Debug Exception and Monitor Control Register Definitions */ -#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ -#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ - -#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ -#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ - -#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ -#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ - -#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ -#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ - -#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ -#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ - -#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ -#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ - -#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ -#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ - -#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ -#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ - -#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ -#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ - -#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ -#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ - -#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ -#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ - -#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ -#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ - -#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ -#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ - -/*@} end of group CMSIS_CoreDebug */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_core_bitfield Core register bit field macros - \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). - @{ - */ - -/** - \brief Mask and shift a bit field value for use in a register bit range. - \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. - \return Masked and shifted value. -*/ -#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) - -/** - \brief Mask and shift a register value to extract a bit filed value. - \param[in] field Name of the register bit field. - \param[in] value Value of register. This parameter is interpreted as an uint32_t type. - \return Masked and shifted bit field value. -*/ -#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) - -/*@} end of group CMSIS_core_bitfield */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_core_base Core Definitions - \brief Definitions for base addresses, unions, and structures. - @{ - */ - -/* Memory mapping of Core Hardware */ -#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ -#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ -#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ -#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ -#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ -#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ -#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ -#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ - -#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ -#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ -#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ -#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ -#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ -#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ -#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ -#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ - -#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) - #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ - #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ -#endif - -/*@} */ - - - -/******************************************************************************* - * Hardware Abstraction Layer - Core Function Interface contains: - - Core NVIC Functions - - Core SysTick Functions - - Core Debug Functions - - Core Register Access Functions - ******************************************************************************/ -/** - \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference -*/ - - - -/* ########################## NVIC functions #################################### */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_NVICFunctions NVIC Functions - \brief Functions that manage interrupts and exceptions via the NVIC. - @{ - */ - -#ifdef CMSIS_NVIC_VIRTUAL - #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE - #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" - #endif - #include CMSIS_NVIC_VIRTUAL_HEADER_FILE -#else - #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping - #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping - #define NVIC_EnableIRQ __NVIC_EnableIRQ - #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ - #define NVIC_DisableIRQ __NVIC_DisableIRQ - #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ - #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ - #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ - #define NVIC_GetActive __NVIC_GetActive - #define NVIC_SetPriority __NVIC_SetPriority - #define NVIC_GetPriority __NVIC_GetPriority - #define NVIC_SystemReset __NVIC_SystemReset -#endif /* CMSIS_NVIC_VIRTUAL */ - -#ifdef CMSIS_VECTAB_VIRTUAL - #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE - #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" - #endif - #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE -#else - #define NVIC_SetVector __NVIC_SetVector - #define NVIC_GetVector __NVIC_GetVector -#endif /* (CMSIS_VECTAB_VIRTUAL) */ - -#define NVIC_USER_IRQ_OFFSET 16 - - -/* The following EXC_RETURN values are saved the LR on exception entry */ -#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ -#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ -#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ - - -/** - \brief Set Priority Grouping - \details Sets the priority grouping field using the required unlock sequence. - The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. - Only values from 0..7 are used. - In case of a conflict between priority grouping and available - priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. - \param [in] PriorityGroup Priority grouping field. - */ -__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) -{ - uint32_t reg_value; - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ - - reg_value = SCB->AIRCR; /* read old register configuration */ - reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ - reg_value = (reg_value | - ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ - SCB->AIRCR = reg_value; -} - - -/** - \brief Get Priority Grouping - \details Reads the priority grouping field from the NVIC Interrupt Controller. - \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). - */ -__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) -{ - return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); -} - - -/** - \brief Enable Interrupt - \details Enables a device specific interrupt in the NVIC interrupt controller. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - __COMPILER_BARRIER(); - NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - __COMPILER_BARRIER(); - } -} - - -/** - \brief Get Interrupt Enable status - \details Returns a device specific interrupt enable status from the NVIC interrupt controller. - \param [in] IRQn Device specific interrupt number. - \return 0 Interrupt is not enabled. - \return 1 Interrupt is enabled. - \note IRQn must not be negative. - */ -__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); - } - else - { - return(0U); - } -} - - -/** - \brief Disable Interrupt - \details Disables a device specific interrupt in the NVIC interrupt controller. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - __DSB(); - __ISB(); - } -} - - -/** - \brief Get Pending Interrupt - \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. - \param [in] IRQn Device specific interrupt number. - \return 0 Interrupt status is not pending. - \return 1 Interrupt status is pending. - \note IRQn must not be negative. - */ -__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); - } - else - { - return(0U); - } -} - - -/** - \brief Set Pending Interrupt - \details Sets the pending bit of a device specific interrupt in the NVIC pending register. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - } -} - - -/** - \brief Clear Pending Interrupt - \details Clears the pending bit of a device specific interrupt in the NVIC pending register. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - } -} - - -/** - \brief Get Active Interrupt - \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. - \param [in] IRQn Device specific interrupt number. - \return 0 Interrupt status is not active. - \return 1 Interrupt status is active. - \note IRQn must not be negative. - */ -__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); - } - else - { - return(0U); - } -} - - -/** - \brief Set Interrupt Priority - \details Sets the priority of a device specific interrupt or a processor exception. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - \param [in] IRQn Interrupt number. - \param [in] priority Priority to set. - \note The priority cannot be set for every processor exception. - */ -__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); - } - else - { - SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); - } -} - - -/** - \brief Get Interrupt Priority - \details Reads the priority of a device specific interrupt or a processor exception. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - \param [in] IRQn Interrupt number. - \return Interrupt Priority. - Value is aligned automatically to the implemented priority bits of the microcontroller. - */ -__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) -{ - - if ((int32_t)(IRQn) >= 0) - { - return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); - } - else - { - return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); - } -} - - -/** - \brief Encode Priority - \details Encodes the priority for an interrupt with the given priority group, - preemptive priority value, and subpriority value. - In case of a conflict between priority grouping and available - priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. - \param [in] PriorityGroup Used priority group. - \param [in] PreemptPriority Preemptive priority value (starting from 0). - \param [in] SubPriority Subpriority value (starting from 0). - \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). - */ -__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) -{ - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ - uint32_t PreemptPriorityBits; - uint32_t SubPriorityBits; - - PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); - SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); - - return ( - ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | - ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) - ); -} - - -/** - \brief Decode Priority - \details Decodes an interrupt priority value with a given priority group to - preemptive priority value and subpriority value. - In case of a conflict between priority grouping and available - priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. - \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). - \param [in] PriorityGroup Used priority group. - \param [out] pPreemptPriority Preemptive priority value (starting from 0). - \param [out] pSubPriority Subpriority value (starting from 0). - */ -__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) -{ - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ - uint32_t PreemptPriorityBits; - uint32_t SubPriorityBits; - - PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); - SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); - - *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); - *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); -} - - -/** - \brief Set Interrupt Vector - \details Sets an interrupt vector in SRAM based interrupt vector table. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - VTOR must been relocated to SRAM before. - \param [in] IRQn Interrupt number - \param [in] vector Address of interrupt handler function - */ -__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) -{ - uint32_t vectors = (uint32_t )SCB->VTOR; - (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; - /* ARM Application Note 321 states that the M3 does not require the architectural barrier */ -} - - -/** - \brief Get Interrupt Vector - \details Reads an interrupt vector from interrupt vector table. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - \param [in] IRQn Interrupt number. - \return Address of interrupt handler function - */ -__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) -{ - uint32_t vectors = (uint32_t )SCB->VTOR; - return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); -} - - -/** - \brief System Reset - \details Initiates a system reset request to reset the MCU. - */ -__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) -{ - __DSB(); /* Ensure all outstanding memory accesses included - buffered write are completed before reset */ - SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | - SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ - __DSB(); /* Ensure completion of memory access */ - - for(;;) /* wait until reset */ - { - __NOP(); - } -} - -/*@} end of CMSIS_Core_NVICFunctions */ - -/* ########################## MPU functions #################################### */ - -#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) - -#include "mpu_armv7.h" - -#endif - - -/* ########################## FPU functions #################################### */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_FpuFunctions FPU Functions - \brief Function that provides FPU type. - @{ - */ - -/** - \brief get FPU type - \details returns the FPU type - \returns - - \b 0: No FPU - - \b 1: Single precision FPU - - \b 2: Double + Single precision FPU - */ -__STATIC_INLINE uint32_t SCB_GetFPUType(void) -{ - return 0U; /* No FPU */ -} - - -/*@} end of CMSIS_Core_FpuFunctions */ - - - -/* ################################## SysTick function ############################################ */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_SysTickFunctions SysTick Functions - \brief Functions that configure the System. - @{ - */ - -#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) - -/** - \brief System Tick Configuration - \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. - Counter is in free running mode to generate periodic interrupts. - \param [in] ticks Number of ticks between two interrupts. - \return 0 Function succeeded. - \return 1 Function failed. - \note When the variable __Vendor_SysTickConfig is set to 1, then the - function SysTick_Config is not included. In this case, the file device.h - must contain a vendor-specific implementation of this function. - */ -__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) -{ - if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) - { - return (1UL); /* Reload value impossible */ - } - - SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ - NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ - SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | - SysTick_CTRL_TICKINT_Msk | - SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ - return (0UL); /* Function successful */ -} - -#endif - -/*@} end of CMSIS_Core_SysTickFunctions */ - - - -/* ##################################### Debug In/Output function ########################################### */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_core_DebugFunctions ITM Functions - \brief Functions that access the ITM debug interface. - @{ - */ - -extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ -#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ - - -/** - \brief ITM Send Character - \details Transmits a character via the ITM channel 0, and - \li Just returns when no debugger is connected that has booked the output. - \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. - \param [in] ch Character to transmit. - \returns Character to transmit. - */ -__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) -{ - if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ - ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ - { - while (ITM->PORT[0U].u32 == 0UL) - { - __NOP(); - } - ITM->PORT[0U].u8 = (uint8_t)ch; - } - return (ch); -} - - -/** - \brief ITM Receive Character - \details Inputs a character via the external variable \ref ITM_RxBuffer. - \return Received character. - \return -1 No character pending. - */ -__STATIC_INLINE int32_t ITM_ReceiveChar (void) -{ - int32_t ch = -1; /* no character available */ - - if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) - { - ch = ITM_RxBuffer; - ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ - } - - return (ch); -} - - -/** - \brief ITM Check Character - \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. - \return 0 No character available. - \return 1 Character available. - */ -__STATIC_INLINE int32_t ITM_CheckChar (void) -{ - - if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) - { - return (0); /* no character available */ - } - else - { - return (1); /* character available */ - } -} - -/*@} end of CMSIS_core_DebugFunctions */ - - - - -#ifdef __cplusplus -} -#endif - -#endif /* __CORE_CM3_H_DEPENDANT */ - -#endif /* __CMSIS_GENERIC */ - diff --git a/panda/board/inc/core_cm4.h b/panda/board/inc/core_cm4.h deleted file mode 100644 index 0d40081a38..0000000000 --- a/panda/board/inc/core_cm4.h +++ /dev/null @@ -1,2125 +0,0 @@ -/**************************************************************************//** - * @file core_cm4.h - * @brief CMSIS Cortex-M4 Core Peripheral Access Layer Header File - * @version V5.1.0 - * @date 13. March 2019 - ******************************************************************************/ -/* - * Copyright (c) 2009-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 __CORE_CM4_H_GENERIC -#define __CORE_CM4_H_GENERIC - -#include - -#ifdef __cplusplus - extern "C" { -#endif - -/** - \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions - CMSIS violates the following MISRA-C:2004 rules: - - \li Required Rule 8.5, object/function definition in header file.
- Function definitions in header files are used to allow 'inlining'. - - \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
- Unions are used for effective representation of core registers. - - \li Advisory Rule 19.7, Function-like macro defined.
- Function-like macros are used to allow more efficient code. - */ - - -/******************************************************************************* - * CMSIS definitions - ******************************************************************************/ -/** - \ingroup Cortex_M4 - @{ - */ - -#include "cmsis_version.h" - -/* CMSIS CM4 definitions */ -#define __CM4_CMSIS_VERSION_MAIN (__CM_CMSIS_VERSION_MAIN) /*!< \deprecated [31:16] CMSIS HAL main version */ -#define __CM4_CMSIS_VERSION_SUB (__CM_CMSIS_VERSION_SUB) /*!< \deprecated [15:0] CMSIS HAL sub version */ -#define __CM4_CMSIS_VERSION ((__CM4_CMSIS_VERSION_MAIN << 16U) | \ - __CM4_CMSIS_VERSION_SUB ) /*!< \deprecated CMSIS HAL version number */ - -#define __CORTEX_M (4U) /*!< Cortex-M Core */ - -/** __FPU_USED indicates whether an FPU is used or not. - For this, __FPU_PRESENT has to be checked prior to making use of FPU specific registers and functions. -*/ -#if defined ( __CC_ARM ) - #if defined __TARGET_FPU_VFP - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#elif defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) - #if defined __ARM_FP - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #warning "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#elif defined ( __GNUC__ ) - #if defined (__VFP_FP__) && !defined(__SOFTFP__) - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#elif defined ( __ICCARM__ ) - #if defined __ARMVFP__ - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#elif defined ( __TI_ARM__ ) - #if defined __TI_VFP_SUPPORT__ - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#elif defined ( __TASKING__ ) - #if defined __FPU_VFP__ - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#elif defined ( __CSMC__ ) - #if ( __CSMC__ & 0x400U) - #if defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U) - #define __FPU_USED 1U - #else - #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" - #define __FPU_USED 0U - #endif - #else - #define __FPU_USED 0U - #endif - -#endif - -#include "cmsis_compiler.h" /* CMSIS compiler specific defines */ - - -#ifdef __cplusplus -} -#endif - -#endif /* __CORE_CM4_H_GENERIC */ - -#ifndef __CMSIS_GENERIC - -#ifndef __CORE_CM4_H_DEPENDANT -#define __CORE_CM4_H_DEPENDANT - -#ifdef __cplusplus - extern "C" { -#endif - -/* check device defines and use defaults */ -#if defined __CHECK_DEVICE_DEFINES - #ifndef __CM4_REV - #define __CM4_REV 0x0000U - #warning "__CM4_REV not defined in device header file; using default!" - #endif - - #ifndef __FPU_PRESENT - #define __FPU_PRESENT 0U - #warning "__FPU_PRESENT not defined in device header file; using default!" - #endif - - #ifndef __MPU_PRESENT - #define __MPU_PRESENT 0U - #warning "__MPU_PRESENT not defined in device header file; using default!" - #endif - - #ifndef __NVIC_PRIO_BITS - #define __NVIC_PRIO_BITS 3U - #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" - #endif - - #ifndef __Vendor_SysTickConfig - #define __Vendor_SysTickConfig 0U - #warning "__Vendor_SysTickConfig not defined in device header file; using default!" - #endif -#endif - -/* IO definitions (access restrictions to peripheral registers) */ -/** - \defgroup CMSIS_glob_defs CMSIS Global Defines - - IO Type Qualifiers are used - \li to specify the access to peripheral variables. - \li for automatic generation of peripheral register debug information. -*/ -#ifdef __cplusplus - #define __I volatile /*!< Defines 'read only' permissions */ -#else - #define __I volatile const /*!< Defines 'read only' permissions */ -#endif -#define __O volatile /*!< Defines 'write only' permissions */ -#define __IO volatile /*!< Defines 'read / write' permissions */ - -/* following defines should be used for structure members */ -#define __IM volatile const /*! Defines 'read only' structure member permissions */ -#define __OM volatile /*! Defines 'write only' structure member permissions */ -#define __IOM volatile /*! Defines 'read / write' structure member permissions */ - -/*@} end of group Cortex_M4 */ - - - -/******************************************************************************* - * Register Abstraction - Core Register contain: - - Core Register - - Core NVIC Register - - Core SCB Register - - Core SysTick Register - - Core Debug Register - - Core MPU Register - - Core FPU Register - ******************************************************************************/ -/** - \defgroup CMSIS_core_register Defines and Type Definitions - \brief Type definitions and defines for Cortex-M processor based devices. -*/ - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_CORE Status and Control Registers - \brief Core Register type definitions. - @{ - */ - -/** - \brief Union type to access the Application Program Status Register (APSR). - */ -typedef union -{ - struct - { - uint32_t _reserved0:16; /*!< bit: 0..15 Reserved */ - uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ - uint32_t _reserved1:7; /*!< bit: 20..26 Reserved */ - uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ - uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ - uint32_t C:1; /*!< bit: 29 Carry condition code flag */ - uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ - uint32_t N:1; /*!< bit: 31 Negative condition code flag */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} APSR_Type; - -/* APSR Register Definitions */ -#define APSR_N_Pos 31U /*!< APSR: N Position */ -#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ - -#define APSR_Z_Pos 30U /*!< APSR: Z Position */ -#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ - -#define APSR_C_Pos 29U /*!< APSR: C Position */ -#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ - -#define APSR_V_Pos 28U /*!< APSR: V Position */ -#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ - -#define APSR_Q_Pos 27U /*!< APSR: Q Position */ -#define APSR_Q_Msk (1UL << APSR_Q_Pos) /*!< APSR: Q Mask */ - -#define APSR_GE_Pos 16U /*!< APSR: GE Position */ -#define APSR_GE_Msk (0xFUL << APSR_GE_Pos) /*!< APSR: GE Mask */ - - -/** - \brief Union type to access the Interrupt Program Status Register (IPSR). - */ -typedef union -{ - struct - { - uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} IPSR_Type; - -/* IPSR Register Definitions */ -#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ -#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ - - -/** - \brief Union type to access the Special-Purpose Program Status Registers (xPSR). - */ -typedef union -{ - struct - { - uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ - uint32_t _reserved0:1; /*!< bit: 9 Reserved */ - uint32_t ICI_IT_1:6; /*!< bit: 10..15 ICI/IT part 1 */ - uint32_t GE:4; /*!< bit: 16..19 Greater than or Equal flags */ - uint32_t _reserved1:4; /*!< bit: 20..23 Reserved */ - uint32_t T:1; /*!< bit: 24 Thumb bit */ - uint32_t ICI_IT_2:2; /*!< bit: 25..26 ICI/IT part 2 */ - uint32_t Q:1; /*!< bit: 27 Saturation condition flag */ - uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ - uint32_t C:1; /*!< bit: 29 Carry condition code flag */ - uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ - uint32_t N:1; /*!< bit: 31 Negative condition code flag */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} xPSR_Type; - -/* xPSR Register Definitions */ -#define xPSR_N_Pos 31U /*!< xPSR: N Position */ -#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ - -#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ -#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ - -#define xPSR_C_Pos 29U /*!< xPSR: C Position */ -#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ - -#define xPSR_V_Pos 28U /*!< xPSR: V Position */ -#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ - -#define xPSR_Q_Pos 27U /*!< xPSR: Q Position */ -#define xPSR_Q_Msk (1UL << xPSR_Q_Pos) /*!< xPSR: Q Mask */ - -#define xPSR_ICI_IT_2_Pos 25U /*!< xPSR: ICI/IT part 2 Position */ -#define xPSR_ICI_IT_2_Msk (3UL << xPSR_ICI_IT_2_Pos) /*!< xPSR: ICI/IT part 2 Mask */ - -#define xPSR_T_Pos 24U /*!< xPSR: T Position */ -#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ - -#define xPSR_GE_Pos 16U /*!< xPSR: GE Position */ -#define xPSR_GE_Msk (0xFUL << xPSR_GE_Pos) /*!< xPSR: GE Mask */ - -#define xPSR_ICI_IT_1_Pos 10U /*!< xPSR: ICI/IT part 1 Position */ -#define xPSR_ICI_IT_1_Msk (0x3FUL << xPSR_ICI_IT_1_Pos) /*!< xPSR: ICI/IT part 1 Mask */ - -#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ -#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ - - -/** - \brief Union type to access the Control Registers (CONTROL). - */ -typedef union -{ - struct - { - uint32_t nPRIV:1; /*!< bit: 0 Execution privilege in Thread mode */ - uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ - uint32_t FPCA:1; /*!< bit: 2 FP extension active flag */ - uint32_t _reserved0:29; /*!< bit: 3..31 Reserved */ - } b; /*!< Structure used for bit access */ - uint32_t w; /*!< Type used for word access */ -} CONTROL_Type; - -/* CONTROL Register Definitions */ -#define CONTROL_FPCA_Pos 2U /*!< CONTROL: FPCA Position */ -#define CONTROL_FPCA_Msk (1UL << CONTROL_FPCA_Pos) /*!< CONTROL: FPCA Mask */ - -#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ -#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ - -#define CONTROL_nPRIV_Pos 0U /*!< CONTROL: nPRIV Position */ -#define CONTROL_nPRIV_Msk (1UL /*<< CONTROL_nPRIV_Pos*/) /*!< CONTROL: nPRIV Mask */ - -/*@} end of group CMSIS_CORE */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) - \brief Type definitions for the NVIC Registers - @{ - */ - -/** - \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). - */ -typedef struct -{ - __IOM uint32_t ISER[8U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ - uint32_t RESERVED0[24U]; - __IOM uint32_t ICER[8U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ - uint32_t RESERVED1[24U]; - __IOM uint32_t ISPR[8U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ - uint32_t RESERVED2[24U]; - __IOM uint32_t ICPR[8U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ - uint32_t RESERVED3[24U]; - __IOM uint32_t IABR[8U]; /*!< Offset: 0x200 (R/W) Interrupt Active bit Register */ - uint32_t RESERVED4[56U]; - __IOM uint8_t IP[240U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register (8Bit wide) */ - uint32_t RESERVED5[644U]; - __OM uint32_t STIR; /*!< Offset: 0xE00 ( /W) Software Trigger Interrupt Register */ -} NVIC_Type; - -/* Software Triggered Interrupt Register Definitions */ -#define NVIC_STIR_INTID_Pos 0U /*!< STIR: INTLINESNUM Position */ -#define NVIC_STIR_INTID_Msk (0x1FFUL /*<< NVIC_STIR_INTID_Pos*/) /*!< STIR: INTLINESNUM Mask */ - -/*@} end of group CMSIS_NVIC */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_SCB System Control Block (SCB) - \brief Type definitions for the System Control Block Registers - @{ - */ - -/** - \brief Structure type to access the System Control Block (SCB). - */ -typedef struct -{ - __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ - __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ - __IOM uint32_t VTOR; /*!< Offset: 0x008 (R/W) Vector Table Offset Register */ - __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ - __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ - __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ - __IOM uint8_t SHP[12U]; /*!< Offset: 0x018 (R/W) System Handlers Priority Registers (4-7, 8-11, 12-15) */ - __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ - __IOM uint32_t CFSR; /*!< Offset: 0x028 (R/W) Configurable Fault Status Register */ - __IOM uint32_t HFSR; /*!< Offset: 0x02C (R/W) HardFault Status Register */ - __IOM uint32_t DFSR; /*!< Offset: 0x030 (R/W) Debug Fault Status Register */ - __IOM uint32_t MMFAR; /*!< Offset: 0x034 (R/W) MemManage Fault Address Register */ - __IOM uint32_t BFAR; /*!< Offset: 0x038 (R/W) BusFault Address Register */ - __IOM uint32_t AFSR; /*!< Offset: 0x03C (R/W) Auxiliary Fault Status Register */ - __IM uint32_t PFR[2U]; /*!< Offset: 0x040 (R/ ) Processor Feature Register */ - __IM uint32_t DFR; /*!< Offset: 0x048 (R/ ) Debug Feature Register */ - __IM uint32_t ADR; /*!< Offset: 0x04C (R/ ) Auxiliary Feature Register */ - __IM uint32_t MMFR[4U]; /*!< Offset: 0x050 (R/ ) Memory Model Feature Register */ - __IM uint32_t ISAR[5U]; /*!< Offset: 0x060 (R/ ) Instruction Set Attributes Register */ - uint32_t RESERVED0[5U]; - __IOM uint32_t CPACR; /*!< Offset: 0x088 (R/W) Coprocessor Access Control Register */ -} SCB_Type; - -/* SCB CPUID Register Definitions */ -#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ -#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ - -#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ -#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ - -#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ -#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ - -#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ -#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ - -#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ -#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ - -/* SCB Interrupt Control State Register Definitions */ -#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ -#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ - -#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ -#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ - -#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ -#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ - -#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ -#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ - -#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ -#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ - -#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ -#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ - -#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ -#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ - -#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ -#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ - -#define SCB_ICSR_RETTOBASE_Pos 11U /*!< SCB ICSR: RETTOBASE Position */ -#define SCB_ICSR_RETTOBASE_Msk (1UL << SCB_ICSR_RETTOBASE_Pos) /*!< SCB ICSR: RETTOBASE Mask */ - -#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ -#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ - -/* SCB Vector Table Offset Register Definitions */ -#define SCB_VTOR_TBLOFF_Pos 7U /*!< SCB VTOR: TBLOFF Position */ -#define SCB_VTOR_TBLOFF_Msk (0x1FFFFFFUL << SCB_VTOR_TBLOFF_Pos) /*!< SCB VTOR: TBLOFF Mask */ - -/* SCB Application Interrupt and Reset Control Register Definitions */ -#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ -#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ - -#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ -#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ - -#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ -#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ - -#define SCB_AIRCR_PRIGROUP_Pos 8U /*!< SCB AIRCR: PRIGROUP Position */ -#define SCB_AIRCR_PRIGROUP_Msk (7UL << SCB_AIRCR_PRIGROUP_Pos) /*!< SCB AIRCR: PRIGROUP Mask */ - -#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ -#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ - -#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ -#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ - -#define SCB_AIRCR_VECTRESET_Pos 0U /*!< SCB AIRCR: VECTRESET Position */ -#define SCB_AIRCR_VECTRESET_Msk (1UL /*<< SCB_AIRCR_VECTRESET_Pos*/) /*!< SCB AIRCR: VECTRESET Mask */ - -/* SCB System Control Register Definitions */ -#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ -#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ - -#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ -#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ - -#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ -#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ - -/* SCB Configuration Control Register Definitions */ -#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ -#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ - -#define SCB_CCR_BFHFNMIGN_Pos 8U /*!< SCB CCR: BFHFNMIGN Position */ -#define SCB_CCR_BFHFNMIGN_Msk (1UL << SCB_CCR_BFHFNMIGN_Pos) /*!< SCB CCR: BFHFNMIGN Mask */ - -#define SCB_CCR_DIV_0_TRP_Pos 4U /*!< SCB CCR: DIV_0_TRP Position */ -#define SCB_CCR_DIV_0_TRP_Msk (1UL << SCB_CCR_DIV_0_TRP_Pos) /*!< SCB CCR: DIV_0_TRP Mask */ - -#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ -#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ - -#define SCB_CCR_USERSETMPEND_Pos 1U /*!< SCB CCR: USERSETMPEND Position */ -#define SCB_CCR_USERSETMPEND_Msk (1UL << SCB_CCR_USERSETMPEND_Pos) /*!< SCB CCR: USERSETMPEND Mask */ - -#define SCB_CCR_NONBASETHRDENA_Pos 0U /*!< SCB CCR: NONBASETHRDENA Position */ -#define SCB_CCR_NONBASETHRDENA_Msk (1UL /*<< SCB_CCR_NONBASETHRDENA_Pos*/) /*!< SCB CCR: NONBASETHRDENA Mask */ - -/* SCB System Handler Control and State Register Definitions */ -#define SCB_SHCSR_USGFAULTENA_Pos 18U /*!< SCB SHCSR: USGFAULTENA Position */ -#define SCB_SHCSR_USGFAULTENA_Msk (1UL << SCB_SHCSR_USGFAULTENA_Pos) /*!< SCB SHCSR: USGFAULTENA Mask */ - -#define SCB_SHCSR_BUSFAULTENA_Pos 17U /*!< SCB SHCSR: BUSFAULTENA Position */ -#define SCB_SHCSR_BUSFAULTENA_Msk (1UL << SCB_SHCSR_BUSFAULTENA_Pos) /*!< SCB SHCSR: BUSFAULTENA Mask */ - -#define SCB_SHCSR_MEMFAULTENA_Pos 16U /*!< SCB SHCSR: MEMFAULTENA Position */ -#define SCB_SHCSR_MEMFAULTENA_Msk (1UL << SCB_SHCSR_MEMFAULTENA_Pos) /*!< SCB SHCSR: MEMFAULTENA Mask */ - -#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ -#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ - -#define SCB_SHCSR_BUSFAULTPENDED_Pos 14U /*!< SCB SHCSR: BUSFAULTPENDED Position */ -#define SCB_SHCSR_BUSFAULTPENDED_Msk (1UL << SCB_SHCSR_BUSFAULTPENDED_Pos) /*!< SCB SHCSR: BUSFAULTPENDED Mask */ - -#define SCB_SHCSR_MEMFAULTPENDED_Pos 13U /*!< SCB SHCSR: MEMFAULTPENDED Position */ -#define SCB_SHCSR_MEMFAULTPENDED_Msk (1UL << SCB_SHCSR_MEMFAULTPENDED_Pos) /*!< SCB SHCSR: MEMFAULTPENDED Mask */ - -#define SCB_SHCSR_USGFAULTPENDED_Pos 12U /*!< SCB SHCSR: USGFAULTPENDED Position */ -#define SCB_SHCSR_USGFAULTPENDED_Msk (1UL << SCB_SHCSR_USGFAULTPENDED_Pos) /*!< SCB SHCSR: USGFAULTPENDED Mask */ - -#define SCB_SHCSR_SYSTICKACT_Pos 11U /*!< SCB SHCSR: SYSTICKACT Position */ -#define SCB_SHCSR_SYSTICKACT_Msk (1UL << SCB_SHCSR_SYSTICKACT_Pos) /*!< SCB SHCSR: SYSTICKACT Mask */ - -#define SCB_SHCSR_PENDSVACT_Pos 10U /*!< SCB SHCSR: PENDSVACT Position */ -#define SCB_SHCSR_PENDSVACT_Msk (1UL << SCB_SHCSR_PENDSVACT_Pos) /*!< SCB SHCSR: PENDSVACT Mask */ - -#define SCB_SHCSR_MONITORACT_Pos 8U /*!< SCB SHCSR: MONITORACT Position */ -#define SCB_SHCSR_MONITORACT_Msk (1UL << SCB_SHCSR_MONITORACT_Pos) /*!< SCB SHCSR: MONITORACT Mask */ - -#define SCB_SHCSR_SVCALLACT_Pos 7U /*!< SCB SHCSR: SVCALLACT Position */ -#define SCB_SHCSR_SVCALLACT_Msk (1UL << SCB_SHCSR_SVCALLACT_Pos) /*!< SCB SHCSR: SVCALLACT Mask */ - -#define SCB_SHCSR_USGFAULTACT_Pos 3U /*!< SCB SHCSR: USGFAULTACT Position */ -#define SCB_SHCSR_USGFAULTACT_Msk (1UL << SCB_SHCSR_USGFAULTACT_Pos) /*!< SCB SHCSR: USGFAULTACT Mask */ - -#define SCB_SHCSR_BUSFAULTACT_Pos 1U /*!< SCB SHCSR: BUSFAULTACT Position */ -#define SCB_SHCSR_BUSFAULTACT_Msk (1UL << SCB_SHCSR_BUSFAULTACT_Pos) /*!< SCB SHCSR: BUSFAULTACT Mask */ - -#define SCB_SHCSR_MEMFAULTACT_Pos 0U /*!< SCB SHCSR: MEMFAULTACT Position */ -#define SCB_SHCSR_MEMFAULTACT_Msk (1UL /*<< SCB_SHCSR_MEMFAULTACT_Pos*/) /*!< SCB SHCSR: MEMFAULTACT Mask */ - -/* SCB Configurable Fault Status Register Definitions */ -#define SCB_CFSR_USGFAULTSR_Pos 16U /*!< SCB CFSR: Usage Fault Status Register Position */ -#define SCB_CFSR_USGFAULTSR_Msk (0xFFFFUL << SCB_CFSR_USGFAULTSR_Pos) /*!< SCB CFSR: Usage Fault Status Register Mask */ - -#define SCB_CFSR_BUSFAULTSR_Pos 8U /*!< SCB CFSR: Bus Fault Status Register Position */ -#define SCB_CFSR_BUSFAULTSR_Msk (0xFFUL << SCB_CFSR_BUSFAULTSR_Pos) /*!< SCB CFSR: Bus Fault Status Register Mask */ - -#define SCB_CFSR_MEMFAULTSR_Pos 0U /*!< SCB CFSR: Memory Manage Fault Status Register Position */ -#define SCB_CFSR_MEMFAULTSR_Msk (0xFFUL /*<< SCB_CFSR_MEMFAULTSR_Pos*/) /*!< SCB CFSR: Memory Manage Fault Status Register Mask */ - -/* MemManage Fault Status Register (part of SCB Configurable Fault Status Register) */ -#define SCB_CFSR_MMARVALID_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 7U) /*!< SCB CFSR (MMFSR): MMARVALID Position */ -#define SCB_CFSR_MMARVALID_Msk (1UL << SCB_CFSR_MMARVALID_Pos) /*!< SCB CFSR (MMFSR): MMARVALID Mask */ - -#define SCB_CFSR_MLSPERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 5U) /*!< SCB CFSR (MMFSR): MLSPERR Position */ -#define SCB_CFSR_MLSPERR_Msk (1UL << SCB_CFSR_MLSPERR_Pos) /*!< SCB CFSR (MMFSR): MLSPERR Mask */ - -#define SCB_CFSR_MSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 4U) /*!< SCB CFSR (MMFSR): MSTKERR Position */ -#define SCB_CFSR_MSTKERR_Msk (1UL << SCB_CFSR_MSTKERR_Pos) /*!< SCB CFSR (MMFSR): MSTKERR Mask */ - -#define SCB_CFSR_MUNSTKERR_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 3U) /*!< SCB CFSR (MMFSR): MUNSTKERR Position */ -#define SCB_CFSR_MUNSTKERR_Msk (1UL << SCB_CFSR_MUNSTKERR_Pos) /*!< SCB CFSR (MMFSR): MUNSTKERR Mask */ - -#define SCB_CFSR_DACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 1U) /*!< SCB CFSR (MMFSR): DACCVIOL Position */ -#define SCB_CFSR_DACCVIOL_Msk (1UL << SCB_CFSR_DACCVIOL_Pos) /*!< SCB CFSR (MMFSR): DACCVIOL Mask */ - -#define SCB_CFSR_IACCVIOL_Pos (SCB_SHCSR_MEMFAULTACT_Pos + 0U) /*!< SCB CFSR (MMFSR): IACCVIOL Position */ -#define SCB_CFSR_IACCVIOL_Msk (1UL /*<< SCB_CFSR_IACCVIOL_Pos*/) /*!< SCB CFSR (MMFSR): IACCVIOL Mask */ - -/* BusFault Status Register (part of SCB Configurable Fault Status Register) */ -#define SCB_CFSR_BFARVALID_Pos (SCB_CFSR_BUSFAULTSR_Pos + 7U) /*!< SCB CFSR (BFSR): BFARVALID Position */ -#define SCB_CFSR_BFARVALID_Msk (1UL << SCB_CFSR_BFARVALID_Pos) /*!< SCB CFSR (BFSR): BFARVALID Mask */ - -#define SCB_CFSR_LSPERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 5U) /*!< SCB CFSR (BFSR): LSPERR Position */ -#define SCB_CFSR_LSPERR_Msk (1UL << SCB_CFSR_LSPERR_Pos) /*!< SCB CFSR (BFSR): LSPERR Mask */ - -#define SCB_CFSR_STKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 4U) /*!< SCB CFSR (BFSR): STKERR Position */ -#define SCB_CFSR_STKERR_Msk (1UL << SCB_CFSR_STKERR_Pos) /*!< SCB CFSR (BFSR): STKERR Mask */ - -#define SCB_CFSR_UNSTKERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 3U) /*!< SCB CFSR (BFSR): UNSTKERR Position */ -#define SCB_CFSR_UNSTKERR_Msk (1UL << SCB_CFSR_UNSTKERR_Pos) /*!< SCB CFSR (BFSR): UNSTKERR Mask */ - -#define SCB_CFSR_IMPRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 2U) /*!< SCB CFSR (BFSR): IMPRECISERR Position */ -#define SCB_CFSR_IMPRECISERR_Msk (1UL << SCB_CFSR_IMPRECISERR_Pos) /*!< SCB CFSR (BFSR): IMPRECISERR Mask */ - -#define SCB_CFSR_PRECISERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 1U) /*!< SCB CFSR (BFSR): PRECISERR Position */ -#define SCB_CFSR_PRECISERR_Msk (1UL << SCB_CFSR_PRECISERR_Pos) /*!< SCB CFSR (BFSR): PRECISERR Mask */ - -#define SCB_CFSR_IBUSERR_Pos (SCB_CFSR_BUSFAULTSR_Pos + 0U) /*!< SCB CFSR (BFSR): IBUSERR Position */ -#define SCB_CFSR_IBUSERR_Msk (1UL << SCB_CFSR_IBUSERR_Pos) /*!< SCB CFSR (BFSR): IBUSERR Mask */ - -/* UsageFault Status Register (part of SCB Configurable Fault Status Register) */ -#define SCB_CFSR_DIVBYZERO_Pos (SCB_CFSR_USGFAULTSR_Pos + 9U) /*!< SCB CFSR (UFSR): DIVBYZERO Position */ -#define SCB_CFSR_DIVBYZERO_Msk (1UL << SCB_CFSR_DIVBYZERO_Pos) /*!< SCB CFSR (UFSR): DIVBYZERO Mask */ - -#define SCB_CFSR_UNALIGNED_Pos (SCB_CFSR_USGFAULTSR_Pos + 8U) /*!< SCB CFSR (UFSR): UNALIGNED Position */ -#define SCB_CFSR_UNALIGNED_Msk (1UL << SCB_CFSR_UNALIGNED_Pos) /*!< SCB CFSR (UFSR): UNALIGNED Mask */ - -#define SCB_CFSR_NOCP_Pos (SCB_CFSR_USGFAULTSR_Pos + 3U) /*!< SCB CFSR (UFSR): NOCP Position */ -#define SCB_CFSR_NOCP_Msk (1UL << SCB_CFSR_NOCP_Pos) /*!< SCB CFSR (UFSR): NOCP Mask */ - -#define SCB_CFSR_INVPC_Pos (SCB_CFSR_USGFAULTSR_Pos + 2U) /*!< SCB CFSR (UFSR): INVPC Position */ -#define SCB_CFSR_INVPC_Msk (1UL << SCB_CFSR_INVPC_Pos) /*!< SCB CFSR (UFSR): INVPC Mask */ - -#define SCB_CFSR_INVSTATE_Pos (SCB_CFSR_USGFAULTSR_Pos + 1U) /*!< SCB CFSR (UFSR): INVSTATE Position */ -#define SCB_CFSR_INVSTATE_Msk (1UL << SCB_CFSR_INVSTATE_Pos) /*!< SCB CFSR (UFSR): INVSTATE Mask */ - -#define SCB_CFSR_UNDEFINSTR_Pos (SCB_CFSR_USGFAULTSR_Pos + 0U) /*!< SCB CFSR (UFSR): UNDEFINSTR Position */ -#define SCB_CFSR_UNDEFINSTR_Msk (1UL << SCB_CFSR_UNDEFINSTR_Pos) /*!< SCB CFSR (UFSR): UNDEFINSTR Mask */ - -/* SCB Hard Fault Status Register Definitions */ -#define SCB_HFSR_DEBUGEVT_Pos 31U /*!< SCB HFSR: DEBUGEVT Position */ -#define SCB_HFSR_DEBUGEVT_Msk (1UL << SCB_HFSR_DEBUGEVT_Pos) /*!< SCB HFSR: DEBUGEVT Mask */ - -#define SCB_HFSR_FORCED_Pos 30U /*!< SCB HFSR: FORCED Position */ -#define SCB_HFSR_FORCED_Msk (1UL << SCB_HFSR_FORCED_Pos) /*!< SCB HFSR: FORCED Mask */ - -#define SCB_HFSR_VECTTBL_Pos 1U /*!< SCB HFSR: VECTTBL Position */ -#define SCB_HFSR_VECTTBL_Msk (1UL << SCB_HFSR_VECTTBL_Pos) /*!< SCB HFSR: VECTTBL Mask */ - -/* SCB Debug Fault Status Register Definitions */ -#define SCB_DFSR_EXTERNAL_Pos 4U /*!< SCB DFSR: EXTERNAL Position */ -#define SCB_DFSR_EXTERNAL_Msk (1UL << SCB_DFSR_EXTERNAL_Pos) /*!< SCB DFSR: EXTERNAL Mask */ - -#define SCB_DFSR_VCATCH_Pos 3U /*!< SCB DFSR: VCATCH Position */ -#define SCB_DFSR_VCATCH_Msk (1UL << SCB_DFSR_VCATCH_Pos) /*!< SCB DFSR: VCATCH Mask */ - -#define SCB_DFSR_DWTTRAP_Pos 2U /*!< SCB DFSR: DWTTRAP Position */ -#define SCB_DFSR_DWTTRAP_Msk (1UL << SCB_DFSR_DWTTRAP_Pos) /*!< SCB DFSR: DWTTRAP Mask */ - -#define SCB_DFSR_BKPT_Pos 1U /*!< SCB DFSR: BKPT Position */ -#define SCB_DFSR_BKPT_Msk (1UL << SCB_DFSR_BKPT_Pos) /*!< SCB DFSR: BKPT Mask */ - -#define SCB_DFSR_HALTED_Pos 0U /*!< SCB DFSR: HALTED Position */ -#define SCB_DFSR_HALTED_Msk (1UL /*<< SCB_DFSR_HALTED_Pos*/) /*!< SCB DFSR: HALTED Mask */ - -/*@} end of group CMSIS_SCB */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_SCnSCB System Controls not in SCB (SCnSCB) - \brief Type definitions for the System Control and ID Register not in the SCB - @{ - */ - -/** - \brief Structure type to access the System Control and ID Register not in the SCB. - */ -typedef struct -{ - uint32_t RESERVED0[1U]; - __IM uint32_t ICTR; /*!< Offset: 0x004 (R/ ) Interrupt Controller Type Register */ - __IOM uint32_t ACTLR; /*!< Offset: 0x008 (R/W) Auxiliary Control Register */ -} SCnSCB_Type; - -/* Interrupt Controller Type Register Definitions */ -#define SCnSCB_ICTR_INTLINESNUM_Pos 0U /*!< ICTR: INTLINESNUM Position */ -#define SCnSCB_ICTR_INTLINESNUM_Msk (0xFUL /*<< SCnSCB_ICTR_INTLINESNUM_Pos*/) /*!< ICTR: INTLINESNUM Mask */ - -/* Auxiliary Control Register Definitions */ -#define SCnSCB_ACTLR_DISOOFP_Pos 9U /*!< ACTLR: DISOOFP Position */ -#define SCnSCB_ACTLR_DISOOFP_Msk (1UL << SCnSCB_ACTLR_DISOOFP_Pos) /*!< ACTLR: DISOOFP Mask */ - -#define SCnSCB_ACTLR_DISFPCA_Pos 8U /*!< ACTLR: DISFPCA Position */ -#define SCnSCB_ACTLR_DISFPCA_Msk (1UL << SCnSCB_ACTLR_DISFPCA_Pos) /*!< ACTLR: DISFPCA Mask */ - -#define SCnSCB_ACTLR_DISFOLD_Pos 2U /*!< ACTLR: DISFOLD Position */ -#define SCnSCB_ACTLR_DISFOLD_Msk (1UL << SCnSCB_ACTLR_DISFOLD_Pos) /*!< ACTLR: DISFOLD Mask */ - -#define SCnSCB_ACTLR_DISDEFWBUF_Pos 1U /*!< ACTLR: DISDEFWBUF Position */ -#define SCnSCB_ACTLR_DISDEFWBUF_Msk (1UL << SCnSCB_ACTLR_DISDEFWBUF_Pos) /*!< ACTLR: DISDEFWBUF Mask */ - -#define SCnSCB_ACTLR_DISMCYCINT_Pos 0U /*!< ACTLR: DISMCYCINT Position */ -#define SCnSCB_ACTLR_DISMCYCINT_Msk (1UL /*<< SCnSCB_ACTLR_DISMCYCINT_Pos*/) /*!< ACTLR: DISMCYCINT Mask */ - -/*@} end of group CMSIS_SCnotSCB */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_SysTick System Tick Timer (SysTick) - \brief Type definitions for the System Timer Registers. - @{ - */ - -/** - \brief Structure type to access the System Timer (SysTick). - */ -typedef struct -{ - __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ - __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ - __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ - __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ -} SysTick_Type; - -/* SysTick Control / Status Register Definitions */ -#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ -#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ - -#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ -#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ - -#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ -#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ - -#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ -#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ - -/* SysTick Reload Register Definitions */ -#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ -#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ - -/* SysTick Current Register Definitions */ -#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ -#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ - -/* SysTick Calibration Register Definitions */ -#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ -#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ - -#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ -#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ - -#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ -#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ - -/*@} end of group CMSIS_SysTick */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_ITM Instrumentation Trace Macrocell (ITM) - \brief Type definitions for the Instrumentation Trace Macrocell (ITM) - @{ - */ - -/** - \brief Structure type to access the Instrumentation Trace Macrocell Register (ITM). - */ -typedef struct -{ - __OM union - { - __OM uint8_t u8; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 8-bit */ - __OM uint16_t u16; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 16-bit */ - __OM uint32_t u32; /*!< Offset: 0x000 ( /W) ITM Stimulus Port 32-bit */ - } PORT [32U]; /*!< Offset: 0x000 ( /W) ITM Stimulus Port Registers */ - uint32_t RESERVED0[864U]; - __IOM uint32_t TER; /*!< Offset: 0xE00 (R/W) ITM Trace Enable Register */ - uint32_t RESERVED1[15U]; - __IOM uint32_t TPR; /*!< Offset: 0xE40 (R/W) ITM Trace Privilege Register */ - uint32_t RESERVED2[15U]; - __IOM uint32_t TCR; /*!< Offset: 0xE80 (R/W) ITM Trace Control Register */ - uint32_t RESERVED3[32U]; - uint32_t RESERVED4[43U]; - __OM uint32_t LAR; /*!< Offset: 0xFB0 ( /W) ITM Lock Access Register */ - __IM uint32_t LSR; /*!< Offset: 0xFB4 (R/ ) ITM Lock Status Register */ - uint32_t RESERVED5[6U]; - __IM uint32_t PID4; /*!< Offset: 0xFD0 (R/ ) ITM Peripheral Identification Register #4 */ - __IM uint32_t PID5; /*!< Offset: 0xFD4 (R/ ) ITM Peripheral Identification Register #5 */ - __IM uint32_t PID6; /*!< Offset: 0xFD8 (R/ ) ITM Peripheral Identification Register #6 */ - __IM uint32_t PID7; /*!< Offset: 0xFDC (R/ ) ITM Peripheral Identification Register #7 */ - __IM uint32_t PID0; /*!< Offset: 0xFE0 (R/ ) ITM Peripheral Identification Register #0 */ - __IM uint32_t PID1; /*!< Offset: 0xFE4 (R/ ) ITM Peripheral Identification Register #1 */ - __IM uint32_t PID2; /*!< Offset: 0xFE8 (R/ ) ITM Peripheral Identification Register #2 */ - __IM uint32_t PID3; /*!< Offset: 0xFEC (R/ ) ITM Peripheral Identification Register #3 */ - __IM uint32_t CID0; /*!< Offset: 0xFF0 (R/ ) ITM Component Identification Register #0 */ - __IM uint32_t CID1; /*!< Offset: 0xFF4 (R/ ) ITM Component Identification Register #1 */ - __IM uint32_t CID2; /*!< Offset: 0xFF8 (R/ ) ITM Component Identification Register #2 */ - __IM uint32_t CID3; /*!< Offset: 0xFFC (R/ ) ITM Component Identification Register #3 */ -} ITM_Type; - -/* ITM Trace Privilege Register Definitions */ -#define ITM_TPR_PRIVMASK_Pos 0U /*!< ITM TPR: PRIVMASK Position */ -#define ITM_TPR_PRIVMASK_Msk (0xFFFFFFFFUL /*<< ITM_TPR_PRIVMASK_Pos*/) /*!< ITM TPR: PRIVMASK Mask */ - -/* ITM Trace Control Register Definitions */ -#define ITM_TCR_BUSY_Pos 23U /*!< ITM TCR: BUSY Position */ -#define ITM_TCR_BUSY_Msk (1UL << ITM_TCR_BUSY_Pos) /*!< ITM TCR: BUSY Mask */ - -#define ITM_TCR_TraceBusID_Pos 16U /*!< ITM TCR: ATBID Position */ -#define ITM_TCR_TraceBusID_Msk (0x7FUL << ITM_TCR_TraceBusID_Pos) /*!< ITM TCR: ATBID Mask */ - -#define ITM_TCR_GTSFREQ_Pos 10U /*!< ITM TCR: Global timestamp frequency Position */ -#define ITM_TCR_GTSFREQ_Msk (3UL << ITM_TCR_GTSFREQ_Pos) /*!< ITM TCR: Global timestamp frequency Mask */ - -#define ITM_TCR_TSPrescale_Pos 8U /*!< ITM TCR: TSPrescale Position */ -#define ITM_TCR_TSPrescale_Msk (3UL << ITM_TCR_TSPrescale_Pos) /*!< ITM TCR: TSPrescale Mask */ - -#define ITM_TCR_SWOENA_Pos 4U /*!< ITM TCR: SWOENA Position */ -#define ITM_TCR_SWOENA_Msk (1UL << ITM_TCR_SWOENA_Pos) /*!< ITM TCR: SWOENA Mask */ - -#define ITM_TCR_DWTENA_Pos 3U /*!< ITM TCR: DWTENA Position */ -#define ITM_TCR_DWTENA_Msk (1UL << ITM_TCR_DWTENA_Pos) /*!< ITM TCR: DWTENA Mask */ - -#define ITM_TCR_SYNCENA_Pos 2U /*!< ITM TCR: SYNCENA Position */ -#define ITM_TCR_SYNCENA_Msk (1UL << ITM_TCR_SYNCENA_Pos) /*!< ITM TCR: SYNCENA Mask */ - -#define ITM_TCR_TSENA_Pos 1U /*!< ITM TCR: TSENA Position */ -#define ITM_TCR_TSENA_Msk (1UL << ITM_TCR_TSENA_Pos) /*!< ITM TCR: TSENA Mask */ - -#define ITM_TCR_ITMENA_Pos 0U /*!< ITM TCR: ITM Enable bit Position */ -#define ITM_TCR_ITMENA_Msk (1UL /*<< ITM_TCR_ITMENA_Pos*/) /*!< ITM TCR: ITM Enable bit Mask */ - -/* ITM Lock Status Register Definitions */ -#define ITM_LSR_ByteAcc_Pos 2U /*!< ITM LSR: ByteAcc Position */ -#define ITM_LSR_ByteAcc_Msk (1UL << ITM_LSR_ByteAcc_Pos) /*!< ITM LSR: ByteAcc Mask */ - -#define ITM_LSR_Access_Pos 1U /*!< ITM LSR: Access Position */ -#define ITM_LSR_Access_Msk (1UL << ITM_LSR_Access_Pos) /*!< ITM LSR: Access Mask */ - -#define ITM_LSR_Present_Pos 0U /*!< ITM LSR: Present Position */ -#define ITM_LSR_Present_Msk (1UL /*<< ITM_LSR_Present_Pos*/) /*!< ITM LSR: Present Mask */ - -/*@}*/ /* end of group CMSIS_ITM */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_DWT Data Watchpoint and Trace (DWT) - \brief Type definitions for the Data Watchpoint and Trace (DWT) - @{ - */ - -/** - \brief Structure type to access the Data Watchpoint and Trace Register (DWT). - */ -typedef struct -{ - __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) Control Register */ - __IOM uint32_t CYCCNT; /*!< Offset: 0x004 (R/W) Cycle Count Register */ - __IOM uint32_t CPICNT; /*!< Offset: 0x008 (R/W) CPI Count Register */ - __IOM uint32_t EXCCNT; /*!< Offset: 0x00C (R/W) Exception Overhead Count Register */ - __IOM uint32_t SLEEPCNT; /*!< Offset: 0x010 (R/W) Sleep Count Register */ - __IOM uint32_t LSUCNT; /*!< Offset: 0x014 (R/W) LSU Count Register */ - __IOM uint32_t FOLDCNT; /*!< Offset: 0x018 (R/W) Folded-instruction Count Register */ - __IM uint32_t PCSR; /*!< Offset: 0x01C (R/ ) Program Counter Sample Register */ - __IOM uint32_t COMP0; /*!< Offset: 0x020 (R/W) Comparator Register 0 */ - __IOM uint32_t MASK0; /*!< Offset: 0x024 (R/W) Mask Register 0 */ - __IOM uint32_t FUNCTION0; /*!< Offset: 0x028 (R/W) Function Register 0 */ - uint32_t RESERVED0[1U]; - __IOM uint32_t COMP1; /*!< Offset: 0x030 (R/W) Comparator Register 1 */ - __IOM uint32_t MASK1; /*!< Offset: 0x034 (R/W) Mask Register 1 */ - __IOM uint32_t FUNCTION1; /*!< Offset: 0x038 (R/W) Function Register 1 */ - uint32_t RESERVED1[1U]; - __IOM uint32_t COMP2; /*!< Offset: 0x040 (R/W) Comparator Register 2 */ - __IOM uint32_t MASK2; /*!< Offset: 0x044 (R/W) Mask Register 2 */ - __IOM uint32_t FUNCTION2; /*!< Offset: 0x048 (R/W) Function Register 2 */ - uint32_t RESERVED2[1U]; - __IOM uint32_t COMP3; /*!< Offset: 0x050 (R/W) Comparator Register 3 */ - __IOM uint32_t MASK3; /*!< Offset: 0x054 (R/W) Mask Register 3 */ - __IOM uint32_t FUNCTION3; /*!< Offset: 0x058 (R/W) Function Register 3 */ -} DWT_Type; - -/* DWT Control Register Definitions */ -#define DWT_CTRL_NUMCOMP_Pos 28U /*!< DWT CTRL: NUMCOMP Position */ -#define DWT_CTRL_NUMCOMP_Msk (0xFUL << DWT_CTRL_NUMCOMP_Pos) /*!< DWT CTRL: NUMCOMP Mask */ - -#define DWT_CTRL_NOTRCPKT_Pos 27U /*!< DWT CTRL: NOTRCPKT Position */ -#define DWT_CTRL_NOTRCPKT_Msk (0x1UL << DWT_CTRL_NOTRCPKT_Pos) /*!< DWT CTRL: NOTRCPKT Mask */ - -#define DWT_CTRL_NOEXTTRIG_Pos 26U /*!< DWT CTRL: NOEXTTRIG Position */ -#define DWT_CTRL_NOEXTTRIG_Msk (0x1UL << DWT_CTRL_NOEXTTRIG_Pos) /*!< DWT CTRL: NOEXTTRIG Mask */ - -#define DWT_CTRL_NOCYCCNT_Pos 25U /*!< DWT CTRL: NOCYCCNT Position */ -#define DWT_CTRL_NOCYCCNT_Msk (0x1UL << DWT_CTRL_NOCYCCNT_Pos) /*!< DWT CTRL: NOCYCCNT Mask */ - -#define DWT_CTRL_NOPRFCNT_Pos 24U /*!< DWT CTRL: NOPRFCNT Position */ -#define DWT_CTRL_NOPRFCNT_Msk (0x1UL << DWT_CTRL_NOPRFCNT_Pos) /*!< DWT CTRL: NOPRFCNT Mask */ - -#define DWT_CTRL_CYCEVTENA_Pos 22U /*!< DWT CTRL: CYCEVTENA Position */ -#define DWT_CTRL_CYCEVTENA_Msk (0x1UL << DWT_CTRL_CYCEVTENA_Pos) /*!< DWT CTRL: CYCEVTENA Mask */ - -#define DWT_CTRL_FOLDEVTENA_Pos 21U /*!< DWT CTRL: FOLDEVTENA Position */ -#define DWT_CTRL_FOLDEVTENA_Msk (0x1UL << DWT_CTRL_FOLDEVTENA_Pos) /*!< DWT CTRL: FOLDEVTENA Mask */ - -#define DWT_CTRL_LSUEVTENA_Pos 20U /*!< DWT CTRL: LSUEVTENA Position */ -#define DWT_CTRL_LSUEVTENA_Msk (0x1UL << DWT_CTRL_LSUEVTENA_Pos) /*!< DWT CTRL: LSUEVTENA Mask */ - -#define DWT_CTRL_SLEEPEVTENA_Pos 19U /*!< DWT CTRL: SLEEPEVTENA Position */ -#define DWT_CTRL_SLEEPEVTENA_Msk (0x1UL << DWT_CTRL_SLEEPEVTENA_Pos) /*!< DWT CTRL: SLEEPEVTENA Mask */ - -#define DWT_CTRL_EXCEVTENA_Pos 18U /*!< DWT CTRL: EXCEVTENA Position */ -#define DWT_CTRL_EXCEVTENA_Msk (0x1UL << DWT_CTRL_EXCEVTENA_Pos) /*!< DWT CTRL: EXCEVTENA Mask */ - -#define DWT_CTRL_CPIEVTENA_Pos 17U /*!< DWT CTRL: CPIEVTENA Position */ -#define DWT_CTRL_CPIEVTENA_Msk (0x1UL << DWT_CTRL_CPIEVTENA_Pos) /*!< DWT CTRL: CPIEVTENA Mask */ - -#define DWT_CTRL_EXCTRCENA_Pos 16U /*!< DWT CTRL: EXCTRCENA Position */ -#define DWT_CTRL_EXCTRCENA_Msk (0x1UL << DWT_CTRL_EXCTRCENA_Pos) /*!< DWT CTRL: EXCTRCENA Mask */ - -#define DWT_CTRL_PCSAMPLENA_Pos 12U /*!< DWT CTRL: PCSAMPLENA Position */ -#define DWT_CTRL_PCSAMPLENA_Msk (0x1UL << DWT_CTRL_PCSAMPLENA_Pos) /*!< DWT CTRL: PCSAMPLENA Mask */ - -#define DWT_CTRL_SYNCTAP_Pos 10U /*!< DWT CTRL: SYNCTAP Position */ -#define DWT_CTRL_SYNCTAP_Msk (0x3UL << DWT_CTRL_SYNCTAP_Pos) /*!< DWT CTRL: SYNCTAP Mask */ - -#define DWT_CTRL_CYCTAP_Pos 9U /*!< DWT CTRL: CYCTAP Position */ -#define DWT_CTRL_CYCTAP_Msk (0x1UL << DWT_CTRL_CYCTAP_Pos) /*!< DWT CTRL: CYCTAP Mask */ - -#define DWT_CTRL_POSTINIT_Pos 5U /*!< DWT CTRL: POSTINIT Position */ -#define DWT_CTRL_POSTINIT_Msk (0xFUL << DWT_CTRL_POSTINIT_Pos) /*!< DWT CTRL: POSTINIT Mask */ - -#define DWT_CTRL_POSTPRESET_Pos 1U /*!< DWT CTRL: POSTPRESET Position */ -#define DWT_CTRL_POSTPRESET_Msk (0xFUL << DWT_CTRL_POSTPRESET_Pos) /*!< DWT CTRL: POSTPRESET Mask */ - -#define DWT_CTRL_CYCCNTENA_Pos 0U /*!< DWT CTRL: CYCCNTENA Position */ -#define DWT_CTRL_CYCCNTENA_Msk (0x1UL /*<< DWT_CTRL_CYCCNTENA_Pos*/) /*!< DWT CTRL: CYCCNTENA Mask */ - -/* DWT CPI Count Register Definitions */ -#define DWT_CPICNT_CPICNT_Pos 0U /*!< DWT CPICNT: CPICNT Position */ -#define DWT_CPICNT_CPICNT_Msk (0xFFUL /*<< DWT_CPICNT_CPICNT_Pos*/) /*!< DWT CPICNT: CPICNT Mask */ - -/* DWT Exception Overhead Count Register Definitions */ -#define DWT_EXCCNT_EXCCNT_Pos 0U /*!< DWT EXCCNT: EXCCNT Position */ -#define DWT_EXCCNT_EXCCNT_Msk (0xFFUL /*<< DWT_EXCCNT_EXCCNT_Pos*/) /*!< DWT EXCCNT: EXCCNT Mask */ - -/* DWT Sleep Count Register Definitions */ -#define DWT_SLEEPCNT_SLEEPCNT_Pos 0U /*!< DWT SLEEPCNT: SLEEPCNT Position */ -#define DWT_SLEEPCNT_SLEEPCNT_Msk (0xFFUL /*<< DWT_SLEEPCNT_SLEEPCNT_Pos*/) /*!< DWT SLEEPCNT: SLEEPCNT Mask */ - -/* DWT LSU Count Register Definitions */ -#define DWT_LSUCNT_LSUCNT_Pos 0U /*!< DWT LSUCNT: LSUCNT Position */ -#define DWT_LSUCNT_LSUCNT_Msk (0xFFUL /*<< DWT_LSUCNT_LSUCNT_Pos*/) /*!< DWT LSUCNT: LSUCNT Mask */ - -/* DWT Folded-instruction Count Register Definitions */ -#define DWT_FOLDCNT_FOLDCNT_Pos 0U /*!< DWT FOLDCNT: FOLDCNT Position */ -#define DWT_FOLDCNT_FOLDCNT_Msk (0xFFUL /*<< DWT_FOLDCNT_FOLDCNT_Pos*/) /*!< DWT FOLDCNT: FOLDCNT Mask */ - -/* DWT Comparator Mask Register Definitions */ -#define DWT_MASK_MASK_Pos 0U /*!< DWT MASK: MASK Position */ -#define DWT_MASK_MASK_Msk (0x1FUL /*<< DWT_MASK_MASK_Pos*/) /*!< DWT MASK: MASK Mask */ - -/* DWT Comparator Function Register Definitions */ -#define DWT_FUNCTION_MATCHED_Pos 24U /*!< DWT FUNCTION: MATCHED Position */ -#define DWT_FUNCTION_MATCHED_Msk (0x1UL << DWT_FUNCTION_MATCHED_Pos) /*!< DWT FUNCTION: MATCHED Mask */ - -#define DWT_FUNCTION_DATAVADDR1_Pos 16U /*!< DWT FUNCTION: DATAVADDR1 Position */ -#define DWT_FUNCTION_DATAVADDR1_Msk (0xFUL << DWT_FUNCTION_DATAVADDR1_Pos) /*!< DWT FUNCTION: DATAVADDR1 Mask */ - -#define DWT_FUNCTION_DATAVADDR0_Pos 12U /*!< DWT FUNCTION: DATAVADDR0 Position */ -#define DWT_FUNCTION_DATAVADDR0_Msk (0xFUL << DWT_FUNCTION_DATAVADDR0_Pos) /*!< DWT FUNCTION: DATAVADDR0 Mask */ - -#define DWT_FUNCTION_DATAVSIZE_Pos 10U /*!< DWT FUNCTION: DATAVSIZE Position */ -#define DWT_FUNCTION_DATAVSIZE_Msk (0x3UL << DWT_FUNCTION_DATAVSIZE_Pos) /*!< DWT FUNCTION: DATAVSIZE Mask */ - -#define DWT_FUNCTION_LNK1ENA_Pos 9U /*!< DWT FUNCTION: LNK1ENA Position */ -#define DWT_FUNCTION_LNK1ENA_Msk (0x1UL << DWT_FUNCTION_LNK1ENA_Pos) /*!< DWT FUNCTION: LNK1ENA Mask */ - -#define DWT_FUNCTION_DATAVMATCH_Pos 8U /*!< DWT FUNCTION: DATAVMATCH Position */ -#define DWT_FUNCTION_DATAVMATCH_Msk (0x1UL << DWT_FUNCTION_DATAVMATCH_Pos) /*!< DWT FUNCTION: DATAVMATCH Mask */ - -#define DWT_FUNCTION_CYCMATCH_Pos 7U /*!< DWT FUNCTION: CYCMATCH Position */ -#define DWT_FUNCTION_CYCMATCH_Msk (0x1UL << DWT_FUNCTION_CYCMATCH_Pos) /*!< DWT FUNCTION: CYCMATCH Mask */ - -#define DWT_FUNCTION_EMITRANGE_Pos 5U /*!< DWT FUNCTION: EMITRANGE Position */ -#define DWT_FUNCTION_EMITRANGE_Msk (0x1UL << DWT_FUNCTION_EMITRANGE_Pos) /*!< DWT FUNCTION: EMITRANGE Mask */ - -#define DWT_FUNCTION_FUNCTION_Pos 0U /*!< DWT FUNCTION: FUNCTION Position */ -#define DWT_FUNCTION_FUNCTION_Msk (0xFUL /*<< DWT_FUNCTION_FUNCTION_Pos*/) /*!< DWT FUNCTION: FUNCTION Mask */ - -/*@}*/ /* end of group CMSIS_DWT */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_TPI Trace Port Interface (TPI) - \brief Type definitions for the Trace Port Interface (TPI) - @{ - */ - -/** - \brief Structure type to access the Trace Port Interface Register (TPI). - */ -typedef struct -{ - __IM uint32_t SSPSR; /*!< Offset: 0x000 (R/ ) Supported Parallel Port Size Register */ - __IOM uint32_t CSPSR; /*!< Offset: 0x004 (R/W) Current Parallel Port Size Register */ - uint32_t RESERVED0[2U]; - __IOM uint32_t ACPR; /*!< Offset: 0x010 (R/W) Asynchronous Clock Prescaler Register */ - uint32_t RESERVED1[55U]; - __IOM uint32_t SPPR; /*!< Offset: 0x0F0 (R/W) Selected Pin Protocol Register */ - uint32_t RESERVED2[131U]; - __IM uint32_t FFSR; /*!< Offset: 0x300 (R/ ) Formatter and Flush Status Register */ - __IOM uint32_t FFCR; /*!< Offset: 0x304 (R/W) Formatter and Flush Control Register */ - __IM uint32_t FSCR; /*!< Offset: 0x308 (R/ ) Formatter Synchronization Counter Register */ - uint32_t RESERVED3[759U]; - __IM uint32_t TRIGGER; /*!< Offset: 0xEE8 (R/ ) TRIGGER Register */ - __IM uint32_t FIFO0; /*!< Offset: 0xEEC (R/ ) Integration ETM Data */ - __IM uint32_t ITATBCTR2; /*!< Offset: 0xEF0 (R/ ) ITATBCTR2 */ - uint32_t RESERVED4[1U]; - __IM uint32_t ITATBCTR0; /*!< Offset: 0xEF8 (R/ ) ITATBCTR0 */ - __IM uint32_t FIFO1; /*!< Offset: 0xEFC (R/ ) Integration ITM Data */ - __IOM uint32_t ITCTRL; /*!< Offset: 0xF00 (R/W) Integration Mode Control */ - uint32_t RESERVED5[39U]; - __IOM uint32_t CLAIMSET; /*!< Offset: 0xFA0 (R/W) Claim tag set */ - __IOM uint32_t CLAIMCLR; /*!< Offset: 0xFA4 (R/W) Claim tag clear */ - uint32_t RESERVED7[8U]; - __IM uint32_t DEVID; /*!< Offset: 0xFC8 (R/ ) TPIU_DEVID */ - __IM uint32_t DEVTYPE; /*!< Offset: 0xFCC (R/ ) TPIU_DEVTYPE */ -} TPI_Type; - -/* TPI Asynchronous Clock Prescaler Register Definitions */ -#define TPI_ACPR_PRESCALER_Pos 0U /*!< TPI ACPR: PRESCALER Position */ -#define TPI_ACPR_PRESCALER_Msk (0x1FFFUL /*<< TPI_ACPR_PRESCALER_Pos*/) /*!< TPI ACPR: PRESCALER Mask */ - -/* TPI Selected Pin Protocol Register Definitions */ -#define TPI_SPPR_TXMODE_Pos 0U /*!< TPI SPPR: TXMODE Position */ -#define TPI_SPPR_TXMODE_Msk (0x3UL /*<< TPI_SPPR_TXMODE_Pos*/) /*!< TPI SPPR: TXMODE Mask */ - -/* TPI Formatter and Flush Status Register Definitions */ -#define TPI_FFSR_FtNonStop_Pos 3U /*!< TPI FFSR: FtNonStop Position */ -#define TPI_FFSR_FtNonStop_Msk (0x1UL << TPI_FFSR_FtNonStop_Pos) /*!< TPI FFSR: FtNonStop Mask */ - -#define TPI_FFSR_TCPresent_Pos 2U /*!< TPI FFSR: TCPresent Position */ -#define TPI_FFSR_TCPresent_Msk (0x1UL << TPI_FFSR_TCPresent_Pos) /*!< TPI FFSR: TCPresent Mask */ - -#define TPI_FFSR_FtStopped_Pos 1U /*!< TPI FFSR: FtStopped Position */ -#define TPI_FFSR_FtStopped_Msk (0x1UL << TPI_FFSR_FtStopped_Pos) /*!< TPI FFSR: FtStopped Mask */ - -#define TPI_FFSR_FlInProg_Pos 0U /*!< TPI FFSR: FlInProg Position */ -#define TPI_FFSR_FlInProg_Msk (0x1UL /*<< TPI_FFSR_FlInProg_Pos*/) /*!< TPI FFSR: FlInProg Mask */ - -/* TPI Formatter and Flush Control Register Definitions */ -#define TPI_FFCR_TrigIn_Pos 8U /*!< TPI FFCR: TrigIn Position */ -#define TPI_FFCR_TrigIn_Msk (0x1UL << TPI_FFCR_TrigIn_Pos) /*!< TPI FFCR: TrigIn Mask */ - -#define TPI_FFCR_EnFCont_Pos 1U /*!< TPI FFCR: EnFCont Position */ -#define TPI_FFCR_EnFCont_Msk (0x1UL << TPI_FFCR_EnFCont_Pos) /*!< TPI FFCR: EnFCont Mask */ - -/* TPI TRIGGER Register Definitions */ -#define TPI_TRIGGER_TRIGGER_Pos 0U /*!< TPI TRIGGER: TRIGGER Position */ -#define TPI_TRIGGER_TRIGGER_Msk (0x1UL /*<< TPI_TRIGGER_TRIGGER_Pos*/) /*!< TPI TRIGGER: TRIGGER Mask */ - -/* TPI Integration ETM Data Register Definitions (FIFO0) */ -#define TPI_FIFO0_ITM_ATVALID_Pos 29U /*!< TPI FIFO0: ITM_ATVALID Position */ -#define TPI_FIFO0_ITM_ATVALID_Msk (0x1UL << TPI_FIFO0_ITM_ATVALID_Pos) /*!< TPI FIFO0: ITM_ATVALID Mask */ - -#define TPI_FIFO0_ITM_bytecount_Pos 27U /*!< TPI FIFO0: ITM_bytecount Position */ -#define TPI_FIFO0_ITM_bytecount_Msk (0x3UL << TPI_FIFO0_ITM_bytecount_Pos) /*!< TPI FIFO0: ITM_bytecount Mask */ - -#define TPI_FIFO0_ETM_ATVALID_Pos 26U /*!< TPI FIFO0: ETM_ATVALID Position */ -#define TPI_FIFO0_ETM_ATVALID_Msk (0x1UL << TPI_FIFO0_ETM_ATVALID_Pos) /*!< TPI FIFO0: ETM_ATVALID Mask */ - -#define TPI_FIFO0_ETM_bytecount_Pos 24U /*!< TPI FIFO0: ETM_bytecount Position */ -#define TPI_FIFO0_ETM_bytecount_Msk (0x3UL << TPI_FIFO0_ETM_bytecount_Pos) /*!< TPI FIFO0: ETM_bytecount Mask */ - -#define TPI_FIFO0_ETM2_Pos 16U /*!< TPI FIFO0: ETM2 Position */ -#define TPI_FIFO0_ETM2_Msk (0xFFUL << TPI_FIFO0_ETM2_Pos) /*!< TPI FIFO0: ETM2 Mask */ - -#define TPI_FIFO0_ETM1_Pos 8U /*!< TPI FIFO0: ETM1 Position */ -#define TPI_FIFO0_ETM1_Msk (0xFFUL << TPI_FIFO0_ETM1_Pos) /*!< TPI FIFO0: ETM1 Mask */ - -#define TPI_FIFO0_ETM0_Pos 0U /*!< TPI FIFO0: ETM0 Position */ -#define TPI_FIFO0_ETM0_Msk (0xFFUL /*<< TPI_FIFO0_ETM0_Pos*/) /*!< TPI FIFO0: ETM0 Mask */ - -/* TPI ITATBCTR2 Register Definitions */ -#define TPI_ITATBCTR2_ATREADY2_Pos 0U /*!< TPI ITATBCTR2: ATREADY2 Position */ -#define TPI_ITATBCTR2_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY2_Pos*/) /*!< TPI ITATBCTR2: ATREADY2 Mask */ - -#define TPI_ITATBCTR2_ATREADY1_Pos 0U /*!< TPI ITATBCTR2: ATREADY1 Position */ -#define TPI_ITATBCTR2_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR2_ATREADY1_Pos*/) /*!< TPI ITATBCTR2: ATREADY1 Mask */ - -/* TPI Integration ITM Data Register Definitions (FIFO1) */ -#define TPI_FIFO1_ITM_ATVALID_Pos 29U /*!< TPI FIFO1: ITM_ATVALID Position */ -#define TPI_FIFO1_ITM_ATVALID_Msk (0x1UL << TPI_FIFO1_ITM_ATVALID_Pos) /*!< TPI FIFO1: ITM_ATVALID Mask */ - -#define TPI_FIFO1_ITM_bytecount_Pos 27U /*!< TPI FIFO1: ITM_bytecount Position */ -#define TPI_FIFO1_ITM_bytecount_Msk (0x3UL << TPI_FIFO1_ITM_bytecount_Pos) /*!< TPI FIFO1: ITM_bytecount Mask */ - -#define TPI_FIFO1_ETM_ATVALID_Pos 26U /*!< TPI FIFO1: ETM_ATVALID Position */ -#define TPI_FIFO1_ETM_ATVALID_Msk (0x1UL << TPI_FIFO1_ETM_ATVALID_Pos) /*!< TPI FIFO1: ETM_ATVALID Mask */ - -#define TPI_FIFO1_ETM_bytecount_Pos 24U /*!< TPI FIFO1: ETM_bytecount Position */ -#define TPI_FIFO1_ETM_bytecount_Msk (0x3UL << TPI_FIFO1_ETM_bytecount_Pos) /*!< TPI FIFO1: ETM_bytecount Mask */ - -#define TPI_FIFO1_ITM2_Pos 16U /*!< TPI FIFO1: ITM2 Position */ -#define TPI_FIFO1_ITM2_Msk (0xFFUL << TPI_FIFO1_ITM2_Pos) /*!< TPI FIFO1: ITM2 Mask */ - -#define TPI_FIFO1_ITM1_Pos 8U /*!< TPI FIFO1: ITM1 Position */ -#define TPI_FIFO1_ITM1_Msk (0xFFUL << TPI_FIFO1_ITM1_Pos) /*!< TPI FIFO1: ITM1 Mask */ - -#define TPI_FIFO1_ITM0_Pos 0U /*!< TPI FIFO1: ITM0 Position */ -#define TPI_FIFO1_ITM0_Msk (0xFFUL /*<< TPI_FIFO1_ITM0_Pos*/) /*!< TPI FIFO1: ITM0 Mask */ - -/* TPI ITATBCTR0 Register Definitions */ -#define TPI_ITATBCTR0_ATREADY2_Pos 0U /*!< TPI ITATBCTR0: ATREADY2 Position */ -#define TPI_ITATBCTR0_ATREADY2_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY2_Pos*/) /*!< TPI ITATBCTR0: ATREADY2 Mask */ - -#define TPI_ITATBCTR0_ATREADY1_Pos 0U /*!< TPI ITATBCTR0: ATREADY1 Position */ -#define TPI_ITATBCTR0_ATREADY1_Msk (0x1UL /*<< TPI_ITATBCTR0_ATREADY1_Pos*/) /*!< TPI ITATBCTR0: ATREADY1 Mask */ - -/* TPI Integration Mode Control Register Definitions */ -#define TPI_ITCTRL_Mode_Pos 0U /*!< TPI ITCTRL: Mode Position */ -#define TPI_ITCTRL_Mode_Msk (0x3UL /*<< TPI_ITCTRL_Mode_Pos*/) /*!< TPI ITCTRL: Mode Mask */ - -/* TPI DEVID Register Definitions */ -#define TPI_DEVID_NRZVALID_Pos 11U /*!< TPI DEVID: NRZVALID Position */ -#define TPI_DEVID_NRZVALID_Msk (0x1UL << TPI_DEVID_NRZVALID_Pos) /*!< TPI DEVID: NRZVALID Mask */ - -#define TPI_DEVID_MANCVALID_Pos 10U /*!< TPI DEVID: MANCVALID Position */ -#define TPI_DEVID_MANCVALID_Msk (0x1UL << TPI_DEVID_MANCVALID_Pos) /*!< TPI DEVID: MANCVALID Mask */ - -#define TPI_DEVID_PTINVALID_Pos 9U /*!< TPI DEVID: PTINVALID Position */ -#define TPI_DEVID_PTINVALID_Msk (0x1UL << TPI_DEVID_PTINVALID_Pos) /*!< TPI DEVID: PTINVALID Mask */ - -#define TPI_DEVID_MinBufSz_Pos 6U /*!< TPI DEVID: MinBufSz Position */ -#define TPI_DEVID_MinBufSz_Msk (0x7UL << TPI_DEVID_MinBufSz_Pos) /*!< TPI DEVID: MinBufSz Mask */ - -#define TPI_DEVID_AsynClkIn_Pos 5U /*!< TPI DEVID: AsynClkIn Position */ -#define TPI_DEVID_AsynClkIn_Msk (0x1UL << TPI_DEVID_AsynClkIn_Pos) /*!< TPI DEVID: AsynClkIn Mask */ - -#define TPI_DEVID_NrTraceInput_Pos 0U /*!< TPI DEVID: NrTraceInput Position */ -#define TPI_DEVID_NrTraceInput_Msk (0x1FUL /*<< TPI_DEVID_NrTraceInput_Pos*/) /*!< TPI DEVID: NrTraceInput Mask */ - -/* TPI DEVTYPE Register Definitions */ -#define TPI_DEVTYPE_SubType_Pos 4U /*!< TPI DEVTYPE: SubType Position */ -#define TPI_DEVTYPE_SubType_Msk (0xFUL /*<< TPI_DEVTYPE_SubType_Pos*/) /*!< TPI DEVTYPE: SubType Mask */ - -#define TPI_DEVTYPE_MajorType_Pos 0U /*!< TPI DEVTYPE: MajorType Position */ -#define TPI_DEVTYPE_MajorType_Msk (0xFUL << TPI_DEVTYPE_MajorType_Pos) /*!< TPI DEVTYPE: MajorType Mask */ - -/*@}*/ /* end of group CMSIS_TPI */ - - -#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_MPU Memory Protection Unit (MPU) - \brief Type definitions for the Memory Protection Unit (MPU) - @{ - */ - -/** - \brief Structure type to access the Memory Protection Unit (MPU). - */ -typedef struct -{ - __IM uint32_t TYPE; /*!< Offset: 0x000 (R/ ) MPU Type Register */ - __IOM uint32_t CTRL; /*!< Offset: 0x004 (R/W) MPU Control Register */ - __IOM uint32_t RNR; /*!< Offset: 0x008 (R/W) MPU Region RNRber Register */ - __IOM uint32_t RBAR; /*!< Offset: 0x00C (R/W) MPU Region Base Address Register */ - __IOM uint32_t RASR; /*!< Offset: 0x010 (R/W) MPU Region Attribute and Size Register */ - __IOM uint32_t RBAR_A1; /*!< Offset: 0x014 (R/W) MPU Alias 1 Region Base Address Register */ - __IOM uint32_t RASR_A1; /*!< Offset: 0x018 (R/W) MPU Alias 1 Region Attribute and Size Register */ - __IOM uint32_t RBAR_A2; /*!< Offset: 0x01C (R/W) MPU Alias 2 Region Base Address Register */ - __IOM uint32_t RASR_A2; /*!< Offset: 0x020 (R/W) MPU Alias 2 Region Attribute and Size Register */ - __IOM uint32_t RBAR_A3; /*!< Offset: 0x024 (R/W) MPU Alias 3 Region Base Address Register */ - __IOM uint32_t RASR_A3; /*!< Offset: 0x028 (R/W) MPU Alias 3 Region Attribute and Size Register */ -} MPU_Type; - -#define MPU_TYPE_RALIASES 4U - -/* MPU Type Register Definitions */ -#define MPU_TYPE_IREGION_Pos 16U /*!< MPU TYPE: IREGION Position */ -#define MPU_TYPE_IREGION_Msk (0xFFUL << MPU_TYPE_IREGION_Pos) /*!< MPU TYPE: IREGION Mask */ - -#define MPU_TYPE_DREGION_Pos 8U /*!< MPU TYPE: DREGION Position */ -#define MPU_TYPE_DREGION_Msk (0xFFUL << MPU_TYPE_DREGION_Pos) /*!< MPU TYPE: DREGION Mask */ - -#define MPU_TYPE_SEPARATE_Pos 0U /*!< MPU TYPE: SEPARATE Position */ -#define MPU_TYPE_SEPARATE_Msk (1UL /*<< MPU_TYPE_SEPARATE_Pos*/) /*!< MPU TYPE: SEPARATE Mask */ - -/* MPU Control Register Definitions */ -#define MPU_CTRL_PRIVDEFENA_Pos 2U /*!< MPU CTRL: PRIVDEFENA Position */ -#define MPU_CTRL_PRIVDEFENA_Msk (1UL << MPU_CTRL_PRIVDEFENA_Pos) /*!< MPU CTRL: PRIVDEFENA Mask */ - -#define MPU_CTRL_HFNMIENA_Pos 1U /*!< MPU CTRL: HFNMIENA Position */ -#define MPU_CTRL_HFNMIENA_Msk (1UL << MPU_CTRL_HFNMIENA_Pos) /*!< MPU CTRL: HFNMIENA Mask */ - -#define MPU_CTRL_ENABLE_Pos 0U /*!< MPU CTRL: ENABLE Position */ -#define MPU_CTRL_ENABLE_Msk (1UL /*<< MPU_CTRL_ENABLE_Pos*/) /*!< MPU CTRL: ENABLE Mask */ - -/* MPU Region Number Register Definitions */ -#define MPU_RNR_REGION_Pos 0U /*!< MPU RNR: REGION Position */ -#define MPU_RNR_REGION_Msk (0xFFUL /*<< MPU_RNR_REGION_Pos*/) /*!< MPU RNR: REGION Mask */ - -/* MPU Region Base Address Register Definitions */ -#define MPU_RBAR_ADDR_Pos 5U /*!< MPU RBAR: ADDR Position */ -#define MPU_RBAR_ADDR_Msk (0x7FFFFFFUL << MPU_RBAR_ADDR_Pos) /*!< MPU RBAR: ADDR Mask */ - -#define MPU_RBAR_VALID_Pos 4U /*!< MPU RBAR: VALID Position */ -#define MPU_RBAR_VALID_Msk (1UL << MPU_RBAR_VALID_Pos) /*!< MPU RBAR: VALID Mask */ - -#define MPU_RBAR_REGION_Pos 0U /*!< MPU RBAR: REGION Position */ -#define MPU_RBAR_REGION_Msk (0xFUL /*<< MPU_RBAR_REGION_Pos*/) /*!< MPU RBAR: REGION Mask */ - -/* MPU Region Attribute and Size Register Definitions */ -#define MPU_RASR_ATTRS_Pos 16U /*!< MPU RASR: MPU Region Attribute field Position */ -#define MPU_RASR_ATTRS_Msk (0xFFFFUL << MPU_RASR_ATTRS_Pos) /*!< MPU RASR: MPU Region Attribute field Mask */ - -#define MPU_RASR_XN_Pos 28U /*!< MPU RASR: ATTRS.XN Position */ -#define MPU_RASR_XN_Msk (1UL << MPU_RASR_XN_Pos) /*!< MPU RASR: ATTRS.XN Mask */ - -#define MPU_RASR_AP_Pos 24U /*!< MPU RASR: ATTRS.AP Position */ -#define MPU_RASR_AP_Msk (0x7UL << MPU_RASR_AP_Pos) /*!< MPU RASR: ATTRS.AP Mask */ - -#define MPU_RASR_TEX_Pos 19U /*!< MPU RASR: ATTRS.TEX Position */ -#define MPU_RASR_TEX_Msk (0x7UL << MPU_RASR_TEX_Pos) /*!< MPU RASR: ATTRS.TEX Mask */ - -#define MPU_RASR_S_Pos 18U /*!< MPU RASR: ATTRS.S Position */ -#define MPU_RASR_S_Msk (1UL << MPU_RASR_S_Pos) /*!< MPU RASR: ATTRS.S Mask */ - -#define MPU_RASR_C_Pos 17U /*!< MPU RASR: ATTRS.C Position */ -#define MPU_RASR_C_Msk (1UL << MPU_RASR_C_Pos) /*!< MPU RASR: ATTRS.C Mask */ - -#define MPU_RASR_B_Pos 16U /*!< MPU RASR: ATTRS.B Position */ -#define MPU_RASR_B_Msk (1UL << MPU_RASR_B_Pos) /*!< MPU RASR: ATTRS.B Mask */ - -#define MPU_RASR_SRD_Pos 8U /*!< MPU RASR: Sub-Region Disable Position */ -#define MPU_RASR_SRD_Msk (0xFFUL << MPU_RASR_SRD_Pos) /*!< MPU RASR: Sub-Region Disable Mask */ - -#define MPU_RASR_SIZE_Pos 1U /*!< MPU RASR: Region Size Field Position */ -#define MPU_RASR_SIZE_Msk (0x1FUL << MPU_RASR_SIZE_Pos) /*!< MPU RASR: Region Size Field Mask */ - -#define MPU_RASR_ENABLE_Pos 0U /*!< MPU RASR: Region enable bit Position */ -#define MPU_RASR_ENABLE_Msk (1UL /*<< MPU_RASR_ENABLE_Pos*/) /*!< MPU RASR: Region enable bit Disable Mask */ - -/*@} end of group CMSIS_MPU */ -#endif /* defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_FPU Floating Point Unit (FPU) - \brief Type definitions for the Floating Point Unit (FPU) - @{ - */ - -/** - \brief Structure type to access the Floating Point Unit (FPU). - */ -typedef struct -{ - uint32_t RESERVED0[1U]; - __IOM uint32_t FPCCR; /*!< Offset: 0x004 (R/W) Floating-Point Context Control Register */ - __IOM uint32_t FPCAR; /*!< Offset: 0x008 (R/W) Floating-Point Context Address Register */ - __IOM uint32_t FPDSCR; /*!< Offset: 0x00C (R/W) Floating-Point Default Status Control Register */ - __IM uint32_t MVFR0; /*!< Offset: 0x010 (R/ ) Media and FP Feature Register 0 */ - __IM uint32_t MVFR1; /*!< Offset: 0x014 (R/ ) Media and FP Feature Register 1 */ - __IM uint32_t MVFR2; /*!< Offset: 0x018 (R/ ) Media and FP Feature Register 2 */ -} FPU_Type; - -/* Floating-Point Context Control Register Definitions */ -#define FPU_FPCCR_ASPEN_Pos 31U /*!< FPCCR: ASPEN bit Position */ -#define FPU_FPCCR_ASPEN_Msk (1UL << FPU_FPCCR_ASPEN_Pos) /*!< FPCCR: ASPEN bit Mask */ - -#define FPU_FPCCR_LSPEN_Pos 30U /*!< FPCCR: LSPEN Position */ -#define FPU_FPCCR_LSPEN_Msk (1UL << FPU_FPCCR_LSPEN_Pos) /*!< FPCCR: LSPEN bit Mask */ - -#define FPU_FPCCR_MONRDY_Pos 8U /*!< FPCCR: MONRDY Position */ -#define FPU_FPCCR_MONRDY_Msk (1UL << FPU_FPCCR_MONRDY_Pos) /*!< FPCCR: MONRDY bit Mask */ - -#define FPU_FPCCR_BFRDY_Pos 6U /*!< FPCCR: BFRDY Position */ -#define FPU_FPCCR_BFRDY_Msk (1UL << FPU_FPCCR_BFRDY_Pos) /*!< FPCCR: BFRDY bit Mask */ - -#define FPU_FPCCR_MMRDY_Pos 5U /*!< FPCCR: MMRDY Position */ -#define FPU_FPCCR_MMRDY_Msk (1UL << FPU_FPCCR_MMRDY_Pos) /*!< FPCCR: MMRDY bit Mask */ - -#define FPU_FPCCR_HFRDY_Pos 4U /*!< FPCCR: HFRDY Position */ -#define FPU_FPCCR_HFRDY_Msk (1UL << FPU_FPCCR_HFRDY_Pos) /*!< FPCCR: HFRDY bit Mask */ - -#define FPU_FPCCR_THREAD_Pos 3U /*!< FPCCR: processor mode bit Position */ -#define FPU_FPCCR_THREAD_Msk (1UL << FPU_FPCCR_THREAD_Pos) /*!< FPCCR: processor mode active bit Mask */ - -#define FPU_FPCCR_USER_Pos 1U /*!< FPCCR: privilege level bit Position */ -#define FPU_FPCCR_USER_Msk (1UL << FPU_FPCCR_USER_Pos) /*!< FPCCR: privilege level bit Mask */ - -#define FPU_FPCCR_LSPACT_Pos 0U /*!< FPCCR: Lazy state preservation active bit Position */ -#define FPU_FPCCR_LSPACT_Msk (1UL /*<< FPU_FPCCR_LSPACT_Pos*/) /*!< FPCCR: Lazy state preservation active bit Mask */ - -/* Floating-Point Context Address Register Definitions */ -#define FPU_FPCAR_ADDRESS_Pos 3U /*!< FPCAR: ADDRESS bit Position */ -#define FPU_FPCAR_ADDRESS_Msk (0x1FFFFFFFUL << FPU_FPCAR_ADDRESS_Pos) /*!< FPCAR: ADDRESS bit Mask */ - -/* Floating-Point Default Status Control Register Definitions */ -#define FPU_FPDSCR_AHP_Pos 26U /*!< FPDSCR: AHP bit Position */ -#define FPU_FPDSCR_AHP_Msk (1UL << FPU_FPDSCR_AHP_Pos) /*!< FPDSCR: AHP bit Mask */ - -#define FPU_FPDSCR_DN_Pos 25U /*!< FPDSCR: DN bit Position */ -#define FPU_FPDSCR_DN_Msk (1UL << FPU_FPDSCR_DN_Pos) /*!< FPDSCR: DN bit Mask */ - -#define FPU_FPDSCR_FZ_Pos 24U /*!< FPDSCR: FZ bit Position */ -#define FPU_FPDSCR_FZ_Msk (1UL << FPU_FPDSCR_FZ_Pos) /*!< FPDSCR: FZ bit Mask */ - -#define FPU_FPDSCR_RMode_Pos 22U /*!< FPDSCR: RMode bit Position */ -#define FPU_FPDSCR_RMode_Msk (3UL << FPU_FPDSCR_RMode_Pos) /*!< FPDSCR: RMode bit Mask */ - -/* Media and FP Feature Register 0 Definitions */ -#define FPU_MVFR0_FP_rounding_modes_Pos 28U /*!< MVFR0: FP rounding modes bits Position */ -#define FPU_MVFR0_FP_rounding_modes_Msk (0xFUL << FPU_MVFR0_FP_rounding_modes_Pos) /*!< MVFR0: FP rounding modes bits Mask */ - -#define FPU_MVFR0_Short_vectors_Pos 24U /*!< MVFR0: Short vectors bits Position */ -#define FPU_MVFR0_Short_vectors_Msk (0xFUL << FPU_MVFR0_Short_vectors_Pos) /*!< MVFR0: Short vectors bits Mask */ - -#define FPU_MVFR0_Square_root_Pos 20U /*!< MVFR0: Square root bits Position */ -#define FPU_MVFR0_Square_root_Msk (0xFUL << FPU_MVFR0_Square_root_Pos) /*!< MVFR0: Square root bits Mask */ - -#define FPU_MVFR0_Divide_Pos 16U /*!< MVFR0: Divide bits Position */ -#define FPU_MVFR0_Divide_Msk (0xFUL << FPU_MVFR0_Divide_Pos) /*!< MVFR0: Divide bits Mask */ - -#define FPU_MVFR0_FP_excep_trapping_Pos 12U /*!< MVFR0: FP exception trapping bits Position */ -#define FPU_MVFR0_FP_excep_trapping_Msk (0xFUL << FPU_MVFR0_FP_excep_trapping_Pos) /*!< MVFR0: FP exception trapping bits Mask */ - -#define FPU_MVFR0_Double_precision_Pos 8U /*!< MVFR0: Double-precision bits Position */ -#define FPU_MVFR0_Double_precision_Msk (0xFUL << FPU_MVFR0_Double_precision_Pos) /*!< MVFR0: Double-precision bits Mask */ - -#define FPU_MVFR0_Single_precision_Pos 4U /*!< MVFR0: Single-precision bits Position */ -#define FPU_MVFR0_Single_precision_Msk (0xFUL << FPU_MVFR0_Single_precision_Pos) /*!< MVFR0: Single-precision bits Mask */ - -#define FPU_MVFR0_A_SIMD_registers_Pos 0U /*!< MVFR0: A_SIMD registers bits Position */ -#define FPU_MVFR0_A_SIMD_registers_Msk (0xFUL /*<< FPU_MVFR0_A_SIMD_registers_Pos*/) /*!< MVFR0: A_SIMD registers bits Mask */ - -/* Media and FP Feature Register 1 Definitions */ -#define FPU_MVFR1_FP_fused_MAC_Pos 28U /*!< MVFR1: FP fused MAC bits Position */ -#define FPU_MVFR1_FP_fused_MAC_Msk (0xFUL << FPU_MVFR1_FP_fused_MAC_Pos) /*!< MVFR1: FP fused MAC bits Mask */ - -#define FPU_MVFR1_FP_HPFP_Pos 24U /*!< MVFR1: FP HPFP bits Position */ -#define FPU_MVFR1_FP_HPFP_Msk (0xFUL << FPU_MVFR1_FP_HPFP_Pos) /*!< MVFR1: FP HPFP bits Mask */ - -#define FPU_MVFR1_D_NaN_mode_Pos 4U /*!< MVFR1: D_NaN mode bits Position */ -#define FPU_MVFR1_D_NaN_mode_Msk (0xFUL << FPU_MVFR1_D_NaN_mode_Pos) /*!< MVFR1: D_NaN mode bits Mask */ - -#define FPU_MVFR1_FtZ_mode_Pos 0U /*!< MVFR1: FtZ mode bits Position */ -#define FPU_MVFR1_FtZ_mode_Msk (0xFUL /*<< FPU_MVFR1_FtZ_mode_Pos*/) /*!< MVFR1: FtZ mode bits Mask */ - -/* Media and FP Feature Register 2 Definitions */ - -#define FPU_MVFR2_VFP_Misc_Pos 4U /*!< MVFR2: VFP Misc bits Position */ -#define FPU_MVFR2_VFP_Misc_Msk (0xFUL << FPU_MVFR2_VFP_Misc_Pos) /*!< MVFR2: VFP Misc bits Mask */ - -/*@} end of group CMSIS_FPU */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) - \brief Type definitions for the Core Debug Registers - @{ - */ - -/** - \brief Structure type to access the Core Debug Register (CoreDebug). - */ -typedef struct -{ - __IOM uint32_t DHCSR; /*!< Offset: 0x000 (R/W) Debug Halting Control and Status Register */ - __OM uint32_t DCRSR; /*!< Offset: 0x004 ( /W) Debug Core Register Selector Register */ - __IOM uint32_t DCRDR; /*!< Offset: 0x008 (R/W) Debug Core Register Data Register */ - __IOM uint32_t DEMCR; /*!< Offset: 0x00C (R/W) Debug Exception and Monitor Control Register */ -} CoreDebug_Type; - -/* Debug Halting Control and Status Register Definitions */ -#define CoreDebug_DHCSR_DBGKEY_Pos 16U /*!< CoreDebug DHCSR: DBGKEY Position */ -#define CoreDebug_DHCSR_DBGKEY_Msk (0xFFFFUL << CoreDebug_DHCSR_DBGKEY_Pos) /*!< CoreDebug DHCSR: DBGKEY Mask */ - -#define CoreDebug_DHCSR_S_RESET_ST_Pos 25U /*!< CoreDebug DHCSR: S_RESET_ST Position */ -#define CoreDebug_DHCSR_S_RESET_ST_Msk (1UL << CoreDebug_DHCSR_S_RESET_ST_Pos) /*!< CoreDebug DHCSR: S_RESET_ST Mask */ - -#define CoreDebug_DHCSR_S_RETIRE_ST_Pos 24U /*!< CoreDebug DHCSR: S_RETIRE_ST Position */ -#define CoreDebug_DHCSR_S_RETIRE_ST_Msk (1UL << CoreDebug_DHCSR_S_RETIRE_ST_Pos) /*!< CoreDebug DHCSR: S_RETIRE_ST Mask */ - -#define CoreDebug_DHCSR_S_LOCKUP_Pos 19U /*!< CoreDebug DHCSR: S_LOCKUP Position */ -#define CoreDebug_DHCSR_S_LOCKUP_Msk (1UL << CoreDebug_DHCSR_S_LOCKUP_Pos) /*!< CoreDebug DHCSR: S_LOCKUP Mask */ - -#define CoreDebug_DHCSR_S_SLEEP_Pos 18U /*!< CoreDebug DHCSR: S_SLEEP Position */ -#define CoreDebug_DHCSR_S_SLEEP_Msk (1UL << CoreDebug_DHCSR_S_SLEEP_Pos) /*!< CoreDebug DHCSR: S_SLEEP Mask */ - -#define CoreDebug_DHCSR_S_HALT_Pos 17U /*!< CoreDebug DHCSR: S_HALT Position */ -#define CoreDebug_DHCSR_S_HALT_Msk (1UL << CoreDebug_DHCSR_S_HALT_Pos) /*!< CoreDebug DHCSR: S_HALT Mask */ - -#define CoreDebug_DHCSR_S_REGRDY_Pos 16U /*!< CoreDebug DHCSR: S_REGRDY Position */ -#define CoreDebug_DHCSR_S_REGRDY_Msk (1UL << CoreDebug_DHCSR_S_REGRDY_Pos) /*!< CoreDebug DHCSR: S_REGRDY Mask */ - -#define CoreDebug_DHCSR_C_SNAPSTALL_Pos 5U /*!< CoreDebug DHCSR: C_SNAPSTALL Position */ -#define CoreDebug_DHCSR_C_SNAPSTALL_Msk (1UL << CoreDebug_DHCSR_C_SNAPSTALL_Pos) /*!< CoreDebug DHCSR: C_SNAPSTALL Mask */ - -#define CoreDebug_DHCSR_C_MASKINTS_Pos 3U /*!< CoreDebug DHCSR: C_MASKINTS Position */ -#define CoreDebug_DHCSR_C_MASKINTS_Msk (1UL << CoreDebug_DHCSR_C_MASKINTS_Pos) /*!< CoreDebug DHCSR: C_MASKINTS Mask */ - -#define CoreDebug_DHCSR_C_STEP_Pos 2U /*!< CoreDebug DHCSR: C_STEP Position */ -#define CoreDebug_DHCSR_C_STEP_Msk (1UL << CoreDebug_DHCSR_C_STEP_Pos) /*!< CoreDebug DHCSR: C_STEP Mask */ - -#define CoreDebug_DHCSR_C_HALT_Pos 1U /*!< CoreDebug DHCSR: C_HALT Position */ -#define CoreDebug_DHCSR_C_HALT_Msk (1UL << CoreDebug_DHCSR_C_HALT_Pos) /*!< CoreDebug DHCSR: C_HALT Mask */ - -#define CoreDebug_DHCSR_C_DEBUGEN_Pos 0U /*!< CoreDebug DHCSR: C_DEBUGEN Position */ -#define CoreDebug_DHCSR_C_DEBUGEN_Msk (1UL /*<< CoreDebug_DHCSR_C_DEBUGEN_Pos*/) /*!< CoreDebug DHCSR: C_DEBUGEN Mask */ - -/* Debug Core Register Selector Register Definitions */ -#define CoreDebug_DCRSR_REGWnR_Pos 16U /*!< CoreDebug DCRSR: REGWnR Position */ -#define CoreDebug_DCRSR_REGWnR_Msk (1UL << CoreDebug_DCRSR_REGWnR_Pos) /*!< CoreDebug DCRSR: REGWnR Mask */ - -#define CoreDebug_DCRSR_REGSEL_Pos 0U /*!< CoreDebug DCRSR: REGSEL Position */ -#define CoreDebug_DCRSR_REGSEL_Msk (0x1FUL /*<< CoreDebug_DCRSR_REGSEL_Pos*/) /*!< CoreDebug DCRSR: REGSEL Mask */ - -/* Debug Exception and Monitor Control Register Definitions */ -#define CoreDebug_DEMCR_TRCENA_Pos 24U /*!< CoreDebug DEMCR: TRCENA Position */ -#define CoreDebug_DEMCR_TRCENA_Msk (1UL << CoreDebug_DEMCR_TRCENA_Pos) /*!< CoreDebug DEMCR: TRCENA Mask */ - -#define CoreDebug_DEMCR_MON_REQ_Pos 19U /*!< CoreDebug DEMCR: MON_REQ Position */ -#define CoreDebug_DEMCR_MON_REQ_Msk (1UL << CoreDebug_DEMCR_MON_REQ_Pos) /*!< CoreDebug DEMCR: MON_REQ Mask */ - -#define CoreDebug_DEMCR_MON_STEP_Pos 18U /*!< CoreDebug DEMCR: MON_STEP Position */ -#define CoreDebug_DEMCR_MON_STEP_Msk (1UL << CoreDebug_DEMCR_MON_STEP_Pos) /*!< CoreDebug DEMCR: MON_STEP Mask */ - -#define CoreDebug_DEMCR_MON_PEND_Pos 17U /*!< CoreDebug DEMCR: MON_PEND Position */ -#define CoreDebug_DEMCR_MON_PEND_Msk (1UL << CoreDebug_DEMCR_MON_PEND_Pos) /*!< CoreDebug DEMCR: MON_PEND Mask */ - -#define CoreDebug_DEMCR_MON_EN_Pos 16U /*!< CoreDebug DEMCR: MON_EN Position */ -#define CoreDebug_DEMCR_MON_EN_Msk (1UL << CoreDebug_DEMCR_MON_EN_Pos) /*!< CoreDebug DEMCR: MON_EN Mask */ - -#define CoreDebug_DEMCR_VC_HARDERR_Pos 10U /*!< CoreDebug DEMCR: VC_HARDERR Position */ -#define CoreDebug_DEMCR_VC_HARDERR_Msk (1UL << CoreDebug_DEMCR_VC_HARDERR_Pos) /*!< CoreDebug DEMCR: VC_HARDERR Mask */ - -#define CoreDebug_DEMCR_VC_INTERR_Pos 9U /*!< CoreDebug DEMCR: VC_INTERR Position */ -#define CoreDebug_DEMCR_VC_INTERR_Msk (1UL << CoreDebug_DEMCR_VC_INTERR_Pos) /*!< CoreDebug DEMCR: VC_INTERR Mask */ - -#define CoreDebug_DEMCR_VC_BUSERR_Pos 8U /*!< CoreDebug DEMCR: VC_BUSERR Position */ -#define CoreDebug_DEMCR_VC_BUSERR_Msk (1UL << CoreDebug_DEMCR_VC_BUSERR_Pos) /*!< CoreDebug DEMCR: VC_BUSERR Mask */ - -#define CoreDebug_DEMCR_VC_STATERR_Pos 7U /*!< CoreDebug DEMCR: VC_STATERR Position */ -#define CoreDebug_DEMCR_VC_STATERR_Msk (1UL << CoreDebug_DEMCR_VC_STATERR_Pos) /*!< CoreDebug DEMCR: VC_STATERR Mask */ - -#define CoreDebug_DEMCR_VC_CHKERR_Pos 6U /*!< CoreDebug DEMCR: VC_CHKERR Position */ -#define CoreDebug_DEMCR_VC_CHKERR_Msk (1UL << CoreDebug_DEMCR_VC_CHKERR_Pos) /*!< CoreDebug DEMCR: VC_CHKERR Mask */ - -#define CoreDebug_DEMCR_VC_NOCPERR_Pos 5U /*!< CoreDebug DEMCR: VC_NOCPERR Position */ -#define CoreDebug_DEMCR_VC_NOCPERR_Msk (1UL << CoreDebug_DEMCR_VC_NOCPERR_Pos) /*!< CoreDebug DEMCR: VC_NOCPERR Mask */ - -#define CoreDebug_DEMCR_VC_MMERR_Pos 4U /*!< CoreDebug DEMCR: VC_MMERR Position */ -#define CoreDebug_DEMCR_VC_MMERR_Msk (1UL << CoreDebug_DEMCR_VC_MMERR_Pos) /*!< CoreDebug DEMCR: VC_MMERR Mask */ - -#define CoreDebug_DEMCR_VC_CORERESET_Pos 0U /*!< CoreDebug DEMCR: VC_CORERESET Position */ -#define CoreDebug_DEMCR_VC_CORERESET_Msk (1UL /*<< CoreDebug_DEMCR_VC_CORERESET_Pos*/) /*!< CoreDebug DEMCR: VC_CORERESET Mask */ - -/*@} end of group CMSIS_CoreDebug */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_core_bitfield Core register bit field macros - \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). - @{ - */ - -/** - \brief Mask and shift a bit field value for use in a register bit range. - \param[in] field Name of the register bit field. - \param[in] value Value of the bit field. This parameter is interpreted as an uint32_t type. - \return Masked and shifted value. -*/ -#define _VAL2FLD(field, value) (((uint32_t)(value) << field ## _Pos) & field ## _Msk) - -/** - \brief Mask and shift a register value to extract a bit filed value. - \param[in] field Name of the register bit field. - \param[in] value Value of register. This parameter is interpreted as an uint32_t type. - \return Masked and shifted bit field value. -*/ -#define _FLD2VAL(field, value) (((uint32_t)(value) & field ## _Msk) >> field ## _Pos) - -/*@} end of group CMSIS_core_bitfield */ - - -/** - \ingroup CMSIS_core_register - \defgroup CMSIS_core_base Core Definitions - \brief Definitions for base addresses, unions, and structures. - @{ - */ - -/* Memory mapping of Core Hardware */ -#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ -#define ITM_BASE (0xE0000000UL) /*!< ITM Base Address */ -#define DWT_BASE (0xE0001000UL) /*!< DWT Base Address */ -#define TPI_BASE (0xE0040000UL) /*!< TPI Base Address */ -#define CoreDebug_BASE (0xE000EDF0UL) /*!< Core Debug Base Address */ -#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ -#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ -#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ - -#define SCnSCB ((SCnSCB_Type *) SCS_BASE ) /*!< System control Register not in SCB */ -#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ -#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ -#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ -#define ITM ((ITM_Type *) ITM_BASE ) /*!< ITM configuration struct */ -#define DWT ((DWT_Type *) DWT_BASE ) /*!< DWT configuration struct */ -#define TPI ((TPI_Type *) TPI_BASE ) /*!< TPI configuration struct */ -#define CoreDebug ((CoreDebug_Type *) CoreDebug_BASE) /*!< Core Debug configuration struct */ - -#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) - #define MPU_BASE (SCS_BASE + 0x0D90UL) /*!< Memory Protection Unit */ - #define MPU ((MPU_Type *) MPU_BASE ) /*!< Memory Protection Unit */ -#endif - -#define FPU_BASE (SCS_BASE + 0x0F30UL) /*!< Floating Point Unit */ -#define FPU ((FPU_Type *) FPU_BASE ) /*!< Floating Point Unit */ - -/*@} */ - - - -/******************************************************************************* - * Hardware Abstraction Layer - Core Function Interface contains: - - Core NVIC Functions - - Core SysTick Functions - - Core Debug Functions - - Core Register Access Functions - ******************************************************************************/ -/** - \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference -*/ - - - -/* ########################## NVIC functions #################################### */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_NVICFunctions NVIC Functions - \brief Functions that manage interrupts and exceptions via the NVIC. - @{ - */ - -#ifdef CMSIS_NVIC_VIRTUAL - #ifndef CMSIS_NVIC_VIRTUAL_HEADER_FILE - #define CMSIS_NVIC_VIRTUAL_HEADER_FILE "cmsis_nvic_virtual.h" - #endif - #include CMSIS_NVIC_VIRTUAL_HEADER_FILE -#else - #define NVIC_SetPriorityGrouping __NVIC_SetPriorityGrouping - #define NVIC_GetPriorityGrouping __NVIC_GetPriorityGrouping - #define NVIC_EnableIRQ __NVIC_EnableIRQ - #define NVIC_GetEnableIRQ __NVIC_GetEnableIRQ - #define NVIC_DisableIRQ __NVIC_DisableIRQ - #define NVIC_GetPendingIRQ __NVIC_GetPendingIRQ - #define NVIC_SetPendingIRQ __NVIC_SetPendingIRQ - #define NVIC_ClearPendingIRQ __NVIC_ClearPendingIRQ - #define NVIC_GetActive __NVIC_GetActive - #define NVIC_SetPriority __NVIC_SetPriority - #define NVIC_GetPriority __NVIC_GetPriority - #define NVIC_SystemReset __NVIC_SystemReset -#endif /* CMSIS_NVIC_VIRTUAL */ - -#ifdef CMSIS_VECTAB_VIRTUAL - #ifndef CMSIS_VECTAB_VIRTUAL_HEADER_FILE - #define CMSIS_VECTAB_VIRTUAL_HEADER_FILE "cmsis_vectab_virtual.h" - #endif - #include CMSIS_VECTAB_VIRTUAL_HEADER_FILE -#else - #define NVIC_SetVector __NVIC_SetVector - #define NVIC_GetVector __NVIC_GetVector -#endif /* (CMSIS_VECTAB_VIRTUAL) */ - -#define NVIC_USER_IRQ_OFFSET 16 - - -/* The following EXC_RETURN values are saved the LR on exception entry */ -#define EXC_RETURN_HANDLER (0xFFFFFFF1UL) /* return to Handler mode, uses MSP after return */ -#define EXC_RETURN_THREAD_MSP (0xFFFFFFF9UL) /* return to Thread mode, uses MSP after return */ -#define EXC_RETURN_THREAD_PSP (0xFFFFFFFDUL) /* return to Thread mode, uses PSP after return */ -#define EXC_RETURN_HANDLER_FPU (0xFFFFFFE1UL) /* return to Handler mode, uses MSP after return, restore floating-point state */ -#define EXC_RETURN_THREAD_MSP_FPU (0xFFFFFFE9UL) /* return to Thread mode, uses MSP after return, restore floating-point state */ -#define EXC_RETURN_THREAD_PSP_FPU (0xFFFFFFEDUL) /* return to Thread mode, uses PSP after return, restore floating-point state */ - - -/** - \brief Set Priority Grouping - \details Sets the priority grouping field using the required unlock sequence. - The parameter PriorityGroup is assigned to the field SCB->AIRCR [10:8] PRIGROUP field. - Only values from 0..7 are used. - In case of a conflict between priority grouping and available - priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. - \param [in] PriorityGroup Priority grouping field. - */ -__STATIC_INLINE void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup) -{ - uint32_t reg_value; - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ - - reg_value = SCB->AIRCR; /* read old register configuration */ - reg_value &= ~((uint32_t)(SCB_AIRCR_VECTKEY_Msk | SCB_AIRCR_PRIGROUP_Msk)); /* clear bits to change */ - reg_value = (reg_value | - ((uint32_t)0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (PriorityGroupTmp << SCB_AIRCR_PRIGROUP_Pos) ); /* Insert write key and priority group */ - SCB->AIRCR = reg_value; -} - - -/** - \brief Get Priority Grouping - \details Reads the priority grouping field from the NVIC Interrupt Controller. - \return Priority grouping field (SCB->AIRCR [10:8] PRIGROUP field). - */ -__STATIC_INLINE uint32_t __NVIC_GetPriorityGrouping(void) -{ - return ((uint32_t)((SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) >> SCB_AIRCR_PRIGROUP_Pos)); -} - - -/** - \brief Enable Interrupt - \details Enables a device specific interrupt in the NVIC interrupt controller. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_EnableIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - __COMPILER_BARRIER(); - NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - __COMPILER_BARRIER(); - } -} - - -/** - \brief Get Interrupt Enable status - \details Returns a device specific interrupt enable status from the NVIC interrupt controller. - \param [in] IRQn Device specific interrupt number. - \return 0 Interrupt is not enabled. - \return 1 Interrupt is enabled. - \note IRQn must not be negative. - */ -__STATIC_INLINE uint32_t __NVIC_GetEnableIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - return((uint32_t)(((NVIC->ISER[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); - } - else - { - return(0U); - } -} - - -/** - \brief Disable Interrupt - \details Disables a device specific interrupt in the NVIC interrupt controller. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_DisableIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->ICER[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - __DSB(); - __ISB(); - } -} - - -/** - \brief Get Pending Interrupt - \details Reads the NVIC pending register and returns the pending bit for the specified device specific interrupt. - \param [in] IRQn Device specific interrupt number. - \return 0 Interrupt status is not pending. - \return 1 Interrupt status is pending. - \note IRQn must not be negative. - */ -__STATIC_INLINE uint32_t __NVIC_GetPendingIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - return((uint32_t)(((NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); - } - else - { - return(0U); - } -} - - -/** - \brief Set Pending Interrupt - \details Sets the pending bit of a device specific interrupt in the NVIC pending register. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_SetPendingIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->ISPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - } -} - - -/** - \brief Clear Pending Interrupt - \details Clears the pending bit of a device specific interrupt in the NVIC pending register. - \param [in] IRQn Device specific interrupt number. - \note IRQn must not be negative. - */ -__STATIC_INLINE void __NVIC_ClearPendingIRQ(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->ICPR[(((uint32_t)IRQn) >> 5UL)] = (uint32_t)(1UL << (((uint32_t)IRQn) & 0x1FUL)); - } -} - - -/** - \brief Get Active Interrupt - \details Reads the active register in the NVIC and returns the active bit for the device specific interrupt. - \param [in] IRQn Device specific interrupt number. - \return 0 Interrupt status is not active. - \return 1 Interrupt status is active. - \note IRQn must not be negative. - */ -__STATIC_INLINE uint32_t __NVIC_GetActive(IRQn_Type IRQn) -{ - if ((int32_t)(IRQn) >= 0) - { - return((uint32_t)(((NVIC->IABR[(((uint32_t)IRQn) >> 5UL)] & (1UL << (((uint32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); - } - else - { - return(0U); - } -} - - -/** - \brief Set Interrupt Priority - \details Sets the priority of a device specific interrupt or a processor exception. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - \param [in] IRQn Interrupt number. - \param [in] priority Priority to set. - \note The priority cannot be set for every processor exception. - */ -__STATIC_INLINE void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) -{ - if ((int32_t)(IRQn) >= 0) - { - NVIC->IP[((uint32_t)IRQn)] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); - } - else - { - SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); - } -} - - -/** - \brief Get Interrupt Priority - \details Reads the priority of a device specific interrupt or a processor exception. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - \param [in] IRQn Interrupt number. - \return Interrupt Priority. - Value is aligned automatically to the implemented priority bits of the microcontroller. - */ -__STATIC_INLINE uint32_t __NVIC_GetPriority(IRQn_Type IRQn) -{ - - if ((int32_t)(IRQn) >= 0) - { - return(((uint32_t)NVIC->IP[((uint32_t)IRQn)] >> (8U - __NVIC_PRIO_BITS))); - } - else - { - return(((uint32_t)SCB->SHP[(((uint32_t)IRQn) & 0xFUL)-4UL] >> (8U - __NVIC_PRIO_BITS))); - } -} - - -/** - \brief Encode Priority - \details Encodes the priority for an interrupt with the given priority group, - preemptive priority value, and subpriority value. - In case of a conflict between priority grouping and available - priority bits (__NVIC_PRIO_BITS), the smallest possible priority group is set. - \param [in] PriorityGroup Used priority group. - \param [in] PreemptPriority Preemptive priority value (starting from 0). - \param [in] SubPriority Subpriority value (starting from 0). - \return Encoded priority. Value can be used in the function \ref NVIC_SetPriority(). - */ -__STATIC_INLINE uint32_t NVIC_EncodePriority (uint32_t PriorityGroup, uint32_t PreemptPriority, uint32_t SubPriority) -{ - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ - uint32_t PreemptPriorityBits; - uint32_t SubPriorityBits; - - PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); - SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); - - return ( - ((PreemptPriority & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL)) << SubPriorityBits) | - ((SubPriority & (uint32_t)((1UL << (SubPriorityBits )) - 1UL))) - ); -} - - -/** - \brief Decode Priority - \details Decodes an interrupt priority value with a given priority group to - preemptive priority value and subpriority value. - In case of a conflict between priority grouping and available - priority bits (__NVIC_PRIO_BITS) the smallest possible priority group is set. - \param [in] Priority Priority value, which can be retrieved with the function \ref NVIC_GetPriority(). - \param [in] PriorityGroup Used priority group. - \param [out] pPreemptPriority Preemptive priority value (starting from 0). - \param [out] pSubPriority Subpriority value (starting from 0). - */ -__STATIC_INLINE void NVIC_DecodePriority (uint32_t Priority, uint32_t PriorityGroup, uint32_t* const pPreemptPriority, uint32_t* const pSubPriority) -{ - uint32_t PriorityGroupTmp = (PriorityGroup & (uint32_t)0x07UL); /* only values 0..7 are used */ - uint32_t PreemptPriorityBits; - uint32_t SubPriorityBits; - - PreemptPriorityBits = ((7UL - PriorityGroupTmp) > (uint32_t)(__NVIC_PRIO_BITS)) ? (uint32_t)(__NVIC_PRIO_BITS) : (uint32_t)(7UL - PriorityGroupTmp); - SubPriorityBits = ((PriorityGroupTmp + (uint32_t)(__NVIC_PRIO_BITS)) < (uint32_t)7UL) ? (uint32_t)0UL : (uint32_t)((PriorityGroupTmp - 7UL) + (uint32_t)(__NVIC_PRIO_BITS)); - - *pPreemptPriority = (Priority >> SubPriorityBits) & (uint32_t)((1UL << (PreemptPriorityBits)) - 1UL); - *pSubPriority = (Priority ) & (uint32_t)((1UL << (SubPriorityBits )) - 1UL); -} - - -/** - \brief Set Interrupt Vector - \details Sets an interrupt vector in SRAM based interrupt vector table. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - VTOR must been relocated to SRAM before. - \param [in] IRQn Interrupt number - \param [in] vector Address of interrupt handler function - */ -__STATIC_INLINE void __NVIC_SetVector(IRQn_Type IRQn, uint32_t vector) -{ - uint32_t vectors = (uint32_t )SCB->VTOR; - (* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)) = vector; - /* ARM Application Note 321 states that the M4 does not require the architectural barrier */ -} - - -/** - \brief Get Interrupt Vector - \details Reads an interrupt vector from interrupt vector table. - The interrupt number can be positive to specify a device specific interrupt, - or negative to specify a processor exception. - \param [in] IRQn Interrupt number. - \return Address of interrupt handler function - */ -__STATIC_INLINE uint32_t __NVIC_GetVector(IRQn_Type IRQn) -{ - uint32_t vectors = (uint32_t )SCB->VTOR; - return (uint32_t)(* (int *) (vectors + ((int32_t)IRQn + NVIC_USER_IRQ_OFFSET) * 4)); -} - - -/** - \brief System Reset - \details Initiates a system reset request to reset the MCU. - */ -__NO_RETURN __STATIC_INLINE void __NVIC_SystemReset(void) -{ - __DSB(); /* Ensure all outstanding memory accesses included - buffered write are completed before reset */ - SCB->AIRCR = (uint32_t)((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | - (SCB->AIRCR & SCB_AIRCR_PRIGROUP_Msk) | - SCB_AIRCR_SYSRESETREQ_Msk ); /* Keep priority group unchanged */ - __DSB(); /* Ensure completion of memory access */ - - for(;;) /* wait until reset */ - { - __NOP(); - } -} - -/*@} end of CMSIS_Core_NVICFunctions */ - - -/* ########################## MPU functions #################################### */ - -#if defined (__MPU_PRESENT) && (__MPU_PRESENT == 1U) - -#include "mpu_armv7.h" - -#endif - - -/* ########################## FPU functions #################################### */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_FpuFunctions FPU Functions - \brief Function that provides FPU type. - @{ - */ - -/** - \brief get FPU type - \details returns the FPU type - \returns - - \b 0: No FPU - - \b 1: Single precision FPU - - \b 2: Double + Single precision FPU - */ -__STATIC_INLINE uint32_t SCB_GetFPUType(void) -{ - uint32_t mvfr0; - - mvfr0 = FPU->MVFR0; - if ((mvfr0 & (FPU_MVFR0_Single_precision_Msk | FPU_MVFR0_Double_precision_Msk)) == 0x020U) - { - return 1U; /* Single precision FPU */ - } - else - { - return 0U; /* No FPU */ - } -} - - -/*@} end of CMSIS_Core_FpuFunctions */ - - - -/* ################################## SysTick function ############################################ */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_Core_SysTickFunctions SysTick Functions - \brief Functions that configure the System. - @{ - */ - -#if defined (__Vendor_SysTickConfig) && (__Vendor_SysTickConfig == 0U) - -/** - \brief System Tick Configuration - \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. - Counter is in free running mode to generate periodic interrupts. - \param [in] ticks Number of ticks between two interrupts. - \return 0 Function succeeded. - \return 1 Function failed. - \note When the variable __Vendor_SysTickConfig is set to 1, then the - function SysTick_Config is not included. In this case, the file device.h - must contain a vendor-specific implementation of this function. - */ -__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) -{ - if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) - { - return (1UL); /* Reload value impossible */ - } - - SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ - NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ - SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ - SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | - SysTick_CTRL_TICKINT_Msk | - SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ - return (0UL); /* Function successful */ -} - -#endif - -/*@} end of CMSIS_Core_SysTickFunctions */ - - - -/* ##################################### Debug In/Output function ########################################### */ -/** - \ingroup CMSIS_Core_FunctionInterface - \defgroup CMSIS_core_DebugFunctions ITM Functions - \brief Functions that access the ITM debug interface. - @{ - */ - -extern volatile int32_t ITM_RxBuffer; /*!< External variable to receive characters. */ -#define ITM_RXBUFFER_EMPTY ((int32_t)0x5AA55AA5U) /*!< Value identifying \ref ITM_RxBuffer is ready for next character. */ - - -/** - \brief ITM Send Character - \details Transmits a character via the ITM channel 0, and - \li Just returns when no debugger is connected that has booked the output. - \li Is blocking when a debugger is connected, but the previous character sent has not been transmitted. - \param [in] ch Character to transmit. - \returns Character to transmit. - */ -__STATIC_INLINE uint32_t ITM_SendChar (uint32_t ch) -{ - if (((ITM->TCR & ITM_TCR_ITMENA_Msk) != 0UL) && /* ITM enabled */ - ((ITM->TER & 1UL ) != 0UL) ) /* ITM Port #0 enabled */ - { - while (ITM->PORT[0U].u32 == 0UL) - { - __NOP(); - } - ITM->PORT[0U].u8 = (uint8_t)ch; - } - return (ch); -} - - -/** - \brief ITM Receive Character - \details Inputs a character via the external variable \ref ITM_RxBuffer. - \return Received character. - \return -1 No character pending. - */ -__STATIC_INLINE int32_t ITM_ReceiveChar (void) -{ - int32_t ch = -1; /* no character available */ - - if (ITM_RxBuffer != ITM_RXBUFFER_EMPTY) - { - ch = ITM_RxBuffer; - ITM_RxBuffer = ITM_RXBUFFER_EMPTY; /* ready for next character */ - } - - return (ch); -} - - -/** - \brief ITM Check Character - \details Checks whether a character is pending for reading in the variable \ref ITM_RxBuffer. - \return 0 No character available. - \return 1 Character available. - */ -__STATIC_INLINE int32_t ITM_CheckChar (void) -{ - - if (ITM_RxBuffer == ITM_RXBUFFER_EMPTY) - { - return (0); /* no character available */ - } - else - { - return (1); /* character available */ - } -} - -/*@} end of CMSIS_core_DebugFunctions */ - - - - -#ifdef __cplusplus -} -#endif - -#endif /* __CORE_CM4_H_DEPENDANT */ - -#endif /* __CMSIS_GENERIC */ - diff --git a/panda/board/inc/mpu_armv7.h b/panda/board/inc/mpu_armv7.h deleted file mode 100644 index ef8e6810ca..0000000000 --- a/panda/board/inc/mpu_armv7.h +++ /dev/null @@ -1,273 +0,0 @@ -/****************************************************************************** - * @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 - diff --git a/panda/board/inc/stm32f205xx.h b/panda/board/inc/stm32f205xx.h deleted file mode 100644 index 622faead62..0000000000 --- a/panda/board/inc/stm32f205xx.h +++ /dev/null @@ -1,7666 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f205xx.h - * @author MCD Application Team - * @version V2.1.2 - * @date 29-June-2016 - * @brief CMSIS STM32F205xx Device Peripheral Access Layer Header File. - * This file contains : - * - Data structures and the address mapping for all peripherals - * - Peripherals registers declarations and bits definition - * - Macros to access peripheral’s registers hardware - * - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32f205xx - * @{ - */ - -#ifndef __STM32F205xx_H -#define __STM32F205xx_H - -#ifdef __cplusplus - extern "C" { -#endif /* __cplusplus */ - - -/** @addtogroup Configuration_section_for_CMSIS - * @{ - */ - -/** - * @brief Configuration of the Cortex-M3 Processor and Core Peripherals - */ -#define __CM3_REV 0x0200U /*!< Core revision r0p1 */ -#define __MPU_PRESENT 1U /*!< STM32F2XX provides an MPU */ -#define __NVIC_PRIO_BITS 4U /*!< STM32F2XX uses 4 Bits for the Priority Levels */ -#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */ - -/** - * @} - */ - -/** @addtogroup Peripheral_interrupt_number_definition - * @{ - */ - -/** - * @brief STM32F2XX Interrupt Number Definition, according to the selected device - * in @ref Library_configuration_section - */ -typedef enum -{ -/****** Cortex-M3 Processor Exceptions Numbers ****************************************************************/ - NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ - MemoryManagement_IRQn = -12, /*!< 4 Cortex-M3 Memory Management Interrupt */ - BusFault_IRQn = -11, /*!< 5 Cortex-M3 Bus Fault Interrupt */ - UsageFault_IRQn = -10, /*!< 6 Cortex-M3 Usage Fault Interrupt */ - SVCall_IRQn = -5, /*!< 11 Cortex-M3 SV Call Interrupt */ - DebugMonitor_IRQn = -4, /*!< 12 Cortex-M3 Debug Monitor Interrupt */ - PendSV_IRQn = -2, /*!< 14 Cortex-M3 Pend SV Interrupt */ - SysTick_IRQn = -1, /*!< 15 Cortex-M3 System Tick Interrupt */ -/****** STM32 specific Interrupt Numbers **********************************************************************/ - WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ - PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ - TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ - RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ - FLASH_IRQn = 4, /*!< FLASH global Interrupt */ - RCC_IRQn = 5, /*!< RCC global Interrupt */ - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ - EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ - EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ - EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ - DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ - DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ - DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ - DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ - DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ - DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ - DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ - ADC_IRQn = 18, /*!< ADC1, ADC2 and ADC3 global Interrupts */ - CAN1_TX_IRQn = 19, /*!< CAN1 TX Interrupt */ - CAN1_RX0_IRQn = 20, /*!< CAN1 RX0 Interrupt */ - CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ - CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ - EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ - TIM1_BRK_TIM9_IRQn = 24, /*!< TIM1 Break interrupt and TIM9 global interrupt */ - TIM1_UP_TIM10_IRQn = 25, /*!< TIM1 Update Interrupt and TIM10 global interrupt */ - TIM1_TRG_COM_TIM11_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */ - TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ - TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ - TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ - TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ - I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ - I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ - I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ - I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ - SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ - SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ - USART1_IRQn = 37, /*!< USART1 global Interrupt */ - USART2_IRQn = 38, /*!< USART2 global Interrupt */ - USART3_IRQn = 39, /*!< USART3 global Interrupt */ - EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ - RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ - OTG_FS_WKUP_IRQn = 42, /*!< USB OTG FS Wakeup through EXTI line interrupt */ - TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ - TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ - TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ - TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare Interrupt */ - DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ - FSMC_IRQn = 48, /*!< FSMC global Interrupt */ - SDIO_IRQn = 49, /*!< SDIO global Interrupt */ - TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ - SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ - UART4_IRQn = 52, /*!< UART4 global Interrupt */ - UART5_IRQn = 53, /*!< UART5 global Interrupt */ - TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ - TIM7_IRQn = 55, /*!< TIM7 global interrupt */ - DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ - DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ - DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ - DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ - DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ - CAN2_TX_IRQn = 63, /*!< CAN2 TX Interrupt */ - CAN2_RX0_IRQn = 64, /*!< CAN2 RX0 Interrupt */ - CAN2_RX1_IRQn = 65, /*!< CAN2 RX1 Interrupt */ - CAN2_SCE_IRQn = 66, /*!< CAN2 SCE Interrupt */ - OTG_FS_IRQn = 67, /*!< USB OTG FS global Interrupt */ - DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ - DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ - DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ - USART6_IRQn = 71, /*!< USART6 global interrupt */ - I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ - I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ - OTG_HS_EP1_OUT_IRQn = 74, /*!< USB OTG HS End Point 1 Out global interrupt */ - OTG_HS_EP1_IN_IRQn = 75, /*!< USB OTG HS End Point 1 In global interrupt */ - OTG_HS_WKUP_IRQn = 76, /*!< USB OTG HS Wakeup through EXTI interrupt */ - OTG_HS_IRQn = 77, /*!< USB OTG HS global interrupt */ - HASH_RNG_IRQn = 80 /*!< Hash and RNG global interrupt */ -} IRQn_Type; - -/** - * @} - */ - -#include "core_cm3.h" -#include "system_stm32f2xx.h" -#include - -/** @addtogroup Peripheral_registers_structures - * @{ - */ - -/** - * @brief Analog to Digital Converter - */ - -typedef struct -{ - __IO uint32_t SR; /*!< ADC status register, Address offset: 0x00 */ - __IO uint32_t CR1; /*!< ADC control register 1, Address offset: 0x04 */ - __IO uint32_t CR2; /*!< ADC control register 2, Address offset: 0x08 */ - __IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x0C */ - __IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x10 */ - __IO uint32_t JOFR1; /*!< ADC injected channel data offset register 1, Address offset: 0x14 */ - __IO uint32_t JOFR2; /*!< ADC injected channel data offset register 2, Address offset: 0x18 */ - __IO uint32_t JOFR3; /*!< ADC injected channel data offset register 3, Address offset: 0x1C */ - __IO uint32_t JOFR4; /*!< ADC injected channel data offset register 4, Address offset: 0x20 */ - __IO uint32_t HTR; /*!< ADC watchdog higher threshold register, Address offset: 0x24 */ - __IO uint32_t LTR; /*!< ADC watchdog lower threshold register, Address offset: 0x28 */ - __IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x2C */ - __IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x30 */ - __IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x34 */ - __IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x38*/ - __IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x3C */ - __IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x40 */ - __IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x44 */ - __IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x48 */ - __IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x4C */ -} ADC_TypeDef; - -typedef struct -{ - __IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ - __IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ - __IO uint32_t CDR; /*!< ADC common regular data register for dual - AND triple modes, Address offset: ADC1 base address + 0x308 */ -} ADC_Common_TypeDef; - - -/** - * @brief Controller Area Network TxMailBox - */ - -typedef struct -{ - __IO uint32_t TIR; /*!< CAN TX mailbox identifier register */ - __IO uint32_t TDTR; /*!< CAN mailbox data length control and time stamp register */ - __IO uint32_t TDLR; /*!< CAN mailbox data low register */ - __IO uint32_t TDHR; /*!< CAN mailbox data high register */ -} CAN_TxMailBox_TypeDef; - -/** - * @brief Controller Area Network FIFOMailBox - */ - -typedef struct -{ - __IO uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */ - __IO uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */ - __IO uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */ - __IO uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */ -} CAN_FIFOMailBox_TypeDef; - -/** - * @brief Controller Area Network FilterRegister - */ - -typedef struct -{ - __IO uint32_t FR1; /*!< CAN Filter bank register 1 */ - __IO uint32_t FR2; /*!< CAN Filter bank register 1 */ -} CAN_FilterRegister_TypeDef; - -/** - * @brief Controller Area Network - */ - -typedef struct -{ - __IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */ - __IO uint32_t MSR; /*!< CAN master status register, Address offset: 0x04 */ - __IO uint32_t TSR; /*!< CAN transmit status register, Address offset: 0x08 */ - __IO uint32_t RF0R; /*!< CAN receive FIFO 0 register, Address offset: 0x0C */ - __IO uint32_t RF1R; /*!< CAN receive FIFO 1 register, Address offset: 0x10 */ - __IO uint32_t IER; /*!< CAN interrupt enable register, Address offset: 0x14 */ - __IO uint32_t ESR; /*!< CAN error status register, Address offset: 0x18 */ - __IO uint32_t BTR; /*!< CAN bit timing register, Address offset: 0x1C */ - uint32_t RESERVED0[88]; /*!< Reserved, 0x020 - 0x17F */ - CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< CAN Tx MailBox, Address offset: 0x180 - 0x1AC */ - CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< CAN FIFO MailBox, Address offset: 0x1B0 - 0x1CC */ - uint32_t RESERVED1[12]; /*!< Reserved, 0x1D0 - 0x1FF */ - __IO uint32_t FMR; /*!< CAN filter master register, Address offset: 0x200 */ - __IO uint32_t FM1R; /*!< CAN filter mode register, Address offset: 0x204 */ - uint32_t RESERVED2; /*!< Reserved, 0x208 */ - __IO uint32_t FS1R; /*!< CAN filter scale register, Address offset: 0x20C */ - uint32_t RESERVED3; /*!< Reserved, 0x210 */ - __IO uint32_t FFA1R; /*!< CAN filter FIFO assignment register, Address offset: 0x214 */ - uint32_t RESERVED4; /*!< Reserved, 0x218 */ - __IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */ - uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */ - CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */ -} CAN_TypeDef; - -/** - * @brief CRC calculation unit - */ - -typedef struct -{ - __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ - __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ - uint8_t RESERVED0; /*!< Reserved, 0x05 */ - uint16_t RESERVED1; /*!< Reserved, 0x06 */ - __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ -} CRC_TypeDef; - -/** - * @brief Digital to Analog Converter - */ - -typedef struct -{ - __IO uint32_t CR; /*!< DAC control register, Address offset: 0x00 */ - __IO uint32_t SWTRIGR; /*!< DAC software trigger register, Address offset: 0x04 */ - __IO uint32_t DHR12R1; /*!< DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 */ - __IO uint32_t DHR12L1; /*!< DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C */ - __IO uint32_t DHR8R1; /*!< DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 */ - __IO uint32_t DHR12R2; /*!< DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 */ - __IO uint32_t DHR12L2; /*!< DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 */ - __IO uint32_t DHR8R2; /*!< DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C */ - __IO uint32_t DHR12RD; /*!< Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 */ - __IO uint32_t DHR12LD; /*!< DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 */ - __IO uint32_t DHR8RD; /*!< DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 */ - __IO uint32_t DOR1; /*!< DAC channel1 data output register, Address offset: 0x2C */ - __IO uint32_t DOR2; /*!< DAC channel2 data output register, Address offset: 0x30 */ - __IO uint32_t SR; /*!< DAC status register, Address offset: 0x34 */ -} DAC_TypeDef; - -/** - * @brief Debug MCU - */ - -typedef struct -{ - __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ - __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ - __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */ - __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */ -}DBGMCU_TypeDef; - - -/** - * @brief DMA Controller - */ - -typedef struct -{ - __IO uint32_t CR; /*!< DMA stream x configuration register */ - __IO uint32_t NDTR; /*!< DMA stream x number of data register */ - __IO uint32_t PAR; /*!< DMA stream x peripheral address register */ - __IO uint32_t M0AR; /*!< DMA stream x memory 0 address register */ - __IO uint32_t M1AR; /*!< DMA stream x memory 1 address register */ - __IO uint32_t FCR; /*!< DMA stream x FIFO control register */ -} DMA_Stream_TypeDef; - -typedef struct -{ - __IO uint32_t LISR; /*!< DMA low interrupt status register, Address offset: 0x00 */ - __IO uint32_t HISR; /*!< DMA high interrupt status register, Address offset: 0x04 */ - __IO uint32_t LIFCR; /*!< DMA low interrupt flag clear register, Address offset: 0x08 */ - __IO uint32_t HIFCR; /*!< DMA high interrupt flag clear register, Address offset: 0x0C */ -} DMA_TypeDef; - - -/** - * @brief External Interrupt/Event Controller - */ - -typedef struct -{ - __IO uint32_t IMR; /*!< EXTI Interrupt mask register, Address offset: 0x00 */ - __IO uint32_t EMR; /*!< EXTI Event mask register, Address offset: 0x04 */ - __IO uint32_t RTSR; /*!< EXTI Rising trigger selection register, Address offset: 0x08 */ - __IO uint32_t FTSR; /*!< EXTI Falling trigger selection register, Address offset: 0x0C */ - __IO uint32_t SWIER; /*!< EXTI Software interrupt event register, Address offset: 0x10 */ - __IO uint32_t PR; /*!< EXTI Pending register, Address offset: 0x14 */ -} EXTI_TypeDef; - -/** - * @brief FLASH Registers - */ - -typedef struct -{ - __IO uint32_t ACR; /*!< FLASH access control register, Address offset: 0x00 */ - __IO uint32_t KEYR; /*!< FLASH key register, Address offset: 0x04 */ - __IO uint32_t OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ - __IO uint32_t SR; /*!< FLASH status register, Address offset: 0x0C */ - __IO uint32_t CR; /*!< FLASH control register, Address offset: 0x10 */ - __IO uint32_t OPTCR; /*!< FLASH option control register, Address offset: 0x14 */ -} FLASH_TypeDef; - - -/** - * @brief Flexible Static Memory Controller - */ - -typedef struct -{ - __IO uint32_t BTCR[8]; /*!< NOR/PSRAM chip-select control register(BCR) and chip-select timing register(BTR), Address offset: 0x00-1C */ -} FSMC_Bank1_TypeDef; - -/** - * @brief Flexible Static Memory Controller Bank1E - */ - -typedef struct -{ - __IO uint32_t BWTR[7]; /*!< NOR/PSRAM write timing registers, Address offset: 0x104-0x11C */ -} FSMC_Bank1E_TypeDef; - -/** - * @brief Flexible Static Memory Controller Bank2 - */ - -typedef struct -{ - __IO uint32_t PCR2; /*!< NAND Flash control register 2, Address offset: 0x60 */ - __IO uint32_t SR2; /*!< NAND Flash FIFO status and interrupt register 2, Address offset: 0x64 */ - __IO uint32_t PMEM2; /*!< NAND Flash Common memory space timing register 2, Address offset: 0x68 */ - __IO uint32_t PATT2; /*!< NAND Flash Attribute memory space timing register 2, Address offset: 0x6C */ - uint32_t RESERVED0; /*!< Reserved, 0x70 */ - __IO uint32_t ECCR2; /*!< NAND Flash ECC result registers 2, Address offset: 0x74 */ - uint32_t RESERVED1; /*!< Reserved, 0x78 */ - uint32_t RESERVED2; /*!< Reserved, 0x7C */ - __IO uint32_t PCR3; /*!< NAND Flash control register 3, Address offset: 0x80 */ - __IO uint32_t SR3; /*!< NAND Flash FIFO status and interrupt register 3, Address offset: 0x84 */ - __IO uint32_t PMEM3; /*!< NAND Flash Common memory space timing register 3, Address offset: 0x88 */ - __IO uint32_t PATT3; /*!< NAND Flash Attribute memory space timing register 3, Address offset: 0x8C */ - uint32_t RESERVED3; /*!< Reserved, 0x90 */ - __IO uint32_t ECCR3; /*!< NAND Flash ECC result registers 3, Address offset: 0x94 */ -} FSMC_Bank2_3_TypeDef; - -/** - * @brief Flexible Static Memory Controller Bank4 - */ - -typedef struct -{ - __IO uint32_t PCR4; /*!< PC Card control register 4, Address offset: 0xA0 */ - __IO uint32_t SR4; /*!< PC Card FIFO status and interrupt register 4, Address offset: 0xA4 */ - __IO uint32_t PMEM4; /*!< PC Card Common memory space timing register 4, Address offset: 0xA8 */ - __IO uint32_t PATT4; /*!< PC Card Attribute memory space timing register 4, Address offset: 0xAC */ - __IO uint32_t PIO4; /*!< PC Card I/O space timing register 4, Address offset: 0xB0 */ -} FSMC_Bank4_TypeDef; - - -/** - * @brief General Purpose I/O - */ - -typedef struct -{ - __IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */ - __IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ - __IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ - __IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ - __IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */ - __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */ - __IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */ - __IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ - __IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */ -} GPIO_TypeDef; - -/** - * @brief System configuration controller - */ - -typedef struct -{ - __IO uint32_t MEMRMP; /*!< SYSCFG memory remap register, Address offset: 0x00 */ - __IO uint32_t PMC; /*!< SYSCFG peripheral mode configuration register, Address offset: 0x04 */ - __IO uint32_t EXTICR[4]; /*!< SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 */ - uint32_t RESERVED[2]; /*!< Reserved, 0x18-0x1C */ - __IO uint32_t CMPCR; /*!< SYSCFG Compensation cell control register, Address offset: 0x20 */ -} SYSCFG_TypeDef; - -/** - * @brief Inter-integrated Circuit Interface - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< I2C Control register 1, Address offset: 0x00 */ - __IO uint32_t CR2; /*!< I2C Control register 2, Address offset: 0x04 */ - __IO uint32_t OAR1; /*!< I2C Own address register 1, Address offset: 0x08 */ - __IO uint32_t OAR2; /*!< I2C Own address register 2, Address offset: 0x0C */ - __IO uint32_t DR; /*!< I2C Data register, Address offset: 0x10 */ - __IO uint32_t SR1; /*!< I2C Status register 1, Address offset: 0x14 */ - __IO uint32_t SR2; /*!< I2C Status register 2, Address offset: 0x18 */ - __IO uint32_t CCR; /*!< I2C Clock control register, Address offset: 0x1C */ - __IO uint32_t TRISE; /*!< I2C TRISE register, Address offset: 0x20 */ -} I2C_TypeDef; - -/** - * @brief Independent WATCHDOG - */ - -typedef struct -{ - __IO uint32_t KR; /*!< IWDG Key register, Address offset: 0x00 */ - __IO uint32_t PR; /*!< IWDG Prescaler register, Address offset: 0x04 */ - __IO uint32_t RLR; /*!< IWDG Reload register, Address offset: 0x08 */ - __IO uint32_t SR; /*!< IWDG Status register, Address offset: 0x0C */ -} IWDG_TypeDef; - -/** - * @brief Power Control - */ - -typedef struct -{ - __IO uint32_t CR; /*!< PWR power control register, Address offset: 0x00 */ - __IO uint32_t CSR; /*!< PWR power control/status register, Address offset: 0x04 */ -} PWR_TypeDef; - -/** - * @brief Reset and Clock Control - */ - -typedef struct -{ - __IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */ - __IO uint32_t PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ - __IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ - __IO uint32_t CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ - __IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ - __IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ - __IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ - uint32_t RESERVED0; /*!< Reserved, 0x1C */ - __IO uint32_t APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ - __IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ - uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0x2C */ - __IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ - __IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ - __IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ - uint32_t RESERVED2; /*!< Reserved, 0x3C */ - __IO uint32_t APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ - __IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ - uint32_t RESERVED3[2]; /*!< Reserved, 0x48-0x4C */ - __IO uint32_t AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ - __IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ - __IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ - uint32_t RESERVED4; /*!< Reserved, 0x5C */ - __IO uint32_t APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ - __IO uint32_t APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ - uint32_t RESERVED5[2]; /*!< Reserved, 0x68-0x6C */ - __IO uint32_t BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ - __IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ - uint32_t RESERVED6[2]; /*!< Reserved, 0x78-0x7C */ - __IO uint32_t SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ - __IO uint32_t PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ - -} RCC_TypeDef; - -/** - * @brief Real-Time Clock - */ - -typedef struct -{ - __IO uint32_t TR; /*!< RTC time register, Address offset: 0x00 */ - __IO uint32_t DR; /*!< RTC date register, Address offset: 0x04 */ - __IO uint32_t CR; /*!< RTC control register, Address offset: 0x08 */ - __IO uint32_t ISR; /*!< RTC initialization and status register, Address offset: 0x0C */ - __IO uint32_t PRER; /*!< RTC prescaler register, Address offset: 0x10 */ - __IO uint32_t WUTR; /*!< RTC wakeup timer register, Address offset: 0x14 */ - __IO uint32_t CALIBR; /*!< RTC calibration register, Address offset: 0x18 */ - __IO uint32_t ALRMAR; /*!< RTC alarm A register, Address offset: 0x1C */ - __IO uint32_t ALRMBR; /*!< RTC alarm B register, Address offset: 0x20 */ - __IO uint32_t WPR; /*!< RTC write protection register, Address offset: 0x24 */ - uint32_t RESERVED1; /*!< Reserved, 0x28 */ - uint32_t RESERVED2; /*!< Reserved, 0x2C */ - __IO uint32_t TSTR; /*!< RTC time stamp time register, Address offset: 0x30 */ - __IO uint32_t TSDR; /*!< RTC time stamp date register, Address offset: 0x34 */ - uint32_t RESERVED3; /*!< Reserved, 0x38 */ - uint32_t RESERVED4; /*!< Reserved, 0x3C */ - __IO uint32_t TAFCR; /*!< RTC tamper and alternate function configuration register, Address offset: 0x40 */ - uint32_t RESERVED5; /*!< Reserved, 0x44 */ - uint32_t RESERVED6; /*!< Reserved, 0x48 */ - uint32_t RESERVED7; /*!< Reserved, 0x4C */ - __IO uint32_t BKP0R; /*!< RTC backup register 1, Address offset: 0x50 */ - __IO uint32_t BKP1R; /*!< RTC backup register 1, Address offset: 0x54 */ - __IO uint32_t BKP2R; /*!< RTC backup register 2, Address offset: 0x58 */ - __IO uint32_t BKP3R; /*!< RTC backup register 3, Address offset: 0x5C */ - __IO uint32_t BKP4R; /*!< RTC backup register 4, Address offset: 0x60 */ - __IO uint32_t BKP5R; /*!< RTC backup register 5, Address offset: 0x64 */ - __IO uint32_t BKP6R; /*!< RTC backup register 6, Address offset: 0x68 */ - __IO uint32_t BKP7R; /*!< RTC backup register 7, Address offset: 0x6C */ - __IO uint32_t BKP8R; /*!< RTC backup register 8, Address offset: 0x70 */ - __IO uint32_t BKP9R; /*!< RTC backup register 9, Address offset: 0x74 */ - __IO uint32_t BKP10R; /*!< RTC backup register 10, Address offset: 0x78 */ - __IO uint32_t BKP11R; /*!< RTC backup register 11, Address offset: 0x7C */ - __IO uint32_t BKP12R; /*!< RTC backup register 12, Address offset: 0x80 */ - __IO uint32_t BKP13R; /*!< RTC backup register 13, Address offset: 0x84 */ - __IO uint32_t BKP14R; /*!< RTC backup register 14, Address offset: 0x88 */ - __IO uint32_t BKP15R; /*!< RTC backup register 15, Address offset: 0x8C */ - __IO uint32_t BKP16R; /*!< RTC backup register 16, Address offset: 0x90 */ - __IO uint32_t BKP17R; /*!< RTC backup register 17, Address offset: 0x94 */ - __IO uint32_t BKP18R; /*!< RTC backup register 18, Address offset: 0x98 */ - __IO uint32_t BKP19R; /*!< RTC backup register 19, Address offset: 0x9C */ -} RTC_TypeDef; - - -/** - * @brief SD host Interface - */ - -typedef struct -{ - __IO uint32_t POWER; /*!< SDIO power control register, Address offset: 0x00 */ - __IO uint32_t CLKCR; /*!< SDI clock control register, Address offset: 0x04 */ - __IO uint32_t ARG; /*!< SDIO argument register, Address offset: 0x08 */ - __IO uint32_t CMD; /*!< SDIO command register, Address offset: 0x0C */ - __IO const uint32_t RESPCMD; /*!< SDIO command response register, Address offset: 0x10 */ - __IO const uint32_t RESP1; /*!< SDIO response 1 register, Address offset: 0x14 */ - __IO const uint32_t RESP2; /*!< SDIO response 2 register, Address offset: 0x18 */ - __IO const uint32_t RESP3; /*!< SDIO response 3 register, Address offset: 0x1C */ - __IO const uint32_t RESP4; /*!< SDIO response 4 register, Address offset: 0x20 */ - __IO uint32_t DTIMER; /*!< SDIO data timer register, Address offset: 0x24 */ - __IO uint32_t DLEN; /*!< SDIO data length register, Address offset: 0x28 */ - __IO uint32_t DCTRL; /*!< SDIO data control register, Address offset: 0x2C */ - __IO const uint32_t DCOUNT; /*!< SDIO data counter register, Address offset: 0x30 */ - __IO const uint32_t STA; /*!< SDIO status register, Address offset: 0x34 */ - __IO uint32_t ICR; /*!< SDIO interrupt clear register, Address offset: 0x38 */ - __IO uint32_t MASK; /*!< SDIO mask register, Address offset: 0x3C */ - uint32_t RESERVED0[2]; /*!< Reserved, 0x40-0x44 */ - __IO const uint32_t FIFOCNT; /*!< SDIO FIFO counter register, Address offset: 0x48 */ - uint32_t RESERVED1[13]; /*!< Reserved, 0x4C-0x7C */ - __IO uint32_t FIFO; /*!< SDIO data FIFO register, Address offset: 0x80 */ -} SDIO_TypeDef; - -/** - * @brief Serial Peripheral Interface - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< SPI control register 1 (not used in I2S mode), Address offset: 0x00 */ - __IO uint32_t CR2; /*!< SPI control register 2, Address offset: 0x04 */ - __IO uint32_t SR; /*!< SPI status register, Address offset: 0x08 */ - __IO uint32_t DR; /*!< SPI data register, Address offset: 0x0C */ - __IO uint32_t CRCPR; /*!< SPI CRC polynomial register (not used in I2S mode), Address offset: 0x10 */ - __IO uint32_t RXCRCR; /*!< SPI RX CRC register (not used in I2S mode), Address offset: 0x14 */ - __IO uint32_t TXCRCR; /*!< SPI TX CRC register (not used in I2S mode), Address offset: 0x18 */ - __IO uint32_t I2SCFGR; /*!< SPI_I2S configuration register, Address offset: 0x1C */ - __IO uint32_t I2SPR; /*!< SPI_I2S prescaler register, Address offset: 0x20 */ -} SPI_TypeDef; - -/** - * @brief TIM - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ - __IO uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ - __IO uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ - __IO uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ - __IO uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ - __IO uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ - __IO uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ - __IO uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ - __IO uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ - __IO uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ - __IO uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ - __IO uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ - __IO uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ - __IO uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ - __IO uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ - __IO uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ - __IO uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ - __IO uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ - __IO uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ - __IO uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ - __IO uint32_t OR; /*!< TIM option register, Address offset: 0x50 */ -} TIM_TypeDef; - -/** - * @brief Universal Synchronous Asynchronous Receiver Transmitter - */ - -typedef struct -{ - __IO uint32_t SR; /*!< USART Status register, Address offset: 0x00 */ - __IO uint32_t DR; /*!< USART Data register, Address offset: 0x04 */ - __IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */ - __IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */ - __IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */ - __IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */ - __IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */ -} USART_TypeDef; - -/** - * @brief Window WATCHDOG - */ - -typedef struct -{ - __IO uint32_t CR; /*!< WWDG Control register, Address offset: 0x00 */ - __IO uint32_t CFR; /*!< WWDG Configuration register, Address offset: 0x04 */ - __IO uint32_t SR; /*!< WWDG Status register, Address offset: 0x08 */ -} WWDG_TypeDef; - - -/** - * @brief RNG - */ - -typedef struct -{ - __IO uint32_t CR; /*!< RNG control register, Address offset: 0x00 */ - __IO uint32_t SR; /*!< RNG status register, Address offset: 0x04 */ - __IO uint32_t DR; /*!< RNG data register, Address offset: 0x08 */ -} RNG_TypeDef; - - - -/** - * @brief __USB_OTG_Core_register - */ -typedef struct -{ - __IO uint32_t GOTGCTL; /*!< USB_OTG Control and Status Register Address offset : 0x00 */ - __IO uint32_t GOTGINT; /*!< USB_OTG Interrupt Register Address offset : 0x04 */ - __IO uint32_t GAHBCFG; /*!< Core AHB Configuration Register Address offset : 0x08 */ - __IO uint32_t GUSBCFG; /*!< Core USB Configuration Register Address offset : 0x0C */ - __IO uint32_t GRSTCTL; /*!< Core Reset Register Address offset : 0x10 */ - __IO uint32_t GINTSTS; /*!< Core Interrupt Register Address offset : 0x14 */ - __IO uint32_t GINTMSK; /*!< Core Interrupt Mask Register Address offset : 0x18 */ - __IO uint32_t GRXSTSR; /*!< Receive Sts Q Read Register Address offset : 0x1C */ - __IO uint32_t GRXSTSP; /*!< Receive Sts Q Read & POP Register Address offset : 0x20 */ - __IO uint32_t GRXFSIZ; /* Receive FIFO Size Register Address offset : 0x24 */ - __IO uint32_t DIEPTXF0_HNPTXFSIZ; /*!< EP0 / Non Periodic Tx FIFO Size Register Address offset : 0x28 */ - __IO uint32_t HNPTXSTS; /*!< Non Periodic Tx FIFO/Queue Sts reg Address offset : 0x2C */ - uint32_t Reserved30[2]; /* Reserved Address offset : 0x30 */ - __IO uint32_t GCCFG; /*!< General Purpose IO Register Address offset : 0x38 */ - __IO uint32_t CID; /*!< User ID Register Address offset : 0x3C */ - uint32_t Reserved40[48]; /*!< Reserved Address offset : 0x40-0xFF */ - __IO uint32_t HPTXFSIZ; /*!< Host Periodic Tx FIFO Size Reg Address offset : 0x100 */ - __IO uint32_t DIEPTXF[0x0F]; /*!< dev Periodic Transmit FIFO */ -} -USB_OTG_GlobalTypeDef; - - - -/** - * @brief __device_Registers - */ -typedef struct -{ - __IO uint32_t DCFG; /*!< dev Configuration Register Address offset : 0x800 */ - __IO uint32_t DCTL; /*!< dev Control Register Address offset : 0x804 */ - __IO uint32_t DSTS; /*!< dev Status Register (RO) Address offset : 0x808 */ - uint32_t Reserved0C; /*!< Reserved Address offset : 0x80C */ - __IO uint32_t DIEPMSK; /* !< dev IN Endpoint Mask Address offset : 0x810 */ - __IO uint32_t DOEPMSK; /*!< dev OUT Endpoint Mask Address offset : 0x814 */ - __IO uint32_t DAINT; /*!< dev All Endpoints Itr Reg Address offset : 0x818 */ - __IO uint32_t DAINTMSK; /*!< dev All Endpoints Itr Mask Address offset : 0x81C */ - uint32_t Reserved20; /*!< Reserved Address offset : 0x820 */ - uint32_t Reserved9; /*!< Reserved Address offset : 0x824 */ - __IO uint32_t DVBUSDIS; /*!< dev VBUS discharge Register Address offset : 0x828 */ - __IO uint32_t DVBUSPULSE; /*!< dev VBUS Pulse Register Address offset : 0x82C */ - __IO uint32_t DTHRCTL; /*!< dev thr Address offset : 0x830 */ - __IO uint32_t DIEPEMPMSK; /*!< dev empty msk Address offset : 0x834 */ - __IO uint32_t DEACHINT; /*!< dedicated EP interrupt Address offset : 0x838 */ - __IO uint32_t DEACHMSK; /*!< dedicated EP msk Address offset : 0x83C */ - uint32_t Reserved40; /*!< dedicated EP mask Address offset : 0x840 */ - __IO uint32_t DINEP1MSK; /*!< dedicated EP mask Address offset : 0x844 */ - uint32_t Reserved44[15]; /*!< Reserved Address offset : 0x844-0x87C */ - __IO uint32_t DOUTEP1MSK; /*!< dedicated EP msk Address offset : 0x884 */ -} -USB_OTG_DeviceTypeDef; - - -/** - * @brief __IN_Endpoint-Specific_Register - */ -typedef struct -{ - __IO uint32_t DIEPCTL; /* dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h */ - uint32_t Reserved04; /* Reserved 900h + (ep_num * 20h) + 04h */ - __IO uint32_t DIEPINT; /* dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h */ - uint32_t Reserved0C; /* Reserved 900h + (ep_num * 20h) + 0Ch */ - __IO uint32_t DIEPTSIZ; /* IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h */ - __IO uint32_t DIEPDMA; /* IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h */ - __IO uint32_t DTXFSTS; /*IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h */ - uint32_t Reserved18; /* Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch */ -} -USB_OTG_INEndpointTypeDef; - - -/** - * @brief __OUT_Endpoint-Specific_Registers - */ -typedef struct -{ - __IO uint32_t DOEPCTL; /* dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h*/ - uint32_t Reserved04; /* Reserved B00h + (ep_num * 20h) + 04h*/ - __IO uint32_t DOEPINT; /* dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h*/ - uint32_t Reserved0C; /* Reserved B00h + (ep_num * 20h) + 0Ch*/ - __IO uint32_t DOEPTSIZ; /* dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h*/ - __IO uint32_t DOEPDMA; /* dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h*/ - uint32_t Reserved18[2]; /* Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch*/ -} -USB_OTG_OUTEndpointTypeDef; - - -/** - * @brief __Host_Mode_Register_Structures - */ -typedef struct -{ - __IO uint32_t HCFG; /* Host Configuration Register 400h*/ - __IO uint32_t HFIR; /* Host Frame Interval Register 404h*/ - __IO uint32_t HFNUM; /* Host Frame Nbr/Frame Remaining 408h*/ - uint32_t Reserved40C; /* Reserved 40Ch*/ - __IO uint32_t HPTXSTS; /* Host Periodic Tx FIFO/ Queue Status 410h*/ - __IO uint32_t HAINT; /* Host All Channels Interrupt Register 414h*/ - __IO uint32_t HAINTMSK; /* Host All Channels Interrupt Mask 418h*/ -} -USB_OTG_HostTypeDef; - - -/** - * @brief __Host_Channel_Specific_Registers - */ -typedef struct -{ - __IO uint32_t HCCHAR; - __IO uint32_t HCSPLT; - __IO uint32_t HCINT; - __IO uint32_t HCINTMSK; - __IO uint32_t HCTSIZ; - __IO uint32_t HCDMA; - uint32_t Reserved[2]; -} -USB_OTG_HostChannelTypeDef; - - -/** - * @brief Peripheral_memory_map - */ -#define FLASH_BASE 0x08000000U /*!< FLASH(up to 1 MB) base address in the alias region */ -#define SRAM1_BASE 0x20000000U /*!< SRAM1(112 KB) base address in the alias region */ -#define SRAM2_BASE 0x2001C000U /*!< SRAM2(16 KB) base address in the alias region */ -#define PERIPH_BASE 0x40000000U /*!< Peripheral base address in the alias region */ -#define BKPSRAM_BASE 0x40024000U /*!< Backup SRAM(4 KB) base address in the alias region */ -#define FSMC_R_BASE 0xA0000000U /*!< FSMC registers base address */ -#define SRAM1_BB_BASE 0x22000000U /*!< SRAM1(112 KB) base address in the bit-band region */ -#define SRAM2_BB_BASE 0x22380000U /*!< SRAM2(16 KB) base address in the bit-band region */ -#define PERIPH_BB_BASE 0x42000000U /*!< Peripheral base address in the bit-band region */ -#define BKPSRAM_BB_BASE 0x42480000U /*!< Backup SRAM(4 KB) base address in the bit-band region */ -#define FLASH_END 0x080FFFFFU /*!< FLASH end address */ - -/* Legacy defines */ -#define SRAM_BASE SRAM1_BASE -#define SRAM_BB_BASE SRAM1_BB_BASE - - -/*!< Peripheral memory map */ -#define APB1PERIPH_BASE PERIPH_BASE -#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000U) -#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000U) -#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000U) - -/*!< APB1 peripherals */ -#define TIM2_BASE (APB1PERIPH_BASE + 0x0000U) -#define TIM3_BASE (APB1PERIPH_BASE + 0x0400U) -#define TIM4_BASE (APB1PERIPH_BASE + 0x0800U) -#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00U) -#define TIM6_BASE (APB1PERIPH_BASE + 0x1000U) -#define TIM7_BASE (APB1PERIPH_BASE + 0x1400U) -#define TIM12_BASE (APB1PERIPH_BASE + 0x1800U) -#define TIM13_BASE (APB1PERIPH_BASE + 0x1C00U) -#define TIM14_BASE (APB1PERIPH_BASE + 0x2000U) -#define RTC_BASE (APB1PERIPH_BASE + 0x2800U) -#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00U) -#define IWDG_BASE (APB1PERIPH_BASE + 0x3000U) -#define SPI2_BASE (APB1PERIPH_BASE + 0x3800U) -#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00U) -#define USART2_BASE (APB1PERIPH_BASE + 0x4400U) -#define USART3_BASE (APB1PERIPH_BASE + 0x4800U) -#define UART4_BASE (APB1PERIPH_BASE + 0x4C00U) -#define UART5_BASE (APB1PERIPH_BASE + 0x5000U) -#define I2C1_BASE (APB1PERIPH_BASE + 0x5400U) -#define I2C2_BASE (APB1PERIPH_BASE + 0x5800U) -#define I2C3_BASE (APB1PERIPH_BASE + 0x5C00U) -#define CAN1_BASE (APB1PERIPH_BASE + 0x6400U) -#define CAN2_BASE (APB1PERIPH_BASE + 0x6800U) -#define PWR_BASE (APB1PERIPH_BASE + 0x7000U) -#define DAC_BASE (APB1PERIPH_BASE + 0x7400U) - -/*!< APB2 peripherals */ -#define TIM1_BASE (APB2PERIPH_BASE + 0x0000U) -#define TIM8_BASE (APB2PERIPH_BASE + 0x0400U) -#define USART1_BASE (APB2PERIPH_BASE + 0x1000U) -#define USART6_BASE (APB2PERIPH_BASE + 0x1400U) -#define ADC1_BASE (APB2PERIPH_BASE + 0x2000U) -#define ADC2_BASE (APB2PERIPH_BASE + 0x2100U) -#define ADC3_BASE (APB2PERIPH_BASE + 0x2200U) -#define ADC_BASE (APB2PERIPH_BASE + 0x2300U) -#define SDIO_BASE (APB2PERIPH_BASE + 0x2C00U) -#define SPI1_BASE (APB2PERIPH_BASE + 0x3000U) -#define SYSCFG_BASE (APB2PERIPH_BASE + 0x3800U) -#define EXTI_BASE (APB2PERIPH_BASE + 0x3C00U) -#define TIM9_BASE (APB2PERIPH_BASE + 0x4000U) -#define TIM10_BASE (APB2PERIPH_BASE + 0x4400U) -#define TIM11_BASE (APB2PERIPH_BASE + 0x4800U) - -/*!< AHB1 peripherals */ -#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000U) -#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400U) -#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800U) -#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00U) -#define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000U) -#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400U) -#define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800U) -#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00U) -#define GPIOI_BASE (AHB1PERIPH_BASE + 0x2000U) -#define CRC_BASE (AHB1PERIPH_BASE + 0x3000U) -#define RCC_BASE (AHB1PERIPH_BASE + 0x3800U) -#define FLASH_R_BASE (AHB1PERIPH_BASE + 0x3C00U) -#define DMA1_BASE (AHB1PERIPH_BASE + 0x6000U) -#define DMA1_Stream0_BASE (DMA1_BASE + 0x010U) -#define DMA1_Stream1_BASE (DMA1_BASE + 0x028U) -#define DMA1_Stream2_BASE (DMA1_BASE + 0x040U) -#define DMA1_Stream3_BASE (DMA1_BASE + 0x058U) -#define DMA1_Stream4_BASE (DMA1_BASE + 0x070U) -#define DMA1_Stream5_BASE (DMA1_BASE + 0x088U) -#define DMA1_Stream6_BASE (DMA1_BASE + 0x0A0U) -#define DMA1_Stream7_BASE (DMA1_BASE + 0x0B8U) -#define DMA2_BASE (AHB1PERIPH_BASE + 0x6400U) -#define DMA2_Stream0_BASE (DMA2_BASE + 0x010U) -#define DMA2_Stream1_BASE (DMA2_BASE + 0x028U) -#define DMA2_Stream2_BASE (DMA2_BASE + 0x040U) -#define DMA2_Stream3_BASE (DMA2_BASE + 0x058U) -#define DMA2_Stream4_BASE (DMA2_BASE + 0x070U) -#define DMA2_Stream5_BASE (DMA2_BASE + 0x088U) -#define DMA2_Stream6_BASE (DMA2_BASE + 0x0A0U) -#define DMA2_Stream7_BASE (DMA2_BASE + 0x0B8U) - -/*!< AHB2 peripherals */ -#define RNG_BASE (AHB2PERIPH_BASE + 0x60800U) - -/*!< FSMC Bankx registers base address */ -#define FSMC_Bank1_R_BASE (FSMC_R_BASE + 0x0000U) -#define FSMC_Bank1E_R_BASE (FSMC_R_BASE + 0x0104U) -#define FSMC_Bank2_3_R_BASE (FSMC_R_BASE + 0x0060U) -#define FSMC_Bank4_R_BASE (FSMC_R_BASE + 0x00A0U) - -/* Debug MCU registers base address */ -#define DBGMCU_BASE 0xE0042000U - -/*!< USB registers base address */ -#define USB_OTG_HS_PERIPH_BASE 0x40040000U -#define USB_OTG_FS_PERIPH_BASE 0x50000000U - -#define USB_OTG_GLOBAL_BASE 0x000U -#define USB_OTG_DEVICE_BASE 0x800U -#define USB_OTG_IN_ENDPOINT_BASE 0x900U -#define USB_OTG_OUT_ENDPOINT_BASE 0xB00U -#define USB_OTG_EP_REG_SIZE 0x20U -#define USB_OTG_HOST_BASE 0x400U -#define USB_OTG_HOST_PORT_BASE 0x440U -#define USB_OTG_HOST_CHANNEL_BASE 0x500U -#define USB_OTG_HOST_CHANNEL_SIZE 0x20U -#define USB_OTG_PCGCCTL_BASE 0xE00U -#define USB_OTG_FIFO_BASE 0x1000U -#define USB_OTG_FIFO_SIZE 0x1000U - -/** - * @} - */ - -/** @addtogroup Peripheral_declaration - * @{ - */ -#define TIM2 ((TIM_TypeDef *) TIM2_BASE) -#define TIM3 ((TIM_TypeDef *) TIM3_BASE) -#define TIM4 ((TIM_TypeDef *) TIM4_BASE) -#define TIM5 ((TIM_TypeDef *) TIM5_BASE) -#define TIM6 ((TIM_TypeDef *) TIM6_BASE) -#define TIM7 ((TIM_TypeDef *) TIM7_BASE) -#define TIM12 ((TIM_TypeDef *) TIM12_BASE) -#define TIM13 ((TIM_TypeDef *) TIM13_BASE) -#define TIM14 ((TIM_TypeDef *) TIM14_BASE) -#define RTC ((RTC_TypeDef *) RTC_BASE) -#define WWDG ((WWDG_TypeDef *) WWDG_BASE) -#define IWDG ((IWDG_TypeDef *) IWDG_BASE) -#define SPI2 ((SPI_TypeDef *) SPI2_BASE) -#define SPI3 ((SPI_TypeDef *) SPI3_BASE) -#define USART2 ((USART_TypeDef *) USART2_BASE) -#define USART3 ((USART_TypeDef *) USART3_BASE) -#define UART4 ((USART_TypeDef *) UART4_BASE) -#define UART5 ((USART_TypeDef *) UART5_BASE) -#define I2C1 ((I2C_TypeDef *) I2C1_BASE) -#define I2C2 ((I2C_TypeDef *) I2C2_BASE) -#define I2C3 ((I2C_TypeDef *) I2C3_BASE) -#define CAN1 ((CAN_TypeDef *) CAN1_BASE) -#define CAN2 ((CAN_TypeDef *) CAN2_BASE) -#define PWR ((PWR_TypeDef *) PWR_BASE) -#define DAC ((DAC_TypeDef *) DAC_BASE) -#define TIM1 ((TIM_TypeDef *) TIM1_BASE) -#define TIM8 ((TIM_TypeDef *) TIM8_BASE) -#define USART1 ((USART_TypeDef *) USART1_BASE) -#define USART6 ((USART_TypeDef *) USART6_BASE) -#define ADC ((ADC_Common_TypeDef *) ADC_BASE) -#define ADC1 ((ADC_TypeDef *) ADC1_BASE) -#define ADC2 ((ADC_TypeDef *) ADC2_BASE) -#define ADC3 ((ADC_TypeDef *) ADC3_BASE) -#define SDIO ((SDIO_TypeDef *) SDIO_BASE) -#define SPI1 ((SPI_TypeDef *) SPI1_BASE) -#define SYSCFG ((SYSCFG_TypeDef *) SYSCFG_BASE) -#define EXTI ((EXTI_TypeDef *) EXTI_BASE) -#define TIM9 ((TIM_TypeDef *) TIM9_BASE) -#define TIM10 ((TIM_TypeDef *) TIM10_BASE) -#define TIM11 ((TIM_TypeDef *) TIM11_BASE) -#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) -#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) -#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) -#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) -#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) -#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) -#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) -#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE) -#define GPIOI ((GPIO_TypeDef *) GPIOI_BASE) -#define CRC ((CRC_TypeDef *) CRC_BASE) -#define RCC ((RCC_TypeDef *) RCC_BASE) -#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) -#define DMA1 ((DMA_TypeDef *) DMA1_BASE) -#define DMA1_Stream0 ((DMA_Stream_TypeDef *) DMA1_Stream0_BASE) -#define DMA1_Stream1 ((DMA_Stream_TypeDef *) DMA1_Stream1_BASE) -#define DMA1_Stream2 ((DMA_Stream_TypeDef *) DMA1_Stream2_BASE) -#define DMA1_Stream3 ((DMA_Stream_TypeDef *) DMA1_Stream3_BASE) -#define DMA1_Stream4 ((DMA_Stream_TypeDef *) DMA1_Stream4_BASE) -#define DMA1_Stream5 ((DMA_Stream_TypeDef *) DMA1_Stream5_BASE) -#define DMA1_Stream6 ((DMA_Stream_TypeDef *) DMA1_Stream6_BASE) -#define DMA1_Stream7 ((DMA_Stream_TypeDef *) DMA1_Stream7_BASE) -#define DMA2 ((DMA_TypeDef *) DMA2_BASE) -#define DMA2_Stream0 ((DMA_Stream_TypeDef *) DMA2_Stream0_BASE) -#define DMA2_Stream1 ((DMA_Stream_TypeDef *) DMA2_Stream1_BASE) -#define DMA2_Stream2 ((DMA_Stream_TypeDef *) DMA2_Stream2_BASE) -#define DMA2_Stream3 ((DMA_Stream_TypeDef *) DMA2_Stream3_BASE) -#define DMA2_Stream4 ((DMA_Stream_TypeDef *) DMA2_Stream4_BASE) -#define DMA2_Stream5 ((DMA_Stream_TypeDef *) DMA2_Stream5_BASE) -#define DMA2_Stream6 ((DMA_Stream_TypeDef *) DMA2_Stream6_BASE) -#define DMA2_Stream7 ((DMA_Stream_TypeDef *) DMA2_Stream7_BASE) -#define RNG ((RNG_TypeDef *) RNG_BASE) -#define FSMC_Bank1 ((FSMC_Bank1_TypeDef *) FSMC_Bank1_R_BASE) -#define FSMC_Bank1E ((FSMC_Bank1E_TypeDef *) FSMC_Bank1E_R_BASE) -#define FSMC_Bank2_3 ((FSMC_Bank2_3_TypeDef *) FSMC_Bank2_3_R_BASE) -#define FSMC_Bank4 ((FSMC_Bank4_TypeDef *) FSMC_Bank4_R_BASE) - -#define DBGMCU ((DBGMCU_TypeDef *) DBGMCU_BASE) - -#define USB_OTG_FS ((USB_OTG_GlobalTypeDef *) USB_OTG_FS_PERIPH_BASE) -#define USB_OTG_HS ((USB_OTG_GlobalTypeDef *) USB_OTG_HS_PERIPH_BASE) - -/** - * @} - */ - -/** @addtogroup Exported_constants - * @{ - */ - - /** @addtogroup Peripheral_Registers_Bits_Definition - * @{ - */ - -/******************************************************************************/ -/* Peripheral Registers_Bits_Definition */ -/******************************************************************************/ - -/******************************************************************************/ -/* */ -/* Analog to Digital Converter */ -/* */ -/******************************************************************************/ -/******************** Bit definition for ADC_SR register ********************/ -#define ADC_SR_AWD 0x00000001U /*!
© COPYRIGHT(c) 2016 STMicroelectronics
- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32f2xx - * @{ - */ - -#ifndef __STM32F2xx_H -#define __STM32F2xx_H - -#ifdef __cplusplus - extern "C" { -#endif /* __cplusplus */ - -/** @addtogroup Library_configuration_section - * @{ - */ - -/** - * @brief STM32 Family - */ -#if !defined (STM32F2) -#define STM32F2 -#endif /* STM32F2 */ - -/* Uncomment the line below according to the target STM32 device used in your - application - */ -#if !defined (STM32F205xx) && !defined (STM32F215xx) && !defined (STM32F207xx) && !defined (STM32F217xx) - - /* #define STM32F205xx */ /*!< STM32F205RG, STM32F205VG, STM32F205ZG, STM32F205RF, STM32F205VF, STM32F205ZF, - STM32F205RE, STM32F205VE, STM32F205ZE, STM32F205RC, STM32F205VC, STM32F205ZC, - STM32F205RB and STM32F205VB Devices */ - /* #define STM32F215xx */ /*!< STM32F215RG, STM32F215VG, STM32F215ZG, STM32F215RE, STM32F215VE and STM32F215ZE Devices */ - /* #define STM32F207xx */ /*!< STM32F207VG, STM32F207ZG, STM32F207IG, STM32F207VF, STM32F207ZF, STM32F207IF, - STM32F207VE, STM32F207ZE, STM32F207IE, STM32F207VC, STM32F207ZC and STM32F207IC Devices */ - /* #define STM32F217xx */ /*!< STM32F217VG, STM32F217ZG, STM32F217IG, STM32F217VE, STM32F217ZE and STM32F217IE Devices */ - -#endif - -/* Tip: To avoid modifying this file each time you need to switch between these - devices, you can define the device in your toolchain compiler preprocessor. - */ -#if !defined (USE_HAL_DRIVER) -/** - * @brief Comment the line below if you will not use the peripherals drivers. - In this case, these drivers will not be included and the application code will - be based on direct access to peripherals registers - */ - /*#define USE_HAL_DRIVER */ -#endif /* USE_HAL_DRIVER */ - -/** - * @brief CMSIS Device version number V2.1.2 - */ -#define __STM32F2xx_CMSIS_VERSION_MAIN (0x02U) /*!< [31:24] main version */ -#define __STM32F2xx_CMSIS_VERSION_SUB1 (0x01U) /*!< [23:16] sub1 version */ -#define __STM32F2xx_CMSIS_VERSION_SUB2 (0x02U) /*!< [15:8] sub2 version */ -#define __STM32F2xx_CMSIS_VERSION_RC (0x00U) /*!< [7:0] release candidate */ -#define __STM32F2xx_CMSIS_VERSION ((__STM32F2xx_CMSIS_VERSION_MAIN << 24)\ - |(__STM32F2xx_CMSIS_VERSION_SUB1 << 16)\ - |(__STM32F2xx_CMSIS_VERSION_SUB2 << 8 )\ - |(__STM32F2xx_CMSIS_VERSION)) - -/** - * @} - */ - -/** @addtogroup Device_Included - * @{ - */ - -#if defined(STM32F205xx) - #include "stm32f205xx.h" -#elif defined(STM32F215xx) - #include "stm32f215xx.h" -#elif defined(STM32F207xx) - #include "stm32f207xx.h" -#elif defined(STM32F217xx) - #include "stm32f217xx.h" -#else - #error "Please select first the target STM32F2xx device used in your application (in stm32f2xx.h file)" -#endif - -/** - * @} - */ - -/** @addtogroup Exported_types - * @{ - */ -typedef enum -{ - RESET = 0, - SET = !RESET -} FlagStatus, ITStatus; - -typedef enum -{ - DISABLE = 0, - ENABLE = !DISABLE -} FunctionalState; -#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) - -typedef enum -{ - ERROR = 0, - SUCCESS = !ERROR -} ErrorStatus; - -/** - * @} - */ - - -/** @addtogroup Exported_macro - * @{ - */ -#define SET_BIT(REG, BIT) ((REG) |= (BIT)) - -#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) - -#define READ_BIT(REG, BIT) ((REG) & (BIT)) - -#define CLEAR_REG(REG) ((REG) = (0x0)) - -#define WRITE_REG(REG, VAL) ((REG) = (VAL)) - -#define READ_REG(REG) ((REG)) - -#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) - -#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) - - -/** - * @} - */ - -#if defined (USE_HAL_DRIVER) - #include "stm32f2xx_hal.h" -#endif /* USE_HAL_DRIVER */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __STM32F2xx_H */ - -/** - * @} - */ - -/** - * @} - */ - - - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/stm32f2xx_hal_def.h b/panda/board/inc/stm32f2xx_hal_def.h deleted file mode 100644 index dfef07939c..0000000000 --- a/panda/board/inc/stm32f2xx_hal_def.h +++ /dev/null @@ -1,181 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f2xx_hal_def.h - * @author MCD Application Team - * @version V1.1.3 - * @date 29-June-2016 - * @brief This file contains HAL common defines, enumeration, macros and - * structures definitions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F2xx_HAL_DEF -#define __STM32F2xx_HAL_DEF - -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f2xx.h" -//#include "Legacy/stm32_hal_legacy.h" -//#include - -/* Exported types ------------------------------------------------------------*/ - -/** - * @brief HAL Status structures definition - */ -typedef enum -{ - HAL_OK = 0x00U, - HAL_ERROR = 0x01U, - HAL_BUSY = 0x02U, - HAL_TIMEOUT = 0x03U -} HAL_StatusTypeDef; - -/** - * @brief HAL Lock structures definition - */ -typedef enum -{ - HAL_UNLOCKED = 0x00U, - HAL_LOCKED = 0x01U -} HAL_LockTypeDef; - -/* Exported macro ------------------------------------------------------------*/ -#define HAL_MAX_DELAY 0xFFFFFFFFU - -#define HAL_IS_BIT_SET(REG, BIT) (((REG) & (BIT)) != RESET) -#define HAL_IS_BIT_CLR(REG, BIT) (((REG) & (BIT)) == RESET) - -#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD_, __DMA_HANDLE_) \ - do{ \ - (__HANDLE__)->__PPP_DMA_FIELD_ = &(__DMA_HANDLE_); \ - (__DMA_HANDLE_).Parent = (__HANDLE__); \ - } while(0) - -#define UNUSED(x) ((void)(x)) - -/** @brief Reset the Handle's State field. - * @param __HANDLE__: specifies the Peripheral Handle. - * @note This macro can be used for the following purpose: - * - When the Handle is declared as local variable; before passing it as parameter - * to HAL_PPP_Init() for the first time, it is mandatory to use this macro - * to set to 0 the Handle's "State" field. - * Otherwise, "State" field may have any random value and the first time the function - * HAL_PPP_Init() is called, the low level hardware initialization will be missed - * (i.e. HAL_PPP_MspInit() will not be executed). - * - When there is a need to reconfigure the low level hardware: instead of calling - * HAL_PPP_DeInit() then HAL_PPP_Init(), user can make a call to this macro then HAL_PPP_Init(). - * In this later function, when the Handle's "State" field is set to 0, it will execute the function - * HAL_PPP_MspInit() which will reconfigure the low level hardware. - * @retval None - */ -#define __HAL_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = 0U) - -#if (USE_RTOS == 1) - /* Reserved for future use */ - #error " USE_RTOS should be 0 in the current HAL release " -#else - #define __HAL_LOCK(__HANDLE__) \ - do{ \ - if((__HANDLE__)->Lock == HAL_LOCKED) \ - { \ - return HAL_BUSY; \ - } \ - else \ - { \ - (__HANDLE__)->Lock = HAL_LOCKED; \ - } \ - }while (0) - - #define __HAL_UNLOCK(__HANDLE__) \ - do{ \ - (__HANDLE__)->Lock = HAL_UNLOCKED; \ - }while (0) -#endif /* USE_RTOS */ - -#if defined ( __GNUC__ ) - #ifndef __weak - #define __weak __attribute__((weak)) - #endif /* __weak */ - #ifndef __packed - #define __packed __attribute__((__packed__)) - #endif /* __packed */ -#endif /* __GNUC__ */ - - -/* Macro to get variable aligned on 4-bytes, for __ICCARM__ the directive "#pragma data_alignment=4" must be used instead */ -#if defined (__GNUC__) /* GNU Compiler */ - #ifndef __ALIGN_END - #define __ALIGN_END __attribute__ ((aligned (4))) - #endif /* __ALIGN_END */ - #ifndef __ALIGN_BEGIN - #define __ALIGN_BEGIN - #endif /* __ALIGN_BEGIN */ -#else - #ifndef __ALIGN_END - #define __ALIGN_END - #endif /* __ALIGN_END */ - #ifndef __ALIGN_BEGIN - #if defined (__CC_ARM) /* ARM Compiler */ - #define __ALIGN_BEGIN __align(4) - #elif defined (__ICCARM__) /* IAR Compiler */ - #define __ALIGN_BEGIN - #endif /* __CC_ARM */ - #endif /* __ALIGN_BEGIN */ -#endif /* __GNUC__ */ - -/** - * @brief __NOINLINE definition - */ -#if defined ( __CC_ARM ) || defined ( __GNUC__ ) -/* ARM & GNUCompiler - ---------------- -*/ -#define __NOINLINE __attribute__ ( (noinline) ) - -#elif defined ( __ICCARM__ ) -/* ICCARM Compiler - --------------- -*/ -#define __NOINLINE _Pragma("optimize = no_inline") - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ___STM32F2xx_HAL_DEF */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/stm32f2xx_hal_gpio_ex.h b/panda/board/inc/stm32f2xx_hal_gpio_ex.h deleted file mode 100644 index 7cef9a648b..0000000000 --- a/panda/board/inc/stm32f2xx_hal_gpio_ex.h +++ /dev/null @@ -1,299 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f2xx_hal_gpio_ex.h - * @author MCD Application Team - * @version V1.1.3 - * @date 29-June-2016 - * @brief Header file of GPIO HAL Extension module. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F2xx_HAL_GPIO_EX_H -#define __STM32F2xx_HAL_GPIO_EX_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f2xx_hal_def.h" - -/** @addtogroup STM32F2xx_HAL_Driver - * @{ - */ - -/** @defgroup GPIOEx GPIOEx - * @{ - */ - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ - -/** @defgroup GPIOEx_Exported_Constants GPIO Exported Constants - * @{ - */ - -/** @defgroup GPIO_Alternate_function_selection GPIO Alternate function selection - * @{ - */ - -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0xAU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0xAU) /* OTG_HS Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#if defined(STM32F207xx) || defined(STM32F217xx) -#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */ -#endif /* STM32F207xx || STM32F217xx */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FSMC ((uint8_t)0xCU) /* FSMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0xCU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0xCU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 13 selection - */ -#if defined(STM32F207xx) || defined(STM32F217xx) -#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */ -#endif /* STM32F207xx || STM32F217xx */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ - -/** - * @} - */ - -/** - * @} - */ - -/* Exported macro ------------------------------------------------------------*/ -/** @defgroup GPIOEx_Exported_Macros GPIO Exported Macros - * @{ - */ -/** - * @} - */ - -/* Exported functions --------------------------------------------------------*/ -/** @defgroup GPIOEx_Exported_Functions GPIO Exported Functions - * @{ - */ -/** - * @} - */ - -/* Private types -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Private constants ---------------------------------------------------------*/ -/** @defgroup GPIOEx_Private_Constants GPIO Private Constants - * @{ - */ -/** - * @} - */ - -/* Private macros ------------------------------------------------------------*/ -/** @defgroup GPIOEx_Private_Macros GPIO Private Macros - * @{ - */ -/** @defgroup GPIOEx_Get_Port_Index GPIO Get Port Index - * @{ - */ -#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\ - ((__GPIOx__) == (GPIOB))? 1U :\ - ((__GPIOx__) == (GPIOC))? 2U :\ - ((__GPIOx__) == (GPIOD))? 3U :\ - ((__GPIOx__) == (GPIOE))? 4U :\ - ((__GPIOx__) == (GPIOF))? 5U :\ - ((__GPIOx__) == (GPIOG))? 6U :\ - ((__GPIOx__) == (GPIOH))? 7U :\ - ((__GPIOx__) == (GPIOI))? 8U : 9U) -/** - * @} - */ - -/** @defgroup GPIOEx_IS_Alternat_function_selection GPIO Check Alternate Function - * @{ - */ -#if defined(STM32F207xx) || defined(STM32F217xx) - -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF11_ETH) || ((AF) == GPIO_AF12_OTG_HS_FS) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF13_DCMI) || \ - ((AF) == GPIO_AF12_FSMC) || ((AF) == GPIO_AF15_EVENTOUT)) -#else /* STM32F207xx || STM32F217xx */ -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF12_OTG_HS_FS) || ((AF) == GPIO_AF12_SDIO) || \ - ((AF) == GPIO_AF12_FSMC) || ((AF) == GPIO_AF15_EVENTOUT)) -#endif /* STM32F207xx || STM32F217xx */ - -/** - * @} - */ - -/** - * @} - */ - -/* Private functions ---------------------------------------------------------*/ -/** @defgroup GPIOEx_Private_Functions GPIO Private Functions - * @{ - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32F2xx_HAL_GPIO_EX_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/stm32f413xx.h b/panda/board/inc/stm32f413xx.h deleted file mode 100644 index 0962a8def1..0000000000 --- a/panda/board/inc/stm32f413xx.h +++ /dev/null @@ -1,14995 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f413xx.h - * @author MCD Application Team - * @version V2.6.0 - * @date 04-November-2016 - * @brief CMSIS STM32F413xx Device Peripheral Access Layer Header File. - * - * This file contains: - * - Data structures and the address mapping for all peripherals - * - peripherals registers declarations and bits definition - * - Macros to access peripheral’s registers hardware - * - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS_Device - * @{ - */ - -/** @addtogroup stm32f413xx - * @{ - */ - -#ifndef __STM32F413xx_H -#define __STM32F413xx_H - -#ifdef __cplusplus - extern "C" { -#endif /* __cplusplus */ - -/** @addtogroup Configuration_section_for_CMSIS - * @{ - */ - -/** - * @brief Configuration of the Cortex-M4 Processor and Core Peripherals - */ -#define __CM4_REV 0x0001U /*!< Core revision r0p1 */ -#define __MPU_PRESENT 1U /*!< STM32F4XX provides an MPU */ -#define __NVIC_PRIO_BITS 4U /*!< STM32F4XX uses 4 Bits for the Priority Levels */ -#define __Vendor_SysTickConfig 0U /*!< Set to 1 if different SysTick Config is used */ -#define __FPU_PRESENT 1U /*!< FPU present */ - -/** - * @} - */ - -/** @addtogroup Peripheral_interrupt_number_definition - * @{ - */ - -/** - * @brief STM32F4XX Interrupt Number Definition, according to the selected device - * in @ref Library_configuration_section - */ -typedef enum -{ -/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/ - NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ - MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */ - BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */ - UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */ - SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */ - DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */ - PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */ - SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */ -/****** STM32 specific Interrupt Numbers **********************************************************************/ - WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ - PVD_IRQn = 1, /*!< PVD through EXTI Line detection Interrupt */ - TAMP_STAMP_IRQn = 2, /*!< Tamper and TimeStamp interrupts through the EXTI line */ - RTC_WKUP_IRQn = 3, /*!< RTC Wakeup interrupt through the EXTI line */ - FLASH_IRQn = 4, /*!< FLASH global Interrupt */ - RCC_IRQn = 5, /*!< RCC global Interrupt */ - EXTI0_IRQn = 6, /*!< EXTI Line0 Interrupt */ - EXTI1_IRQn = 7, /*!< EXTI Line1 Interrupt */ - EXTI2_IRQn = 8, /*!< EXTI Line2 Interrupt */ - EXTI3_IRQn = 9, /*!< EXTI Line3 Interrupt */ - EXTI4_IRQn = 10, /*!< EXTI Line4 Interrupt */ - DMA1_Stream0_IRQn = 11, /*!< DMA1 Stream 0 global Interrupt */ - DMA1_Stream1_IRQn = 12, /*!< DMA1 Stream 1 global Interrupt */ - DMA1_Stream2_IRQn = 13, /*!< DMA1 Stream 2 global Interrupt */ - DMA1_Stream3_IRQn = 14, /*!< DMA1 Stream 3 global Interrupt */ - DMA1_Stream4_IRQn = 15, /*!< DMA1 Stream 4 global Interrupt */ - DMA1_Stream5_IRQn = 16, /*!< DMA1 Stream 5 global Interrupt */ - DMA1_Stream6_IRQn = 17, /*!< DMA1 Stream 6 global Interrupt */ - ADC_IRQn = 18, /*!< ADC1, ADC2 and ADC3 global Interrupts */ - CAN1_TX_IRQn = 19, /*!< CAN1 TX Interrupt */ - CAN1_RX0_IRQn = 20, /*!< CAN1 RX0 Interrupt */ - CAN1_RX1_IRQn = 21, /*!< CAN1 RX1 Interrupt */ - CAN1_SCE_IRQn = 22, /*!< CAN1 SCE Interrupt */ - EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */ - TIM1_BRK_TIM9_IRQn = 24, /*!< TIM1 Break interrupt and TIM9 global interrupt */ - TIM1_UP_TIM10_IRQn = 25, /*!< TIM1 Update Interrupt and TIM10 global interrupt */ - TIM1_TRG_COM_TIM11_IRQn = 26, /*!< TIM1 Trigger and Commutation Interrupt and TIM11 global interrupt */ - TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */ - TIM2_IRQn = 28, /*!< TIM2 global Interrupt */ - TIM3_IRQn = 29, /*!< TIM3 global Interrupt */ - TIM4_IRQn = 30, /*!< TIM4 global Interrupt */ - I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */ - I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */ - I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */ - I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */ - SPI1_IRQn = 35, /*!< SPI1 global Interrupt */ - SPI2_IRQn = 36, /*!< SPI2 global Interrupt */ - USART1_IRQn = 37, /*!< USART1 global Interrupt */ - USART2_IRQn = 38, /*!< USART2 global Interrupt */ - USART3_IRQn = 39, /*!< USART3 global Interrupt */ - EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */ - RTC_Alarm_IRQn = 41, /*!< RTC Alarm (A and B) through EXTI Line Interrupt */ - OTG_FS_WKUP_IRQn = 42, /*!< USB OTG FS Wakeup through EXTI line interrupt */ - TIM8_BRK_TIM12_IRQn = 43, /*!< TIM8 Break Interrupt and TIM12 global interrupt */ - TIM8_UP_TIM13_IRQn = 44, /*!< TIM8 Update Interrupt and TIM13 global interrupt */ - TIM8_TRG_COM_TIM14_IRQn = 45, /*!< TIM8 Trigger and Commutation Interrupt and TIM14 global interrupt */ - TIM8_CC_IRQn = 46, /*!< TIM8 Capture Compare global interrupt */ - DMA1_Stream7_IRQn = 47, /*!< DMA1 Stream7 Interrupt */ - FSMC_IRQn = 48, /*!< FSMC global Interrupt */ - SDIO_IRQn = 49, /*!< SDIO global Interrupt */ - TIM5_IRQn = 50, /*!< TIM5 global Interrupt */ - SPI3_IRQn = 51, /*!< SPI3 global Interrupt */ - UART4_IRQn = 52, /*!< UART4 global Interrupt */ - UART5_IRQn = 53, /*!< UART5 global Interrupt */ - TIM6_DAC_IRQn = 54, /*!< TIM6 global and DAC1&2 underrun error interrupts */ - TIM7_IRQn = 55, /*!< TIM7 global interrupt */ - DMA2_Stream0_IRQn = 56, /*!< DMA2 Stream 0 global Interrupt */ - DMA2_Stream1_IRQn = 57, /*!< DMA2 Stream 1 global Interrupt */ - DMA2_Stream2_IRQn = 58, /*!< DMA2 Stream 2 global Interrupt */ - DMA2_Stream3_IRQn = 59, /*!< DMA2 Stream 3 global Interrupt */ - DMA2_Stream4_IRQn = 60, /*!< DMA2 Stream 4 global Interrupt */ - DFSDM1_FLT0_IRQn = 61, /*!< DFSDM1 Filter 0 global Interrupt */ - DFSDM1_FLT1_IRQn = 62, /*!< DFSDM1 Filter 1 global Interrupt */ - CAN2_TX_IRQn = 63, /*!< CAN2 TX Interrupt */ - CAN2_RX0_IRQn = 64, /*!< CAN2 RX0 Interrupt */ - CAN2_RX1_IRQn = 65, /*!< CAN2 RX1 Interrupt */ - CAN2_SCE_IRQn = 66, /*!< CAN2 SCE Interrupt */ - OTG_FS_IRQn = 67, /*!< USB OTG FS global Interrupt */ - DMA2_Stream5_IRQn = 68, /*!< DMA2 Stream 5 global interrupt */ - DMA2_Stream6_IRQn = 69, /*!< DMA2 Stream 6 global interrupt */ - DMA2_Stream7_IRQn = 70, /*!< DMA2 Stream 7 global interrupt */ - USART6_IRQn = 71, /*!< USART6 global interrupt */ - I2C3_EV_IRQn = 72, /*!< I2C3 event interrupt */ - I2C3_ER_IRQn = 73, /*!< I2C3 error interrupt */ - CAN3_TX_IRQn = 74, /*!< CAN3 TX Interrupt */ - CAN3_RX0_IRQn = 75, /*!< CAN3 RX0 Interrupt */ - CAN3_RX1_IRQn = 76, /*!< CAN3 RX1 Interrupt */ - CAN3_SCE_IRQn = 77, /*!< CAN3 SCE Interrupt */ - RNG_IRQn = 80, /*!< RNG global Interrupt */ - FPU_IRQn = 81, /*!< FPU global interrupt */ - UART7_IRQn = 82, /*!< UART7 global interrupt */ - UART8_IRQn = 83, /*!< UART8 global interrupt */ - SPI4_IRQn = 84, /*!< SPI4 global Interrupt */ - SPI5_IRQn = 85, /*!< SPI5 global Interrupt */ - SAI1_IRQn = 87, /*!< SAI1 global Interrupt */ - UART9_IRQn = 88, /*!< UART9 global Interrupt */ - UART10_IRQn = 89, /*!< UART10 global Interrupt */ - QUADSPI_IRQn = 92, /*!< QuadSPI global Interrupt */ - FMPI2C1_EV_IRQn = 95, /*!< FMPI2C1 Event Interrupt */ - FMPI2C1_ER_IRQn = 96, /*!< FMPI2C1 Error Interrupt */ - LPTIM1_IRQn = 97, /*!< LP TIM1 interrupt */ - DFSDM2_FLT0_IRQn = 98, /*!< DFSDM2 Filter 0 global Interrupt */ - DFSDM2_FLT1_IRQn = 99, /*!< DFSDM2 Filter 1 global Interrupt */ - DFSDM2_FLT2_IRQn = 100, /*!< DFSDM2 Filter 2 global Interrupt */ - DFSDM2_FLT3_IRQn = 101 /*!< DFSDM2 Filter 3 global Interrupt */ -} IRQn_Type; - -/** - * @} - */ - -#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */ -#include "system_stm32f4xx.h" -#include - -/** @addtogroup Peripheral_registers_structures - * @{ - */ - -/** - * @brief Analog to Digital Converter - */ - -typedef struct -{ - __IO uint32_t SR; /*!< ADC status register, Address offset: 0x00 */ - __IO uint32_t CR1; /*!< ADC control register 1, Address offset: 0x04 */ - __IO uint32_t CR2; /*!< ADC control register 2, Address offset: 0x08 */ - __IO uint32_t SMPR1; /*!< ADC sample time register 1, Address offset: 0x0C */ - __IO uint32_t SMPR2; /*!< ADC sample time register 2, Address offset: 0x10 */ - __IO uint32_t JOFR1; /*!< ADC injected channel data offset register 1, Address offset: 0x14 */ - __IO uint32_t JOFR2; /*!< ADC injected channel data offset register 2, Address offset: 0x18 */ - __IO uint32_t JOFR3; /*!< ADC injected channel data offset register 3, Address offset: 0x1C */ - __IO uint32_t JOFR4; /*!< ADC injected channel data offset register 4, Address offset: 0x20 */ - __IO uint32_t HTR; /*!< ADC watchdog higher threshold register, Address offset: 0x24 */ - __IO uint32_t LTR; /*!< ADC watchdog lower threshold register, Address offset: 0x28 */ - __IO uint32_t SQR1; /*!< ADC regular sequence register 1, Address offset: 0x2C */ - __IO uint32_t SQR2; /*!< ADC regular sequence register 2, Address offset: 0x30 */ - __IO uint32_t SQR3; /*!< ADC regular sequence register 3, Address offset: 0x34 */ - __IO uint32_t JSQR; /*!< ADC injected sequence register, Address offset: 0x38*/ - __IO uint32_t JDR1; /*!< ADC injected data register 1, Address offset: 0x3C */ - __IO uint32_t JDR2; /*!< ADC injected data register 2, Address offset: 0x40 */ - __IO uint32_t JDR3; /*!< ADC injected data register 3, Address offset: 0x44 */ - __IO uint32_t JDR4; /*!< ADC injected data register 4, Address offset: 0x48 */ - __IO uint32_t DR; /*!< ADC regular data register, Address offset: 0x4C */ -} ADC_TypeDef; - -typedef struct -{ - __IO uint32_t CSR; /*!< ADC Common status register, Address offset: ADC1 base address + 0x300 */ - __IO uint32_t CCR; /*!< ADC common control register, Address offset: ADC1 base address + 0x304 */ - __IO uint32_t CDR; /*!< ADC common regular data register for dual - AND triple modes, Address offset: ADC1 base address + 0x308 */ -} ADC_Common_TypeDef; - - -/** - * @brief Controller Area Network TxMailBox - */ - -typedef struct -{ - __IO uint32_t TIR; /*!< CAN TX mailbox identifier register */ - __IO uint32_t TDTR; /*!< CAN mailbox data length control and time stamp register */ - __IO uint32_t TDLR; /*!< CAN mailbox data low register */ - __IO uint32_t TDHR; /*!< CAN mailbox data high register */ -} CAN_TxMailBox_TypeDef; - -/** - * @brief Controller Area Network FIFOMailBox - */ - -typedef struct -{ - __IO uint32_t RIR; /*!< CAN receive FIFO mailbox identifier register */ - __IO uint32_t RDTR; /*!< CAN receive FIFO mailbox data length control and time stamp register */ - __IO uint32_t RDLR; /*!< CAN receive FIFO mailbox data low register */ - __IO uint32_t RDHR; /*!< CAN receive FIFO mailbox data high register */ -} CAN_FIFOMailBox_TypeDef; - -/** - * @brief Controller Area Network FilterRegister - */ - -typedef struct -{ - __IO uint32_t FR1; /*!< CAN Filter bank register 1 */ - __IO uint32_t FR2; /*!< CAN Filter bank register 1 */ -} CAN_FilterRegister_TypeDef; - -/** - * @brief Controller Area Network - */ - -typedef struct -{ - __IO uint32_t MCR; /*!< CAN master control register, Address offset: 0x00 */ - __IO uint32_t MSR; /*!< CAN master status register, Address offset: 0x04 */ - __IO uint32_t TSR; /*!< CAN transmit status register, Address offset: 0x08 */ - __IO uint32_t RF0R; /*!< CAN receive FIFO 0 register, Address offset: 0x0C */ - __IO uint32_t RF1R; /*!< CAN receive FIFO 1 register, Address offset: 0x10 */ - __IO uint32_t IER; /*!< CAN interrupt enable register, Address offset: 0x14 */ - __IO uint32_t ESR; /*!< CAN error status register, Address offset: 0x18 */ - __IO uint32_t BTR; /*!< CAN bit timing register, Address offset: 0x1C */ - uint32_t RESERVED0[88]; /*!< Reserved, 0x020 - 0x17F */ - CAN_TxMailBox_TypeDef sTxMailBox[3]; /*!< CAN Tx MailBox, Address offset: 0x180 - 0x1AC */ - CAN_FIFOMailBox_TypeDef sFIFOMailBox[2]; /*!< CAN FIFO MailBox, Address offset: 0x1B0 - 0x1CC */ - uint32_t RESERVED1[12]; /*!< Reserved, 0x1D0 - 0x1FF */ - __IO uint32_t FMR; /*!< CAN filter master register, Address offset: 0x200 */ - __IO uint32_t FM1R; /*!< CAN filter mode register, Address offset: 0x204 */ - uint32_t RESERVED2; /*!< Reserved, 0x208 */ - __IO uint32_t FS1R; /*!< CAN filter scale register, Address offset: 0x20C */ - uint32_t RESERVED3; /*!< Reserved, 0x210 */ - __IO uint32_t FFA1R; /*!< CAN filter FIFO assignment register, Address offset: 0x214 */ - uint32_t RESERVED4; /*!< Reserved, 0x218 */ - __IO uint32_t FA1R; /*!< CAN filter activation register, Address offset: 0x21C */ - uint32_t RESERVED5[8]; /*!< Reserved, 0x220-0x23F */ - CAN_FilterRegister_TypeDef sFilterRegister[28]; /*!< CAN Filter Register, Address offset: 0x240-0x31C */ -} CAN_TypeDef; - -/** - * @brief CRC calculation unit - */ - -typedef struct -{ - __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ - __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ - uint8_t RESERVED0; /*!< Reserved, 0x05 */ - uint16_t RESERVED1; /*!< Reserved, 0x06 */ - __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ -} CRC_TypeDef; - -/** - * @brief DFSDM module registers - */ -typedef struct -{ - __IO uint32_t FLTCR1; /*!< DFSDM control register1, Address offset: 0x100 */ - __IO uint32_t FLTCR2; /*!< DFSDM control register2, Address offset: 0x104 */ - __IO uint32_t FLTISR; /*!< DFSDM interrupt and status register, Address offset: 0x108 */ - __IO uint32_t FLTICR; /*!< DFSDM interrupt flag clear register, Address offset: 0x10C */ - __IO uint32_t FLTJCHGR; /*!< DFSDM injected channel group selection register, Address offset: 0x110 */ - __IO uint32_t FLTFCR; /*!< DFSDM filter control register, Address offset: 0x114 */ - __IO uint32_t FLTJDATAR; /*!< DFSDM data register for injected group, Address offset: 0x118 */ - __IO uint32_t FLTRDATAR; /*!< DFSDM data register for regular group, Address offset: 0x11C */ - __IO uint32_t FLTAWHTR; /*!< DFSDM analog watchdog high threshold register, Address offset: 0x120 */ - __IO uint32_t FLTAWLTR; /*!< DFSDM analog watchdog low threshold register, Address offset: 0x124 */ - __IO uint32_t FLTAWSR; /*!< DFSDM analog watchdog status register Address offset: 0x128 */ - __IO uint32_t FLTAWCFR; /*!< DFSDM analog watchdog clear flag register Address offset: 0x12C */ - __IO uint32_t FLTEXMAX; /*!< DFSDM extreme detector maximum register, Address offset: 0x130 */ - __IO uint32_t FLTEXMIN; /*!< DFSDM extreme detector minimum register Address offset: 0x134 */ - __IO uint32_t FLTCNVTIMR; /*!< DFSDM conversion timer, Address offset: 0x138 */ -} DFSDM_Filter_TypeDef; - -/** - * @brief DFSDM channel configuration registers - */ -typedef struct -{ - __IO uint32_t CHCFGR1; /*!< DFSDM channel configuration register1, Address offset: 0x00 */ - __IO uint32_t CHCFGR2; /*!< DFSDM channel configuration register2, Address offset: 0x04 */ - __IO uint32_t CHAWSCDR; /*!< DFSDM channel analog watchdog and - short circuit detector register, Address offset: 0x08 */ - __IO uint32_t CHWDATAR; /*!< DFSDM channel watchdog filter data register, Address offset: 0x0C */ - __IO uint32_t CHDATINR; /*!< DFSDM channel data input register, Address offset: 0x10 */ -} DFSDM_Channel_TypeDef; - -/** - * @brief Digital to Analog Converter - */ - -typedef struct -{ - __IO uint32_t CR; /*!< DAC control register, Address offset: 0x00 */ - __IO uint32_t SWTRIGR; /*!< DAC software trigger register, Address offset: 0x04 */ - __IO uint32_t DHR12R1; /*!< DAC channel1 12-bit right-aligned data holding register, Address offset: 0x08 */ - __IO uint32_t DHR12L1; /*!< DAC channel1 12-bit left aligned data holding register, Address offset: 0x0C */ - __IO uint32_t DHR8R1; /*!< DAC channel1 8-bit right aligned data holding register, Address offset: 0x10 */ - __IO uint32_t DHR12R2; /*!< DAC channel2 12-bit right aligned data holding register, Address offset: 0x14 */ - __IO uint32_t DHR12L2; /*!< DAC channel2 12-bit left aligned data holding register, Address offset: 0x18 */ - __IO uint32_t DHR8R2; /*!< DAC channel2 8-bit right-aligned data holding register, Address offset: 0x1C */ - __IO uint32_t DHR12RD; /*!< Dual DAC 12-bit right-aligned data holding register, Address offset: 0x20 */ - __IO uint32_t DHR12LD; /*!< DUAL DAC 12-bit left aligned data holding register, Address offset: 0x24 */ - __IO uint32_t DHR8RD; /*!< DUAL DAC 8-bit right aligned data holding register, Address offset: 0x28 */ - __IO uint32_t DOR1; /*!< DAC channel1 data output register, Address offset: 0x2C */ - __IO uint32_t DOR2; /*!< DAC channel2 data output register, Address offset: 0x30 */ - __IO uint32_t SR; /*!< DAC status register, Address offset: 0x34 */ -} DAC_TypeDef; - -/** - * @brief Debug MCU - */ - -typedef struct -{ - __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ - __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ - __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */ - __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */ -}DBGMCU_TypeDef; - - -/** - * @brief DMA Controller - */ - -typedef struct -{ - __IO uint32_t CR; /*!< DMA stream x configuration register */ - __IO uint32_t NDTR; /*!< DMA stream x number of data register */ - __IO uint32_t PAR; /*!< DMA stream x peripheral address register */ - __IO uint32_t M0AR; /*!< DMA stream x memory 0 address register */ - __IO uint32_t M1AR; /*!< DMA stream x memory 1 address register */ - __IO uint32_t FCR; /*!< DMA stream x FIFO control register */ -} DMA_Stream_TypeDef; - -typedef struct -{ - __IO uint32_t LISR; /*!< DMA low interrupt status register, Address offset: 0x00 */ - __IO uint32_t HISR; /*!< DMA high interrupt status register, Address offset: 0x04 */ - __IO uint32_t LIFCR; /*!< DMA low interrupt flag clear register, Address offset: 0x08 */ - __IO uint32_t HIFCR; /*!< DMA high interrupt flag clear register, Address offset: 0x0C */ -} DMA_TypeDef; - -/** - * @brief External Interrupt/Event Controller - */ - -typedef struct -{ - __IO uint32_t IMR; /*!< EXTI Interrupt mask register, Address offset: 0x00 */ - __IO uint32_t EMR; /*!< EXTI Event mask register, Address offset: 0x04 */ - __IO uint32_t RTSR; /*!< EXTI Rising trigger selection register, Address offset: 0x08 */ - __IO uint32_t FTSR; /*!< EXTI Falling trigger selection register, Address offset: 0x0C */ - __IO uint32_t SWIER; /*!< EXTI Software interrupt event register, Address offset: 0x10 */ - __IO uint32_t PR; /*!< EXTI Pending register, Address offset: 0x14 */ -} EXTI_TypeDef; - -/** - * @brief FLASH Registers - */ - -typedef struct -{ - __IO uint32_t ACR; /*!< FLASH access control register, Address offset: 0x00 */ - __IO uint32_t KEYR; /*!< FLASH key register, Address offset: 0x04 */ - __IO uint32_t OPTKEYR; /*!< FLASH option key register, Address offset: 0x08 */ - __IO uint32_t SR; /*!< FLASH status register, Address offset: 0x0C */ - __IO uint32_t CR; /*!< FLASH control register, Address offset: 0x10 */ - __IO uint32_t OPTCR; /*!< FLASH option control register , Address offset: 0x14 */ - __IO uint32_t OPTCR1; /*!< FLASH option control register 1, Address offset: 0x18 */ -} FLASH_TypeDef; - - - -/** - * @brief Flexible Static Memory Controller - */ - -typedef struct -{ - __IO uint32_t BTCR[8]; /*!< NOR/PSRAM chip-select control register(BCR) and chip-select timing register(BTR), Address offset: 0x00-1C */ -} FSMC_Bank1_TypeDef; - -/** - * @brief Flexible Static Memory Controller Bank1E - */ - -typedef struct -{ - __IO uint32_t BWTR[7]; /*!< NOR/PSRAM write timing registers, Address offset: 0x104-0x11C */ -} FSMC_Bank1E_TypeDef; -/** - * @brief General Purpose I/O - */ - -typedef struct -{ - __IO uint32_t MODER; /*!< GPIO port mode register, Address offset: 0x00 */ - __IO uint32_t OTYPER; /*!< GPIO port output type register, Address offset: 0x04 */ - __IO uint32_t OSPEEDR; /*!< GPIO port output speed register, Address offset: 0x08 */ - __IO uint32_t PUPDR; /*!< GPIO port pull-up/pull-down register, Address offset: 0x0C */ - __IO uint32_t IDR; /*!< GPIO port input data register, Address offset: 0x10 */ - __IO uint32_t ODR; /*!< GPIO port output data register, Address offset: 0x14 */ - __IO uint32_t BSRR; /*!< GPIO port bit set/reset register, Address offset: 0x18 */ - __IO uint32_t LCKR; /*!< GPIO port configuration lock register, Address offset: 0x1C */ - __IO uint32_t AFR[2]; /*!< GPIO alternate function registers, Address offset: 0x20-0x24 */ -} GPIO_TypeDef; - -/** - * @brief System configuration controller - */ - -typedef struct -{ - __IO uint32_t MEMRMP; /*!< SYSCFG memory remap register, Address offset: 0x00 */ - __IO uint32_t PMC; /*!< SYSCFG peripheral mode configuration register, Address offset: 0x04 */ - __IO uint32_t EXTICR[4]; /*!< SYSCFG external interrupt configuration registers, Address offset: 0x08-0x14 */ - uint32_t RESERVED; /*!< Reserved, 0x18 */ - __IO uint32_t CFGR2; /*!< SYSCFG Configuration register2, Address offset: 0x1C */ - __IO uint32_t CMPCR; /*!< SYSCFG Compensation cell control register, Address offset: 0x20 */ - uint32_t RESERVED1[2]; /*!< Reserved, 0x24-0x28 */ - __IO uint32_t CFGR; /*!< SYSCFG Configuration register, Address offset: 0x2C */ - __IO uint32_t MCHDLYCR; /*!< SYSCFG multi-channel delay register, Address offset: 0x30 */ -} SYSCFG_TypeDef; - -/** - * @brief Inter-integrated Circuit Interface - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< I2C Control register 1, Address offset: 0x00 */ - __IO uint32_t CR2; /*!< I2C Control register 2, Address offset: 0x04 */ - __IO uint32_t OAR1; /*!< I2C Own address register 1, Address offset: 0x08 */ - __IO uint32_t OAR2; /*!< I2C Own address register 2, Address offset: 0x0C */ - __IO uint32_t DR; /*!< I2C Data register, Address offset: 0x10 */ - __IO uint32_t SR1; /*!< I2C Status register 1, Address offset: 0x14 */ - __IO uint32_t SR2; /*!< I2C Status register 2, Address offset: 0x18 */ - __IO uint32_t CCR; /*!< I2C Clock control register, Address offset: 0x1C */ - __IO uint32_t TRISE; /*!< I2C TRISE register, Address offset: 0x20 */ - __IO uint32_t FLTR; /*!< I2C FLTR register, Address offset: 0x24 */ -} I2C_TypeDef; - -/** - * @brief Inter-integrated Circuit Interface - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< FMPI2C Control register 1, Address offset: 0x00 */ - __IO uint32_t CR2; /*!< FMPI2C Control register 2, Address offset: 0x04 */ - __IO uint32_t OAR1; /*!< FMPI2C Own address 1 register, Address offset: 0x08 */ - __IO uint32_t OAR2; /*!< FMPI2C Own address 2 register, Address offset: 0x0C */ - __IO uint32_t TIMINGR; /*!< FMPI2C Timing register, Address offset: 0x10 */ - __IO uint32_t TIMEOUTR; /*!< FMPI2C Timeout register, Address offset: 0x14 */ - __IO uint32_t ISR; /*!< FMPI2C Interrupt and status register, Address offset: 0x18 */ - __IO uint32_t ICR; /*!< FMPI2C Interrupt clear register, Address offset: 0x1C */ - __IO uint32_t PECR; /*!< FMPI2C PEC register, Address offset: 0x20 */ - __IO uint32_t RXDR; /*!< FMPI2C Receive data register, Address offset: 0x24 */ - __IO uint32_t TXDR; /*!< FMPI2C Transmit data register, Address offset: 0x28 */ -} FMPI2C_TypeDef; - -/** - * @brief Independent WATCHDOG - */ - -typedef struct -{ - __IO uint32_t KR; /*!< IWDG Key register, Address offset: 0x00 */ - __IO uint32_t PR; /*!< IWDG Prescaler register, Address offset: 0x04 */ - __IO uint32_t RLR; /*!< IWDG Reload register, Address offset: 0x08 */ - __IO uint32_t SR; /*!< IWDG Status register, Address offset: 0x0C */ -} IWDG_TypeDef; - - -/** - * @brief Power Control - */ - -typedef struct -{ - __IO uint32_t CR; /*!< PWR power control register, Address offset: 0x00 */ - __IO uint32_t CSR; /*!< PWR power control/status register, Address offset: 0x04 */ -} PWR_TypeDef; - -/** - * @brief Reset and Clock Control - */ - -typedef struct -{ - __IO uint32_t CR; /*!< RCC clock control register, Address offset: 0x00 */ - __IO uint32_t PLLCFGR; /*!< RCC PLL configuration register, Address offset: 0x04 */ - __IO uint32_t CFGR; /*!< RCC clock configuration register, Address offset: 0x08 */ - __IO uint32_t CIR; /*!< RCC clock interrupt register, Address offset: 0x0C */ - __IO uint32_t AHB1RSTR; /*!< RCC AHB1 peripheral reset register, Address offset: 0x10 */ - __IO uint32_t AHB2RSTR; /*!< RCC AHB2 peripheral reset register, Address offset: 0x14 */ - __IO uint32_t AHB3RSTR; /*!< RCC AHB3 peripheral reset register, Address offset: 0x18 */ - uint32_t RESERVED0; /*!< Reserved, 0x1C */ - __IO uint32_t APB1RSTR; /*!< RCC APB1 peripheral reset register, Address offset: 0x20 */ - __IO uint32_t APB2RSTR; /*!< RCC APB2 peripheral reset register, Address offset: 0x24 */ - uint32_t RESERVED1[2]; /*!< Reserved, 0x28-0x2C */ - __IO uint32_t AHB1ENR; /*!< RCC AHB1 peripheral clock register, Address offset: 0x30 */ - __IO uint32_t AHB2ENR; /*!< RCC AHB2 peripheral clock register, Address offset: 0x34 */ - __IO uint32_t AHB3ENR; /*!< RCC AHB3 peripheral clock register, Address offset: 0x38 */ - uint32_t RESERVED2; /*!< Reserved, 0x3C */ - __IO uint32_t APB1ENR; /*!< RCC APB1 peripheral clock enable register, Address offset: 0x40 */ - __IO uint32_t APB2ENR; /*!< RCC APB2 peripheral clock enable register, Address offset: 0x44 */ - uint32_t RESERVED3[2]; /*!< Reserved, 0x48-0x4C */ - __IO uint32_t AHB1LPENR; /*!< RCC AHB1 peripheral clock enable in low power mode register, Address offset: 0x50 */ - __IO uint32_t AHB2LPENR; /*!< RCC AHB2 peripheral clock enable in low power mode register, Address offset: 0x54 */ - __IO uint32_t AHB3LPENR; /*!< RCC AHB3 peripheral clock enable in low power mode register, Address offset: 0x58 */ - uint32_t RESERVED4; /*!< Reserved, 0x5C */ - __IO uint32_t APB1LPENR; /*!< RCC APB1 peripheral clock enable in low power mode register, Address offset: 0x60 */ - __IO uint32_t APB2LPENR; /*!< RCC APB2 peripheral clock enable in low power mode register, Address offset: 0x64 */ - uint32_t RESERVED5[2]; /*!< Reserved, 0x68-0x6C */ - __IO uint32_t BDCR; /*!< RCC Backup domain control register, Address offset: 0x70 */ - __IO uint32_t CSR; /*!< RCC clock control & status register, Address offset: 0x74 */ - uint32_t RESERVED6[2]; /*!< Reserved, 0x78-0x7C */ - __IO uint32_t SSCGR; /*!< RCC spread spectrum clock generation register, Address offset: 0x80 */ - __IO uint32_t PLLI2SCFGR; /*!< RCC PLLI2S configuration register, Address offset: 0x84 */ - uint32_t RESERVED7; /*!< Reserved, 0x84 */ - __IO uint32_t DCKCFGR; /*!< RCC Dedicated Clocks configuration register, Address offset: 0x8C */ - __IO uint32_t CKGATENR; /*!< RCC Clocks Gated ENable Register, Address offset: 0x90 */ - __IO uint32_t DCKCFGR2; /*!< RCC Dedicated Clocks configuration register 2, Address offset: 0x94 */ -} RCC_TypeDef; - -/** - * @brief Real-Time Clock - */ - -typedef struct -{ - __IO uint32_t TR; /*!< RTC time register, Address offset: 0x00 */ - __IO uint32_t DR; /*!< RTC date register, Address offset: 0x04 */ - __IO uint32_t CR; /*!< RTC control register, Address offset: 0x08 */ - __IO uint32_t ISR; /*!< RTC initialization and status register, Address offset: 0x0C */ - __IO uint32_t PRER; /*!< RTC prescaler register, Address offset: 0x10 */ - __IO uint32_t WUTR; /*!< RTC wakeup timer register, Address offset: 0x14 */ - __IO uint32_t CALIBR; /*!< RTC calibration register, Address offset: 0x18 */ - __IO uint32_t ALRMAR; /*!< RTC alarm A register, Address offset: 0x1C */ - __IO uint32_t ALRMBR; /*!< RTC alarm B register, Address offset: 0x20 */ - __IO uint32_t WPR; /*!< RTC write protection register, Address offset: 0x24 */ - __IO uint32_t SSR; /*!< RTC sub second register, Address offset: 0x28 */ - __IO uint32_t SHIFTR; /*!< RTC shift control register, Address offset: 0x2C */ - __IO uint32_t TSTR; /*!< RTC time stamp time register, Address offset: 0x30 */ - __IO uint32_t TSDR; /*!< RTC time stamp date register, Address offset: 0x34 */ - __IO uint32_t TSSSR; /*!< RTC time-stamp sub second register, Address offset: 0x38 */ - __IO uint32_t CALR; /*!< RTC calibration register, Address offset: 0x3C */ - __IO uint32_t TAFCR; /*!< RTC tamper and alternate function configuration register, Address offset: 0x40 */ - __IO uint32_t ALRMASSR;/*!< RTC alarm A sub second register, Address offset: 0x44 */ - __IO uint32_t ALRMBSSR;/*!< RTC alarm B sub second register, Address offset: 0x48 */ - uint32_t RESERVED7; /*!< Reserved, 0x4C */ - __IO uint32_t BKP0R; /*!< RTC backup register 1, Address offset: 0x50 */ - __IO uint32_t BKP1R; /*!< RTC backup register 1, Address offset: 0x54 */ - __IO uint32_t BKP2R; /*!< RTC backup register 2, Address offset: 0x58 */ - __IO uint32_t BKP3R; /*!< RTC backup register 3, Address offset: 0x5C */ - __IO uint32_t BKP4R; /*!< RTC backup register 4, Address offset: 0x60 */ - __IO uint32_t BKP5R; /*!< RTC backup register 5, Address offset: 0x64 */ - __IO uint32_t BKP6R; /*!< RTC backup register 6, Address offset: 0x68 */ - __IO uint32_t BKP7R; /*!< RTC backup register 7, Address offset: 0x6C */ - __IO uint32_t BKP8R; /*!< RTC backup register 8, Address offset: 0x70 */ - __IO uint32_t BKP9R; /*!< RTC backup register 9, Address offset: 0x74 */ - __IO uint32_t BKP10R; /*!< RTC backup register 10, Address offset: 0x78 */ - __IO uint32_t BKP11R; /*!< RTC backup register 11, Address offset: 0x7C */ - __IO uint32_t BKP12R; /*!< RTC backup register 12, Address offset: 0x80 */ - __IO uint32_t BKP13R; /*!< RTC backup register 13, Address offset: 0x84 */ - __IO uint32_t BKP14R; /*!< RTC backup register 14, Address offset: 0x88 */ - __IO uint32_t BKP15R; /*!< RTC backup register 15, Address offset: 0x8C */ - __IO uint32_t BKP16R; /*!< RTC backup register 16, Address offset: 0x90 */ - __IO uint32_t BKP17R; /*!< RTC backup register 17, Address offset: 0x94 */ - __IO uint32_t BKP18R; /*!< RTC backup register 18, Address offset: 0x98 */ - __IO uint32_t BKP19R; /*!< RTC backup register 19, Address offset: 0x9C */ -} RTC_TypeDef; - -/** - * @brief Serial Audio Interface - */ - -typedef struct -{ - __IO uint32_t GCR; /*!< SAI global configuration register, Address offset: 0x00 */ -} SAI_TypeDef; - -typedef struct -{ - __IO uint32_t CR1; /*!< SAI block x configuration register 1, Address offset: 0x04 */ - __IO uint32_t CR2; /*!< SAI block x configuration register 2, Address offset: 0x08 */ - __IO uint32_t FRCR; /*!< SAI block x frame configuration register, Address offset: 0x0C */ - __IO uint32_t SLOTR; /*!< SAI block x slot register, Address offset: 0x10 */ - __IO uint32_t IMR; /*!< SAI block x interrupt mask register, Address offset: 0x14 */ - __IO uint32_t SR; /*!< SAI block x status register, Address offset: 0x18 */ - __IO uint32_t CLRFR; /*!< SAI block x clear flag register, Address offset: 0x1C */ - __IO uint32_t DR; /*!< SAI block x data register, Address offset: 0x20 */ -} SAI_Block_TypeDef; - -/** - * @brief SD host Interface - */ - -typedef struct -{ - __IO uint32_t POWER; /*!< SDIO power control register, Address offset: 0x00 */ - __IO uint32_t CLKCR; /*!< SDI clock control register, Address offset: 0x04 */ - __IO uint32_t ARG; /*!< SDIO argument register, Address offset: 0x08 */ - __IO uint32_t CMD; /*!< SDIO command register, Address offset: 0x0C */ - __IO const uint32_t RESPCMD; /*!< SDIO command response register, Address offset: 0x10 */ - __IO const uint32_t RESP1; /*!< SDIO response 1 register, Address offset: 0x14 */ - __IO const uint32_t RESP2; /*!< SDIO response 2 register, Address offset: 0x18 */ - __IO const uint32_t RESP3; /*!< SDIO response 3 register, Address offset: 0x1C */ - __IO const uint32_t RESP4; /*!< SDIO response 4 register, Address offset: 0x20 */ - __IO uint32_t DTIMER; /*!< SDIO data timer register, Address offset: 0x24 */ - __IO uint32_t DLEN; /*!< SDIO data length register, Address offset: 0x28 */ - __IO uint32_t DCTRL; /*!< SDIO data control register, Address offset: 0x2C */ - __IO const uint32_t DCOUNT; /*!< SDIO data counter register, Address offset: 0x30 */ - __IO const uint32_t STA; /*!< SDIO status register, Address offset: 0x34 */ - __IO uint32_t ICR; /*!< SDIO interrupt clear register, Address offset: 0x38 */ - __IO uint32_t MASK; /*!< SDIO mask register, Address offset: 0x3C */ - uint32_t RESERVED0[2]; /*!< Reserved, 0x40-0x44 */ - __IO const uint32_t FIFOCNT; /*!< SDIO FIFO counter register, Address offset: 0x48 */ - uint32_t RESERVED1[13]; /*!< Reserved, 0x4C-0x7C */ - __IO uint32_t FIFO; /*!< SDIO data FIFO register, Address offset: 0x80 */ -} SDIO_TypeDef; - -/** - * @brief Serial Peripheral Interface - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< SPI control register 1 (not used in I2S mode), Address offset: 0x00 */ - __IO uint32_t CR2; /*!< SPI control register 2, Address offset: 0x04 */ - __IO uint32_t SR; /*!< SPI status register, Address offset: 0x08 */ - __IO uint32_t DR; /*!< SPI data register, Address offset: 0x0C */ - __IO uint32_t CRCPR; /*!< SPI CRC polynomial register (not used in I2S mode), Address offset: 0x10 */ - __IO uint32_t RXCRCR; /*!< SPI RX CRC register (not used in I2S mode), Address offset: 0x14 */ - __IO uint32_t TXCRCR; /*!< SPI TX CRC register (not used in I2S mode), Address offset: 0x18 */ - __IO uint32_t I2SCFGR; /*!< SPI_I2S configuration register, Address offset: 0x1C */ - __IO uint32_t I2SPR; /*!< SPI_I2S prescaler register, Address offset: 0x20 */ -} SPI_TypeDef; - -/** - * @brief QUAD Serial Peripheral Interface - */ - -typedef struct -{ - __IO uint32_t CR; /*!< QUADSPI Control register, Address offset: 0x00 */ - __IO uint32_t DCR; /*!< QUADSPI Device Configuration register, Address offset: 0x04 */ - __IO uint32_t SR; /*!< QUADSPI Status register, Address offset: 0x08 */ - __IO uint32_t FCR; /*!< QUADSPI Flag Clear register, Address offset: 0x0C */ - __IO uint32_t DLR; /*!< QUADSPI Data Length register, Address offset: 0x10 */ - __IO uint32_t CCR; /*!< QUADSPI Communication Configuration register, Address offset: 0x14 */ - __IO uint32_t AR; /*!< QUADSPI Address register, Address offset: 0x18 */ - __IO uint32_t ABR; /*!< QUADSPI Alternate Bytes register, Address offset: 0x1C */ - __IO uint32_t DR; /*!< QUADSPI Data register, Address offset: 0x20 */ - __IO uint32_t PSMKR; /*!< QUADSPI Polling Status Mask register, Address offset: 0x24 */ - __IO uint32_t PSMAR; /*!< QUADSPI Polling Status Match register, Address offset: 0x28 */ - __IO uint32_t PIR; /*!< QUADSPI Polling Interval register, Address offset: 0x2C */ - __IO uint32_t LPTR; /*!< QUADSPI Low Power Timeout register, Address offset: 0x30 */ -} QUADSPI_TypeDef; - -/** - * @brief TIM - */ - -typedef struct -{ - __IO uint32_t CR1; /*!< TIM control register 1, Address offset: 0x00 */ - __IO uint32_t CR2; /*!< TIM control register 2, Address offset: 0x04 */ - __IO uint32_t SMCR; /*!< TIM slave mode control register, Address offset: 0x08 */ - __IO uint32_t DIER; /*!< TIM DMA/interrupt enable register, Address offset: 0x0C */ - __IO uint32_t SR; /*!< TIM status register, Address offset: 0x10 */ - __IO uint32_t EGR; /*!< TIM event generation register, Address offset: 0x14 */ - __IO uint32_t CCMR1; /*!< TIM capture/compare mode register 1, Address offset: 0x18 */ - __IO uint32_t CCMR2; /*!< TIM capture/compare mode register 2, Address offset: 0x1C */ - __IO uint32_t CCER; /*!< TIM capture/compare enable register, Address offset: 0x20 */ - __IO uint32_t CNT; /*!< TIM counter register, Address offset: 0x24 */ - __IO uint32_t PSC; /*!< TIM prescaler, Address offset: 0x28 */ - __IO uint32_t ARR; /*!< TIM auto-reload register, Address offset: 0x2C */ - __IO uint32_t RCR; /*!< TIM repetition counter register, Address offset: 0x30 */ - __IO uint32_t CCR1; /*!< TIM capture/compare register 1, Address offset: 0x34 */ - __IO uint32_t CCR2; /*!< TIM capture/compare register 2, Address offset: 0x38 */ - __IO uint32_t CCR3; /*!< TIM capture/compare register 3, Address offset: 0x3C */ - __IO uint32_t CCR4; /*!< TIM capture/compare register 4, Address offset: 0x40 */ - __IO uint32_t BDTR; /*!< TIM break and dead-time register, Address offset: 0x44 */ - __IO uint32_t DCR; /*!< TIM DMA control register, Address offset: 0x48 */ - __IO uint32_t DMAR; /*!< TIM DMA address for full transfer, Address offset: 0x4C */ - __IO uint32_t OR; /*!< TIM option register, Address offset: 0x50 */ -} TIM_TypeDef; - -/** - * @brief Universal Synchronous Asynchronous Receiver Transmitter - */ - -typedef struct -{ - __IO uint32_t SR; /*!< USART Status register, Address offset: 0x00 */ - __IO uint32_t DR; /*!< USART Data register, Address offset: 0x04 */ - __IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x08 */ - __IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x0C */ - __IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x10 */ - __IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x14 */ - __IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x18 */ -} USART_TypeDef; - -/** - * @brief Window WATCHDOG - */ - -typedef struct -{ - __IO uint32_t CR; /*!< WWDG Control register, Address offset: 0x00 */ - __IO uint32_t CFR; /*!< WWDG Configuration register, Address offset: 0x04 */ - __IO uint32_t SR; /*!< WWDG Status register, Address offset: 0x08 */ -} WWDG_TypeDef; - -/** - * @brief RNG - */ - -typedef struct -{ - __IO uint32_t CR; /*!< RNG control register, Address offset: 0x00 */ - __IO uint32_t SR; /*!< RNG status register, Address offset: 0x04 */ - __IO uint32_t DR; /*!< RNG data register, Address offset: 0x08 */ -} RNG_TypeDef; - -/** - * @brief USB_OTG_Core_Registers - */ -typedef struct -{ - __IO uint32_t GOTGCTL; /*!< USB_OTG Control and Status Register 000h */ - __IO uint32_t GOTGINT; /*!< USB_OTG Interrupt Register 004h */ - __IO uint32_t GAHBCFG; /*!< Core AHB Configuration Register 008h */ - __IO uint32_t GUSBCFG; /*!< Core USB Configuration Register 00Ch */ - __IO uint32_t GRSTCTL; /*!< Core Reset Register 010h */ - __IO uint32_t GINTSTS; /*!< Core Interrupt Register 014h */ - __IO uint32_t GINTMSK; /*!< Core Interrupt Mask Register 018h */ - __IO uint32_t GRXSTSR; /*!< Receive Sts Q Read Register 01Ch */ - __IO uint32_t GRXSTSP; /*!< Receive Sts Q Read & POP Register 020h */ - __IO uint32_t GRXFSIZ; /*!< Receive FIFO Size Register 024h */ - __IO uint32_t DIEPTXF0_HNPTXFSIZ; /*!< EP0 / Non Periodic Tx FIFO Size Register 028h */ - __IO uint32_t HNPTXSTS; /*!< Non Periodic Tx FIFO/Queue Sts reg 02Ch */ - uint32_t Reserved30[2]; /*!< Reserved 030h */ - __IO uint32_t GCCFG; /*!< General Purpose IO Register 038h */ - __IO uint32_t CID; /*!< User ID Register 03Ch */ - uint32_t Reserved5[3]; /*!< Reserved 040h-048h */ - __IO uint32_t GHWCFG3; /*!< User HW config3 04Ch */ - uint32_t Reserved6; /*!< Reserved 050h */ - __IO uint32_t GLPMCFG; /*!< LPM Register 054h */ - uint32_t Reserved; /*!< Reserved 058h */ - __IO uint32_t GDFIFOCFG; /*!< DFIFO Software Config Register 05Ch */ - uint32_t Reserved43[40]; /*!< Reserved 058h-0FFh */ - __IO uint32_t HPTXFSIZ; /*!< Host Periodic Tx FIFO Size Reg 100h */ - __IO uint32_t DIEPTXF[0x0F]; /*!< dev Periodic Transmit FIFO */ -} USB_OTG_GlobalTypeDef; - -/** - * @brief USB_OTG_device_Registers - */ -typedef struct -{ - __IO uint32_t DCFG; /*!< dev Configuration Register 800h */ - __IO uint32_t DCTL; /*!< dev Control Register 804h */ - __IO uint32_t DSTS; /*!< dev Status Register (RO) 808h */ - uint32_t Reserved0C; /*!< Reserved 80Ch */ - __IO uint32_t DIEPMSK; /*!< dev IN Endpoint Mask 810h */ - __IO uint32_t DOEPMSK; /*!< dev OUT Endpoint Mask 814h */ - __IO uint32_t DAINT; /*!< dev All Endpoints Itr Reg 818h */ - __IO uint32_t DAINTMSK; /*!< dev All Endpoints Itr Mask 81Ch */ - uint32_t Reserved20; /*!< Reserved 820h */ - uint32_t Reserved9; /*!< Reserved 824h */ - __IO uint32_t DVBUSDIS; /*!< dev VBUS discharge Register 828h */ - __IO uint32_t DVBUSPULSE; /*!< dev VBUS Pulse Register 82Ch */ - __IO uint32_t DTHRCTL; /*!< dev threshold 830h */ - __IO uint32_t DIEPEMPMSK; /*!< dev empty msk 834h */ - __IO uint32_t DEACHINT; /*!< dedicated EP interrupt 838h */ - __IO uint32_t DEACHMSK; /*!< dedicated EP msk 83Ch */ - uint32_t Reserved40; /*!< dedicated EP mask 840h */ - __IO uint32_t DINEP1MSK; /*!< dedicated EP mask 844h */ - uint32_t Reserved44[15]; /*!< Reserved 844-87Ch */ - __IO uint32_t DOUTEP1MSK; /*!< dedicated EP msk 884h */ -} USB_OTG_DeviceTypeDef; - -/** - * @brief USB_OTG_IN_Endpoint-Specific_Register - */ -typedef struct -{ - __IO uint32_t DIEPCTL; /*!< dev IN Endpoint Control Reg 900h + (ep_num * 20h) + 00h */ - uint32_t Reserved04; /*!< Reserved 900h + (ep_num * 20h) + 04h */ - __IO uint32_t DIEPINT; /*!< dev IN Endpoint Itr Reg 900h + (ep_num * 20h) + 08h */ - uint32_t Reserved0C; /*!< Reserved 900h + (ep_num * 20h) + 0Ch */ - __IO uint32_t DIEPTSIZ; /*!< IN Endpoint Txfer Size 900h + (ep_num * 20h) + 10h */ - __IO uint32_t DIEPDMA; /*!< IN Endpoint DMA Address Reg 900h + (ep_num * 20h) + 14h */ - __IO uint32_t DTXFSTS; /*!< IN Endpoint Tx FIFO Status Reg 900h + (ep_num * 20h) + 18h */ - uint32_t Reserved18; /*!< Reserved 900h+(ep_num*20h)+1Ch-900h+ (ep_num * 20h) + 1Ch */ -} USB_OTG_INEndpointTypeDef; - -/** - * @brief USB_OTG_OUT_Endpoint-Specific_Registers - */ -typedef struct -{ - __IO uint32_t DOEPCTL; /*!< dev OUT Endpoint Control Reg B00h + (ep_num * 20h) + 00h */ - uint32_t Reserved04; /*!< Reserved B00h + (ep_num * 20h) + 04h */ - __IO uint32_t DOEPINT; /*!< dev OUT Endpoint Itr Reg B00h + (ep_num * 20h) + 08h */ - uint32_t Reserved0C; /*!< Reserved B00h + (ep_num * 20h) + 0Ch */ - __IO uint32_t DOEPTSIZ; /*!< dev OUT Endpoint Txfer Size B00h + (ep_num * 20h) + 10h */ - __IO uint32_t DOEPDMA; /*!< dev OUT Endpoint DMA Address B00h + (ep_num * 20h) + 14h */ - uint32_t Reserved18[2]; /*!< Reserved B00h + (ep_num * 20h) + 18h - B00h + (ep_num * 20h) + 1Ch */ -} USB_OTG_OUTEndpointTypeDef; - -/** - * @brief USB_OTG_Host_Mode_Register_Structures - */ -typedef struct -{ - __IO uint32_t HCFG; /*!< Host Configuration Register 400h */ - __IO uint32_t HFIR; /*!< Host Frame Interval Register 404h */ - __IO uint32_t HFNUM; /*!< Host Frame Nbr/Frame Remaining 408h */ - uint32_t Reserved40C; /*!< Reserved 40Ch */ - __IO uint32_t HPTXSTS; /*!< Host Periodic Tx FIFO/ Queue Status 410h */ - __IO uint32_t HAINT; /*!< Host All Channels Interrupt Register 414h */ - __IO uint32_t HAINTMSK; /*!< Host All Channels Interrupt Mask 418h */ -} USB_OTG_HostTypeDef; - -/** - * @brief USB_OTG_Host_Channel_Specific_Registers - */ -typedef struct -{ - __IO uint32_t HCCHAR; /*!< Host Channel Characteristics Register 500h */ - __IO uint32_t HCSPLT; /*!< Host Channel Split Control Register 504h */ - __IO uint32_t HCINT; /*!< Host Channel Interrupt Register 508h */ - __IO uint32_t HCINTMSK; /*!< Host Channel Interrupt Mask Register 50Ch */ - __IO uint32_t HCTSIZ; /*!< Host Channel Transfer Size Register 510h */ - __IO uint32_t HCDMA; /*!< Host Channel DMA Address Register 514h */ - uint32_t Reserved[2]; /*!< Reserved */ -} USB_OTG_HostChannelTypeDef; - -/** - * @brief LPTIMER - */ -typedef struct -{ - __IO uint32_t ISR; /*!< LPTIM Interrupt and Status register, Address offset: 0x00 */ - __IO uint32_t ICR; /*!< LPTIM Interrupt Clear register, Address offset: 0x04 */ - __IO uint32_t IER; /*!< LPTIM Interrupt Enable register, Address offset: 0x08 */ - __IO uint32_t CFGR; /*!< LPTIM Configuration register, Address offset: 0x0C */ - __IO uint32_t CR; /*!< LPTIM Control register, Address offset: 0x10 */ - __IO uint32_t CMP; /*!< LPTIM Compare register, Address offset: 0x14 */ - __IO uint32_t ARR; /*!< LPTIM Autoreload register, Address offset: 0x18 */ - __IO uint32_t CNT; /*!< LPTIM Counter register, Address offset: 0x1C */ - __IO uint32_t OR; /*!< LPTIM Option register, Address offset: 0x20 */ -} LPTIM_TypeDef; - -/** - * @} - */ - -/** @addtogroup Peripheral_memory_map - * @{ - */ -#define FLASH_BASE 0x08000000U /*!< FLASH (up to 1.5 MB) base address in the alias region */ -#define SRAM1_BASE 0x20000000U /*!< SRAM1(256 KB) base address in the alias region */ -#define SRAM2_BASE 0x20040000U /*!< SRAM2(64 KB) base address in the alias region */ -#define PERIPH_BASE 0x40000000U /*!< Peripheral base address in the alias region */ -#define FSMC_R_BASE 0xA0000000U /*!< FSMC registers base address */ -#define QSPI_R_BASE 0xA0001000U /*!< QuadSPI registers base address */ -#define SRAM1_BB_BASE 0x22000000U /*!< SRAM1(256 KB) base address in the bit-band region */ -#define SRAM2_BB_BASE 0x22800000U /*!< SRAM2(64 KB) base address in the bit-band region */ -#define PERIPH_BB_BASE 0x42000000U /*!< Peripheral base address in the bit-band region */ -#define FLASH_END 0x0817FFFFU /*!< FLASH end address */ - -/* Legacy defines */ -#define SRAM_BASE SRAM1_BASE -#define SRAM_BB_BASE SRAM1_BB_BASE - - -/*!< Peripheral memory map */ -#define APB1PERIPH_BASE PERIPH_BASE -#define APB2PERIPH_BASE (PERIPH_BASE + 0x00010000U) -#define AHB1PERIPH_BASE (PERIPH_BASE + 0x00020000U) -#define AHB2PERIPH_BASE (PERIPH_BASE + 0x10000000U) - -/*!< APB1 peripherals */ -#define TIM2_BASE (APB1PERIPH_BASE + 0x0000U) -#define TIM3_BASE (APB1PERIPH_BASE + 0x0400U) -#define TIM4_BASE (APB1PERIPH_BASE + 0x0800U) -#define TIM5_BASE (APB1PERIPH_BASE + 0x0C00U) -#define TIM6_BASE (APB1PERIPH_BASE + 0x1000U) -#define TIM7_BASE (APB1PERIPH_BASE + 0x1400U) -#define TIM12_BASE (APB1PERIPH_BASE + 0x1800U) -#define TIM13_BASE (APB1PERIPH_BASE + 0x1C00U) -#define TIM14_BASE (APB1PERIPH_BASE + 0x2000U) -#define LPTIM1_BASE (APB1PERIPH_BASE + 0x2400U) -#define RTC_BASE (APB1PERIPH_BASE + 0x2800U) -#define WWDG_BASE (APB1PERIPH_BASE + 0x2C00U) -#define IWDG_BASE (APB1PERIPH_BASE + 0x3000U) -#define I2S2ext_BASE (APB1PERIPH_BASE + 0x3400U) -#define SPI2_BASE (APB1PERIPH_BASE + 0x3800U) -#define SPI3_BASE (APB1PERIPH_BASE + 0x3C00U) -#define I2S3ext_BASE (APB1PERIPH_BASE + 0x4000U) -#define USART2_BASE (APB1PERIPH_BASE + 0x4400U) -#define USART3_BASE (APB1PERIPH_BASE + 0x4800U) -#define UART4_BASE (APB1PERIPH_BASE + 0x4C00U) -#define UART5_BASE (APB1PERIPH_BASE + 0x5000U) -#define I2C1_BASE (APB1PERIPH_BASE + 0x5400U) -#define I2C2_BASE (APB1PERIPH_BASE + 0x5800U) -#define I2C3_BASE (APB1PERIPH_BASE + 0x5C00U) -#define FMPI2C1_BASE (APB1PERIPH_BASE + 0x6000U) -#define CAN1_BASE (APB1PERIPH_BASE + 0x6400U) -#define CAN2_BASE (APB1PERIPH_BASE + 0x6800U) -#define CAN3_BASE (APB1PERIPH_BASE + 0x6C00U) -#define PWR_BASE (APB1PERIPH_BASE + 0x7000U) -#define DAC_BASE (APB1PERIPH_BASE + 0x7400U) -#define UART7_BASE (APB1PERIPH_BASE + 0x7800U) -#define UART8_BASE (APB1PERIPH_BASE + 0x7C00U) - -/*!< APB2 peripherals */ -#define TIM1_BASE (APB2PERIPH_BASE + 0x0000U) -#define TIM8_BASE (APB2PERIPH_BASE + 0x0400U) -#define USART1_BASE (APB2PERIPH_BASE + 0x1000U) -#define USART6_BASE (APB2PERIPH_BASE + 0x1400U) -#define UART9_BASE (APB2PERIPH_BASE + 0x1800U) -#define UART10_BASE (APB2PERIPH_BASE + 0x1C00U) -#define ADC1_BASE (APB2PERIPH_BASE + 0x2000U) -#define ADC_BASE (APB2PERIPH_BASE + 0x2300U) -#define SDIO_BASE (APB2PERIPH_BASE + 0x2C00U) -#define SPI1_BASE (APB2PERIPH_BASE + 0x3000U) -#define SPI4_BASE (APB2PERIPH_BASE + 0x3400U) -#define SYSCFG_BASE (APB2PERIPH_BASE + 0x3800U) -#define EXTI_BASE (APB2PERIPH_BASE + 0x3C00U) -#define TIM9_BASE (APB2PERIPH_BASE + 0x4000U) -#define TIM10_BASE (APB2PERIPH_BASE + 0x4400U) -#define TIM11_BASE (APB2PERIPH_BASE + 0x4800U) -#define SPI5_BASE (APB2PERIPH_BASE + 0x5000U) -#define DFSDM1_BASE (APB2PERIPH_BASE + 0x6000U) -#define DFSDM2_BASE (APB2PERIPH_BASE + 0x6400U) -#define DFSDM1_Channel0_BASE (DFSDM1_BASE + 0x00U) -#define DFSDM1_Channel1_BASE (DFSDM1_BASE + 0x20U) -#define DFSDM1_Channel2_BASE (DFSDM1_BASE + 0x40U) -#define DFSDM1_Channel3_BASE (DFSDM1_BASE + 0x60U) -#define DFSDM1_Filter0_BASE (DFSDM1_BASE + 0x100U) -#define DFSDM1_Filter1_BASE (DFSDM1_BASE + 0x180U) -#define DFSDM2_Channel0_BASE (DFSDM2_BASE + 0x00U) -#define DFSDM2_Channel1_BASE (DFSDM2_BASE + 0x20U) -#define DFSDM2_Channel2_BASE (DFSDM2_BASE + 0x40U) -#define DFSDM2_Channel3_BASE (DFSDM2_BASE + 0x60U) -#define DFSDM2_Channel4_BASE (DFSDM2_BASE + 0x80U) -#define DFSDM2_Channel5_BASE (DFSDM2_BASE + 0xA0U) -#define DFSDM2_Channel6_BASE (DFSDM2_BASE + 0xC0U) -#define DFSDM2_Channel7_BASE (DFSDM2_BASE + 0xE0U) -#define DFSDM2_Filter0_BASE (DFSDM2_BASE + 0x100U) -#define DFSDM2_Filter1_BASE (DFSDM2_BASE + 0x180U) -#define DFSDM2_Filter2_BASE (DFSDM2_BASE + 0x200U) -#define DFSDM2_Filter3_BASE (DFSDM2_BASE + 0x280U) -#define SAI1_BASE (APB2PERIPH_BASE + 0x5800U) -#define SAI1_Block_A_BASE (SAI1_BASE + 0x004U) -#define SAI1_Block_B_BASE (SAI1_BASE + 0x024U) - -/*!< AHB1 peripherals */ -#define GPIOA_BASE (AHB1PERIPH_BASE + 0x0000U) -#define GPIOB_BASE (AHB1PERIPH_BASE + 0x0400U) -#define GPIOC_BASE (AHB1PERIPH_BASE + 0x0800U) -#define GPIOD_BASE (AHB1PERIPH_BASE + 0x0C00U) -#define GPIOE_BASE (AHB1PERIPH_BASE + 0x1000U) -#define GPIOF_BASE (AHB1PERIPH_BASE + 0x1400U) -#define GPIOG_BASE (AHB1PERIPH_BASE + 0x1800U) -#define GPIOH_BASE (AHB1PERIPH_BASE + 0x1C00U) -#define CRC_BASE (AHB1PERIPH_BASE + 0x3000U) -#define RCC_BASE (AHB1PERIPH_BASE + 0x3800U) -#define FLASH_R_BASE (AHB1PERIPH_BASE + 0x3C00U) -#define DMA1_BASE (AHB1PERIPH_BASE + 0x6000U) -#define DMA1_Stream0_BASE (DMA1_BASE + 0x010U) -#define DMA1_Stream1_BASE (DMA1_BASE + 0x028U) -#define DMA1_Stream2_BASE (DMA1_BASE + 0x040U) -#define DMA1_Stream3_BASE (DMA1_BASE + 0x058U) -#define DMA1_Stream4_BASE (DMA1_BASE + 0x070U) -#define DMA1_Stream5_BASE (DMA1_BASE + 0x088U) -#define DMA1_Stream6_BASE (DMA1_BASE + 0x0A0U) -#define DMA1_Stream7_BASE (DMA1_BASE + 0x0B8U) -#define DMA2_BASE (AHB1PERIPH_BASE + 0x6400U) -#define DMA2_Stream0_BASE (DMA2_BASE + 0x010U) -#define DMA2_Stream1_BASE (DMA2_BASE + 0x028U) -#define DMA2_Stream2_BASE (DMA2_BASE + 0x040U) -#define DMA2_Stream3_BASE (DMA2_BASE + 0x058U) -#define DMA2_Stream4_BASE (DMA2_BASE + 0x070U) -#define DMA2_Stream5_BASE (DMA2_BASE + 0x088U) -#define DMA2_Stream6_BASE (DMA2_BASE + 0x0A0U) -#define DMA2_Stream7_BASE (DMA2_BASE + 0x0B8U) - -/*!< AHB2 peripherals */ -#define RNG_BASE (AHB2PERIPH_BASE + 0x60800U) - - -/*!< FSMC Bankx registers base address */ -#define FSMC_Bank1_R_BASE (FSMC_R_BASE + 0x0000U) -#define FSMC_Bank1E_R_BASE (FSMC_R_BASE + 0x0104U) - -/*!< Debug MCU registers base address */ -#define DBGMCU_BASE 0xE0042000U -/*!< USB registers base address */ -#define USB_OTG_FS_PERIPH_BASE 0x50000000U - -#define USB_OTG_GLOBAL_BASE 0x000U -#define USB_OTG_DEVICE_BASE 0x800U -#define USB_OTG_IN_ENDPOINT_BASE 0x900U -#define USB_OTG_OUT_ENDPOINT_BASE 0xB00U -#define USB_OTG_EP_REG_SIZE 0x20U -#define USB_OTG_HOST_BASE 0x400U -#define USB_OTG_HOST_PORT_BASE 0x440U -#define USB_OTG_HOST_CHANNEL_BASE 0x500U -#define USB_OTG_HOST_CHANNEL_SIZE 0x20U -#define USB_OTG_PCGCCTL_BASE 0xE00U -#define USB_OTG_FIFO_BASE 0x1000U -#define USB_OTG_FIFO_SIZE 0x1000U - -#define UID_BASE 0x1FFF7A10U /*!< Unique device ID register base address */ -#define FLASHSIZE_BASE 0x1FFF7A22U /*!< FLASH Size register base address */ -#define PACKAGE_BASE 0x1FFF7BF0U /*!< Package size register base address */ -/** - * @} - */ - -/** @addtogroup Peripheral_declaration - * @{ - */ -#define TIM2 ((TIM_TypeDef *) TIM2_BASE) -#define TIM3 ((TIM_TypeDef *) TIM3_BASE) -#define TIM4 ((TIM_TypeDef *) TIM4_BASE) -#define TIM5 ((TIM_TypeDef *) TIM5_BASE) -#define TIM6 ((TIM_TypeDef *) TIM6_BASE) -#define TIM7 ((TIM_TypeDef *) TIM7_BASE) -#define TIM12 ((TIM_TypeDef *) TIM12_BASE) -#define TIM13 ((TIM_TypeDef *) TIM13_BASE) -#define TIM14 ((TIM_TypeDef *) TIM14_BASE) -#define LPTIM1 ((LPTIM_TypeDef *) LPTIM1_BASE) -#define RTC ((RTC_TypeDef *) RTC_BASE) -#define WWDG ((WWDG_TypeDef *) WWDG_BASE) -#define IWDG ((IWDG_TypeDef *) IWDG_BASE) -#define I2S2ext ((SPI_TypeDef *) I2S2ext_BASE) -#define SPI2 ((SPI_TypeDef *) SPI2_BASE) -#define SPI3 ((SPI_TypeDef *) SPI3_BASE) -#define I2S3ext ((SPI_TypeDef *) I2S3ext_BASE) -#define USART2 ((USART_TypeDef *) USART2_BASE) -#define USART3 ((USART_TypeDef *) USART3_BASE) -#define UART4 ((USART_TypeDef *) UART4_BASE) -#define UART5 ((USART_TypeDef *) UART5_BASE) -#define I2C1 ((I2C_TypeDef *) I2C1_BASE) -#define I2C2 ((I2C_TypeDef *) I2C2_BASE) -#define I2C3 ((I2C_TypeDef *) I2C3_BASE) -#define FMPI2C1 ((FMPI2C_TypeDef *) FMPI2C1_BASE) -#define CAN1 ((CAN_TypeDef *) CAN1_BASE) -#define CAN2 ((CAN_TypeDef *) CAN2_BASE) -#define CAN3 ((CAN_TypeDef *) CAN3_BASE) -#define PWR ((PWR_TypeDef *) PWR_BASE) -#define DAC1 ((DAC_TypeDef *) DAC_BASE) -#define DAC ((DAC_TypeDef *) DAC_BASE) /* Kept for legacy purpose */ -#define UART7 ((USART_TypeDef *) UART7_BASE) -#define UART8 ((USART_TypeDef *) UART8_BASE) -#define TIM1 ((TIM_TypeDef *) TIM1_BASE) -#define TIM8 ((TIM_TypeDef *) TIM8_BASE) -#define USART1 ((USART_TypeDef *) USART1_BASE) -#define USART6 ((USART_TypeDef *) USART6_BASE) -#define UART9 ((USART_TypeDef *) UART9_BASE) -#define UART10 ((USART_TypeDef *) UART10_BASE) -#define ADC ((ADC_Common_TypeDef *) ADC_BASE) -#define ADC1 ((ADC_TypeDef *) ADC1_BASE) -#define SDIO ((SDIO_TypeDef *) SDIO_BASE) -#define SPI1 ((SPI_TypeDef *) SPI1_BASE) -#define SPI4 ((SPI_TypeDef *) SPI4_BASE) -#define SYSCFG ((SYSCFG_TypeDef *) SYSCFG_BASE) -#define EXTI ((EXTI_TypeDef *) EXTI_BASE) -#define TIM9 ((TIM_TypeDef *) TIM9_BASE) -#define TIM10 ((TIM_TypeDef *) TIM10_BASE) -#define TIM11 ((TIM_TypeDef *) TIM11_BASE) -#define SPI5 ((SPI_TypeDef *) SPI5_BASE) -#define DFSDM1_Channel0 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel0_BASE) -#define DFSDM1_Channel1 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel1_BASE) -#define DFSDM1_Channel2 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel2_BASE) -#define DFSDM1_Channel3 ((DFSDM_Channel_TypeDef *) DFSDM1_Channel3_BASE) -#define DFSDM1_Filter0 ((DFSDM_Filter_TypeDef *) DFSDM1_Filter0_BASE) -#define DFSDM1_Filter1 ((DFSDM_Filter_TypeDef *) DFSDM1_Filter1_BASE) -#define DFSDM2_Channel0 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel0_BASE) -#define DFSDM2_Channel1 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel1_BASE) -#define DFSDM2_Channel2 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel2_BASE) -#define DFSDM2_Channel3 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel3_BASE) -#define DFSDM2_Channel4 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel4_BASE) -#define DFSDM2_Channel5 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel5_BASE) -#define DFSDM2_Channel6 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel6_BASE) -#define DFSDM2_Channel7 ((DFSDM_Channel_TypeDef *) DFSDM2_Channel7_BASE) -#define DFSDM2_Filter0 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter0_BASE) -#define DFSDM2_Filter1 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter1_BASE) -#define DFSDM2_Filter2 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter2_BASE) -#define DFSDM2_Filter3 ((DFSDM_Filter_TypeDef *) DFSDM2_Filter3_BASE) -#define SAI1 ((SAI_TypeDef *) SAI1_BASE) -#define SAI1_Block_A ((SAI_Block_TypeDef *)SAI1_Block_A_BASE) -#define SAI1_Block_B ((SAI_Block_TypeDef *)SAI1_Block_B_BASE) -#define GPIOA ((GPIO_TypeDef *) GPIOA_BASE) -#define GPIOB ((GPIO_TypeDef *) GPIOB_BASE) -#define GPIOC ((GPIO_TypeDef *) GPIOC_BASE) -#define GPIOD ((GPIO_TypeDef *) GPIOD_BASE) -#define GPIOE ((GPIO_TypeDef *) GPIOE_BASE) -#define GPIOF ((GPIO_TypeDef *) GPIOF_BASE) -#define GPIOG ((GPIO_TypeDef *) GPIOG_BASE) -#define GPIOH ((GPIO_TypeDef *) GPIOH_BASE) -#define CRC ((CRC_TypeDef *) CRC_BASE) -#define RCC ((RCC_TypeDef *) RCC_BASE) -#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE) -#define DMA1 ((DMA_TypeDef *) DMA1_BASE) -#define DMA1_Stream0 ((DMA_Stream_TypeDef *) DMA1_Stream0_BASE) -#define DMA1_Stream1 ((DMA_Stream_TypeDef *) DMA1_Stream1_BASE) -#define DMA1_Stream2 ((DMA_Stream_TypeDef *) DMA1_Stream2_BASE) -#define DMA1_Stream3 ((DMA_Stream_TypeDef *) DMA1_Stream3_BASE) -#define DMA1_Stream4 ((DMA_Stream_TypeDef *) DMA1_Stream4_BASE) -#define DMA1_Stream5 ((DMA_Stream_TypeDef *) DMA1_Stream5_BASE) -#define DMA1_Stream6 ((DMA_Stream_TypeDef *) DMA1_Stream6_BASE) -#define DMA1_Stream7 ((DMA_Stream_TypeDef *) DMA1_Stream7_BASE) -#define DMA2 ((DMA_TypeDef *) DMA2_BASE) -#define DMA2_Stream0 ((DMA_Stream_TypeDef *) DMA2_Stream0_BASE) -#define DMA2_Stream1 ((DMA_Stream_TypeDef *) DMA2_Stream1_BASE) -#define DMA2_Stream2 ((DMA_Stream_TypeDef *) DMA2_Stream2_BASE) -#define DMA2_Stream3 ((DMA_Stream_TypeDef *) DMA2_Stream3_BASE) -#define DMA2_Stream4 ((DMA_Stream_TypeDef *) DMA2_Stream4_BASE) -#define DMA2_Stream5 ((DMA_Stream_TypeDef *) DMA2_Stream5_BASE) -#define DMA2_Stream6 ((DMA_Stream_TypeDef *) DMA2_Stream6_BASE) -#define DMA2_Stream7 ((DMA_Stream_TypeDef *) DMA2_Stream7_BASE) -#define RNG ((RNG_TypeDef *) RNG_BASE) -#define FSMC_Bank1 ((FSMC_Bank1_TypeDef *) FSMC_Bank1_R_BASE) -#define FSMC_Bank1E ((FSMC_Bank1E_TypeDef *) FSMC_Bank1E_R_BASE) -#define QUADSPI ((QUADSPI_TypeDef *) QSPI_R_BASE) -#define DBGMCU ((DBGMCU_TypeDef *) DBGMCU_BASE) -#define USB_OTG_FS ((USB_OTG_GlobalTypeDef *) USB_OTG_FS_PERIPH_BASE) - -/** - * @} - */ - -/** @addtogroup Exported_constants - * @{ - */ - - /** @addtogroup Peripheral_Registers_Bits_Definition - * @{ - */ - -/******************************************************************************/ -/* Peripheral Registers_Bits_Definition */ -/******************************************************************************/ - -/******************************************************************************/ -/* */ -/* Analog to Digital Converter */ -/* */ -/******************************************************************************/ -/******************** Bit definition for ADC_SR register ********************/ -#define ADC_SR_AWD_Pos (0U) -#define ADC_SR_AWD_Msk (0x1U << ADC_SR_AWD_Pos) /*!< 0x00000001 */ -#define ADC_SR_AWD ADC_SR_AWD_Msk /*!
© COPYRIGHT(c) 2016 STMicroelectronics
- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32f4xx - * @{ - */ - -#ifndef __STM32F4xx_H -#define __STM32F4xx_H - -#ifdef __cplusplus - extern "C" { -#endif /* __cplusplus */ - -/** @addtogroup Library_configuration_section - * @{ - */ - -/** - * @brief STM32 Family - */ -#if !defined (STM32F4) -#define STM32F4 -#endif /* STM32F4 */ - -/* Uncomment the line below according to the target STM32 device used in your - application - */ -#if !defined (STM32F405xx) && !defined (STM32F415xx) && !defined (STM32F407xx) && !defined (STM32F417xx) && \ - !defined (STM32F427xx) && !defined (STM32F437xx) && !defined (STM32F429xx) && !defined (STM32F439xx) && \ - !defined (STM32F401xC) && !defined (STM32F401xE) && !defined (STM32F410Tx) && !defined (STM32F410Cx) && \ - !defined (STM32F410Rx) && !defined (STM32F411xE) && !defined (STM32F446xx) && !defined (STM32F469xx) && \ - !defined (STM32F479xx) && !defined (STM32F412Cx) && !defined (STM32F412Rx) && !defined (STM32F412Vx) && \ - !defined (STM32F412Zx) && !defined (STM32F413xx) && !defined (STM32F423xx) - /* #define STM32F405xx */ /*!< STM32F405RG, STM32F405VG and STM32F405ZG Devices */ - /* #define STM32F415xx */ /*!< STM32F415RG, STM32F415VG and STM32F415ZG Devices */ - /* #define STM32F407xx */ /*!< STM32F407VG, STM32F407VE, STM32F407ZG, STM32F407ZE, STM32F407IG and STM32F407IE Devices */ - /* #define STM32F417xx */ /*!< STM32F417VG, STM32F417VE, STM32F417ZG, STM32F417ZE, STM32F417IG and STM32F417IE Devices */ - /* #define STM32F427xx */ /*!< STM32F427VG, STM32F427VI, STM32F427ZG, STM32F427ZI, STM32F427IG and STM32F427II Devices */ - /* #define STM32F437xx */ /*!< STM32F437VG, STM32F437VI, STM32F437ZG, STM32F437ZI, STM32F437IG and STM32F437II Devices */ - /* #define STM32F429xx */ /*!< STM32F429VG, STM32F429VI, STM32F429ZG, STM32F429ZI, STM32F429BG, STM32F429BI, STM32F429NG, - STM32F439NI, STM32F429IG and STM32F429II Devices */ - /* #define STM32F439xx */ /*!< STM32F439VG, STM32F439VI, STM32F439ZG, STM32F439ZI, STM32F439BG, STM32F439BI, STM32F439NG, - STM32F439NI, STM32F439IG and STM32F439II Devices */ - /* #define STM32F401xC */ /*!< STM32F401CB, STM32F401CC, STM32F401RB, STM32F401RC, STM32F401VB and STM32F401VC Devices */ - /* #define STM32F401xE */ /*!< STM32F401CD, STM32F401RD, STM32F401VD, STM32F401CE, STM32F401RE and STM32F401VE Devices */ - /* #define STM32F410Tx */ /*!< STM32F410T8 and STM32F410TB Devices */ - /* #define STM32F410Cx */ /*!< STM32F410C8 and STM32F410CB Devices */ - /* #define STM32F410Rx */ /*!< STM32F410R8 and STM32F410RB Devices */ - /* #define STM32F411xE */ /*!< STM32F411CC, STM32F411RC, STM32F411VC, STM32F411CE, STM32F411RE and STM32F411VE Devices */ - /* #define STM32F446xx */ /*!< STM32F446MC, STM32F446ME, STM32F446RC, STM32F446RE, STM32F446VC, STM32F446VE, STM32F446ZC, - and STM32F446ZE Devices */ - /* #define STM32F469xx */ /*!< STM32F469AI, STM32F469II, STM32F469BI, STM32F469NI, STM32F469AG, STM32F469IG, STM32F469BG, - STM32F469NG, STM32F469AE, STM32F469IE, STM32F469BE and STM32F469NE Devices */ - /* #define STM32F479xx */ /*!< STM32F479AI, STM32F479II, STM32F479BI, STM32F479NI, STM32F479AG, STM32F479IG, STM32F479BG - and STM32F479NG Devices */ - /* #define STM32F412Cx */ /*!< STM32F412CEU and STM32F412CGU Devices */ - /* #define STM32F412Zx */ /*!< STM32F412ZET, STM32F412ZGT, STM32F412ZEJ and STM32F412ZGJ Devices */ - /* #define STM32F412Vx */ /*!< STM32F412VET, STM32F412VGT, STM32F412VEH and STM32F412VGH Devices */ - /* #define STM32F412Rx */ /*!< STM32F412RET, STM32F412RGT, STM32F412REY and STM32F412RGY Devices */ - /* #define STM32F413xx */ /*!< STM32F413CH, STM32F413MH, STM32F413RH, STM32F413VH, STM32F413ZH, STM32F413CG, STM32F413MG, - STM32F413RG, STM32F413VG and STM32F413ZG Devices */ - /* #define STM32F423xx */ /*!< STM32F423CH, STM32F423RH, STM32F423VH and STM32F423ZH Devices */ -#endif - -/* Tip: To avoid modifying this file each time you need to switch between these - devices, you can define the device in your toolchain compiler preprocessor. - */ -#if !defined (USE_HAL_DRIVER) -/** - * @brief Comment the line below if you will not use the peripherals drivers. - In this case, these drivers will not be included and the application code will - be based on direct access to peripherals registers - */ - /*#define USE_HAL_DRIVER */ -#endif /* USE_HAL_DRIVER */ - -/** - * @brief CMSIS version number V2.6.0 - */ -#define __STM32F4xx_CMSIS_VERSION_MAIN (0x02U) /*!< [31:24] main version */ -#define __STM32F4xx_CMSIS_VERSION_SUB1 (0x06U) /*!< [23:16] sub1 version */ -#define __STM32F4xx_CMSIS_VERSION_SUB2 (0x00U) /*!< [15:8] sub2 version */ -#define __STM32F4xx_CMSIS_VERSION_RC (0x00U) /*!< [7:0] release candidate */ -#define __STM32F4xx_CMSIS_VERSION ((__STM32F4xx_CMSIS_VERSION_MAIN << 24)\ - |(__STM32F4xx_CMSIS_VERSION_SUB1 << 16)\ - |(__STM32F4xx_CMSIS_VERSION_SUB2 << 8 )\ - |(__STM32F4xx_CMSIS_VERSION)) - -/** - * @} - */ - -/** @addtogroup Device_Included - * @{ - */ - -#if defined(STM32F405xx) - #include "stm32f405xx.h" -#elif defined(STM32F415xx) - #include "stm32f415xx.h" -#elif defined(STM32F407xx) - #include "stm32f407xx.h" -#elif defined(STM32F417xx) - #include "stm32f417xx.h" -#elif defined(STM32F427xx) - #include "stm32f427xx.h" -#elif defined(STM32F437xx) - #include "stm32f437xx.h" -#elif defined(STM32F429xx) - #include "stm32f429xx.h" -#elif defined(STM32F439xx) - #include "stm32f439xx.h" -#elif defined(STM32F401xC) - #include "stm32f401xc.h" -#elif defined(STM32F401xE) - #include "stm32f401xe.h" -#elif defined(STM32F410Tx) - #include "stm32f410tx.h" -#elif defined(STM32F410Cx) - #include "stm32f410cx.h" -#elif defined(STM32F410Rx) - #include "stm32f410rx.h" -#elif defined(STM32F411xE) - #include "stm32f411xe.h" -#elif defined(STM32F446xx) - #include "stm32f446xx.h" -#elif defined(STM32F469xx) - #include "stm32f469xx.h" -#elif defined(STM32F479xx) - #include "stm32f479xx.h" -#elif defined(STM32F412Cx) - #include "stm32f412cx.h" -#elif defined(STM32F412Zx) - #include "stm32f412zx.h" -#elif defined(STM32F412Rx) - #include "stm32f412rx.h" -#elif defined(STM32F412Vx) - #include "stm32f412vx.h" -#elif defined(STM32F413xx) - #include "stm32f413xx.h" -#elif defined(STM32F423xx) - #include "stm32f423xx.h" -#else - #error "Please select first the target STM32F4xx device used in your application (in stm32f4xx.h file)" -#endif - -/** - * @} - */ - -/** @addtogroup Exported_types - * @{ - */ -typedef enum -{ - RESET = 0U, - SET = !RESET -} FlagStatus, ITStatus; - -typedef enum -{ - DISABLE = 0U, - ENABLE = !DISABLE -} FunctionalState; -#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) - -typedef enum -{ - ERROR = 0U, - SUCCESS = !ERROR -} ErrorStatus; - -/** - * @} - */ - - -/** @addtogroup Exported_macro - * @{ - */ -#define SET_BIT(REG, BIT) ((REG) |= (BIT)) - -#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) - -#define READ_BIT(REG, BIT) ((REG) & (BIT)) - -#define CLEAR_REG(REG) ((REG) = (0x0)) - -#define WRITE_REG(REG, VAL) ((REG) = (VAL)) - -#define READ_REG(REG) ((REG)) - -#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) - -#define POSITION_VAL(VAL) (__CLZ(__RBIT(VAL))) - - -/** - * @} - */ - -#if defined (USE_HAL_DRIVER) - #include "stm32f4xx_hal.h" -#endif /* USE_HAL_DRIVER */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __STM32F4xx_H */ -/** - * @} - */ - -/** - * @} - */ - - - - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/stm32f4xx_hal_def.h b/panda/board/inc/stm32f4xx_hal_def.h deleted file mode 100644 index b77f179a0c..0000000000 --- a/panda/board/inc/stm32f4xx_hal_def.h +++ /dev/null @@ -1,214 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_def.h - * @author MCD Application Team - * @version V1.6.0 - * @date 04-November-2016 - * @brief This file contains HAL common defines, enumeration, macros and - * structures definitions. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_DEF -#define __STM32F4xx_HAL_DEF - -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx.h" -//#include "Legacy/stm32_hal_legacy.h" -//#include - -/* Exported types ------------------------------------------------------------*/ - -/** - * @brief HAL Status structures definition - */ -typedef enum -{ - HAL_OK = 0x00U, - HAL_ERROR = 0x01U, - HAL_BUSY = 0x02U, - HAL_TIMEOUT = 0x03U -} HAL_StatusTypeDef; - -/** - * @brief HAL Lock structures definition - */ -typedef enum -{ - HAL_UNLOCKED = 0x00U, - HAL_LOCKED = 0x01U -} HAL_LockTypeDef; - -/* Exported macro ------------------------------------------------------------*/ -#define HAL_MAX_DELAY 0xFFFFFFFFU - -#define HAL_IS_BIT_SET(REG, BIT) (((REG) & (BIT)) != RESET) -#define HAL_IS_BIT_CLR(REG, BIT) (((REG) & (BIT)) == RESET) - -#define __HAL_LINKDMA(__HANDLE__, __PPP_DMA_FIELD__, __DMA_HANDLE__) \ - do{ \ - (__HANDLE__)->__PPP_DMA_FIELD__ = &(__DMA_HANDLE__); \ - (__DMA_HANDLE__).Parent = (__HANDLE__); \ - } while(0) - -#define UNUSED(x) ((void)(x)) - -/** @brief Reset the Handle's State field. - * @param __HANDLE__: specifies the Peripheral Handle. - * @note This macro can be used for the following purpose: - * - When the Handle is declared as local variable; before passing it as parameter - * to HAL_PPP_Init() for the first time, it is mandatory to use this macro - * to set to 0 the Handle's "State" field. - * Otherwise, "State" field may have any random value and the first time the function - * HAL_PPP_Init() is called, the low level hardware initialization will be missed - * (i.e. HAL_PPP_MspInit() will not be executed). - * - When there is a need to reconfigure the low level hardware: instead of calling - * HAL_PPP_DeInit() then HAL_PPP_Init(), user can make a call to this macro then HAL_PPP_Init(). - * In this later function, when the Handle's "State" field is set to 0, it will execute the function - * HAL_PPP_MspInit() which will reconfigure the low level hardware. - * @retval None - */ -#define __HAL_RESET_HANDLE_STATE(__HANDLE__) ((__HANDLE__)->State = 0U) - -#if (USE_RTOS == 1) - /* Reserved for future use */ - #error "USE_RTOS should be 0 in the current HAL release" -#else - #define __HAL_LOCK(__HANDLE__) \ - do{ \ - if((__HANDLE__)->Lock == HAL_LOCKED) \ - { \ - return HAL_BUSY; \ - } \ - else \ - { \ - (__HANDLE__)->Lock = HAL_LOCKED; \ - } \ - }while (0) - - #define __HAL_UNLOCK(__HANDLE__) \ - do{ \ - (__HANDLE__)->Lock = HAL_UNLOCKED; \ - }while (0) -#endif /* USE_RTOS */ - -#if defined ( __GNUC__ ) - #ifndef __weak - #define __weak __attribute__((weak)) - #endif /* __weak */ - #ifndef __packed - #define __packed __attribute__((__packed__)) - #endif /* __packed */ -#endif /* __GNUC__ */ - - -/* Macro to get variable aligned on 4-bytes, for __ICCARM__ the directive "#pragma data_alignment=4" must be used instead */ -#if defined (__GNUC__) /* GNU Compiler */ - #ifndef __ALIGN_END - #define __ALIGN_END __attribute__ ((aligned (4))) - #endif /* __ALIGN_END */ - #ifndef __ALIGN_BEGIN - #define __ALIGN_BEGIN - #endif /* __ALIGN_BEGIN */ -#else - #ifndef __ALIGN_END - #define __ALIGN_END - #endif /* __ALIGN_END */ - #ifndef __ALIGN_BEGIN - #if defined (__CC_ARM) /* ARM Compiler */ - #define __ALIGN_BEGIN __align(4) - #elif defined (__ICCARM__) /* IAR Compiler */ - #define __ALIGN_BEGIN - #endif /* __CC_ARM */ - #endif /* __ALIGN_BEGIN */ -#endif /* __GNUC__ */ - - -/** - * @brief __RAM_FUNC definition - */ -#if defined ( __CC_ARM ) -/* ARM Compiler - ------------ - RAM functions are defined using the toolchain options. - Functions that are executed in RAM should reside in a separate source module. - Using the 'Options for File' dialog you can simply change the 'Code / Const' - area of a module to a memory space in physical RAM. - Available memory areas are declared in the 'Target' tab of the 'Options for Target' - dialog. -*/ -#define __RAM_FUNC HAL_StatusTypeDef - -#elif defined ( __ICCARM__ ) -/* ICCARM Compiler - --------------- - RAM functions are defined using a specific toolchain keyword "__ramfunc". -*/ -#define __RAM_FUNC __ramfunc HAL_StatusTypeDef - -#elif defined ( __GNUC__ ) -/* GNU Compiler - ------------ - RAM functions are defined using a specific toolchain attribute - "__attribute__((section(".RamFunc")))". -*/ -#define __RAM_FUNC HAL_StatusTypeDef __attribute__((section(".RamFunc"))) - -#endif - -/** - * @brief __NOINLINE definition - */ -#if defined ( __CC_ARM ) || defined ( __GNUC__ ) -/* ARM & GNUCompiler - ---------------- -*/ -#define __NOINLINE __attribute__ ( (noinline) ) - -#elif defined ( __ICCARM__ ) -/* ICCARM Compiler - --------------- -*/ -#define __NOINLINE _Pragma("optimize = no_inline") - -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* ___STM32F4xx_HAL_DEF */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/stm32f4xx_hal_gpio_ex.h b/panda/board/inc/stm32f4xx_hal_gpio_ex.h deleted file mode 100644 index 6c5f34dcb7..0000000000 --- a/panda/board/inc/stm32f4xx_hal_gpio_ex.h +++ /dev/null @@ -1,1591 +0,0 @@ -/** - ****************************************************************************** - * @file stm32f4xx_hal_gpio_ex.h - * @author MCD Application Team - * @version V1.6.0 - * @date 04-November-2016 - * @brief Header file of GPIO HAL Extension module. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/* Define to prevent recursive inclusion -------------------------------------*/ -#ifndef __STM32F4xx_HAL_GPIO_EX_H -#define __STM32F4xx_HAL_GPIO_EX_H - -#ifdef __cplusplus - extern "C" { -#endif - -/* Includes ------------------------------------------------------------------*/ -#include "stm32f4xx_hal_def.h" - -/** @addtogroup STM32F4xx_HAL_Driver - * @{ - */ - -/** @defgroup GPIOEx GPIOEx - * @{ - */ - -/* Exported types ------------------------------------------------------------*/ -/* Exported constants --------------------------------------------------------*/ -/** @defgroup GPIOEx_Exported_Constants GPIO Exported Constants - * @{ - */ - -/** @defgroup GPIO_Alternate_function_selection GPIO Alternate Function Selection - * @{ - */ - -/*------------------------------------------ STM32F429xx/STM32F439xx ---------*/ -#if defined(STM32F429xx) || defined(STM32F439xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */ -#define GPIO_AF5_SPI5 ((uint8_t)0x05U) /* SPI5 Alternate Function mapping */ -#define GPIO_AF5_SPI6 ((uint8_t)0x05U) /* SPI6 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ -#define GPIO_AF6_SAI1 ((uint8_t)0x06U) /* SAI1 Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ -#define GPIO_AF8_UART7 ((uint8_t)0x08U) /* UART7 Alternate Function mapping */ -#define GPIO_AF8_UART8 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_LTDC ((uint8_t)0x09U) /* LCD-TFT Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0x0AU) /* OTG_HS Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FMC ((uint8_t)0x0CU) /* FMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0x0CU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 13 selection - */ -#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */ - -/** - * @brief AF 14 selection - */ -#define GPIO_AF14_LTDC ((uint8_t)0x0EU) /* LCD-TFT Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F429xx || STM32F439xx */ -/*----------------------------------------------------------------------------*/ - -/*---------------------------------- STM32F427xx/STM32F437xx------------------*/ -#if defined(STM32F427xx) || defined(STM32F437xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */ -#define GPIO_AF5_SPI5 ((uint8_t)0x05U) /* SPI5 Alternate Function mapping */ -#define GPIO_AF5_SPI6 ((uint8_t)0x05U) /* SPI6 Alternate Function mapping */ -/** @brief GPIO_Legacy - */ -#define GPIO_AF5_I2S3ext GPIO_AF5_SPI3 /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ -#define GPIO_AF6_SAI1 ((uint8_t)0x06U) /* SAI1 Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ -#define GPIO_AF8_UART7 ((uint8_t)0x08U) /* UART7 Alternate Function mapping */ -#define GPIO_AF8_UART8 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0x0AU) /* OTG_HS Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FMC ((uint8_t)0x0CU) /* FMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0x0CU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 13 selection - */ -#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F427xx || STM32F437xx */ -/*----------------------------------------------------------------------------*/ - -/*---------------------------------- STM32F407xx/STM32F417xx------------------*/ -#if defined(STM32F407xx) || defined(STM32F417xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0x0AU) /* OTG_HS Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FSMC ((uint8_t)0x0CU) /* FSMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0x0CU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 13 selection - */ -#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F407xx || STM32F417xx */ -/*----------------------------------------------------------------------------*/ - -/*---------------------------------- STM32F405xx/STM32F415xx------------------*/ -#if defined(STM32F405xx) || defined(STM32F415xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0x0AU) /* OTG_HS Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FSMC ((uint8_t)0x0CU) /* FSMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0x0CU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F405xx || STM32F415xx */ - -/*----------------------------------------------------------------------------*/ - -/*---------------------------------------- STM32F401xx------------------------*/ -#if defined(STM32F401xC) || defined(STM32F401xE) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_I2C2 ((uint8_t)0x09U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF9_I2C3 ((uint8_t)0x09U) /* I2C3 Alternate Function mapping */ - - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F401xC || STM32F401xE */ -/*----------------------------------------------------------------------------*/ - -/*--------------- STM32F412Zx/STM32F412Vx/STM32F412Rx/STM32F412Cx-------------*/ -#if defined(STM32F412Zx) || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ -#define GPIO_AF4_FMPI2C1 ((uint8_t)0x04U) /* FMPI2C1 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1/I2S1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4/I2S4 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI2 ((uint8_t)0x06U) /* I2S2 Alternate Function mapping */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_SPI4 ((uint8_t)0x06U) /* SPI4/I2S4 Alternate Function mapping */ -#define GPIO_AF6_SPI5 ((uint8_t)0x06U) /* SPI5/I2S5 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ -#define GPIO_AF6_DFSDM1 ((uint8_t)0x06U) /* DFSDM1 Alternate Function mapping */ -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_SPI3 ((uint8_t)0x07U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ -#define GPIO_AF8_USART3 ((uint8_t)0x08U) /* USART3 Alternate Function mapping */ -#define GPIO_AF8_DFSDM1 ((uint8_t)0x08U) /* DFSDM1 Alternate Function mapping */ -#define GPIO_AF8_CAN1 ((uint8_t)0x08U) /* CAN1 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_I2C2 ((uint8_t)0x09U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF9_I2C3 ((uint8_t)0x09U) /* I2C3 Alternate Function mapping */ -#define GPIO_AF9_FMPI2C1 ((uint8_t)0x09U) /* FMPI2C1 Alternate Function mapping */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_QSPI ((uint8_t)0x09U) /* QSPI Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_DFSDM1 ((uint8_t)0x0AU) /* DFSDM1 Alternate Function mapping */ -#define GPIO_AF10_QSPI ((uint8_t)0x0AU) /* QSPI Alternate Function mapping */ -#define GPIO_AF10_FMC ((uint8_t)0x0AU) /* FMC Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ -#define GPIO_AF12_FSMC ((uint8_t)0x0CU) /* FMC Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx */ - -/*----------------------------------------------------------------------------*/ - -/*--------------- STM32F413xx/STM32F423xx-------------------------------------*/ -#if defined(STM32F413xx) || defined(STM32F423xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ -#define GPIO_AF1_LPTIM1 ((uint8_t)0x01U) /* LPTIM1 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ -#define GPIO_AF3_DFSDM2 ((uint8_t)0x03U) /* DFSDM2 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ -#define GPIO_AF4_FMPI2C1 ((uint8_t)0x04U) /* FMPI2C1 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1/I2S1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4/I2S4 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI2 ((uint8_t)0x06U) /* I2S2 Alternate Function mapping */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_SPI4 ((uint8_t)0x06U) /* SPI4/I2S4 Alternate Function mapping */ -#define GPIO_AF6_SPI5 ((uint8_t)0x06U) /* SPI5/I2S5 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ -#define GPIO_AF6_DFSDM1 ((uint8_t)0x06U) /* DFSDM1 Alternate Function mapping */ -#define GPIO_AF6_DFSDM2 ((uint8_t)0x06U) /* DFSDM2 Alternate Function mapping */ -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_SPI3 ((uint8_t)0x07U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF7_SAI1 ((uint8_t)0x07U) /* SAI1 Alternate Function mapping */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ -#define GPIO_AF7_DFSDM2 ((uint8_t)0x07U) /* DFSDM2 Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ -#define GPIO_AF8_USART3 ((uint8_t)0x08U) /* USART3 Alternate Function mapping */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_UART7 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */ -#define GPIO_AF8_UART8 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */ -#define GPIO_AF8_DFSDM1 ((uint8_t)0x08U) /* DFSDM1 Alternate Function mapping */ -#define GPIO_AF8_CAN1 ((uint8_t)0x08U) /* CAN1 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_I2C2 ((uint8_t)0x09U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF9_I2C3 ((uint8_t)0x09U) /* I2C3 Alternate Function mapping */ -#define GPIO_AF9_FMPI2C1 ((uint8_t)0x09U) /* FMPI2C1 Alternate Function mapping */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_QSPI ((uint8_t)0x09U) /* QSPI Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_SAI1 ((uint8_t)0x0AU) /* SAI1 Alternate Function mapping */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_DFSDM1 ((uint8_t)0x0AU) /* DFSDM1 Alternate Function mapping */ -#define GPIO_AF10_DFSDM2 ((uint8_t)0x0AU) /* DFSDM2 Alternate Function mapping */ -#define GPIO_AF10_QSPI ((uint8_t)0x0AU) /* QSPI Alternate Function mapping */ -#define GPIO_AF10_FSMC ((uint8_t)0x0AU) /* FSMC Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#define GPIO_AF11_UART4 ((uint8_t)0x0BU) /* UART4 Alternate Function mapping */ -#define GPIO_AF11_UART5 ((uint8_t)0x0BU) /* UART5 Alternate Function mapping */ -#define GPIO_AF11_UART9 ((uint8_t)0x0BU) /* UART9 Alternate Function mapping */ -#define GPIO_AF11_UART10 ((uint8_t)0x0BU) /* UART10 Alternate Function mapping */ -#define GPIO_AF11_CAN3 ((uint8_t)0x0BU) /* CAN3 Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ -#define GPIO_AF12_FSMC ((uint8_t)0x0CU) /* FMC Alternate Function mapping */ - -/** - * @brief AF 14 selection - */ -#define GPIO_AF14_RNG ((uint8_t)0x0EU) /* RNG Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F413xx || STM32F423xx */ - -/*---------------------------------------- STM32F411xx------------------------*/ -#if defined(STM32F411xE) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1/I2S1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI2 ((uint8_t)0x06U) /* I2S2 Alternate Function mapping */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_SPI4 ((uint8_t)0x06U) /* SPI4/I2S4 Alternate Function mapping */ -#define GPIO_AF6_SPI5 ((uint8_t)0x06U) /* SPI5/I2S5 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_SPI3 ((uint8_t)0x07U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_I2C2 ((uint8_t)0x09U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF9_I2C3 ((uint8_t)0x09U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F411xE */ - -/*---------------------------------------- STM32F410xx------------------------*/ -#if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_LPTIM1 ((uint8_t)0x01U) /* LPTIM1 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_FMPI2C1 ((uint8_t)0x04U) /* FMPI2C1 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1/I2S1 Alternate Function mapping */ -#if defined(STM32F410Cx) || defined(STM32F410Rx) -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#endif /* STM32F410Cx || STM32F410Rx */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI1 ((uint8_t)0x06U) /* SPI1 Alternate Function mapping */ -#if defined(STM32F410Cx) || defined(STM32F410Rx) -#define GPIO_AF6_SPI2 ((uint8_t)0x06U) /* I2S2 Alternate Function mapping */ -#endif /* STM32F410Cx || STM32F410Rx */ -#define GPIO_AF6_SPI5 ((uint8_t)0x06U) /* SPI5/I2S5 Alternate Function mapping */ -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_I2C2 ((uint8_t)0x09U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF9_FMPI2C1 ((uint8_t)0x09U) /* FMPI2C1 Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ -#endif /* STM32F410Tx || STM32F410Cx || STM32F410Rx */ - -/*---------------------------------------- STM32F446xx -----------------------*/ -#if defined(STM32F446xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ -#define GPIO_AF3_CEC ((uint8_t)0x03U) /* CEC Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ -#define GPIO_AF4_FMPI2C1 ((uint8_t)0x04U) /* FMPI2C1 Alternate Function mapping */ -#define GPIO_AF4_CEC ((uint8_t)0x04U) /* CEC Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1/I2S1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI2 ((uint8_t)0x06U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_SPI4 ((uint8_t)0x06U) /* SPI4 Alternate Function mapping */ -#define GPIO_AF6_SAI1 ((uint8_t)0x06U) /* SAI1 Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_UART5 ((uint8_t)0x07U) /* UART5 Alternate Function mapping */ -#define GPIO_AF7_SPI2 ((uint8_t)0x07U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF7_SPI3 ((uint8_t)0x07U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF7_SPDIFRX ((uint8_t)0x07U) /* SPDIFRX Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ -#define GPIO_AF8_SPDIFRX ((uint8_t)0x08U) /* SPDIFRX Alternate Function mapping */ -#define GPIO_AF8_SAI2 ((uint8_t)0x08U) /* SAI2 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_QSPI ((uint8_t)0x09U) /* QSPI Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0x0AU) /* OTG_HS Alternate Function mapping */ -#define GPIO_AF10_SAI2 ((uint8_t)0x0AU) /* SAI2 Alternate Function mapping */ -#define GPIO_AF10_QSPI ((uint8_t)0x0AU) /* QSPI Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FMC ((uint8_t)0x0CU) /* FMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0x0CU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 13 selection - */ -#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ - -#endif /* STM32F446xx */ -/*----------------------------------------------------------------------------*/ - -/*-------------------------------- STM32F469xx/STM32F479xx--------------------*/ -#if defined(STM32F469xx) || defined(STM32F479xx) -/** - * @brief AF 0 selection - */ -#define GPIO_AF0_RTC_50Hz ((uint8_t)0x00U) /* RTC_50Hz Alternate Function mapping */ -#define GPIO_AF0_MCO ((uint8_t)0x00U) /* MCO (MCO1 and MCO2) Alternate Function mapping */ -#define GPIO_AF0_TAMPER ((uint8_t)0x00U) /* TAMPER (TAMPER_1 and TAMPER_2) Alternate Function mapping */ -#define GPIO_AF0_SWJ ((uint8_t)0x00U) /* SWJ (SWD and JTAG) Alternate Function mapping */ -#define GPIO_AF0_TRACE ((uint8_t)0x00U) /* TRACE Alternate Function mapping */ - -/** - * @brief AF 1 selection - */ -#define GPIO_AF1_TIM1 ((uint8_t)0x01U) /* TIM1 Alternate Function mapping */ -#define GPIO_AF1_TIM2 ((uint8_t)0x01U) /* TIM2 Alternate Function mapping */ - -/** - * @brief AF 2 selection - */ -#define GPIO_AF2_TIM3 ((uint8_t)0x02U) /* TIM3 Alternate Function mapping */ -#define GPIO_AF2_TIM4 ((uint8_t)0x02U) /* TIM4 Alternate Function mapping */ -#define GPIO_AF2_TIM5 ((uint8_t)0x02U) /* TIM5 Alternate Function mapping */ - -/** - * @brief AF 3 selection - */ -#define GPIO_AF3_TIM8 ((uint8_t)0x03U) /* TIM8 Alternate Function mapping */ -#define GPIO_AF3_TIM9 ((uint8_t)0x03U) /* TIM9 Alternate Function mapping */ -#define GPIO_AF3_TIM10 ((uint8_t)0x03U) /* TIM10 Alternate Function mapping */ -#define GPIO_AF3_TIM11 ((uint8_t)0x03U) /* TIM11 Alternate Function mapping */ - -/** - * @brief AF 4 selection - */ -#define GPIO_AF4_I2C1 ((uint8_t)0x04U) /* I2C1 Alternate Function mapping */ -#define GPIO_AF4_I2C2 ((uint8_t)0x04U) /* I2C2 Alternate Function mapping */ -#define GPIO_AF4_I2C3 ((uint8_t)0x04U) /* I2C3 Alternate Function mapping */ - -/** - * @brief AF 5 selection - */ -#define GPIO_AF5_SPI1 ((uint8_t)0x05U) /* SPI1 Alternate Function mapping */ -#define GPIO_AF5_SPI2 ((uint8_t)0x05U) /* SPI2/I2S2 Alternate Function mapping */ -#define GPIO_AF5_SPI3 ((uint8_t)0x05U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF5_SPI4 ((uint8_t)0x05U) /* SPI4 Alternate Function mapping */ -#define GPIO_AF5_SPI5 ((uint8_t)0x05U) /* SPI5 Alternate Function mapping */ -#define GPIO_AF5_SPI6 ((uint8_t)0x05U) /* SPI6 Alternate Function mapping */ -#define GPIO_AF5_I2S3ext ((uint8_t)0x05U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 6 selection - */ -#define GPIO_AF6_SPI3 ((uint8_t)0x06U) /* SPI3/I2S3 Alternate Function mapping */ -#define GPIO_AF6_I2S2ext ((uint8_t)0x06U) /* I2S2ext_SD Alternate Function mapping */ -#define GPIO_AF6_SAI1 ((uint8_t)0x06U) /* SAI1 Alternate Function mapping */ - -/** - * @brief AF 7 selection - */ -#define GPIO_AF7_USART1 ((uint8_t)0x07U) /* USART1 Alternate Function mapping */ -#define GPIO_AF7_USART2 ((uint8_t)0x07U) /* USART2 Alternate Function mapping */ -#define GPIO_AF7_USART3 ((uint8_t)0x07U) /* USART3 Alternate Function mapping */ -#define GPIO_AF7_I2S3ext ((uint8_t)0x07U) /* I2S3ext_SD Alternate Function mapping */ - -/** - * @brief AF 8 selection - */ -#define GPIO_AF8_UART4 ((uint8_t)0x08U) /* UART4 Alternate Function mapping */ -#define GPIO_AF8_UART5 ((uint8_t)0x08U) /* UART5 Alternate Function mapping */ -#define GPIO_AF8_USART6 ((uint8_t)0x08U) /* USART6 Alternate Function mapping */ -#define GPIO_AF8_UART7 ((uint8_t)0x08U) /* UART7 Alternate Function mapping */ -#define GPIO_AF8_UART8 ((uint8_t)0x08U) /* UART8 Alternate Function mapping */ - -/** - * @brief AF 9 selection - */ -#define GPIO_AF9_CAN1 ((uint8_t)0x09U) /* CAN1 Alternate Function mapping */ -#define GPIO_AF9_CAN2 ((uint8_t)0x09U) /* CAN2 Alternate Function mapping */ -#define GPIO_AF9_TIM12 ((uint8_t)0x09U) /* TIM12 Alternate Function mapping */ -#define GPIO_AF9_TIM13 ((uint8_t)0x09U) /* TIM13 Alternate Function mapping */ -#define GPIO_AF9_TIM14 ((uint8_t)0x09U) /* TIM14 Alternate Function mapping */ -#define GPIO_AF9_LTDC ((uint8_t)0x09U) /* LCD-TFT Alternate Function mapping */ -#define GPIO_AF9_QSPI ((uint8_t)0x09U) /* QSPI Alternate Function mapping */ - -/** - * @brief AF 10 selection - */ -#define GPIO_AF10_OTG_FS ((uint8_t)0x0AU) /* OTG_FS Alternate Function mapping */ -#define GPIO_AF10_OTG_HS ((uint8_t)0x0AU) /* OTG_HS Alternate Function mapping */ -#define GPIO_AF10_QSPI ((uint8_t)0x0AU) /* QSPI Alternate Function mapping */ - -/** - * @brief AF 11 selection - */ -#define GPIO_AF11_ETH ((uint8_t)0x0BU) /* ETHERNET Alternate Function mapping */ - -/** - * @brief AF 12 selection - */ -#define GPIO_AF12_FMC ((uint8_t)0x0CU) /* FMC Alternate Function mapping */ -#define GPIO_AF12_OTG_HS_FS ((uint8_t)0x0CU) /* OTG HS configured in FS, Alternate Function mapping */ -#define GPIO_AF12_SDIO ((uint8_t)0x0CU) /* SDIO Alternate Function mapping */ - -/** - * @brief AF 13 selection - */ -#define GPIO_AF13_DCMI ((uint8_t)0x0DU) /* DCMI Alternate Function mapping */ -#define GPIO_AF13_DSI ((uint8_t)0x0DU) /* DSI Alternate Function mapping */ - -/** - * @brief AF 14 selection - */ -#define GPIO_AF14_LTDC ((uint8_t)0x0EU) /* LCD-TFT Alternate Function mapping */ - -/** - * @brief AF 15 selection - */ -#define GPIO_AF15_EVENTOUT ((uint8_t)0x0FU) /* EVENTOUT Alternate Function mapping */ - -#endif /* STM32F469xx || STM32F479xx */ -/*----------------------------------------------------------------------------*/ -/** - * @} - */ - -/** - * @} - */ - -/* Exported macro ------------------------------------------------------------*/ -/** @defgroup GPIOEx_Exported_Macros GPIO Exported Macros - * @{ - */ -/** - * @} - */ - -/* Exported functions --------------------------------------------------------*/ -/** @defgroup GPIOEx_Exported_Functions GPIO Exported Functions - * @{ - */ -/** - * @} - */ - -/* Private types -------------------------------------------------------------*/ -/* Private variables ---------------------------------------------------------*/ -/* Private constants ---------------------------------------------------------*/ -/** @defgroup GPIOEx_Private_Constants GPIO Private Constants - * @{ - */ -/** - * @} - */ - -/* Private macros ------------------------------------------------------------*/ -/** @defgroup GPIOEx_Private_Macros GPIO Private Macros - * @{ - */ -/** @defgroup GPIOEx_Get_Port_Index GPIO Get Port Index - * @{ - */ -#if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx) -#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\ - ((__GPIOx__) == (GPIOB))? 1U :\ - ((__GPIOx__) == (GPIOC))? 2U :\ - ((__GPIOx__) == (GPIOD))? 3U :\ - ((__GPIOx__) == (GPIOE))? 4U :\ - ((__GPIOx__) == (GPIOF))? 5U :\ - ((__GPIOx__) == (GPIOG))? 6U :\ - ((__GPIOx__) == (GPIOH))? 7U : 8U) -#endif /* STM32F405xx || STM32F415xx || STM32F407xx || STM32F417xx */ - -#if defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx) ||\ - defined(STM32F469xx) || defined(STM32F479xx) -#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\ - ((__GPIOx__) == (GPIOB))? 1U :\ - ((__GPIOx__) == (GPIOC))? 2U :\ - ((__GPIOx__) == (GPIOD))? 3U :\ - ((__GPIOx__) == (GPIOE))? 4U :\ - ((__GPIOx__) == (GPIOF))? 5U :\ - ((__GPIOx__) == (GPIOG))? 6U :\ - ((__GPIOx__) == (GPIOH))? 7U :\ - ((__GPIOx__) == (GPIOI))? 8U :\ - ((__GPIOx__) == (GPIOJ))? 9U : 10U) -#endif /* STM32F427xx || STM32F437xx || STM32F429xx || STM32F439xx || STM32F469xx || STM32F479xx */ - -#if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) -#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\ - ((__GPIOx__) == (GPIOB))? 1U :\ - ((__GPIOx__) == (GPIOC))? 2U : 7U) -#endif /* STM32F410Tx || STM32F410Cx || STM32F410Rx */ - -#if defined(STM32F401xC) || defined(STM32F401xE) || defined(STM32F411xE) -#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\ - ((__GPIOx__) == (GPIOB))? 1U :\ - ((__GPIOx__) == (GPIOC))? 2U :\ - ((__GPIOx__) == (GPIOD))? 3U :\ - ((__GPIOx__) == (GPIOE))? 4U : 7U) -#endif /* STM32F401xC || STM32F401xE || STM32F411xE */ - -#if defined(STM32F446xx) || defined(STM32F412Zx) ||defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) || defined(STM32F413xx) || defined(STM32F423xx) -#define GPIO_GET_INDEX(__GPIOx__) (uint8_t)(((__GPIOx__) == (GPIOA))? 0U :\ - ((__GPIOx__) == (GPIOB))? 1U :\ - ((__GPIOx__) == (GPIOC))? 2U :\ - ((__GPIOx__) == (GPIOD))? 3U :\ - ((__GPIOx__) == (GPIOE))? 4U :\ - ((__GPIOx__) == (GPIOF))? 5U :\ - ((__GPIOx__) == (GPIOG))? 6U : 7U) -#endif /* STM32F446xx || STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx || STM32F413xx || STM32F423xx */ - -/** - * @} - */ - -/** @defgroup GPIOEx_IS_Alternat_function_selection GPIO Check Alternate Function - * @{ - */ -/*------------------------- STM32F429xx/STM32F439xx---------------------------*/ -#if defined(STM32F429xx) || defined(STM32F439xx) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF11_ETH) || ((AF) == GPIO_AF12_OTG_HS_FS) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF13_DCMI) || \ - ((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF5_SPI4) || \ - ((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \ - ((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \ - ((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF6_SAI1) || \ - ((AF) == GPIO_AF14_LTDC)) - -#endif /* STM32F429xx || STM32F439xx */ -/*----------------------------------------------------------------------------*/ - -/*---------------------------------- STM32F427xx/STM32F437xx------------------*/ -#if defined(STM32F427xx) || defined(STM32F437xx) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF11_ETH) || ((AF) == GPIO_AF12_OTG_HS_FS) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF13_DCMI) || \ - ((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF5_SPI4) || \ - ((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \ - ((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \ - ((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF6_SAI1)) - -#endif /* STM32F427xx || STM32F437xx */ -/*----------------------------------------------------------------------------*/ - -/*---------------------------------- STM32F407xx/STM32F417xx------------------*/ -#if defined(STM32F407xx) || defined(STM32F417xx) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF11_ETH) || ((AF) == GPIO_AF12_OTG_HS_FS) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF13_DCMI) || \ - ((AF) == GPIO_AF12_FSMC) || ((AF) == GPIO_AF15_EVENTOUT)) - -#endif /* STM32F407xx || STM32F417xx */ -/*----------------------------------------------------------------------------*/ - -/*---------------------------------- STM32F405xx/STM32F415xx------------------*/ -#if defined(STM32F405xx) || defined(STM32F415xx) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF12_OTG_HS_FS) || ((AF) == GPIO_AF12_SDIO) || \ - ((AF) == GPIO_AF12_FSMC) || ((AF) == GPIO_AF15_EVENTOUT)) - -#endif /* STM32F405xx || STM32F415xx */ - -/*----------------------------------------------------------------------------*/ - -/*---------------------------------------- STM32F401xx------------------------*/ -#if defined(STM32F401xC) || defined(STM32F401xE) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF4_I2C1) || \ - ((AF) == GPIO_AF4_I2C2) || ((AF) == GPIO_AF4_I2C3) || \ - ((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF5_SPI4) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF8_USART6) || ((AF) == GPIO_AF10_OTG_FS) || \ - ((AF) == GPIO_AF9_I2C2) || ((AF) == GPIO_AF9_I2C3) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF15_EVENTOUT)) - -#endif /* STM32F401xC || STM32F401xE */ -/*----------------------------------------------------------------------------*/ -/*---------------------------------------- STM32F410xx------------------------*/ -#if defined(STM32F410Tx) || defined(STM32F410Cx) || defined(STM32F410Rx) -#define IS_GPIO_AF(AF) (((AF) < 10U) || ((AF) == 15U)) -#endif /* STM32F410Tx || STM32F410Cx || STM32F410Rx */ - -/*---------------------------------------- STM32F411xx------------------------*/ -#if defined(STM32F411xE) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF4_I2C1) || \ - ((AF) == GPIO_AF4_I2C2) || ((AF) == GPIO_AF4_I2C3) || \ - ((AF) == GPIO_AF5_SPI1) || ((AF) == GPIO_AF5_SPI2) || \ - ((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF6_SPI4) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF5_SPI4) || \ - ((AF) == GPIO_AF6_SPI5) || ((AF) == GPIO_AF7_SPI3) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF8_USART6) || ((AF) == GPIO_AF10_OTG_FS) || \ - ((AF) == GPIO_AF9_I2C2) || ((AF) == GPIO_AF9_I2C3) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF15_EVENTOUT)) - -#endif /* STM32F411xE */ -/*----------------------------------------------------------------------------*/ - -/*----------------------------------------------- STM32F446xx ----------------*/ -#if defined(STM32F446xx) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF11_ETH) || ((AF) == GPIO_AF12_OTG_HS_FS) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF13_DCMI) || \ - ((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF5_SPI4) || \ - ((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF6_SAI1) || \ - ((AF) == GPIO_AF3_CEC) || ((AF) == GPIO_AF4_CEC) || \ - ((AF) == GPIO_AF5_SPI3) || ((AF) == GPIO_AF6_SPI2) || \ - ((AF) == GPIO_AF6_SPI4) || ((AF) == GPIO_AF7_UART5) || \ - ((AF) == GPIO_AF7_SPI2) || ((AF) == GPIO_AF7_SPI3) || \ - ((AF) == GPIO_AF7_SPDIFRX) || ((AF) == GPIO_AF8_SPDIFRX) || \ - ((AF) == GPIO_AF8_SAI2) || ((AF) == GPIO_AF9_QSPI) || \ - ((AF) == GPIO_AF10_SAI2) || ((AF) == GPIO_AF10_QSPI)) - -#endif /* STM32F446xx */ -/*----------------------------------------------------------------------------*/ - -/*------------------------------------------- STM32F469xx/STM32F479xx --------*/ -#if defined(STM32F469xx) || defined(STM32F479xx) -#define IS_GPIO_AF(AF) (((AF) == GPIO_AF0_RTC_50Hz) || ((AF) == GPIO_AF9_TIM14) || \ - ((AF) == GPIO_AF0_MCO) || ((AF) == GPIO_AF0_TAMPER) || \ - ((AF) == GPIO_AF0_SWJ) || ((AF) == GPIO_AF0_TRACE) || \ - ((AF) == GPIO_AF1_TIM1) || ((AF) == GPIO_AF1_TIM2) || \ - ((AF) == GPIO_AF2_TIM3) || ((AF) == GPIO_AF2_TIM4) || \ - ((AF) == GPIO_AF2_TIM5) || ((AF) == GPIO_AF3_TIM8) || \ - ((AF) == GPIO_AF4_I2C1) || ((AF) == GPIO_AF4_I2C2) || \ - ((AF) == GPIO_AF4_I2C3) || ((AF) == GPIO_AF5_SPI1) || \ - ((AF) == GPIO_AF5_SPI2) || ((AF) == GPIO_AF9_TIM13) || \ - ((AF) == GPIO_AF6_SPI3) || ((AF) == GPIO_AF9_TIM12) || \ - ((AF) == GPIO_AF7_USART1) || ((AF) == GPIO_AF7_USART2) || \ - ((AF) == GPIO_AF7_USART3) || ((AF) == GPIO_AF8_UART4) || \ - ((AF) == GPIO_AF8_UART5) || ((AF) == GPIO_AF8_USART6) || \ - ((AF) == GPIO_AF9_CAN1) || ((AF) == GPIO_AF9_CAN2) || \ - ((AF) == GPIO_AF10_OTG_FS) || ((AF) == GPIO_AF10_OTG_HS) || \ - ((AF) == GPIO_AF11_ETH) || ((AF) == GPIO_AF12_OTG_HS_FS) || \ - ((AF) == GPIO_AF12_SDIO) || ((AF) == GPIO_AF13_DCMI) || \ - ((AF) == GPIO_AF15_EVENTOUT) || ((AF) == GPIO_AF5_SPI4) || \ - ((AF) == GPIO_AF5_SPI5) || ((AF) == GPIO_AF5_SPI6) || \ - ((AF) == GPIO_AF8_UART7) || ((AF) == GPIO_AF8_UART8) || \ - ((AF) == GPIO_AF12_FMC) || ((AF) == GPIO_AF6_SAI1) || \ - ((AF) == GPIO_AF14_LTDC) || ((AF) == GPIO_AF13_DSI) || \ - ((AF) == GPIO_AF9_QSPI) || ((AF) == GPIO_AF10_QSPI)) - -#endif /* STM32F469xx || STM32F479xx */ -/*----------------------------------------------------------------------------*/ - -/*------------------STM32F412Zx/STM32F412Vx/STM32F412Rx/STM32F412Cx-----------*/ -#if defined(STM32F412Zx) || defined(STM32F412Vx) || defined(STM32F412Rx) || defined(STM32F412Cx) -#define IS_GPIO_AF(AF) (((AF) < 16U) && ((AF) != 11U) && ((AF) != 14U) && ((AF) != 13U)) -#endif /* STM32F412Zx || STM32F412Vx || STM32F412Rx || STM32F412Cx */ -/*----------------------------------------------------------------------------*/ - -/*------------------STM32F413xx/STM32F423xx-----------------------------------*/ -#if defined(STM32F413xx) || defined(STM32F423xx) -#define IS_GPIO_AF(AF) (((AF) < 16U) && ((AF) != 13U)) -#endif /* STM32F413xx || STM32F423xx */ -/*----------------------------------------------------------------------------*/ - -/** - * @} - */ - -/** - * @} - */ - -/* Private functions ---------------------------------------------------------*/ -/** @defgroup GPIOEx_Private_Functions GPIO Private Functions - * @{ - */ - -/** - * @} - */ - -/** - * @} - */ - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /* __STM32F4xx_HAL_GPIO_EX_H */ - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/system_stm32f2xx.h b/panda/board/inc/system_stm32f2xx.h deleted file mode 100644 index cd4b83c570..0000000000 --- a/panda/board/inc/system_stm32f2xx.h +++ /dev/null @@ -1,122 +0,0 @@ -/** - ****************************************************************************** - * @file system_stm32f2xx.h - * @author MCD Application Team - * @version V2.1.2 - * @date 29-June-2016 - * @brief CMSIS Cortex-M3 Device System Source File for STM32F2xx devices. -****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32f2xx_system - * @{ - */ - -/** - * @brief Define to prevent recursive inclusion - */ -#ifndef __SYSTEM_STM32F2XX_H -#define __SYSTEM_STM32F2XX_H - -#ifdef __cplusplus - extern "C" { -#endif - -/** @addtogroup STM32F2xx_System_Includes - * @{ - */ - -/** - * @} - */ - - -/** @addtogroup STM32F2xx_System_Exported_types - * @{ - */ - /* This variable is updated in three ways: - 1) by calling CMSIS function SystemCoreClockUpdate() - 2) by calling HAL API function HAL_RCC_GetSysClockFreq() - 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency - Note: If you use this function to configure the system clock; then there - is no need to call the 2 first functions listed above, since SystemCoreClock - variable is updated automatically. - */ -extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ - - -/** - * @} - */ - -/** @addtogroup STM32F2xx_System_Exported_Constants - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32F2xx_System_Exported_Macros - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32F2xx_System_Exported_Functions - * @{ - */ - -extern void SystemInit(void); -extern void SystemCoreClockUpdate(void); -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /*__SYSTEM_STM32F2XX_H */ - -/** - * @} - */ - -/** - * @} - */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/inc/system_stm32f4xx.h b/panda/board/inc/system_stm32f4xx.h deleted file mode 100644 index 7978dab458..0000000000 --- a/panda/board/inc/system_stm32f4xx.h +++ /dev/null @@ -1,124 +0,0 @@ -/** - ****************************************************************************** - * @file system_stm32f4xx.h - * @author MCD Application Team - * @version V2.6.0 - * @date 04-November-2016 - * @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT(c) 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - -/** @addtogroup CMSIS - * @{ - */ - -/** @addtogroup stm32f4xx_system - * @{ - */ - -/** - * @brief Define to prevent recursive inclusion - */ -#ifndef __SYSTEM_STM32F4XX_H -#define __SYSTEM_STM32F4XX_H - -#ifdef __cplusplus - extern "C" { -#endif - -/** @addtogroup STM32F4xx_System_Includes - * @{ - */ - -/** - * @} - */ - - -/** @addtogroup STM32F4xx_System_Exported_types - * @{ - */ - /* This variable is updated in three ways: - 1) by calling CMSIS function SystemCoreClockUpdate() - 2) by calling HAL API function HAL_RCC_GetSysClockFreq() - 3) each time HAL_RCC_ClockConfig() is called to configure the system clock frequency - Note: If you use this function to configure the system clock; then there - is no need to call the 2 first functions listed above, since SystemCoreClock - variable is updated automatically. - */ -extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */ - -extern const uint8_t AHBPrescTable[16]; /*!< AHB prescalers table values */ -extern const uint8_t APBPrescTable[8]; /*!< APB prescalers table values */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Exported_Constants - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Exported_Macros - * @{ - */ - -/** - * @} - */ - -/** @addtogroup STM32F4xx_System_Exported_Functions - * @{ - */ - -extern void SystemInit(void); -extern void SystemCoreClockUpdate(void); -/** - * @} - */ - -#ifdef __cplusplus -} -#endif - -#endif /*__SYSTEM_STM32F4XX_H */ - -/** - * @} - */ - -/** - * @} - */ -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/libc.h b/panda/board/libc.h deleted file mode 100644 index 67411fbb31..0000000000 --- a/panda/board/libc.h +++ /dev/null @@ -1,42 +0,0 @@ -// **** libc **** - -void delay(int a) { - volatile int i; - for (i = 0; i < a; i++); -} - -void *memset(void *str, int c, unsigned int n) { - uint8_t *s = str; - for (unsigned int i = 0; i < n; i++) { - *s = c; - s++; - } - return str; -} - -void *memcpy(void *dest, const void *src, unsigned int n) { - uint8_t *d = dest; - const uint8_t *s = src; - for (unsigned int i = 0; i < n; i++) { - *d = *s; - d++; - s++; - } - return dest; -} - -int memcmp(const void * ptr1, const void * ptr2, unsigned int num) { - int ret = 0; - const uint8_t *p1 = ptr1; - const uint8_t *p2 = ptr2; - for (unsigned int i = 0; i < num; i++) { - if (*p1 != *p2) { - ret = -1; - break; - } - p1++; - p2++; - } - return ret; -} - diff --git a/panda/board/main.c b/panda/board/main.c deleted file mode 100644 index dd4edb33d1..0000000000 --- a/panda/board/main.c +++ /dev/null @@ -1,872 +0,0 @@ -//#define EON -//#define PANDA - -// ********************* Includes ********************* -#include "config.h" -#include "obj/gitversion.h" - -#include "main_declarations.h" -#include "critical.h" - -#include "libc.h" -#include "provision.h" -#include "faults.h" - -#include "drivers/registers.h" -#include "drivers/interrupts.h" - -#include "drivers/llcan.h" -#include "drivers/llgpio.h" -#include "drivers/adc.h" -#include "drivers/pwm.h" - -#include "board.h" - -#include "drivers/uart.h" -#include "drivers/usb.h" -#include "drivers/gmlan_alt.h" -#include "drivers/timer.h" -#include "drivers/clock.h" - -#include "gpio.h" - -#ifndef EON -#include "drivers/spi.h" -#endif - -#include "power_saving.h" -#include "safety.h" - -#include "drivers/can.h" - -extern int _app_start[0xc000]; // Only first 3 sectors of size 0x4000 are used - -struct __attribute__((packed)) health_t { - uint32_t uptime_pkt; - uint32_t voltage_pkt; - uint32_t current_pkt; - uint32_t can_send_errs_pkt; - uint32_t can_fwd_errs_pkt; - uint32_t gmlan_send_errs_pkt; - uint32_t faults_pkt; - uint8_t ignition_line_pkt; - uint8_t ignition_can_pkt; - uint8_t controls_allowed_pkt; - uint8_t gas_interceptor_detected_pkt; - uint8_t car_harness_status_pkt; - uint8_t usb_power_mode_pkt; - uint8_t safety_mode_pkt; - uint8_t fault_status_pkt; - uint8_t power_save_enabled_pkt; -}; - - -// ********************* Serial debugging ********************* - -bool check_started(void) { - return current_board->check_ignition() || ignition_can; -} - -void debug_ring_callback(uart_ring *ring) { - char rcv; - while (getc(ring, &rcv)) { - (void)putc(ring, rcv); // misra-c2012-17.7: cast to void is ok: debug function - - // only allow bootloader entry on debug builds - #ifdef ALLOW_DEBUG - // jump to DFU flash - if (rcv == 'z') { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - } - #endif - - // normal reset - if (rcv == 'x') { - NVIC_SystemReset(); - } - - // enable CDP mode - if (rcv == 'C') { - puts("switching USB to CDP mode\n"); - current_board->set_usb_power_mode(USB_POWER_CDP); - } - if (rcv == 'c') { - puts("switching USB to client mode\n"); - current_board->set_usb_power_mode(USB_POWER_CLIENT); - } - if (rcv == 'D') { - puts("switching USB to DCP mode\n"); - current_board->set_usb_power_mode(USB_POWER_DCP); - } - } -} - -// ****************************** safety mode ****************************** - -// this is the only way to leave silent mode -void set_safety_mode(uint16_t mode, int16_t param) { - uint16_t mode_copy = mode; - int err = set_safety_hooks(mode_copy, param); - if (err == -1) { - puts("Error: safety set mode failed. Falling back to SILENT\n"); - mode_copy = SAFETY_SILENT; - err = set_safety_hooks(mode_copy, 0); - if (err == -1) { - puts("Error: Failed setting SILENT mode. Hanging\n"); - while (true) { - // TERMINAL ERROR: we can't continue if SILENT safety mode isn't succesfully set - } - } - } - switch (mode_copy) { - case SAFETY_SILENT: - set_intercept_relay(false); - if (board_has_obd()) { - current_board->set_can_mode(CAN_MODE_NORMAL); - } - can_silent = ALL_CAN_SILENT; - break; - case SAFETY_NOOUTPUT: - set_intercept_relay(false); - if (board_has_obd()) { - current_board->set_can_mode(CAN_MODE_NORMAL); - } - can_silent = ALL_CAN_LIVE; - break; - case SAFETY_ELM327: - set_intercept_relay(false); - heartbeat_counter = 0U; - if (board_has_obd()) { - current_board->set_can_mode(CAN_MODE_OBD_CAN2); - } - can_silent = ALL_CAN_LIVE; - break; - default: - set_intercept_relay(true); - heartbeat_counter = 0U; - if (board_has_obd()) { - current_board->set_can_mode(CAN_MODE_NORMAL); - } - can_silent = ALL_CAN_LIVE; - break; - } - can_init_all(); -} - -// ***************************** USB port ***************************** - -int get_health_pkt(void *dat) { - COMPILE_TIME_ASSERT(sizeof(struct health_t) <= MAX_RESP_LEN); - struct health_t * health = (struct health_t*)dat; - - health->uptime_pkt = uptime_cnt; - health->voltage_pkt = adc_get_voltage(); - health->current_pkt = current_board->read_current(); - - //Use the GPIO pin to determine ignition or use a CAN based logic - health->ignition_line_pkt = (uint8_t)(current_board->check_ignition()); - health->ignition_can_pkt = (uint8_t)(ignition_can); - - health->controls_allowed_pkt = controls_allowed; - health->gas_interceptor_detected_pkt = gas_interceptor_detected; - health->can_send_errs_pkt = can_send_errs; - health->can_fwd_errs_pkt = can_fwd_errs; - health->gmlan_send_errs_pkt = gmlan_send_errs; - health->car_harness_status_pkt = car_harness_status; - health->usb_power_mode_pkt = usb_power_mode; - health->safety_mode_pkt = (uint8_t)(current_safety_mode); - health->power_save_enabled_pkt = (uint8_t)(power_save_status == POWER_SAVE_STATUS_ENABLED); - - health->fault_status_pkt = fault_status; - health->faults_pkt = faults; - - return sizeof(*health); -} - -int get_rtc_pkt(void *dat) { - timestamp_t t = rtc_get_time(); - (void)memcpy(dat, &t, sizeof(t)); - return sizeof(t); -} - -int usb_cb_ep1_in(void *usbdata, int len, bool hardwired) { - UNUSED(hardwired); - CAN_FIFOMailBox_TypeDef *reply = (CAN_FIFOMailBox_TypeDef *)usbdata; - int ilen = 0; - while (ilen < MIN(len/0x10, 4) && can_pop(&can_rx_q, &reply[ilen])) { - ilen++; - } - return ilen*0x10; -} - -// send on serial, first byte to select the ring -void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) { - UNUSED(hardwired); - uint8_t *usbdata8 = (uint8_t *)usbdata; - uart_ring *ur = get_ring_by_number(usbdata8[0]); - if ((len != 0) && (ur != NULL)) { - if ((usbdata8[0] < 2U) || safety_tx_lin_hook(usbdata8[0] - 2U, &usbdata8[1], len - 1)) { - for (int i = 1; i < len; i++) { - while (!putc(ur, usbdata8[i])) { - // wait - } - } - } - } -} - -// send on CAN -void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) { - UNUSED(hardwired); - int dpkt = 0; - uint32_t *d32 = (uint32_t *)usbdata; - for (dpkt = 0; dpkt < (len / 4); dpkt += 4) { - CAN_FIFOMailBox_TypeDef to_push; - to_push.RDHR = d32[dpkt + 3]; - to_push.RDLR = d32[dpkt + 2]; - to_push.RDTR = d32[dpkt + 1]; - to_push.RIR = d32[dpkt]; - - uint8_t bus_number = (to_push.RDTR >> 4) & CAN_BUS_NUM_MASK; - can_send(&to_push, bus_number, false); - } -} - -void usb_cb_enumeration_complete() { - puts("USB enumeration complete\n"); - is_enumerated = 1; -} - -int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) { - unsigned int resp_len = 0; - uart_ring *ur = NULL; - int i; - timestamp_t t; - switch (setup->b.bRequest) { - // **** 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 = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xa2: set rtc month - case 0xa2: - t = rtc_get_time(); - t.month = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xa3: set rtc day - case 0xa3: - t = rtc_get_time(); - t.day = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xa4: set rtc weekday - case 0xa4: - t = rtc_get_time(); - t.weekday = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xa5: set rtc hour - case 0xa5: - t = rtc_get_time(); - t.hour = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xa6: set rtc minute - case 0xa6: - t = rtc_get_time(); - t.minute = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xa7: set rtc second - case 0xa7: - t = rtc_get_time(); - t.second = setup->b.wValue.w; - rtc_set_time(t); - break; - // **** 0xb0: set IR power - case 0xb0: - if(power_save_status == POWER_SAVE_STATUS_DISABLED){ - current_board->set_ir_power(setup->b.wValue.w); - } else { - puts("Setting IR power not allowed in power saving mode\n"); - } - break; - // **** 0xb1: set fan power - case 0xb1: - if(power_save_status == POWER_SAVE_STATUS_DISABLED){ - current_board->set_fan_power(setup->b.wValue.w); - } else { - puts("Setting fan power not allowed in power saving mode\n"); - } - break; - // **** 0xb2: get fan rpm - case 0xb2: - resp[0] = (fan_rpm & 0x00FFU); - resp[1] = ((fan_rpm & 0xFF00U) >> 8U); - resp_len = 2; - break; - // **** 0xb3: set phone power - case 0xb3: - current_board->set_phone_power(setup->b.wValue.w > 0U); - break; - // **** 0xc0: get CAN debug info - case 0xc0: - puts("can tx: "); puth(can_tx_cnt); - puts(" txd: "); puth(can_txd_cnt); - puts(" rx: "); puth(can_rx_cnt); - puts(" err: "); puth(can_err_cnt); - puts("\n"); - break; - // **** 0xc1: get hardware type - case 0xc1: - resp[0] = hw_type; - resp_len = 1; - break; - // **** 0xd0: fetch serial number - case 0xd0: - // addresses are OTP - if (setup->b.wValue.w == 1U) { - (void)memcpy(resp, (uint8_t *)0x1fff79c0, 0x10); - resp_len = 0x10; - } else { - get_provision_chunk(resp); - resp_len = PROVISION_CHUNK_LEN; - } - break; - // **** 0xd1: enter bootloader mode - case 0xd1: - // this allows reflashing of the bootstub - // so it's blocked over wifi - switch (setup->b.wValue.w) { - case 0: - // only allow bootloader entry on debug builds - #ifdef ALLOW_DEBUG - if (hardwired) { - puts("-> entering bootloader\n"); - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - } - #endif - break; - case 1: - puts("-> entering softloader\n"); - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - NVIC_SystemReset(); - break; - default: - puts("Bootloader mode invalid\n"); - break; - } - break; - // **** 0xd2: get health packet - case 0xd2: - resp_len = get_health_pkt(resp); - break; - // **** 0xd3: get first 64 bytes of signature - case 0xd3: - { - resp_len = 64; - char * code = (char*)_app_start; - int code_len = _app_start[0]; - (void)memcpy(resp, &code[code_len], resp_len); - } - break; - // **** 0xd4: get second 64 bytes of signature - case 0xd4: - { - resp_len = 64; - char * code = (char*)_app_start; - int code_len = _app_start[0]; - (void)memcpy(resp, &code[code_len + 64], resp_len); - } - break; - // **** 0xd6: get version - case 0xd6: - COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN); - (void)memcpy(resp, gitversion, sizeof(gitversion)); - resp_len = sizeof(gitversion) - 1U; - break; - // **** 0xd8: reset ST - case 0xd8: - NVIC_SystemReset(); - break; - // **** 0xd9: set ESP power - case 0xd9: - if (setup->b.wValue.w == 1U) { - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - } else if (setup->b.wValue.w == 2U) { - current_board->set_esp_gps_mode(ESP_GPS_BOOTMODE); - } else { - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); - } - break; - // **** 0xda: reset ESP, with optional boot mode - case 0xda: - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); - delay(1000000); - if (setup->b.wValue.w == 1U) { - current_board->set_esp_gps_mode(ESP_GPS_BOOTMODE); - } else { - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - } - delay(1000000); - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - break; - // **** 0xdb: set GMLAN (white/grey) or OBD CAN (black) multiplexing mode - case 0xdb: - if(board_has_obd()){ - if (setup->b.wValue.w == 1U) { - // Enable OBD CAN - current_board->set_can_mode(CAN_MODE_OBD_CAN2); - } else { - // Disable OBD CAN - current_board->set_can_mode(CAN_MODE_NORMAL); - } - } else { - if (setup->b.wValue.w == 1U) { - // GMLAN ON - if (setup->b.wIndex.w == 1U) { - can_set_gmlan(1); - } else if (setup->b.wIndex.w == 2U) { - can_set_gmlan(2); - } else { - puts("Invalid bus num for GMLAN CAN set\n"); - } - } else { - can_set_gmlan(-1); - } - } - break; - - // **** 0xdc: set safety mode - case 0xdc: - // Blocked over WiFi. - // Allow SILENT, NOOUTPUT and ELM security mode to be set over wifi. - if (hardwired || (setup->b.wValue.w == SAFETY_SILENT) || - (setup->b.wValue.w == SAFETY_NOOUTPUT) || - (setup->b.wValue.w == SAFETY_ELM327)) { - set_safety_mode(setup->b.wValue.w, (uint16_t) setup->b.wIndex.w); - } - break; - // **** 0xdd: enable can forwarding - case 0xdd: - // wValue = Can Bus Num to forward from - // wIndex = Can Bus Num to forward to - if ((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w < BUS_MAX) && - (setup->b.wValue.w != setup->b.wIndex.w)) { // set forwarding - can_set_forwarding(setup->b.wValue.w, setup->b.wIndex.w & CAN_BUS_NUM_MASK); - } else if((setup->b.wValue.w < BUS_MAX) && (setup->b.wIndex.w == 0xFFU)){ //Clear Forwarding - can_set_forwarding(setup->b.wValue.w, -1); - } else { - puts("Invalid CAN bus forwarding\n"); - } - break; - // **** 0xde: set can bitrate - case 0xde: - if (setup->b.wValue.w < BUS_MAX) { - can_speed[setup->b.wValue.w] = setup->b.wIndex.w; - can_init(CAN_NUM_FROM_BUS_NUM(setup->b.wValue.w)); - } - break; - // **** 0xdf: set long controls allowed - case 0xdf: - if (hardwired) { - long_controls_allowed = setup->b.wValue.w & 1U; - } - break; - // **** 0xe0: uart read - case 0xe0: - ur = get_ring_by_number(setup->b.wValue.w); - if (!ur) { - break; - } - - // TODO: Remove this again and fix boardd code to hande the message bursts instead of single chars - if (ur == &uart_ring_esp_gps) { - dma_pointer_handler(ur, DMA2_Stream5->NDTR); - } - - // read - while ((resp_len < MIN(setup->b.wLength.w, MAX_RESP_LEN)) && - getc(ur, (char*)&resp[resp_len])) { - ++resp_len; - } - break; - // **** 0xe1: uart set baud rate - case 0xe1: - ur = get_ring_by_number(setup->b.wValue.w); - if (!ur) { - break; - } - uart_set_baud(ur->uart, setup->b.wIndex.w); - break; - // **** 0xe2: uart set parity - case 0xe2: - ur = get_ring_by_number(setup->b.wValue.w); - if (!ur) { - break; - } - switch (setup->b.wIndex.w) { - case 0: - // disable parity, 8-bit - ur->uart->CR1 &= ~(USART_CR1_PCE | USART_CR1_M); - break; - case 1: - // even parity, 9-bit - ur->uart->CR1 &= ~USART_CR1_PS; - ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M; - break; - case 2: - // odd parity, 9-bit - ur->uart->CR1 |= USART_CR1_PS; - ur->uart->CR1 |= USART_CR1_PCE | USART_CR1_M; - break; - default: - break; - } - break; - // **** 0xe4: uart set baud rate extended - case 0xe4: - ur = get_ring_by_number(setup->b.wValue.w); - if (!ur) { - break; - } - uart_set_baud(ur->uart, (int)setup->b.wIndex.w*300); - break; - // **** 0xe5: set CAN loopback (for testing) - case 0xe5: - can_loopback = (setup->b.wValue.w > 0U); - can_init_all(); - break; - // **** 0xe6: set USB power - case 0xe6: - current_board->set_usb_power_mode(setup->b.wValue.w); - break; - // **** 0xe7: set power save state - case 0xe7: - set_power_save_state(setup->b.wValue.w); - break; - // **** 0xf0: do k-line wValue pulse on uart2 for Acura - case 0xf0: - if (setup->b.wValue.w == 1U) { - GPIOC->ODR &= ~(1U << 10); - GPIOC->MODER &= ~GPIO_MODER_MODER10_1; - GPIOC->MODER |= GPIO_MODER_MODER10_0; - } else { - GPIOC->ODR &= ~(1U << 12); - GPIOC->MODER &= ~GPIO_MODER_MODER12_1; - GPIOC->MODER |= GPIO_MODER_MODER12_0; - } - - for (i = 0; i < 80; i++) { - delay(8000); - if (setup->b.wValue.w == 1U) { - GPIOC->ODR |= (1U << 10); - GPIOC->ODR &= ~(1U << 10); - } else { - GPIOC->ODR |= (1U << 12); - GPIOC->ODR &= ~(1U << 12); - } - } - - if (setup->b.wValue.w == 1U) { - GPIOC->MODER &= ~GPIO_MODER_MODER10_0; - GPIOC->MODER |= GPIO_MODER_MODER10_1; - } else { - GPIOC->MODER &= ~GPIO_MODER_MODER12_0; - GPIOC->MODER |= GPIO_MODER_MODER12_1; - } - - delay(140 * 9000); - break; - // **** 0xf1: Clear CAN ring buffer. - case 0xf1: - if (setup->b.wValue.w == 0xFFFFU) { - puts("Clearing CAN Rx queue\n"); - can_clear(&can_rx_q); - } else if (setup->b.wValue.w < BUS_MAX) { - puts("Clearing CAN Tx queue\n"); - can_clear(can_queues[setup->b.wValue.w]); - } else { - puts("Clearing CAN CAN ring buffer failed: wrong bus number\n"); - } - break; - // **** 0xf2: Clear UART ring buffer. - case 0xf2: - { - uart_ring * rb = get_ring_by_number(setup->b.wValue.w); - if (rb != NULL) { - puts("Clearing UART queue.\n"); - clear_uart_buff(rb); - } - break; - } - // **** 0xf3: Heartbeat. Resets heartbeat counter. - case 0xf3: - { - heartbeat_counter = 0U; - break; - } - default: - puts("NO HANDLER "); - puth(setup->b.bRequest); - puts("\n"); - break; - } - return resp_len; -} - -#ifndef EON -int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { - // data[0] = endpoint - // data[2] = length - // data[4:] = data - UNUSED(len); - int resp_len = 0; - switch (data[0]) { - case 0: - // control transfer - resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), data_out, 0); - break; - case 1: - // ep 1, read - resp_len = usb_cb_ep1_in(data_out, 0x40, 0); - break; - case 2: - // ep 2, send serial - usb_cb_ep2_out(data+4, data[2], 0); - break; - case 3: - // ep 3, send CAN - usb_cb_ep3_out(data+4, data[2], 0); - break; - default: - puts("SPI data invalid"); - break; - } - return resp_len; -} -#endif - -// ***************************** main code ***************************** - -// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck -void __initialize_hardware_early(void) { - early(); -} - -void __attribute__ ((noinline)) enable_fpu(void) { - // enable the FPU - SCB->CPACR |= ((3UL << (10U * 2U)) | (3UL << (11U * 2U))); -} - -// go into SILENT when the EON does not send a heartbeat for this amount of seconds. -#define EON_HEARTBEAT_IGNITION_CNT_ON 5U -#define EON_HEARTBEAT_IGNITION_CNT_OFF 2U - -// called once per second -void TIM1_BRK_TIM9_IRQ_Handler(void) { - if (TIM9->SR != 0) { - can_live = pending_can_live; - - current_board->usb_power_mode_tick(uptime_cnt); - - //puth(usart1_dma); puts(" "); puth(DMA2_Stream5->M0AR); puts(" "); puth(DMA2_Stream5->NDTR); puts("\n"); - - // reset this every 16th pass - if ((uptime_cnt & 0xFU) == 0U) { - pending_can_live = 0; - } - #ifdef DEBUG - puts("** blink "); - puth(can_rx_q.r_ptr); puts(" "); puth(can_rx_q.w_ptr); puts(" "); - puth(can_tx1_q.r_ptr); puts(" "); puth(can_tx1_q.w_ptr); puts(" "); - puth(can_tx2_q.r_ptr); puts(" "); puth(can_tx2_q.w_ptr); puts("\n"); - #endif - - // Tick fan driver - fan_tick(); - //puts("Fan speed: "); puth((unsigned int) fan_rpm); puts("rpm\n"); - - // set green LED to be controls allowed - current_board->set_led(LED_GREEN, controls_allowed); - - // turn off the blue LED, turned on by CAN - // unless we are in power saving mode - current_board->set_led(LED_BLUE, (uptime_cnt & 1U) && (power_save_status == POWER_SAVE_STATUS_ENABLED)); - - // increase heartbeat counter and cap it at the uint32 limit - if (heartbeat_counter < __UINT32_MAX__) { - heartbeat_counter += 1U; - } - - #ifdef EON - // check heartbeat counter if we are running EON code. - // if the heartbeat has been gone for a while, go to SILENT safety mode and enter power save - if (heartbeat_counter >= (check_started() ? EON_HEARTBEAT_IGNITION_CNT_ON : EON_HEARTBEAT_IGNITION_CNT_OFF)) { - puts("EON hasn't sent a heartbeat for 0x"); - puth(heartbeat_counter); - puts(" seconds. Safety is set to SILENT mode.\n"); - if (current_safety_mode != SAFETY_SILENT) { - set_safety_mode(SAFETY_SILENT, 0U); - } - if (power_save_status != POWER_SAVE_STATUS_ENABLED) { - set_power_save_state(POWER_SAVE_STATUS_ENABLED); - } - } - - // enter CDP mode when car starts to ensure we are charging a turned off EON - if (check_started() && (usb_power_mode != USB_POWER_CDP)) { - current_board->set_usb_power_mode(USB_POWER_CDP); - } - #endif - - // check registers - check_registers(); - - // set ignition_can to false after 2s of no CAN seen - if (ignition_can_cnt > 2U) { - ignition_can = false; - }; - - // on to the next one - uptime_cnt += 1U; - safety_mode_cnt += 1U; - ignition_can_cnt += 1U; - } - TIM9->SR = 0; -} - -int main(void) { - // Init interrupt table - init_interrupts(true); - - // 1s timer - REGISTER_INTERRUPT(TIM1_BRK_TIM9_IRQn, TIM1_BRK_TIM9_IRQ_Handler, 2U, FAULT_INTERRUPT_RATE_TIM1) - - // shouldn't have interrupts here, but just in case - disable_interrupts(); - - // init early devices - clock_init(); - peripherals_init(); - detect_configuration(); - detect_board_type(); - adc_init(); - - // print hello - puts("\n\n\n************************ MAIN START ************************\n"); - - // check for non-supported board types - if(hw_type == HW_TYPE_UNKNOWN){ - puts("Unsupported board type\n"); - while (1) { /* hang */ } - } - - puts("Config:\n"); - puts(" Board type: "); puts(current_board->board_type); puts("\n"); - puts(has_external_debug_serial ? " Real serial\n" : " USB serial\n"); - puts(is_entering_bootmode ? " ESP wants bootmode\n" : " No bootmode\n"); - - // init board - current_board->init(); - - // panda has an FPU, let's use it! - enable_fpu(); - - // enable main uart if it's connected - if (has_external_debug_serial) { - // WEIRDNESS: without this gate around the UART, it would "crash", but only if the ESP is enabled - // assuming it's because the lines were left floating and spurious noise was on them - uart_init(&uart_ring_debug, 115200); - } - - if (board_has_gps()) { - uart_init(&uart_ring_esp_gps, 9600); - } else { - // enable ESP uart - uart_init(&uart_ring_esp_gps, 115200); - } - - if(board_has_lin()){ - // enable LIN - uart_init(&uart_ring_lin1, 10400); - UART5->CR2 |= USART_CR2_LINEN; - uart_init(&uart_ring_lin2, 10400); - USART3->CR2 |= USART_CR2_LINEN; - } - - // init microsecond system timer - // increments 1000000 times per second - // generate an update to set the prescaler - TIM2->PSC = 48-1; - TIM2->CR1 = TIM_CR1_CEN; - TIM2->EGR = TIM_EGR_UG; - // use TIM2->CNT to read - - // init to SILENT and can silent - set_safety_mode(SAFETY_SILENT, 0); - - // enable CAN TXs - current_board->enable_can_transcievers(true); - -#ifndef EON - spi_init(); -#endif - - // 1hz - timer_init(TIM9, 1464); - NVIC_EnableIRQ(TIM1_BRK_TIM9_IRQn); - -#ifdef DEBUG - puts("DEBUG ENABLED\n"); -#endif - // enable USB (right before interrupts or enum can fail!) - usb_init(); - - puts("**** INTERRUPTS ON ****\n"); - enable_interrupts(); - - // LED should keep on blinking all the time - uint64_t cnt = 0; - - for (cnt=0;;cnt++) { - if (power_save_status == POWER_SAVE_STATUS_DISABLED) { - #ifdef DEBUG_FAULTS - if(fault_status == FAULT_STATUS_NONE){ - #endif - int div_mode = ((usb_power_mode == USB_POWER_DCP) ? 4 : 1); - - // useful for debugging, fade breaks = panda is overloaded - for (int div_mode_loop = 0; div_mode_loop < div_mode; div_mode_loop++) { - for (int fade = 0; fade < 1024; fade += 8) { - for (int i = 0; i < (128/div_mode); i++) { - current_board->set_led(LED_RED, 1); - if (fade < 512) { delay(fade); } else { delay(1024-fade); } - current_board->set_led(LED_RED, 0); - if (fade < 512) { delay(512-fade); } else { delay(fade-512); } - } - } - } - #ifdef DEBUG_FAULTS - } else { - current_board->set_led(LED_RED, 1); - delay(512000U); - current_board->set_led(LED_RED, 0); - delay(512000U); - } - #endif - } else { - __WFI(); - } - } - - return 0; -} diff --git a/panda/board/main_declarations.h b/panda/board/main_declarations.h deleted file mode 100644 index 363a992dbf..0000000000 --- a/panda/board/main_declarations.h +++ /dev/null @@ -1,15 +0,0 @@ -// ******************** Prototypes ******************** -void puts(const char *a); -void puth(unsigned int i); -void puth2(unsigned int i); -typedef struct board board; -typedef struct harness_configuration harness_configuration; -void can_flip_buses(uint8_t bus1, uint8_t bus2); -void can_set_obd(uint8_t harness_orientation, bool obd); - -// ********************* Globals ********************** -uint8_t hw_type = 0; -const board *current_board; -bool is_enumerated = 0; -uint32_t heartbeat_counter = 0; -uint32_t uptime_cnt = 0; diff --git a/panda/board/obj/.placeholder b/panda/board/obj/.placeholder deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/panda/board/obj/panda.bin.signed b/panda/board/obj/panda.bin.signed deleted file mode 100644 index 8526a5b993edb2d34f1fb74051ff02c758b98ae2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31564 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 KPRR$CKKL5xe}$d^ diff --git a/panda/board/pedal/.gitignore b/panda/board/pedal/.gitignore deleted file mode 100644 index 94053f2925..0000000000 --- a/panda/board/pedal/.gitignore +++ /dev/null @@ -1 +0,0 @@ -obj/* diff --git a/panda/board/pedal/Makefile b/panda/board/pedal/Makefile deleted file mode 100644 index 7ce6dd0768..0000000000 --- a/panda/board/pedal/Makefile +++ /dev/null @@ -1,67 +0,0 @@ -# :set noet -PROJ_NAME = comma - -CFLAGS = -O2 -Wall -Wextra -Wstrict-prototypes -Werror -std=gnu11 -DPEDAL -CFLAGS += -mlittle-endian -mthumb -mcpu=cortex-m3 -CFLAGS += -msoft-float -DSTM32F2 -DSTM32F205xx -CFLAGS += -I ../inc -I ../ -I ../../ -nostdlib -fno-builtin -CFLAGS += -T../stm32_flash.ld - -STARTUP_FILE = startup_stm32f205xx - -CC = arm-none-eabi-gcc -OBJCOPY = arm-none-eabi-objcopy -OBJDUMP = arm-none-eabi-objdump -DFU_UTIL = "dfu-util" - -# pedal only uses the debug cert -CERT = ../../certs/debug -CFLAGS += "-DALLOW_DEBUG" - -canflash: obj/$(PROJ_NAME).bin - ../../tests/pedal/enter_canloader.py $< - -usbflash: obj/$(PROJ_NAME).bin - ../../tests/pedal/enter_canloader.py; sleep 0.5 - PYTHONPATH=../../ python -c "from python import Panda; p = [x for x in [Panda(x) for x in Panda.list()] if x.bootstub]; assert(len(p)==1); p[0].flash('obj/$(PROJ_NAME).bin', reconnect=False)" - -recover: obj/bootstub.bin obj/$(PROJ_NAME).bin - ../../tests/pedal/enter_canloader.py --recover; sleep 0.5 - $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08004000 -D obj/$(PROJ_NAME).bin - $(DFU_UTIL) -d 0483:df11 -a 0 -s 0x08000000:leave -D obj/bootstub.bin - -include ../../common/version.mk - -obj/cert.h: ../../crypto/getcertheader.py - ../../crypto/getcertheader.py ../../certs/debug.pub ../../certs/release.pub > $@ - -obj/main.o: main.c ../*.h - mkdir -p obj - $(CC) $(CFLAGS) -o $@ -c $< - -obj/bootstub.o: ../bootstub.c ../*.h obj/gitversion.h obj/cert.h - mkdir -p obj - mkdir -p ../obj - cp obj/gitversion.h ../obj/gitversion.h - cp obj/cert.h ../obj/cert.h - $(CC) $(CFLAGS) -o $@ -c $< - -obj/$(STARTUP_FILE).o: ../$(STARTUP_FILE).s - $(CC) $(CFLAGS) -o $@ -c $< - -obj/%.o: ../../crypto/%.c - $(CC) $(CFLAGS) -o $@ -c $< - -obj/$(PROJ_NAME).bin: obj/$(STARTUP_FILE).o obj/main.o - # hack - $(CC) -Wl,--section-start,.isr_vector=0x8004000 $(CFLAGS) -o obj/$(PROJ_NAME).elf $^ - $(OBJCOPY) -v -O binary obj/$(PROJ_NAME).elf obj/code.bin - SETLEN=1 ../../crypto/sign.py obj/code.bin $@ $(CERT) - -obj/bootstub.bin: obj/$(STARTUP_FILE).o obj/bootstub.o obj/sha.o obj/rsa.o - $(CC) $(CFLAGS) -o obj/bootstub.$(PROJ_NAME).elf $^ - $(OBJCOPY) -v -O binary obj/bootstub.$(PROJ_NAME).elf $@ - -clean: - rm -f obj/* - diff --git a/panda/board/pedal/README b/panda/board/pedal/README deleted file mode 100644 index cf779db258..0000000000 --- a/panda/board/pedal/README +++ /dev/null @@ -1,28 +0,0 @@ -This is the firmware for the comma pedal. It borrows a lot from panda. - -The comma pedal is a gas pedal interceptor for Honda/Acura. It allows you to "virtually" press the pedal. - -This is the open source software. Note that it is not ready to use yet. - -== Test Plan == - -* Startup -** Confirm STATE_FAULT_STARTUP -* Timeout -** Send value -** Confirm value is output -** Stop sending messages -** Confirm value is passthru after 100ms -** Confirm STATE_FAULT_TIMEOUT -* Random values -** Send random 6 byte messages -** Confirm random values cause passthru -** Confirm STATE_FAULT_BAD_CHECKSUM -* Same message lockout -** Send same message repeated -** Confirm timeout behavior -* Don't set enable -** Confirm no output -* Set enable and values -** Confirm output - diff --git a/panda/board/pedal/main.c b/panda/board/pedal/main.c deleted file mode 100644 index 667d27bf0f..0000000000 --- a/panda/board/pedal/main.c +++ /dev/null @@ -1,352 +0,0 @@ -// ********************* Includes ********************* -#include "../config.h" -#include "libc.h" - -#include "main_declarations.h" -#include "critical.h" -#include "faults.h" - -#include "drivers/registers.h" -#include "drivers/interrupts.h" -#include "drivers/llcan.h" -#include "drivers/llgpio.h" -#include "drivers/adc.h" - -#include "board.h" - -#include "drivers/clock.h" -#include "drivers/dac.h" -#include "drivers/timer.h" - -#include "gpio.h" - -#define CAN CAN1 - -//#define PEDAL_USB - -#ifdef PEDAL_USB - #include "drivers/uart.h" - #include "drivers/usb.h" -#else - // no serial either - void puts(const char *a) { - UNUSED(a); - } - void puth(unsigned int i) { - UNUSED(i); - } - void puth2(unsigned int i) { - UNUSED(i); - } -#endif - -#define ENTER_BOOTLOADER_MAGIC 0xdeadbeef -uint32_t enter_bootloader_mode; - -// cppcheck-suppress unusedFunction ; used in headers not included in cppcheck -void __initialize_hardware_early(void) { - early(); -} - -// ********************* serial debugging ********************* - -#ifdef PEDAL_USB - -void debug_ring_callback(uart_ring *ring) { - char rcv; - while (getc(ring, &rcv) != 0) { - (void)putc(ring, rcv); - } -} - -int usb_cb_ep1_in(void *usbdata, int len, bool hardwired) { - UNUSED(usbdata); - UNUSED(len); - UNUSED(hardwired); - return 0; -} -void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) { - UNUSED(usbdata); - UNUSED(len); - UNUSED(hardwired); -} -void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) { - UNUSED(usbdata); - UNUSED(len); - UNUSED(hardwired); -} -void usb_cb_enumeration_complete(void) {} - -int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) { - UNUSED(hardwired); - unsigned int resp_len = 0; - uart_ring *ur = NULL; - switch (setup->b.bRequest) { - // **** 0xe0: uart read - case 0xe0: - ur = get_ring_by_number(setup->b.wValue.w); - if (!ur) { - break; - } - // read - while ((resp_len < MIN(setup->b.wLength.w, MAX_RESP_LEN)) && - getc(ur, (char*)&resp[resp_len])) { - ++resp_len; - } - break; - default: - puts("NO HANDLER "); - puth(setup->b.bRequest); - puts("\n"); - break; - } - return resp_len; -} - -#endif - -// ***************************** pedal can checksum ***************************** - -uint8_t pedal_checksum(uint8_t *dat, int len) { - uint8_t crc = 0xFF; - uint8_t poly = 0xD5; // standard crc8 - int i, j; - for (i = len - 1; i >= 0; i--) { - crc ^= dat[i]; - for (j = 0; j < 8; j++) { - if ((crc & 0x80U) != 0U) { - crc = (uint8_t)((crc << 1) ^ poly); - } - else { - crc <<= 1; - } - } - } - return crc; -} - -// ***************************** can port ***************************** - -// addresses to be used on CAN -#define CAN_GAS_INPUT 0x200 -#define CAN_GAS_OUTPUT 0x201U -#define CAN_GAS_SIZE 6 -#define COUNTER_CYCLE 0xFU - -void CAN1_TX_IRQ_Handler(void) { - // clear interrupt - CAN->TSR |= CAN_TSR_RQCP0; -} - -// two independent values -uint16_t gas_set_0 = 0; -uint16_t gas_set_1 = 0; - -#define MAX_TIMEOUT 10U -uint32_t timeout = 0; -uint32_t current_index = 0; - -#define NO_FAULT 0U -#define FAULT_BAD_CHECKSUM 1U -#define FAULT_SEND 2U -#define FAULT_SCE 3U -#define FAULT_STARTUP 4U -#define FAULT_TIMEOUT 5U -#define FAULT_INVALID 6U -uint8_t state = FAULT_STARTUP; - -void CAN1_RX0_IRQ_Handler(void) { - while ((CAN->RF0R & CAN_RF0R_FMP0) != 0) { - #ifdef DEBUG - puts("CAN RX\n"); - #endif - int address = CAN->sFIFOMailBox[0].RIR >> 21; - if (address == CAN_GAS_INPUT) { - // softloader entry - if (GET_BYTES_04(&CAN->sFIFOMailBox[0]) == 0xdeadface) { - if (GET_BYTES_48(&CAN->sFIFOMailBox[0]) == 0x0ab00b1e) { - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - NVIC_SystemReset(); - } else if (GET_BYTES_48(&CAN->sFIFOMailBox[0]) == 0x02b00b1e) { - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - } else { - puts("Failed entering Softloader or Bootloader\n"); - } - } - - // normal packet - uint8_t dat[8]; - for (int i=0; i<8; i++) { - dat[i] = GET_BYTE(&CAN->sFIFOMailBox[0], i); - } - uint16_t value_0 = (dat[0] << 8) | dat[1]; - uint16_t value_1 = (dat[2] << 8) | dat[3]; - bool enable = ((dat[4] >> 7) & 1U) != 0U; - uint8_t index = dat[4] & COUNTER_CYCLE; - if (pedal_checksum(dat, CAN_GAS_SIZE - 1) == dat[5]) { - if (((current_index + 1U) & COUNTER_CYCLE) == index) { - #ifdef DEBUG - puts("setting gas "); - puth(value_0); - puts("\n"); - #endif - if (enable) { - gas_set_0 = value_0; - gas_set_1 = value_1; - } else { - // clear the fault state if values are 0 - if ((value_0 == 0U) && (value_1 == 0U)) { - state = NO_FAULT; - } else { - state = FAULT_INVALID; - } - gas_set_0 = 0; - gas_set_1 = 0; - } - // clear the timeout - timeout = 0; - } - current_index = index; - } else { - // wrong checksum = fault - state = FAULT_BAD_CHECKSUM; - } - } - // next - CAN->RF0R |= CAN_RF0R_RFOM0; - } -} - -void CAN1_SCE_IRQ_Handler(void) { - state = FAULT_SCE; - llcan_clear_send(CAN); -} - -uint32_t pdl0 = 0; -uint32_t pdl1 = 0; -unsigned int pkt_idx = 0; - -int led_value = 0; - -void TIM3_IRQ_Handler(void) { - #ifdef DEBUG - puth(TIM3->CNT); - puts(" "); - puth(pdl0); - puts(" "); - puth(pdl1); - puts("\n"); - #endif - - // check timer for sending the user pedal and clearing the CAN - if ((CAN->TSR & CAN_TSR_TME0) == CAN_TSR_TME0) { - uint8_t dat[8]; - dat[0] = (pdl0 >> 8) & 0xFFU; - dat[1] = (pdl0 >> 0) & 0xFFU; - dat[2] = (pdl1 >> 8) & 0xFFU; - dat[3] = (pdl1 >> 0) & 0xFFU; - dat[4] = ((state & 0xFU) << 4) | pkt_idx; - dat[5] = pedal_checksum(dat, CAN_GAS_SIZE - 1); - CAN->sTxMailBox[0].TDLR = dat[0] | (dat[1] << 8) | (dat[2] << 16) | (dat[3] << 24); - CAN->sTxMailBox[0].TDHR = dat[4] | (dat[5] << 8); - CAN->sTxMailBox[0].TDTR = 6; // len of packet is 5 - CAN->sTxMailBox[0].TIR = (CAN_GAS_OUTPUT << 21) | 1U; - ++pkt_idx; - pkt_idx &= COUNTER_CYCLE; - } else { - // old can packet hasn't sent! - state = FAULT_SEND; - #ifdef DEBUG - puts("CAN MISS\n"); - #endif - } - - // blink the LED - current_board->set_led(LED_GREEN, led_value); - led_value = !led_value; - - TIM3->SR = 0; - - // up timeout for gas set - if (timeout == MAX_TIMEOUT) { - state = FAULT_TIMEOUT; - } else { - timeout += 1U; - } -} - -// ***************************** main code ***************************** - -void pedal(void) { - // read/write - pdl0 = adc_get(ADCCHAN_ACCEL0); - pdl1 = adc_get(ADCCHAN_ACCEL1); - - // write the pedal to the DAC - if (state == NO_FAULT) { - dac_set(0, MAX(gas_set_0, pdl0)); - dac_set(1, MAX(gas_set_1, pdl1)); - } else { - dac_set(0, pdl0); - dac_set(1, pdl1); - } - - watchdog_feed(); -} - -int main(void) { - // Init interrupt table - init_interrupts(true); - - REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - - // Should run at around 732Hz (see init below) - REGISTER_INTERRUPT(TIM3_IRQn, TIM3_IRQ_Handler, 1000U, FAULT_INTERRUPT_RATE_TIM3) - - disable_interrupts(); - - // init devices - clock_init(); - peripherals_init(); - detect_configuration(); - detect_board_type(); - - // init board - current_board->init(); - -#ifdef PEDAL_USB - // enable USB - usb_init(); -#endif - - // pedal stuff - dac_init(); - adc_init(); - - // init can - bool llcan_speed_set = llcan_set_speed(CAN1, 5000, false, false); - if (!llcan_speed_set) { - puts("Failed to set llcan speed"); - } - - llcan_init(CAN1); - - // 48mhz / 65536 ~= 732 - timer_init(TIM3, 15); - NVIC_EnableIRQ(TIM3_IRQn); - - watchdog_init(); - - puts("**** INTERRUPTS ON ****\n"); - enable_interrupts(); - - // main pedal loop - while (1) { - pedal(); - } - - return 0; -} diff --git a/panda/board/pedal/main_declarations.h b/panda/board/pedal/main_declarations.h deleted file mode 100644 index 9a40f8ae3a..0000000000 --- a/panda/board/pedal/main_declarations.h +++ /dev/null @@ -1,11 +0,0 @@ -// ******************** Prototypes ******************** -void puts(const char *a); -void puth(unsigned int i); -void puth2(unsigned int i); -typedef struct board board; -typedef struct harness_configuration harness_configuration; - -// ********************* Globals ********************** -uint8_t hw_type = 0; -const board *current_board; -bool is_enumerated = 0; \ No newline at end of file diff --git a/panda/board/pedal/obj/.gitkeep b/panda/board/pedal/obj/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/panda/board/power_saving.h b/panda/board/power_saving.h deleted file mode 100644 index 3ee2170d71..0000000000 --- a/panda/board/power_saving.h +++ /dev/null @@ -1,60 +0,0 @@ -// WARNING: To stay in compliance with the SIL2 rules laid out in STM UM1840, we should never implement any of the available hardware low power modes. -// See rule: CoU_3 - -#define POWER_SAVE_STATUS_DISABLED 0 -#define POWER_SAVE_STATUS_ENABLED 1 - -int power_save_status = POWER_SAVE_STATUS_DISABLED; - -void set_power_save_state(int state) { - - bool is_valid_state = (state == POWER_SAVE_STATUS_ENABLED) || (state == POWER_SAVE_STATUS_DISABLED); - if (is_valid_state && (state != power_save_status)) { - bool enable = false; - if (state == POWER_SAVE_STATUS_ENABLED) { - puts("enable power savings\n"); - if (board_has_gps()) { - char UBLOX_SLEEP_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x08\x00\x17\x78"; - uart_ring *ur = get_ring_by_number(1); - for (unsigned int i = 0; i < sizeof(UBLOX_SLEEP_MSG) - 1U; i++) while (!putc(ur, UBLOX_SLEEP_MSG[i])); - } - } else { - puts("disable power savings\n"); - if (board_has_gps()) { - char UBLOX_WAKE_MSG[] = "\xb5\x62\x06\x04\x04\x00\x01\x00\x09\x00\x18\x7a"; - uart_ring *ur = get_ring_by_number(1); - for (unsigned int i = 0; i < sizeof(UBLOX_WAKE_MSG) - 1U; i++) while (!putc(ur, UBLOX_WAKE_MSG[i])); - } - enable = true; - } - - current_board->enable_can_transcievers(enable); - - // Switch EPS/GPS - if (enable) { - current_board->set_esp_gps_mode(ESP_GPS_ENABLED); - } else { - current_board->set_esp_gps_mode(ESP_GPS_DISABLED); - } - - if(board_has_gmlan()){ - // turn on GMLAN - set_gpio_output(GPIOB, 14, enable); - set_gpio_output(GPIOB, 15, enable); - } - - if(board_has_lin()){ - // turn on LIN - set_gpio_output(GPIOB, 7, enable); - set_gpio_output(GPIOA, 14, enable); - } - - // Switch off IR and fan when in power saving - if(!enable){ - current_board->set_ir_power(0U); - current_board->set_fan_power(0U); - } - - power_save_status = state; - } -} diff --git a/panda/board/provision.h b/panda/board/provision.h deleted file mode 100644 index 9091322f1a..0000000000 --- a/panda/board/provision.h +++ /dev/null @@ -1,13 +0,0 @@ -#define PROVISION_CHUNK_LEN 0x20 - -// WiFi SSID = 0x0 - 0x10 -// WiFi password = 0x10 - 0x1C -// SHA1 checksum = 0x1C - 0x20 - -void get_provision_chunk(uint8_t *resp) { - (void)memcpy(resp, (uint8_t *)0x1fff79e0, PROVISION_CHUNK_LEN); - if (memcmp(resp, "\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", 0x20) == 0) { - (void)memcpy(resp, "unprovisioned\x00\x00\x00testing123\x00\x00\xa3\xa6\x99\xec", 0x20); - } -} - diff --git a/panda/board/safety.h b/panda/board/safety.h deleted file mode 100644 index 0a216e5b1f..0000000000 --- a/panda/board/safety.h +++ /dev/null @@ -1,234 +0,0 @@ -// include first, needed by safety policies -#include "safety_declarations.h" -// Include the actual safety policies. -#include "safety/safety_defaults.h" -#include "safety/safety_honda.h" -#include "safety/safety_toyota.h" -#include "safety/safety_toyota_ipas.h" -#include "safety/safety_tesla.h" -#include "safety/safety_gm_ascm.h" -#include "safety/safety_gm.h" -#include "safety/safety_ford.h" -#include "safety/safety_cadillac.h" -#include "safety/safety_hyundai.h" -#include "safety/safety_chrysler.h" -#include "safety/safety_subaru.h" -#include "safety/safety_mazda.h" -#include "safety/safety_volkswagen.h" -#include "safety/safety_elm327.h" - -// from cereal.car.CarParams.SafetyModel -#define SAFETY_SILENT 0U -#define SAFETY_HONDA 1U -#define SAFETY_TOYOTA 2U -#define SAFETY_ELM327 3U -#define SAFETY_GM 4U -#define SAFETY_HONDA_BOSCH 5U -#define SAFETY_FORD 6U -#define SAFETY_CADILLAC 7U -#define SAFETY_HYUNDAI 8U -#define SAFETY_CHRYSLER 9U -#define SAFETY_TESLA 10U -#define SAFETY_SUBARU 11U -#define SAFETY_MAZDA 13U -#define SAFETY_VOLKSWAGEN 15U -#define SAFETY_TOYOTA_IPAS 16U -#define SAFETY_ALLOUTPUT 17U -#define SAFETY_GM_ASCM 18U -#define SAFETY_NOOUTPUT 19U - -uint16_t current_safety_mode = SAFETY_SILENT; -const safety_hooks *current_hooks = &nooutput_hooks; - -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push){ - current_hooks->rx(to_push); -} - -int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - return current_hooks->tx(to_send); -} - -int safety_tx_lin_hook(int lin_num, uint8_t *data, int len){ - return current_hooks->tx_lin(lin_num, data, len); -} - -int safety_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - return current_hooks->fwd(bus_num, to_fwd); -} - -bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len) { - bool allowed = false; - for (int i = 0; i < len; i++) { - if ((addr == addr_list[i].addr) && (bus == addr_list[i].bus)) { - allowed = true; - break; - } - } - return allowed; -} - -typedef struct { - uint16_t id; - const safety_hooks *hooks; -} safety_hook_config; - -const safety_hook_config safety_hook_registry[] = { - {SAFETY_SILENT, &nooutput_hooks}, - {SAFETY_HONDA, &honda_hooks}, - {SAFETY_TOYOTA, &toyota_hooks}, - {SAFETY_ELM327, &elm327_hooks}, - {SAFETY_GM, &gm_hooks}, - {SAFETY_HONDA_BOSCH, &honda_bosch_hooks}, - {SAFETY_HYUNDAI, &hyundai_hooks}, - {SAFETY_CHRYSLER, &chrysler_hooks}, - {SAFETY_SUBARU, &subaru_hooks}, - {SAFETY_MAZDA, &mazda_hooks}, - {SAFETY_VOLKSWAGEN, &volkswagen_hooks}, - {SAFETY_NOOUTPUT, &nooutput_hooks}, -#ifdef ALLOW_DEBUG - {SAFETY_CADILLAC, &cadillac_hooks}, - {SAFETY_TOYOTA_IPAS, &toyota_ipas_hooks}, - {SAFETY_TESLA, &tesla_hooks}, - {SAFETY_ALLOUTPUT, &alloutput_hooks}, - {SAFETY_GM_ASCM, &gm_ascm_hooks}, - {SAFETY_FORD, &ford_hooks}, -#endif -}; - -int set_safety_hooks(uint16_t mode, int16_t param) { - safety_mode_cnt = 0U; // reset safety mode timer - int set_status = -1; // not set - int hook_config_count = sizeof(safety_hook_registry) / sizeof(safety_hook_config); - for (int i = 0; i < hook_config_count; i++) { - if (safety_hook_registry[i].id == mode) { - current_hooks = safety_hook_registry[i].hooks; - current_safety_mode = safety_hook_registry[i].id; - set_status = 0; // set - break; - } - } - if ((set_status == 0) && (current_hooks->init != NULL)) { - current_hooks->init(param); - } - return set_status; -} - -// compute the time elapsed (in microseconds) from 2 counter samples -// case where ts < ts_last is ok: overflow is properly re-casted into uint32_t -uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last) { - return ts - ts_last; -} - -// convert a trimmed integer to signed 32 bit int -int to_signed(int d, int bits) { - int d_signed = d; - if (d >= (1 << MAX((bits - 1), 0))) { - d_signed = d - (1 << MAX(bits, 0)); - } - return d_signed; -} - -// given a new sample, update the smaple_t struct -void update_sample(struct sample_t *sample, int sample_new) { - int sample_size = sizeof(sample->values) / sizeof(sample->values[0]); - for (int i = sample_size - 1; i > 0; i--) { - sample->values[i] = sample->values[i-1]; - } - sample->values[0] = sample_new; - - // get the minimum and maximum measured samples - sample->min = sample->values[0]; - sample->max = sample->values[0]; - for (int i = 1; i < sample_size; i++) { - if (sample->values[i] < sample->min) { - sample->min = sample->values[i]; - } - if (sample->values[i] > sample->max) { - sample->max = sample->values[i]; - } - } -} - -bool max_limit_check(int val, const int MAX_VAL, const int MIN_VAL) { - return (val > MAX_VAL) || (val < MIN_VAL); -} - -// check that commanded value isn't too far from measured -bool dist_to_meas_check(int val, int val_last, struct sample_t *val_meas, - const int MAX_RATE_UP, const int MAX_RATE_DOWN, const int MAX_ERROR) { - - // *** val rate limit check *** - int highest_allowed_rl = MAX(val_last, 0) + MAX_RATE_UP; - int lowest_allowed_rl = MIN(val_last, 0) - MAX_RATE_UP; - - // if we've exceeded the meas val, we must start moving toward 0 - int highest_allowed = MIN(highest_allowed_rl, MAX(val_last - MAX_RATE_DOWN, MAX(val_meas->max, 0) + MAX_ERROR)); - int lowest_allowed = MAX(lowest_allowed_rl, MIN(val_last + MAX_RATE_DOWN, MIN(val_meas->min, 0) - MAX_ERROR)); - - // check for violation - return (val < lowest_allowed) || (val > highest_allowed); -} - -// check that commanded value isn't fighting against driver -bool driver_limit_check(int val, int val_last, struct sample_t *val_driver, - const int MAX_VAL, const int MAX_RATE_UP, const int MAX_RATE_DOWN, - const int MAX_ALLOWANCE, const int DRIVER_FACTOR) { - - int highest_allowed_rl = MAX(val_last, 0) + MAX_RATE_UP; - int lowest_allowed_rl = MIN(val_last, 0) - MAX_RATE_UP; - - int driver_max_limit = MAX_VAL + (MAX_ALLOWANCE + val_driver->max) * DRIVER_FACTOR; - int driver_min_limit = -MAX_VAL + (-MAX_ALLOWANCE + val_driver->min) * DRIVER_FACTOR; - - // if we've exceeded the applied torque, we must start moving toward 0 - int highest_allowed = MIN(highest_allowed_rl, MAX(val_last - MAX_RATE_DOWN, - MAX(driver_max_limit, 0))); - int lowest_allowed = MAX(lowest_allowed_rl, MIN(val_last + MAX_RATE_DOWN, - MIN(driver_min_limit, 0))); - - // check for violation - return (val < lowest_allowed) || (val > highest_allowed); -} - - -// real time check, mainly used for steer torque rate limiter -bool rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA) { - - // *** torque real time rate limit check *** - int highest_val = MAX(val_last, 0) + MAX_RT_DELTA; - int lowest_val = MIN(val_last, 0) - MAX_RT_DELTA; - - // check for violation - return (val < lowest_val) || (val > highest_val); -} - - -// interp function that holds extreme values -float interpolate(struct lookup_t xy, float x) { - - int size = sizeof(xy.x) / sizeof(xy.x[0]); - float ret = xy.y[size - 1]; // default output is last point - - // x is lower than the first point in the x array. Return the first point - if (x <= xy.x[0]) { - ret = xy.y[0]; - - } else { - // find the index such that (xy.x[i] <= x < xy.x[i+1]) and linearly interp - for (int i=0; i < (size - 1); i++) { - if (x < xy.x[i+1]) { - float x0 = xy.x[i]; - float y0 = xy.y[i]; - float dx = xy.x[i+1] - x0; - float dy = xy.y[i+1] - y0; - // dx should not be zero as xy.x is supposed to be monotonic - if (dx <= 0.) { - dx = 0.0001; - } - ret = (dy * (x - x0) / dx) + y0; - break; - } - } - } - return ret; -} diff --git a/panda/board/safety/safety_cadillac.h b/panda/board/safety/safety_cadillac.h deleted file mode 100644 index ccfa78d3f7..0000000000 --- a/panda/board/safety/safety_cadillac.h +++ /dev/null @@ -1,124 +0,0 @@ -#define CADILLAC_TORQUE_MSG_N 4 // 4 torque messages: 0x151, 0x152, 0x153, 0x154 - -const AddrBus CADILLAC_TX_MSGS[] = {{0x151, 2}, {0x152, 0}, {0x153, 2}, {0x154, 0}}; -const int CADILLAC_MAX_STEER = 150; // 1s -// real time torque limit to prevent controls spamming -// the real time limit is 1500/sec -const int CADILLAC_MAX_RT_DELTA = 75; // max delta torque allowed for real time checks -const uint32_t CADILLAC_RT_INTERVAL = 250000; // 250ms between real time checks -const int CADILLAC_MAX_RATE_UP = 2; -const int CADILLAC_MAX_RATE_DOWN = 5; -const int CADILLAC_DRIVER_TORQUE_ALLOWANCE = 50; -const int CADILLAC_DRIVER_TORQUE_FACTOR = 4; - -int cadillac_cruise_engaged_last = 0; -int cadillac_rt_torque_last = 0; -const int cadillac_torque_msgs_n = 4; -int cadillac_desired_torque_last[CADILLAC_TORQUE_MSG_N] = {0}; -uint32_t cadillac_ts_last = 0; -bool cadillac_supercruise_on = 0; -struct sample_t cadillac_torque_driver; // last few driver torques measured - -int cadillac_get_torque_idx(int addr, int array_size) { - return MIN(MAX(addr - 0x151, 0), array_size); // 0x151 is id 0, 0x152 is id 1 and so on... -} - -static void cadillac_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if (addr == 356) { - int torque_driver_new = ((GET_BYTE(to_push, 0) & 0x7U) << 8) | (GET_BYTE(to_push, 1)); - - torque_driver_new = to_signed(torque_driver_new, 11); - // update array of samples - update_sample(&cadillac_torque_driver, torque_driver_new); - } - - // enter controls on rising edge of ACC, exit controls on ACC off - if ((addr == 0x370) && (bus == 0)) { - int cruise_engaged = GET_BYTE(to_push, 2) & 0x80; // bit 23 - if (cruise_engaged && !cadillac_cruise_engaged_last) { - controls_allowed = 1; - } - if (!cruise_engaged) { - controls_allowed = 0; - } - cadillac_cruise_engaged_last = cruise_engaged; - } - - // know supercruise mode and block openpilot msgs if on - if ((addr == 0x152) || (addr == 0x154)) { - cadillac_supercruise_on = (GET_BYTE(to_push, 4) & 0x10) != 0; - } -} - -static int cadillac_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (!addr_allowed(addr, bus, CADILLAC_TX_MSGS, sizeof(CADILLAC_TX_MSGS) / sizeof(CADILLAC_TX_MSGS[0]))) { - tx = 0; - } - - // steer cmd checks - if ((addr == 0x151) || (addr == 0x152) || (addr == 0x153) || (addr == 0x154)) { - int desired_torque = ((GET_BYTE(to_send, 0) & 0x3f) << 8) | GET_BYTE(to_send, 1); - int violation = 0; - uint32_t ts = TIM2->CNT; - int idx = cadillac_get_torque_idx(addr, CADILLAC_TORQUE_MSG_N); - desired_torque = to_signed(desired_torque, 14); - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, CADILLAC_MAX_STEER, -CADILLAC_MAX_STEER); - - // *** torque rate limit check *** - int desired_torque_last = cadillac_desired_torque_last[idx]; - violation |= driver_limit_check(desired_torque, desired_torque_last, &cadillac_torque_driver, - CADILLAC_MAX_STEER, CADILLAC_MAX_RATE_UP, CADILLAC_MAX_RATE_DOWN, - CADILLAC_DRIVER_TORQUE_ALLOWANCE, CADILLAC_DRIVER_TORQUE_FACTOR); - - // used next time - cadillac_desired_torque_last[idx] = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, cadillac_rt_torque_last, CADILLAC_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, cadillac_ts_last); - if (ts_elapsed > CADILLAC_RT_INTERVAL) { - cadillac_rt_torque_last = desired_torque; - cadillac_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - cadillac_desired_torque_last[idx] = 0; - cadillac_rt_torque_last = 0; - cadillac_ts_last = ts; - } - - if (violation || cadillac_supercruise_on) { - tx = 0; - } - - } - return tx; -} - -const safety_hooks cadillac_hooks = { - .init = nooutput_init, - .rx = cadillac_rx_hook, - .tx = cadillac_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = default_fwd_hook, -}; diff --git a/panda/board/safety/safety_chrysler.h b/panda/board/safety/safety_chrysler.h deleted file mode 100644 index ce9f65f2af..0000000000 --- a/panda/board/safety/safety_chrysler.h +++ /dev/null @@ -1,140 +0,0 @@ -const int CHRYSLER_MAX_STEER = 261; -const int CHRYSLER_MAX_RT_DELTA = 112; // max delta torque allowed for real time checks -const uint32_t CHRYSLER_RT_INTERVAL = 250000; // 250ms between real time checks -const int CHRYSLER_MAX_RATE_UP = 3; -const int CHRYSLER_MAX_RATE_DOWN = 3; -const int CHRYSLER_MAX_TORQUE_ERROR = 80; // max torque cmd in excess of torque motor -const AddrBus CHRYSLER_TX_MSGS[] = {{571, 0}, {658, 0}, {678, 0}}; - -int chrysler_rt_torque_last = 0; -int chrysler_desired_torque_last = 0; -int chrysler_cruise_engaged_last = 0; -uint32_t chrysler_ts_last = 0; -struct sample_t chrysler_torque_meas; // last few torques measured - -static void chrysler_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - // Measured eps torque - if (addr == 544) { - int torque_meas_new = ((GET_BYTE(to_push, 4) & 0x7U) << 8) + GET_BYTE(to_push, 5) - 1024U; - - // update array of samples - update_sample(&chrysler_torque_meas, torque_meas_new); - } - - // enter controls on rising edge of ACC, exit controls on ACC off - if (addr == 0x1F4) { - int cruise_engaged = ((GET_BYTE(to_push, 2) & 0x38) >> 3) == 7; - if (cruise_engaged && !chrysler_cruise_engaged_last) { - controls_allowed = 1; - } - if (!cruise_engaged) { - controls_allowed = 0; - } - chrysler_cruise_engaged_last = cruise_engaged; - } - - // check if stock camera ECU is on bus 0 - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x292)) { - relay_malfunction = true; - } -} - -static int chrysler_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (!addr_allowed(addr, bus, CHRYSLER_TX_MSGS, sizeof(CHRYSLER_TX_MSGS) / sizeof(CHRYSLER_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // LKA STEER - if (addr == 0x292) { - int desired_torque = ((GET_BYTE(to_send, 0) & 0x7U) << 8) + GET_BYTE(to_send, 1) - 1024U; - uint32_t ts = TIM2->CNT; - bool violation = 0; - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, CHRYSLER_MAX_STEER, -CHRYSLER_MAX_STEER); - - // *** torque rate limit check *** - violation |= dist_to_meas_check(desired_torque, chrysler_desired_torque_last, - &chrysler_torque_meas, CHRYSLER_MAX_RATE_UP, CHRYSLER_MAX_RATE_DOWN, CHRYSLER_MAX_TORQUE_ERROR); - - // used next time - chrysler_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, chrysler_rt_torque_last, CHRYSLER_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, chrysler_ts_last); - if (ts_elapsed > CHRYSLER_RT_INTERVAL) { - chrysler_rt_torque_last = desired_torque; - chrysler_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - chrysler_desired_torque_last = 0; - chrysler_rt_torque_last = 0; - chrysler_ts_last = ts; - } - - if (violation) { - tx = 0; - } - } - - // FORCE CANCEL: only the cancel button press is allowed - if (addr == 571) { - if (GET_BYTE(to_send, 0) != 1) { - tx = 0; - } - } - - return tx; -} - -static int chrysler_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - - int bus_fwd = -1; - int addr = GET_ADDR(to_fwd); - - if (!relay_malfunction) { - // forward CAN 0 -> 2 so stock LKAS camera sees messages - if (bus_num == 0) { - bus_fwd = 2; - } - // forward all messages from camera except LKAS_COMMAND and LKAS_HUD - if ((bus_num == 2) && (addr != 658) && (addr != 678)) { - bus_fwd = 0; - } - } - return bus_fwd; -} - - -const safety_hooks chrysler_hooks = { - .init = nooutput_init, - .rx = chrysler_rx_hook, - .tx = chrysler_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = chrysler_fwd_hook, -}; diff --git a/panda/board/safety/safety_defaults.h b/panda/board/safety/safety_defaults.h deleted file mode 100644 index 4733438c9c..0000000000 --- a/panda/board/safety/safety_defaults.h +++ /dev/null @@ -1,65 +0,0 @@ -void default_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - UNUSED(to_push); -} - -// *** no output safety mode *** - -static void nooutput_init(int16_t param) { - UNUSED(param); - controls_allowed = false; - relay_malfunction = false; -} - -static int nooutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - UNUSED(to_send); - return false; -} - -static int nooutput_tx_lin_hook(int lin_num, uint8_t *data, int len) { - UNUSED(lin_num); - UNUSED(data); - UNUSED(len); - return false; -} - -static int default_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - UNUSED(bus_num); - UNUSED(to_fwd); - return -1; -} - -const safety_hooks nooutput_hooks = { - .init = nooutput_init, - .rx = default_rx_hook, - .tx = nooutput_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = default_fwd_hook, -}; - -// *** all output safety mode *** - -static void alloutput_init(int16_t param) { - UNUSED(param); - controls_allowed = true; - relay_malfunction = false; -} - -static int alloutput_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - UNUSED(to_send); - return true; -} - -static int alloutput_tx_lin_hook(int lin_num, uint8_t *data, int len) { - UNUSED(lin_num); - UNUSED(data); - UNUSED(len); - return true; -} - -const safety_hooks alloutput_hooks = { - .init = alloutput_init, - .rx = default_rx_hook, - .tx = alloutput_tx_hook, - .tx_lin = alloutput_tx_lin_hook, - .fwd = default_fwd_hook, -}; diff --git a/panda/board/safety/safety_elm327.h b/panda/board/safety/safety_elm327.h deleted file mode 100644 index df515b05d6..0000000000 --- a/panda/board/safety/safety_elm327.h +++ /dev/null @@ -1,42 +0,0 @@ -static int elm327_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - int len = GET_LEN(to_send); - - //All ISO 15765-4 messages must be 8 bytes long - if (len != 8) { - tx = 0; - } - - //Check valid 29 bit send addresses for ISO 15765-4 - //Check valid 11 bit send addresses for ISO 15765-4 - if ((addr != 0x18DB33F1) && ((addr & 0x1FFF00FF) != 0x18DA00F1) && - ((addr != 0x7DF) && ((addr & 0x1FFFFFF8) != 0x7E0))) { - tx = 0; - } - return tx; -} - -static int elm327_tx_lin_hook(int lin_num, uint8_t *data, int len) { - int tx = 1; - if (lin_num != 0) { - tx = 0; //Only operate on LIN 0, aka serial 2 - } - if ((len < 5) || (len > 11)) { - tx = 0; //Valid KWP size - } - if (!(((data[0] & 0xF8U) == 0xC0U) && ((data[0] & 0x07U) != 0U) && - (data[1] == 0x33U) && (data[2] == 0xF1U))) { - tx = 0; //Bad msg - } - return tx; -} - -const safety_hooks elm327_hooks = { - .init = nooutput_init, - .rx = default_rx_hook, - .tx = elm327_tx_hook, - .tx_lin = elm327_tx_lin_hook, - .fwd = default_fwd_hook, -}; diff --git a/panda/board/safety/safety_ford.h b/panda/board/safety/safety_ford.h deleted file mode 100644 index 47c7342a44..0000000000 --- a/panda/board/safety/safety_ford.h +++ /dev/null @@ -1,113 +0,0 @@ -// board enforces -// in-state -// accel set/resume -// out-state -// cancel button -// accel rising edge -// brake rising edge -// brake > 0mph - -int ford_brake_prev = 0; -int ford_gas_prev = 0; -bool ford_moving = false; - -static void ford_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - - int addr = GET_ADDR(to_push); - int bus = GET_BUS(to_push); - - if (addr == 0x217) { - // wheel speeds are 14 bits every 16 - ford_moving = false; - for (int i = 0; i < 8; i += 2) { - ford_moving |= GET_BYTE(to_push, i) | (GET_BYTE(to_push, (int)(i + 1)) & 0xFCU); - } - } - - // state machine to enter and exit controls - if (addr == 0x83) { - bool cancel = GET_BYTE(to_push, 1) & 0x1; - bool set_or_resume = GET_BYTE(to_push, 3) & 0x30; - if (cancel) { - controls_allowed = 0; - } - if (set_or_resume) { - controls_allowed = 1; - } - } - - // exit controls on rising edge of brake press or on brake press when - // speed > 0 - if (addr == 0x165) { - int brake = GET_BYTE(to_push, 0) & 0x20; - if (brake && (!(ford_brake_prev) || ford_moving)) { - controls_allowed = 0; - } - ford_brake_prev = brake; - } - - // exit controls on rising edge of gas press - if (addr == 0x204) { - int gas = (GET_BYTE(to_push, 0) & 0x03) | GET_BYTE(to_push, 1); - if (gas && !(ford_gas_prev)) { - controls_allowed = 0; - } - ford_gas_prev = gas; - } - - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 0x3CA)) { - relay_malfunction = true; - } -} - -// all commands: just steering -// if controls_allowed and no pedals pressed -// allow all commands up to limit -// else -// block all commands that produce actuation - -static int ford_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - - // disallow actuator commands if gas or brake (with vehicle moving) are pressed - // and the the latching controls_allowed flag is True - int pedal_pressed = ford_gas_prev || (ford_brake_prev && ford_moving); - bool current_controls_allowed = controls_allowed && !(pedal_pressed); - - if (relay_malfunction) { - tx = 0; - } - - // STEER: safety check - if (addr == 0x3CA) { - if (!current_controls_allowed) { - // bits 7-4 need to be 0xF to disallow lkas commands - if ((GET_BYTE(to_send, 0) & 0xF0) != 0xF0) { - tx = 0; - } - } - } - - // FORCE CANCEL: safety check only relevant when spamming the cancel button - // ensuring that set and resume aren't sent - if (addr == 0x83) { - if ((GET_BYTE(to_send, 3) & 0x30) != 0) { - tx = 0; - } - } - - // 1 allows the message through - return tx; -} - -// TODO: keep camera on bus 2 and make a fwd_hook - -const safety_hooks ford_hooks = { - .init = nooutput_init, - .rx = ford_rx_hook, - .tx = ford_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = default_fwd_hook, -}; diff --git a/panda/board/safety/safety_gm.h b/panda/board/safety/safety_gm.h deleted file mode 100644 index 92c32ad808..0000000000 --- a/panda/board/safety/safety_gm.h +++ /dev/null @@ -1,222 +0,0 @@ -// board enforces -// in-state -// accel set/resume -// out-state -// cancel button -// regen paddle -// accel rising edge -// brake rising edge -// brake > 0mph - -const int GM_MAX_STEER = 300; -const int GM_MAX_RT_DELTA = 128; // max delta torque allowed for real time checks -const uint32_t GM_RT_INTERVAL = 250000; // 250ms between real time checks -const int GM_MAX_RATE_UP = 7; -const int GM_MAX_RATE_DOWN = 17; -const int GM_DRIVER_TORQUE_ALLOWANCE = 50; -const int GM_DRIVER_TORQUE_FACTOR = 4; -const int GM_MAX_GAS = 3072; -const int GM_MAX_REGEN = 1404; -const int GM_MAX_BRAKE = 350; -const AddrBus GM_TX_MSGS[] = {{384, 0}, {1033, 0}, {1034, 0}, {715, 0}, {880, 0}, // pt bus - {161, 1}, {774, 1}, {776, 1}, {784, 1}, // obs bus - {789, 2}, // ch bus - {0x104c006c, 3}, {0x10400060, 3}}; // gmlan - -int gm_brake_prev = 0; -int gm_gas_prev = 0; -bool gm_moving = false; -int gm_rt_torque_last = 0; -int gm_desired_torque_last = 0; -uint32_t gm_ts_last = 0; -struct sample_t gm_torque_driver; // last few driver torques measured - -static void gm_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if (addr == 388) { - int torque_driver_new = ((GET_BYTE(to_push, 6) & 0x7) << 8) | GET_BYTE(to_push, 7); - torque_driver_new = to_signed(torque_driver_new, 11); - // update array of samples - update_sample(&gm_torque_driver, torque_driver_new); - } - - // sample speed, really only care if car is moving or not - // rear left wheel speed - if (addr == 842) { - gm_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1); - } - - // ACC steering wheel buttons - if (addr == 481) { - int button = (GET_BYTE(to_push, 5) & 0x70) >> 4; - switch (button) { - case 2: // resume - case 3: // set - controls_allowed = 1; - break; - case 6: // cancel - controls_allowed = 0; - break; - default: - break; // any other button is irrelevant - } - } - - // exit controls on rising edge of brake press or on brake press when - // speed > 0 - if (addr == 241) { - int brake = GET_BYTE(to_push, 1); - // Brake pedal's potentiometer returns near-zero reading - // even when pedal is not pressed - if (brake < 10) { - brake = 0; - } - if (brake && (!gm_brake_prev || gm_moving)) { - controls_allowed = 0; - } - gm_brake_prev = brake; - } - - // exit controls on rising edge of gas press - if (addr == 417) { - int gas = GET_BYTE(to_push, 6); - if (gas && !gm_gas_prev && long_controls_allowed) { - controls_allowed = 0; - } - gm_gas_prev = gas; - } - - // exit controls on regen paddle - if (addr == 189) { - bool regen = GET_BYTE(to_push, 0) & 0x20; - if (regen) { - controls_allowed = 0; - } - } - - // Check if ASCM or LKA camera are online - // on powertrain bus. - // 384 = ASCMLKASteeringCmd - // 715 = ASCMGasRegenCmd - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 384) || (addr == 715))) { - relay_malfunction = true; - } -} - -// all commands: gas/regen, friction brake and steering -// if controls_allowed and no pedals pressed -// allow all commands up to limit -// else -// block all commands that produce actuation - -static int gm_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (!addr_allowed(addr, bus, GM_TX_MSGS, sizeof(GM_TX_MSGS)/sizeof(GM_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // disallow actuator commands if gas or brake (with vehicle moving) are pressed - // and the the latching controls_allowed flag is True - int pedal_pressed = gm_gas_prev || (gm_brake_prev && gm_moving); - bool current_controls_allowed = controls_allowed && !pedal_pressed; - - // BRAKE: safety check - if (addr == 789) { - int brake = ((GET_BYTE(to_send, 0) & 0xFU) << 8) + GET_BYTE(to_send, 1); - brake = (0x1000 - brake) & 0xFFF; - if (!current_controls_allowed || !long_controls_allowed) { - if (brake != 0) { - tx = 0; - } - } - if (brake > GM_MAX_BRAKE) { - tx = 0; - } - } - - // LKA STEER: safety check - if (addr == 384) { - int desired_torque = ((GET_BYTE(to_send, 0) & 0x7U) << 8) + GET_BYTE(to_send, 1); - uint32_t ts = TIM2->CNT; - bool violation = 0; - desired_torque = to_signed(desired_torque, 11); - - if (current_controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, GM_MAX_STEER, -GM_MAX_STEER); - - // *** torque rate limit check *** - violation |= driver_limit_check(desired_torque, gm_desired_torque_last, &gm_torque_driver, - GM_MAX_STEER, GM_MAX_RATE_UP, GM_MAX_RATE_DOWN, - GM_DRIVER_TORQUE_ALLOWANCE, GM_DRIVER_TORQUE_FACTOR); - - // used next time - gm_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, gm_rt_torque_last, GM_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, gm_ts_last); - if (ts_elapsed > GM_RT_INTERVAL) { - gm_rt_torque_last = desired_torque; - gm_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!current_controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !current_controls_allowed) { - gm_desired_torque_last = 0; - gm_rt_torque_last = 0; - gm_ts_last = ts; - } - - if (violation) { - tx = 0; - } - } - - // GAS/REGEN: safety check - if (addr == 715) { - int gas_regen = ((GET_BYTE(to_send, 2) & 0x7FU) << 5) + ((GET_BYTE(to_send, 3) & 0xF8U) >> 3); - // Disabled message is !engaged with gas - // value that corresponds to max regen. - if (!current_controls_allowed || !long_controls_allowed) { - bool apply = GET_BYTE(to_send, 0) & 1U; - if (apply || (gas_regen != GM_MAX_REGEN)) { - tx = 0; - } - } - if (gas_regen > GM_MAX_GAS) { - tx = 0; - } - } - - // 1 allows the message through - return tx; -} - - -const safety_hooks gm_hooks = { - .init = nooutput_init, - .rx = gm_rx_hook, - .tx = gm_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = default_fwd_hook, -}; diff --git a/panda/board/safety/safety_gm_ascm.h b/panda/board/safety/safety_gm_ascm.h deleted file mode 100644 index 36fd1d8f2a..0000000000 --- a/panda/board/safety/safety_gm_ascm.h +++ /dev/null @@ -1,44 +0,0 @@ -// BUS 0 is on the LKAS module (ASCM) side -// BUS 2 is on the actuator (EPS) side - -static int gm_ascm_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - - int bus_fwd = -1; - - if (bus_num == 0) { - int addr = GET_ADDR(to_fwd); - bus_fwd = 2; - // do not propagate lkas messages from ascm to actuators, unless supercruise is on - // block 0x152 and 0x154, which are the lkas command from ASCM1 and ASCM2 - // block 0x315 and 0x2cb, which are the brake and accel commands from ASCM1 - //if ((addr == 0x152) || (addr == 0x154) || (addr == 0x315) || (addr == 0x2cb)) { - if ((addr == 0x152) || (addr == 0x154)) { - bool supercruise_on = (GET_BYTE(to_fwd, 4) & 0x10) != 0; // bit 36 - if (!supercruise_on) { - bus_fwd = -1; - } - } - if ((addr == 0x151) || (addr == 0x153) || (addr == 0x314)) { - // on the chassis bus, the OBDII port is on the module side, so we need to read - // the lkas messages sent by openpilot (put on unused 0x151 ane 0x153 addrs) and send it to - // the actuator as 0x152 and 0x154 - uint32_t fwd_addr = addr + 1; - to_fwd->RIR = (fwd_addr << 21) | (to_fwd->RIR & 0x1fffff); - } - } - - if (bus_num == 2) { - bus_fwd = 0; - } - - return bus_fwd; -} - -const safety_hooks gm_ascm_hooks = { - .init = nooutput_init, - .rx = default_rx_hook, - .tx = alloutput_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = gm_ascm_fwd_hook, -}; - diff --git a/panda/board/safety/safety_honda.h b/panda/board/safety/safety_honda.h deleted file mode 100644 index ab8ceb5290..0000000000 --- a/panda/board/safety/safety_honda.h +++ /dev/null @@ -1,276 +0,0 @@ -// board enforces -// in-state -// accel set/resume -// out-state -// cancel button -// accel rising edge -// brake rising edge -// brake > 0mph -const AddrBus HONDA_N_TX_MSGS[] = {{0xE4, 0}, {0x194, 0}, {0x1FA, 0}, {0x200, 0}, {0x30C, 0}, {0x33D, 0}}; -const AddrBus HONDA_BH_TX_MSGS[] = {{0xE4, 0}, {0x296, 1}, {0x33D, 0}}; // Bosch Harness -const AddrBus HONDA_BG_TX_MSGS[] = {{0xE4, 2}, {0x296, 0}, {0x33D, 2}}; // Bosch Giraffe -const int HONDA_GAS_INTERCEPTOR_THRESHOLD = 328; // ratio between offset and gain from dbc file -int honda_brake = 0; -int honda_gas_prev = 0; -bool honda_brake_pressed_prev = false; -bool honda_moving = false; -bool honda_bosch_hardware = false; -bool honda_alt_brake_msg = false; -bool honda_fwd_brake = false; - -static void honda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - - int addr = GET_ADDR(to_push); - int len = GET_LEN(to_push); - int bus = GET_BUS(to_push); - - // sample speed - if (addr == 0x158) { - // first 2 bytes - honda_moving = GET_BYTE(to_push, 0) | GET_BYTE(to_push, 1); - } - - // state machine to enter and exit controls - // 0x1A6 for the ILX, 0x296 for the Civic Touring - if ((addr == 0x1A6) || (addr == 0x296)) { - int button = (GET_BYTE(to_push, 0) & 0xE0) >> 5; - switch (button) { - case 2: // cancel - controls_allowed = 0; - break; - case 3: // set - case 4: // resume - controls_allowed = 1; - break; - default: - break; // any other button is irrelevant - } - } - - // user brake signal on 0x17C reports applied brake from computer brake on accord - // and crv, which prevents the usual brake safety from working correctly. these - // cars have a signal on 0x1BE which only detects user's brake being applied so - // in these cases, this is used instead. - // most hondas: 0x17C bit 53 - // accord, crv: 0x1BE bit 4 - // exit controls on rising edge of brake press or on brake press when speed > 0 - bool is_user_brake_msg = honda_alt_brake_msg ? ((addr) == 0x1BE) : ((addr) == 0x17C); - if (is_user_brake_msg) { - bool brake_pressed = honda_alt_brake_msg ? (GET_BYTE((to_push), 0) & 0x10) : (GET_BYTE((to_push), 6) & 0x20); - if (brake_pressed && (!(honda_brake_pressed_prev) || honda_moving)) { - controls_allowed = 0; - } - honda_brake_pressed_prev = brake_pressed; - } - - // exit controls on rising edge of gas press if interceptor (0x201 w/ len = 6) - // length check because bosch hardware also uses this id (0x201 w/ len = 8) - if ((addr == 0x201) && (len == 6)) { - gas_interceptor_detected = 1; - int gas_interceptor = GET_INTERCEPTOR(to_push); - if ((gas_interceptor > HONDA_GAS_INTERCEPTOR_THRESHOLD) && - (gas_interceptor_prev <= HONDA_GAS_INTERCEPTOR_THRESHOLD) && - long_controls_allowed) { - controls_allowed = 0; - } - gas_interceptor_prev = gas_interceptor; - } - - // exit controls on rising edge of gas press if no interceptor - if (!gas_interceptor_detected) { - if (addr == 0x17C) { - int gas = GET_BYTE(to_push, 0); - if (gas && !(honda_gas_prev) && long_controls_allowed) { - controls_allowed = 0; - } - honda_gas_prev = gas; - } - } - if ((bus == 2) && (addr == 0x1FA)) { - bool honda_stock_aeb = GET_BYTE(to_push, 3) & 0x20; - int honda_stock_brake = (GET_BYTE(to_push, 0) << 2) + ((GET_BYTE(to_push, 1) >> 6) & 0x3); - - // Forward AEB when stock braking is higher than openpilot braking - // only stop forwarding when AEB event is over - if (!honda_stock_aeb) { - honda_fwd_brake = false; - } else if (honda_stock_brake >= honda_brake) { - honda_fwd_brake = true; - } else { - // Leave Honda forward brake as is - } - } - - // if steering controls messages are received on the destination bus, it's an indication - // that the relay might be malfunctioning - int bus_rdr_car = (board_has_relay()) ? 0 : 2; // radar bus, car side - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && ((addr == 0xE4) || (addr == 0x194))) { - if ((honda_bosch_hardware && (bus == bus_rdr_car)) || - (!honda_bosch_hardware && (bus == 0))) { - relay_malfunction = true; - } - } -} - -// all commands: gas, brake and steering -// if controls_allowed and no pedals pressed -// allow all commands up to limit -// else -// block all commands that produce actuation - -static int honda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (honda_bosch_hardware) { - if (board_has_relay() && !addr_allowed(addr, bus, HONDA_BH_TX_MSGS, sizeof(HONDA_BH_TX_MSGS)/sizeof(HONDA_BH_TX_MSGS[0]))) { - tx = 0; - } - if (!board_has_relay() && !addr_allowed(addr, bus, HONDA_BG_TX_MSGS, sizeof(HONDA_BG_TX_MSGS)/sizeof(HONDA_BG_TX_MSGS[0]))) { - tx = 0; - } - } - if (!honda_bosch_hardware && !addr_allowed(addr, bus, HONDA_N_TX_MSGS, sizeof(HONDA_N_TX_MSGS)/sizeof(HONDA_N_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // disallow actuator commands if gas or brake (with vehicle moving) are pressed - // and the the latching controls_allowed flag is True - int pedal_pressed = honda_gas_prev || (gas_interceptor_prev > HONDA_GAS_INTERCEPTOR_THRESHOLD) || - (honda_brake_pressed_prev && honda_moving); - bool current_controls_allowed = controls_allowed && !(pedal_pressed); - - // BRAKE: safety check - if ((addr == 0x1FA) && (bus == 0)) { - honda_brake = (GET_BYTE(to_send, 0) << 2) + ((GET_BYTE(to_send, 1) >> 6) & 0x3); - if (!current_controls_allowed || !long_controls_allowed) { - if (honda_brake != 0) { - tx = 0; - } - } - if (honda_brake > 255) { - tx = 0; - } - if (honda_fwd_brake) { - tx = 0; - } - } - - // STEER: safety check - if ((addr == 0xE4) || (addr == 0x194)) { - if (!current_controls_allowed) { - bool steer_applied = GET_BYTE(to_send, 0) | GET_BYTE(to_send, 1); - if (steer_applied) { - tx = 0; - } - } - } - - // GAS: safety check - if (addr == 0x200) { - if (!current_controls_allowed || !long_controls_allowed) { - if (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1)) { - tx = 0; - } - } - } - - // 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 - int bus_pt = ((board_has_relay()) && honda_bosch_hardware)? 1 : 0; - if ((addr == 0x296) && honda_bosch_hardware && - !current_controls_allowed && (bus == bus_pt)) { - if (((GET_BYTE(to_send, 0) >> 5) & 0x7) != 2) { - tx = 0; - } - } - - // 1 allows the message through - return tx; -} - -static void honda_init(int16_t param) { - UNUSED(param); - controls_allowed = false; - relay_malfunction = false; - honda_bosch_hardware = false; - honda_alt_brake_msg = false; -} - -static void honda_bosch_init(int16_t param) { - controls_allowed = false; - relay_malfunction = false; - honda_bosch_hardware = true; - // Checking for alternate brake override from safety parameter - honda_alt_brake_msg = (param == 1) ? true : false; -} - -static int honda_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - // fwd from car to camera. also fwd certain msgs from camera to car - // 0xE4 is steering on all cars except CRV and RDX, 0x194 for CRV and RDX, - // 0x1FA is brake control, 0x30C is acc hud, 0x33D is lkas hud, - int bus_fwd = -1; - - if (!relay_malfunction) { - if (bus_num == 0) { - bus_fwd = 2; - } - if (bus_num == 2) { - // block stock lkas messages and stock acc messages (if OP is doing ACC) - int addr = GET_ADDR(to_fwd); - bool is_lkas_msg = (addr == 0xE4) || (addr == 0x194) || (addr == 0x33D); - bool is_acc_hud_msg = addr == 0x30C; - bool is_brake_msg = addr == 0x1FA; - bool block_fwd = is_lkas_msg || - (is_acc_hud_msg && long_controls_allowed) || - (is_brake_msg && long_controls_allowed && !honda_fwd_brake); - if (!block_fwd) { - bus_fwd = 0; - } - } - } - return bus_fwd; -} - -static int honda_bosch_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - int bus_fwd = -1; - int bus_rdr_cam = (board_has_relay()) ? 2 : 1; // radar bus, camera side - int bus_rdr_car = (board_has_relay()) ? 0 : 2; // radar bus, car side - - if (!relay_malfunction) { - if (bus_num == bus_rdr_car) { - bus_fwd = bus_rdr_cam; - } - if (bus_num == bus_rdr_cam) { - int addr = GET_ADDR(to_fwd); - int is_lkas_msg = (addr == 0xE4) || (addr == 0x33D); - if (!is_lkas_msg) { - bus_fwd = bus_rdr_car; - } - } - } - return bus_fwd; -} - -const safety_hooks honda_hooks = { - .init = honda_init, - .rx = honda_rx_hook, - .tx = honda_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = honda_fwd_hook, -}; - -const safety_hooks honda_bosch_hooks = { - .init = honda_bosch_init, - .rx = honda_rx_hook, - .tx = honda_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = honda_bosch_fwd_hook, -}; diff --git a/panda/board/safety/safety_hyundai.h b/panda/board/safety/safety_hyundai.h deleted file mode 100644 index b2d215f687..0000000000 --- a/panda/board/safety/safety_hyundai.h +++ /dev/null @@ -1,143 +0,0 @@ -const int HYUNDAI_MAX_STEER = 255; // like stock -const int HYUNDAI_MAX_RT_DELTA = 112; // max delta torque allowed for real time checks -const uint32_t HYUNDAI_RT_INTERVAL = 250000; // 250ms between real time checks -const int HYUNDAI_MAX_RATE_UP = 3; -const int HYUNDAI_MAX_RATE_DOWN = 7; -const int HYUNDAI_DRIVER_TORQUE_ALLOWANCE = 50; -const int HYUNDAI_DRIVER_TORQUE_FACTOR = 2; - -const AddrBus HYUNDAI_TX_MSGS[] = {{832, 0}, {1265, 0}}; - -int hyundai_rt_torque_last = 0; -int hyundai_desired_torque_last = 0; -int hyundai_cruise_engaged_last = 0; -uint32_t hyundai_ts_last = 0; -struct sample_t hyundai_torque_driver; // last few driver torques measured - -static void hyundai_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if (addr == 897) { - int torque_driver_new = ((GET_BYTES_04(to_push) >> 11) & 0xfff) - 2048; - // update array of samples - update_sample(&hyundai_torque_driver, torque_driver_new); - } - - // check if stock camera ECU is on bus 0 - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == 832)) { - relay_malfunction = true; - } - - // enter controls on rising edge of ACC, exit controls on ACC off - if (addr == 1057) { - // 2 bits: 13-14 - int cruise_engaged = (GET_BYTES_04(to_push) >> 13) & 0x3; - if (cruise_engaged && !hyundai_cruise_engaged_last) { - controls_allowed = 1; - } - if (!cruise_engaged) { - controls_allowed = 0; - } - hyundai_cruise_engaged_last = cruise_engaged; - } -} - -static int hyundai_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (!addr_allowed(addr, bus, HYUNDAI_TX_MSGS, sizeof(HYUNDAI_TX_MSGS)/sizeof(HYUNDAI_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // LKA STEER: safety check - if (addr == 832) { - int desired_torque = ((GET_BYTES_04(to_send) >> 16) & 0x7ff) - 1024; - uint32_t ts = TIM2->CNT; - bool violation = 0; - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, HYUNDAI_MAX_STEER, -HYUNDAI_MAX_STEER); - - // *** torque rate limit check *** - violation |= driver_limit_check(desired_torque, hyundai_desired_torque_last, &hyundai_torque_driver, - HYUNDAI_MAX_STEER, HYUNDAI_MAX_RATE_UP, HYUNDAI_MAX_RATE_DOWN, - HYUNDAI_DRIVER_TORQUE_ALLOWANCE, HYUNDAI_DRIVER_TORQUE_FACTOR); - - // used next time - hyundai_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, hyundai_rt_torque_last, HYUNDAI_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, hyundai_ts_last); - if (ts_elapsed > HYUNDAI_RT_INTERVAL) { - hyundai_rt_torque_last = desired_torque; - hyundai_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - hyundai_desired_torque_last = 0; - hyundai_rt_torque_last = 0; - hyundai_ts_last = ts; - } - - if (violation) { - tx = 0; - } - } - - // FORCE CANCEL: safety check only relevant when spamming the cancel button. - // ensuring that only the cancel button press is sent (VAL 4) when controls are off. - // This avoids unintended engagements while still allowing resume spam - if ((addr == 1265) && !controls_allowed) { - if ((GET_BYTES_04(to_send) & 0x7) != 4) { - tx = 0; - } - } - - // 1 allows the message through - return tx; -} - -static int hyundai_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - - int bus_fwd = -1; - int addr = GET_ADDR(to_fwd); - // forward cam to ccan and viceversa, except lkas cmd - if (!relay_malfunction) { - if (bus_num == 0) { - bus_fwd = 2; - } - if ((bus_num == 2) && (addr != 832)) { - bus_fwd = 0; - } - } - return bus_fwd; -} - - -const safety_hooks hyundai_hooks = { - .init = nooutput_init, - .rx = hyundai_rx_hook, - .tx = hyundai_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = hyundai_fwd_hook, -}; diff --git a/panda/board/safety/safety_mazda.h b/panda/board/safety/safety_mazda.h deleted file mode 100644 index f1215f23da..0000000000 --- a/panda/board/safety/safety_mazda.h +++ /dev/null @@ -1,149 +0,0 @@ - -// CAN msgs we care about -#define MAZDA_LKAS 0x243 -#define MAZDA_LANEINFO 0x440 -#define MAZDA_CRZ_CTRL 0x21c -#define MAZDA_WHEEL_SPEED 0x215 -#define MAZDA_STEER_TORQUE 0x240 - -// CAN bus numbers -#define MAZDA_MAIN 0 -#define MAZDA_AUX 1 -#define MAZDA_CAM 2 - -#define MAZDA_MAX_STEER 2048 - -// max delta torque allowed for real time checks -#define MAZDA_MAX_RT_DELTA 940 -// 250ms between real time checks -#define MAZDA_RT_INTERVAL 250000 -#define MAZDA_MAX_RATE_UP 10 -#define MAZDA_MAX_RATE_DOWN 25 -#define MAZDA_DRIVER_TORQUE_ALLOWANCE 15 -#define MAZDA_DRIVER_TORQUE_FACTOR 1 - - -int mazda_cruise_engaged_last = 0; -int mazda_rt_torque_last = 0; -int mazda_desired_torque_last = 0; -uint32_t mazda_ts_last = 0; -struct sample_t mazda_torque_driver; // last few driver torques measured - -// track msgs coming from OP so that we know what CAM msgs to drop and what to forward -void mazda_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if ((addr == MAZDA_STEER_TORQUE) && (bus == MAZDA_MAIN)) { - int torque_driver_new = GET_BYTE(to_push, 0) - 127; - // update array of samples - update_sample(&mazda_torque_driver, torque_driver_new); - } - - // enter controls on rising edge of ACC, exit controls on ACC off - if ((addr == MAZDA_CRZ_CTRL) && (bus == MAZDA_MAIN)) { - int cruise_engaged = GET_BYTE(to_push, 0) & 8; - if (cruise_engaged != 0) { - if (!mazda_cruise_engaged_last) { - controls_allowed = 1; - } - } - else { - controls_allowed = 0; - } - mazda_cruise_engaged_last = cruise_engaged; - } - - // if we see wheel speed msgs on MAZDA_CAM bus then relay is closed - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == MAZDA_CAM) && (addr == MAZDA_WHEEL_SPEED)) { - relay_malfunction = true; - } -} - -static int mazda_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (relay_malfunction) { - tx = 0; - } - - // Check if msg is sent on the main BUS - if (bus == MAZDA_MAIN) { - // steer cmd checks - if (addr == MAZDA_LKAS) { - int desired_torque = (((GET_BYTE(to_send, 0) & 0x0f) << 8) | GET_BYTE(to_send, 1)) - MAZDA_MAX_STEER; - bool violation = 0; - uint32_t ts = TIM2->CNT; - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, MAZDA_MAX_STEER, -MAZDA_MAX_STEER); - - // *** torque rate limit check *** - int desired_torque_last = mazda_desired_torque_last; - violation |= driver_limit_check(desired_torque, desired_torque_last, &mazda_torque_driver, - MAZDA_MAX_STEER, MAZDA_MAX_RATE_UP, MAZDA_MAX_RATE_DOWN, - MAZDA_DRIVER_TORQUE_ALLOWANCE, MAZDA_DRIVER_TORQUE_FACTOR); - // used next time - mazda_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, mazda_rt_torque_last, MAZDA_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, mazda_ts_last); - if (ts_elapsed > ((uint32_t) MAZDA_RT_INTERVAL)) { - mazda_rt_torque_last = desired_torque; - mazda_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - mazda_desired_torque_last = 0; - mazda_rt_torque_last = 0; - mazda_ts_last = ts; - } - - if (violation) { - tx = 0; - } - } - } - return tx; -} - -static int mazda_fwd_hook(int bus, CAN_FIFOMailBox_TypeDef *to_fwd) { - int bus_fwd = -1; - if (!relay_malfunction) { - int addr = GET_ADDR(to_fwd); - if (bus == MAZDA_MAIN) { - bus_fwd = MAZDA_CAM; - } - else if (bus == MAZDA_CAM) { - if (!(addr == MAZDA_LKAS)) { - bus_fwd = MAZDA_MAIN; - } - } - else { - bus_fwd = -1; - } - } - return bus_fwd; -} - -const safety_hooks mazda_hooks = { - .init = nooutput_init, - .rx = mazda_rx_hook, - .tx = mazda_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = mazda_fwd_hook, -}; diff --git a/panda/board/safety/safety_subaru.h b/panda/board/safety/safety_subaru.h deleted file mode 100644 index 66e5947f85..0000000000 --- a/panda/board/safety/safety_subaru.h +++ /dev/null @@ -1,144 +0,0 @@ -const int SUBARU_MAX_STEER = 2047; // 1s -// real time torque limit to prevent controls spamming -// the real time limit is 1500/sec -const int SUBARU_MAX_RT_DELTA = 940; // max delta torque allowed for real time checks -const uint32_t SUBARU_RT_INTERVAL = 250000; // 250ms between real time checks -const int SUBARU_MAX_RATE_UP = 50; -const int SUBARU_MAX_RATE_DOWN = 70; -const int SUBARU_DRIVER_TORQUE_ALLOWANCE = 60; -const int SUBARU_DRIVER_TORQUE_FACTOR = 10; - -const AddrBus SUBARU_TX_MSGS[] = {{0x122, 0}, {0x164, 0}, {0x221, 0}, {0x322, 0}}; - -int subaru_cruise_engaged_last = 0; -int subaru_rt_torque_last = 0; -int subaru_desired_torque_last = 0; -uint32_t subaru_ts_last = 0; -struct sample_t subaru_torque_driver; // last few driver torques measured - -static void subaru_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - if (((addr == 0x119) || (addr == 0x371)) && (bus == 0)){ - int bit_shift = (addr == 0x119) ? 16 : 29; - int torque_driver_new = ((GET_BYTES_04(to_push) >> bit_shift) & 0x7FF); - torque_driver_new = to_signed(torque_driver_new, 11); - // update array of samples - update_sample(&subaru_torque_driver, torque_driver_new); - } - - // enter controls on rising edge of ACC, exit controls on ACC off - if (((addr == 0x240) || (addr == 0x144)) && (bus == 0)) { - int bit_shift = (addr == 0x240) ? 9 : 17; - int cruise_engaged = ((GET_BYTES_48(to_push) >> bit_shift) & 1); - if (cruise_engaged && !subaru_cruise_engaged_last) { - controls_allowed = 1; - } - if (!cruise_engaged) { - controls_allowed = 0; - } - subaru_cruise_engaged_last = cruise_engaged; - } - - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && ((addr == 0x122) || (addr == 0x164))) { - relay_malfunction = true; - } -} - -static int subaru_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (!addr_allowed(addr, bus, SUBARU_TX_MSGS, sizeof(SUBARU_TX_MSGS) / sizeof(SUBARU_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // steer cmd checks - if ((addr == 0x122) || (addr == 0x164)) { - int bit_shift = (addr == 0x122) ? 16 : 8; - int desired_torque = ((GET_BYTES_04(to_send) >> bit_shift) & 0x1FFF); - bool violation = 0; - uint32_t ts = TIM2->CNT; - desired_torque = to_signed(desired_torque, 13); - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, SUBARU_MAX_STEER, -SUBARU_MAX_STEER); - - // *** torque rate limit check *** - int desired_torque_last = subaru_desired_torque_last; - violation |= driver_limit_check(desired_torque, desired_torque_last, &subaru_torque_driver, - SUBARU_MAX_STEER, SUBARU_MAX_RATE_UP, SUBARU_MAX_RATE_DOWN, - SUBARU_DRIVER_TORQUE_ALLOWANCE, SUBARU_DRIVER_TORQUE_FACTOR); - - // used next time - subaru_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, subaru_rt_torque_last, SUBARU_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, subaru_ts_last); - if (ts_elapsed > SUBARU_RT_INTERVAL) { - subaru_rt_torque_last = desired_torque; - subaru_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - subaru_desired_torque_last = 0; - subaru_rt_torque_last = 0; - subaru_ts_last = ts; - } - - if (violation) { - tx = 0; - } - - } - return tx; -} - -static int subaru_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - int bus_fwd = -1; - - if (!relay_malfunction) { - if (bus_num == 0) { - bus_fwd = 2; // Camera CAN - } - if (bus_num == 2) { - // 290 is LKAS for Global Platform - // 356 is LKAS for outback 2015 - // 545 is ES_Distance - // 802 is ES_LKAS - int addr = GET_ADDR(to_fwd); - int block_msg = (addr == 290) || (addr == 356) || (addr == 545) || (addr == 802); - if (!block_msg) { - bus_fwd = 0; // Main CAN - } - } - } - // fallback to do not forward - return bus_fwd; -} - -const safety_hooks subaru_hooks = { - .init = nooutput_init, - .rx = subaru_rx_hook, - .tx = subaru_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = subaru_fwd_hook, -}; diff --git a/panda/board/safety/safety_tesla.h b/panda/board/safety/safety_tesla.h deleted file mode 100644 index 2e5d20c622..0000000000 --- a/panda/board/safety/safety_tesla.h +++ /dev/null @@ -1,213 +0,0 @@ -// board enforces -// in-state -// accel set/resume -// out-state -// cancel button -// regen paddle -// accel rising edge -// brake rising edge -// brake > 0mph -// -bool fmax_limit_check(float val, const float MAX_VAL, const float MIN_VAL) { - return (val > MAX_VAL) || (val < MIN_VAL); -} - -// 2m/s are added to be less restrictive -const struct lookup_t TESLA_LOOKUP_ANGLE_RATE_UP = { - {2., 7., 17.}, - {5., .8, .25}}; - -const struct lookup_t TESLA_LOOKUP_ANGLE_RATE_DOWN = { - {2., 7., 17.}, - {5., 3.5, .8}}; - -const struct lookup_t TESLA_LOOKUP_MAX_ANGLE = { - {2., 29., 38.}, - {410., 92., 36.}}; - -const uint32_t TESLA_RT_INTERVAL = 250000; // 250ms between real time checks - -// state of angle limits -float tesla_desired_angle_last = 0; // last desired steer angle -float tesla_rt_angle_last = 0.; // last real time angle -float tesla_ts_angle_last = 0; - -int tesla_controls_allowed_last = 0; - -int tesla_brake_prev = 0; -int tesla_gas_prev = 0; -int tesla_speed = 0; -int eac_status = 0; - -void set_gmlan_digital_output(int to_set); -void reset_gmlan_switch_timeout(void); -void gmlan_switch_init(int timeout_enable); - - -static void tesla_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - set_gmlan_digital_output(0); // #define GMLAN_HIGH 0 - reset_gmlan_switch_timeout(); //we're still in tesla safety mode, reset the timeout counter and make sure our output is enabled - - int addr = GET_ADDR(to_push); - - if (addr == 0x45) { - // 6 bits starting at position 0 - int lever_position = GET_BYTE(to_push, 0) & 0x3F; - if (lever_position == 2) { // pull forward - // activate openpilot - controls_allowed = 1; - } - if (lever_position == 1) { // push towards the back - // deactivate openpilot - controls_allowed = 0; - } - } - - // exit controls on brake press - // DI_torque2::DI_brakePedal 0x118 - if (addr == 0x118) { - // 1 bit at position 16 - if ((GET_BYTE(to_push, 1) & 0x80) != 0) { - // disable break cancel by commenting line below - controls_allowed = 0; - } - //get vehicle speed in m/s. Tesla gives MPH - tesla_speed = (((((GET_BYTE(to_push, 3) & 0xF) << 8) + GET_BYTE(to_push, 2)) * 0.05) - 25) * 1.609 / 3.6; - if (tesla_speed < 0) { - tesla_speed = 0; - } - } - - // exit controls on EPAS error - // EPAS_sysStatus::EPAS_eacStatus 0x370 - if (addr == 0x370) { - // if EPAS_eacStatus is not 1 or 2, disable control - eac_status = (GET_BYTE(to_push, 6) >> 5) & 0x7; - // For human steering override we must not disable controls when eac_status == 0 - // Additional safety: we could only allow eac_status == 0 when we have human steering allowed - if (controls_allowed && (eac_status != 0) && (eac_status != 1) && (eac_status != 2)) { - controls_allowed = 0; - //puts("EPAS error! \n"); - } - } - //get latest steering wheel angle - if (addr == 0x00E) { - float angle_meas_now = (int)(((((GET_BYTE(to_push, 0) & 0x3F) << 8) + GET_BYTE(to_push, 1)) * 0.1) - 819.2); - uint32_t ts = TIM2->CNT; - uint32_t ts_elapsed = get_ts_elapsed(ts, tesla_ts_angle_last); - - // *** angle real time check - // add 1 to not false trigger the violation and multiply by 25 since the check is done every 250 ms and steer angle is updated at 100Hz - float rt_delta_angle_up = (interpolate(TESLA_LOOKUP_ANGLE_RATE_UP, tesla_speed) * 25.) + 1.; - float rt_delta_angle_down = (interpolate(TESLA_LOOKUP_ANGLE_RATE_DOWN, tesla_speed) * 25.) + 1.; - float highest_rt_angle = tesla_rt_angle_last + ((tesla_rt_angle_last > 0.) ? rt_delta_angle_up : rt_delta_angle_down); - float lowest_rt_angle = tesla_rt_angle_last - ((tesla_rt_angle_last > 0.) ? rt_delta_angle_down : rt_delta_angle_up); - - if ((ts_elapsed > TESLA_RT_INTERVAL) || (controls_allowed && !tesla_controls_allowed_last)) { - tesla_rt_angle_last = angle_meas_now; - tesla_ts_angle_last = ts; - } - - // check for violation; - if (fmax_limit_check(angle_meas_now, highest_rt_angle, lowest_rt_angle)) { - // We should not be able to STEER under these conditions - // Other sending is fine (to allow human override) - controls_allowed = 0; - //puts("WARN: RT Angle - No steer allowed! \n"); - } else { - controls_allowed = 1; - } - - tesla_controls_allowed_last = controls_allowed; - } -} - -// all commands: gas/regen, friction brake and steering -// if controls_allowed and no pedals pressed -// allow all commands up to limit -// else -// block all commands that produce actuation - -static int tesla_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - - // do not transmit CAN message if steering angle too high - // DAS_steeringControl::DAS_steeringAngleRequest - if (addr == 0x488) { - float angle_raw = ((GET_BYTE(to_send, 0) & 0x7F) << 8) + GET_BYTE(to_send, 1); - float desired_angle = (angle_raw * 0.1) - 1638.35; - bool violation = 0; - int st_enabled = GET_BYTE(to_send, 2) & 0x40; - - if (st_enabled == 0) { - //steering is not enabled, do not check angles and do send - tesla_desired_angle_last = desired_angle; - } else if (controls_allowed) { - // add 1 to not false trigger the violation - float delta_angle_up = interpolate(TESLA_LOOKUP_ANGLE_RATE_UP, tesla_speed) + 1.; - float delta_angle_down = interpolate(TESLA_LOOKUP_ANGLE_RATE_DOWN, tesla_speed) + 1.; - float highest_desired_angle = tesla_desired_angle_last + ((tesla_desired_angle_last > 0.) ? delta_angle_up : delta_angle_down); - float lowest_desired_angle = tesla_desired_angle_last - ((tesla_desired_angle_last > 0.) ? delta_angle_down : delta_angle_up); - float TESLA_MAX_ANGLE = interpolate(TESLA_LOOKUP_MAX_ANGLE, tesla_speed) + 1.; - - //check for max angles - violation |= fmax_limit_check(desired_angle, TESLA_MAX_ANGLE, -TESLA_MAX_ANGLE); - - //check for angle delta changes - violation |= fmax_limit_check(desired_angle, highest_desired_angle, lowest_desired_angle); - - if (violation) { - controls_allowed = 0; - tx = 0; - } - tesla_desired_angle_last = desired_angle; - } else { - tx = 0; - } - } - return tx; -} - -static void tesla_init(int16_t param) { - UNUSED(param); - controls_allowed = 0; - gmlan_switch_init(1); //init the gmlan switch with 1s timeout enabled -} - -static int tesla_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - - int bus_fwd = -1; - int addr = GET_ADDR(to_fwd); - - if (bus_num == 0) { - // change inhibit of GTW_epasControl - - if (addr != 0x214) { - // remove EPB_epasControl - bus_fwd = 2; // Custom EPAS bus - } - if (addr == 0x101) { - to_fwd->RDLR = GET_BYTES_04(to_fwd) | 0x4000; // 0x4000: WITH_ANGLE, 0xC000: WITH_BOTH (angle and torque) - uint32_t checksum = (GET_BYTE(to_fwd, 1) + GET_BYTE(to_fwd, 0) + 2) & 0xFF; - to_fwd->RDLR = GET_BYTES_04(to_fwd) & 0xFFFF; - to_fwd->RDLR = GET_BYTES_04(to_fwd) + (checksum << 16); - } - } - if (bus_num == 2) { - // remove GTW_epasControl in forwards - if (addr != 0x101) { - bus_fwd = 0; // Chassis CAN - } - } - return bus_fwd; -} - -const safety_hooks tesla_hooks = { - .init = tesla_init, - .rx = tesla_rx_hook, - .tx = tesla_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = tesla_fwd_hook, -}; diff --git a/panda/board/safety/safety_toyota.h b/panda/board/safety/safety_toyota.h deleted file mode 100644 index 0576a46381..0000000000 --- a/panda/board/safety/safety_toyota.h +++ /dev/null @@ -1,228 +0,0 @@ -// global torque limit -const int TOYOTA_MAX_TORQUE = 1500; // max torque cmd allowed ever - -// rate based torque limit + stay within actually applied -// packet is sent at 100hz, so this limit is 1000/sec -const int TOYOTA_MAX_RATE_UP = 10; // ramp up slow -const int TOYOTA_MAX_RATE_DOWN = 25; // ramp down fast -const int TOYOTA_MAX_TORQUE_ERROR = 350; // max torque cmd in excess of torque motor - -// real time torque limit to prevent controls spamming -// the real time limit is 1500/sec -const int TOYOTA_MAX_RT_DELTA = 375; // max delta torque allowed for real time checks -const uint32_t TOYOTA_RT_INTERVAL = 250000; // 250ms between real time checks - -// longitudinal limits -const int TOYOTA_MAX_ACCEL = 1500; // 1.5 m/s2 -const int TOYOTA_MIN_ACCEL = -3000; // 3.0 m/s2 - -const int TOYOTA_GAS_INTERCEPTOR_THRESHOLD = 475; // ratio between offset and gain from dbc file - -// allowed DSU messages on bus 0 and 1 -const AddrBus TOYOTA_TX_MSGS[] = {{0x283, 0}, {0x2E6, 0}, {0x2E7, 0}, {0x33E, 0}, {0x344, 0}, {0x365, 0}, {0x366, 0}, {0x4CB, 0}, // DSU bus 0 - {0x128, 1}, {0x141, 1}, {0x160, 1}, {0x161, 1}, {0x470, 1}, // DSU bus 1 - {0x2E4, 0}, {0x411, 0}, {0x412, 0}, {0x343, 0}, {0x1D2, 0}, // LKAS + ACC - {0x200, 0}}; // interceptor - -// global actuation limit states -int toyota_dbc_eps_torque_factor = 100; // conversion factor for STEER_TORQUE_EPS in %: see dbc file - -// states -int toyota_desired_torque_last = 0; // last desired steer torque -int toyota_rt_torque_last = 0; // last desired torque for real time check -uint32_t toyota_ts_last = 0; -int toyota_cruise_engaged_last = 0; // cruise state -int toyota_gas_prev = 0; -struct sample_t toyota_torque_meas; // last 3 motor torques produced by the eps - - -static void toyota_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - // get eps motor torque (0.66 factor in dbc) - if (addr == 0x260) { - int torque_meas_new = (GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6); - torque_meas_new = to_signed(torque_meas_new, 16); - - // scale by dbc_factor - torque_meas_new = (torque_meas_new * toyota_dbc_eps_torque_factor) / 100; - - // update array of sample - update_sample(&toyota_torque_meas, torque_meas_new); - - // increase torque_meas by 1 to be conservative on rounding - toyota_torque_meas.min--; - toyota_torque_meas.max++; - } - - // enter controls on rising edge of ACC, exit controls on ACC off - if (addr == 0x1D2) { - // 5th bit is CRUISE_ACTIVE - int cruise_engaged = GET_BYTE(to_push, 0) & 0x20; - if (!cruise_engaged) { - controls_allowed = 0; - } - if (cruise_engaged && !toyota_cruise_engaged_last) { - controls_allowed = 1; - } - toyota_cruise_engaged_last = cruise_engaged; - } - - // exit controls on rising edge of interceptor gas press - if (addr == 0x201) { - gas_interceptor_detected = 1; - int gas_interceptor = GET_INTERCEPTOR(to_push); - if ((gas_interceptor > TOYOTA_GAS_INTERCEPTOR_THRESHOLD) && - (gas_interceptor_prev <= TOYOTA_GAS_INTERCEPTOR_THRESHOLD) && - long_controls_allowed) { - controls_allowed = 0; - } - gas_interceptor_prev = gas_interceptor; - } - - // exit controls on rising edge of gas press - if (addr == 0x2C1) { - int gas = GET_BYTE(to_push, 6) & 0xFF; - if ((gas > 0) && (toyota_gas_prev == 0) && !gas_interceptor_detected && long_controls_allowed) { - controls_allowed = 0; - } - toyota_gas_prev = gas; - } - - // 0x2E4 is lkas cmd. If it is on bus 0, then relay is unexpectedly closed - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (addr == 0x2E4) && (bus == 0)) { - relay_malfunction = true; - } -} - -static int toyota_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - - if (!addr_allowed(addr, bus, TOYOTA_TX_MSGS, sizeof(TOYOTA_TX_MSGS)/sizeof(TOYOTA_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // Check if msg is sent on BUS 0 - if (bus == 0) { - - // GAS PEDAL: safety check - if (addr == 0x200) { - if (!controls_allowed || !long_controls_allowed) { - if (GET_BYTE(to_send, 0) || GET_BYTE(to_send, 1)) { - tx = 0; - } - } - } - - // ACCEL: safety check on byte 1-2 - if (addr == 0x343) { - int desired_accel = (GET_BYTE(to_send, 0) << 8) | GET_BYTE(to_send, 1); - desired_accel = to_signed(desired_accel, 16); - if (!controls_allowed || !long_controls_allowed) { - if (desired_accel != 0) { - tx = 0; - } - } - bool violation = max_limit_check(desired_accel, TOYOTA_MAX_ACCEL, TOYOTA_MIN_ACCEL); - if (violation) { - tx = 0; - } - } - - // STEER: safety check on bytes 2-3 - if (addr == 0x2E4) { - int desired_torque = (GET_BYTE(to_send, 1) << 8) | GET_BYTE(to_send, 2); - desired_torque = to_signed(desired_torque, 16); - bool violation = 0; - - uint32_t ts = TIM2->CNT; - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, TOYOTA_MAX_TORQUE, -TOYOTA_MAX_TORQUE); - - // *** torque rate limit check *** - violation |= dist_to_meas_check(desired_torque, toyota_desired_torque_last, - &toyota_torque_meas, TOYOTA_MAX_RATE_UP, TOYOTA_MAX_RATE_DOWN, TOYOTA_MAX_TORQUE_ERROR); - - // used next time - toyota_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, toyota_rt_torque_last, TOYOTA_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, toyota_ts_last); - if (ts_elapsed > TOYOTA_RT_INTERVAL) { - toyota_rt_torque_last = desired_torque; - toyota_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = 1; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - toyota_desired_torque_last = 0; - toyota_rt_torque_last = 0; - toyota_ts_last = ts; - } - - if (violation) { - tx = 0; - } - } - } - - return tx; -} - -static void toyota_init(int16_t param) { - controls_allowed = 0; - relay_malfunction = 0; - toyota_dbc_eps_torque_factor = param; -} - -static int toyota_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - - int bus_fwd = -1; - if (!relay_malfunction) { - if (bus_num == 0) { - bus_fwd = 2; - } - if (bus_num == 2) { - int addr = GET_ADDR(to_fwd); - // block stock lkas messages and stock acc messages (if OP is doing ACC) - // in TSS2, 0x191 is LTA which we need to block to avoid controls collision - int is_lkas_msg = ((addr == 0x2E4) || (addr == 0x412) || (addr == 0x191)); - // in TSS2 the camera does ACC as well, so filter 0x343 - int is_acc_msg = (addr == 0x343); - int block_msg = is_lkas_msg || (is_acc_msg && long_controls_allowed); - if (!block_msg) { - bus_fwd = 0; - } - } - } - return bus_fwd; -} - -const safety_hooks toyota_hooks = { - .init = toyota_init, - .rx = toyota_rx_hook, - .tx = toyota_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = toyota_fwd_hook, -}; diff --git a/panda/board/safety/safety_toyota_ipas.h b/panda/board/safety/safety_toyota_ipas.h deleted file mode 100644 index d5833e45db..0000000000 --- a/panda/board/safety/safety_toyota_ipas.h +++ /dev/null @@ -1,168 +0,0 @@ -// uses tons from safety_toyota -// TODO: refactor to repeat less code - -// IPAS override -const int32_t TOYOTA_IPAS_OVERRIDE_THRESHOLD = 200; // disallow controls when user torque exceeds this value - -// 2m/s are added to be less restrictive -const struct lookup_t LOOKUP_ANGLE_RATE_UP = { - {2., 7., 17.}, - {5., .8, .15}}; - -const struct lookup_t LOOKUP_ANGLE_RATE_DOWN = { - {2., 7., 17.}, - {5., 3.5, .4}}; - -const float RT_ANGLE_FUDGE = 1.5; // for RT checks allow 50% more angle change -const float CAN_TO_DEG = 2. / 3.; // convert angles from CAN unit to degrees - -int ipas_state = 1; // 1 disabled, 3 executing angle control, 5 override -int angle_control = 0; // 1 if direct angle control packets are seen -float speed = 0.; - -struct sample_t angle_meas; // last 3 steer angles -struct sample_t torque_driver; // last 3 driver steering torque - -// state of angle limits -int16_t desired_angle_last = 0; // last desired steer angle -int16_t rt_angle_last = 0; // last desired torque for real time check -uint32_t ts_angle_last = 0; - -int controls_allowed_last = 0; - - -static void toyota_ipas_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - // check standard toyota stuff as well - toyota_rx_hook(to_push); - - int addr = GET_ADDR(to_push); - - if (addr == 0x260) { - // get driver steering torque - int16_t torque_driver_new = (GET_BYTE(to_push, 1) << 8) | GET_BYTE(to_push, 2); - - // update array of samples - update_sample(&torque_driver, torque_driver_new); - } - - // get steer angle - if (addr == 0x25) { - int angle_meas_new = ((GET_BYTE(to_push, 0) & 0xF) << 8) | GET_BYTE(to_push, 1); - uint32_t ts = TIM2->CNT; - - angle_meas_new = to_signed(angle_meas_new, 12); - - // update array of samples - update_sample(&angle_meas, angle_meas_new); - - // *** angle real time check - // add 1 to not false trigger the violation and multiply by 20 since the check is done every 250ms and steer angle is updated at 80Hz - int rt_delta_angle_up = ((int)(RT_ANGLE_FUDGE * ((interpolate(LOOKUP_ANGLE_RATE_UP, speed) * 20. * CAN_TO_DEG) + 1.))); - int rt_delta_angle_down = ((int)(RT_ANGLE_FUDGE * ((interpolate(LOOKUP_ANGLE_RATE_DOWN, speed) * 20. * CAN_TO_DEG) + 1.))); - int highest_rt_angle = rt_angle_last + ((rt_angle_last > 0) ? rt_delta_angle_up : rt_delta_angle_down); - int lowest_rt_angle = rt_angle_last - ((rt_angle_last > 0) ? rt_delta_angle_down : rt_delta_angle_up); - - // every RT_INTERVAL or when controls are turned on, set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, ts_angle_last); - if ((ts_elapsed > TOYOTA_RT_INTERVAL) || (controls_allowed && !controls_allowed_last)) { - rt_angle_last = angle_meas_new; - ts_angle_last = ts; - } - - // check for violation - if (angle_control && - ((angle_meas_new < lowest_rt_angle) || - (angle_meas_new > highest_rt_angle))) { - controls_allowed = 0; - } - - controls_allowed_last = controls_allowed; - } - - // get speed - if (addr == 0xb4) { - speed = ((float)((GET_BYTE(to_push, 5) << 8) | GET_BYTE(to_push, 6))) * 0.01 / 3.6; - } - - // get ipas state - if (addr == 0x262) { - ipas_state = GET_BYTE(to_push, 0) & 0xf; - } - - // exit controls on high steering override - if (angle_control && ((torque_driver.min > TOYOTA_IPAS_OVERRIDE_THRESHOLD) || - (torque_driver.max < -TOYOTA_IPAS_OVERRIDE_THRESHOLD) || - (ipas_state==5))) { - controls_allowed = 0; - } -} - -static int toyota_ipas_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - - int tx = 1; - int bypass_standard_tx_hook = 0; - int bus = GET_BUS(to_send); - int addr = GET_ADDR(to_send); - - // Check if msg is sent on BUS 0 - if (bus == 0) { - - // STEER ANGLE - if ((addr == 0x266) || (addr == 0x167)) { - - angle_control = 1; // we are in angle control mode - int desired_angle = ((GET_BYTE(to_send, 0) & 0xF) << 8) | GET_BYTE(to_send, 1); - int ipas_state_cmd = GET_BYTE(to_send, 0) >> 4; - bool violation = 0; - - desired_angle = to_signed(desired_angle, 12); - - if (controls_allowed) { - // add 1 to not false trigger the violation - float delta_angle_float; - delta_angle_float = (interpolate(LOOKUP_ANGLE_RATE_UP, speed) * CAN_TO_DEG) + 1.; - int delta_angle_up = (int) (delta_angle_float); - delta_angle_float = (interpolate(LOOKUP_ANGLE_RATE_DOWN, speed) * CAN_TO_DEG) + 1.; - int delta_angle_down = (int) (delta_angle_float); - - int highest_desired_angle = desired_angle_last + ((desired_angle_last > 0) ? delta_angle_up : delta_angle_down); - int lowest_desired_angle = desired_angle_last - ((desired_angle_last > 0) ? delta_angle_down : delta_angle_up); - if ((desired_angle > highest_desired_angle) || - (desired_angle < lowest_desired_angle)){ - violation = 1; - controls_allowed = 0; - } - } - - // desired steer angle should be the same as steer angle measured when controls are off - if ((!controls_allowed) && - ((desired_angle < (angle_meas.min - 1)) || - (desired_angle > (angle_meas.max + 1)) || - (ipas_state_cmd != 1))) { - violation = 1; - } - - desired_angle_last = desired_angle; - - if (violation) { - tx = 0; - } - bypass_standard_tx_hook = 1; - } - } - - // check standard toyota stuff as well if addr isn't IPAS related - if (!bypass_standard_tx_hook) { - tx &= toyota_tx_hook(to_send); - } - - return tx; -} - -const safety_hooks toyota_ipas_hooks = { - .init = toyota_init, - .rx = toyota_ipas_rx_hook, - .tx = toyota_ipas_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = toyota_fwd_hook, -}; diff --git a/panda/board/safety/safety_volkswagen.h b/panda/board/safety/safety_volkswagen.h deleted file mode 100644 index c16e559ce1..0000000000 --- a/panda/board/safety/safety_volkswagen.h +++ /dev/null @@ -1,177 +0,0 @@ -// Safety-relevant CAN messages for the Volkswagen MQB platform. -#define MSG_EPS_01 0x09F -#define MSG_MOTOR_20 0x121 -#define MSG_ACC_06 0x122 -#define MSG_HCA_01 0x126 -#define MSG_GRA_ACC_01 0x12B -#define MSG_LDW_02 0x397 - -const int VOLKSWAGEN_MAX_STEER = 250; // 2.5 Nm (EPS side max of 3.0Nm with fault if violated) -const int VOLKSWAGEN_MAX_RT_DELTA = 75; // 4 max rate up * 50Hz send rate * 250000 RT interval / 1000000 = 50 ; 50 * 1.5 for safety pad = 75 -const uint32_t VOLKSWAGEN_RT_INTERVAL = 250000; // 250ms between real time checks -const int VOLKSWAGEN_MAX_RATE_UP = 4; // 2.0 Nm/s available rate of change from the steering rack (EPS side delta-limit of 5.0 Nm/s) -const int VOLKSWAGEN_MAX_RATE_DOWN = 10; // 5.0 Nm/s available rate of change from the steering rack (EPS side delta-limit of 5.0 Nm/s) -const int VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE = 80; -const int VOLKSWAGEN_DRIVER_TORQUE_FACTOR = 3; - -// MSG_GRA_ACC_01 is allowed on bus 0 and 2 to keep compatibility with gateway and camera integration -const AddrBus VOLKSWAGEN_TX_MSGS[] = {{MSG_HCA_01, 0}, {MSG_GRA_ACC_01, 0}, {MSG_GRA_ACC_01, 2}, {MSG_LDW_02, 0}}; - -struct sample_t volkswagen_torque_driver; // last few driver torques measured -int volkswagen_rt_torque_last = 0; -int volkswagen_desired_torque_last = 0; -uint32_t volkswagen_ts_last = 0; -int volkswagen_gas_prev = 0; - -static void volkswagen_rx_hook(CAN_FIFOMailBox_TypeDef *to_push) { - int bus = GET_BUS(to_push); - int addr = GET_ADDR(to_push); - - // Update driver input torque samples from EPS_01.Driver_Strain for absolute torque, and EPS_01.Driver_Strain_VZ - // for the direction. - if ((bus == 0) && (addr == MSG_EPS_01)) { - int torque_driver_new = GET_BYTE(to_push, 5) | ((GET_BYTE(to_push, 6) & 0x1F) << 8); - int sign = (GET_BYTE(to_push, 6) & 0x80) >> 7; - if (sign == 1) { - torque_driver_new *= -1; - } - - update_sample(&volkswagen_torque_driver, torque_driver_new); - } - - // Monitor ACC_06.ACC_Status_ACC for stock ACC status. Because the current MQB port is lateral-only, OP's control - // allowed state is directly driven by stock ACC engagement. Permit the ACC message to come from either bus, in - // order to accommodate future camera-side integrations if needed. - if (addr == MSG_ACC_06) { - int acc_status = (GET_BYTE(to_push, 7) & 0x70) >> 4; - controls_allowed = ((acc_status == 3) || (acc_status == 4) || (acc_status == 5)) ? 1 : 0; - } - - // exit controls on rising edge of gas press. Bits [12-20) - if (addr == MSG_MOTOR_20) { - int gas = (GET_BYTES_04(to_push) >> 12) & 0xFF; - if ((gas > 0) && (volkswagen_gas_prev == 0) && long_controls_allowed) { - controls_allowed = 0; - } - volkswagen_gas_prev = gas; - } - - if ((safety_mode_cnt > RELAY_TRNS_TIMEOUT) && (bus == 0) && (addr == MSG_HCA_01)) { - relay_malfunction = true; - } -} - -static int volkswagen_tx_hook(CAN_FIFOMailBox_TypeDef *to_send) { - int addr = GET_ADDR(to_send); - int bus = GET_BUS(to_send); - int tx = 1; - - if (!addr_allowed(addr, bus, VOLKSWAGEN_TX_MSGS, sizeof(VOLKSWAGEN_TX_MSGS)/sizeof(VOLKSWAGEN_TX_MSGS[0]))) { - tx = 0; - } - - if (relay_malfunction) { - tx = 0; - } - - // Safety check for HCA_01 Heading Control Assist torque. - if (addr == MSG_HCA_01) { - bool violation = false; - - int desired_torque = GET_BYTE(to_send, 2) | ((GET_BYTE(to_send, 3) & 0x3F) << 8); - int sign = (GET_BYTE(to_send, 3) & 0x80) >> 7; - if (sign == 1) { - desired_torque *= -1; - } - - uint32_t ts = TIM2->CNT; - - if (controls_allowed) { - - // *** global torque limit check *** - violation |= max_limit_check(desired_torque, VOLKSWAGEN_MAX_STEER, -VOLKSWAGEN_MAX_STEER); - - // *** torque rate limit check *** - violation |= driver_limit_check(desired_torque, volkswagen_desired_torque_last, &volkswagen_torque_driver, - VOLKSWAGEN_MAX_STEER, VOLKSWAGEN_MAX_RATE_UP, VOLKSWAGEN_MAX_RATE_DOWN, - VOLKSWAGEN_DRIVER_TORQUE_ALLOWANCE, VOLKSWAGEN_DRIVER_TORQUE_FACTOR); - volkswagen_desired_torque_last = desired_torque; - - // *** torque real time rate limit check *** - violation |= rt_rate_limit_check(desired_torque, volkswagen_rt_torque_last, VOLKSWAGEN_MAX_RT_DELTA); - - // every RT_INTERVAL set the new limits - uint32_t ts_elapsed = get_ts_elapsed(ts, volkswagen_ts_last); - if (ts_elapsed > VOLKSWAGEN_RT_INTERVAL) { - volkswagen_rt_torque_last = desired_torque; - volkswagen_ts_last = ts; - } - } - - // no torque if controls is not allowed - if (!controls_allowed && (desired_torque != 0)) { - violation = true; - } - - // reset to 0 if either controls is not allowed or there's a violation - if (violation || !controls_allowed) { - volkswagen_desired_torque_last = 0; - volkswagen_rt_torque_last = 0; - volkswagen_ts_last = ts; - } - - if (violation) { - tx = 0; - } - } - - // FORCE CANCEL: ensuring that only the cancel button press is sent when controls are off. - // This avoids unintended engagements while still allowing resume spam - if ((addr == MSG_GRA_ACC_01) && !controls_allowed) { - // disallow resume and set: bits 16 and 19 - if ((GET_BYTE(to_send, 2) & 0x9) != 0) { - tx = 0; - } - } - - // 1 allows the message through - return tx; -} - -static int volkswagen_fwd_hook(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd) { - int addr = GET_ADDR(to_fwd); - int bus_fwd = -1; - - // NOTE: Will need refactoring for other bus layouts, such as no-forwarding at camera or J533 running-gear CAN - - if (!relay_malfunction) { - switch (bus_num) { - case 0: - // Forward all traffic from J533 gateway to Extended CAN devices. - bus_fwd = 2; - break; - case 2: - if ((addr == MSG_HCA_01) || (addr == MSG_LDW_02)) { - // OP takes control of the Heading Control Assist and Lane Departure Warning messages from the camera. - bus_fwd = -1; - } else { - // Forward all remaining traffic from Extended CAN devices to J533 gateway. - bus_fwd = 0; - } - break; - default: - // No other buses should be in use; fallback to do-not-forward. - bus_fwd = -1; - break; - } - } - return bus_fwd; -} - -const safety_hooks volkswagen_hooks = { - .init = nooutput_init, - .rx = volkswagen_rx_hook, - .tx = volkswagen_tx_hook, - .tx_lin = nooutput_tx_lin_hook, - .fwd = volkswagen_fwd_hook, -}; diff --git a/panda/board/safety_declarations.h b/panda/board/safety_declarations.h deleted file mode 100644 index e192d74fb7..0000000000 --- a/panda/board/safety_declarations.h +++ /dev/null @@ -1,64 +0,0 @@ -// sample struct that keeps 3 samples in memory -struct sample_t { - int values[6]; - int min; - int max; -} sample_t_default = {{0}, 0, 0}; - -// safety code requires floats -struct lookup_t { - float x[3]; - float y[3]; -}; - -typedef struct { - int addr; - int bus; -} AddrBus; - -void safety_rx_hook(CAN_FIFOMailBox_TypeDef *to_push); -int safety_tx_hook(CAN_FIFOMailBox_TypeDef *to_send); -int safety_tx_lin_hook(int lin_num, uint8_t *data, int len); -uint32_t get_ts_elapsed(uint32_t ts, uint32_t ts_last); -int to_signed(int d, int bits); -void update_sample(struct sample_t *sample, int sample_new); -bool max_limit_check(int val, const int MAX, const int MIN); -bool dist_to_meas_check(int val, int val_last, struct sample_t *val_meas, - const int MAX_RATE_UP, const int MAX_RATE_DOWN, const int MAX_ERROR); -bool driver_limit_check(int val, int val_last, struct sample_t *val_driver, - const int MAX, const int MAX_RATE_UP, const int MAX_RATE_DOWN, - const int MAX_ALLOWANCE, const int DRIVER_FACTOR); -bool rt_rate_limit_check(int val, int val_last, const int MAX_RT_DELTA); -float interpolate(struct lookup_t xy, float x); -bool addr_allowed(int addr, int bus, const AddrBus addr_list[], int len); - -typedef void (*safety_hook_init)(int16_t param); -typedef void (*rx_hook)(CAN_FIFOMailBox_TypeDef *to_push); -typedef int (*tx_hook)(CAN_FIFOMailBox_TypeDef *to_send); -typedef int (*tx_lin_hook)(int lin_num, uint8_t *data, int len); -typedef int (*fwd_hook)(int bus_num, CAN_FIFOMailBox_TypeDef *to_fwd); - -typedef struct { - safety_hook_init init; - rx_hook rx; - tx_hook tx; - tx_lin_hook tx_lin; - fwd_hook fwd; -} safety_hooks; - -// This can be set by the safety hooks -bool controls_allowed = false; -bool relay_malfunction = false; -bool gas_interceptor_detected = false; -int gas_interceptor_prev = 0; - -// This is set by USB command 0xdf -bool long_controls_allowed = true; - -// time since safety mode has been changed -uint32_t safety_mode_cnt = 0U; -// allow 1s of transition timeout after relay changes state before assessing malfunctioning -const uint32_t RELAY_TRNS_TIMEOUT = 1U; - -// avg between 2 tracks -#define GET_INTERCEPTOR(msg) (((GET_BYTE((msg), 0) << 8) + GET_BYTE((msg), 1) + ((GET_BYTE((msg), 2) << 8) + GET_BYTE((msg), 3)) / 2 ) / 2) diff --git a/panda/board/spi_flasher.h b/panda/board/spi_flasher.h deleted file mode 100644 index fbdbab8a61..0000000000 --- a/panda/board/spi_flasher.h +++ /dev/null @@ -1,340 +0,0 @@ -// flasher state variables -uint32_t *prog_ptr = NULL; -int unlocked = 0; - -#ifdef uart_ring -void debug_ring_callback(uart_ring *ring) {} -#endif - -int usb_cb_control_msg(USB_Setup_TypeDef *setup, uint8_t *resp, bool hardwired) { - int resp_len = 0; - - // flasher machine - memset(resp, 0, 4); - memcpy(resp+4, "\xde\xad\xd0\x0d", 4); - resp[0] = 0xff; - resp[2] = setup->b.bRequest; - resp[3] = ~setup->b.bRequest; - *((uint32_t **)&resp[8]) = prog_ptr; - resp_len = 0xc; - - int sec; - switch (setup->b.bRequest) { - // **** 0xb0: flasher echo - case 0xb0: - resp[1] = 0xff; - break; - // **** 0xb1: unlock flash - case 0xb1: - if (FLASH->CR & FLASH_CR_LOCK) { - FLASH->KEYR = 0x45670123; - FLASH->KEYR = 0xCDEF89AB; - resp[1] = 0xff; - } - current_board->set_led(LED_GREEN, 1); - unlocked = 1; - prog_ptr = (uint32_t *)0x8004000; - break; - // **** 0xb2: erase sector - case 0xb2: - sec = setup->b.wValue.w; - // don't erase the bootloader - if (sec != 0 && sec < 12 && unlocked) { - FLASH->CR = (sec << 3) | FLASH_CR_SER; - FLASH->CR |= FLASH_CR_STRT; - while (FLASH->SR & FLASH_SR_BSY); - resp[1] = 0xff; - } - break; - // **** 0xd0: fetch serial number - case 0xd0: - #ifdef STM32F4 - // addresses are OTP - if (setup->b.wValue.w == 1) { - memcpy(resp, (void *)0x1fff79c0, 0x10); - resp_len = 0x10; - } else { - get_provision_chunk(resp); - resp_len = PROVISION_CHUNK_LEN; - } - #endif - break; - // **** 0xd1: enter bootloader mode - case 0xd1: - // this allows reflashing of the bootstub - // so it's blocked over wifi - switch (setup->b.wValue.w) { - case 0: - #ifdef ALLOW_DEBUG - if (hardwired) { - #else - // no more bootstub on UNO - if (hardwired && hw_type != HW_TYPE_UNO) { - #endif - puts("-> entering bootloader\n"); - enter_bootloader_mode = ENTER_BOOTLOADER_MAGIC; - NVIC_SystemReset(); - } - break; - case 1: - puts("-> entering softloader\n"); - enter_bootloader_mode = ENTER_SOFTLOADER_MAGIC; - NVIC_SystemReset(); - break; - } - break; - // **** 0xd6: get version - case 0xd6: - COMPILE_TIME_ASSERT(sizeof(gitversion) <= MAX_RESP_LEN); - memcpy(resp, gitversion, sizeof(gitversion)); - resp_len = sizeof(gitversion); - break; - // **** 0xd8: reset ST - case 0xd8: - NVIC_SystemReset(); - break; - } - return resp_len; -} - -int usb_cb_ep1_in(void *usbdata, int len, bool hardwired) { - UNUSED(usbdata); - UNUSED(len); - UNUSED(hardwired); - return 0; -} -void usb_cb_ep3_out(void *usbdata, int len, bool hardwired) { - UNUSED(usbdata); - UNUSED(len); - UNUSED(hardwired); -} - -int is_enumerated = 0; -void usb_cb_enumeration_complete(void) { - puts("USB enumeration complete\n"); - is_enumerated = 1; -} - -void usb_cb_ep2_out(void *usbdata, int len, bool hardwired) { - UNUSED(hardwired); - current_board->set_led(LED_RED, 0); - for (int i = 0; i < len/4; i++) { - // program byte 1 - FLASH->CR = FLASH_CR_PSIZE_1 | FLASH_CR_PG; - - *prog_ptr = *(uint32_t*)(usbdata+(i*4)); - while (FLASH->SR & FLASH_SR_BSY); - - //*(uint64_t*)(&spi_tx_buf[0x30+(i*4)]) = *prog_ptr; - prog_ptr++; - } - current_board->set_led(LED_RED, 1); -} - - -int spi_cb_rx(uint8_t *data, int len, uint8_t *data_out) { - UNUSED(len); - int resp_len = 0; - switch (data[0]) { - case 0: - // control transfer - resp_len = usb_cb_control_msg((USB_Setup_TypeDef *)(data+4), data_out, 0); - break; - case 2: - // ep 2, flash! - usb_cb_ep2_out(data+4, data[2], 0); - break; - } - return resp_len; -} - -#ifdef PEDAL - -#include "drivers/llcan.h" -#define CAN CAN1 - -#define CAN_BL_INPUT 0x1 -#define CAN_BL_OUTPUT 0x2 - -void CAN1_TX_IRQ_Handler(void) { - // clear interrupt - CAN->TSR |= CAN_TSR_RQCP0; -} - -#define ISOTP_BUF_SIZE 0x110 - -uint8_t isotp_buf[ISOTP_BUF_SIZE]; -uint8_t *isotp_buf_ptr = NULL; -int isotp_buf_remain = 0; - -uint8_t isotp_buf_out[ISOTP_BUF_SIZE]; -uint8_t *isotp_buf_out_ptr = NULL; -int isotp_buf_out_remain = 0; -int isotp_buf_out_idx = 0; - -void bl_can_send(uint8_t *odat) { - // wait for send - while (!(CAN->TSR & CAN_TSR_TME0)); - - // send continue - CAN->sTxMailBox[0].TDLR = ((uint32_t*)odat)[0]; - CAN->sTxMailBox[0].TDHR = ((uint32_t*)odat)[1]; - CAN->sTxMailBox[0].TDTR = 8; - CAN->sTxMailBox[0].TIR = (CAN_BL_OUTPUT << 21) | 1; -} - -void CAN1_RX0_IRQ_Handler(void) { - while (CAN->RF0R & CAN_RF0R_FMP0) { - if ((CAN->sFIFOMailBox[0].RIR>>21) == CAN_BL_INPUT) { - uint8_t dat[8]; - for (int i = 0; i < 8; i++) { - dat[i] = GET_BYTE(&CAN->sFIFOMailBox[0], i); - } - uint8_t odat[8]; - uint8_t type = dat[0] & 0xF0; - if (type == 0x30) { - // continue - while (isotp_buf_out_remain > 0) { - // wait for send - while (!(CAN->TSR & CAN_TSR_TME0)); - - odat[0] = 0x20 | isotp_buf_out_idx; - memcpy(odat+1, isotp_buf_out_ptr, 7); - isotp_buf_out_remain -= 7; - isotp_buf_out_ptr += 7; - isotp_buf_out_idx++; - - bl_can_send(odat); - } - } else if (type == 0x20) { - if (isotp_buf_remain > 0) { - memcpy(isotp_buf_ptr, dat+1, 7); - isotp_buf_ptr += 7; - isotp_buf_remain -= 7; - } - if (isotp_buf_remain <= 0) { - int len = isotp_buf_ptr - isotp_buf + isotp_buf_remain; - - // call the function - memset(isotp_buf_out, 0, ISOTP_BUF_SIZE); - isotp_buf_out_remain = spi_cb_rx(isotp_buf, len, isotp_buf_out); - isotp_buf_out_ptr = isotp_buf_out; - isotp_buf_out_idx = 0; - - // send initial - if (isotp_buf_out_remain <= 7) { - odat[0] = isotp_buf_out_remain; - memcpy(odat+1, isotp_buf_out_ptr, isotp_buf_out_remain); - } else { - odat[0] = 0x10 | (isotp_buf_out_remain>>8); - odat[1] = isotp_buf_out_remain & 0xFF; - memcpy(odat+2, isotp_buf_out_ptr, 6); - isotp_buf_out_remain -= 6; - isotp_buf_out_ptr += 6; - isotp_buf_out_idx++; - } - - bl_can_send(odat); - } - } else if (type == 0x10) { - int len = ((dat[0]&0xF)<<8) | dat[1]; - - // setup buffer - isotp_buf_ptr = isotp_buf; - memcpy(isotp_buf_ptr, dat+2, 6); - - if (len < (ISOTP_BUF_SIZE-0x10)) { - isotp_buf_ptr += 6; - isotp_buf_remain = len-6; - } - - memset(odat, 0, 8); - odat[0] = 0x30; - bl_can_send(odat); - } - } - // next - CAN->RF0R |= CAN_RF0R_RFOM0; - } -} - -void CAN1_SCE_IRQ_Handler(void) { - llcan_clear_send(CAN); -} - -#endif - -void soft_flasher_start(void) { - #ifdef PEDAL - REGISTER_INTERRUPT(CAN1_TX_IRQn, CAN1_TX_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN1_RX0_IRQn, CAN1_RX0_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - REGISTER_INTERRUPT(CAN1_SCE_IRQn, CAN1_SCE_IRQ_Handler, CAN_INTERRUPT_RATE, FAULT_INTERRUPT_RATE_CAN_1) - #endif - - puts("\n\n\n************************ FLASHER START ************************\n"); - - enter_bootloader_mode = 0; - - RCC->AHB1ENR |= RCC_AHB1ENR_DMA2EN; - RCC->APB2ENR |= RCC_APB2ENR_SPI1EN; - RCC->AHB2ENR |= RCC_AHB2ENR_OTGFSEN; - RCC->APB1ENR |= RCC_APB1ENR_USART2EN; - -// pedal has the canloader -#ifdef PEDAL - RCC->APB1ENR |= RCC_APB1ENR_CAN1EN; - - // B8,B9: CAN 1 - set_gpio_alternate(GPIOB, 8, GPIO_AF9_CAN1); - set_gpio_alternate(GPIOB, 9, GPIO_AF9_CAN1); - current_board->enable_can_transciever(1, true); - - // init can - llcan_set_speed(CAN1, 5000, false, false); - llcan_init(CAN1); -#endif - - // A4,A5,A6,A7: setup SPI - set_gpio_alternate(GPIOA, 4, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 5, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 6, GPIO_AF5_SPI1); - set_gpio_alternate(GPIOA, 7, GPIO_AF5_SPI1); - - // A2,A3: USART 2 for debugging - set_gpio_alternate(GPIOA, 2, GPIO_AF7_USART2); - set_gpio_alternate(GPIOA, 3, GPIO_AF7_USART2); - - // A11,A12: USB - set_gpio_alternate(GPIOA, 11, GPIO_AF10_OTG_FS); - set_gpio_alternate(GPIOA, 12, GPIO_AF10_OTG_FS); - GPIOA->OSPEEDR = GPIO_OSPEEDER_OSPEEDR11 | GPIO_OSPEEDER_OSPEEDR12; - - // flasher - spi_init(); - - // enable USB - usb_init(); - - // green LED on for flashing - current_board->set_led(LED_GREEN, 1); - - enable_interrupts(); - - uint64_t cnt = 0; - - for (cnt=0;;cnt++) { - if (cnt == 35 && !is_enumerated && usb_power_mode == USB_POWER_CLIENT) { - // if you are connected through a hub to the phone - // you need power to be able to see the device - puts("USBP: didn't enumerate, switching to CDP mode\n"); - current_board->set_usb_power_mode(USB_POWER_CDP); - current_board->set_led(LED_BLUE, 1); - } - // blink the green LED fast - current_board->set_led(LED_GREEN, 0); - delay(500000); - current_board->set_led(LED_GREEN, 1); - delay(500000); - } -} - diff --git a/panda/board/startup_stm32f205xx.s b/panda/board/startup_stm32f205xx.s deleted file mode 100644 index 7554efc4c1..0000000000 --- a/panda/board/startup_stm32f205xx.s +++ /dev/null @@ -1,511 +0,0 @@ -/** - ****************************************************************************** - * @file startup_stm32f205xx.s - * @author MCD Application Team - * @version V2.1.2 - * @date 29-June-2016 - * @brief STM32F205xx Devices vector table for Atollic TrueSTUDIO toolchain. - * This module performs: - * - Set the initial SP - * - Set the initial PC == Reset_Handler, - * - Set the vector table entries with the exceptions ISR address - * - Branches to main in the C library (which eventually - * calls main()). - * After Reset the Cortex-M3 processor is in Thread mode, - * priority is Privileged, and the Stack is set to Main. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - - .syntax unified - .cpu cortex-m3 - .thumb - -.global g_pfnVectors -.global Default_Handler - -/* start address for the initialization values of the .data section. -defined in linker script */ -.word _sidata -/* start address for the .data section. defined in linker script */ -.word _sdata -/* end address for the .data section. defined in linker script */ -.word _edata -/* start address for the .bss section. defined in linker script */ -.word _sbss -/* end address for the .bss section. defined in linker script */ -.word _ebss -/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ - -/** - * @brief This is the code that gets called when the processor first - * starts execution following a reset event. Only the absolutely - * necessary set is performed, after which the application - * supplied main() routine is called. - * @param None - * @retval : None -*/ - - .section .text.Reset_Handler - .weak Reset_Handler - .type Reset_Handler, %function -Reset_Handler: - ldr sp, =_estack /* set stack pointer */ - bl __initialize_hardware_early - -/* Copy the data segment initializers from flash to SRAM */ - movs r1, #0 - b LoopCopyDataInit - -CopyDataInit: - ldr r3, =_sidata - ldr r3, [r3, r1] - str r3, [r0, r1] - adds r1, r1, #4 - -LoopCopyDataInit: - ldr r0, =_sdata - ldr r3, =_edata - adds r2, r0, r1 - cmp r2, r3 - bcc CopyDataInit - ldr r2, =_sbss - b LoopFillZerobss -/* Zero fill the bss segment. */ -FillZerobss: - movs r3, #0 - str r3, [r2], #4 - -LoopFillZerobss: - ldr r3, = _ebss - cmp r2, r3 - bcc FillZerobss - -/* Call the clock system initialization function.*/ - /*bl SystemInit */ -/* Call static constructors */ - /*bl __libc_init_array*/ -/* Call the application's entry point.*/ - bl main - bx lr -.size Reset_Handler, .-Reset_Handler - -/** - * @brief This is the code that gets called when the processor receives an - * unexpected interrupt. This simply enters an infinite loop, preserving - * the system state for examination by a debugger. - * @param None - * @retval None -*/ - .section .text.Default_Handler,"ax",%progbits -Default_Handler: -Infinite_Loop: - b Infinite_Loop - .size Default_Handler, .-Default_Handler -/****************************************************************************** -* -* The minimal vector table for a Cortex M3. Note that the proper constructs -* must be placed on this to ensure that it ends up at physical address -* 0x0000.0000. -* -*******************************************************************************/ - .section .isr_vector,"a",%progbits - .type g_pfnVectors, %object - .size g_pfnVectors, .-g_pfnVectors - - - -g_pfnVectors: - .word _estack - .word Reset_Handler - - .word NMI_Handler - .word HardFault_Handler - .word MemManage_Handler - .word BusFault_Handler - .word UsageFault_Handler - .word 0 - .word 0 - .word 0 - .word 0 - .word SVC_Handler - .word DebugMon_Handler - .word 0 - .word PendSV_Handler - .word SysTick_Handler - - /* External Interrupts */ - .word WWDG_IRQHandler /* Window WatchDog */ - .word PVD_IRQHandler /* PVD through EXTI Line detection */ - .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ - .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ - .word FLASH_IRQHandler /* FLASH */ - .word RCC_IRQHandler /* RCC */ - .word EXTI0_IRQHandler /* EXTI Line0 */ - .word EXTI1_IRQHandler /* EXTI Line1 */ - .word EXTI2_IRQHandler /* EXTI Line2 */ - .word EXTI3_IRQHandler /* EXTI Line3 */ - .word EXTI4_IRQHandler /* EXTI Line4 */ - .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ - .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ - .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ - .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ - .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ - .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ - .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ - .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ - .word CAN1_TX_IRQHandler /* CAN1 TX */ - .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ - .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ - .word CAN1_SCE_IRQHandler /* CAN1 SCE */ - .word EXTI9_5_IRQHandler /* External Line[9:5]s */ - .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ - .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ - .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ - .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ - .word TIM2_IRQHandler /* TIM2 */ - .word TIM3_IRQHandler /* TIM3 */ - .word TIM4_IRQHandler /* TIM4 */ - .word I2C1_EV_IRQHandler /* I2C1 Event */ - .word I2C1_ER_IRQHandler /* I2C1 Error */ - .word I2C2_EV_IRQHandler /* I2C2 Event */ - .word I2C2_ER_IRQHandler /* I2C2 Error */ - .word SPI1_IRQHandler /* SPI1 */ - .word SPI2_IRQHandler /* SPI2 */ - .word USART1_IRQHandler /* USART1 */ - .word USART2_IRQHandler /* USART2 */ - .word USART3_IRQHandler /* USART3 */ - .word EXTI15_10_IRQHandler /* External Line[15:10]s */ - .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ - .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ - .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ - .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ - .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ - .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ - .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ - .word FSMC_IRQHandler /* FSMC */ - .word SDIO_IRQHandler /* SDIO */ - .word TIM5_IRQHandler /* TIM5 */ - .word SPI3_IRQHandler /* SPI3 */ - .word UART4_IRQHandler /* UART4 */ - .word UART5_IRQHandler /* UART5 */ - .word TIM6_DAC_IRQHandler /* TIM6 and DAC1&2 underrun errors */ - .word TIM7_IRQHandler /* TIM7 */ - .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ - .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ - .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ - .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ - .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word CAN2_TX_IRQHandler /* CAN2 TX */ - .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ - .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ - .word CAN2_SCE_IRQHandler /* CAN2 SCE */ - .word OTG_FS_IRQHandler /* USB OTG FS */ - .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ - .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ - .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ - .word USART6_IRQHandler /* USART6 */ - .word I2C3_EV_IRQHandler /* I2C3 event */ - .word I2C3_ER_IRQHandler /* I2C3 error */ - .word OTG_HS_EP1_OUT_IRQHandler /* USB OTG HS End Point 1 Out */ - .word OTG_HS_EP1_IN_IRQHandler /* USB OTG HS End Point 1 In */ - .word OTG_HS_WKUP_IRQHandler /* USB OTG HS Wakeup through EXTI */ - .word OTG_HS_IRQHandler /* USB OTG HS */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word HASH_RNG_IRQHandler /* Hash and Rng */ - -/******************************************************************************* -* -* Provide weak aliases for each Exception handler to the Default_Handler. -* As they are weak aliases, any function with the same name will override -* this definition. -* -*******************************************************************************/ - .weak NMI_Handler - .thumb_set NMI_Handler,Default_Handler - - .weak HardFault_Handler - .thumb_set HardFault_Handler,Default_Handler - - .weak MemManage_Handler - .thumb_set MemManage_Handler,Default_Handler - - .weak BusFault_Handler - .thumb_set BusFault_Handler,Default_Handler - - .weak UsageFault_Handler - .thumb_set UsageFault_Handler,Default_Handler - - .weak SVC_Handler - .thumb_set SVC_Handler,Default_Handler - - .weak DebugMon_Handler - .thumb_set DebugMon_Handler,Default_Handler - - .weak PendSV_Handler - .thumb_set PendSV_Handler,Default_Handler - - .weak SysTick_Handler - .thumb_set SysTick_Handler,Default_Handler - - .weak WWDG_IRQHandler - .thumb_set WWDG_IRQHandler,Default_Handler - - .weak PVD_IRQHandler - .thumb_set PVD_IRQHandler,Default_Handler - - .weak TAMP_STAMP_IRQHandler - .thumb_set TAMP_STAMP_IRQHandler,Default_Handler - - .weak RTC_WKUP_IRQHandler - .thumb_set RTC_WKUP_IRQHandler,Default_Handler - - .weak FLASH_IRQHandler - .thumb_set FLASH_IRQHandler,Default_Handler - - .weak RCC_IRQHandler - .thumb_set RCC_IRQHandler,Default_Handler - - .weak EXTI0_IRQHandler - .thumb_set EXTI0_IRQHandler,Default_Handler - - .weak EXTI1_IRQHandler - .thumb_set EXTI1_IRQHandler,Default_Handler - - .weak EXTI2_IRQHandler - .thumb_set EXTI2_IRQHandler,Default_Handler - - .weak EXTI3_IRQHandler - .thumb_set EXTI3_IRQHandler,Default_Handler - - .weak EXTI4_IRQHandler - .thumb_set EXTI4_IRQHandler,Default_Handler - - .weak DMA1_Stream0_IRQHandler - .thumb_set DMA1_Stream0_IRQHandler,Default_Handler - - .weak DMA1_Stream1_IRQHandler - .thumb_set DMA1_Stream1_IRQHandler,Default_Handler - - .weak DMA1_Stream2_IRQHandler - .thumb_set DMA1_Stream2_IRQHandler,Default_Handler - - .weak DMA1_Stream3_IRQHandler - .thumb_set DMA1_Stream3_IRQHandler,Default_Handler - - .weak DMA1_Stream4_IRQHandler - .thumb_set DMA1_Stream4_IRQHandler,Default_Handler - - .weak DMA1_Stream5_IRQHandler - .thumb_set DMA1_Stream5_IRQHandler,Default_Handler - - .weak DMA1_Stream6_IRQHandler - .thumb_set DMA1_Stream6_IRQHandler,Default_Handler - - .weak ADC_IRQHandler - .thumb_set ADC_IRQHandler,Default_Handler - - .weak CAN1_TX_IRQHandler - .thumb_set CAN1_TX_IRQHandler,Default_Handler - - .weak CAN1_RX0_IRQHandler - .thumb_set CAN1_RX0_IRQHandler,Default_Handler - - .weak CAN1_RX1_IRQHandler - .thumb_set CAN1_RX1_IRQHandler,Default_Handler - - .weak CAN1_SCE_IRQHandler - .thumb_set CAN1_SCE_IRQHandler,Default_Handler - - .weak EXTI9_5_IRQHandler - .thumb_set EXTI9_5_IRQHandler,Default_Handler - - .weak TIM1_BRK_TIM9_IRQHandler - .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler - - .weak TIM1_UP_TIM10_IRQHandler - .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler - - .weak TIM1_TRG_COM_TIM11_IRQHandler - .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler - - .weak TIM1_CC_IRQHandler - .thumb_set TIM1_CC_IRQHandler,Default_Handler - - .weak TIM2_IRQHandler - .thumb_set TIM2_IRQHandler,Default_Handler - - .weak TIM3_IRQHandler - .thumb_set TIM3_IRQHandler,Default_Handler - - .weak TIM4_IRQHandler - .thumb_set TIM4_IRQHandler,Default_Handler - - .weak I2C1_EV_IRQHandler - .thumb_set I2C1_EV_IRQHandler,Default_Handler - - .weak I2C1_ER_IRQHandler - .thumb_set I2C1_ER_IRQHandler,Default_Handler - - .weak I2C2_EV_IRQHandler - .thumb_set I2C2_EV_IRQHandler,Default_Handler - - .weak I2C2_ER_IRQHandler - .thumb_set I2C2_ER_IRQHandler,Default_Handler - - .weak SPI1_IRQHandler - .thumb_set SPI1_IRQHandler,Default_Handler - - .weak SPI2_IRQHandler - .thumb_set SPI2_IRQHandler,Default_Handler - - .weak USART1_IRQHandler - .thumb_set USART1_IRQHandler,Default_Handler - - .weak USART2_IRQHandler - .thumb_set USART2_IRQHandler,Default_Handler - - .weak USART3_IRQHandler - .thumb_set USART3_IRQHandler,Default_Handler - - .weak EXTI15_10_IRQHandler - .thumb_set EXTI15_10_IRQHandler,Default_Handler - - .weak RTC_Alarm_IRQHandler - .thumb_set RTC_Alarm_IRQHandler,Default_Handler - - .weak OTG_FS_WKUP_IRQHandler - .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler - - .weak TIM8_BRK_TIM12_IRQHandler - .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler - - .weak TIM8_UP_TIM13_IRQHandler - .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler - - .weak TIM8_TRG_COM_TIM14_IRQHandler - .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler - - .weak TIM8_CC_IRQHandler - .thumb_set TIM8_CC_IRQHandler,Default_Handler - - .weak DMA1_Stream7_IRQHandler - .thumb_set DMA1_Stream7_IRQHandler,Default_Handler - - .weak FSMC_IRQHandler - .thumb_set FSMC_IRQHandler,Default_Handler - - .weak SDIO_IRQHandler - .thumb_set SDIO_IRQHandler,Default_Handler - - .weak TIM5_IRQHandler - .thumb_set TIM5_IRQHandler,Default_Handler - - .weak SPI3_IRQHandler - .thumb_set SPI3_IRQHandler,Default_Handler - - .weak UART4_IRQHandler - .thumb_set UART4_IRQHandler,Default_Handler - - .weak UART5_IRQHandler - .thumb_set UART5_IRQHandler,Default_Handler - - .weak TIM6_DAC_IRQHandler - .thumb_set TIM6_DAC_IRQHandler,Default_Handler - - .weak TIM7_IRQHandler - .thumb_set TIM7_IRQHandler,Default_Handler - - .weak DMA2_Stream0_IRQHandler - .thumb_set DMA2_Stream0_IRQHandler,Default_Handler - - .weak DMA2_Stream1_IRQHandler - .thumb_set DMA2_Stream1_IRQHandler,Default_Handler - - .weak DMA2_Stream2_IRQHandler - .thumb_set DMA2_Stream2_IRQHandler,Default_Handler - - .weak DMA2_Stream3_IRQHandler - .thumb_set DMA2_Stream3_IRQHandler,Default_Handler - - .weak DMA2_Stream4_IRQHandler - .thumb_set DMA2_Stream4_IRQHandler,Default_Handler - - .weak CAN2_TX_IRQHandler - .thumb_set CAN2_TX_IRQHandler,Default_Handler - - .weak CAN2_RX0_IRQHandler - .thumb_set CAN2_RX0_IRQHandler,Default_Handler - - .weak CAN2_RX1_IRQHandler - .thumb_set CAN2_RX1_IRQHandler,Default_Handler - - .weak CAN2_SCE_IRQHandler - .thumb_set CAN2_SCE_IRQHandler,Default_Handler - - .weak OTG_FS_IRQHandler - .thumb_set OTG_FS_IRQHandler,Default_Handler - - .weak DMA2_Stream5_IRQHandler - .thumb_set DMA2_Stream5_IRQHandler,Default_Handler - - .weak DMA2_Stream6_IRQHandler - .thumb_set DMA2_Stream6_IRQHandler,Default_Handler - - .weak DMA2_Stream7_IRQHandler - .thumb_set DMA2_Stream7_IRQHandler,Default_Handler - - .weak USART6_IRQHandler - .thumb_set USART6_IRQHandler,Default_Handler - - .weak I2C3_EV_IRQHandler - .thumb_set I2C3_EV_IRQHandler,Default_Handler - - .weak I2C3_ER_IRQHandler - .thumb_set I2C3_ER_IRQHandler,Default_Handler - - .weak OTG_HS_EP1_OUT_IRQHandler - .thumb_set OTG_HS_EP1_OUT_IRQHandler,Default_Handler - - .weak OTG_HS_EP1_IN_IRQHandler - .thumb_set OTG_HS_EP1_IN_IRQHandler,Default_Handler - - .weak OTG_HS_WKUP_IRQHandler - .thumb_set OTG_HS_WKUP_IRQHandler,Default_Handler - - .weak OTG_HS_IRQHandler - .thumb_set OTG_HS_IRQHandler,Default_Handler - - .weak HASH_RNG_IRQHandler - .thumb_set HASH_RNG_IRQHandler,Default_Handler - -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/startup_stm32f413xx.s b/panda/board/startup_stm32f413xx.s deleted file mode 100644 index 6e6fb5ffa5..0000000000 --- a/panda/board/startup_stm32f413xx.s +++ /dev/null @@ -1,583 +0,0 @@ -/** - ****************************************************************************** - * @file startup_stm32f413xx.s - * @author MCD Application Team - * @version V2.6.0 - * @date 04-November-2016 - * @brief STM32F413xx Devices vector table for GCC based toolchains. - * This module performs: - * - Set the initial SP - * - Set the initial PC == Reset_Handler, - * - Set the vector table entries with the exceptions ISR address - * - Branches to main in the C library (which eventually - * calls main()). - * After Reset the Cortex-M4 processor is in Thread mode, - * priority is Privileged, and the Stack is set to Main. - ****************************************************************************** - * @attention - * - *

© COPYRIGHT 2016 STMicroelectronics

- * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** - */ - - .syntax unified - .cpu cortex-m4 - .fpu softvfp - .thumb - -.global g_pfnVectors -.global Default_Handler - -/* start address for the initialization values of the .data section. -defined in linker script */ -.word _sidata -/* start address for the .data section. defined in linker script */ -.word _sdata -/* end address for the .data section. defined in linker script */ -.word _edata -/* start address for the .bss section. defined in linker script */ -.word _sbss -/* end address for the .bss section. defined in linker script */ -.word _ebss -/* stack used for SystemInit_ExtMemCtl; always internal RAM used */ - -/** - * @brief This is the code that gets called when the processor first - * starts execution following a reset event. Only the absolutely - * necessary set is performed, after which the application - * supplied main() routine is called. - * @param None - * @retval : None -*/ - - .section .text.Reset_Handler - .weak Reset_Handler - .type Reset_Handler, %function -Reset_Handler: - ldr sp, =_estack /* set stack pointer */ - bl __initialize_hardware_early - -/* Copy the data segment initializers from flash to SRAM */ - movs r1, #0 - b LoopCopyDataInit - -CopyDataInit: - ldr r3, =_sidata - ldr r3, [r3, r1] - str r3, [r0, r1] - adds r1, r1, #4 - -LoopCopyDataInit: - ldr r0, =_sdata - ldr r3, =_edata - adds r2, r0, r1 - cmp r2, r3 - bcc CopyDataInit - ldr r2, =_sbss - b LoopFillZerobss -/* Zero fill the bss segment. */ -FillZerobss: - movs r3, #0 - str r3, [r2], #4 - -LoopFillZerobss: - ldr r3, = _ebss - cmp r2, r3 - bcc FillZerobss - -/* Call the clock system intitialization function.*/ - /* bl SystemInit */ -/* Call static constructors */ - /* bl __libc_init_array */ -/* Call the application's entry point.*/ - bl main - bx lr -.size Reset_Handler, .-Reset_Handler - -/** - * @brief This is the code that gets called when the processor receives an - * unexpected interrupt. This simply enters an infinite loop, preserving - * the system state for examination by a debugger. - * @param None - * @retval None -*/ - .section .text.Default_Handler,"ax",%progbits -Default_Handler: -Infinite_Loop: - b Infinite_Loop - .size Default_Handler, .-Default_Handler -/****************************************************************************** -* -* The minimal vector table for a Cortex M3. Note that the proper constructs -* must be placed on this to ensure that it ends up at physical address -* 0x0000.0000. -* -*******************************************************************************/ - .section .isr_vector,"a",%progbits - .type g_pfnVectors, %object - .size g_pfnVectors, .-g_pfnVectors - -g_pfnVectors: - .word _estack - .word Reset_Handler - .word NMI_Handler - .word HardFault_Handler - .word MemManage_Handler - .word BusFault_Handler - .word UsageFault_Handler - .word 0 - .word 0 - .word 0 - .word 0 - .word SVC_Handler - .word DebugMon_Handler - .word 0 - .word PendSV_Handler - .word SysTick_Handler - - /* External Interrupts */ - .word WWDG_IRQHandler /* Window WatchDog */ - .word PVD_IRQHandler /* PVD through EXTI Line detection */ - .word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */ - .word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */ - .word FLASH_IRQHandler /* FLASH */ - .word RCC_IRQHandler /* RCC */ - .word EXTI0_IRQHandler /* EXTI Line0 */ - .word EXTI1_IRQHandler /* EXTI Line1 */ - .word EXTI2_IRQHandler /* EXTI Line2 */ - .word EXTI3_IRQHandler /* EXTI Line3 */ - .word EXTI4_IRQHandler /* EXTI Line4 */ - .word DMA1_Stream0_IRQHandler /* DMA1 Stream 0 */ - .word DMA1_Stream1_IRQHandler /* DMA1 Stream 1 */ - .word DMA1_Stream2_IRQHandler /* DMA1 Stream 2 */ - .word DMA1_Stream3_IRQHandler /* DMA1 Stream 3 */ - .word DMA1_Stream4_IRQHandler /* DMA1 Stream 4 */ - .word DMA1_Stream5_IRQHandler /* DMA1 Stream 5 */ - .word DMA1_Stream6_IRQHandler /* DMA1 Stream 6 */ - .word ADC_IRQHandler /* ADC1, ADC2 and ADC3s */ - .word CAN1_TX_IRQHandler /* CAN1 TX */ - .word CAN1_RX0_IRQHandler /* CAN1 RX0 */ - .word CAN1_RX1_IRQHandler /* CAN1 RX1 */ - .word CAN1_SCE_IRQHandler /* CAN1 SCE */ - .word EXTI9_5_IRQHandler /* External Line[9:5]s */ - .word TIM1_BRK_TIM9_IRQHandler /* TIM1 Break and TIM9 */ - .word TIM1_UP_TIM10_IRQHandler /* TIM1 Update and TIM10 */ - .word TIM1_TRG_COM_TIM11_IRQHandler /* TIM1 Trigger and Commutation and TIM11 */ - .word TIM1_CC_IRQHandler /* TIM1 Capture Compare */ - .word TIM2_IRQHandler /* TIM2 */ - .word TIM3_IRQHandler /* TIM3 */ - .word TIM4_IRQHandler /* TIM4 */ - .word I2C1_EV_IRQHandler /* I2C1 Event */ - .word I2C1_ER_IRQHandler /* I2C1 Error */ - .word I2C2_EV_IRQHandler /* I2C2 Event */ - .word I2C2_ER_IRQHandler /* I2C2 Error */ - .word SPI1_IRQHandler /* SPI1 */ - .word SPI2_IRQHandler /* SPI2 */ - .word USART1_IRQHandler /* USART1 */ - .word USART2_IRQHandler /* USART2 */ - .word USART3_IRQHandler /* USART3 */ - .word EXTI15_10_IRQHandler /* External Line[15:10]s */ - .word RTC_Alarm_IRQHandler /* RTC Alarm (A and B) through EXTI Line */ - .word OTG_FS_WKUP_IRQHandler /* USB OTG FS Wakeup through EXTI line */ - .word TIM8_BRK_TIM12_IRQHandler /* TIM8 Break and TIM12 */ - .word TIM8_UP_TIM13_IRQHandler /* TIM8 Update and TIM13 */ - .word TIM8_TRG_COM_TIM14_IRQHandler /* TIM8 Trigger and Commutation and TIM14 */ - .word TIM8_CC_IRQHandler /* TIM8 Capture Compare */ - .word DMA1_Stream7_IRQHandler /* DMA1 Stream7 */ - .word FSMC_IRQHandler /* FSMC */ - .word SDIO_IRQHandler /* SDIO */ - .word TIM5_IRQHandler /* TIM5 */ - .word SPI3_IRQHandler /* SPI3 */ - .word UART4_IRQHandler /* UART4 */ - .word UART5_IRQHandler /* UART5 */ - .word TIM6_DAC_IRQHandler /* TIM6, DAC1 and DAC2 */ - .word TIM7_IRQHandler /* TIM7 */ - .word DMA2_Stream0_IRQHandler /* DMA2 Stream 0 */ - .word DMA2_Stream1_IRQHandler /* DMA2 Stream 1 */ - .word DMA2_Stream2_IRQHandler /* DMA2 Stream 2 */ - .word DMA2_Stream3_IRQHandler /* DMA2 Stream 3 */ - .word DMA2_Stream4_IRQHandler /* DMA2 Stream 4 */ - .word DFSDM1_FLT0_IRQHandler /* DFSDM1 Filter0 */ - .word DFSDM1_FLT1_IRQHandler /* DFSDM1 Filter1 */ - .word CAN2_TX_IRQHandler /* CAN2 TX */ - .word CAN2_RX0_IRQHandler /* CAN2 RX0 */ - .word CAN2_RX1_IRQHandler /* CAN2 RX1 */ - .word CAN2_SCE_IRQHandler /* CAN2 SCE */ - .word OTG_FS_IRQHandler /* USB OTG FS */ - .word DMA2_Stream5_IRQHandler /* DMA2 Stream 5 */ - .word DMA2_Stream6_IRQHandler /* DMA2 Stream 6 */ - .word DMA2_Stream7_IRQHandler /* DMA2 Stream 7 */ - .word USART6_IRQHandler /* USART6 */ - .word I2C3_EV_IRQHandler /* I2C3 event */ - .word I2C3_ER_IRQHandler /* I2C3 error */ - .word CAN3_TX_IRQHandler /* CAN3 TX */ - .word CAN3_RX0_IRQHandler /* CAN3 RX0 */ - .word CAN3_RX1_IRQHandler /* CAN3 RX1 */ - .word CAN3_SCE_IRQHandler /* CAN3 SCE */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word RNG_IRQHandler /* RNG */ - .word FPU_IRQHandler /* FPU */ - .word UART7_IRQHandler /* UART7 */ - .word UART8_IRQHandler /* UART8 */ - .word SPI4_IRQHandler /* SPI4 */ - .word SPI5_IRQHandler /* SPI5 */ - .word 0 /* Reserved */ - .word SAI1_IRQHandler /* SAI1 */ - .word UART9_IRQHandler /* UART9 */ - .word UART10_IRQHandler /* UART10 */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word QUADSPI_IRQHandler /* QuadSPI */ - .word 0 /* Reserved */ - .word 0 /* Reserved */ - .word FMPI2C1_EV_IRQHandler /* FMPI2C1 Event */ - .word FMPI2C1_ER_IRQHandler /* FMPI2C1 Error */ - .word LPTIM1_IRQHandler /* LPTIM1 */ - .word DFSDM2_FLT0_IRQHandler /* DFSDM2 Filter0 */ - .word DFSDM2_FLT1_IRQHandler /* DFSDM2 Filter1 */ - .word DFSDM2_FLT2_IRQHandler /* DFSDM2 Filter2 */ - .word DFSDM2_FLT3_IRQHandler /* DFSDM2 Filter3 */ - -/******************************************************************************* -* -* Provide weak aliases for each Exception handler to the Default_Handler. -* As they are weak aliases, any function with the same name will override -* this definition. -* -*******************************************************************************/ - .weak NMI_Handler - .thumb_set NMI_Handler,Default_Handler - - .weak HardFault_Handler - .thumb_set HardFault_Handler,Default_Handler - - .weak MemManage_Handler - .thumb_set MemManage_Handler,Default_Handler - - .weak BusFault_Handler - .thumb_set BusFault_Handler,Default_Handler - - .weak UsageFault_Handler - .thumb_set UsageFault_Handler,Default_Handler - - .weak SVC_Handler - .thumb_set SVC_Handler,Default_Handler - - .weak DebugMon_Handler - .thumb_set DebugMon_Handler,Default_Handler - - .weak PendSV_Handler - .thumb_set PendSV_Handler,Default_Handler - - .weak SysTick_Handler - .thumb_set SysTick_Handler,Default_Handler - - .weak WWDG_IRQHandler - .thumb_set WWDG_IRQHandler,Default_Handler - - .weak PVD_IRQHandler - .thumb_set PVD_IRQHandler,Default_Handler - - .weak TAMP_STAMP_IRQHandler - .thumb_set TAMP_STAMP_IRQHandler,Default_Handler - - .weak RTC_WKUP_IRQHandler - .thumb_set RTC_WKUP_IRQHandler,Default_Handler - - .weak FLASH_IRQHandler - .thumb_set FLASH_IRQHandler,Default_Handler - - .weak RCC_IRQHandler - .thumb_set RCC_IRQHandler,Default_Handler - - .weak EXTI0_IRQHandler - .thumb_set EXTI0_IRQHandler,Default_Handler - - .weak EXTI1_IRQHandler - .thumb_set EXTI1_IRQHandler,Default_Handler - - .weak EXTI2_IRQHandler - .thumb_set EXTI2_IRQHandler,Default_Handler - - .weak EXTI3_IRQHandler - .thumb_set EXTI3_IRQHandler,Default_Handler - - .weak EXTI4_IRQHandler - .thumb_set EXTI4_IRQHandler,Default_Handler - - .weak DMA1_Stream0_IRQHandler - .thumb_set DMA1_Stream0_IRQHandler,Default_Handler - - .weak DMA1_Stream1_IRQHandler - .thumb_set DMA1_Stream1_IRQHandler,Default_Handler - - .weak DMA1_Stream2_IRQHandler - .thumb_set DMA1_Stream2_IRQHandler,Default_Handler - - .weak DMA1_Stream3_IRQHandler - .thumb_set DMA1_Stream3_IRQHandler,Default_Handler - - .weak DMA1_Stream4_IRQHandler - .thumb_set DMA1_Stream4_IRQHandler,Default_Handler - - .weak DMA1_Stream5_IRQHandler - .thumb_set DMA1_Stream5_IRQHandler,Default_Handler - - .weak DMA1_Stream6_IRQHandler - .thumb_set DMA1_Stream6_IRQHandler,Default_Handler - - .weak ADC_IRQHandler - .thumb_set ADC_IRQHandler,Default_Handler - - .weak CAN1_TX_IRQHandler - .thumb_set CAN1_TX_IRQHandler,Default_Handler - - .weak CAN1_RX0_IRQHandler - .thumb_set CAN1_RX0_IRQHandler,Default_Handler - - .weak CAN1_RX1_IRQHandler - .thumb_set CAN1_RX1_IRQHandler,Default_Handler - - .weak CAN1_SCE_IRQHandler - .thumb_set CAN1_SCE_IRQHandler,Default_Handler - - .weak EXTI9_5_IRQHandler - .thumb_set EXTI9_5_IRQHandler,Default_Handler - - .weak TIM1_BRK_TIM9_IRQHandler - .thumb_set TIM1_BRK_TIM9_IRQHandler,Default_Handler - - .weak TIM1_UP_TIM10_IRQHandler - .thumb_set TIM1_UP_TIM10_IRQHandler,Default_Handler - - .weak TIM1_TRG_COM_TIM11_IRQHandler - .thumb_set TIM1_TRG_COM_TIM11_IRQHandler,Default_Handler - - .weak TIM1_CC_IRQHandler - .thumb_set TIM1_CC_IRQHandler,Default_Handler - - .weak TIM2_IRQHandler - .thumb_set TIM2_IRQHandler,Default_Handler - - .weak TIM3_IRQHandler - .thumb_set TIM3_IRQHandler,Default_Handler - - .weak TIM4_IRQHandler - .thumb_set TIM4_IRQHandler,Default_Handler - - .weak I2C1_EV_IRQHandler - .thumb_set I2C1_EV_IRQHandler,Default_Handler - - .weak I2C1_ER_IRQHandler - .thumb_set I2C1_ER_IRQHandler,Default_Handler - - .weak I2C2_EV_IRQHandler - .thumb_set I2C2_EV_IRQHandler,Default_Handler - - .weak I2C2_ER_IRQHandler - .thumb_set I2C2_ER_IRQHandler,Default_Handler - - .weak SPI1_IRQHandler - .thumb_set SPI1_IRQHandler,Default_Handler - - .weak SPI2_IRQHandler - .thumb_set SPI2_IRQHandler,Default_Handler - - .weak USART1_IRQHandler - .thumb_set USART1_IRQHandler,Default_Handler - - .weak USART2_IRQHandler - .thumb_set USART2_IRQHandler,Default_Handler - - .weak USART3_IRQHandler - .thumb_set USART3_IRQHandler,Default_Handler - - .weak EXTI15_10_IRQHandler - .thumb_set EXTI15_10_IRQHandler,Default_Handler - - .weak RTC_Alarm_IRQHandler - .thumb_set RTC_Alarm_IRQHandler,Default_Handler - - .weak OTG_FS_WKUP_IRQHandler - .thumb_set OTG_FS_WKUP_IRQHandler,Default_Handler - - .weak TIM8_BRK_TIM12_IRQHandler - .thumb_set TIM8_BRK_TIM12_IRQHandler,Default_Handler - - .weak TIM8_UP_TIM13_IRQHandler - .thumb_set TIM8_UP_TIM13_IRQHandler,Default_Handler - - .weak TIM8_TRG_COM_TIM14_IRQHandler - .thumb_set TIM8_TRG_COM_TIM14_IRQHandler,Default_Handler - - .weak TIM8_CC_IRQHandler - .thumb_set TIM8_CC_IRQHandler,Default_Handler - - .weak DMA1_Stream7_IRQHandler - .thumb_set DMA1_Stream7_IRQHandler,Default_Handler - - .weak FSMC_IRQHandler - .thumb_set FSMC_IRQHandler,Default_Handler - - .weak SDIO_IRQHandler - .thumb_set SDIO_IRQHandler,Default_Handler - - .weak TIM5_IRQHandler - .thumb_set TIM5_IRQHandler,Default_Handler - - .weak SPI3_IRQHandler - .thumb_set SPI3_IRQHandler,Default_Handler - - .weak UART4_IRQHandler - .thumb_set UART4_IRQHandler,Default_Handler - - .weak UART5_IRQHandler - .thumb_set UART5_IRQHandler,Default_Handler - - .weak TIM6_DAC_IRQHandler - .thumb_set TIM6_DAC_IRQHandler,Default_Handler - - .weak TIM7_IRQHandler - .thumb_set TIM7_IRQHandler,Default_Handler - - .weak DMA2_Stream0_IRQHandler - .thumb_set DMA2_Stream0_IRQHandler,Default_Handler - - .weak DMA2_Stream1_IRQHandler - .thumb_set DMA2_Stream1_IRQHandler,Default_Handler - - .weak DMA2_Stream2_IRQHandler - .thumb_set DMA2_Stream2_IRQHandler,Default_Handler - - .weak DMA2_Stream3_IRQHandler - .thumb_set DMA2_Stream3_IRQHandler,Default_Handler - - .weak DMA2_Stream4_IRQHandler - .thumb_set DMA2_Stream4_IRQHandler,Default_Handler - - .weak DFSDM1_FLT0_IRQHandler - .thumb_set DFSDM1_FLT0_IRQHandler,Default_Handler - - .weak DFSDM1_FLT1_IRQHandler - .thumb_set DFSDM1_FLT1_IRQHandler,Default_Handler - - .weak CAN2_TX_IRQHandler - .thumb_set CAN2_TX_IRQHandler,Default_Handler - - .weak CAN2_RX0_IRQHandler - .thumb_set CAN2_RX0_IRQHandler,Default_Handler - - .weak CAN2_RX1_IRQHandler - .thumb_set CAN2_RX1_IRQHandler,Default_Handler - - .weak CAN2_SCE_IRQHandler - .thumb_set CAN2_SCE_IRQHandler,Default_Handler - - .weak OTG_FS_IRQHandler - .thumb_set OTG_FS_IRQHandler,Default_Handler - - .weak DMA2_Stream5_IRQHandler - .thumb_set DMA2_Stream5_IRQHandler,Default_Handler - - .weak DMA2_Stream6_IRQHandler - .thumb_set DMA2_Stream6_IRQHandler,Default_Handler - - .weak DMA2_Stream7_IRQHandler - .thumb_set DMA2_Stream7_IRQHandler,Default_Handler - - .weak USART6_IRQHandler - .thumb_set USART6_IRQHandler,Default_Handler - - .weak I2C3_EV_IRQHandler - .thumb_set I2C3_EV_IRQHandler,Default_Handler - - .weak I2C3_ER_IRQHandler - .thumb_set I2C3_ER_IRQHandler,Default_Handler - - .weak CAN3_TX_IRQHandler - .thumb_set CAN3_TX_IRQHandler,Default_Handler - - .weak CAN3_RX0_IRQHandler - .thumb_set CAN3_RX0_IRQHandler,Default_Handler - - .weak CAN3_RX1_IRQHandler - .thumb_set CAN3_RX1_IRQHandler,Default_Handler - - .weak CAN3_SCE_IRQHandler - .thumb_set CAN3_SCE_IRQHandler,Default_Handler - - .weak RNG_IRQHandler - .thumb_set RNG_IRQHandler,Default_Handler - - .weak FPU_IRQHandler - .thumb_set FPU_IRQHandler,Default_Handler - - .weak UART7_IRQHandler - .thumb_set UART7_IRQHandler,Default_Handler - - .weak UART8_IRQHandler - .thumb_set UART8_IRQHandler,Default_Handler - - .weak SPI4_IRQHandler - .thumb_set SPI4_IRQHandler,Default_Handler - - .weak SPI5_IRQHandler - .thumb_set SPI5_IRQHandler,Default_Handler - - .weak SAI1_IRQHandler - .thumb_set SAI1_IRQHandler,Default_Handler - - .weak UART9_IRQHandler - .thumb_set UART9_IRQHandler,Default_Handler - - .weak UART10_IRQHandler - .thumb_set UART10_IRQHandler,Default_Handler - - .weak QUADSPI_IRQHandler - .thumb_set QUADSPI_IRQHandler,Default_Handler - - .weak FMPI2C1_EV_IRQHandler - .thumb_set FMPI2C1_EV_IRQHandler,Default_Handler - - .weak FMPI2C1_ER_IRQHandler - .thumb_set FMPI2C1_ER_IRQHandler,Default_Handler - - .weak LPTIM1_IRQHandler - .thumb_set LPTIM1_IRQHandler,Default_Handler - - .weak DFSDM2_FLT0_IRQHandler - .thumb_set DFSDM2_FLT0_IRQHandler,Default_Handler - - .weak DFSDM2_FLT1_IRQHandler - .thumb_set DFSDM2_FLT1_IRQHandler,Default_Handler - - .weak DFSDM2_FLT2_IRQHandler - .thumb_set DFSDM2_FLT2_IRQHandler,Default_Handler - - .weak DFSDM2_FLT3_IRQHandler - .thumb_set DFSDM2_FLT3_IRQHandler,Default_Handler -/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/panda/board/stm32_flash.ld b/panda/board/stm32_flash.ld deleted file mode 100644 index 500319377e..0000000000 --- a/panda/board/stm32_flash.ld +++ /dev/null @@ -1,165 +0,0 @@ -/* -***************************************************************************** -** -** File : stm32_flash.ld -** -** Abstract : Linker script for STM32F407VG Device with -** 1024KByte FLASH, 192KByte RAM -** -** Set heap size, stack size and stack location according -** to application requirements. -** -** Set memory bank area and size if external memory is used. -** -** Target : STMicroelectronics STM32 -** -** Environment : Atollic TrueSTUDIO(R) -** -** Distribution: The file is distributed “as is,” without any warranty -** of any kind. -** -** (c)Copyright Atollic AB. -** You may use this file as-is or modify it according to the needs of your -** project. Distribution of this file (unmodified or modified) is not -** permitted. Atollic AB permit registered Atollic TrueSTUDIO(R) users the -** rights to distribute the assembled, compiled & linked contents of this -** file as part of an application binary file, provided that it is built -** using the Atollic TrueSTUDIO(R) toolchain. -** -***************************************************************************** -*/ - -/* Entry Point */ -ENTRY(Reset_Handler) - -/* Highest address of the user mode stack */ -enter_bootloader_mode = 0x2001FFFC; -_estack = 0x2001FFFC; /* end of 128K RAM on AHB bus*/ -_app_start = 0x08004000; /* Reserve 16K for bootloader */ - -/* Generate a link error if heap and stack don't fit into RAM */ -_Min_Heap_Size = 0; /* required amount of heap */ -_Min_Stack_Size = 0x400; /* required amount of stack */ - -/* Specify the memory areas */ -MEMORY -{ - FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K - RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 128K - MEMORY_B1 (rx) : ORIGIN = 0x60000000, LENGTH = 0K -} - -/* Define output sections */ -SECTIONS -{ - /* The startup code goes first into FLASH */ - .isr_vector : - { - . = ALIGN(4); - KEEP(*(.isr_vector)) /* Startup code */ - . = ALIGN(4); - } >FLASH - - /* The program code and other data goes into FLASH */ - .text : - { - . = ALIGN(4); - *(.text) /* .text sections (code) */ - *(.text*) /* .text* sections (code) */ - *(.rodata) /* .rodata sections (constants, strings, etc.) */ - *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ - *(.glue_7) /* glue arm to thumb code */ - *(.glue_7t) /* glue thumb to arm code */ - *(.eh_frame) - - KEEP (*(.init)) - KEEP (*(.fini)) - - . = ALIGN(4); - _etext = .; /* define a global symbols at end of code */ - _exit = .; - } >FLASH - - - .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH - .ARM : { - __exidx_start = .; - *(.ARM.exidx*) - __exidx_end = .; - } >FLASH - - .preinit_array : - { - PROVIDE_HIDDEN (__preinit_array_start = .); - KEEP (*(.preinit_array*)) - PROVIDE_HIDDEN (__preinit_array_end = .); - } >FLASH - .init_array : - { - PROVIDE_HIDDEN (__init_array_start = .); - KEEP (*(SORT(.init_array.*))) - KEEP (*(.init_array*)) - PROVIDE_HIDDEN (__init_array_end = .); - } >FLASH - .fini_array : - { - PROVIDE_HIDDEN (__fini_array_start = .); - KEEP (*(.fini_array*)) - KEEP (*(SORT(.fini_array.*))) - PROVIDE_HIDDEN (__fini_array_end = .); - } >FLASH - - /* used by the startup to initialize data */ - _sidata = .; - - /* Initialized data sections goes into RAM, load LMA copy after code */ - .data : AT ( _sidata ) - { - . = ALIGN(4); - _sdata = .; /* create a global symbol at data start */ - *(.data) /* .data sections */ - *(.data*) /* .data* sections */ - - . = ALIGN(4); - _edata = .; /* define a global symbol at data end */ - } >RAM - - /* Uninitialized data section */ - . = ALIGN(4); - .bss : - { - /* This is used by the startup in order to initialize the .bss secion */ - _sbss = .; /* define a global symbol at bss start */ - __bss_start__ = _sbss; - *(.bss) - *(.bss*) - *(COMMON) - - . = ALIGN(4); - _ebss = .; /* define a global symbol at bss end */ - __bss_end__ = _ebss; - } >RAM - - /* User_heap_stack section, used to check that there is enough RAM left */ - ._user_heap_stack : - { - . = ALIGN(4); - PROVIDE ( end = . ); - PROVIDE ( _end = . ); - . = . + _Min_Heap_Size; - . = . + _Min_Stack_Size; - . = ALIGN(4); - } >RAM - - /* MEMORY_bank1 section, code must be located here explicitly */ - /* Example: extern int foo(void) __attribute__ ((section (".mb1text"))); */ - .memory_b1_text : - { - *(.mb1text) /* .mb1text sections (code) */ - *(.mb1text*) /* .mb1text* sections (code) */ - *(.mb1rodata) /* read-only data (constants) */ - *(.mb1rodata*) - } >MEMORY_B1 - - .ARM.attributes 0 : { *(.ARM.attributes) } -} diff --git a/panda/board/tests/test_rsa.c b/panda/board/tests/test_rsa.c deleted file mode 100644 index f4a7d6be0f..0000000000 --- a/panda/board/tests/test_rsa.c +++ /dev/null @@ -1,35 +0,0 @@ -/* -gcc -DTEST_RSA test_rsa.c ../crypto/rsa.c ../crypto/sha.c && ./a.out -*/ - -#include -#include - -#define MAX_LEN 0x40000 -char buf[MAX_LEN]; - -#include "../crypto/sha.h" -#include "../crypto/rsa.h" -#include "../obj/cert.h" - -int main() { - FILE *f = fopen("../obj/panda.bin", "rb"); - int tlen = fread(buf, 1, MAX_LEN, f); - fclose(f); - printf("read %d\n", tlen); - uint32_t *_app_start = (uint32_t *)buf; - - int len = _app_start[0]; - char digest[SHA_DIGEST_SIZE]; - SHA_hash(&_app_start[1], len-4, digest); - printf("SHA hash done\n"); - - if (!RSA_verify(&rsa_key, ((void*)&_app_start[0]) + len, RSANUMBYTES, digest, SHA_DIGEST_SIZE)) { - printf("RSA fail\n"); - } else { - printf("RSA match!!!\n"); - } - - return 0; -} - diff --git a/panda/board/tools/dfu-util-aarch64 b/panda/board/tools/dfu-util-aarch64 deleted file mode 100755 index 250c592ada97954922020a4509c669a53a03a016..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116048 zcmeFa34D`P_BVc$v}w{72y~?_GzAK6ponE_D@)QAEQ^3`0l_7tZAwFzv`s5iM2e_W z!EuPdh|3I{&XnpnD4^7hMP~+4M-<$3EV%p%I0~{g3ikb;``nv81ggLH{r^6n|NHs8 zQ+RUjJ$FC%+;h)4_vXp+Nz*55H5w-WbnFF2u|tUp#wrqKz1)?@$}(68v$8=fiRqCZ zj7R1RgiWHDga+iLKOLSRJO@O2AdI3+_>)k!PLSH`?yvb_B}GEUN27dFU)d%loox~| z3b;XZ%wQDhqMQ~{DwncZ!KZ9i%1L-iR3o7rAB~NkHKIR(FjlFKNl1C=@5Zm|N_an& z=&yd7M2>4b4W2q@et2lIuf?PO8z~~`fDw2G;j!Qe!!sUF9G>2I z=x>+;SSld#)Nni_@MPo3!;_1L{-)tcz%zj&zw)O8mqCW1j=QH@IrklgdJq>m&?B>y z2EqTRmj8Vz@PX^)xo+y|i)D2+J}K)azo8ra@^0|wx~V_C8+=|j`0{S>k8ry6V&(uo zd;|Tt8hsMG>F1B#)c;*K`1`uSAM6Idyc>M8nD@qjd0*X4{^vygrhxo=1pa{l{PUa+ zkyr4^+dO|4|44a0p&R;Wy1_fT!N1Sz@5xL7^YS6@&z180WH8~pli@DF!G z&!OGqr|sry>*6axx8{I-=i_ejzt#<&Rk(`kJw<8P4j(bx;~qXj#O=lIs=8Wtg}tuU zQROLh)=Ip`S!XYC7S%75h~f%|tJ3bOs&m$sI*OeVU0UmOQYEFXg~;zIu60${x&5`& zSJgU8fxq3=RbnBpnJ`x=K+XEwusbU1?7-Bys{GyH?I{)7D_ovB*$;QMvr2|lEvT~) zy4#-CIxCzGkF%?Bb!DKOy{f*lsEa&Qm#3~49a9a$?(h`5T(V%TQ=y@H?9L@Fe~(>N zUEyD(lB1*qb$MjH#T9N3Cx1x=W|G)iDf zj3$#l93^bAqqb@ZbJV$AtaNd$tIkPnGP|?HQRhI*MII06?WnC&hwXL|b5@n`uz&y< zuB!?kb;V_N7x63SC0A96bBVxuoV6}Tg}tP-{xSpu!d~lkQ$w@zCrz0#rOv$lws zz;5rhf3$R}9GI8sQ?hf!UaeuuKgP5?qy>aH;-6h%B{SuqG%BHlDb{6G%Nn{$^JG=M zO5G4g9H-PnIHeEj_LP>o%724G!VF-=J;;*OG9Tn1{Ym>lCpM5F%M^UZCTa;bmcWk` zcxwQDg23km;HL=utN{G=zftPHDFE*j_yqxYufUfD;NKSb>Hz$A0>2~xAJ(L_+ZcdP z7Wk$Be6GN+3BWHB_zeO0zX<%M0KEQwrQPNL{2YPb9)NEY_}u~c?E=3y0RM@=9|*wr zU8S^pC;&h6J_Y|#0Di8(w*}xG0^c5hcM1Hd0Q?ex?+C!(E$~eEeI#Fb1>O*V-y-m) z0Q@ro9~*%Go4}g`@JA$m>*f5MXIAKt5`dTX@rVGtw2w0a@X|iE2H>S#J1YRs1YK?l zz)SmSK>%LbPh|mkX(ufSz)L%(F#s>^lBNK>S@dU30AA{|8v^iBZ`~AtmwIb+0AAWR z+XL_>(eCa5ywuB@g&r*VWLA|jUk3v4vjx6A0Dr5%8~$|pyx+Q1%zFTSY`KEZ3&3O7 z=YM4Z`0xq^-xPqa75SS3@QVfhKmh(;fo~7M7m4}}f4;o`_lx`~0r&?6J}&_Oh`^Tx z;Qt`-O#%2P1im={-?Bs*?|}gPb0U9x0Dk&iN`8aTv*kP<5%MY}0RO6}Cocg1mc$D_ z(O^GP`vt32_#~xC{`rx>Ymq-hg>O^g4Jv%Q3QvAL`FBc%C*Pv{>rmmzm+Aj|LYXgW zx2GS;m_db?equ^Csqk`-CVZ?4ul5g_Rd}_1lcK_tk5c}PP~oLdnbI;;c=9pJKdTBa zebSVcr@~8LJK<-k@Z?LCe>bV{(q~O+3siXWf6Biy6f@T6)Let^sjxI~2?sKPg@ z@PkzNCKZ0L3cp5$AELrqDj;mL0- z{|>0|*GeSdAr(Gdh5tx}m;P%?Zd2j;!GAKgD!)~Q zm*+K;{6dnriu?hT-&>={lSP2P{l2X zXRG4F5ie53(-FU06(5867F9e8@%^g!1jLW2;@OC6`*gKG8Sw$C_*BHRRq+{!7pda; zh~KS>&p~{PDn1|a{i^tFh#ynMixAgFbhTfK_yARW5#rgZcopJBs(3BpcdO#JBfdoy zzXS38s`y=qA5+EeMqC@&)&6~m4^YKdA)c*@KZtmdD*h1ScdO#RM|_Ja{wU)6Rq;O} zeoPhLg19!StNlMAK0p<3K|EU(e+Ka)Rs1=`?^ea1M|_Ja{vzW0m3Uk6#MRInA}?W` zUD7eHm9d?SP5j`}(tXW)b@mVTW9|JN&)@L8j_1?mE$y-GQjX5s*%`d8voi>fZrcHrH?-P(9Xd@5?0L&E zU1Bry*=u~v8|BG2m#mM2zf-fh$MwH(#Owj9$%px*eFJ-WEv&8XWD#Cj)wuBk~` z#0s14Xx?qqM6Pbvv2?R0@dMtsCv851#_DTNWWHv!OZ9z=F;brPc-HDg8#3RD;Kuw2 z|>JnNm>S9`m?ic=K^BsMSc`<*M zHm%jyigNAoRv(Skyg9g)#)m$PYDd~Z;PPf;%&f6b3eqm{dZ<3Cm+J2eUWl~Ne7EbO zEi}i!Q}va`v`miak>J)5=o|XzleC~Vq z>LN~>gIJ+0q%oiJ{1f=bAhr{{;Z4*eoV;hX^~ZBDjgOiIZ4%LEYAX@+Y!6|amJ2yg zD0D3e=xaXeYfEIUdQtwk&d`$bNM5TUnDtJ1#L!A(oWskT(y4FM$B|mLGXnI9!vmcq z@*LK}NDbRr2A)aW#%lI5R+zYp)vVC4!gif0o$^7)jwDE9hTaaESbfA(R6p_61hjE< zCCyPnI*oG{`qds`_5JwZq}D`D#7To`<9y0bw4(ee_XoF*Mn9TGo0~+Nn*o1Bo1y;p zSY%hdQ7u`b-b78*$@#j*xF0d5mr)PVEaLu2oOThI6N<-S9v%*1UWN8CEpC);3bAIM z!#dfcWv4HOtbdfoYsENeyf!gj8Y_*D#zt$OWPl#yqp?%Jy808-5-s{eTf1F2rkc-BX| z%vA6@q)20^Q*)~|^D)G?p?nI$EVpB< z8Tg}+og}B8MjFQvt%eQt)*-$Lc{gLfm>b5{B@SZO9tFSgF*Nq`9ziE zJk-^kGk-VEvPTh|622wh_2T`tq01WcjmwOWrCusMd>ngi%I47cLooW#h<@_+bBB2+i980QH8UkB zcC1o1-b?i2^8`9Qf$%0>#~AEg*DgT)81I^-dxm+f#>V_tkd~MVo|N>l#(5u5l_lC= zLv4-*&56FbY2LcKOa(&%^0*O)?G>rCpWs~@kiJkAKOn-1{h05Io~*_^mKBBtvvrSy zh6apvDrk8Ba_ibfpyTT0hIpc%YnkOS%cbRqLC>|Rn$WP6zW}eIr(v0Ot(vAeXoL8g zWU7?K(cp2SNy;dNuggXWzP2WKXUhHwzNYatrYL-E01Z=8*iITZA75jHm+F`FB^sT% zh;?A;7)!V_I;QY{^9ZlTVa+^*G<9AraGjJtRnQbX`wzq=&$fhu-XR@h$AaFlL)T#6 z*bdsRfepL80JOPqY^e9~oPplhm3_UL*9`T}&x!MTK&yDrj`;MyP+szB8}{|>)INB# zNyA1Nm+esTWc+0`RMU^f!+8?Cf&H_vX=(FrgC=1$gFe-Uy*H$-!_ zyzm*>I@UwTi``?rnW(1(>+~4*nG-r|EA2IQ>@~+@Hpbb_mU1iF#r`$wIQEx`8bi5R z%L*qZjVf=0d^pbY8u`9N?U0HG>QV^reE!9^Xq|`?`-?3iSR-*Nnpw)K_V-8a4sYgAa<95~<>79cx_2sB8nD$-E z#USurl&BB;Fyt}qCoP`?&jgBnjuQeHMjdAXi~wqcW4&OnZ_ zXyWq-%Y3wF^vlF(?-;~!;u$H&J6yxowMC-Ncxx-}NR0}dyH#k{FY7UP2SEcq78dOt zh`QwZ8iw!!>9FOd!KRxE+iuFXi|)K_Z5TW3 zJulgl*z?w{#Dg`tJt@4mcdwx_eA_P8J! z&l}0d!esn)rH+fBE9rS;zkF1XP3!eI*1U$XQz6jF?w!E;41#{9$CI={ zX{S|``?G*g0-ovBzvI$U4QzhqZAMw569Z%muJdZ*VJizdVePe0dpzy+30}wa#(bh5 z;r|Ler){CZyLnO{iyo zpc|am=`3e-T1yb*`&p@vu@vvEvYnd-@VO%$YYEnondoV^W**}*BGK}dF0$qCkT(~w zu3?i|&V(@E3%ZW6@CUD<_#Jmy*TNP}UwZQZZyR__kqwdXImB4bp}uq4sId3-9b-GS zvE}8Ek(-gfO&1TpL|n@)SG1SF+glsLdT$eLUW9y@d#O{=)(v?8qRJvR*mA4FN6MZF&2_Glx@ z_d#YsAFy0nIvI4G1p4NJ&N-lWHe`Tp8|cs1Kj*vG2k^Br8ujz|p@BSpE#jRzE#^s! zaypa`LOsE#4|B9MWZNawA?L#f{fzBR@nW9f571cpLias~{*?8xwz}f1t#|0H%6eNf z$Uj%{8soHZjCXkmt2wD>g||T8Az#rMJau&+o@dYS7Xyk1R?-)zv z`FwNwXgI%Kb*|S9<~qU{RloY8j>h1Qv7^xs=#6V`1|4@jl>Gj~>$>8Hj;OAWM zbq>};_BQZ&*Lny~=5n|OW%zoCRQ9h*#4oyEL>UdrYEg#{bp>H9KyKw|yq&KZ-#t1| z$s=WaYN&A^_|gL zTl+TDckEz_{+xokmTS%BD@L=z2*`7ZUnKDRMzKQj;gPQWF~)2i#YVS>*fL*&J?w+M zc@F+x!$>xYc(5(T>e~XjOFAZO;SAWt9j8zRyWVK{Pg-Bl&Fg4KyT_xkRy2x!M>fSv z$g>i<{)Z#j&h`P;)-yv`E7`9nVPBr;2|obpMmXJOOIbz`&cuZjcn9e(2&N~9%}VP^^RO!9|GT3sI@gQ7`_k4ln$i7 z0RJVOPlej!9?MHY8v6bw`aZSCFZZ4NSAl&usrv3f-+!s!ndtWb>|fOHZ;*GMzGI95 zeK16UzCK;eX6VK|-WPH7_po+t9MK{czBL+;0pl?k8(R}~hLb0KorN^!b$aIAs5P8i z+0j|J19YZ2-Mm%v?(L|*5phn}>Y?5&#M{GIdNX_zjTIzGa>Hp8O}#&%vO72;>E1lcfjpH6su0n{DuazK?j!rOvUKb>>BSP5vKBN?=@bk z!wFnxK3lR0G%=Vk-|=kJPnb_SA35r=HXK`QZQylP4D8u7%g{#mb|W4 zl)9Q|U7$@`7fI33yRnuH&)R%s5Ag8YSLQn!De}FmN<*Ki4h_=e+=XDAjlRy&&Dx07 znj~xHQS9L~H^*{2zEw!PPW{NN8|Z*2Ra`QZIOv_HjQK z=o+Uo?ms|3MA=51mmGx*Jd3>M9&9v&zi9(xJ$R?3a{$hF9@2Gm_QCUz77))v8bCY` zu@3S*v=3mJ;H!>yToFAFp2l9)l8XMd#WCNprPhX{pj#X0e;7JoTQqBEN0{=UTthq3 z+6Mz7U%Q1hG!wsIjkV85ouH`^{<7n@u}nh`;EGsgJnA(hus*zef7b90`pn}PYkM4P z_!RNBKA=$;+u4ROeMs?W<})KsvYP17UWz?WgY%?Pmf3ExW|lF-7{h?ZeB#^oFVM~+ zv`sv+*#`NDvjflwef5piK=;JD0N+Nghg{-ye&Bo5bG+8N z#IWAxvy%=5PK3YvGtzavPA)j!S@^Uj+)}Oy z4}DV;W;xm33B9GUH4}2ivxRvlLcTopQ)eNqv!%e%T3Zg>)~`DYX&<=`LT0^o_|T_Q+B#>;mT9iGHlxV)Ly9?bhOK zWkH|I&6p~RXQ200O&U~LFrV9o52k-aSy`jiDv>WxFaQ*A?Ww!~^l<`lt>Dqc40aLFqR z4%>R)|7hvw)rS{eT5^~jO7;HxCARHb_yym-KsGpZ3+&IltsKp}=jUqCz7FGo-k{Sc zHWqj!68ter$99fJ-DB{K#Iq}ZsP}{Hpsoo~=+x^%R?(J`FSXE@rT%Df1jruYG z{TPUT3_?E!qYwM~tbcR}`ax$!CwH)IC(w_l(2sSX$JtAryDlxwMf*9RJ^BUSrhXZ) zXB&g8nV|-ZKODa0ez7C-`k6+S^)rlw+_xxn`el2K^qnR;b2<)x3FO8Z$XMEMZ2WvK zvgI4}0Y06UweSm(j;_bNtktsBM+Yi8JL$xaAWu7NA3E1c3R7e!+h=GU1>c0E%UIB5 z-IfsVi{OJ@mUQn+fMmOUke%+muqfS2b`^NjTPFIlsk5^%C4`Mq`VrCcI@%!JcLVQ7 zM9Wu*FF`;0>LT7Gnn8zzUDvmz3it&&?5`Xb#c{67aM2uB0-V{OFNWjnz%k&Iu|)uv zXek0t8C&eh&9t`BZ}z^S^$hgw_i+Z6_m8|*Pc+sZ^rXCh7+Mbjcjv%?nS{f+eGKJK zxEArj%=?Cn+Yq-f@81yrH9Jp(@=5Cyp9!6(zli>D++M}kat!0%1)RKhU`(+3f^LBv zgFSZw_FPgV+3`5Ps<|8It;UwGA=AFmg<67WT+k0_eZ-#uVeGF`lD9d5=F9m&X-^w!kD*NIgR!P3c zD9azn7iPj4#0bc7lVJ?z@sP$~ZKe8->on60kmF-CQK4KXmGyo#8a8qiw-H~ay5W=C zhH_N@nEMT_f5M#xI+rFq@q1n$rR{G(yXLzL1>10T(Q;R8!MQ(UZ+ePl9{(%LJh6ji zlKpuP?9U`Y=dZUiFVPxzHY^Vb8aIb_jD@{&=)wm!-%YS1e}r8hg|YsGx|hI~>O$7pYay_VP;`e86^Y}hkRz#WCHO*Uo|wd1$DcMH3+ zFYL;=%k1udA|K638)!oHLGQCroeM5P4~7lcu4kjkp1qnq_Y=;?r9DUVHtb_w?L1Eh z=Xa*~0e?jOXTd9wMV8;A|7yGPQN+n6=5xH}a=Y>-l)IwNol2cwBaOFl=UC3~QY4 zn}GZ)dogchBdoa8S!jmL##;-#HIxr?NB(b4TiEv%)E~?*+2*6r=2@iEJp!7Sj4S3L z!h&@H`##cg{v7N;+#8^BYJK7Y&HYMcU*mHjZ27y;4#lsWhX~7Jr2Udze;#sz_O89K zK`-cZ@Na1?N2#yCEr#ApHdO|lm4nxyCmo7?Kd-gvwY=5?*aJu}*{;P|B=D><$cM|> zJ69kL4nU4G{0({G>)YEykr7Qj*q96r{7OOA*87o<(<%HqFV1|X#bR%ubB`A=cB+H+ zCfZy6hPEjTx~(%n9*}>mUDqc)R? zOY1nPnA^!V@R)l1_hS5zVHgkX--(v8sp$R zR6UOCqyLui*et#tk0X9J=7Hx~qu{;*t}};xraI`gLC|l5p=;@(bHQJ_)Bv4NOFG{n z;vw>JlYK;cg+Uh;);E~l2zwlRQV{q}*U}R_f|oS#z2kt%1ho)zsq&w`0=l$=zL+!Y zVa(SAdcK6`9Q5T5+$sBMpmv*G7k@G|oa-BWPnxHT4Wl+L;5@34crM)9n%BcL<~VGw zIXdI&ZQ8hLUufe`j@!2`t|?gAuMD>0%#>g@mUOyE>|J~=?$2vouj?BITYB0=T~zsg z%*juv*QJXMrL)8~%&Ed-F_@EhOM+M*29#T>iws+iGPtK!_>!L8D9fBB9)@n-f%Cmh zsE@a!+ILr@PBY1pyQ*;nJS2I3$;`oiy;VEN{3 z=fkvz9>cvKNmrz|l+k{T^-MIPwe=m&rybh3)e3)+ewSd`h_+~t0nH(26Uu*t9lG~y zXCdcTw*vT0g34^BC?>PD7iQmga#+t_QD72G2|a@8rTJ%2Ceh zaunYrufJrxsK2je3hL&#L*u+ZK?l6hE1~23Tn*}ht+W(2#%m1zd2P$8E!nB}!w(Oh zf*)Gh*HScwX)&76X`}muJ{}@ zhI=m|@1>vmJ1=d9o$}6smB_K#5kfbo@k`UAYUx{)fc`}z4s{YVdlZs zni6YmB{>>;X~E%8^k+8Y+@6PmYTk}wg;RpWx!7LjB_GiIpTnqx_5c$qWu+}j> z*(f>#g73$&WH`gw1N|1%&bG*QI^dvFhI z@kY5m8hdzu5B!-J*18dAE7RZyg^aLJc^l+8O9}E0MtWy|R@1}43Zr$9>$tyX41*2W z%bFPx0Xs0pni(Ds8#vLL8I3l_piK|p9JEXItfg_>8HBz@TP_S>H|_wwH|nHwF``>f zgdYK~6Ys-Wlpej$(0T#qQq!OlQh#Fyl7GNZeiVKF3TNUZtCjPI2&|jfmcL?+#lALj zHSIrkT|)U#oTaqS%ubblhvPqRzr!f%3(E^eKOp1J2pX~;-Z^Oh($ab0xtqXybHRgi zz>Bl7rV7RRw_fG%4;5>wAI>jhEFP4lxlK9{#O1zQ#>16-!~>MiCGoqpyu4G!t+4l@ zn-f3qdOl)2{Z<(tr{VE=i2HiQcXZe_=;P&n0qhSgXNBHT%ykT1OCrvuNuPlKX&ufJ z4l#F-uh9s9H|>qrDtja1irj?ECLf+d%2DVUhES%^Yi}iMA** zBhoSsbIIokGUF8TlK&QbSg5p3XEsqSXOV}_$e26VH=m!sN3`t29>vF|+V_)GdJo+j z3EcNHAg>j>pv%wEVYhAbg-qgdNrN#YiT&G0{U+LhHqFqv_*|_C=5zA{(s+D#2#31aF1BhuLONj#%S`sfHXS$e;1JB?lgGk$nt}Xy!*bm*rR+z+lv!+j>sOC^!urHB?C(%KUnTi0t1 ztI0-Oj<^wZQ9V?5(ve8-v8_zh7u7Nl>4}iQwezD@!-6N&RSb8{21w- ze_fRK@sMcm(wyF2s{hzp)UlFzzuLjPyU^A*ynl4=83TVtWJ?dKH=Nak^#;u#caEb> z2W+N96RX*!HLl)_wM65YtF(W51?c$*{7e(~u$rR?(_J{le-vx^HF%_DIs2F;C$>k&u!GJfwap5N`lVpD9Sycq94P#2vuahh49 zy{{qeLp`*P+6TgyFgv<{{P8@T7GBUkkhNxN*=U~sR19bwYk3}J)Z-5v`#+IRV+POF zOvl;M^;F-P+|=_pmpqR)h&K<^8sg)iOQnRdKJCyip`)!!C}XKO!)`r~J6i3~+lXfk z;j9(+r&~VghG$6!!Facm4@Ax#&6NSZ5Sp(8bT<@pIZ?-I4e#P!Abd>}H_RLAJ@%X2 z)GyJWVE9~>Jc-D|yn27Uf30D3Uwp-bohrFg8y^BZD~t6m!uXC4%uPKp6leaahWPfO zthJeZgwHDX@yTEPOZ2%9SM)qJKN5f5Md{$lgWq-*(wPv=`8nYD9K0TZIf$~% zMx1z)^iG15=Ud>2r%rGf-O`;N2%CcMS7h76Z)8b=4~J}e(oxCh^_9*D`zsOl7yKkY z(05&eT8<+x_uZ-dYG1);r}*xSmZ-pdDj%OZUl{U{pIq&SKLa_{9+sFs1?PpdMwjau z-D}Hq^YN&1>DoCd98;UB`e;PEh=Cq!5qTqwH=x*eP@V^fzI z3R1_%_DM;~vyhByhQ3#Z`f+!zp=|zVxrR3%VS`cWq=_Ux7A~E+3z! z?>UjbUy->yKgLY@XPhCc~^(xv* zOi|W#Gx54j=Vc!+;PMo*x`pI#;y70GTawA(RaO_z>s9h<{CSD)XRrq483oB#X^RsN zsN0uqZ$!V%u&@33XkKX^beGS=dNB_++}R+#x(T#z*Fm0uzLM_8p$ksLnbSV_tlMEz zUG*+4Y|kt1yrV6$#oKY$>Ql5sb9DwXq7C$t^QFPKlh(!a{V*E*zX|smIW97R<9Y+f z;}0nD9*75?2l0Iq?FfCTr5SC}xzkgF*F9>{HRe}pBFQ#RhyQf@19yc!wnxKGr%i#q zty%r(YU6=Nmpj?%*(+8*3clOEN897%3e3l}6}i4d7Iv}`b~AmSW%QIFpLInL{I&7v zEjZ8Eg1p&{1HG#u!>9MYKW-21dDu%>=IXn`9-Gcs=JXZ7g|gGrgG9I|!UhrUgK)SA zM!$f!t!XrdD3*k{BJOSYh z5za<UOKD$@f4kLTz+<^)?bJZ?ngb1 z*mKmn3+JE5Q@K7){@6Q_=ltAPU>9_qDUw|*&H^lSr-IG^=u9BhHojYXf_2VRnWCO_Eu zxvz2kjQ44rh4VP|iTs(-=vRmRW!M3i+wXk6L${{8+py(%KbQZkOwn7v-7C7qL^Q!&dc~Gcv^;^nabNv_j-bbFsBs#x~X<6KdwWgtNtgV)^B(_t@XTbPlTOg}_TadS? z5ALoo?MY3NQcrK>AIkSeQ+j`d7ogk%IAC2d$;hjhAwm}s@u7&I)b z40SU2ok$*}LjOpG&VjI^Yb_WG-ZWV3D1*CM=@qDNqm9+9!aQ=CZb4KB>VtTi1l0{EMdN)W3jde(S2--JFy+ zH4JBxZ)~w=Ozf?x*$mtKjfW8KtEsV3_-=$}Yif?dPJZJDd&a?I_KY{*vuC`u-=2}$ z&rmQ0cDD<5cq-2GU4vOG`Pz;`Up-K3&)8RF&mjMR1H8fa5#bAiTvx_-akw`HW843n zJ)4*;yaq!xKK8R~Y9DEn0 zW1~53aE?eeFYy*=*#6;FQikKN3lN3UCMW&s4S0PLS1O zD1RiC|?%pp|Fk0=-DU?bo9^=Jn;Wt#%IuLUAR9-`)M0^dLsI~ z5B?WpZ}?qs2P6!4Kk)sdOhC8K%yCsCfy)jh+#>)}7-;UkJ%`r&&qkA=#;`tM|X zyK;tXk#lHL&UObQULK+%Jz~EU_q8EX&2FahZ5n=DVoeQ|~3) z@|VN+SS9YJYj_#GjDM!YwTSdSj#dmJj^oBKgKf8Y-E|WXfx4_JusCO=3O6Jkczd0 zGoPtO%o*)NDf7xYPDF0XU-i;&Y7LsugBG1(>Qu-W%e+M$hGlt&^E8Hop;y73&|aDE zU;u6^%I2Z2GT>9u4vjSFm*na(T}-#l>% z2LtO|rMnWhNQL_e--V-o^RcM#61NEBq&iRH-i#a%<@MvCa|hxL$RC?DW$LQI;A7g$ zFpsI&yEO3e=fVFTjd^@t(Sr`r_n;L$2uhV)NwSe|$IC#)GC*35eNDCu59BzPhP&x^=^4(sSgtfP}#ao6F`%AE(| zm&d6eBiQME(B+S7WBt66igJ=)sBN+tCC@BU&C?k{|AU-Ix_AP%yG71H;2bW}5s!7{ zmH8|I^Vbqkr_47sARnK5O_-l|-UOZec~$t6m}`k&r5c085l_(E6F-~)oo&}L_*{$! z+i^F<2%9ey-xD%m4IY01G<*qnNA^I6C;FM#>7OuO2W&u^!(Z}IZ1}D-=59rvA4M_kT!ANleZ1xRtJMP@vjHFI zV=aTOZ~*&qBJ{dO=nHf|c^~#-2l|Zt@epet>;2;2IP=3E%;SSHy`LgZch(*GR&3|U zQ)tt_Jx`4D?x8r=1dpE`=Y5IdSO+|wJKp;O#jyr>e9d_84vM309zQbP`&Wt&CLO}2 z^w%)KOTOW4|0aFG2HQvR6C1~2Ew`-9CmnJVbeDGM_$OA~jd*DJKEw|USk)(m8Nv+X zSs$WT`;d)s7L=iKVISR{Z~sfb8nb5F9kdUYX`14u0gwCoH7DO+nQt}b+(Bt!n#A;B z8Hs%;ePYs}nv=Mny0Ldy&9{KiKWpD+_vX{RREkghZNC~9!j#9Z=}`{ew9wsF7w%*; zgh{uld$qH3)<6F9sA*uvOJQPP`roI?IF!r7Lv=L+e${$;9j}Wtbz3q#LbSIX@GU%} zUhXPei26QLmsO=v`J2T2bs$d=%HAT<>i{?4G9x`__jPu%{mQdO6($_Tw-fF)w2dbP zPvq;Jon>=wuW(MvD#@zOD$a6cIkF0}>au2Mbu5+6`)y`s9 zX@l8aXb||}nUNvo2-qviMl4~xlbyu28T@}tObMlB$OJoM|2Is5h zsIPJqRXC{?dc`(gPK}pwo0ZqLqY@XJ;Wp<^o^396RP%hZ3$o41d#25f+a0b7Lb4m& zwWy)YQN?@MP4-fEeN{=4xv;juydW)&UXeb;?5Ha753a7vX;xm3ZC2iTPJ=9QdGOxq zDra$>8L#v<7uDDCCX^n8vK&WMl^ZC$hF$cEfeJMAEM@%p^;K!~qHx(~>Koo;?QyxQ z1cgKu{6+I1fq2opIk`kuj(3-%?K)N39nM-e%XK1aC1_T)P*#pth1b=4vdr`nar9kz zTRWlf>T$d(-8|l$>=|ZOa#5rtROBpi);WsH=za4_N&XUddjGuHQHoYjKc$PrV!SfG zmR?Iv70qO^joptrKRkX;(4BNi1V3Y%5uW0^OymR}BdZu%)>a3`=joCnlUk?3-ntOiAkHWG-<#m2vV{ z%*)ZG_}3e)Sbro{&{#09sC2ep++cZ#wLmljg{wUE)z$7=>NXJ%*!u3)gL`pRh1*fW z%A6I|^j>;e&;Iw*D-EWVI4c|ttlCjm#*|mz*VpoiW5uNl8UK9&tZFb1A2NdYkpg-* zKa*3D#($QezM2|R!g$lZ$C)O77=bU+G*4aS$aFT_gP$?TG9yD;J^0OhGk$UaUGm(@ zIn``VD>J91QD==t<1G4d14v7-3}MWb_>~2e4n?jx$R$Rj%INe8z^rQ2q+!Cy|TH(*exI^|iG~t7tGg>PWVL=ES5@$}95K6UtE3 ziJ}TgQ8<@NqW^Ajl%C`-txO1(9A=}$V=N@840c`Ya1m#N|D5JpCrNTH_at+v1t1Ni zgxAMc_BdtVn~*h5>~9lp9wu<~vj<&x9=kOZ-8UA9opcWWb%bkXDZilrE>H2K($-2u z5St4ct43qQK<07yX@oT5&EYhm=HV2a;IE8l!B8$QT#UkCHS;*}!wXfl6S~@`%`S)k zeu?19D;syAJh7>H9DUlaC{C?S@$Xk%tWkh+VjmqRer^K4d;y{oc`id-g)Rkr4M6r$ zfh+suK;5(#j>AX5Xl(w)M8#-)mvxX+zo@}XzYalSf`a_FO*oI$q29~Zop~IszAh3| zeNrnZMd3OKqH64nB$lP5B=(q%ij*a59!H`Loy^BZ2%V_55VO zzP~JA?wE9H=JGx`mwq}o6gx}m5#j13{ltmCdsLB!MxmB=m~rLzU_g#Sb8cyUfs+eqs54?k z(NC<9rle$}{e(|>tz$82#zx{N3MOA6-f;5_Y?+Sg>I!VBq=U*bO7*-{%5Zce)n6DA zNu_|&y7QQ6R%!3;+C9KqT)d(v7st>Q#NSLIUWhfNtm~=}OIv0XFo%AAhzL%ZsE|}5 z{0r~$GFRje$cG+H$(=rF7*q+UYgP5A`mz@JM03TD&lp!0YkAzyz>Y2&k61DyV+8+` zy(p+JF2;6JT3-Rlu1qzrNH)?{KMe@n?^*033!=zTTu#wip+(aEOJ&5SJxOxC!bivm zRRmm*;oM-GF=g^3@PwjbD&iW901hMtmFrB<@{^PvT%iOgHU}05>C|cX^`M22wvtu+ z?RO~+d>wFhRWX_}Qlh1!2!fgBtGX82pBwGFs-U%1S3p_!>sXQ)fEd7}{QQ~um=Myc zsie|xktbKtA^GnKab;T0KPi!z9icvA%b-mZ{ivyTdg|nCFm@TeyU_j~sQHnz7;mpD zqiBCIsj#9AGMUgHzH4`7yu81DJ=Wu7zcF z=JXLGMyKH;(>xa=g1TE!Tvq8SsT*d_bJRL2N`QuD&J8#k#0~CpH+G}q;i2j(t{s6Y zt{r7Abk~BT%yZloB{0-z1O;`@QkaXP($GTEh9Hy{);cOlm!6EDXfhYLOY6AIrUGRS zkJ*-8Fmw9s!b#KTnP<#2!}Q6w%_y7~I*b2?7KlQ-GEBsUT&T&#ZzZ+IGkhU-4|i3$ zXSlm|VJOYJqNt4+o&k}=Jtd^jiO>5x9dXji7dJw=25<%azJ4Uo5ge{xxw`tZI50Ux+Em zkeX_H(~k%h<0Rgtfr{lp7ELvzfU^#!7x?9>L+SDrkafugqFCn2y6>t>u#~2YwRnh_ zgBmTt?`tW8CZVbfoaE1}oXZPbnSWLen7?kn=)Eo{;YZ*Tv*)xFFJXr}m63WmI zCPad?H;GZHd#FSC&AMUSYeDELrQ@abRmEf-fKgPxU8gq6x`x+fPO+Kf`zVFEQ0cC1 zU{k7YhpVPURRf$h_+h%s{}g6%7uDf+$%yV$@ztAG%3Z#c_$G>eJ7`gHTF%AqrJ36Bw5GSv#lWb|#6^m4%>NUHm7awVJ;IEK?GMp{AM_LA<0|>3ntPQ({xuGVjNO)-3(rge zo0M-Wm}H-2yM7Y8!B$XU=W&)l$(C!MJ!4k>%)&`Ig=`iKNLX^_5lfOsWGsPd;J{9kS?5{TYPD2i}u zkXl&mhNW9fmacP&v$!6*J5vM(bsQobe4#8UGu#Cz9!N{!*&%_)eVyFzLc~#~m}(&{ zz`rsfAQsY&J503&_{)@F*QYGmCitnii;1>Y5B*RicS1RYbwTPs%OyjDT+oWJ<59&9!h%CGi8JUH zAPnhyidWZlxi!GJ9YOjwWT1ySOQkpgz$C-~)KNcgDrx~ICk;Hct6`A|NMyT`R#&5tEJD?>pe$AVrQ8Y|nn-=3jwakK_`88|bAK4o{hwc3Pk$Hr!QMDUiz$VkKr62W3RyVki8O zsFs8z{GJe!{wjZ=42pmc@n1cq!}#n}Ivvn4h<;=r`d9KyYFwFQK5JbY%e4-w$S+%1 ziY!~?s&e2&K~^!0I?e|dXuv8Sxm2jQwYBxtb*g5v%sI+20;igvpnSiPF|n`lZ46FQ zH{VUc-H`T|TR@j@faV-pB9J_FkP&2zpa|4KWjzlQq=f$qo9tp|MTIikax9ntkIJ5- znoH;e$j`If3g_!Yw(8$+r|<>tw*wS^t#JBX$+N?|bZA(B%CwWmMaWKbngd5H-03Zu zoQ5vF99&J{D}w6?vM&T@K?TD4q!rf1JHr&~oH(b>QI35Jo&;Jb$S>@ju2UbJmvDZA zgPJodu_?D}Nw_a&2k^3y2Y%(*F4ABAm3+TePhffz>g(>YCf|J9HMb^Lf!pd~E73m0 znTzyD2tfV=w!n004GPoybw=(c%QDkG7s{@|_PXR6RF+&~NiIn)M%}}B<+FtFs%xl* zIS$jRj%zArI=n`{E zvWNabgf3>%eg({(RA|e|BkhY@w1BxYrq8tHrWMSakwfU*8QHT7<|!ebAoI!f>(40> zlvjq+=GvwdrtzaPLeHLcSry!ez^2TYW1BuDH^9C^ZZmgFV7|F`;BqBMNm3mZc5Sto zPt1m^1UoIa=^&exnuwH6e#D4vt%Qpsl8%@x7jeg%4SFrtg zDVeWhVT;j0Ybk6f$Xu*VX!!JF!fA@H&sA)OU$jp05?boA3l;T1*eGI7l?_9h9fC3C zgp1vz%n1h+H3;<#PI>MJ5c)`9L6KaELCGAv9GM~Df8}&e9xF$vNJ zv>R^pHo(AEq}&k5H0hN_(%fnp4 zU5}r3rs2b>>ku<0&kKtcevwlqjV?@_-#0<-CoWkP{fhgUe<^>pdoj2ZEXfP80CtsV6fT94gP$>MgKX#oAqb@hmL-Gk`R?%o>kuK@1@NKeGrobay0fEVqrjp_Q z3jGs@A2p|+ug@oaORDmUitVX`dj*Ho{tW;VRwZgxj$3I*0Kt?s$U6o$AZ577wNO=# ze)F7opvbw$D`mG0jbuICmw_T_JjatcP&dJXKJ;6*Q zN4NsP^=*+VRkLJVGEtx0s%jP9T+mRO;a5$Z!~GblB)atiF<_HQzrX8PeON|NPKhC0 zwcr!@py5ZVr@hP!L96)mYM~%QMNLXdVt#){B~)XmVepU;i>ewECyx*Wl;D7NwwP|1 zfQh>L1;Gl!@!L4OUm`B=Snz70sKC`qnla9u$=eLZ2A4og&T@M^E;`;QoI-BTiVFCd z6&I1HhiloiN=o@*4fO+J3(LFC<@AKwlmnG4Sh@U9*xIuk4RkOqTpuvPu!s6v!m_R^ zu5GBMy?e$@v&_@sHKQ^Aw;H^%W^=hK8%JR@(X?=tD5-2v%m4hHzrO-v8 zNq70wZ1;ya)r=ThB)dbOt1g2x(lbAW8?g~3q?gS*PSUMu<}l zRm#8Lj|f>z;bD%R-w}NAM&ly{`@UX@uWd8-yR(a`366fU_&C9>>r4JfFum#1o&=xR z{TbcwWc`o7-$thns1H|{!emf%0`J-m|OoDCHb1ot+Vmk_+e zS9FQsw{JM{H7Ler-lB;l_;H24m|*evUOy5%*Te8zf(Oi1c%=$sx0zh{DkNiH*%rJ{ zu(oC)zBb9&yI<+X5xo9L5WY&q*rj`WyhpHnSLl-je{9}G-&k zdl_Hi|-KZ_2esfr3Pbv+^tO^XlM$y6MXLD@V^rrbUf@?g1@=b z&3`tx_w=%xDE?GG$3BAN(@LKwxW@JwzAnL-zUEU6!I#bNZ6Ihdz5hMI`|o|WhG62Z z=kYag#-99Y&qjhHkL+$IxaEzIB?L$LSTBMPHXDCWFm^-FqXb{-v1mELwDFbr+5=+` zSCn`OYHlh1hTz#7>2+F+6*(&KN(9C}8sWT`;0#vu1Hpf<*H;i+`lJT0OJHo@S;O4~ z=f2+S9KpYTyxmD~*6|nm5InK_)zt*=Y-+to@QZ$*7ZIG2_DK}MGj|?-fS_~wk)H_O zN7=rIVxP1Y^_N^a$ zK=7`$?`|ge`u>kH2y7ryi^!G&{Q{u9B^^}8k#oHpjUJc6GL?eP)8>G7d| zC3t?SZVbT%cLdo8zV`isF9^>5Vqr7E?;otXmSDrHuE_)+*x`7SVBE^mmkDlq&z($g z%(1e3g6kKDzeP}Yeb`F`TcfoD2wpQdcs9XTuY2)t1XIFZd5+*i^LGv<7_?}|Ed>AE z`Qd(o*S>RT7s1tk{CF6_e$V{tW`f)Impn#r@DIh`5`28?qI!a%Yb&(`x9N?K6P!4v z=ShP1E)1z97%`Ux6TExsp7jJH@7R5e;4?#?T}m(`{`qi%k3IO_Lj-%g`u^7hU-y(fK=qu4jrm2p;Y%cMzQPPDM1qCC5TH5&Z7G z9v>1cTp2Wj;Qk%DOoEQV3;#^;LiB<|1aG+BHHF}(i>oFOoVw`UX9#{a|AUVSmWF*{ zC3xz(kH!)#c;@A81poHOm;Oa?`8&^DPw;r>t`P(iet6{-f~)qwc#zDA@E;2N zhXVgo6zCLxvc6x7%Y6T@LDI+QFAyFQ2#Nnj1k5})J~k_Cyum3D*!bxe_s?cJ(0 zz>N>&YZLWFit-@>aw87mH6kGKyTyP>ucg0_M8}Lul*#sg?(F1t#0HTce8}Tsc#UJY{N{AvjTH|H19 zDCzcJNw4^obZ0=iT(1&6Nd^QAOfUJB^y*(pFaH0S?)sJTzn1R!mGZxq&YcUYIs)la zr%Iz>VEXJ|N$1W5Ri41|xvI3Q1-a8pl@M6oqe{D4kUOWYmJooG^~!Z{eNIl6Ipz8p zI9DGvJahOGeEs3t(Ic)+A8Ag(nT|M6#1~pCa52Dt-FejT5yMBA*(0b-*{}W!+sr_0 zjX0TdSKRKjE2rLe{uR{8=mAbB?X_-q9Xp0?jbA;r^K(@@uHe)=*)G(g#9gJ1Vy7Kf z3+;4ah+T&|D{*^~{fr#Ah=uQyV}mQB@4g=Qml5CWLmSNDN8%h27pm*%i+=2gAFE_# zWBmw`jm4v(YJB~n&MuC38F`Tqrtg_D`b8S0fA}^eo9-{ITn^!F-0nx>jIY$S(2gq! z&LwPsAFbqNoBW8bp(_)`?>u}A#065U?y&!Lo6%I)@Nqb6uTe9E)%sbw@VVHjH! zMgUUK!KuB(Z7)&2L|m^-jl_zp+f@8dyz~z};Q$1||BV{(Z95codWvgZ)phP#HWzq> zVl=s~Qnm#e2U;(Zv+rRc$kKJ8O)!Or(SZov*eAMyOybJ|9#((~#1(V86{KqGQ}jlu zS|P6dJ~Q?751a{)Lmk=-2mF)hDXPUibY+Nkep8oyL_OhXT!$&HZeVzAwLmD`D89AK z_Mt{4qjF9D0^+!SS7+z9bxOd|xE}MgKNBt(6gyczczi{pe$xI4gYn}8VL$daDsK?- zcUbzfiGVUUe}rbIM%cyWSN17XOn(tv0+o~bH26Tli|ggMsL!vTvt$1LimwZN=tt1q zL}hI3EkDwKeU=sZMyntYZicKhWKOK%)j3 z?5c}p?BL`=@LG(=X244yLgV!LvI#g3b#cICXDrTNR%@yqnDpa;rA6B&Ld zxBf-7dde4TDB&!Y^vxszCKs$wDWtq6Ojp5h8Uf)Q4L(?@Dw^v zAq++A{5FyuLqT>N*5J{y#xXeVMTq8&NJBSZ%9Z`_OYk4q9)AXm1gCg@`-;@^JTu`i zBG@`w>LqnTbB$5AK`8aQvp6dW4$|HN{LPehtx+cpji3cU1k<}G^MdB+iRkqH%%HhU zzdQoh04RJ@sGgeT;d$ZuUNSttr+y`9&ha;!^bg7KEq(OSGS97%`ft(s`>3AVqV*SG zC-Sg8M*p=8FNoEfk z@URdT;zfr0fY4@zJdWT!6da@@mDivNc?Os_2{S%~-XQh{1qbV11PIXv{S6r1a-K2h zU4#vv<6|=}I6342gyB&cn`2cON6Mx8X}v@0cYlu;+`KNs!c zI&hZENt@3>JeqMvowP55-T@+%$f4~olgAr%()`s9mB6MK&5ENoC-G(SL;pOp6W2(oe*0da-IuofSL8gcC8EkqIpL*8o6G9mhP0s@| z(_VaPOmE{;%X%5nT#zBz^fgcVo+n-8NxieMl!Jo%2bm&~hnWWAbGd0GKJPNkz~?ek z5kBuUHQ;lpX$?N_Fm1tSgXsl)E-}50&&8%M@OirlKOM^IP2s4p&NKv{e^}0X*&t|w zbhAy@BhF0o@ToCX;uGV*r_QtipFt+tMuSa%!>8UvPM8qWd3+j7Q7COR4aa9F>s3uv z8RJZND=ey-hM2}Q2cKG#1D`t9C*m%`t1cp-)Ks3QlQnqyM3X7{BTxMt z(R7M-@F=~umRL!1rUa7{PwYB@Qh)d@Rm-MR_%zS?0n!&z^aAxX{?ABn>4WI`bqK|u z!N&ngJvR>mG=4EYN+Dr2^t0G3J`vhcHKe-ctea9p!PIt2{fSbe@Ts7dUB z@LozLE_#y!%Rt=^5J)2XXA@LI{7P zq-ZJ=??oaNN`%;Dyc~X*O(}Oymg9}IQT{sf_geN0}Kij!VNw2b%;}63_Y3tpWt&I?iHk;2R(y_O$MgF1DSHDf`|nDS{aTq>+wEo z1s^*||0Kf1(1yM#`ln?$&Z5U}rYQLMVSWX~kT9GD(Iy`<1GTO~4y`qWR$>zcQ-W@z zwie-obn4(|bVd#tC=nhsQ~xQDw9^O8V)`!;rh-8?2I)^re7-^7A;Sem7CZ+9O<{fY z{Q=)VtzmIYKLg<}C>(EKAx99H07U4`|BJo1kFTn_^2X0O`|g{2bCa9*kT;SG1c-ou z7L{7GP>GNbLI?qaVnfIaNlhR^P;99nZ@vsxI{LKOv4ytI)V5S<$Bqc7bn1LYTRUZ1 z+d3U*hUsHlI^*+{A}Vcd`}?lF*E;9so{|Yp=cb+H0@9_S$Rjb8=1= z;bsz8rY0lND20+E&Tpw}_(x&hr%=#}Mk&lY$^$}E&@)cnU8#(dSF3??m2vXQIC*89 zyfRK+87HrdlUK&cE92yqb@CD6OTnT$_?KwWo1O<7(lg-2o;TT2%C1B9J3;9IWXYL% zGYs)RAWI&|W}^{oQh!9*S;O!hSMz8j5vr;#=C+0u)W)}4Ac9!14$E6qBRCb|hl zMuJX~Aj|nB@$4|d9Y>Mr)moD+MnGW%>^9jqk;OPUUf2E5c>EN}`zzG=4Kdh2B(XRZ zZzM2&h>EX+&!Cy^?Rx=LXl*444hr^|!Nyw%`4K^W&5|Z;*q&1fKDivBCwsu-ED(s$ zlN6zU5H%5@C&^+AygDaI5xRk|PbMisH}DPlNs7=7yrwWo5xRkIEKX8{zJU0Aurx^# zx`8{!B`HET@Y=Fu3iJlASLGRBq#YXfot6)Md$`U*-L&IFbV8VQ%Q=@4Ln^Ze;*zynRgw)-2~PqY=oZI56rg-b5$Oh!Se)8N!SQIX9qBe?LfucoPB`v58%QP zdI6<56ochIiVH{R1(fDcGdWM;l56~7G%HC#=z5HGH0~tHAKpxGB99%u+Xs+5qpC|-FQ3b7g$CamOOh)zFkE4-afPw+B)P)>1>#tRlO$J&ub((K$0uWx*?Bn zo&}F#b_aaTUYl#%$io*A>oE@&Z6baD(0Hcn$ z9j;nSdG%pjUG+&^mHHa4T73uCsQOP_vs4_!F*Oa>xLSg1w(7$*q4waKqYmLZTRnm6 zC5Q^_tc)H8SF$GWs^}9)o+ogMw$>D-++M<5X?Byl39Qw;Q~Vhisb)7uQ$#g?0@v8n znEI;uFu*uXD7ETlT;nvK)O7~jj#XZ@e+qo!cM`b9fcFu&f;J{`@>1#sgROvbRVy#T zV8yEmT>b@UI!=y5wLC@OB*L~Pq4anifo(Ks@rwyuZ8%&`;PnJ%$FC;%DT1MpzkozJ zU%-WCg!_!jr8MzXT#~(zrO^EsH;*Rs)A;B9o9pD!Y&Mx!TsQAG==f);C z|LI2Zl9KtQtMjTQ^O_sYn*!d3>um}Ktvblx{5^9e7S_ZiX8gI-qN_oU>Y7t13@ zOk?PN9-@8{nNMTr+%I@#d7nmx#>4%RmvRy_K~qG#$0XgW&v&)iUZ4lPRWP!l>tN3cfs%g~`$CDZDuyx&V^6?&HgPKInXdPko) zHkljIyIGRyMDIQznQruMDKc5qp}zFq4W##Oqlez*fTpMbm*kgFBjpyQ$%~m13_u0s zT_r7~Ag{04iy-fMl$fEJ0eNo`vRM#uhh*LZ5$~4F~-c$(O-~M2k#QCB)Le({;&D z1jf3SD8gJVHX(psRYEhF=CQucDWMR6YUuXt67rM=UY%1yA%KCePnJ*!VBj0_ODF^| z@S4IBnKSyv;t~o0XxQ`zOH0V|4BRoUgiOi6Ys*R~1Tb)Cd5KI*y{@8!Jk}WqsJl`n z?GyN?duEqV2taN~_s%V$5P+PIUO(SS(6lREL_X#cW7Dzg4BUXp9qaVb zu@4b=DYYIOHsFHJ<7>xerLQI!tqaMMU32-YgLpx#Vld z(~Tn9oU2RS>c>#_KasCd_nq>7%>Y(D%$7G$M23)>iSVL=0DNxBnM}ZB*v)JLrWNCl zMhG|sfV}wxx(hZ0wWymXPRK(~CdKKnBXx{w0H`{GveY@`<{`)QXNi8t2>P|)XXsPl zmpXtP)6@O078!kR8Vpp{TCAIF|5QKi^r)jT_-&*{02WgX`u5c^+ z@pw@IDeX#^3~91i(B5lcXUhDmr~>W`;Ga84_wTCrf!>4xQ~#PcEOOm4noIzwx>J6b zs~j*@{+){2T+4NpA*mxarE~N=F{wT#L4rI-` zC;D#y-vsmM(&&Exq=+Y4rftNNpjFlRGzcTkKR}xj_LKs%9OFn~&%!EY<_UNs76 z+w5HwS1&zc^`#a95t)yYGPg=!g!FD8-0_%dkjKE)5j_j|{e-WH>A3=@ax~3L;^^F>f{3^=8D?vy9B@5#+^LHw!p3>ka{Dd4CR&B=M%l)r-RF zpdjmTddZrlcTaU0mhYLe)q`nVfEf=W*OJGiFeKgabXZg-;WG?e#AL-Tnz z{vH5MdHz+{|X?IvIYfcpRxeH_5206001&&L%% z%Yg3i7Cw$bI^8b(5dhkf7N&5f`db3}0Yu@SiuM600N@lKA?5EgW>;c1?fb?9UqWux z+ecowguJbHFWp`!F((K24g*_2hn(JhRL@ZpQ6pkj!K_uf2bed3$iiPLnT;^0v)Z$D z3=BR<@ai0GHo^p7pVVd}Oz;i)+H8agUQ?)P6*TlW7He7s7Zd)2rJ7bj19yzmvA}}K?8T!Y4YPAA)Y<6HLZdlC%AX6nQf$kto8Gq z$XRqIt|#gZNQt4IuE~ADDZTxe0n^Q=-R^WO-@_Fym-jN2`E(MwOZL6NIIBhXNb*EmcNoIn}Nx zTY!rAy@Z~-gY(GT9;SiHdkmv)#`t0CVBQ5}e{D+181oiXVC#yB;r(SlSXFxW)tR%H zFa8wcpMMVupCQ_>5U2d{l{nIa^1Uya>^G4$=P!pZ5b@8EHK#LQrqY7%Q@t;2geRzK zfzjqa3tm0>z#Sp4mj4@MpC^*9616j)jCcp=ycY|v10yo!YHPLkB5SO+>Im_f4c}{y za9+KHJdRUw_8LlXO9}G3gRR8#0`bgi1EuNs1=I0QBWtYs0$Fw5No45|fQjEg))@M) zsc!xw*{8j|}gvH624EC-dDgUbNW)GOKqz{)-w%S+0u zX4!LGD}3=YG!eHDC)ZBIEx|J!it=dP;Coh8Eqy9#TNHOGOi> zpgp63YM0nf+=#q6l;iSmBX5ogIbU33Z>@MWF8Q$3jmZCu_)RqYCfS3-2_}ZKOF=;`QSFwoWVO)rwIEXu;zqusUe+A?r=W}yjHhx z`ULihucIw;hDARCwef-I_XCR@^TWOh{oX=y-eP!697a9U?^|rYpF%!v%gN{`Mkm5< zD1WPK^2?Anrg5w3%ESZ68$E3`{8Cp(8Gwc4$w3zxX^2Yq{w&mxLe~l!%$CSgz=QP^h?L*=Y(&n#lE?PQ6z#Rb2 z6Ywnn^t5-OGZ|F?6kQIWjDP_EwFKM;U^W4N4`3buXUYp?b>zcu$H;}cI4@noA{4bHelJdW|`NBH9*Z@lQ zerNNSA#aT64|WJ|Lf#mW$JJOihY_b&6MQ|*_VPzk>X{&@{v;b-gMseDF5L|Nlq z^ygl{=?LK_TTTdo5Tkm|jGxo+{m=;IPBo+QLo+HhqM+`G|i ztx>~2S=gxH#}+nI{$<0o*374WHl~HcG>m7&9LdJAG#$y3d%-O#O-HgcI=Drp$vgPRn*O@Ll{5UngKkl&-$9CUiW3zr|D}cCPe-!R`K8o-I+BgnO*pv} zFn(`=&K*2NgWPTgf8viYBu1s}o^iXWi`dY)ydQa^+IEi&ed5=Ur#sr-YR|acpH5?s za)aSF-8_8PY+GwX;(gdF?3&KLU_Joj3)Z8S@dZBsJL3zgfib?|9stG{d;f6 z_yT7pMI^I+g)VAmwmoBuI9cG3wM^47GZkmGIGT=`??ww*%OjeOnGL=*rsOZzv@kZMx!RQM>7yNu4*6M4XwVcmpRa zdy{EJQe1&7Bj=2!}}yR-TevJ239xcX5sEg%bXm zfbRnM836q&T%u>W9#}d0cetR_#VsavFtXSi>_w4#ImN26${BbagrAMO%gM{TSF9y@ zvgf7O8oZy#J`lTFYJ7kgByJ<@LIRzfPJ(N)0lT?|X-xs(+#Z9jBUO{|LJ7vp(B(#3UDRQ!HqpQq9r zOzGbvOWwk5H`$#t9p@jZ)Dj;>*6491Nn1Q`7VCHoHCo((?8`*l)=Qkfj4Zhhca>qa zYBt_iL8UhP&&X2un7HH;yOO&%8g>4X2(KqLCErCCXJ;e(XyjucB6EN$sVHwdAQ%`O zBt@JXVRvF}zee>92v5n{&aR*e_(4bBA5d@^V0QvP?H5U4=hRA=$!=V=96~?v(;vho zx)GOr>{O7%`fyRUy||r>*=FPIUF|09#yep*-q~j3?S0%$n2mSBY`hb8W5SJer#uTGrCY|2WQ zeRaa@s}pu#ohu5kQ{)=-*S(l@kaSy?qPyfhtZAz+y{&#z7M;UweJE&az_eA+$89}~hTTDW zT)1!Y%5&sqRM#Li| zhLby+Yb~Z)gSS$x=crcRR9wwiJZI`PB5UeBPxVT?k8it-XkWMknku~?h4U!;ZK~=N zY+Xr-h_VwE#Oh3yk?5P>ndvK#N&fhw<}e1Iq(MVuB)LFk1oRZ%&wsm z4^kM;{cFh2Q@`olzxpg-Je*sz0Vy$8lbo8530&*ed`95OUd@*QlfZa5x8_BGr|X)Z z2#gbt)a4-93q%CpE&#ZjKzTSfwE~!L6XvQEjmz@{PRSzIm(_=&s$pENg?QdGYCNS` zw*ygaf)c%~hJq5}sau>H3QC?JczL9Tf)ayojnz<4VqgR%@`M!SjjxS5Wv5r7G5qKu zJa_O>GKdzJ2D!W)CTEPI#U<@bcouoHP_>%!iL_&KSGXk6B$@;lm{SUs-IZ?PXF*T1 z!kI*qylNF7{LDJs+*?|iu-{uQ@wVGN#}xm!qH05Cs&T=LP2Ida#FT{0&qK*GQK`!^^xH|m^nGy`*`(W`JAvfV!Wm@6F zxa0-{QX@|GG!)X7N6*i`3?OZJbY0Abg9UR|g9N_=_~#B{-{2Jf9hm13@LK@m2v~R} zb~Xg82XHZfQfDr%<7m4yL~+(%6@D5eF_OqB>!h|1&?6TR35~f2zJ`MG0YZO@&`vg~ z*hM54y}Eda(5t^*l||Uj+1m3DXOZZK{Ieks*-k`1}>|u zq#Y+MiIMWUO4@N6xMEr*?KllwIir#szk#vi%zpsHIX|UtJ`9MQqrNKpF@WS8^_18# zBw3#K0&AY`*tvtBrT#t^ISDlyEj&hAh|GE)c7~?p2I|UZkbT``Z$Vb)&cn>Z z)%ZKV##yTIt(qM>BBnwD6sCexeTZt@iu^tj>{q0<@lG+-e$6yJmB4ckVh)yHLg0BC zycAi^TGVtMxA0$4*_uv@{(R^Zp|5fa-K(K7 z_EBp25Vh=<7=0X~mP?F423*5Qjr`gmKVjZ{)<(NaLQVK0@g+q%`4wH^CN9$=thv! z44o3on4U+d&R^BYU+ezCB~91hX%F-g8a;_gNTSqJQ(N4}Aj;Gnx{L1KVq~50=U{B) zx-F0+MSHNFuATk_|5f30ATyjRn6nZ1EEVo`3*WbZJ<9rP*rWU&^v0u10477^*-684 zAxf-SRG-A0Cn=3B{h5){@TZNB`zg0@H}kJED#!`=T|{=4kJ|2EIi|)C!Jl&rzatXe zgH}wfNKgxknUv}=3UaEzz#V*=Ea3}o?N>l;rso%oB}^M&s@Wi(@CFKv+xiL{X8vcO z&Kz>WQM#Cw3{PVFFc!^Ep<=|D4u#9wy$K@`n`+nYdA(MM$B}sH8F%AHXu!&Lpg@%` zbR3FEIXe$o3Q9TKfh@Tvn~m&5mO@;&g6cZ@&v5xR{&`pFPaq)|<;jgJ$1QLtCyTU7 z=8vmP7Py6&72X_2B^!#~Uw&oceF;3VgU2g?xH^%*tc~P34PdQ{T$M~DhyXp$HT0C3 zi)>aYNL136#rzB`7Y;`y=as{2PBB~(wjpUI$90K!?gSKG0Y*t`Hj%g*U|uAxz5F`h zt6+BpJ{HUiG3-v!OwbX(spaJ6iZv)HOMFYHHOZ6)gbhVRIu7TEX*J7cLNSHW`DKD6 zeZaqI#~T-LshHzbhR`*{k9=l|hzOYA z7egpmZB;H|ClQteLN(xP)3V?)dA#G7B0B}IcQgYzb*3}26WFL1xiV~{4!y5Yw4y}M zk2%#>jnqvnUHfsXnQV~c1?o!#W|m{kEH~ZEk|WJ5&$ldyn(t@O{{k_y z!l1K7*5cm2&!`*pnaoKC5=H$M&|FqvJ!CtvbTf;mcQiYJX_>H{$?-X$om`PI>30#> zJim*YW>UVL5Ct+J3WEv3{VDcqgS^DAZRX)9CT=H(o?32gzKrEIc3D1RkU>NCUf~b1 zp$QD!WW~UJlSLP*#iDCq4rOm|+Ihyb#l~yNUabShyok$-z;S1(dscNRuspe3@8Zxt$gjnX*}L zN5jnykUUptxWN{~U1f%`#y5h*-_XOV#-SNm%rH(E(Sor+>OUMD_uo)W@_mNM!Xg3= zll=zJ0a%4Cv3`DPx*^y3QX3{0iG58YFDZ_9`bfi>5%3dLUK}`&nRXt|l6g2gn1`1b z93&dm^vD{N^qdSBe->xmyq*JLuyl&6hDRCcs_h8Cv!vTc9NDx1$uy@2!gf2**9fc!j2h1;h%_|;hvL*f~!3IXvN&1XR4=jAV zrjSEhl}AP8Syr%^wbyts0KxRbAS7f`=A=)`+)OoD-QwxRbY+I8VxXo1;Xq?HVj`NU zZFE3I2r<%GmX6d7qIl~HMg|xDWC(%_W4M@B1*u+T~b-$W0&bq*y^7%|9_|5i>M|ChQvFOT(U2mZov(=8a*LKFj1PXDyn5vm$*c zDn|}QRp4C^AEr;JY8x9NGPI604`ivYxUpfK9ebb7TGFKR)!#a?!#Wu~rVFBK6Tocs-0eGc zfja6o8n{vCHRx#U_qbg}wyqmJIGr{Vz~H@Z_tqf7KG1E16RQT2p-%XRUTwM!BRgF3hUKMxf*b-f}OIJi2 zb!Bvyu2x&T*{&`J`M5^ZQp4xelMpg{sV-8_Le5G>c=fs4(ZCX&-K6vCsjtON1cO21 zP8~U~Cz6aybRM{tHG;W%+}){5cj6j0)C~CM(x!J=reW| zvu)m~6W*M0#BH{kP25^`LdmnvaXG2V=T;I`vyW*{{UiQ>q;J%6s2HilSp*8F1SNS&~lTmVv-3Vl0rigYu3>>AZ{^wz_IZ*j=U5(7lMjdO^NyB-UE;DJPp3F5Xcj_xpp%DYVRC^6NzKgCG5tVu! zZvZM(_iZQsjo`IhtEIa7xUNHP4m!}NH5$AW<{WK226>uw*$G$*N+4cjmo7T4%a`aP zvdkYiJAJz>fi0N^AaPAp9oc?NCs1itqfRtpU>mfe)}O+~i|&ki^NV$4k1jf)V;~xD zI-{e=oq!FJ1bcMNaeWa$)Q(2a>qzW2U4C3o0tWq#L{IARuj#3jL%Wd%t@-&`1#oRevL(JfKJ-wY724SOt3g4l^PbV+s?82CA^fn^TMmNlf^HT}F!-N)=VN zp3`N!^hD~u5q9X9F4<+8#&r86hDoWt?m0c~q>h}>>JDA@ln|F>1R0JOdmBHdGRpOlCUqtr2OP9Wh+)jwHTYIth!}c!1lqSCLKoBVsJr37* z^Eo|{JY6#O6>2_;`Fe#>@J_ve(nd|4M1t2h8Tm}9Ur5u=i!RbNDzQ^vOc`>y28j_v z6@4BJckVRimKA+XS2kmo&xcuEjs8!986SrQz!IYu&;rey*flx_Ko+DcT4uzJz$g=H zJ}C@7Afhfiwp+*48n|RN* zswXffJ@p{2N}Y4hsZU{8B5M3OWWRj-ITb&)WbXyIpmT4khfT?^$wO-O>Fq@JrgKj1 z09vV!ee_)Hr}aR67t>QIIJ}6u;+Xn63iH(-B8GmKsJxx$^_6NTaY7yr@Ehv3ol8{C z&e!0hSMSt$yR~l6kwsSVi*?B|OiL0!a;>`g7}|xCan!xrV7b}Hz1ndq5gS(7v0*QU z_`%-Cqrc}0MHKHkQh3+V!T&)-5yTDw3H@fgO-Bsc7sL?ZK~L-o2*X*b$8UO~eom=A3rk#7KFy6?%N^F?cAl z!3OO$>q)=V-cp)e7+RV!s%9sGfFAIyY{6jT0a=ta6Ety|&D? z4l|?LZ=!6ASLb4?B*Ef}dyL#zwr4;-*f%kYs#QC6g_?UK1WSy;2obb)+5WRJa} z!Aa4AC*JVdky$YP&9`k% zGfx;~dWh@?y(V}LjNUhG0AT~>;Fm()h=K*n-;S!!dalmRM#yDG^SI91+oYbjy;1$W z+h_o|;lFb+xL6Nr7V9ab{@pe*!qUH6&oINX(_#oQnGovH+t2A*^-YYFQU&KU-miuT zQ$3;Mdvw+wJ=auf)HRJ3gli@YtslGaM@6*csCqKo_w6)mBLdeYJ5Ah_6}=Nirla@h zglT6;tdQzHqfJz%=3-WblDP`Sd(^>U$nxTC{U>r?oJl5EOyuALDg#7sleqlxXsYf)KCq8cT~F)ThQ&EO-^b}o8I_F`k&}+!rSsmaNC8^J8ZOjT*sfnh7BU`LL_z%$P@h8}+N6tH zpiBfgm586gY&?oekX9m1AuSga%owOrpiq04E^MHU7WPg6N)dMxDPoav;9eMgLzf~f z-nGX>e1+Hr=A)RRi`wOA>@!ejUeid6Y0%^L>Z?fHyL92T7HWnnAsAx~oNCh7nm!#v z@cXpJR%P0DUAPCE)lF<_4Z6TC8Eym5A{e2Vl`%97EU|!1MAa`T8o5>*y!r;_It>b~ zTE>YWzP- z*L6YmQ`p}w(eWm1k7xw1MHqUejxW^{Om@lQrDpHrMeDWu8|^#|<_J^cYV$emA64_L6Ry=0ND!yc<%Csp1#?e6x9u|oV9_lP}*o|Ou%7XMF$KUf#=HfFpt7$+ML z)?{t;lM(2cV-ZjUOGo+&<1ZtY#~%|F$sZG|OI)3uU1Y3xVxzvSQRf<8e<|#vQ9IGS zI*QnZHgUNKe990ol*0UTXrD&g{z8~XOy%!fwrrWY8Br5lc=I#M5QBUO=0hg9L+3u@ zSDS`v2t1;(1@xcJL9EY*2blY+|D4Xj!9|14x$x$j+EuwQ_t@EE{FfY!xT^EL9kL1x|!kuI%#&gf`+R1HCZ|TJ-pxx~zd> zs*3o<-Pz$9FD)VJ}*OYaJpM@_MvoQUBza;Du%smN9rs zg0Opk5@wAUC>HyOr9;p*4QONx1?0){>fpCXW7w@x0=crWM7wvQ>U!b|CZw>7N&OTy z>7x*BtJY7#C-pK&t3LG*r*1!l%cI>Oj<~*rPyu!V$EDPZK-+*` zSGVfYdhPw@yoNbfn{yvDLGi1L_SF42Lqy+xg#M^i=d`{+XB>|DTjw0Q7yC~L2j$ME zWzvihRwwUHEWERU%~Gvw^HCfHR7CI6)3@tfEL%j0UZ|Nkpi$Su+#2-sr*SxV8^v0f zZ4hZ3Str^X4v1;915on5SF zfX`x_*eKZSl-CWXtY~bDj-Y*mhPZNrtSldj_VK&z6L}Mw#d{n!EyEF?K_v~OVz&%3g@S4 z-!?kQHB8|4Q0;Y)=Bhsf4V^l{12S#`f@mPfZJ1^C4bo>+{RQO8R%fsg54fQ7`NGjU zQe43aM?SkEB-HOdLLDU-FGNO9txN`k;N%S*LqxL&W&7b&V(Ki^l0d+TV?zwmcrp?7 zucT08eT{k=QXEfizYq(jf#+4^8H#a~Iyg@IMRF zhC8h*)wAJ*(M<>p%X*47nlU^N#p3U5o_;VFgSI{L-c$od&JK-@5z29j?+O|;CXYGE{aatL zrI4^dZ6(vhkYWd4f-`n=!by5QhOluDISgm19!H4mr?j_>fRAby&%U12#n~#CRByHl zP-+bGIf^4Tc#9mYJkYcmubt-FL{}3&V~!aNtUTWUSbk|Q9&5FEH9*@fi^x?s!SaY| ziOzjeAZr<@pM(#N?bS(~BixCQ+Hk`T&7|n@UMxo2bPi}1>Bv(s5pu2O&@%sNSoOx8 zC{g2Z+_Z#SZp46?%5aeIv{#fmlHO0Xvo)+`hr7A)T)0M3*diP3y0dBgbh9*5@DXfT= z8$?*IXzWqT;S6%IG{1Kb?G*uF(pN4s2duQ0qJvhNOSor`P!2(ZqsmMhZ|EExO1(lG zgE)fyJ5hk(&Qjz6ud_?kR5&F^U4%s&(Wr~Ht3hMcqzRUd#W_cP0wazWFghTgp^n1B z(nQPMtt;;!_f&ZjG$&ziG>yEcy}5YMQ*DmTi!FG=c#!+!WCAmw&(QwhU7En3bQ_h< zi2m#LANahPu% z1h~7W7luVo`oML{AK73x>B1LcM51r%33uzfYjtul_PaQ0pRkB>h077iV|BO)_tvnW z?a`?QU4&5g8#=$9!utr$|6xVR=-u!Ppo_yrEk#rckiucyMZnVdfA{Jkbc@igymUF; zZAqvPV?n)(3>(p~ONIqUjty=y`!(vLhkILywy~ed&sJaG4*M)ur?5un<6a!y8Qe)H zu-2R7&H&D1)mMS1kYNs;QmF4E(!mWWY81GVIknO-$tWJNQU`?^;~@i*}|iA zMmPsDn0r+i1NA6;Gs+7U?i}K-a!KqX*1^{6g1vg?6S@J!a~pLECuy{t;rtdWBydx3 zPrVVxDcBj15cPDwBI|^XAiBn!rmz^AOd$}Thlfi+(4ecIfNp+_8Eh)3FJijps~;gx z#{|%o_3H*d19%%=L04(`EZhtu;UO@m#2SWp4^|26EU=MSWbO;nQ4h`_@)m2nE})2F z=sJ=aEmCbn%dhEiC(L0G<)$FYL~#jX(`iWSpeS0XX!iq)Ha#DigSScI-j=!rW2Ij^ zejYco)E93*1`GHZdKFclx}Ek39$rg=hYb)#s)OiG!D5Q{&9(r>Q4-yCTu)qL1_Oa& zH6q$Z1Pdf4-A_YBbH@#nf^sAr=qDp!0Rgr-KcIG~4X`o?zBmme!YH_tx<&`sWCbg{-wg?t>rA{W8&OBwDr&@j0w567{wx#mt;1h@6_pQ0O4#n@XcLWr=7 zg3yS{r_k)*oO9>()d<$@ZLHq_^(0_CRDc*CnZ>%Hrxh-YLjVa zfXM|gf2T&!JL4Dumz%rkH09nMoEuf2!AZv)^^=dnBmhJFoL#yGdtq=c!K|OWUB4IL zd@_Z*^?aI=lhwa`6#7<=c$n^!)k~;qCvu7Up1TugR;4)fQa@yLBl!R;Ej?{<6-51` zgltUf)E^7Ky%MZ%8c74$(sh`T#ght`;wb}Yj2;r03zNDO=bF3B48dbD--TMz-CxX* zPFAO&3Nup1Hs8(<(nB=r6@=IYcme=EPu+r{Y`}8_2t-?G^zVl~6sn(-*RbfQI$%)0 z2v7yhQ2#S%vrs+l!GSc8;S^xgp+0^)jRxBeIpG;7HjfCPqc~XlKD^@`7#53bRf7t~ zGl3AQ8H);LkwyhYfunDPZ&T!x0Z6Zvkxef`fcy8xXrF|>3k*EYbaAnnAa|pah=HQ& zx6tENn3!g}PYcF(ZpRjS*#3vpJ@tEfOsW72Sr<+T=rnf$vW>5o37HivN?y9A8|c z4`5~7LPoel(Tn_q8R+u*%k1l@6p(JK9QS_JRfa<^6I)Q}kX z;XMfECr`1_S7zw9HfMbPXS`2G?vFkY`ybh#$oXXQK>mY;pDO-~(ueS9FrG)H3x4Te z*`R!r)WdUx^n1H@@fe@~Q3(Fq=XY$Ec(tpw${@$#L@Ssb7sVkvGPr@ht4X#w)md*$IA4`71p9KGf_;XGA$+(c7 z2%r8MPAY$=aV2@FUdw!<#u0{1oW(4Uls`V-7G#!7yXo&%B+4<{HP+-fGeAS_roWny z>a}O+;gf8i(oXuD{D^){CVht8O1%db5jAWHdk*@IDIeRr$d~?(IjWaAPMPwhzuWDP zX(#66+W%^wkdeq~p`y+(LMfGyU}%g!koSJrm#2^hNbgVn-~y zVS42R{rvjuhlDQubq7Qz{kfmp5xVpj7KHf0ADQ`pcGLg7p6EjJ0d`9GIrv9%rvK?T z;or$lM4t3N6sCH<+-Y_^ntn)cr}4m!thbL-W&B3{P%=MM{&wdseH#aRX06-OKhQm^ zySEqrwp>h)kk8t@smuQiF_88v%Dr1QbeXRXuWRbruztAD*|K4C|N0F*-KnlVe2}xF zgFeSPw`15@x6uD!ZyO%9an=nk7{-@L*KHZ@+3ei9uxGfltFH}DoiE!m9Pq%mLN^UF zlS?iKms{I5b#B<)+p}p!|A)b&t9#+KD_8Yw+T6c!gWRp{up;@b;ai`ZH*6Vn@F`)AI+vEVdbZrj$Mn&AGI1IFBec`n8x5Uv##p{$Bb{ zwfz8dI)=VnJv!F(&64uxoYOO=HS>Y%zRt}ZotxGhMbRg(Ny(d`Bs$A-mM&XZ-_g9R zx!yvn>RVSdENixzriK-57Ft-}w&0q@7GBxXv~0mb#xJ|BImorvuc&Y9SkbohJ(oJo z%Q{x9y!P6LcBi?%e&GtqEM2hr1ND;Oug7lcxtYjYTI&OH&RBBJ*bm5d5P4I>2Uf25 z0Qg*UP5p`$lC5uTUDn#suq-3rylO#H!@`c11+5E~jx1U*N_9xGuzpp;HT5G&o0qk9 zT)S*#^TLs6h_QMkrmbOV{j!y9BazFX*K3=WT{jZj($JF8N<(uSIgH?Gs+$6%i4oPAILu|~g64*6>sLVf5FaTT$z8A=*DYvh>u7~lj%dhQWJkCm zV-V&@*L+6Vsc&7dq8^5@2-dz}#flD-cUtQgEbLg>+|s(Nt^S%e`#g#NrEB|TX`WyB z2D4*6fz2PB_CJr_wQ&HGD*PFG90PZ5!34G+rQg&;Zo9i@6MyDhJ`6wFH|~kj>7&om zW9oL%E%B(a=LH5ru7mmw_><+cnh5Ott}e|258yXh-JfI@yY2G z_KVlVz`)K zexCjm3VG0PpbC_wubMl(-B>Gzp{-%3+gy6^ZFX*N)0PdUn)T?8WX0W+Wc=tgz>II+ zr(x`e0xRl{6<885h2wZKdy4 zrR18X`UR~W*Vdz~)%ROcNS^;~iWV$fh}9v)k{VlBzv7zKhL*Nvt(l?_&#_CX?lsGr zuWeYgvUNclEm|2pq3Ul-Kpc$6y>>z1?$bLob|D%JsT~U`xUtNem+o$j|z0+qa3k+XPq!z(2Z#i z#ojt1faI3ox1DvZJ-wjlgI~IBLsy^B!+&k+ghR!(W5CADp*a?4k&F68Pw5)ouw}3V zQ69XI>2W5h42`vo^om>HP%vP9&JYa@c=wu%87>nxV%W%23~t2Vy7pq_Nv}*p+%eD( z)1wP@0la`RQ6c)NDkFh@)tCl>)p5sn+OXJ^mN`L@Rkh_d>C?a*&t?LN6)6t%|al9 z-U;aqzPp3kmWeNZq-}Kz0^YU-%?lT_`a#`@!fToki;P-rRekfquv;`7Db{XXg)osv zg#CyeKHm{u)6mjTk40f*MB7>~_)#336rpLepag=widie~H( z+8AtPSVZeQoSz@lSxVbRhgnsF)<+1+Bt5p-fGC|o8rF6gF6P#ao4Uzf$=4#L+B`gj z@WxoCzkDNFGm#`FrP;^Xb}=Cb`-c(dz|4Yv_inKPmjeUG%;U_uYl$=KVg(Gh+gaCU z2rzvH$r8J7ZC=MJ+w5>B`g%Gk0JS~9Kwt`Wb|W6-8M2}0)(+_|ZG!!baUVhjf7l~c ztPkPPw`XwUrrTsbl0!0H0x>fJDQ9z6CnkQkeTKruc7q6x`-cYlArXQyEH|5xf>$T4 zJdhF6;o3n#7|n2kZD?kc25$mH=Q=uEAc(w@EyiI%FCs1SUueM;+ThuOX|~xB40s1T zTqmM48CG?diISNjbyB8+&_c zE3*lv%R%yBKUM|A_m(jYGfCm+IyWP(wYwK)F)-9+*nFdgQ?rr>TE8I-*> zW{=`$;8NghhWVwJrt-cImzl|2Z*2bf_;XpsS@jyS%xsPuz*gRcD z9{L6Z{ghMS9F&aQEd$a$Xv>4E)I7r|Q&TeUs^)Wk&3xyeWbl?{^HWZ~J}8-o17zf& zWM1a8U{FR6N`~H@OFtmhLCFNtbd^oC{np~d|SUhq*}_$+|=Nsmy`B7*CF z1|Q+njEiKXo^tLzv^}U}p~H-bu(n~YG5}ix)NTg%2dF~~z7U{ZVi122Y<}R?&R}doY>FXc#bDaSZl0L1%C;|I?)OrC2eAK`;29Nlt^_D|$eU>FSakH}50(4`+x76`6eS-8WTYNr6N zK0YYfBfjh{0tVBwV0*|>iHfB@+<8hWp742v>`sbi`wH%nZfp%ufz%c{!we%#!m>*? z->(^(9_KS^l9(|j52}U4lp;x8=R=t?jbczT3P*f-Le|s5Mbc>)tJI44V>gi5)^4u# z0H@Ro`t%9?9^n+`V-dks$b}SsNx-)q+gF(7`LyOPFzonJhME)dfFv{=QiL~gn%^jT zUBg8KoT9ID`*_V4<1MV3Ut(f0@BEJ}M;VNfsusj8PV4`o<9bUJN9UvBddll3ODG z+Q&r$oRazag$$fveV^oXG@7?q6ZDlh`i(}D&rwh@r=!tGge2h+mNkixBs>CY8;_|3 zK0rzABY_W4R+8ZQ3Y+MwoMP03!2@F($y-bv2?q8drlv2q(T^-5<0sTPTx+zx=5tw@ z&$;~wbEH?0({B{dVGHbcjx0$_9pesg>f(fJj9;x!vRuHRR^J$v{HNnwrz(ObJFYjyEt$= z;0JK)g<4W+H7#5fu+9$_x?g4Re1H-Lk_w~Kep|~03>fu<8TAMQNrlnNKBHCvQ-1SZ z!iYZROutd)!g*#8H2+P3EP803rW!$ zpQL3igNFjtQ3g*1s2q+f$~eXBY++CWEuh|Flmse3Nkmc1>nTtv25SRUH-oZVW81X- zpky8n=w$JKJV0f3v5ke6e!)rPA7-3%jBpECR_O-e&N5E=LAXr*k1#Lc37Sk2=Q-x{ z0;i+Vyvk+L=4dp+Sf(+QCn!l%3KnI8~Wo zcd^A_=ngS>IzTtP1pW(vy@$XssLjD=(t`|4ZGg8IoCE*c8z#ScnGPEK4W zRPPYe+i%g3o_b`vA1JunZ-#+qxt4f+Bc){Im|~RHidkdg+)*!nP%`s;b%vze&qd;u zVP^-nOXjR!ujM?0jz0|TVmY$&H&rDgV?<`fV>R0-g-01Qb((T(5BHg@8)H9Dj_vxNCkgz|bL1!RS1L z0q?#)jrTTYw2xDG-PnGHAL0}XOgjtQ$0?BwFuc|8OuNVsbS4y}NYNa>zae80l3Jf+ zxq!h8x?aG*NAb7wSZXA~DCIM16>zSPY8NnI#Ge@qGYUxP?|Vl47Ba)3fbocOWTfbT zPZH|7klf{yEEn*QkGfvKhkaD2>%wTaPtq#jLq4iqz<^Px>%u4?33dGuX82;jIJ4_g z6u7Mx0q6R@r@M()xBdPq*F6@axBRx23m8P4Jz+*YV=K*&Ufnfj1lYk4MPImVO-6|L)ol1URO9PYft zOam2kuVqn0v{77l4i8~at36yRxJ}Vs|DdVI+rht`i<2mi|S*7p(#Y=XN2L z3FCkyG#URiiC<&XnaGps5Rdj__(UqwRp)O;sjW)E&OJJ^J^ z3K;P22{Y;$i_vUf$Q1$xq1pN{qxG4LL`QAR$apWwNVJD&NkCy~?qs+JB^&6oFSCVt z%sJ>_ceqw)Uj1pcc5qvVIK{M{$0Ob3k9f$=mDQmn}7kM?l7Z} ztq(B+sqH$WG0Nwg2Thz}NBS;!Kg7Hb`$D!{U@&0R@(2&$_j5ZzhkF(> zlL7xG=z0-BSdH@B#9?M6H`x&CY-I)y`HcFc>j9&XC7otQ7kmx$3MfL37V4d6@*~`s z>8)f=_!5Mg+s!xp&iFU}1~Rq#T!|x4^n1i_sJEC$xt7yWwhoI!wYtK!LK6RJ zwM64-_elkOnKwrmvR4`0T44J#O28_N9`gIOT)==)cbHMg(FmghKBHCvPx}(}gc*gD zFN_ZRj6zerm>Is}GhScDU99uFx_%9VLGMHE=)a6niX|ELB?|RxUWgBOksQR)S)_uj=U-nQNvChGRv3#nR20@k6C50iw9+?pRg)5icpYXN8bsIG+!E)Gx( zg%a_!o^!J!uyFF6-A*Pe!e#zs*Sv!ZAXFxa6zv>7EsPY;c|Cy z=_~#TRgWAj$w?Kc@_!b#UorQx_aKaq26(IeC#%?G!mTBP-( zECohXPMXgID3M1_M?odxh$ujbG@>M+1QcyU2mvDzD=MgbnHi|#mIK9)GF;u6wMJ2L zogA$O7BdjG82`!8Ayy}aFAPdIUFUk~sdN(qQI{!$Xn4M_yN#J7qm28EQO147{tOAw z+>Cd@E47$yr^%lr?QIOU2dGh6OdaOpQ$AVmJQgC*%nCUq75T6)67UF9L)6r}5Vdv` zA!=pB9`}W4pBoaQRfO2aMc9svB1CPb5OR0vJP(h#Q!kl0Y>+_qgdSrRu|!A88Mr?p znWHRgjF9(7dhd@2<^-3-spLbZNKnsmQEpIlU(Wq3Lm>G7wT4B67z3CT0#^B`)dI>) zz+PG^W~S0Lgzo~%I)vd9Fklo~Sfyx=-~4g`7y78{1r)C`ibTR_wqL7Nz$PEHTEKu& z=vI(0l8K471YGPhY8NnI6gmNxqBVZ4Z3x+7DnwpNvnXvK5Dgq0i#gY zgpss>t_e8gGinzwU=-?_6dmwuwFnq2P2F7RCsJ#lUu(I5L9H&IoPp;!t@7Qkbi=2V zqLfdvT);U#s$Iaqk4xu$Mp7itNsO|N2}z63c)5VV($+3uz$nz#Ff-WUGYa)f*7SWo z$#MY?`KWdQ5BsQ4TXNs~1)n6egh|m$K1s`I244+OzNQ#B%S932v$qI%(noc@z@Xgw z8)X9)W0E?*R!AFCG&>+^VNjel#!K3IDWH0p!B+#+Sq6g;Gt}G+CQ0juFnXJQj3SZL z`s13HwNh3ctiPGc_w&UJq5A>`W7hRnXpBO0OgN={M#}{Z7a)`l3Z4>MYSBs2u;eUoOOFT|)XT&pj$)&pEip5H*kd6L_Dk<(Fb zX~=^eXZ+r`h|c6D<|xblt4tk?N4xAT zCeQ`$NAN&GyEHe$Z>~MeyFJWXJi0&n|DC*Nuuo|5eM5_Y+x%Nc-4FBGdGM!L-4366 z%bEEoH&lf88lU%a0R!GWVctDq-XRYnyyf0G)?EP)`_1*rP10@tjm+L~bD>!-3K-y8 zBaK+Fb93wfWjXn;eB;cI^g%)F@b5wNonlZrgl8iBQDtC&rG3^H@uskdHwl9>|IWls z|34$rKwy#YMn?~^vSkcuJXoWFWoaS`i z*4-lDJpXP`*L(&S2dGSOb})nBBTJm%Z{9Dz==xDdn9YXpI=D(d9Gz%5BzV`oV?NT z0W?H1nYYXQ9mvcZiDy{O_N6?|^QhqWg1ilP3v`yd^s5B3@MA!wu%7D`mv|q()wGw2k)qN-(sZ}~g7)z^n82NlP z_WO++HQqwPi6MQEMKC3w%WOq-dL2=X(CG_c;*Z4+6dO%XV>=){*+AhJM$zZs4c>$` zzKDOmqUH5;R7ngh{F2S*QAH^KExkJH{jY)J+A_hO2g5+w|3L&YB|e2B()`m%Me|P( zESP4E;yZzM&`xDCAv`>7sz6^H1ox z=lo)v<9rrN%#HZx4>pe$J$aHgk?u~HgT`f2pgVa#o_Q4^ZFFS3_M;Nf_JbC@(p+Q~ zxCfTaRZNHJwL`uUG-HV*A&g)AF}RriwWf>9o-ij6C+M^P{?~h~0PIOupuNEA76mn> zBf*RQCc++gc!x>Kk;X@Vq&H$HoHs!~mZ>a+Hqu_ySO^tZDa<<2?+azra0&Y8&)T0s zM89dHf=^_&EJlDf99pG3=bp)qvjHYSA3INLc5ON@8k}q(DD4&VAr|)m={Xms;*$c{ z3qFc}zJ0L5ZvhqeeH4Y?&eMY3@RR8b*ub6z&L3!er90>$Npm?6!5G~eG$vzYjBPqq z13A65|1!`}O%2uXkbN~=Eg0I9G*lzU^T((<*68)2sgYy7!WYqu*kYE&WWE&mk&%;h z0Z~b-W+?B49{iE+gTw~=eE`&pz(3z)hUD3q_=*TN$N0`5^uuG3Z!-K+XvX~p3>YK} z@Q07J|6Sll%JDEnwi-7*c#U*7`djg{9H4oFD9yEv7DP&tN_o8@wFC+BW*aAa!-S1FfcwTGZH`pLcg$2ot3Q(GEb z<0O-4`(JEna2>)tqTj2W z=I{|xK0-(O4e+i|o^_TdBVXY5%Xo{F;&cY5vYX0$64Y`HuJTa1JmW48g3BKE1(rkJ zO%v3#kUSDj3n2Xtuw1e)lV|I6cAXe%7Dp@d)Q1=d_C3O>sJd)7hNv;Pfs|U*z;Or}DQ}O>DPv_)MJ{m!w?I$|G3IsZ=M|6et}E!>YIoNhxT zLBIW++FWow!*nuFGyi%tptMjK&*K!Qb)3o_j3Lg;JkP8ze`stl$Xt3G|b{i;#Dconic|oJM%vkUvAPwSudx zw{mzZr-kxI55v6PY~}PVPUX4$fD=PpF6(!S^L3og;8YGOGwZ)oy*XTeE~g@={1HGV zzZCa>E~i^Lm0Jt)*9fwnXV#Z9*EL*kEvK>`4{&}cgYRz6XYxD1_(wQB%<0iF=w;nK z!v5?8rxM?t;rv+suA9sII33`08>bRKKEU}*d3UqF5Wh(WS@b)=Y35y1TN+%SWx7+G z%8kDqo@W82g@j(>2bs@ubNHR=iywN3{gT9=bUs4A$2pbzofaEh2e@2rdWxLl9|B4X z37!1Sw)iWD{Zu}uyE)CQpIJ{{rzp2P<+f@I`?JiOoSFQNuwGAaDz{U*+0XQGD);kb z-pj3!On$F0pE2uaR1iNnCOyyFvD%Zkn9k_w_Y$XPIQ9Q}lKrIc8OxuH#qV?mzqdG_ zlW~{GN)cRlGo9RfdZ+dWSWbD%w%iGlxL)SHe}6M*%0N62Uf?u`*NtLMXK>oi=^9S&;&dOUi`jpPzii{Y^y|zR{w=e;dCc!mZ7;LG z@5Cq5Z~Jnxoo4bo%6gLZL;5H4D3ku3@(LUN=Q!3)r&W&U$U~GP@yeOcK58UB;>e%Z zj>K!{fAgMoBtGicuYRUu>6P{W8yF!utP!!H4Z{mm;5G7R$95Kw9?ltBXeR>T$?%{E?<6h}xH0#)LuW(v9wi8}!4FLPJiWM|J z^NfY>!#>IYGLCH-csq{aak1k#-jSF>xY_2)o!@5k*N$VExy>)Ml-hAj`EPlXG8xCC zJYItT9DuhQm*EWgZS@-GO5U>wA3H8#J=<}?e94gCj!T6ziDL%gv(^9!XXqn>v8kOe zVZB*Bk9WSAKa$?+x!n0B+nGx}x6F&uB$aV&Q3%7_QV@AYNaq4>R%J4d!_$1!Xt z;`hE+GLqhoW4ZGW8F8bGwC5deOIr^h76 z_E%y3*zv7!Vj1?i)^Hu~lrJ=Zf3f;6cc$~%iWFG=mzl>I1V^dWe>F}5M*gh+$2pxD z>$25$i)2W#<0lk-ufhf6O5# zVZ7sAGXcRnBZ4*@^j~n`v<8LkcGL)1#x)&V4*Kso@E0BUPZ{rc8y_=r_nE}I;-IHB zM3d}!UF6Ju*a*l(&fgsLH-%pBd-a`r=M9tP?`6E>?fR$@{G`Y~4BWbvMq=_=F+UcSyHkfJ|!F-HdmvFYPw$#&ygy})_iqb+&cZJ_<582Y%9lf69T= zTGUB;KFxT?)8CK##CXpE-|dZ`)2e;8flsn0t+k=}qx1d?BIk7`oN^E!m z5O&i#T*VjCO>yiW0D*sChR-H{knvsWp+*kd5B$fM8bPuP-Z@G zUx(d{YuWLcdcQmBF>U+X^?nvsbwlPTrkw)gZ^8!;ojyMI@X~@899w>5er`EE5aB^9rdxrFpQEQ%<3S`<77k7Dk;-2 zqb-Iz0NqG>=tNkRhM}*7`CPJ zeo1VoL{VLgvZko$CXGf?Q}OyzLWGFKy4H&WMV^0ArF3JYdsevjg@8ZltyBD=Hx@ z91hVRBz+b3lAS$tDaIUzB~*oD7v-kLN&Ej661dm8?>C1k@n53#-9<)l3DZDX?X=D3Y=&NzQ6M?b2o=7A1{l zNuoXZuqe8Q9acrjT1jEcP;DN9U+)k`8Np3+$^2Dal!$Dp2_$Ml=}Zue{VwW{^0QtZ z=0%kyiTZvJbP?}N3||}@iK(GFg{2-dC*CV@T$hC zT8%?XsIpIw((w#>yLV&?6l=RXK9xD-Cp=?DF@-__MmfJBI zo0*24=~ZZpIMw6G*60FTMewP#7KBEWWW|iF=!5=&fiV5&tq?1EwCd6ButEy;yo^=7 zL1@Pkn(S!ChBrkUp@h(#s&Joso?mSaFo`3@q`_%la~!gUp5G6vzURlAIY>=fm!7|x zk9_o1l@|GqivVR9Um-C_ZkW}c&;Q84M_i*$_H*2h_~?nUNMk>ZX)^KADP%m%>1DX- z`RzPBFIAibPz{j9+Ju8Nf(Dq5>Ev@|rV@k&&!;(s#q-1(3`bpaE90B%H1ClZnsgCb zyJfPbS6P}Tn(vilOd*4PG>ge!vx6{d%R)W0n-B^Z*|?3sU~Juj|6f^pJw><9@;I$o z&-aqtPv31x7q~(1K@N`y8vbiSpy?+>u>9<3-W%xet9!vqOANIBSt-!;dHfEdgJ6<@ z+jTzl_wfN-5w85Yj!@HETCri{wn~?x_U6-io zwD6PuWE$09V2^&*P?^fp^^2P7C$6-9<=6Jp<0Imq#~&TK&Qa5AREUH4--o&hWU(NFs|uOWVIzpk&;bZe#|<&4&^=sGgw zBFeAp*)&xP4!nfFM+IG zzrMHH^DV=F(Im}T`89pn;@9=5mxcd_QojmNK23jR@#{L)jb{wUv^GoxD4)vv4Kjo& znLZaff6-73l~7Wf|2l9|amJ!ket8|$lxlM{{j=~l1d{os)c<)Mn1U;x(*Fk;8>6z1 zf7ejF%X$xO)7}BV#)z~2gW=aT^5*LGw0Al9J=$%LZ z{0D{q%hr2oo4@Pezx24Fyg|XGb=ds$Zbf~+MdrP-Z77EpgLTQiqp`Qm|NJ>aIVI~X f?m^*;_)~jmT*hOziS=Kme}jYL?L^Qz?E3!;B5e#U diff --git a/panda/board/tools/dfu-util-aarch64-linux b/panda/board/tools/dfu-util-aarch64-linux deleted file mode 100755 index b366f869ace1cdd2f8f742dc5c639e672c39ccb4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 159256 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 )<{|LvBdVd!e>g7+GYxQ}{-}0bY{>mb~{JwL_ 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 diff --git a/panda/board/tools/dfu-util-x86_64-linux b/panda/board/tools/dfu-util-x86_64-linux deleted file mode 100755 index 7be3dc3a7ef682b46a30e6852993a40999780cea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 152156 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%0DT)N%n)n--o!*l}Rs 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 obj/cert.h - -include ../common/version.mk - -obj/sha.o: ../crypto/sha.c - $(CC) $(CFLAGS) -c $^ -o $@ - -obj/rsa.o: ../crypto/rsa.c - $(CC) $(CFLAGS) -c $^ -o $@ - -oldflash: proxy-0x00000.bin - ../python/esptool.py write_flash 0 proxy-0x00000.bin 0x40000 proxy-0x40000.bin - -user1.bin: obj/proxy.o obj/elm327.o obj/webserver.o obj/sha.o obj/rsa.o - $(CC) $(CFLAGS) $^ -o a.out -L$(SDK_BASE)/ld -T$(SDK_BASE)/ld/eagle.app.v6.new.1024.app1.ld $(LDLIBS) - $(OBJCP) --only-section .text -O binary a.out eagle.app.v6.text.bin - $(OBJCP) --only-section .data -O binary a.out eagle.app.v6.data.bin - $(OBJCP) --only-section .rodata -O binary a.out eagle.app.v6.rodata.bin - $(OBJCP) --only-section .irom0.text -O binary a.out eagle.app.v6.irom0text.bin - COMPILE=gcc python2 ./esp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20/tools/gen_appbin.py a.out 2 0 32 4 0 - rm -f eagle.app.v6.*.bin - mv eagle.app.flash.bin $@ - ../crypto/sign.py $@ $@ $(CERT) - -user2.bin: obj/proxy.o obj/elm327.o obj/webserver.o obj/sha.o obj/rsa.o - $(CC) $(CFLAGS) $^ -o a.out -L$(SDK_BASE)/ld -T$(SDK_BASE)/ld/eagle.app.v6.new.1024.app2.ld $(LDLIBS) - $(OBJCP) --only-section .text -O binary a.out eagle.app.v6.text.bin - $(OBJCP) --only-section .data -O binary a.out eagle.app.v6.data.bin - $(OBJCP) --only-section .rodata -O binary a.out eagle.app.v6.rodata.bin - $(OBJCP) --only-section .irom0.text -O binary a.out eagle.app.v6.irom0text.bin - COMPILE=gcc python2 ./esp-open-sdk/ESP8266_NONOS_SDK_V1.5.4_16_05_20/tools/gen_appbin.py a.out 2 0 32 4 0 - rm -f eagle.app.v6.*.bin - mv eagle.app.flash.bin $@ - ../crypto/sign.py $@ $@ $(CERT) - -ota: user1.bin user2.bin - curl http://192.168.0.10/espupdate1 --upload-file user1.bin - curl http://192.168.0.10/espupdate2 --upload-file user2.bin - -clean: - rm -f proxy proxy.o proxy-0x00000.bin proxy-0x40000.bin eagle.app.* user1.bin user2.bin a.out obj/* diff --git a/panda/boardesp/README.md b/panda/boardesp/README.md deleted file mode 100644 index 5a8fab1477..0000000000 --- a/panda/boardesp/README.md +++ /dev/null @@ -1,22 +0,0 @@ - -Dependencies ------ - -**Debian / Ubuntu** - -``` -./get_sdk.sh -``` - -**Mac** - -``` -./get_sdk_mac.sh -``` - -Programming ------ - -``` -make -``` diff --git a/panda/boardesp/elm327.c b/panda/boardesp/elm327.c deleted file mode 100644 index cec9fd836d..0000000000 --- a/panda/boardesp/elm327.c +++ /dev/null @@ -1,1578 +0,0 @@ -#include "ets_sys.h" -#include "osapi.h" -#include "gpio.h" -#include "os_type.h" -#include "user_interface.h" -#include "espconn.h" -#include "mem.h" - -#include "driver/uart.h" - -//#define ELM_DEBUG - -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -int ICACHE_FLASH_ATTR spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen); - -#define ELM_PORT 35000 - -//Version 1.5 is an invalid version used by many pirate clones -//that only partially support 1.0. -#define IDENT_MSG "ELM327 v1.5\r\r" -#define DEVICE_DESC "Panda\n\n" - -#define SHOW_CONNECTION(msg, p_conn) os_printf("%s %p, proto %p, %d.%d.%d.%d:%d disconnect\r\n", \ - msg, p_conn, (p_conn)->proto.tcp, (p_conn)->proto.tcp->remote_ip[0], \ - (p_conn)->proto.tcp->remote_ip[1], (p_conn)->proto.tcp->remote_ip[2], \ - (p_conn)->proto.tcp->remote_ip[3], (p_conn)->proto.tcp->remote_port) - -const static char hex_lookup[] = {'0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; - -typedef struct __attribute__((packed)) { - bool tx : 1; - bool : 1; - bool ext : 1; - uint32_t addr : 29; - - uint8_t len : 4; - uint8_t bus : 8; - uint8_t : 4; //unused - uint16_t ts : 16; - uint8_t data[8]; -} panda_can_msg_t; - -//TODO: Masking is likely unnecessary for these bit fields. Check. -#define panda_get_can_addr(recv) (((recv)->ext) ? ((recv)->addr & 0x1FFFFFFF) :\ - (((recv)->addr >> 18) & 0x7FF)) - -#define PANDA_CAN_FLAG_TRANSMIT 1 -#define PANDA_CAN_FLAG_EXTENDED 4 - -#define PANDA_USB_CAN_WRITE_BUS_NUM 3 -#define PANDA_USB_LIN_WRITE_BUS_NUM 2 - -#define SAFETY_ELM327 3U - -typedef struct _elm_tcp_conn { - struct espconn *conn; - struct _elm_tcp_conn *next; -} elm_tcp_conn_t; - -typedef struct __attribute__((packed)) { - uint8_t len; - uint8_t dat[7]; //mode and data -} elm_can_obd_msg; - -typedef struct __attribute__((packed)) { - uint8_t priority; - uint8_t receiver; - uint8_t sender; - - uint8_t dat[8]; //mode, data, and checksum -} elm_lin_obd_msg; - -typedef struct __attribute__((packed)) { - uint16_t usb_ep_num; - uint16_t payload_len; - - uint8_t serial_port; - //uint8_t msg[8+3]; - elm_lin_obd_msg msg; -} elm_lin_usb_msg; - -static struct espconn elm_conn; -static esp_tcp elm_proto; -static elm_tcp_conn_t *connection_list = NULL; - -static char stripped_msg[0x100]; -static uint16 stripped_msg_len = 0; - -static char in_msg[0x100]; -static uint16 in_msg_len = 0; - -static char rsp_buff[536]; //TCP min MTU -static uint16 rsp_buff_len = 0; - -static uint8_t pandaSendData[0x14] = {0}; -static uint32_t pandaRecvData[0x40] = {0}; -static uint32_t pandaRecvDataDummy[0x40] = {0}; // Used for CAN write operations (no received data) - -#define ELM_MODE_SELECTED_PROTOCOL_DEFAULT 6 -#define ELM_MODE_TIMEOUT_DEFAULT 20; -#define ELM_MODE_KEEPALIVE_PERIOD_DEFAULT (0x92*20) - -static bool elm_mode_echo = true; -static bool elm_mode_linefeed = false; -static bool elm_mode_additional_headers = false; -static bool elm_mode_auto_protocol = true; -static uint8_t elm_selected_protocol = ELM_MODE_SELECTED_PROTOCOL_DEFAULT; -static bool elm_mode_print_spaces = true; -static uint8_t elm_mode_adaptive_timing = 1; -static bool elm_mode_allow_long = false; -static uint16_t elm_mode_timeout = ELM_MODE_TIMEOUT_DEFAULT; -static uint16_t elm_mode_keepalive_period = ELM_MODE_KEEPALIVE_PERIOD_DEFAULT; - -bool lin_bus_initialized = false; - -/*********************************************** - *** ELM CLI response functions *** - *** (for sending data back to the terminal) *** - ***********************************************/ - -// All ELM operations are global, so send data out to all connections -void ICACHE_FLASH_ATTR elm_tcp_tx_flush() { - if(!rsp_buff_len) return; // Was causing small error messages - - for(elm_tcp_conn_t *iter = connection_list; iter != NULL; iter = iter->next){ - int8_t err = espconn_send(iter->conn, rsp_buff, rsp_buff_len); - if(err){ - os_printf(" Wifi %p TX error code %d\n", iter->conn, err); - if(err == ESPCONN_ARG) { - if(iter == connection_list) { - connection_list = iter->next; - } else { - for(elm_tcp_conn_t *iter2 = connection_list; iter2 != NULL; iter2 = iter2->next) - if(iter2->next == iter) { - iter2->next = iter->next; - break; - } - } - os_printf(" deleting orphaned connection. iter: %p; conn: %p\n", iter, iter->conn); - os_free(iter); - } - } - } - rsp_buff_len = 0; -} - -static void ICACHE_FLASH_ATTR elm_append_rsp(const char *data, uint16_t len) { - uint16_t overflow_len = 0; - if(rsp_buff_len + len > sizeof(rsp_buff)) { - overflow_len = rsp_buff_len + len - sizeof(rsp_buff); - len = sizeof(rsp_buff) - rsp_buff_len; - } - if(!elm_mode_linefeed) { - memcpy(rsp_buff + rsp_buff_len, data, len); - rsp_buff_len += len; - } else { - for(int i=0; i < len && rsp_buff_len < sizeof(rsp_buff); i++){ - rsp_buff[rsp_buff_len++] = data[i]; - if(data[i] == '\r' && rsp_buff_len < sizeof(rsp_buff)) - rsp_buff[rsp_buff_len++] = '\n'; - } - } - if(overflow_len) { - os_printf("Packet full, sending\n"); - elm_tcp_tx_flush(); - elm_append_rsp(data + len, overflow_len); - } -} - -#define elm_append_rsp_const(str) elm_append_rsp(str, sizeof(str)-1) - -static void ICACHE_FLASH_ATTR elm_append_rsp_hex_byte(uint8_t num) { - elm_append_rsp(&hex_lookup[num >> 4], 1); - elm_append_rsp(&hex_lookup[num & 0xF], 1); - if(elm_mode_print_spaces) elm_append_rsp_const(" "); -} - -void ICACHE_FLASH_ATTR elm_append_rsp_can_msg_addr(const panda_can_msg_t *recv) { - //Show address - uint32_t addr = panda_get_can_addr(recv); - if(recv->ext){ - elm_append_rsp_hex_byte(addr>>24); - elm_append_rsp_hex_byte(addr>>16); - elm_append_rsp_hex_byte(addr>>8); - elm_append_rsp_hex_byte(addr); - } else { - elm_append_rsp(&hex_lookup[addr>>8], 1); - elm_append_rsp_hex_byte(addr); - } -} - -/*************************************** - *** Panda communication functions *** - *** (for controlling the Panda MCU) *** - ***************************************/ - -static int ICACHE_FLASH_ATTR panda_usbemu_ctrl_write(uint8_t request_type, uint8_t request, - uint16_t value, uint16_t index, uint16_t length) { - //self.sock.send(struct.pack("HHBBHHH", 0, 0, request_type, request, value, index, length)); - *(uint16_t*)(pandaSendData) = 0; - *(uint16_t*)(pandaSendData+2) = 0; - pandaSendData[4] = request_type; - pandaSendData[5] = request; - *(uint16_t*)(pandaSendData+6) = value; - *(uint16_t*)(pandaSendData+8) = index; - *(uint16_t*)(pandaSendData+10) = length; - - int returned_count = spi_comm(pandaSendData, 0x10, pandaRecvData, 0x40); - if(returned_count > 0x40 || returned_count < 0) - return -1; - return returned_count; -} - -#define panda_set_can0_cbaud(cbps) panda_usbemu_ctrl_write(0x40, 0xde, 0, cbps, 0) -#define panda_set_can0_kbaud(kbps) panda_usbemu_ctrl_write(0x40, 0xde, 0, kbps*10, 0) -#define panda_set_safety_mode(mode) panda_usbemu_ctrl_write(0x40, 0xdc, mode, 0, 0) -#define panda_kline_wakeup_pulse() panda_usbemu_ctrl_write(0x40, 0xf0, 0, 0, 0) -#define panda_clear_can_rx() panda_usbemu_ctrl_write(0x40, 0xf1, 0xFFFF, 0, 0) -#define panda_clear_lin_txrx() panda_usbemu_ctrl_write(0x40, 0xf2, 2, 0, 0) - -static int ICACHE_FLASH_ATTR panda_usbemu_can_read(panda_can_msg_t** can_msgs) { - int returned_count = spi_comm((uint8_t *)((const uint16 []){1,0}), 4, pandaRecvData, 0x40); - if(returned_count > 0x40 || returned_count < 0){ - os_printf("CAN read got invalid length\n"); - return -1; - } - *can_msgs = (panda_can_msg_t*)(pandaRecvData+1); - return returned_count/sizeof(panda_can_msg_t); -} - -static int ICACHE_FLASH_ATTR panda_usbemu_can_write(bool ext, uint32_t addr, - char *candata, uint8_t canlen) { - uint32_t rir; - - if(canlen > 8) return 0; - - if(ext || addr >= 0x800){ - rir = (addr << 3) | PANDA_CAN_FLAG_TRANSMIT | PANDA_CAN_FLAG_EXTENDED; - }else{ - rir = (addr << 21) | PANDA_CAN_FLAG_TRANSMIT; - } - - #define MAX_CAN_LEN 8 - - //Wifi USB Wrapper - *(uint16_t*)(pandaSendData) = PANDA_USB_CAN_WRITE_BUS_NUM; //USB Bulk Endpoint ID. - *(uint16_t*)(pandaSendData+2) = MAX_CAN_LEN; - //BULK MESSAGE - *(uint32_t*)(pandaSendData+4) = rir; - *(uint32_t*)(pandaSendData+8) = MAX_CAN_LEN | (0 << 4); //0 is CAN bus number. - //CAN DATA - memcpy(pandaSendData+12, candata, canlen); - memset(pandaSendData+12+canlen, 0, MAX_CAN_LEN-canlen); - for(int i = 12+canlen; i < 20; i++) pandaSendData[i] = 0; //Zero the rest - - /* spi_comm will erase data in the recv buffer even if you are only - * interested in sending data that gets no response (like writing - * can data). This behavior becomes problematic when trying to send - * a can message while processsing received can messages. A dummy - * recv buffer is used here so received data is not overwritten. */ - int returned_count = spi_comm(pandaSendData, 0x14, pandaRecvDataDummy, 0x40); - if(returned_count) - os_printf("ELM Can send expected 0 bytes back from panda. Got %d bytes instead\n", returned_count); - if(returned_count > 0x40) return 0; - return returned_count; -} - -elm_lin_obd_msg lin_last_sent_msg; -uint16_t lin_last_sent_msg_len = 0; -bool lin_await_msg_echo = false; - -static int ICACHE_FLASH_ATTR panda_usbemu_kline_read(uint16_t len) { - int returned_count = panda_usbemu_ctrl_write(0xC0, 0xE0, 2, 0, len); - if(returned_count > len || returned_count < 0){ - os_printf("LIN read got invalid length\n"); - return -1; - } - - #ifdef ELM_DEBUG - if(returned_count) { - os_printf("LIN Received %d bytes\n", returned_count); - os_printf(" Data: "); - for(int i = 0; i < returned_count; i++) - os_printf("%02x ", ((char*)(pandaRecvData+1))[i]); - os_printf("\n"); - } - #endif - return returned_count; -} - -static int ICACHE_FLASH_ATTR panda_usbemu_kline_write(elm_lin_obd_msg *msg) { - elm_lin_usb_msg usb_msg = {}; - - usb_msg.usb_ep_num = PANDA_USB_LIN_WRITE_BUS_NUM; //USB Bulk Endpoint ID. - usb_msg.payload_len = (msg->priority & 0x07) + 4 + 1; //The +1 is for serial_port - usb_msg.serial_port = 2; - memcpy(&usb_msg.msg, msg, sizeof(elm_lin_obd_msg)); - - /* spi_comm will erase data in the recv buffer even if you are only - * interested in sending data that gets no response (like writing - * can data). This behavior becomes problematic when trying to send - * a can message while processsing received can messages. A dummy - * recv buffer is used here so received data is not overwritten. */ - int returned_count = spi_comm((char*)&usb_msg, sizeof(elm_lin_usb_msg), pandaRecvDataDummy, 0x40); - - if(returned_count) - os_printf("ELM LIN send expected 0 bytes back from panda. Got %d bytes instead\n", returned_count); - if(returned_count > 0x40) return 0; - - return returned_count; -} - -/**************************************** - *** Ringbuffer *** - ****************************************/ - -//LIN data is delivered in chunks of arbitrary size. Using a -//ringbuffer to handle it. -uint8_t lin_ringbuff[0x20]; -uint8_t lin_ringbuff_start = 0; -uint8_t lin_ringbuff_end = 0; -#define lin_ringbuff_len \ - (((sizeof(lin_ringbuff) + lin_ringbuff_end) - lin_ringbuff_start)% sizeof(lin_ringbuff)) -#define lin_ringbuff_get(index) (lin_ringbuff[(lin_ringbuff_start + index) % sizeof(lin_ringbuff)]) -#define lin_ringbuff_consume(len) lin_ringbuff_start = ((lin_ringbuff_start + len) % sizeof(lin_ringbuff)) -#define lin_ringbuff_clear()\ - {lin_ringbuff_start = 0; \ - lin_ringbuff_end = 0;} - -int ICACHE_FLASH_ATTR elm_LIN_ringbuff_memcmp(uint8_t *data, uint16_t len) { - if(len > lin_ringbuff_len) return 1; - for(int i = 0; i < len; i++) - if(lin_ringbuff_get(i) != data[i]) return 1; - return 0; // Going with memcpy ret format where 0 means 'equal' -} - -uint16_t ICACHE_FLASH_ATTR elm_LIN_read_into_ringbuff() { - int bytelen = panda_usbemu_kline_read((sizeof(lin_ringbuff) - lin_ringbuff_len) - 1); - if(bytelen < 0) return 0; - for(int j = 0; j < bytelen; j++) { - lin_ringbuff[lin_ringbuff_end % sizeof(lin_ringbuff)] = ((char*)(pandaRecvData+1))[j]; - lin_ringbuff_end = (lin_ringbuff_end + 1) % sizeof(lin_ringbuff); - if(lin_ringbuff_start == lin_ringbuff_end) lin_ringbuff_start++; - } - - #ifdef ELM_DEBUG - if(bytelen){ - os_printf(" RB Data (%d %d %d): ", lin_ringbuff_start, lin_ringbuff_end, lin_ringbuff_len); - for(int i = 0; i < sizeof(lin_ringbuff); i++) - os_printf("%02x ", lin_ringbuff[i]); - os_printf("\n"); - } - #endif - - return bytelen; -} - -/**************************************** - *** String parsing utility functions *** - ****************************************/ - -static int8_t ICACHE_FLASH_ATTR elm_decode_hex_char(char b){ - if(b >= '0' && b <= '9') return b - '0'; - if(b >= 'A' && b <= 'F') return (b - 'A') + 10; - if(b >= 'a' && b <= 'f') return (b - 'a') + 10; - return -1; -} - -static uint8_t ICACHE_FLASH_ATTR elm_decode_hex_byte(const char* data) { - return (elm_decode_hex_char(data[0]) << 4) | elm_decode_hex_char(data[1]); -} - -static bool ICACHE_FLASH_ATTR elm_check_valid_hex_chars(const char* data, uint8_t len) { - for(int i = 0; i < len; i++){ - char b = data[i]; - if(!((b >= '0' && b <= '9') || (b >= 'A' && b <= 'F') || (b >= 'a' && b <= 'f'))) - return 0; - } - return 1; -} - -static uint16_t ICACHE_FLASH_ATTR elm_strip(const char *data, uint16_t lenin, - char *outbuff, uint16_t outbufflen) { - uint16_t count = 0; - for(uint16_t i = 0; i < lenin; i++) { - if(count >= outbufflen) break; - if(data[i] == ' ') continue; - if(data[i] >= 'a' && data[i] <= 'z'){ - outbuff[count++] = data[i] - ('a' - 'A'); - } else { - outbuff[count++] = data[i]; - } - if(data[i] == '\r') break; - } - return count; -} - -static int ICACHE_FLASH_ATTR elm_msg_find_cr_or_eos(char *data, uint16_t len){ - uint16_t i; - for(i = 0; i < len; i++) - if(data[i] == '\r') { - i++; - break; - } - return i; -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *****************************************************/ - -typedef enum { - AUTO, LIN, CAN11, CAN29, NA -} elm_proto_type_t; - -typedef struct elm_protocol { - bool supported; - elm_proto_type_t type; - uint16_t cbaud; //Centibaud (cbaud * 10 = kbaud) - void (*process_obd)(const struct elm_protocol*, const char*, uint16_t); - //init is used to init and de-init a protocol. Init functions should - //not do things that would leave a new protocol in an invalid state - //after the new protocol's init is called (e.g. No arming timers). - void (*init)(const struct elm_protocol*); - char* name; -} elm_protocol_t; - -static const elm_protocol_t* ICACHE_FLASH_ATTR elm_current_proto(); -void ICACHE_FLASH_ATTR elm_reset_aux_timer(); -static void ICACHE_FLASH_ATTR elm_autodetect_cb(bool); - -static const elm_protocol_t elm_protocols[]; -//(sizeof(elm_protocols)/sizeof(elm_protocol_t)) -#define ELM_PROTOCOL_COUNT 13 - -#define LOOPCOUNT_FULL 4 -static int loopcount = 0; -static volatile os_timer_t elm_timeout; -static volatile os_timer_t elm_proto_aux_timeout; - -static bool is_auto_detecting = false; - -// Used only by elm_timer_cb, so not volatile -static bool did_multimessage = false; -static bool got_msg_this_run = false; -static bool can_tx_worked = false; -static uint8_t elm_msg_mode_ret_filter; -static uint8_t elm_msg_pid_ret_filter; - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> SAE J1850 implementation (Unsupported) *** - *****************************************************/ - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_J1850(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("NO DATA\r\r>"); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> ISO 14230-4 implementation *** - *****************************************************/ - -const char *lin_cmd_backup = NULL; //Holds msg while bus init is done -uint16_t lin_cmd_backup_len = 0; -bool lin_waiting_keepalive_echo = false; - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_LIN5baud(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("BUS INIT: ...ERROR\r\r>"); -} - -bool ICACHE_FLASH_ATTR elm_lin_keepalive_echo() { - if(lin_waiting_keepalive_echo) { - for(int pass = 0; pass < 4 && lin_ringbuff_len < 5; pass++) { - elm_LIN_read_into_ringbuff(); - } - - lin_waiting_keepalive_echo = false; - //keepalive Echo should always come before other message echo. - if(lin_ringbuff_len >= 5 && !elm_LIN_ringbuff_memcmp("\xc1\x33\xf1\x3e\x23", 5)){ - lin_ringbuff_consume(5); - return true; - } else { - os_printf("Keep alive echo failed\n"); - return false; - } - } - return true; -} - -void ICACHE_FLASH_ATTR elm_LINFast_keepalive_timer_cb(void *arg) { - if(!lin_bus_initialized) { - os_printf("WARNING! Elm LIN keepalive timer running while bus is not initialized\n"); - return; - } - if(loopcount) { - os_printf("WARNING! Elm LIN keepalive timer during a tx/rx loop!\n"); - return; - } - if(lin_ringbuff_len) { - os_printf("WARNING! lin_ringbuff_len should be 0 when a keepalive echo is processed.\n"); - return; - } - - if(!elm_lin_keepalive_echo()) { - lin_bus_initialized = false; - return; - } - - elm_lin_obd_msg msg = {}; - - msg.priority = 0xC0 | 1; - msg.receiver = 0x33; - msg.sender = 0xF1; - msg.dat[0] = 0x3E; - msg.dat[1] = msg.dat[0] + msg.priority + msg.receiver + msg.sender; // checksum - - #ifdef ELM_DEBUG - os_printf("Sending LIN KEEPALIVE: Priority: %02x; RecvAddr: %02x; SendAddr: %02x; (%02x); ", - msg.priority, msg.receiver, msg.sender, 1); - for(int i = 0; i < 2; i++) os_printf("%02x ", msg.dat[i]); - os_printf("\n"); - #endif - - lin_waiting_keepalive_echo = true; - - panda_usbemu_kline_write(&msg); - elm_reset_aux_timer(); -} - -static void ICACHE_FLASH_ATTR elm_init_LINFast(const elm_protocol_t* proto){ - os_timer_disarm(&elm_proto_aux_timeout); - os_timer_setfn(&elm_proto_aux_timeout, (os_timer_func_t *)elm_LINFast_keepalive_timer_cb, proto); - - lin_bus_initialized = false; - lin_await_msg_echo = false; - lin_waiting_keepalive_echo = false; - - lin_cmd_backup = NULL; - lin_cmd_backup_len = 0; - - lin_ringbuff_clear(); - panda_clear_lin_txrx(); -} - -int ICACHE_FLASH_ATTR elm_LINFast_process_echo() { - if(!elm_lin_keepalive_echo()) { - os_printf("Keepalive echo not detected.\n"); - lin_ringbuff_clear(); - return -1; - } - - if(!lin_await_msg_echo) { - os_printf("Echo abort. Nothing waiting echo\n"); - return 1; - } - - for(int i = 0; i < 4; i++){ - if(lin_ringbuff_len < lin_last_sent_msg_len) elm_LIN_read_into_ringbuff(); - - if(lin_ringbuff_len >= lin_last_sent_msg_len){ - #ifdef ELM_DEBUG - os_printf("Got enough data %d\n", lin_last_sent_msg_len); - #endif - if(!elm_LIN_ringbuff_memcmp((uint8_t*)&lin_last_sent_msg, lin_last_sent_msg_len)) { - #ifdef ELM_DEBUG - os_printf("LIN data was sent successfully.\n"); - #endif - lin_ringbuff_consume(lin_last_sent_msg_len); - lin_await_msg_echo = false; - return 1; - } else { - #ifdef ELM_DEBUG - os_printf("Echo not correct.\n"); - os_printf(" RB Data (%d %d %d): ", lin_ringbuff_start, lin_ringbuff_end, lin_ringbuff_len); - for(int i = 0; i < sizeof(lin_ringbuff); i++) - os_printf("%02x ", lin_ringbuff[i]); - os_printf("\n"); - os_printf(" MSG Data (%d): ", lin_last_sent_msg_len); - for(int i = 0; i < lin_last_sent_msg_len; i++) - os_printf("%02x ", ((uint8_t*)&lin_last_sent_msg)[i]); - os_printf("\n"); - #endif - - if(lin_bus_initialized || loopcount == 0 && i == 4) { - lin_ringbuff_clear(); - return -1; - } else { - os_printf("Lin init echo misaligned? Consuming byte (%02x). Retry.\n", lin_ringbuff_get(0)); - lin_ringbuff_consume(1); - continue; - } - } - } - } - - return !lin_await_msg_echo; //true if echo handled -} - -void ICACHE_FLASH_ATTR elm_LINFast_timer_cb(void *arg){ - const elm_protocol_t* proto = (const elm_protocol_t*) arg; - loopcount--; - #ifdef ELM_DEBUG - os_printf("LIN CB call\n"); - #endif - - if(!lin_bus_initialized) { - os_printf("WARNING: LIN CB called without bus initialized!"); - return; // TODO: shoulnd't ever happen. Handle? - } - - int echo_result = elm_LINFast_process_echo(); - - if(echo_result == -1 || (echo_result == 0 && loopcount == 0)) { - if(!is_auto_detecting){ - elm_append_rsp_const("BUS ERROR\r\r>"); - elm_tcp_tx_flush(); - } - loopcount = 0; - lin_bus_initialized = false; - return; - } - - if(echo_result == 0) { - #ifdef ELM_DEBUG - os_printf("Not ready to process\n"); - #endif - os_timer_arm(&elm_timeout, 30, 0); - return; // Not ready to go on - } - - #ifdef ELM_DEBUG - os_printf("Processing ELM %d\n", lin_ringbuff_len); - #endif - - if(loopcount>0) { - for(int pass = 0; pass < 16 && loopcount; pass++){ - elm_LIN_read_into_ringbuff(); - - while(lin_ringbuff_len > 0){ - //if(lin_ringbuff_len > 0){ - if(lin_ringbuff_get(0) & 0x80 != 0x80){ - os_printf("Resetting LIN bus due to bad first byte.\n"); - loopcount = 0; - lin_bus_initialized = false; - lin_ringbuff_clear(); - - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } - return; - } - - uint8_t newmsg_len = 4 + (lin_ringbuff_get(0) & 0x7); - if(lin_ringbuff_len >= newmsg_len) { - #ifdef ELM_DEBUG - os_printf("Processing LIN MSG. BuffLen %d; expect %d. Dat: ", lin_ringbuff_len, newmsg_len); - for(int i = 0; i < newmsg_len; i++) os_printf("%02x ", lin_ringbuff_get(i)); - os_printf("\n"); - #endif - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - - if(!is_auto_detecting){ - if(elm_mode_additional_headers){ - for(int i = 0; i < newmsg_len; i++) elm_append_rsp_hex_byte(lin_ringbuff_get(i)); - } else { - for(int i = 3; i < newmsg_len - 1; i++) elm_append_rsp_hex_byte(lin_ringbuff_get(i)); - } - elm_append_rsp_const("\r"); - } - - lin_ringbuff_consume(newmsg_len); - //elm_reset_aux_timer(); - } else { - break; //Stop consuming data if there is not enough data for the next msg. - } - } - } - os_timer_arm(&elm_timeout, 50, 0); - } else { - bool got_msg_this_run_backup = got_msg_this_run; - if(!got_msg_this_run) { - #ifdef ELM_DEBUG - os_printf(" No data collected\n"); - #endif - if(!is_auto_detecting) { - elm_append_rsp_const("NO DATA\r"); - } - } - got_msg_this_run = false; - - if(!is_auto_detecting) { - elm_append_rsp_const("\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(got_msg_this_run_backup); - } - - //TX RX over, resume Keepalive timer - elm_reset_aux_timer(); - } -} - -void ICACHE_FLASH_ATTR elm_LINFast_businit_timer_cb(void *arg){ - const elm_protocol_t* proto = (const elm_protocol_t*) arg; - loopcount--; - #ifdef ELM_DEBUG - os_printf("LIN INIT CB call\n"); - #endif - - int echo_result = elm_LINFast_process_echo(); - - if(echo_result == -1 || (echo_result == 0 && loopcount == 0)) { - #ifdef ELM_DEBUG - os_printf("Init failed with echo test\n"); - #endif - - loopcount = 0; - lin_bus_initialized = 0; - - if(!is_auto_detecting){ - if(echo_result == -1) - elm_append_rsp_const("BUS ERROR\r\r>"); - else - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - return; - } - - if(echo_result == 0) { - #ifdef ELM_DEBUG - os_printf("Not ready to process\n"); - #endif - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); - return; // Not ready to go on - } - - #ifdef ELM_DEBUG - os_printf("Bus init ready to process %d bytes\n", lin_ringbuff_len); - #endif - - if(lin_bus_initialized) return; // TODO: shoulnd't ever happen. Handle? - - if(loopcount>0) { - //Keep waiting for response - for(int i = 0; i < 4; i++){ - elm_LIN_read_into_ringbuff(); - - if(lin_ringbuff_len > 0){ - if(lin_ringbuff_get(0) & 0x80 != 0x80){ - os_printf("Resetting LIN bus due to bad first byte.\n"); - loopcount = 0; - lin_ringbuff_clear(); - - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - return; - } - - uint8_t newmsg_len = 4 + (lin_ringbuff_get(0) & 0x7); - if(lin_ringbuff_len < newmsg_len) { - os_printf("Resetting LIN because returned init data was wrong.\n"); - loopcount = 0; - lin_ringbuff_clear(); - - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - return; - } - - if(!elm_LIN_ringbuff_memcmp("\x83\xF1\x10\xC1\x8F\xE9\xBD", 7)) { - lin_ringbuff_consume(7); - lin_bus_initialized = true; - //lin_ringbuff_clear(); - - os_printf("BUS INITIALIZED\n"); - - elm_reset_aux_timer(); - - if(!is_auto_detecting) { - elm_append_rsp_const("OK\r"); - - //Do the send that was delayed - if(lin_cmd_backup_len) { - elm_tcp_tx_flush(); - proto->process_obd(proto, lin_cmd_backup, lin_cmd_backup_len); - } else { - elm_append_rsp_const("\r>"); - elm_tcp_tx_flush(); - } - } else { - #ifdef ELM_DEBUG - os_printf("LIN success. Silent because in autodetect.\n"); - #endif - elm_autodetect_cb(true); - // TODO: Since bus init is good, is it ok to skip sending the '0100' msg? - } - return; - } - } - } - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); - } else { - #ifdef ELM_DEBUG - os_printf("Fall through on bus init\n"); - #endif - if(!is_auto_detecting){ - elm_append_rsp_const("ERROR\r\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(false); - } - elm_reset_aux_timer(); - } -} - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_LINFast(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_lin_obd_msg msg = {}; - uint8_t bytelen = (len-1)/2; - if((bytelen > 7 && !elm_mode_allow_long) || bytelen > 8) { - elm_append_rsp_const("?\r\r>"); - return; - } - - os_timer_disarm(&elm_proto_aux_timeout); - - if(!lin_bus_initialized) { - panda_clear_lin_txrx(); - - if(!is_auto_detecting) - elm_append_rsp_const("BUS INIT: "); - - lin_cmd_backup = cmd; - lin_cmd_backup_len = len; - - bytelen = 1; - msg.dat[0] = 0x81; - msg.dat[1] = 0x81; // checksum - - panda_kline_wakeup_pulse(); - } else { - bytelen = MIN(bytelen, 7); - for(int i = 0; i < bytelen; i++){ - msg.dat[i] = elm_decode_hex_byte(&cmd[i*2]); - msg.dat[bytelen] += msg.dat[i]; - } - - elm_msg_mode_ret_filter = msg.dat[0]; - elm_msg_pid_ret_filter = msg.dat[1]; - } - - msg.priority = 0xC0 | bytelen; - msg.receiver = 0x33; - msg.sender = 0xF1; - msg.dat[bytelen] += msg.priority + msg.receiver + msg.sender; // checksum - - #ifdef ELM_DEBUG - os_printf("Sending LIN OBD: Priority: %02x; RecvAddr: %02x; SendAddr: %02x; (%02x); ", - msg.priority, msg.receiver, msg.sender, bytelen); - for(int i = 0; i < 8; i++) os_printf("%02x ", msg.dat[i]); - os_printf("\n"); - #endif - - lin_last_sent_msg_len = (msg.priority & 0x07) + 4; - memcpy(&lin_last_sent_msg, &msg, lin_last_sent_msg_len); - lin_await_msg_echo = true; - panda_usbemu_kline_write(&msg); - - loopcount = LOOPCOUNT_FULL + 1; - os_timer_disarm(&elm_timeout); - - if(lin_bus_initialized) { - os_timer_setfn(&elm_timeout, (os_timer_func_t *)elm_LINFast_timer_cb, proto); - elm_LINFast_timer_cb((void*)proto); - } else { - os_timer_setfn(&elm_timeout, (os_timer_func_t *)elm_LINFast_businit_timer_cb, proto); - elm_LINFast_businit_timer_cb((void*)proto); - } -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> ISO 15765-4 implementation *** - *****************************************************/ - -void ICACHE_FLASH_ATTR elm_ISO15765_timer_cb(void *arg){ - const elm_protocol_t* proto = (const elm_protocol_t*) arg; - loopcount--; - if(loopcount>0) { - for(int pass = 0; pass < 16 && loopcount; pass++){ - panda_can_msg_t *can_msgs; - int num_can_msgs = panda_usbemu_can_read(&can_msgs); - - #ifdef ELM_DEBUG - if(num_can_msgs) os_printf(" Received %d can messages\n", num_can_msgs); - #endif - - if(num_can_msgs < 0) continue; - if(!num_can_msgs) break; - - for(int i = 0; i < num_can_msgs; i++){ - - panda_can_msg_t *recv = &can_msgs[i]; - - #ifdef ELM_DEBUG - os_printf(" RECV: Bus: %d; Addr: %08x; ext: %d; tx: %d; Len: %d; ", - recv->bus, panda_get_can_addr(recv), recv->ext, recv->tx, recv->len); - for(int j = 0; j < recv->len; j++) os_printf("%02x ", recv->data[j]); - os_printf("Ts: %d\n", recv->ts); - #endif - - if (recv->bus==0 && recv->len == 8 && - ( - (proto->type == CAN11 && !recv->ext && (panda_get_can_addr(recv) & 0x7F8) == 0x7E8) || - (proto->type == CAN29 && recv->ext && (panda_get_can_addr(recv) & 0x1FFFFF00) == 0x18DAF100) - ) - ) { - if(recv->data[0] <= 7 && - recv->data[1] == (0x40|elm_msg_mode_ret_filter) && - recv->data[2] == elm_msg_pid_ret_filter) { - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - - #ifdef ELM_DEBUG - os_printf(" CAN msg response, index: %d\n", i); - #endif - - if(!is_auto_detecting){ - if(elm_mode_additional_headers){ - elm_append_rsp_can_msg_addr(recv); - for(int j = 0; j < recv->data[0]+1; j++) elm_append_rsp_hex_byte(recv->data[j]); - } else { - for(int j = 1; j < recv->data[0]+1; j++) elm_append_rsp_hex_byte(recv->data[j]); - } - - elm_append_rsp_const("\r"); - elm_tcp_tx_flush(); - } - - } else if((recv->data[0] & 0xF0) == 0x10 && - recv->data[2] == (0x40|elm_msg_mode_ret_filter) && - recv->data[3] == elm_msg_pid_ret_filter) { - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - panda_usbemu_can_write(0, - (proto->type==CAN11) ? - 0x7E0 | (panda_get_can_addr(recv)&0x7) : - (0x18DA00F1 | (((panda_get_can_addr(recv))&0xFF)<<8)), - "\x30\x00\x00", 3); - - did_multimessage = true; - - #ifdef ELM_DEBUG - os_printf(" CAN multimsg start response, index: %d, len %d\n", i, - ((recv->data[0]&0xF)<<8) | recv->data[1]); - #endif - - if(!is_auto_detecting){ - if(!elm_mode_additional_headers) { - elm_append_rsp(&hex_lookup[recv->data[0]&0xF], 1); - elm_append_rsp_hex_byte(recv->data[1]); - elm_append_rsp_const("\r0:"); - if(elm_mode_print_spaces) elm_append_rsp_const(" "); - for(int j = 2; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } else { - elm_append_rsp_can_msg_addr(recv); - for(int j = 0; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } - - elm_append_rsp_const("\r"); - elm_tcp_tx_flush(); - } - - } else if (did_multimessage && (recv->data[0] & 0xF0) == 0x20) { - got_msg_this_run = true; - loopcount = LOOPCOUNT_FULL; - #ifdef ELM_DEBUG - os_printf(" CAN multimsg data response, index: %d\n", i); - #endif - - if(!is_auto_detecting){ - if(!elm_mode_additional_headers) { - elm_append_rsp(&hex_lookup[recv->data[0] & 0xF], 1); - elm_append_rsp_const(":"); - if(elm_mode_print_spaces) elm_append_rsp_const(" "); - for(int j = 1; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } else { - elm_append_rsp_can_msg_addr(recv); - for(int j = 0; j < 8; j++) elm_append_rsp_hex_byte(recv->data[j]); - } - elm_append_rsp_const("\r"); - } - } - } else if (recv->bus == 0x80 && recv->len == 8 && - (panda_get_can_addr(recv) == ((proto->type==CAN11) ? 0x7DF : 0x18DB33F1)) - ) { - //Can send receipt - #ifdef ELM_DEBUG - os_printf(" Got CAN tx receipt\n"); - #endif - can_tx_worked = true; - } - } - } - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); - } else { - bool got_msg_this_run_backup = got_msg_this_run; - if(did_multimessage) { - os_printf(" End of multi message\n"); - } else if(!got_msg_this_run) { - os_printf(" No data collected\n"); - if(!is_auto_detecting) { - if(can_tx_worked) { - elm_append_rsp_const("NO DATA\r"); - } else { - elm_append_rsp_const("CAN ERROR\r"); - } - } - } - did_multimessage = false; - got_msg_this_run = false; - can_tx_worked = false; - - if(!is_auto_detecting) { - elm_append_rsp_const("\r>"); - elm_tcp_tx_flush(); - } else { - elm_autodetect_cb(got_msg_this_run_backup); - } - } -} - -static void ICACHE_FLASH_ATTR elm_init_ISO15765(const elm_protocol_t* proto){ - panda_set_can0_cbaud(proto->cbaud); -} - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_ISO15765(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_can_obd_msg msg = {}; - msg.len = (len-1)/2; - if((msg.len > 7 && !elm_mode_allow_long) || msg.len > 8) { - elm_append_rsp_const("?\r\r>"); - return; - } - - msg.len = MIN(msg.len, 7); - - for(int i = 0; i < msg.len; i++) - msg.dat[i] = elm_decode_hex_byte(&cmd[i*2]); - - elm_msg_mode_ret_filter = msg.dat[0]; - elm_msg_pid_ret_filter = msg.dat[1]; - - #ifdef ELM_DEBUG - os_printf("Sending CAN OBD: %02x; ", msg.len); - for(int i = 0; i < 7; i++) - os_printf("%02x ", msg.dat[i]); - os_printf("\n"); - #endif - - panda_clear_can_rx(); - - panda_usbemu_can_write(0, (proto->type==CAN11) ? 0x7DF : 0x18DB33F1, - (uint8_t*)&msg, msg.len+1); - - #ifdef ELM_DEBUG - os_printf("Starting up timer\n"); - #endif - - loopcount = LOOPCOUNT_FULL; - os_timer_disarm(&elm_timeout); - os_timer_setfn(&elm_timeout, (os_timer_func_t *)elm_ISO15765_timer_cb, proto); - os_timer_arm(&elm_timeout, elm_mode_timeout, 0); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> Stuf for unsupported CAN protocols *** - *****************************************************/ - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_CANGen(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("NO DATA\r\r>"); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> AUTO Detect implementation *** - *****************************************************/ - -static int elm_autodetect_proto_iter; -static uint16_t elm_staged_auto_msg_len; -static const char* elm_staged_auto_msg; - -static void ICACHE_FLASH_ATTR elm_autodetect_cb(bool proto_worked){ - if(proto_worked) { - os_printf("Autodetect proto success\n"); - is_auto_detecting = false; - elm_selected_protocol = elm_autodetect_proto_iter; - elm_current_proto()->process_obd(elm_current_proto(), - elm_staged_auto_msg, elm_staged_auto_msg_len); - } else { - for(elm_autodetect_proto_iter++; elm_autodetect_proto_iter < ELM_PROTOCOL_COUNT; - elm_autodetect_proto_iter++){ - const elm_protocol_t *proto = &elm_protocols[elm_autodetect_proto_iter]; - if(proto->supported && proto->type != AUTO) { - os_printf("*** AUTO trying '%s'\n", proto->name); - proto->init(proto); - proto->process_obd(proto, "0100\r", 5); // Try sending on the bus - return; - } - } - - //if(elm_autodetect_main()) return; - is_auto_detecting = false; - os_printf("Autodetect failed\n"); - elm_append_rsp_const("UNABLE TO CONNECT\r\r>"); - elm_tcp_tx_flush(); - } -} - -static void ICACHE_FLASH_ATTR elm_process_obd_cmd_AUTO(const elm_protocol_t* proto, - const char *cmd, uint16_t len) { - elm_append_rsp_const("SEARCHING...\r"); - elm_staged_auto_msg_len = len; - elm_staged_auto_msg = cmd; - is_auto_detecting = true; - - elm_autodetect_proto_iter = 0; - elm_autodetect_cb(false); -} - -/***************************************************** - *** ELM protocol specification and implementation *** - *** -> Protocol Registry and related functions. *** - *****************************************************/ - -static const elm_protocol_t elm_protocols[] = { - {true, AUTO, 0, elm_process_obd_cmd_AUTO, NULL, "AUTO", }, - {false, NA, 416, elm_process_obd_cmd_J1850, NULL, "SAE J1850 PWM", }, - {false, NA, 104, elm_process_obd_cmd_J1850, NULL, "SAE J1850 VPW", }, - {false, LIN, 104, elm_process_obd_cmd_LIN5baud, NULL, "ISO 9141-2", }, - {false, LIN, 104, elm_process_obd_cmd_LIN5baud, NULL, "ISO 14230-4 (KWP 5BAUD)", }, - {true, LIN, 104, elm_process_obd_cmd_LINFast, NULL, "ISO 14230-4 (KWP FAST)", }, - {true, CAN11, 5000, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 11/500)",}, - {true, CAN29, 5000, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 29/500)",}, - {true, CAN11, 2500, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 11/250)",}, - {true, CAN29, 2500, elm_process_obd_cmd_ISO15765, elm_init_ISO15765, "ISO 15765-4 (CAN 29/250)",}, - {false, CAN29, 2500, elm_process_obd_cmd_CANGen, NULL, "SAE J1939 (CAN 29/250)", }, - {false, CAN11, 1250, elm_process_obd_cmd_CANGen, NULL, "USER1 (CAN 11/125)", }, - {false, CAN11, 500, elm_process_obd_cmd_CANGen, NULL, "USER2 (CAN 11/50)", }, -}; - -static const elm_protocol_t* ICACHE_FLASH_ATTR elm_current_proto() { - return &elm_protocols[elm_selected_protocol]; -} - -void ICACHE_FLASH_ATTR elm_reset_aux_timer() { - os_timer_disarm(&elm_proto_aux_timeout); - if(elm_mode_keepalive_period) - os_timer_arm(&elm_proto_aux_timeout, elm_mode_keepalive_period, 0); -} - -void ICACHE_FLASH_ATTR elm_proto_reinit(const elm_protocol_t *proto) { - if(proto->init) proto->init(proto); -} - -/******************************************* - *** ELM AT command parsing and handling *** - *******************************************/ - -enum at_cmd_ids_t { // FULL ELM 1.0 list - AT_INVALID, //Fake - - AT_AMP1, - AT_AL, - AT_AT0, AT_AT1, AT_AT2, // Added ELM 1.2, expected by Torque - AT_BD, - AT_BI, - AT_CAF0, AT_CAF1, - AT_CF_8, AT_CF_3, - AT_CFC0, AT_CFC1, - AT_CM_8, AT_CM_3, - AT_CP, - AT_CS, - AT_CV, - AT_D, - AT_DP, AT_DPN, - AT_E0, AT_E1, - AT_H0, AT_H1, - AT_I, - AT_IB10, - AT_IB96, - AT_L0, AT_L1, - AT_M0, AT_M1, AT_MA, - AT_MR, - AT_MT, - AT_NL, - AT_PC, - AT_R0, AT_R1, - AT_RV, - AT_S0, AT_S1, // Added ELM 1.3, expected by Torque - AT_SH_6, AT_SH_3, - AT_SPA, AT_SP, - AT_ST, - AT_SW, - AT_TPA, AT_TP, - AT_WM_XYZA, AT_WM_XYZAB, AT_WM_XYZABC, - AT_WS, - AT_Z, -}; - -typedef struct { - char* name; - uint8_t name_len; - uint8_t cmd_len; - enum at_cmd_ids_t id; -} at_cmd_reg_t; - -static const at_cmd_reg_t at_cmd_reg[] = { - {"@1", 2, 2, AT_AMP1}, - {"AL", 2, 2, AT_AL}, - {"AT0", 3, 3, AT_AT0}, // Added ELM 1.2, expected by Torque - {"AT1", 3, 3, AT_AT1}, // Added ELM 1.2, expected by Torque - {"AT2", 3, 3, AT_AT2}, // Added ELM 1.2, expected by Torque - {"DP", 2, 2, AT_DP}, - {"DPN", 3, 3, AT_DPN}, - {"E0", 2, 2, AT_E0}, - {"E1", 2, 2, AT_E1}, - {"H0", 2, 2, AT_H0}, - {"H1", 2, 2, AT_H1}, - {"I", 1, 1, AT_I}, - {"L0", 2, 2, AT_L0}, - {"L1", 2, 2, AT_L1}, - {"M0", 2, 2, AT_M0}, - //{"M1", 2, 2, AT_M1}, - {"NL", 2, 2, AT_NL}, - {"PC", 2, 2, AT_PC}, - {"S0", 2, 2, AT_S0}, // Added ELM 1.3, expected by Torque - {"S1", 2, 2, AT_S1}, // Added ELM 1.3, expected by Torque - {"SP", 2, 3, AT_SP}, - {"SPA", 3, 4, AT_SPA}, - {"ST", 2, 4, AT_ST}, - {"SW", 2, 4, AT_SW}, - {"Z", 1, 1, AT_Z}, -}; -#define AT_CMD_REG_LEN (sizeof(at_cmd_reg)/sizeof(at_cmd_reg_t)) - -static enum at_cmd_ids_t ICACHE_FLASH_ATTR elm_parse_at_cmd(char *cmd, uint16_t len){ - int i; - for(i=0; i7 BYTES) - elm_mode_allow_long = true; - break; - case AT_AT0: //DISABLE ADAPTIVE TIMING - elm_mode_adaptive_timing = 0; - break; - case AT_AT1: //SET ADAPTIVE TIMING TO AUTO1 - elm_mode_adaptive_timing = 1; - break; - case AT_AT2: //SET ADAPTIVE TIMING TO AUTO2 - elm_mode_adaptive_timing = 2; - break; - case AT_DP: //DESCRIBE THE PROTOCOL BY NAME - if(elm_mode_auto_protocol && elm_selected_protocol != 0) - elm_append_rsp_const("AUTO, "); - elm_append_rsp(elm_current_proto()->name, - strlen(elm_current_proto()->name)); - elm_append_rsp_const("\r\r"); - return; - case AT_DPN: //DESCRIBE THE PROTOCOL BY NUMBER - //TODO: Required. Report currently selected protocol - if(elm_mode_auto_protocol) - elm_append_rsp_const("A"); - elm_append_rsp(&hex_lookup[elm_selected_protocol], 1); - elm_append_rsp_const("\r\r"); - return; // Don't display 'OK' - case AT_E0: //ECHO OFF - elm_mode_echo = false; - break; - case AT_E1: //ECHO ON - elm_mode_echo = true; - break; - case AT_H0: //SHOW FULL CAN HEADERS OFF - elm_mode_additional_headers = false; - break; - case AT_H1: //SHOW FULL CAN HEADERS ON - elm_mode_additional_headers = true; - break; - case AT_I: //IDENTIFY SELF - elm_append_rsp_const(IDENT_MSG); - return; - case AT_L0: //LINEFEED OFF - elm_mode_linefeed = false; - break; - case AT_L1: //LINEFEED ON - elm_mode_linefeed = true; - break; - case AT_M0: //DISABLE NONVOLATILE STORAGE - //Memory storage is likely unnecessary - break; - case AT_NL: //DISABLE LONG MESSAGE SUPPORT (>7 BYTES) - elm_mode_allow_long = false; - break; - case AT_PC: //PROTOCOL CANCEL (Stop timers and stuff) - { - //Init functions should idenpotently prepare the protocol to be used. - //Thus, the init function can be used as a protocol cancel function - elm_proto_reinit(elm_current_proto()); - break; - } - case AT_S0: //DISABLE PRINTING SPACES IN ECU RESPONSES - elm_mode_print_spaces = false; - break; - case AT_S1: //ENABLE PRINTING SPACES IN ECU RESPONSES - elm_mode_print_spaces = true; - break; - case AT_SP: //SET PROTOCOL - tmp = elm_decode_hex_char(cmd[2]); - if(tmp == -1 || tmp >= ELM_PROTOCOL_COUNT) { - elm_append_rsp_const("?\r\r"); - return; - } - - //De-Init previous protocol - elm_proto_reinit(elm_current_proto()); - - elm_selected_protocol = tmp; - elm_mode_auto_protocol = (tmp == 0); - - //Init new protocol - elm_proto_reinit(elm_current_proto()); - break; - case AT_SPA: //SET PROTOCOL WITH AUTO FALLBACK - tmp = elm_decode_hex_char(cmd[3]); - if(tmp == -1 || tmp >= ELM_PROTOCOL_COUNT) { - elm_append_rsp_const("?\r\r"); - return; - } - - //De-Init previous protocol - elm_proto_reinit(elm_current_proto()); - - elm_selected_protocol = tmp; - elm_mode_auto_protocol = true; - - //Init new protocol - elm_proto_reinit(elm_current_proto()); - break; - case AT_ST: //SET TIMEOUT - if(!elm_check_valid_hex_chars(&cmd[2], 2)) { - elm_append_rsp_const("?\r\r"); - return; - } - - tmp = elm_decode_hex_byte(&cmd[2]); - //20 for CAN, 4 for LIN - elm_mode_timeout = tmp ? tmp*20 : ELM_MODE_TIMEOUT_DEFAULT; - break; - case AT_SW: //SET WAKEUP TIME INTERVAL - if(!elm_check_valid_hex_chars(&cmd[2], 2)) { - elm_append_rsp_const("?\r\r"); - return; - } - - tmp = elm_decode_hex_byte(&cmd[2]); - elm_mode_keepalive_period = tmp ? MAX(tmp, 0x20) * 20 : 0; - - if(lin_bus_initialized){ - os_timer_disarm(&elm_proto_aux_timeout); - if(elm_mode_keepalive_period) - os_timer_arm(&elm_proto_aux_timeout, elm_mode_keepalive_period, 0); - } - break; - case AT_Z: //RESET - elm_mode_echo = true; - elm_mode_linefeed = false; - elm_mode_additional_headers = false; - elm_mode_auto_protocol = true; - elm_selected_protocol = ELM_MODE_SELECTED_PROTOCOL_DEFAULT; - elm_mode_print_spaces = true; - elm_mode_adaptive_timing = 1; - elm_mode_allow_long = false; - elm_mode_timeout = ELM_MODE_TIMEOUT_DEFAULT; - elm_mode_keepalive_period = ELM_MODE_KEEPALIVE_PERIOD_DEFAULT; - - elm_append_rsp_const("\r\r"); - elm_append_rsp_const(IDENT_MSG); - panda_set_safety_mode(SAFETY_ELM327); - - elm_proto_reinit(elm_current_proto()); - return; - default: - elm_append_rsp_const("?\r\r"); - return; - } - - elm_append_rsp_const("OK\r\r"); -} - -/************************************* - *** Connection and cli management *** - *************************************/ - -static void ICACHE_FLASH_ATTR elm_append_in_msg(char *data, uint16_t len) { - if(in_msg_len + len > sizeof(in_msg)) - len = sizeof(in_msg) - in_msg_len; - memcpy(in_msg + in_msg_len, data, len); - in_msg_len += len; -} - -static int ICACHE_FLASH_ATTR elm_msg_is_at_cmd(char *data, uint16_t len){ - return len >= 4 && data[0] == 'A' && data[1] == 'T'; -} - -static void ICACHE_FLASH_ATTR elm_rx_cb(void *arg, char *data, uint16_t len) { - #ifdef ELM_DEBUG - //os_printf("\nGot ELM Data In: '%s'\n", data); - #endif - - rsp_buff_len = 0; - len = elm_msg_find_cr_or_eos(data, len); - - if(loopcount){ - os_timer_disarm(&elm_timeout); - loopcount = 0; - got_msg_this_run = false; - can_tx_worked = false; - did_multimessage = false; - - os_printf("Interrupting operation, stopping timer. msg len: %d\n", len); - elm_append_rsp_const("STOPPED\r\r>"); - if(len == 1 && data[0] == '\r') { - os_printf("Empty msg source of interrupt.\n"); - elm_tcp_tx_flush(); - return; - } - } - - if(!(len == 1 && data[0] == '\r') && in_msg_len && in_msg[in_msg_len-1] == '\r'){ - in_msg_len = 0; - } - - if(!(len == 1 && data[0] == '\r' && in_msg_len && in_msg[in_msg_len-1] == '\r')) { - // Not Repeating last message - elm_append_in_msg(data, len); //Aim to remove this memcpy - } - if(elm_mode_echo) - elm_append_rsp(in_msg, in_msg_len); - - if(in_msg_len > 0 && in_msg[in_msg_len-1] == '\r') { //Got a full line - stripped_msg_len = elm_strip(in_msg, in_msg_len, stripped_msg, sizeof(stripped_msg)); - - if(elm_msg_is_at_cmd(stripped_msg, stripped_msg_len)) { - elm_process_at_cmd(stripped_msg+2, stripped_msg_len-2); - elm_append_rsp_const(">"); - } else if(elm_check_valid_hex_chars(stripped_msg, stripped_msg_len - 1)) { - elm_current_proto()->process_obd(elm_current_proto(), stripped_msg, stripped_msg_len); - } else { - elm_append_rsp_const("?\r\r>"); - } - } - - elm_tcp_tx_flush(); - - //Just clear the buffer if full with no termination - if(in_msg_len == sizeof(in_msg) && in_msg[in_msg_len-1] != '\r') - in_msg_len = 0; -} - -void ICACHE_FLASH_ATTR elm_tcp_disconnect_cb(void *arg){ - struct espconn *pesp_conn = (struct espconn *)arg; - - elm_tcp_conn_t * prev = NULL; - for(elm_tcp_conn_t *iter = connection_list; iter != NULL; iter=iter->next){ - struct espconn *conn = iter->conn; - //SHOW_CONNECTION("Considering Disconnecting", conn); - if(!memcmp(pesp_conn->proto.tcp->remote_ip, conn->proto.tcp->remote_ip, 4) && - pesp_conn->proto.tcp->remote_port == conn->proto.tcp->remote_port){ - os_printf("Deleting ELM Connection!\n"); - if(prev){ - prev->next = iter->next; - } else { - connection_list = iter->next; - } - os_free(iter); - break; - } - - prev = iter; - } - - if(connection_list == NULL) { - //If all clients are disconnected, reset the protocol (cancels - //keep alive timers). This will not detect inproperly killed - //connections. In this case, periodic events associated with the - //current protocol will continue until a new client attaches, a - //command is sent generating a response (ELM will try to responde - //to the dead connection, and remove it upon error), and finally, - //the new client disconnects. OFC a power cycle is also an option. - elm_proto_reinit(elm_current_proto()); - } -} - -void ICACHE_FLASH_ATTR elm_tcp_connect_cb(void *arg) { - struct espconn *pesp_conn = (struct espconn *)arg; - //SHOW_CONNECTION("New connection", pesp_conn); - espconn_set_opt(&elm_conn, ESPCONN_NODELAY); - espconn_regist_recvcb(pesp_conn, elm_rx_cb); - //Allow several sends to be queued at a time. - espconn_tcp_set_buf_count(pesp_conn, 3); - - bool connection_address_already_there = false; - for(elm_tcp_conn_t *iter2 = connection_list; iter2 != NULL; iter2 = iter2->next) - if(iter2->conn == pesp_conn){connection_address_already_there = true; break;} - - if(connection_address_already_there) { - os_printf("ELM WIFI: Memory reuse of recently killed connection\n"); - } else { - os_printf("ELM WIFI: Adding connection\n"); - elm_tcp_conn_t *newconn = os_malloc(sizeof(elm_tcp_conn_t)); - if(!newconn) { - os_printf("Failed to allocate place for connection\n"); - } else { - newconn->next = connection_list; - newconn->conn = pesp_conn; - connection_list = newconn; - } - } -} - -void ICACHE_FLASH_ATTR elm327_init() { - // control listener - elm_proto.local_port = ELM_PORT; - elm_conn.type = ESPCONN_TCP; - elm_conn.state = ESPCONN_NONE; - elm_conn.proto.tcp = &elm_proto; - espconn_regist_connectcb(&elm_conn, elm_tcp_connect_cb); - espconn_regist_disconcb(&elm_conn, elm_tcp_disconnect_cb); - espconn_accept(&elm_conn); - espconn_regist_time(&elm_conn, 0, 0); // 60s timeout for all connections -} diff --git a/panda/boardesp/get_sdk.sh b/panda/boardesp/get_sdk.sh deleted file mode 100755 index b1e8bf2be8..0000000000 --- a/panda/boardesp/get_sdk.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -sudo apt-get install make unrar-free autoconf automake libtool gcc g++ gperf \ - flex bison texinfo gawk ncurses-dev libexpat-dev python-dev python python-serial \ - sed git unzip bash help2man wget bzip2 -# huh? -sudo apt-get install libtool -sudo apt-get install libtool-bin -git clone --recursive https://github.com/pfalcon/esp-open-sdk.git -cd esp-open-sdk -git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec -cp ../python2_make.py . -python2 python2_make.py 'LD_LIBRARY_PATH="" make STANDALONE=y' diff --git a/panda/boardesp/get_sdk_ci.sh b/panda/boardesp/get_sdk_ci.sh deleted file mode 100755 index e95b7bd262..0000000000 --- a/panda/boardesp/get_sdk_ci.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -git clone --recursive https://github.com/pfalcon/esp-open-sdk.git -cd esp-open-sdk -git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec -cp ../python2_make.py . -python2 python2_make.py 'LD_LIBRARY_PATH="" make STANDALONE=y' diff --git a/panda/boardesp/get_sdk_mac.sh b/panda/boardesp/get_sdk_mac.sh deleted file mode 100755 index c2cfcd53b4..0000000000 --- a/panda/boardesp/get_sdk_mac.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash - -# from http://www.esp8266.com/wiki/doku.php?id=setup-osx-compiler-esp8266 - -brew install gnu-sed --with-default-names -brew tap homebrew/dupes -brew install gperf -brew install grep -brew install autoconf -brew install binutils -brew install gawk -brew install wget -brew install automake -brew install libtool -brew install help2man - -brew uninstall gperf - -hdiutil create esp-open-sdk.dmg -volname "esp-open-sdk" -size 10g -fs "Case-sensitive HFS+" -hdiutil mount esp-open-sdk.dmg -ln -s /Volumes/esp-open-sdk esp-open-sdk -cd esp-open-sdk - -git init -git remote add origin https://github.com/pfalcon/esp-open-sdk.git -git fetch origin -git checkout 03f5e898a059451ec5f3de30e7feff30455f7cec -git submodule init -git submodule update --recursive - -cp ../python2_make.py . -python2 python2_make.py 'make STANDALONE=y' diff --git a/panda/boardesp/include/espmissingincludes.h b/panda/boardesp/include/espmissingincludes.h deleted file mode 100644 index 51672d3f50..0000000000 --- a/panda/boardesp/include/espmissingincludes.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef ESPMISSINGINCLUDES_H -#define ESPMISSINGINCLUDES_H - -#include -#include -#include - - -int strcasecmp(const char *a, const char *b); -#ifndef FREERTOS -#include -#include -//Missing function prototypes in include folders. Gcc will warn on these if we don't define 'em anywhere. -//MOST OF THESE ARE GUESSED! but they seem to swork and shut up the compiler. -typedef struct espconn espconn; - -int atoi(const char *nptr); -void ets_install_putc1(void *routine); -void ets_isr_attach(int intr, void *handler, void *arg); -void ets_isr_mask(unsigned intr); -void ets_isr_unmask(unsigned intr); -int ets_memcmp(const void *s1, const void *s2, size_t n); -void *ets_memcpy(void *dest, const void *src, size_t n); -void *ets_memset(void *s, int c, size_t n); -int ets_sprintf(char *str, const char *format, ...) __attribute__ ((format (printf, 2, 3))); -int ets_str2macaddr(void *, void *); -int ets_strcmp(const char *s1, const char *s2); -char *ets_strcpy(char *dest, const char *src); -size_t ets_strlen(const char *s); -int ets_strncmp(const char *s1, const char *s2, int len); -char *ets_strncpy(char *dest, const char *src, size_t n); -char *ets_strstr(const char *haystack, const char *needle); -void ets_timer_arm_new(os_timer_t *a, int b, int c, int isMstimer); -void ets_timer_disarm(os_timer_t *a); -void ets_timer_setfn(os_timer_t *t, ETSTimerFunc *fn, void *parg); -void ets_update_cpu_frequency(int freqmhz); -void *os_memmove(void *dest, const void *src, size_t n); -int os_printf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -int os_snprintf(char *str, size_t size, const char *format, ...) __attribute__ ((format (printf, 3, 4))); -int os_printf_plus(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -void uart_div_modify(int no, unsigned int freq); -uint8 wifi_get_opmode(void); -uint32 system_get_time(); -int rand(void); -void ets_bzero(void *s, size_t n); -void ets_delay_us(int ms); - -//Hack: this is defined in SDK 1.4.0 and undefined in 1.3.0. It's only used for this, the symbol itself -//has no meaning here. -#ifndef RC_LIMIT_P2P_11N -//Defs for SDK <1.4.0 -void *pvPortMalloc(size_t xWantedSize); -void *pvPortZalloc(size_t); -void vPortFree(void *ptr); -void *vPortMalloc(size_t xWantedSize); -void pvPortFree(void *ptr); -#else -void *pvPortMalloc(size_t xWantedSize, const char *file, int line); -void *pvPortZalloc(size_t, const char *file, int line); -void vPortFree(void *ptr, const char *file, int line); -void *vPortMalloc(size_t xWantedSize, const char *file, int line); -void pvPortFree(void *ptr, const char *file, int line); -#endif - -//Standard PIN_FUNC_SELECT gives a warning. Replace by a non-warning one. -#ifdef PIN_FUNC_SELECT -#undef PIN_FUNC_SELECT -#define PIN_FUNC_SELECT(PIN_NAME, FUNC) do { \ - WRITE_PERI_REG(PIN_NAME, \ - (READ_PERI_REG(PIN_NAME) \ - & (~(PERIPHS_IO_MUX_FUNC< _b ? _a : _b; }) - -char ssid[32]; -char password[] = "testing123"; -int wifi_secure_mode = 0; - -static const int pin = 2; - -// Structure holding the TCP connection information. -struct espconn tcp_conn; -// TCP specific protocol structure. -esp_tcp tcp_proto; - -// interrupt communication on port 1338, UDP! -struct espconn inter_conn; -esp_udp inter_proto; - -uint32_t sendData[0x14] = {0}; -uint32_t recvData[0x40] = {0}; - -static int ICACHE_FLASH_ATTR __spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen) { - unsigned int length = 0; - - SpiData spiData; - - spiData.cmd = 2; - spiData.cmdLen = 0; - spiData.addr = NULL; - spiData.addrLen = 0; - - // float boot pin - gpio_output_set(0, 0, 0, (1 << 4)); - - // manual CS pin - gpio_output_set(0, (1 << 5), 0, 0); - memset(sendData, 0xCC, 0x14); - - // wait for ST to respond to CS interrupt - os_delay_us(50); - - // send request - memcpy(((void*)sendData), dat, len); - spiData.data = sendData; - spiData.dataLen = 0x14; - SPIMasterSendData(SpiNum_HSPI, &spiData); - - #define SPI_TIMEOUT 50000 - // give the ST time to be ready, up to 500ms - int i; - for (i = 0; (gpio_input_get() & (1 << 4)) && i < SPI_TIMEOUT; i++) { - os_delay_us(10); - system_soft_wdt_feed(); - } - - // TODO: handle this better - if (i == SPI_TIMEOUT) { - os_printf("ERROR: SPI receive failed\n"); - goto fail; - } - - // blank out recvData - memset(recvData, 0x00, 0x44); - - // receive the length - spiData.data = recvData; - spiData.dataLen = 4; - if(SPIMasterRecvData(SpiNum_HSPI, &spiData) == -1) { - // TODO: Handle gracefully. Maybe fail if len read fails? - os_printf("SPI: Failed to recv length\n"); - goto fail; - } - - length = recvData[0]; - if (length > 0x40) { - os_printf("SPI: BAD LENGTH RECEIVED %x\n", length); - length = 0; - goto fail; - } - - // got response, 0x40 works, 0x44 does not - spiData.data = recvData+1; - spiData.dataLen = (length+3)&(~3); // recvDataLen; - if(SPIMasterRecvData(SpiNum_HSPI, &spiData) == -1) { - // TODO: Handle gracefully. Maybe retry if payload failed. - os_printf("SPI: Failed to recv payload\n"); - length = 0; - goto fail; - } - -fail: - // clear CS - gpio_output_set((1 << 5), 0, 0, 0); - - // set boot pin back - gpio_output_set((1 << 4), 0, (1 << 4), 0); - - return length; -} - -int ICACHE_FLASH_ATTR spi_comm(char *dat, int len, uint32_t *recvData, int recvDataLen) { - // blink the led during SPI comm - if (GPIO_REG_READ(GPIO_OUT_ADDRESS) & (1 << pin)) { - // set gpio low - gpio_output_set(0, (1 << pin), 0, 0); - } else { - // set gpio high - gpio_output_set((1 << pin), 0, 0, 0); - } - - return __spi_comm(dat, len, recvData, recvDataLen); -} - -static void ICACHE_FLASH_ATTR tcp_rx_cb(void *arg, char *data, uint16_t len) { - // nothing too big - if (len > 0x14) return; - - // do the SPI comm - spi_comm(data, len, recvData, 0x40); - - espconn_send(&tcp_conn, recvData, 0x44); -} - -void ICACHE_FLASH_ATTR tcp_connect_cb(void *arg) { - struct espconn *conn = (struct espconn *)arg; - espconn_set_opt(&tcp_conn, ESPCONN_NODELAY); - espconn_regist_recvcb(conn, tcp_rx_cb); -} - -// must be 0x44, because we can fit 4 more -uint8_t buf[0x44*0x10]; -int queue_send_len = -1; - -void ICACHE_FLASH_ATTR poll_can(void *arg) { - uint8_t timerRecvData[0x44] = {0}; - int i = 0; - int j; - - while (i < 0x40) { - int len = spi_comm("\x01\x00\x00\x00", 4, timerRecvData, 0x40); - if (len == 0) break; - if (len > 0x40) { os_printf("SPI LENGTH ERROR!"); break; } - - // if it sends it, assume it's valid CAN - for (j = 0; j < len; j += 0x10) { - memcpy(buf + i*0x10, (timerRecvData+4)+j, 0x10); - i++; - } - } - - if (i != 0) { - int ret = espconn_sendto(&inter_conn, buf, i*0x10); - if (ret != 0) { - os_printf("send failed: %d\n", ret); - queue_send_len = i*0x10; - } else { - queue_send_len = -1; - } - } -} - -int udp_countdown = 0; - -static volatile os_timer_t udp_callback; -void ICACHE_FLASH_ATTR udp_callback_func(void *arg) { - if (queue_send_len == -1) { - poll_can(NULL); - } else { - int ret = espconn_sendto(&inter_conn, buf, queue_send_len); - if (ret == 0) { - queue_send_len = -1; - } - } - if (udp_countdown > 0) { - os_timer_arm(&udp_callback, 5, 0); - udp_countdown--; - } else { - os_printf("UDP timeout\n"); - } -} - -void ICACHE_FLASH_ATTR inter_recv_cb(void *arg, char *pusrdata, unsigned short length) { - remot_info *premot = NULL; - if (espconn_get_connection_info(&inter_conn,&premot,0) == ESPCONN_OK) { - inter_conn.proto.udp->remote_port = premot->remote_port; - inter_conn.proto.udp->remote_ip[0] = premot->remote_ip[0]; - inter_conn.proto.udp->remote_ip[1] = premot->remote_ip[1]; - inter_conn.proto.udp->remote_ip[2] = premot->remote_ip[2]; - inter_conn.proto.udp->remote_ip[3] = premot->remote_ip[3]; - - - if (udp_countdown == 0) { - os_printf("UDP recv\n"); - udp_countdown = 200*5; - - // start 5 second timer - os_timer_disarm(&udp_callback); - os_timer_setfn(&udp_callback, (os_timer_func_t *)udp_callback_func, NULL); - os_timer_arm(&udp_callback, 5, 0); - } else { - udp_countdown = 200*5; - } - } -} - -void ICACHE_FLASH_ATTR wifi_configure(int secure) { - wifi_secure_mode = secure; - - // start wifi AP - wifi_set_opmode(SOFTAP_MODE); - struct softap_config config = {0}; - wifi_softap_get_config(&config); - strcpy(config.ssid, ssid); - if (wifi_secure_mode == 0) strcat(config.ssid, "-pair"); - strcpy(config.password, password); - config.ssid_len = strlen(config.ssid); - config.authmode = wifi_secure_mode ? AUTH_WPA2_PSK : AUTH_OPEN; - config.beacon_interval = 100; - config.max_connection = 4; - wifi_softap_set_config(&config); - - if (wifi_secure_mode) { - // setup tcp server - tcp_proto.local_port = 1337; - tcp_conn.type = ESPCONN_TCP; - tcp_conn.state = ESPCONN_NONE; - tcp_conn.proto.tcp = &tcp_proto; - espconn_regist_connectcb(&tcp_conn, tcp_connect_cb); - espconn_accept(&tcp_conn); - espconn_regist_time(&tcp_conn, 60, 0); // 60s timeout for all connections - - // setup inter server - inter_proto.local_port = 1338; - const char udp_remote_ip[4] = {255, 255, 255, 255}; - os_memcpy(inter_proto.remote_ip, udp_remote_ip, 4); - inter_proto.remote_port = 1338; - - inter_conn.type = ESPCONN_UDP; - inter_conn.proto.udp = &inter_proto; - - espconn_regist_recvcb(&inter_conn, inter_recv_cb); - espconn_create(&inter_conn); - } -} - -void ICACHE_FLASH_ATTR wifi_init() { - // default ssid and password - memset(ssid, 0, 32); - os_sprintf(ssid, "panda-%08x-BROKEN", system_get_chip_id()); - - // fetch secure ssid and password - // update, try 20 times, for 1 second - for (int i = 0; i < 20; i++) { - uint8_t digest[SHA_DIGEST_SIZE]; - char resp[0x20]; - __spi_comm("\x00\x00\x00\x00\x40\xD0\x00\x00\x00\x00\x20\x00", 0xC, recvData, 0x40); - memcpy(resp, recvData+1, 0x20); - - SHA_hash(resp, 0x1C, digest); - if (memcmp(digest, resp+0x1C, 4) == 0) { - // OTP is valid - memcpy(ssid+6, resp, 0x10); - memcpy(password, resp+0x10, 10); - break; - } - os_delay_us(50000); - } - os_printf("Finished getting SID\n"); - os_printf(ssid); - os_printf("\n"); - - // set IP - wifi_softap_dhcps_stop(); //stop DHCP before setting static IP - struct ip_info ip_config; - IP4_ADDR(&ip_config.ip, 192, 168, 0, 10); - IP4_ADDR(&ip_config.gw, 0, 0, 0, 0); - IP4_ADDR(&ip_config.netmask, 255, 255, 255, 0); - wifi_set_ip_info(SOFTAP_IF, &ip_config); - int stupid_gateway = 0; - wifi_softap_set_dhcps_offer_option(OFFER_ROUTER, &stupid_gateway); - wifi_softap_dhcps_start(); - - wifi_configure(0); -} - -#define LOOP_PRIO 2 -#define QUEUE_SIZE 1 -static os_event_t my_queue[QUEUE_SIZE]; -void loop(); - -void ICACHE_FLASH_ATTR web_init(); -void ICACHE_FLASH_ATTR elm327_init(); - -void ICACHE_FLASH_ATTR user_init() { - // init gpio subsystem - gpio_init(); - - // configure UART TXD to be GPIO1, set as output - PIN_FUNC_SELECT(PERIPHS_IO_MUX_U0TXD_U, FUNC_GPIO1); - gpio_output_set(0, 0, (1 << pin), 0); - - // configure SPI - SpiAttr hSpiAttr; - hSpiAttr.bitOrder = SpiBitOrder_MSBFirst; - hSpiAttr.speed = SpiSpeed_10MHz; - hSpiAttr.mode = SpiMode_Master; - hSpiAttr.subMode = SpiSubMode_0; - - // TODO: is one of these CS? - WRITE_PERI_REG(PERIPHS_IO_MUX, 0x105); - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDI_U, 2); // configure io to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTCK_U, 2); // configure io to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTMS_U, 2); // configure io to spi mode - PIN_FUNC_SELECT(PERIPHS_IO_MUX_MTDO_U, 2); // configure io to spi mode - SPIInit(SpiNum_HSPI, &hSpiAttr); - //SPICsPinSelect(SpiNum_HSPI, SpiPinCS_1); - - // configure UART TXD to be GPIO1, set as output - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO5_U, FUNC_GPIO5); - gpio_output_set(0, 0, (1 << 5), 0); - gpio_output_set((1 << 5), 0, 0, 0); - - // uart init - uart_init(BIT_RATE_115200, BIT_RATE_115200); - - // led init - PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2); - gpio_output_set(0, (1 << pin), (1 << pin), 0); - - os_printf("hello\n"); - - // needs SPI - wifi_init(); - - // support ota upgrades - elm327_init(); - web_init(); - - // set gpio high, so LED is off by default - for (int i = 0; i < 5; i++) { - gpio_output_set(0, (1 << pin), 0, 0); - os_delay_us(50000); - gpio_output_set((1 << pin), 0, 0, 0); - os_delay_us(50000); - } - - // jump to OS - system_os_task(loop, LOOP_PRIO, my_queue, QUEUE_SIZE); - system_os_post(LOOP_PRIO, 0, 0); -} - -void ICACHE_FLASH_ATTR loop(os_event_t *events) { - system_os_post(LOOP_PRIO, 0, 0); -} - diff --git a/panda/boardesp/python2_make.py b/panda/boardesp/python2_make.py deleted file mode 100644 index 85bee34577..0000000000 --- a/panda/boardesp/python2_make.py +++ /dev/null @@ -1,4 +0,0 @@ -#!/usr/bin/env python2 -import os -import sys -os.system(sys.argv[1]) diff --git a/panda/boardesp/user_config.h b/panda/boardesp/user_config.h deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/panda/boardesp/webserver.c b/panda/boardesp/webserver.c deleted file mode 100644 index b1a514626f..0000000000 --- a/panda/boardesp/webserver.c +++ /dev/null @@ -1,380 +0,0 @@ -#include "stdlib.h" -#include "ets_sys.h" -#include "osapi.h" -#include "gpio.h" -#include "mem.h" -#include "os_type.h" -#include "user_interface.h" -#include "espconn.h" -#include "upgrade.h" - -#include "crypto/rsa.h" -#include "crypto/sha.h" - -#include "obj/gitversion.h" -#include "obj/cert.h" - -#define MAX(a,b) ((a) > (b) ? (a) : (b)) -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#define espconn_send_string(conn, x) espconn_send(conn, x, strlen(x)) - -#define MAX_RESP 0x800 -char resp[MAX_RESP]; -char pageheader[] = "HTTP/1.0 200 OK\nContent-Type: text/html\n\n" -"\n" -"\n" -"\n" -"Panda\n" -"\n" -"\n" -"\n" -"\n" -"\n"; - -char OK_header[] = "HTTP/1.0 200 OK\nContent-Type: text/html\n\n"; - -static struct espconn web_conn; -static esp_tcp web_proto; -extern char ssid[]; -extern int wifi_secure_mode; - -char *st_firmware; -int real_content_length, content_length = 0; -char *st_firmware_ptr; -LOCAL os_timer_t ota_reboot_timer; - -#define FIRMWARE_SIZE 503808 - -typedef struct { - uint16_t ep; - uint16_t extra_len; - union { - struct { - uint8_t request_type; - uint8_t request; - uint16_t value; - uint16_t index; - uint16_t length; - } control; - uint8_t data[0x10]; - } u; -} usb_msg; - -int ICACHE_FLASH_ATTR usb_cmd(int ep, int len, int request, - int value, int index, char *data) { - usb_msg usb = {0}; - - usb.ep = ep; - usb.extra_len = (ep == 0) ? 0 : len; - if (ep == 0) { - usb.u.control.request_type = 0xc0; - usb.u.control.request = request; - usb.u.control.value = value; - usb.u.control.index = index; - } else { - memcpy(&usb.u.data, data, usb.extra_len); - } - - uint32_t recv[0x44/4]; - spi_comm(&usb, sizeof(usb), recv, 0x40); - - return recv[0]; -} - - -void ICACHE_FLASH_ATTR st_flash() { - if (st_firmware != NULL) { - // boot mode - os_printf("st_flash: enter boot mode\n"); - st_set_boot_mode(1); - - // echo - os_printf("st_flash: wait for echo\n"); - for (int i = 0; i < 10; i++) { - os_printf(" attempt: %d\n", i); - if (usb_cmd(0, 0, 0xb0, 0, 0, NULL) > 0) break; - } - - // unlock flash - os_printf("st_flash: unlock flash\n"); - usb_cmd(0, 0, 0xb1, 0, 0, NULL); - - // erase sector 1 - os_printf("st_flash: erase sector 1\n"); - usb_cmd(0, 0, 0xb2, 1, 0, NULL); - - if (real_content_length >= 16384) { - // erase sector 2 - os_printf("st_flash: erase sector 2\n"); - usb_cmd(0, 0, 0xb2, 2, 0, NULL); - } - - // real content length will always be 0x10 aligned - os_printf("st_flash: flashing\n"); - for (int i = 0; i < real_content_length; i += 0x10) { - int rl = MIN(0x10, real_content_length-i); - usb_cmd(2, rl, 0, 0, 0, &st_firmware[i]); - system_soft_wdt_feed(); - } - - // reboot into normal mode - os_printf("st_flash: rebooting\n"); - usb_cmd(0, 0, 0xd8, 0, 0, NULL); - - // done with this - os_free(st_firmware); - st_firmware = NULL; - } -} - -typedef enum { - NOT_STARTED, - CONNECTION_ESTABLISHED, - RECEIVING_HEADER, - RECEIVING_ST_FIRMWARE, - RECEIVING_ESP_FIRMWARE, - REBOOTING, - ERROR -} web_state_t; - -web_state_t state = NOT_STARTED; -int esp_address, esp_address_erase_limit, start_address; - -void ICACHE_FLASH_ATTR hexdump(char *data, int len) { - int i; - for (i=0;isecure it"); - } - - ets_strcat(resp,"\nSet USB Mode:" - "" - "" - "\n"); - - ets_strcat(resp, pagefooter); - - espconn_send_string(&web_conn, resp); - espconn_disconnect(conn); - } else if (memcmp(data, "GET /secure", 11) == 0 && !wifi_secure_mode) { - wifi_configure(1); - } else if (memcmp(data, "GET /set_property?usb_mode=", 27) == 0 && wifi_secure_mode) { - char mode_value = data[27] - '0'; - if (mode_value >= '\x00' && mode_value <= '\x02') { - memset(resp, 0, MAX_RESP); - char set_usb_mode_packet[] = "\x00\x00\x00\x00\x40\xE6\x00\x00\x00\x00\x40\x00"; - set_usb_mode_packet[6] = mode_value; - uint32_t recvData[1]; - spi_comm(set_usb_mode_packet, 0xC, recvData, 0); - os_sprintf(resp, "%sUSB Mode set to %02x\n\n", OK_header, mode_value); - espconn_send_string(&web_conn, resp); - espconn_disconnect(conn); - } - } else if (memcmp(data, "PUT /stupdate ", 14) == 0 && wifi_secure_mode) { - os_printf("init st firmware\n"); - char *cl = strstr(data, "Content-Length: "); - if (cl != NULL) { - // get content length - cl += strlen("Content-Length: "); - content_length = skip_atoi(&cl); - os_printf("with content length %d\n", content_length); - - // should be small enough to fit in RAM - real_content_length = (content_length+0xF)&(~0xF); - st_firmware_ptr = st_firmware = os_malloc(real_content_length); - memset(st_firmware, 0, real_content_length); - state = RECEIVING_ST_FIRMWARE; - } - - } else if (((memcmp(data, "PUT /espupdate1 ", 16) == 0) || - (memcmp(data, "PUT /espupdate2 ", 16) == 0)) && wifi_secure_mode) { - // 0x1000 = user1.bin - // 0x81000 = user2.bin - // 0x3FE000 = blank.bin - os_printf("init esp firmware\n"); - char *cl = strstr(data, "Content-Length: "); - if (cl != NULL) { - // get content length - cl += strlen("Content-Length: "); - content_length = skip_atoi(&cl); - os_printf("with content length %d\n", content_length); - - // setup flashing - uint8_t current = system_upgrade_userbin_check(); - if (data[14] == '2' && current == UPGRADE_FW_BIN1) { - os_printf("flashing boot2.bin\n"); - state = RECEIVING_ESP_FIRMWARE; - esp_address = 4*1024 + FIRMWARE_SIZE + 16*1024 + 4*1024; - } else if (data[14] == '1' && current == UPGRADE_FW_BIN2) { - os_printf("flashing boot1.bin\n"); - state = RECEIVING_ESP_FIRMWARE; - esp_address = 4*1024; - } else { - espconn_send_string(&web_conn, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\nwrong!\n"); - espconn_disconnect(conn); - } - esp_address_erase_limit = esp_address; - start_address = esp_address; - } - } else { - espconn_send_string(&web_conn, "HTTP/1.0 404 Not Found\nContent-Type: text/html\n\n404 Not Found!\n"); - espconn_disconnect(conn); - } - } else if (state == RECEIVING_ST_FIRMWARE) { - os_printf("receiving st firmware: %d/%d\n", len, content_length); - memcpy(st_firmware_ptr, data, MIN(content_length, len)); - st_firmware_ptr += len; - content_length -= len; - - if (content_length <= 0 && real_content_length > 1000) { - state = NOT_STARTED; - os_printf("done!\n"); - espconn_send_string(&web_conn, "HTTP/1.0 200 OK\nContent-Type: text/html\n\nsuccess!\n"); - espconn_disconnect(conn); - - // reboot - os_printf("Scheduling st_flash in 100ms.\n"); - os_timer_disarm(&ota_reboot_timer); - os_timer_setfn(&ota_reboot_timer, (os_timer_func_t *)st_flash, NULL); - os_timer_arm(&ota_reboot_timer, 100, 0); - } - } else if (state == RECEIVING_ESP_FIRMWARE) { - if ((esp_address+len) < (start_address + FIRMWARE_SIZE)) { - os_printf("receiving esp firmware: %d/%d -- 0x%x - 0x%x\n", len, content_length, - esp_address, esp_address_erase_limit); - content_length -= len; - while (esp_address_erase_limit < (esp_address + len)) { - os_printf("erasing 0x%X\n", esp_address_erase_limit); - spi_flash_erase_sector(esp_address_erase_limit / SPI_FLASH_SEC_SIZE); - esp_address_erase_limit += SPI_FLASH_SEC_SIZE; - } - SpiFlashOpResult res = spi_flash_write(esp_address, data, len); - if (res != SPI_FLASH_RESULT_OK) { - os_printf("flash fail @ 0x%x\n", esp_address); - } - esp_address += len; - - if (content_length == 0) { - - char digest[SHA_DIGEST_SIZE]; - uint32_t rsa[RSANUMBYTES/4]; - uint32_t dat[0x80/4]; - int ll; - spi_flash_read(esp_address-RSANUMBYTES, rsa, RSANUMBYTES); - - // 32-bit aligned accesses only - SHA_CTX ctx; - SHA_init(&ctx); - for (ll = start_address; ll < esp_address-RSANUMBYTES; ll += 0x80) { - spi_flash_read(ll, dat, 0x80); - SHA_update(&ctx, dat, MIN((esp_address-RSANUMBYTES)-ll, 0x80)); - } - memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE); - - if (RSA_verify(&releaseesp_rsa_key, rsa, RSANUMBYTES, digest, SHA_DIGEST_SIZE) || - #ifdef ALLOW_DEBUG - RSA_verify(&debugesp_rsa_key, rsa, RSANUMBYTES, digest, SHA_DIGEST_SIZE) - #else - false - #endif - ) { - os_printf("RSA verify success!\n"); - espconn_send_string(&web_conn, "HTTP/1.0 200 OK\nContent-Type: text/html\n\nsuccess!\n"); - system_upgrade_flag_set(UPGRADE_FLAG_FINISH); - - // reboot - os_printf("Scheduling reboot.\n"); - os_timer_disarm(&ota_reboot_timer); - os_timer_setfn(&ota_reboot_timer, (os_timer_func_t *)system_upgrade_reboot, NULL); - os_timer_arm(&ota_reboot_timer, 2000, 0); - } else { - os_printf("RSA verify FAILURE\n"); - espconn_send_string(&web_conn, "HTTP/1.0 500 Internal Server Error\nContent-Type: text/html\n\nrsa verify fail\n"); - } - espconn_disconnect(conn); - } - } - } -} - -void ICACHE_FLASH_ATTR web_tcp_connect_cb(void *arg) { - state = CONNECTION_ESTABLISHED; - struct espconn *conn = (struct espconn *)arg; - espconn_set_opt(&web_conn, ESPCONN_NODELAY); - espconn_regist_recvcb(conn, web_rx_cb); -} - -void ICACHE_FLASH_ATTR web_init() { - web_proto.local_port = 80; - web_conn.type = ESPCONN_TCP; - web_conn.state = ESPCONN_NONE; - web_conn.proto.tcp = &web_proto; - espconn_regist_connectcb(&web_conn, web_tcp_connect_cb); - espconn_accept(&web_conn); -} - diff --git a/panda/buy.png b/panda/buy.png deleted file mode 100644 index a4a9e0fd40a4268a6b88b068bd6cdc7dd095ab01..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12200 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 C>W0Js diff --git a/panda/certs/debug b/panda/certs/debug deleted file mode 100644 index 39864b6b1a..0000000000 --- a/panda/certs/debug +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXQIBAAKBgQC948lnRo4x44Rd7Y8bQAML4aKDC4XRx958fHV8K6+FbCaP1Z42 -U2kX0yygak0LjoDutpgObmGHZA+Iz3HeUD6VGjr/teN24vPk+A95cRsjt8rgmGQ9 -6HNjaNgjR+gl1F9XxFimMzir82Xpl1ekTueJNXa7ia5HVH1nFdiksOKHGQIDAQAB -AoGAQuPw2I6EHJLW1/eNB75e1FqhUqRGeYV8nEGDaUBCTi+wzc4kM2LijF/5QnDv -vvht9qkfm0XK2VSoHDtnEzcVM/l1ksb68n4R/1nUooAWY6cQI7dCSk/A6yS1EJFg -BXsgGbT/65khw9pzBW2zVtMVcVNWFayqfCO1I9WcDdA1x1kCQQDfrhoZTZNoDEUE -JKM4fiUdWr1h3Aw8KLJFFexSWeGDwo+qqnujYcKWkHa9qaH1RG5x8Kir9s9Oi4Js -mzKwov8fAkEA2VPJPWxJ4vVQpXle6wC1nyoL7s739yxMWFcabvkzDDhlIVBNdVJd -gZKsFWV7QnVNdDMjn9D27FwKu3i2D+kKxwJBANp1SMojqO765MEKI1t+YDNONx6H -cm+i85Fjuv4nCIjOEdCGVuCYDxtMFpxgO2y3HAMuHx5sm8XDnWsDHLvFRdMCQD7V -XqWHnYUk8AAnqy2+ssQl3/VXmZG5GQmhhV74Za3u0C5ljT+SZL6FrYMyKAT67T3f -WzllrT6BDglNyTWoZxkCQQCt0XSoGM3603GGYNt6AUlGSgtXSo/2Px7odGUtQoKA -FH9q6FVMYpQJ38spZxIGufZJmLP8LLg6YIWJj1F+akxr ------END RSA PRIVATE KEY----- diff --git a/panda/certs/debug.pub b/panda/certs/debug.pub deleted file mode 100644 index 00e219d7bb..0000000000 --- a/panda/certs/debug.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQC948lnRo4x44Rd7Y8bQAML4aKDC4XRx958fHV8K6+FbCaP1Z42U2kX0yygak0LjoDutpgObmGHZA+Iz3HeUD6VGjr/teN24vPk+A95cRsjt8rgmGQ96HNjaNgjR+gl1F9XxFimMzir82Xpl1ekTueJNXa7ia5HVH1nFdiksOKHGQ== batman@y840 diff --git a/panda/certs/debugesp b/panda/certs/debugesp deleted file mode 100644 index 789beaac19..0000000000 --- a/panda/certs/debugesp +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgQCjIHvrSCWN0Nec6ozbImYik30PIF7JSWgdwDKTxSJ05RM3pj5E -LQEGt3qcaVrTokO68tpt5Gu1p6ZsNqWg7iVTW9M7Qj7IH45YDzQP/PSRjgSosQA6 -6f5Gokba5QrW38myqimvj+0p+YH+CNGCBRlTUQGCO8uLCspMZneRSLPW9QIDAQAB -AoGADaUn+HRef9BaWMvd4G6uMHI54cwJYbj8NpDfKjExQqnuw5bqWnWRQmiSnwbJ -DC7kj3zE/LBAuj890ot3q1CAWqh47ZICZfoX9Qbi5TpvIHFCGy6YkOliF6iIQhR2 -4+zNKTAA0zNKskOM25PdI+grK1Ni/bEofSA6TrqvEwsmxnkCQQDVp9FUUor2Bo/h -/3oAIP51LTw7vfpztYbJr+BDV63czV2DLXzSwzeNrwH4sA3oy1mjUgMBBgAarNGE -DYlc4H5jAkEAw3UCHzzXPlxkw2QGp7nBly5y3p80Uqc31NuYz8rdX/U8KTngi2No -Ft/SGCEXNpeYbToj+WK3RJJ2Ey0mK8+IxwJAcpGd/5CPsaQNLcw4WK9Yo+8Q2Jxk -G/4gfDCSmqn+smNxnLEcuUwzkwdgkEGgA9BfjeOhdsAH+EXpx90WZrZ/LwJBAK0k -jq+rTqUQZbZsejTEKYjJ/bnV4BzDwoKN0Q1pkLc7X4LJoW74rTFuLgdv8MdMfRtt -IIb/eoeFEpGkMicnHesCQHgR7BTUGBM6Uxam7RCdsgVsxoHBma21E/44ivWUMZzN -3oVt0mPnjS4speOlqwED5pCJ7yw7jwLPFMs8kNxuIKU= ------END RSA PRIVATE KEY----- diff --git a/panda/certs/debugesp.pub b/panda/certs/debugesp.pub deleted file mode 100644 index 3afcf3988e..0000000000 --- a/panda/certs/debugesp.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQCjIHvrSCWN0Nec6ozbImYik30PIF7JSWgdwDKTxSJ05RM3pj5ELQEGt3qcaVrTokO68tpt5Gu1p6ZsNqWg7iVTW9M7Qj7IH45YDzQP/PSRjgSosQA66f5Gokba5QrW38myqimvj+0p+YH+CNGCBRlTUQGCO8uLCspMZneRSLPW9Q== batman@y840 diff --git a/panda/certs/release.pub b/panda/certs/release.pub deleted file mode 100644 index 19066e29a7..0000000000 --- a/panda/certs/release.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDGN9GU2nOc0kKq6vdZI5qUMzHt234ngqofrgCFFxL0D2Whex0zACp9gar0HZp+bvtpoSgU/Ev8wexNKr+A9QTradljiuxi5ctrOra9k+wxqNj63Wrcu4+wU5UnJEVf/buV4jCOFffMT8z3PO4imt8LzHuEIC/m/ASKVYyvuvBRQQ== batman@y840 diff --git a/panda/certs/releaseesp.pub b/panda/certs/releaseesp.pub deleted file mode 100644 index 1d1d54bb7e..0000000000 --- a/panda/certs/releaseesp.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAgQDN4pVyGuJJSde1l3Fjay8qPxog09DsAJZtYPk+armoYO1L6YKReUTcMNyHQYZZMZFmhCdgjCgTIF2QYWMoP4KSe8l6JF04YPP51dIgefc6UXjtlSI8Pyutr0v9xXjSfsVm3RAJxDSHgzs9AoMsluKCL+LhAR1nd7cuHXITJ80O4w== batman@y840 diff --git a/panda/common/version.mk b/panda/common/version.mk deleted file mode 100644 index cc66efaa6d..0000000000 --- a/panda/common/version.mk +++ /dev/null @@ -1,20 +0,0 @@ -ifeq ($(RELEASE),1) - BUILD_TYPE = "RELEASE" -else - BUILD_TYPE = "DEBUG" -endif - -SELF_DIR := $(dir $(lastword $(MAKEFILE_LIST))) - -ifneq ($(wildcard $(SELF_DIR)/../.git/HEAD),) -obj/gitversion.h: $(SELF_DIR)/../VERSION $(SELF_DIR)/../.git/HEAD $(SELF_DIR)/../.git/index - echo "const uint8_t gitversion[] = \"$(shell cat $(SELF_DIR)/../VERSION)-$(BUILDER)-$(shell git rev-parse --short=8 HEAD)-$(BUILD_TYPE)\";" > $@ -else -ifneq ($(wildcard $(SELF_DIR)/../../.git/modules/panda/HEAD),) -obj/gitversion.h: $(SELF_DIR)/../VERSION $(SELF_DIR)/../../.git/modules/panda/HEAD $(SELF_DIR)/../../.git/modules/panda/index - echo "const uint8_t gitversion[] = \"$(shell cat $(SELF_DIR)/../VERSION)-$(BUILDER)-$(shell git rev-parse --short=8 HEAD)-$(BUILD_TYPE)\";" > $@ -else -obj/gitversion.h: $(SELF_DIR)/../VERSION - echo "const uint8_t gitversion[] = \"$(shell cat $(SELF_DIR)/../VERSION)-$(BUILDER)-unknown-$(BUILD_TYPE)\";" > $@ -endif -endif diff --git a/panda/crypto/getcertheader.py b/panda/crypto/getcertheader.py deleted file mode 100755 index bbbe475ef8..0000000000 --- a/panda/crypto/getcertheader.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python3 -import sys -from Crypto.PublicKey import RSA - -def egcd(a, b): - if a == 0: - return (b, 0, 1) - else: - g, y, x = egcd(b % a, a) - return (g, x - (b // a) * y, y) - -def modinv(a, m): - g, x, y = egcd(a, m) - if g != 1: - raise Exception('modular inverse does not exist') - else: - return x % m - -def to_c_string(x): - mod = (hex(x)[2:-1].rjust(0x100, '0')) - hh = ''.join('\\x'+mod[i:i+2] for i in range(0, 0x100, 2)) - return hh - -def to_c_uint32(x): - nums = [] - for i in range(0x20): - nums.append(x%(2**32)) - x //= (2**32) - return "{"+'U,'.join(map(str, nums))+"U}" - -for fn in sys.argv[1:]: - rsa = RSA.importKey(open(fn).read()) - rr = pow(2**1024, 2, rsa.n) - n0inv = 2**32 - modinv(rsa.n, 2**32) - - cname = fn.split("/")[-1].split(".")[0] + "_rsa_key" - - print('RSAPublicKey '+cname+' = {.len = 0x20,') - print(' .n0inv = %dU,' % n0inv) - print(' .n = %s,' % to_c_uint32(rsa.n)) - print(' .rr = %s,' % to_c_uint32(rr)) - print(' .exponent = %d,' % rsa.e) - print('};') - - diff --git a/panda/crypto/hash-internal.h b/panda/crypto/hash-internal.h deleted file mode 100644 index 05ec3ec9fd..0000000000 --- a/panda/crypto/hash-internal.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright 2007 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ - -#include "stdint.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -struct HASH_CTX; // forward decl - -typedef struct HASH_VTAB { - void (* const init)(struct HASH_CTX*); - void (* const update)(struct HASH_CTX*, const void*, int); - const uint8_t* (* const final)(struct HASH_CTX*); - const uint8_t* (* const hash)(const void*, int, uint8_t*); - int size; -} HASH_VTAB; - -typedef struct HASH_CTX { - const HASH_VTAB * f; - uint64_t count; - uint8_t buf[64]; - uint32_t state[8]; // upto SHA2 -} HASH_CTX; - -#define HASH_init(ctx) (ctx)->f->init(ctx) -#define HASH_update(ctx, data, len) (ctx)->f->update(ctx, data, len) -#define HASH_final(ctx) (ctx)->f->final(ctx) -#define HASH_hash(data, len, digest) (ctx)->f->hash(data, len, digest) -#define HASH_size(ctx) (ctx)->f->size - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_HASH_INTERNAL_H_ diff --git a/panda/crypto/rsa.c b/panda/crypto/rsa.c deleted file mode 100644 index 24171e8790..0000000000 --- a/panda/crypto/rsa.c +++ /dev/null @@ -1,294 +0,0 @@ -/* rsa.c -** -** Copyright 2012, The Android Open Source Project -** -** Redistribution and use in source and binary forms, with or without -** modification, are permitted provided that the following conditions are met: -** * Redistributions of source code must retain the above copyright -** notice, this list of conditions and the following disclaimer. -** * Redistributions in binary form must reproduce the above copyright -** notice, this list of conditions and the following disclaimer in the -** documentation and/or other materials provided with the distribution. -** * Neither the name of Google Inc. nor the names of its contributors may -** be used to endorse or promote products derived from this software -** without specific prior written permission. -** -** THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR -** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -** EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -** PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; -** OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR -** OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -** ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "rsa.h" -#include "sha.h" - -// a[] -= mod -static void subM(const RSAPublicKey* key, - uint32_t* a) { - int64_t A = 0; - int i; - for (i = 0; i < key->len; ++i) { - A += (uint64_t)a[i] - key->n[i]; - a[i] = (uint32_t)A; - A >>= 32; - } -} - -// return a[] >= mod -static int geM(const RSAPublicKey* key, - const uint32_t* a) { - int i; - for (i = key->len; i;) { - --i; - if (a[i] < key->n[i]) return 0; - if (a[i] > key->n[i]) return 1; - } - return 1; // equal -} - -// montgomery c[] += a * b[] / R % mod -static void montMulAdd(const RSAPublicKey* key, - uint32_t* c, - const uint32_t a, - const uint32_t* b) { - uint64_t A = (uint64_t)a * b[0] + c[0]; - uint32_t d0 = (uint32_t)A * key->n0inv; - uint64_t B = (uint64_t)d0 * key->n[0] + (uint32_t)A; - int i; - - for (i = 1; i < key->len; ++i) { - A = (A >> 32) + (uint64_t)a * b[i] + c[i]; - B = (B >> 32) + (uint64_t)d0 * key->n[i] + (uint32_t)A; - c[i - 1] = (uint32_t)B; - } - - A = (A >> 32) + (B >> 32); - - c[i - 1] = (uint32_t)A; - - if (A >> 32) { - subM(key, c); - } -} - -// montgomery c[] = a[] * b[] / R % mod -static void montMul(const RSAPublicKey* key, - uint32_t* c, - const uint32_t* a, - const uint32_t* b) { - int i; - for (i = 0; i < key->len; ++i) { - c[i] = 0; - } - for (i = 0; i < key->len; ++i) { - montMulAdd(key, c, a[i], b); - } -} - -// In-place public exponentiation. -// Input and output big-endian byte array in inout. -static void modpow(const RSAPublicKey* key, - uint8_t* inout) { - uint32_t a[RSANUMWORDS]; - uint32_t aR[RSANUMWORDS]; - uint32_t aaR[RSANUMWORDS]; - uint32_t* aaa = 0; - int i; - - // Convert from big endian byte array to little endian word array. - for (i = 0; i < key->len; ++i) { - uint32_t tmp = - (inout[((key->len - 1 - i) * 4) + 0] << 24) | - (inout[((key->len - 1 - i) * 4) + 1] << 16) | - (inout[((key->len - 1 - i) * 4) + 2] << 8) | - (inout[((key->len - 1 - i) * 4) + 3] << 0); - a[i] = tmp; - } - - if (key->exponent == 65537) { - aaa = aaR; // Re-use location. - montMul(key, aR, a, key->rr); // aR = a * RR / R mod M - for (i = 0; i < 16; i += 2) { - montMul(key, aaR, aR, aR); // aaR = aR * aR / R mod M - montMul(key, aR, aaR, aaR); // aR = aaR * aaR / R mod M - } - montMul(key, aaa, aR, a); // aaa = aR * a / R mod M - } else if (key->exponent == 3) { - aaa = aR; // Re-use location. - montMul(key, aR, a, key->rr); /* aR = a * RR / R mod M */ - montMul(key, aaR, aR, aR); /* aaR = aR * aR / R mod M */ - montMul(key, aaa, aaR, a); /* aaa = aaR * a / R mod M */ - } - - // Make sure aaa < mod; aaa is at most 1x mod too large. - if (geM(key, aaa)) { - subM(key, aaa); - } - - // Convert to bigendian byte array - for (i = key->len - 1; i >= 0; --i) { - uint32_t tmp = aaa[i]; - *inout++ = tmp >> 24; - *inout++ = tmp >> 16; - *inout++ = tmp >> 8; - *inout++ = tmp >> 0; - } -} - -// Expected PKCS1.5 signature padding bytes, for a keytool RSA signature. -// Has the 0-length optional parameter encoded in the ASN1 (as opposed to the -// other flavor which omits the optional parameter entirely). This code does not -// accept signatures without the optional parameter. - -/* -static const uint8_t sha_padding[RSANUMBYTES] = { - 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0x00, 0x30, 0x21, 0x30, - 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, - 0x05, 0x00, 0x04, 0x14, - - // 20 bytes of hash go here. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; -*/ - -static const uint8_t sha_padding_1024[RSANUMBYTES] = { - 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x00, - - // 20 bytes of hash go here. - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 -}; - -// SHA-1 of PKCS1.5 signature sha_padding for 2048 bit, as above. -// At the location of the bytes of the hash all 00 are hashed. -/*static const uint8_t kExpectedPadShaRsa2048[SHA_DIGEST_SIZE] = { - 0xdc, 0xbd, 0xbe, 0x42, 0xd5, 0xf5, 0xa7, 0x2e, - 0x6e, 0xfc, 0xf5, 0x5d, 0xaf, 0x9d, 0xea, 0x68, - 0x7c, 0xfb, 0xf1, 0x67 -};*/ - -// Verify a 2048-bit RSA PKCS1.5 signature against an expected hash. -// Both e=3 and e=65537 are supported. hash_len may be -// SHA_DIGEST_SIZE (== 20) to indicate a SHA-1 hash, or -// SHA256_DIGEST_SIZE (== 32) to indicate a SHA-256 hash. No other -// values are supported. -// -// Returns 1 on successful verification, 0 on failure. -int RSA_verify(const RSAPublicKey *key, - const uint8_t *signature, - const int len, - const uint8_t *hash, - const int hash_len) { - uint8_t buf[RSANUMBYTES]; - int i; - //const uint8_t* padding_hash; - - if (key->len != RSANUMWORDS) { - return 0; // Wrong key passed in. - } - - if (len != sizeof(buf)) { - return 0; // Wrong input length. - } - - if (hash_len != SHA_DIGEST_SIZE) { - return 0; // Unsupported hash. - } - - if (key->exponent != 3 && key->exponent != 65537) { - return 0; // Unsupported exponent. - } - - for (i = 0; i < len; ++i) { // Copy input to local workspace. - buf[i] = signature[i]; - } - - modpow(key, buf); // In-place exponentiation. - -#ifdef TEST_RSA - printf("sig\n"); - for (i=0;i> (32 - (bits)))) - -static void SHA1_Transform(SHA_CTX* ctx) { - uint32_t W[80]; - uint32_t A, B, C, D, E; - uint8_t* p = ctx->buf; - int t; - - for(t = 0; t < 16; ++t) { - uint32_t tmp = *p++ << 24; - tmp |= *p++ << 16; - tmp |= *p++ << 8; - tmp |= *p++; - W[t] = tmp; - } - - for(; t < 80; t++) { - W[t] = rol(1,W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16]); - } - - A = ctx->state[0]; - B = ctx->state[1]; - C = ctx->state[2]; - D = ctx->state[3]; - E = ctx->state[4]; - - for(t = 0; t < 80; t++) { - uint32_t tmp = rol(5,A) + E + W[t]; - - if (t < 20) - tmp += (D^(B&(C^D))) + 0x5A827999; - else if ( t < 40) - tmp += (B^C^D) + 0x6ED9EBA1; - else if ( t < 60) - tmp += ((B&C)|(D&(B|C))) + 0x8F1BBCDC; - else - tmp += (B^C^D) + 0xCA62C1D6; - - E = D; - D = C; - C = rol(30,B); - B = A; - A = tmp; - } - - ctx->state[0] += A; - ctx->state[1] += B; - ctx->state[2] += C; - ctx->state[3] += D; - ctx->state[4] += E; -} - -static const HASH_VTAB SHA_VTAB = { - SHA_init, - SHA_update, - SHA_final, - SHA_hash, - SHA_DIGEST_SIZE -}; - -void SHA_init(SHA_CTX* ctx) { - ctx->f = &SHA_VTAB; - ctx->state[0] = 0x67452301; - ctx->state[1] = 0xEFCDAB89; - ctx->state[2] = 0x98BADCFE; - ctx->state[3] = 0x10325476; - ctx->state[4] = 0xC3D2E1F0; - ctx->count = 0; -} - - -void SHA_update(SHA_CTX* ctx, const void* data, int len) { - int i = (int) (ctx->count & 63); - const uint8_t* p = (const uint8_t*)data; - - ctx->count += len; - - while (len--) { - ctx->buf[i++] = *p++; - if (i == 64) { - SHA1_Transform(ctx); - i = 0; - } - } -} - - -const uint8_t* SHA_final(SHA_CTX* ctx) { - uint8_t *p = ctx->buf; - uint64_t cnt = ctx->count * 8; - int i; - - SHA_update(ctx, (uint8_t*)"\x80", 1); - while ((ctx->count & 63) != 56) { - SHA_update(ctx, (uint8_t*)"\0", 1); - } - - /* Hack - right shift operator with non const argument requires - * libgcc.a which is missing in EON - * thus expanding for loop from - - for (i = 0; i < 8; ++i) { - uint8_t tmp = (uint8_t) (cnt >> ((7 - i) * 8)); - SHA_update(ctx, &tmp, 1); - } - - to - */ - - uint8_t tmp = 0; - tmp = (uint8_t) (cnt >> ((7 - 0) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 1) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 2) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 3) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 4) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 5) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 6) * 8)); - SHA_update(ctx, &tmp, 1); - tmp = (uint8_t) (cnt >> ((7 - 7) * 8)); - SHA_update(ctx, &tmp, 1); - - for (i = 0; i < 5; i++) { - uint32_t tmp = ctx->state[i]; - *p++ = tmp >> 24; - *p++ = tmp >> 16; - *p++ = tmp >> 8; - *p++ = tmp >> 0; - } - - return ctx->buf; -} - -/* Convenience function */ -const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest) { - SHA_CTX ctx; - SHA_init(&ctx); - SHA_update(&ctx, data, len); - memcpy(digest, SHA_final(&ctx), SHA_DIGEST_SIZE); - return digest; -} diff --git a/panda/crypto/sha.h b/panda/crypto/sha.h deleted file mode 100644 index 4b51a531bf..0000000000 --- a/panda/crypto/sha.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2005 The Android Open Source Project - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of Google Inc. nor the names of its contributors may - * be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO - * EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#ifndef SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ -#define SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ - -#include "hash-internal.h" - -#ifdef __cplusplus -extern "C" { -#endif // __cplusplus - -typedef HASH_CTX SHA_CTX; - -void SHA_init(SHA_CTX* ctx); -void SHA_update(SHA_CTX* ctx, const void* data, int len); -const uint8_t* SHA_final(SHA_CTX* ctx); - -// Convenience method. Returns digest address. -// NOTE: *digest needs to hold SHA_DIGEST_SIZE bytes. -const uint8_t* SHA_hash(const void* data, int len, uint8_t* digest); - -#define SHA_DIGEST_SIZE 20 - -#ifdef __cplusplus -} -#endif // __cplusplus - -#endif // SYSTEM_CORE_INCLUDE_MINCRYPT_SHA1_H_ diff --git a/panda/crypto/sign.py b/panda/crypto/sign.py deleted file mode 100755 index 8cbe6f4195..0000000000 --- a/panda/crypto/sign.py +++ /dev/null @@ -1,37 +0,0 @@ -#!/usr/bin/env python3 -import os -import sys -import struct -import hashlib -from Crypto.PublicKey import RSA -import binascii - -# increment this to make new hardware not run old versions -VERSION = 2 - -rsa = RSA.importKey(open(sys.argv[3]).read()) - -with open(sys.argv[1], "rb") as f: - dat = f.read() - -print("signing", len(dat), "bytes") - -with open(sys.argv[2], "wb") as f: - if os.getenv("SETLEN") is not None: - # add the version at the end - dat += b"VERS" + struct.pack("I", VERSION) - # add the length at the beginning - x = struct.pack("I", len(dat)) + dat[4:] - # mock signature of dat[4:] - dd = hashlib.sha1(dat[4:]).digest() - else: - x = dat - dd = hashlib.sha1(dat).digest() - - print("hash:", str(binascii.hexlify(dd), "utf-8")) - dd = b"\x00\x01" + b"\xff"*0x69 + b"\x00" + dd - rsa_out = pow(int.from_bytes(dd, byteorder='big', signed=False), rsa.d, rsa.n) - sig = (hex(rsa_out)[2:].rjust(0x100, '0')) - x += binascii.unhexlify(sig) - f.write(x) - diff --git a/panda/crypto/stdint.h b/panda/crypto/stdint.h deleted file mode 100644 index 67ac93ed75..0000000000 --- a/panda/crypto/stdint.h +++ /dev/null @@ -1,4 +0,0 @@ -#define uint8_t unsigned char -#define uint32_t unsigned int -#define int64_t long long -#define uint64_t unsigned long long diff --git a/panda/docs/guide.pdf b/panda/docs/guide.pdf deleted file mode 100644 index 5dbc95680aa4f77e7278af945726749f93192875..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2873505 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

W!8v?@?SX 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

This is your comma.ai panda\n\n"
-"It's open source. Find the code here\n";
-
-char pagefooter[] = "