From df5cc1b07859f87306962567b415e86e043dce5b Mon Sep 17 00:00:00 2001 From: tcd <1369013595@qq.com> Date: Tue, 7 Apr 2026 08:25:55 +0000 Subject: [PATCH 1/7] feat(i2c): Add I2C0 protocol and RmcsBoard support --- .codex | 0 core/include/librmcs/data/datas.hpp | 20 +++ core/src/protocol/deserializer.cpp | 85 ++++++++++++ core/src/protocol/deserializer.hpp | 12 ++ core/src/protocol/protocol.hpp | 15 +++ core/src/protocol/serializer.hpp | 148 +++++++++++++++++++++ firmware/c_board/app/src/usb/vendor.hpp | 24 ++++ firmware/rmcs_board/app/src/app.cpp | 2 + firmware/rmcs_board/app/src/i2c/i2c.hpp | 110 +++++++++++++++ firmware/rmcs_board/app/src/usb/vendor.hpp | 31 +++++ firmware/rmcs_board/bsp/hpm_sdk | 2 +- host/include/librmcs/agent/c_board.hpp | 11 ++ host/include/librmcs/agent/rmcs_board.hpp | 30 +++++ host/include/librmcs/protocol/handler.hpp | 7 + host/src/protocol/handler.cpp | 58 ++++++++ 15 files changed, 554 insertions(+), 1 deletion(-) create mode 100644 .codex create mode 100644 firmware/rmcs_board/app/src/i2c/i2c.hpp diff --git a/.codex b/.codex new file mode 100644 index 0000000..e69de29 diff --git a/core/include/librmcs/data/datas.hpp b/core/include/librmcs/data/datas.hpp index afa015c..225fc28 100644 --- a/core/include/librmcs/data/datas.hpp +++ b/core/include/librmcs/data/datas.hpp @@ -27,6 +27,8 @@ enum class DataId : uint8_t { kUart3 = 14, kImu = 15, + + kI2c0 = 16, }; struct CanDataView { @@ -79,6 +81,20 @@ struct GyroscopeDataView { int16_t z; }; +struct I2cDataView { + uint8_t slave_address; + std::span payload; + bool has_register = false; + uint8_t reg_address = 0; +}; + +struct I2cReadConfigView { + uint8_t slave_address; + uint16_t read_length = 0; + bool has_register = false; + uint8_t reg_address = 0; +}; + class DataCallback { public: DataCallback() = default; @@ -100,6 +116,10 @@ class DataCallback { virtual void accelerometer_receive_callback(const AccelerometerDataView& data) = 0; virtual void gyroscope_receive_callback(const GyroscopeDataView& data) = 0; + + virtual bool i2c_receive_callback(DataId id, const I2cDataView& data) = 0; + + virtual void i2c_error_callback(DataId id, uint8_t slave_address) = 0; }; } // namespace librmcs::data diff --git a/core/src/protocol/deserializer.cpp b/core/src/protocol/deserializer.cpp index 657377c..14af37f 100644 --- a/core/src/protocol/deserializer.cpp +++ b/core/src/protocol/deserializer.cpp @@ -53,6 +53,7 @@ coroutine::LifoTask Deserializer::process_stream() { case FieldId::kUart3: success = co_await process_uart_field(id); break; case FieldId::kGpio: success = co_await process_gpio_field(id); break; case FieldId::kImu: success = co_await process_imu_field(id); break; + case FieldId::kI2c0: success = co_await process_i2c_field(id); break; default: break; } if (!success) @@ -289,4 +290,88 @@ coroutine::LifoTask Deserializer::process_imu_field(FieldId) { co_return true; } +coroutine::LifoTask Deserializer::process_i2c_field(FieldId field_id) { + I2cHeader::PayloadEnum payload_type; + uint8_t slave_address = 0; + uint16_t data_length = 0; + bool has_register = false; + { + const auto* header_bytes = co_await peek_bytes(sizeof(I2cHeader)); + if (!header_bytes) [[unlikely]] + co_return false; + + auto header = I2cHeader::CRef{header_bytes}; + payload_type = header.get(); + has_register = header.get(); + slave_address = header.get(); + data_length = header.get(); + consume_peeked(); + } + + if (slave_address > 0x7F) [[unlikely]] + co_return false; + + switch (payload_type) { + case I2cHeader::PayloadEnum::kWrite: + case I2cHeader::PayloadEnum::kReadResult: { + data::I2cDataView data_view{}; + data_view.slave_address = slave_address; + data_view.has_register = has_register; + + if (has_register) { + const auto* register_bytes = co_await peek_bytes(1); + if (!register_bytes) [[unlikely]] + co_return false; + data_view.reg_address = std::to_integer(register_bytes[0]); + consume_peeked(); + } + + if (data_length) { + const auto* payload_bytes = co_await peek_bytes(data_length); + if (!payload_bytes) [[unlikely]] + co_return false; + data_view.payload = std::span{payload_bytes, data_length}; + consume_peeked(); + } else { + data_view.payload = std::span{}; + } + + if (payload_type == I2cHeader::PayloadEnum::kWrite) { + callback_.i2c_write_deserialized_callback(field_id, data_view); + } else { + callback_.i2c_read_result_deserialized_callback(field_id, data_view); + } + break; + } + case I2cHeader::PayloadEnum::kReadRequest: { + data::I2cReadConfigView data_view{}; + data_view.slave_address = slave_address; + data_view.read_length = data_length; + data_view.has_register = has_register; + + if (has_register) { + const auto* register_bytes = co_await peek_bytes(1); + if (!register_bytes) [[unlikely]] + co_return false; + data_view.reg_address = std::to_integer(register_bytes[0]); + consume_peeked(); + } + + callback_.i2c_read_config_deserialized_callback(field_id, data_view); + break; + } + case I2cHeader::PayloadEnum::kError: { + data::I2cDataView data_view{}; + data_view.slave_address = slave_address; + data_view.payload = std::span{}; + data_view.has_register = false; + callback_.i2c_error_deserialized_callback(field_id, data_view); + break; + } + default: co_return false; + } + + co_return true; +} + } // namespace librmcs::core::protocol diff --git a/core/src/protocol/deserializer.hpp b/core/src/protocol/deserializer.hpp index a8a74f0..7ce9b7b 100644 --- a/core/src/protocol/deserializer.hpp +++ b/core/src/protocol/deserializer.hpp @@ -41,6 +41,16 @@ class DeserializeCallback { virtual void gyroscope_deserialized_callback(const data::GyroscopeDataView& data) = 0; + virtual void i2c_write_deserialized_callback(FieldId id, const data::I2cDataView& data) = 0; + + virtual void + i2c_read_config_deserialized_callback(FieldId id, const data::I2cReadConfigView& data) = 0; + + virtual void + i2c_read_result_deserialized_callback(FieldId id, const data::I2cDataView& data) = 0; + + virtual void i2c_error_deserialized_callback(FieldId id, const data::I2cDataView& data) = 0; + virtual void error_callback() = 0; }; @@ -115,6 +125,8 @@ class Deserializer : private coroutine::InlineLifoContext<1024> { coroutine::LifoTask process_imu_field(FieldId field_id); + coroutine::LifoTask process_i2c_field(FieldId field_id); + // Await until at least `size` contiguous bytes are available at the current read position. // Returns a pointer to a contiguous region of at least `size` bytes. // (from input buffer or pending cache) diff --git a/core/src/protocol/protocol.hpp b/core/src/protocol/protocol.hpp index ba64224..d5abc46 100644 --- a/core/src/protocol/protocol.hpp +++ b/core/src/protocol/protocol.hpp @@ -130,4 +130,19 @@ struct ImuGyroscopePayload : utility::Bitfield<6> { using Z = utility::BitfieldMember<32, 16, int16_t>; }; +struct I2cHeader : utility::Bitfield<3> { + enum class PayloadEnum : uint8_t { + kWrite = 0, + kReadRequest = 1, + kReadResult = 2, + kError = 3, + }; + + using PayloadType = utility::BitfieldMember<4, 2, PayloadEnum>; + using HasRegister = utility::BitfieldMember<6, 1>; + using ErrorFlag = utility::BitfieldMember<7, 1>; + using SlaveAddress = utility::BitfieldMember<8, 7>; + using DataLength = utility::BitfieldMember<15, 9>; +}; + } // namespace librmcs::core::protocol diff --git a/core/src/protocol/serializer.hpp b/core/src/protocol/serializer.hpp index 911349a..cd14315 100644 --- a/core/src/protocol/serializer.hpp +++ b/core/src/protocol/serializer.hpp @@ -334,7 +334,130 @@ class Serializer { return SerializeResult::kSuccess; } + SerializeResult write_i2c_write(FieldId field_id, const data::I2cDataView& view) noexcept { + const std::size_t required = required_i2c_size( + field_id, I2cHeader::PayloadEnum::kWrite, view.payload.size(), view.has_register); + LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); + LIBRMCS_VERIFY_LIKELY(view.slave_address <= 0x7F, SerializeResult::kInvalidArgument); + + auto dst = buffer_.allocate(required); + LIBRMCS_VERIFY_LIKELY(!dst.empty(), SerializeResult::kBadAlloc); + utility::assert_debug(dst.size() == required); + std::byte* cursor = dst.data(); + + write_field_header(cursor, field_id); + + auto header = I2cHeader::Ref(cursor); + cursor += sizeof(I2cHeader); + header.set(I2cHeader::PayloadEnum::kWrite); + header.set(view.has_register); + header.set(false); + header.set(view.slave_address); + header.set(static_cast(view.payload.size())); + + if (view.has_register) + *cursor++ = static_cast(view.reg_address); + + if (!view.payload.empty()) { + std::memcpy(cursor, view.payload.data(), view.payload.size()); + cursor += view.payload.size(); + } + + utility::assert_debug(cursor == dst.data() + dst.size()); + return SerializeResult::kSuccess; + } + + SerializeResult + write_i2c_read_config(FieldId field_id, const data::I2cReadConfigView& view) noexcept { + const std::size_t required = required_i2c_size( + field_id, I2cHeader::PayloadEnum::kReadRequest, view.read_length, view.has_register); + LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); + LIBRMCS_VERIFY_LIKELY(view.slave_address <= 0x7F, SerializeResult::kInvalidArgument); + + auto dst = buffer_.allocate(required); + LIBRMCS_VERIFY_LIKELY(!dst.empty(), SerializeResult::kBadAlloc); + utility::assert_debug(dst.size() == required); + std::byte* cursor = dst.data(); + + write_field_header(cursor, field_id); + + auto header = I2cHeader::Ref(cursor); + cursor += sizeof(I2cHeader); + header.set(I2cHeader::PayloadEnum::kReadRequest); + header.set(view.has_register); + header.set(false); + header.set(view.slave_address); + header.set(view.read_length); + + if (view.has_register) + *cursor++ = static_cast(view.reg_address); + + utility::assert_debug(cursor == dst.data() + dst.size()); + return SerializeResult::kSuccess; + } + + SerializeResult + write_i2c_read_result(FieldId field_id, const data::I2cDataView& view) noexcept { + const std::size_t required = required_i2c_size( + field_id, I2cHeader::PayloadEnum::kReadResult, view.payload.size(), view.has_register); + LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); + LIBRMCS_VERIFY_LIKELY(view.slave_address <= 0x7F, SerializeResult::kInvalidArgument); + + auto dst = buffer_.allocate(required); + LIBRMCS_VERIFY_LIKELY(!dst.empty(), SerializeResult::kBadAlloc); + utility::assert_debug(dst.size() == required); + std::byte* cursor = dst.data(); + + write_field_header(cursor, field_id); + + auto header = I2cHeader::Ref(cursor); + cursor += sizeof(I2cHeader); + header.set(I2cHeader::PayloadEnum::kReadResult); + header.set(view.has_register); + header.set(false); + header.set(view.slave_address); + header.set(static_cast(view.payload.size())); + + if (view.has_register) + *cursor++ = static_cast(view.reg_address); + + if (!view.payload.empty()) { + std::memcpy(cursor, view.payload.data(), view.payload.size()); + cursor += view.payload.size(); + } + + utility::assert_debug(cursor == dst.data() + dst.size()); + return SerializeResult::kSuccess; + } + + SerializeResult write_i2c_error(FieldId field_id, uint8_t slave_address) noexcept { + const std::size_t required = + required_i2c_size(field_id, I2cHeader::PayloadEnum::kError, 0, false); + LIBRMCS_VERIFY_LIKELY(required, SerializeResult::kInvalidArgument); + LIBRMCS_VERIFY_LIKELY(slave_address <= 0x7F, SerializeResult::kInvalidArgument); + + auto dst = buffer_.allocate(required); + LIBRMCS_VERIFY_LIKELY(!dst.empty(), SerializeResult::kBadAlloc); + utility::assert_debug(dst.size() == required); + std::byte* cursor = dst.data(); + + write_field_header(cursor, field_id); + + auto header = I2cHeader::Ref(cursor); + cursor += sizeof(I2cHeader); + header.set(I2cHeader::PayloadEnum::kError); + header.set(false); + header.set(true); + header.set(slave_address); + header.set(0); + + utility::assert_debug(cursor == dst.data() + dst.size()); + return SerializeResult::kSuccess; + } + private: + static constexpr bool is_i2c_field_id(FieldId field_id) { return field_id == FieldId::kI2c0; } + static constexpr bool use_extended_field_header(FieldId field_id) { utility::assert_debug(field_id != FieldId::kExtend); return static_cast(field_id) > 0xF; @@ -437,6 +560,31 @@ class Serializer { return total; } + static std::size_t required_i2c_size( + FieldId field_id, I2cHeader::PayloadEnum payload, std::size_t data_len, + bool has_register) noexcept { + LIBRMCS_VERIFY_LIKELY(is_i2c_field_id(field_id), 0); + LIBRMCS_VERIFY_LIKELY(data_len <= ((1U << 9) - 1U), 0); + switch (payload) { + case I2cHeader::PayloadEnum::kWrite: + case I2cHeader::PayloadEnum::kReadRequest: + case I2cHeader::PayloadEnum::kReadResult: + case I2cHeader::PayloadEnum::kError: break; + default: return 0; + } + + const std::size_t field_header_bytes = required_field_header_size(field_id); + const std::size_t i2c_header_bytes = sizeof(I2cHeader); + const std::size_t register_bytes = has_register ? 1 : 0; + const std::size_t payload_bytes = + payload == I2cHeader::PayloadEnum::kReadRequest ? 0 : data_len; + const std::size_t total = + (field_header_bytes + i2c_header_bytes - 1) + register_bytes + payload_bytes; + LIBRMCS_VERIFY_LIKELY(total <= kProtocolBufferSize, 0); + + return total; + } + SerializeBuffer& buffer_; }; diff --git a/firmware/c_board/app/src/usb/vendor.hpp b/firmware/c_board/app/src/usb/vendor.hpp index e86d6ed..93caa0a 100644 --- a/firmware/c_board/app/src/usb/vendor.hpp +++ b/firmware/c_board/app/src/usb/vendor.hpp @@ -128,6 +128,30 @@ class Vendor (void)data; } + void i2c_write_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + (void)id; + (void)data; + } + + void i2c_read_config_deserialized_callback( + core::protocol::FieldId id, const data::I2cReadConfigView& data) override { + (void)id; + (void)data; + } + + void i2c_read_result_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + (void)id; + (void)data; + } + + void i2c_error_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + (void)id; + (void)data; + } + void error_callback() override { core::utility::assert_failed_always(); } core::protocol::Deserializer deserializer_{*this}; diff --git a/firmware/rmcs_board/app/src/app.cpp b/firmware/rmcs_board/app/src/app.cpp index cb4b94b..47e8e03 100644 --- a/firmware/rmcs_board/app/src/app.cpp +++ b/firmware/rmcs_board/app/src/app.cpp @@ -7,6 +7,7 @@ #include "firmware/rmcs_board/app/src/can/can.hpp" #include "firmware/rmcs_board/app/src/gpio/gpio.hpp" +#include "firmware/rmcs_board/app/src/i2c/i2c.hpp" #include "firmware/rmcs_board/app/src/spi/bmi088/accel.hpp" #include "firmware/rmcs_board/app/src/spi/bmi088/gyro.hpp" #include "firmware/rmcs_board/app/src/uart/uart.hpp" @@ -35,6 +36,7 @@ App::App() { uart::uart2.init(); uart::uart3.init(); uart::uart_dbus.init(); + i2c::i2c0.init(); spi::bmi088::accelerometer.init(); spi::bmi088::gyroscope.init(); diff --git a/firmware/rmcs_board/app/src/i2c/i2c.hpp b/firmware/rmcs_board/app/src/i2c/i2c.hpp new file mode 100644 index 0000000..1917c95 --- /dev/null +++ b/firmware/rmcs_board/app/src/i2c/i2c.hpp @@ -0,0 +1,110 @@ +#pragma once + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "core/include/librmcs/data/datas.hpp" +#include "core/src/protocol/serializer.hpp" +#include "core/src/utility/assert.hpp" +#include "core/src/utility/immovable.hpp" +#include "firmware/rmcs_board/app/src/usb/helper.hpp" +#include "firmware/rmcs_board/app/src/utility/lazy.hpp" + +namespace librmcs::firmware::i2c { + +class I2c : private core::utility::Immovable { +public: + using Lazy = utility::Lazy; + + explicit I2c(data::DataId data_id, uintptr_t i2c_base) + : data_id_(data_id) + , i2c_base_(reinterpret_cast(i2c_base)) { + board_init_i2c(i2c_base_); + } + + void handle_downlink_write(const data::I2cDataView& data) { + if (data.payload.empty()) + return; + + const auto* payload = reinterpret_cast(data.payload.data()); + hpm_stat_t status = status_fail; + if (data.has_register) { + uint8_t reg_address = data.reg_address; + status = i2c_master_address_write( + i2c_base_, data.slave_address, ®_address, sizeof(reg_address), + const_cast(payload), static_cast(data.payload.size())); + } else { + status = i2c_master_write( + i2c_base_, data.slave_address, const_cast(payload), + static_cast(data.payload.size())); + } + + if (status != status_success) { + auto& serializer = usb::get_serializer(); + core::utility::assert_always( + serializer.write_i2c_error(data_id_, data.slave_address) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); + return; + } + } + + void handle_downlink_read_config(const data::I2cReadConfigView& data) { + if (data.read_length == 0 || data.read_length > kMaxDataLength) + return; + + auto* payload = reinterpret_cast(read_buffer_.data()); + hpm_stat_t status = status_fail; + if (data.has_register) { + uint8_t reg_address = data.reg_address; + status = i2c_master_address_read( + i2c_base_, data.slave_address, ®_address, sizeof(reg_address), payload, + data.read_length); + } else { + status = i2c_master_read(i2c_base_, data.slave_address, payload, data.read_length); + } + + auto& serializer = usb::get_serializer(); + if (status != status_success) { + core::utility::assert_always( + serializer.write_i2c_error(data_id_, data.slave_address) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); + return; + } + + core::utility::assert_always( + serializer.write_i2c_read_result( + data_id_, + { + .slave_address = data.slave_address, + .payload = std::span{read_buffer_.data(), data.read_length}, + .has_register = data.has_register, + .reg_address = data.reg_address + }) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); + } + +private: + static constexpr uint16_t kMaxDataLength = (1U << 9) - 1U; + + const data::DataId data_id_; + I2C_Type* i2c_base_; + std::array read_buffer_{}; +}; + +// Convert I2C pointer to base address +// Some boards define BOARD_APP_I2C_BASE as pointer (HPM_I2Cx), others don't define it +#ifndef BOARD_APP_I2C_BASE +inline constinit I2c::Lazy i2c0{data::DataId::kI2c0, HPM_I2C0_BASE}; +#else +inline constinit I2c::Lazy i2c0{ + data::DataId::kI2c0, reinterpret_cast(BOARD_APP_I2C_BASE)}; +#endif + +} // namespace librmcs::firmware::i2c diff --git a/firmware/rmcs_board/app/src/usb/vendor.hpp b/firmware/rmcs_board/app/src/usb/vendor.hpp index cd0e6c9..1fe13b9 100644 --- a/firmware/rmcs_board/app/src/usb/vendor.hpp +++ b/firmware/rmcs_board/app/src/usb/vendor.hpp @@ -18,6 +18,7 @@ #include "core/src/utility/assert.hpp" #include "core/src/utility/immovable.hpp" #include "firmware/rmcs_board/app/src/can/can.hpp" +#include "firmware/rmcs_board/app/src/i2c/i2c.hpp" #include "firmware/rmcs_board/app/src/uart/uart.hpp" #include "firmware/rmcs_board/app/src/usb/interrupt_safe_buffer.hpp" #include "firmware/rmcs_board/app/src/usb/usb_descriptors.hpp" @@ -138,6 +139,36 @@ class Vendor (void)data; } + void i2c_write_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + switch (id) { + case data::DataId::kI2c0: i2c::i2c0->handle_downlink_write(data); break; + default: core::utility::assert_failed_always(); + } + } + + void i2c_read_config_deserialized_callback( + core::protocol::FieldId id, const data::I2cReadConfigView& data) override { + switch (id) { + case data::DataId::kI2c0: i2c::i2c0->handle_downlink_read_config(data); break; + default: core::utility::assert_failed_always(); + } + } + + void i2c_read_result_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + (void)id; + (void)data; + core::utility::assert_failed_always(); + } + + void i2c_error_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + (void)id; + (void)data; + core::utility::assert_failed_always(); + } + void error_callback() override { core::utility::assert_failed_always(); } core::protocol::Deserializer deserializer_{*this}; diff --git a/firmware/rmcs_board/bsp/hpm_sdk b/firmware/rmcs_board/bsp/hpm_sdk index a82a535..132349c 160000 --- a/firmware/rmcs_board/bsp/hpm_sdk +++ b/firmware/rmcs_board/bsp/hpm_sdk @@ -1 +1 @@ -Subproject commit a82a53544d5679a43b70f390c8bbbb8e91f6b8c1 +Subproject commit 132349c9ddad3cbeca7211345d5d6086355f20b9 diff --git a/host/include/librmcs/agent/c_board.hpp b/host/include/librmcs/agent/c_board.hpp index 7816fce..882e8d0 100644 --- a/host/include/librmcs/agent/c_board.hpp +++ b/host/include/librmcs/agent/c_board.hpp @@ -120,6 +120,17 @@ class CBoard : private data::DataCallback { (void)data; } + bool i2c_receive_callback(data::DataId id, const data::I2cDataView& data) final { + (void)id; + (void)data; + return false; + } + + void i2c_error_callback(data::DataId id, uint8_t slave_address) final { + (void)id; + (void)slave_address; + } + host::protocol::Handler handler_; }; diff --git a/host/include/librmcs/agent/rmcs_board.hpp b/host/include/librmcs/agent/rmcs_board.hpp index b4d10aa..157de51 100644 --- a/host/include/librmcs/agent/rmcs_board.hpp +++ b/host/include/librmcs/agent/rmcs_board.hpp @@ -71,6 +71,18 @@ class RmcsBoard : private data::DataCallback { return *this; } + PacketBuilder& i2c0_write(const librmcs::data::I2cDataView& data) { + if (data.payload.empty() || !builder_.write_i2c(data::DataId::kI2c0, data)) + throw std::invalid_argument{"I2C0 write failed: Invalid I2C data"}; + return *this; + } + + PacketBuilder& i2c0_read(const librmcs::data::I2cReadConfigView& data) { + if (data.read_length == 0 || !builder_.write_i2c_read_config(data::DataId::kI2c0, data)) + throw std::invalid_argument{"I2C0 read failed: Invalid I2C read config"}; + return *this; + } + private: explicit PacketBuilder(host::protocol::Handler& handler) noexcept : builder_(handler.start_transmit()) {} @@ -127,6 +139,24 @@ class RmcsBoard : private data::DataCallback { (void)data; } + bool i2c_receive_callback(data::DataId id, const data::I2cDataView& data) final { + switch (id) { + case data::DataId::kI2c0: i2c0_receive_callback(data); return true; + default: return false; + } + } + + void i2c_error_callback(data::DataId id, uint8_t slave_address) final { + switch (id) { + case data::DataId::kI2c0: i2c0_error_callback(slave_address); break; + default: break; + } + } + + virtual void i2c0_receive_callback(const librmcs::data::I2cDataView& data) { (void)data; } + + virtual void i2c0_error_callback(uint8_t slave_address) { (void)slave_address; } + host::protocol::Handler handler_; }; diff --git a/host/include/librmcs/protocol/handler.hpp b/host/include/librmcs/protocol/handler.hpp index 4a9fcca..d175c56 100644 --- a/host/include/librmcs/protocol/handler.hpp +++ b/host/include/librmcs/protocol/handler.hpp @@ -34,6 +34,13 @@ class LIBRMCS_API Handler { bool write_imu_gyroscope(const data::GyroscopeDataView& view) noexcept; + bool write_i2c(data::DataId field_id, const data::I2cDataView& view) noexcept; + + bool write_i2c_read_config( + data::DataId field_id, const data::I2cReadConfigView& view) noexcept; + + bool write_i2c_read_result(data::DataId field_id, const data::I2cDataView& view) noexcept; + private: friend class Handler; diff --git a/host/src/protocol/handler.cpp b/host/src/protocol/handler.cpp index a6ca13c..53e10f0 100644 --- a/host/src/protocol/handler.cpp +++ b/host/src/protocol/handler.cpp @@ -76,6 +76,33 @@ class Handler::Impl : public core::protocol::DeserializeCallback { callback_.gyroscope_receive_callback(data); } + void i2c_write_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + (void)data; + logging::get_logger().error("Unexpected i2c write field in uplink: ", static_cast(id)); + } + + void i2c_read_config_deserialized_callback( + core::protocol::FieldId id, const data::I2cReadConfigView& data) override { + (void)data; + logging::get_logger().error( + "Unexpected i2c read request field in uplink: ", static_cast(id)); + } + + void i2c_read_result_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + if (!callback_.i2c_receive_callback(id, data)) + logging::get_logger().error("Unexpected i2c field id: ", static_cast(id)); + } + + void i2c_error_deserialized_callback( + core::protocol::FieldId id, const data::I2cDataView& data) override { + logging::get_logger().error( + "I2C operation failed on field {} for slave address 0x{:02x}", static_cast(id), + static_cast(data.slave_address)); + callback_.i2c_error_callback(id, data.slave_address); + } + void error_callback() override { logging::get_logger().error("Deserializer encountered an error while parsing input"); } @@ -134,6 +161,20 @@ struct PacketBuilderImpl { return process_result(serializer_.write_imu_gyroscope(view)); } + [[nodiscard]] bool write_i2c(data::DataId field_id, const data::I2cDataView& view) noexcept { + return process_result(serializer_.write_i2c_write(field_id, view)); + } + + [[nodiscard]] bool + write_i2c_read_config(data::DataId field_id, const data::I2cReadConfigView& view) noexcept { + return process_result(serializer_.write_i2c_read_config(field_id, view)); + } + + [[nodiscard]] bool + write_i2c_read_result(data::DataId field_id, const data::I2cDataView& view) noexcept { + return process_result(serializer_.write_i2c_read_result(field_id, view)); + } + private: static bool process_result(core::protocol::Serializer::SerializeResult result) { using core::protocol::Serializer; @@ -204,6 +245,23 @@ bool Handler::PacketBuilder::write_imu_gyroscope(const data::GyroscopeDataView& return std::launder(reinterpret_cast(storage_))->write_imu_gyroscope(view); } +bool Handler::PacketBuilder::write_i2c( + data::DataId field_id, const data::I2cDataView& view) noexcept { + return std::launder(reinterpret_cast(storage_))->write_i2c(field_id, view); +} + +bool Handler::PacketBuilder::write_i2c_read_config( + data::DataId field_id, const data::I2cReadConfigView& view) noexcept { + return std::launder(reinterpret_cast(storage_)) + ->write_i2c_read_config(field_id, view); +} + +bool Handler::PacketBuilder::write_i2c_read_result( + data::DataId field_id, const data::I2cDataView& view) noexcept { + return std::launder(reinterpret_cast(storage_)) + ->write_i2c_read_result(field_id, view); +} + Handler::Handler( uint16_t usb_vid, int32_t usb_pid, std::string_view serial_filter, const agent::AdvancedOptions& options, data::DataCallback& callback) From 44ff397e0fdd237fcc34896add9c3953d3442c26 Mon Sep 17 00:00:00 2001 From: tcd <1369013595@qq.com> Date: Wed, 8 Apr 2026 11:43:33 +0000 Subject: [PATCH 2/7] feat(c_board): Add I2C2 transport support --- firmware/c_board/app/src/app.cpp | 5 + firmware/c_board/app/src/i2c/i2c.cpp | 40 + firmware/c_board/app/src/i2c/i2c.hpp | 194 ++++ firmware/c_board/app/src/usb/vendor.hpp | 15 +- firmware/c_board/bsp/cubemx/Core/Inc/i2c.h | 52 + .../bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h | 2 +- .../bsp/cubemx/Core/Inc/stm32f4xx_it.h | 2 + firmware/c_board/bsp/cubemx/Core/Src/gpio.c | 1 + firmware/c_board/bsp/cubemx/Core/Src/i2c.c | 125 +++ firmware/c_board/bsp/cubemx/Core/Src/main.c | 1 + .../bsp/cubemx/Core/Src/stm32f4xx_it.c | 29 + .../cubemx/cmake/stm32cubemx/CMakeLists.txt | 3 + firmware/c_board/bsp/cubemx/rmcs_slave.ioc | 998 +++++++++--------- host/include/librmcs/agent/c_board.hpp | 31 +- host/include/librmcs/agent/rmcs_board.hpp | 1 + 15 files changed, 996 insertions(+), 503 deletions(-) create mode 100644 firmware/c_board/app/src/i2c/i2c.cpp create mode 100644 firmware/c_board/app/src/i2c/i2c.hpp create mode 100644 firmware/c_board/bsp/cubemx/Core/Inc/i2c.h create mode 100644 firmware/c_board/bsp/cubemx/Core/Src/i2c.c diff --git a/firmware/c_board/app/src/app.cpp b/firmware/c_board/app/src/app.cpp index 9fcd87a..cccff55 100644 --- a/firmware/c_board/app/src/app.cpp +++ b/firmware/c_board/app/src/app.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -12,6 +13,7 @@ #include "firmware/c_board/app/src/can/can.hpp" #include "firmware/c_board/app/src/gpio/gpio.hpp" +#include "firmware/c_board/app/src/i2c/i2c.hpp" #include "firmware/c_board/app/src/led/led.hpp" #include "firmware/c_board/app/src/spi/bmi088/accel.hpp" #include "firmware/c_board/app/src/spi/bmi088/gyro.hpp" @@ -48,6 +50,7 @@ App::App() { MX_SPI1_Init(); MX_CAN1_Init(); MX_CAN2_Init(); + MX_I2C2_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); MX_USART6_UART_Init(); @@ -61,6 +64,7 @@ App::App() { uart::uart1.init(); uart::uart2.init(); uart::uart_dbus.init(); + i2c::i2c0.init(); gpio::gpio.init(); spi::bmi088::accelerometer.init(); spi::bmi088::gyroscope.init(); @@ -79,6 +83,7 @@ App::App() { can::can2->try_transmit(); usb::vendor->try_transmit(); spi::spi1->update(); + i2c::i2c0->update(); usb::vendor->try_transmit(); uart::uart1->try_transmit(); usb::vendor->try_transmit(); diff --git a/firmware/c_board/app/src/i2c/i2c.cpp b/firmware/c_board/app/src/i2c/i2c.cpp new file mode 100644 index 0000000..bbb7ccb --- /dev/null +++ b/firmware/c_board/app/src/i2c/i2c.cpp @@ -0,0 +1,40 @@ +#include "firmware/c_board/app/src/i2c/i2c.hpp" + +#include + +#include "core/src/utility/assert.hpp" + +namespace librmcs::firmware::i2c { + +namespace { + +I2c& get_i2c_instance(I2C_HandleTypeDef* hal_i2c_handle) { + if (hal_i2c_handle == &hi2c2) + return *i2c0; + + core::utility::assert_failed_debug(); +} + +} // namespace + +extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).tx_complete_callback(); +} + +extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).rx_complete_callback(); +} + +extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).tx_complete_callback(); +} + +extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).rx_complete_callback(); +} + +extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).error_callback(); +} + +} // namespace librmcs::firmware::i2c diff --git a/firmware/c_board/app/src/i2c/i2c.hpp b/firmware/c_board/app/src/i2c/i2c.hpp new file mode 100644 index 0000000..5a5b45d --- /dev/null +++ b/firmware/c_board/app/src/i2c/i2c.hpp @@ -0,0 +1,194 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "core/include/librmcs/data/datas.hpp" +#include "core/src/protocol/serializer.hpp" +#include "core/src/utility/assert.hpp" +#include "core/src/utility/immovable.hpp" +#include "firmware/c_board/app/src/led/led.hpp" +#include "firmware/c_board/app/src/usb/helper.hpp" +#include "firmware/c_board/app/src/utility/lazy.hpp" +#include "firmware/c_board/app/src/utility/ring_buffer.hpp" + +namespace librmcs::firmware::i2c { + +class I2c : private core::utility::Immovable { +public: + using Lazy = utility::Lazy; + + I2c(data::DataId data_id, I2C_HandleTypeDef* hal_i2c_handle) + : data_id_(data_id) + , hal_i2c_handle_(hal_i2c_handle) {} + + void handle_downlink_write(const data::I2cDataView& data) { + if (data.payload.empty()) + return; + + if (data.payload.size() > kMaxDataLength) { + write_error(data.slave_address); + return; + } + + if (request_queue_.emplace_back_n( + [&data](std::byte* storage) noexcept { + auto& request = *new (storage) Request{}; + request.operation = Operation::kWrite; + request.slave_address = data.slave_address; + request.length = static_cast(data.payload.size()); + request.has_register = data.has_register; + request.reg_address = data.reg_address; + std::memcpy(request.payload.data(), data.payload.data(), data.payload.size()); + }, + 1) + != 0) { + return; + } + + led::led->downlink_buffer_full(); + write_error(data.slave_address); + } + + void handle_downlink_read_config(const data::I2cReadConfigView& data) { + if (data.read_length == 0 || data.read_length > kMaxDataLength) { + write_error(data.slave_address); + return; + } + + if (request_queue_.emplace_back_n( + [&data](std::byte* storage) noexcept { + auto& request = *new (storage) Request{}; + request.operation = Operation::kRead; + request.slave_address = data.slave_address; + request.length = data.read_length; + request.has_register = data.has_register; + request.reg_address = data.reg_address; + }, + 1) + != 0) { + return; + } + + led::led->downlink_buffer_full(); + write_error(data.slave_address); + } + + void update() { + while (!transfer_in_progress_.load(std::memory_order::acquire) + && request_queue_.pop_front([this](const Request& request) noexcept { + active_request_ = request; + if (!start_active_request()) + write_error(active_request_.slave_address); + })) {} + } + + void tx_complete_callback() { + core::utility::assert_debug(transfer_in_progress_.load(std::memory_order::acquire)); + transfer_in_progress_.store(false, std::memory_order::release); + } + + void rx_complete_callback() { + core::utility::assert_debug(transfer_in_progress_.load(std::memory_order::acquire)); + core::utility::assert_debug(active_request_.operation == Operation::kRead); + + auto& serializer = usb::get_serializer(); + const data::I2cDataView result{ + .slave_address = active_request_.slave_address, + .payload = std::span{read_buffer_.data(), active_request_.length}, + .has_register = active_request_.has_register, + .reg_address = active_request_.reg_address, + }; + core::utility::assert_always( + serializer.write_i2c_read_result(data_id_, result) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); + + transfer_in_progress_.store(false, std::memory_order::release); + } + + void error_callback() { + core::utility::assert_debug(transfer_in_progress_.load(std::memory_order::acquire)); + write_error(active_request_.slave_address); + transfer_in_progress_.store(false, std::memory_order::release); + } + +private: + static constexpr uint16_t kMaxDataLength = (1U << 9) - 1U; + static constexpr size_t kRequestQueueSize = 4; + + enum class Operation : uint8_t { + kWrite, + kRead, + }; + + struct Request { + Operation operation = Operation::kWrite; + uint8_t slave_address = 0; + uint16_t length = 0; + bool has_register = false; + uint8_t reg_address = 0; + std::array payload{}; + }; + + bool start_active_request() { + const auto hal_slave_address = to_hal_slave_address(active_request_.slave_address); + + transfer_in_progress_.store(true, std::memory_order::release); + + if (active_request_.operation == Operation::kWrite) { + auto* payload = reinterpret_cast(active_request_.payload.data()); + const auto status = + active_request_.has_register + ? HAL_I2C_Mem_Write_IT( + hal_i2c_handle_, hal_slave_address, active_request_.reg_address, + I2C_MEMADD_SIZE_8BIT, payload, active_request_.length) + : HAL_I2C_Master_Transmit_IT( + hal_i2c_handle_, hal_slave_address, payload, active_request_.length); + if (status == HAL_OK) + return true; + } else { + auto* payload = reinterpret_cast(read_buffer_.data()); + const auto status = + active_request_.has_register + ? HAL_I2C_Mem_Read_IT( + hal_i2c_handle_, hal_slave_address, active_request_.reg_address, + I2C_MEMADD_SIZE_8BIT, payload, active_request_.length) + : HAL_I2C_Master_Receive_IT( + hal_i2c_handle_, hal_slave_address, payload, active_request_.length); + if (status == HAL_OK) + return true; + } + + transfer_in_progress_.store(false, std::memory_order::release); + return false; + } + + static uint16_t to_hal_slave_address(uint8_t slave_address) { + return static_cast(slave_address) << 1; + } + + void write_error(uint8_t slave_address) { + auto& serializer = usb::get_serializer(); + core::utility::assert_always( + serializer.write_i2c_error(data_id_, slave_address) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); + } + + const data::DataId data_id_; + I2C_HandleTypeDef* hal_i2c_handle_; + utility::RingBuffer request_queue_; + std::atomic transfer_in_progress_ = false; + Request active_request_{}; + std::array read_buffer_{}; +}; + +inline constinit I2c::Lazy i2c0{data::DataId::kI2c0, &hi2c2}; + +} // namespace librmcs::firmware::i2c diff --git a/firmware/c_board/app/src/usb/vendor.hpp b/firmware/c_board/app/src/usb/vendor.hpp index 93caa0a..5a33f21 100644 --- a/firmware/c_board/app/src/usb/vendor.hpp +++ b/firmware/c_board/app/src/usb/vendor.hpp @@ -17,6 +17,7 @@ #include "core/src/utility/immovable.hpp" #include "firmware/c_board/app/src/can/can.hpp" #include "firmware/c_board/app/src/gpio/gpio.hpp" +#include "firmware/c_board/app/src/i2c/i2c.hpp" #include "firmware/c_board/app/src/uart/uart.hpp" #include "firmware/c_board/app/src/usb/interrupt_safe_buffer.hpp" #include "firmware/c_board/app/src/usb/usb_descriptors.hpp" @@ -130,26 +131,32 @@ class Vendor void i2c_write_deserialized_callback( core::protocol::FieldId id, const data::I2cDataView& data) override { - (void)id; - (void)data; + switch (id) { + case data::DataId::kI2c0: i2c::i2c0->handle_downlink_write(data); break; + default: core::utility::assert_failed_always(); + } } void i2c_read_config_deserialized_callback( core::protocol::FieldId id, const data::I2cReadConfigView& data) override { - (void)id; - (void)data; + switch (id) { + case data::DataId::kI2c0: i2c::i2c0->handle_downlink_read_config(data); break; + default: core::utility::assert_failed_always(); + } } void i2c_read_result_deserialized_callback( core::protocol::FieldId id, const data::I2cDataView& data) override { (void)id; (void)data; + core::utility::assert_failed_always(); } void i2c_error_deserialized_callback( core::protocol::FieldId id, const data::I2cDataView& data) override { (void)id; (void)data; + core::utility::assert_failed_always(); } void error_callback() override { core::utility::assert_failed_always(); } diff --git a/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h b/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h new file mode 100644 index 0000000..ef87b7e --- /dev/null +++ b/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h @@ -0,0 +1,52 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file i2c.h + * @brief This file contains all the function prototypes for + * the i2c.c file + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Define to prevent recursive inclusion -------------------------------------*/ +#ifndef __I2C_H__ +#define __I2C_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +/* Includes ------------------------------------------------------------------*/ +#include "main.h" + +/* USER CODE BEGIN Includes */ +#include "stm32f4xx_hal_i2c.h" // IWYU pragma: export +/* USER CODE END Includes */ + +extern I2C_HandleTypeDef hi2c2; + +/* USER CODE BEGIN Private defines */ + +/* USER CODE END Private defines */ + +void MX_I2C2_Init(void); + +/* USER CODE BEGIN Prototypes */ + +/* USER CODE END Prototypes */ + +#ifdef __cplusplus +} +#endif + +#endif /* __I2C_H__ */ + diff --git a/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h b/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h index dfbad6b..488c572 100644 --- a/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h +++ b/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_hal_conf.h @@ -53,7 +53,7 @@ /* #define HAL_SRAM_MODULE_ENABLED */ /* #define HAL_SDRAM_MODULE_ENABLED */ /* #define HAL_HASH_MODULE_ENABLED */ -/* #define HAL_I2C_MODULE_ENABLED */ +#define HAL_I2C_MODULE_ENABLED /* #define HAL_I2S_MODULE_ENABLED */ /* #define HAL_IWDG_MODULE_ENABLED */ /* #define HAL_LTDC_MODULE_ENABLED */ diff --git a/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h b/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h index 455dcbf..195c454 100644 --- a/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h +++ b/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h @@ -60,6 +60,8 @@ void DMA1_Stream1_IRQHandler(void); void DMA1_Stream3_IRQHandler(void); void CAN1_RX0_IRQHandler(void); void EXTI9_5_IRQHandler(void); +void I2C2_EV_IRQHandler(void); +void I2C2_ER_IRQHandler(void); void SPI1_IRQHandler(void); void USART1_IRQHandler(void); void USART3_IRQHandler(void); diff --git a/firmware/c_board/bsp/cubemx/Core/Src/gpio.c b/firmware/c_board/bsp/cubemx/Core/Src/gpio.c index f26ae87..2256a04 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/gpio.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/gpio.c @@ -51,6 +51,7 @@ void MX_GPIO_Init(void) __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOI_CLK_ENABLE(); + __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOH_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); diff --git a/firmware/c_board/bsp/cubemx/Core/Src/i2c.c b/firmware/c_board/bsp/cubemx/Core/Src/i2c.c new file mode 100644 index 0000000..6c195b8 --- /dev/null +++ b/firmware/c_board/bsp/cubemx/Core/Src/i2c.c @@ -0,0 +1,125 @@ +/* USER CODE BEGIN Header */ +/** + ****************************************************************************** + * @file i2c.c + * @brief This file provides code for the configuration + * of the I2C instances. + ****************************************************************************** + * @attention + * + * Copyright (c) 2026 STMicroelectronics. + * All rights reserved. + * + * This software is licensed under terms that can be found in the LICENSE file + * in the root directory of this software component. + * If no LICENSE file comes with this software, it is provided AS-IS. + * + ****************************************************************************** + */ +/* USER CODE END Header */ +/* Includes ------------------------------------------------------------------*/ +#include "i2c.h" + +/* USER CODE BEGIN 0 */ + +/* USER CODE END 0 */ + +I2C_HandleTypeDef hi2c2; + +/* I2C2 init function */ +void MX_I2C2_Init(void) +{ + + /* USER CODE BEGIN I2C2_Init 0 */ + + /* USER CODE END I2C2_Init 0 */ + + /* USER CODE BEGIN I2C2_Init 1 */ + + /* USER CODE END I2C2_Init 1 */ + hi2c2.Instance = I2C2; + hi2c2.Init.ClockSpeed = 100000; + hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2; + hi2c2.Init.OwnAddress1 = 0; + hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; + hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; + hi2c2.Init.OwnAddress2 = 0; + hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; + hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; + if (HAL_I2C_Init(&hi2c2) != HAL_OK) + { + Error_Handler(); + } + /* USER CODE BEGIN I2C2_Init 2 */ + + /* USER CODE END I2C2_Init 2 */ + +} + +void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) +{ + + GPIO_InitTypeDef GPIO_InitStruct = {0}; + if(i2cHandle->Instance==I2C2) + { + /* USER CODE BEGIN I2C2_MspInit 0 */ + + /* USER CODE END I2C2_MspInit 0 */ + + __HAL_RCC_GPIOF_CLK_ENABLE(); + /**I2C2 GPIO Configuration + PF0 ------> I2C2_SDA + PF1 ------> I2C2_SCL + */ + GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1; + GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; + GPIO_InitStruct.Pull = GPIO_NOPULL; + GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; + GPIO_InitStruct.Alternate = GPIO_AF4_I2C2; + HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); + + /* I2C2 clock enable */ + __HAL_RCC_I2C2_CLK_ENABLE(); + + /* I2C2 interrupt Init */ + HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); + HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); + /* USER CODE BEGIN I2C2_MspInit 1 */ + + /* USER CODE END I2C2_MspInit 1 */ + } +} + +void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle) +{ + + if(i2cHandle->Instance==I2C2) + { + /* USER CODE BEGIN I2C2_MspDeInit 0 */ + + /* USER CODE END I2C2_MspDeInit 0 */ + /* Peripheral clock disable */ + __HAL_RCC_I2C2_CLK_DISABLE(); + + /**I2C2 GPIO Configuration + PF0 ------> I2C2_SDA + PF1 ------> I2C2_SCL + */ + HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0); + + HAL_GPIO_DeInit(GPIOF, GPIO_PIN_1); + + /* I2C2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); + HAL_NVIC_DisableIRQ(I2C2_ER_IRQn); + /* USER CODE BEGIN I2C2_MspDeInit 1 */ + + /* USER CODE END I2C2_MspDeInit 1 */ + } +} + +/* USER CODE BEGIN 1 */ + +/* USER CODE END 1 */ diff --git a/firmware/c_board/bsp/cubemx/Core/Src/main.c b/firmware/c_board/bsp/cubemx/Core/Src/main.c index 0e2cd0b..00e2625 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/main.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/main.c @@ -20,6 +20,7 @@ #include "main.h" #include "can.h" #include "dma.h" +#include "i2c.h" #include "spi.h" #include "tim.h" #include "usart.h" diff --git a/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c b/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c index 6047109..935cb65 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c @@ -61,6 +61,7 @@ void tusb_int_handler(uint8_t rhport, bool in_isr); /* External variables --------------------------------------------------------*/ extern CAN_HandleTypeDef hcan1; extern CAN_HandleTypeDef hcan2; +extern I2C_HandleTypeDef hi2c2; extern DMA_HandleTypeDef hdma_spi1_rx; extern DMA_HandleTypeDef hdma_spi1_tx; extern SPI_HandleTypeDef hspi1; @@ -288,6 +289,34 @@ void EXTI9_5_IRQHandler(void) /* USER CODE END EXTI9_5_IRQn 1 */ } +/** + * @brief This function handles I2C2 event interrupt. + */ +void I2C2_EV_IRQHandler(void) +{ + /* USER CODE BEGIN I2C2_EV_IRQn 0 */ + + /* USER CODE END I2C2_EV_IRQn 0 */ + HAL_I2C_EV_IRQHandler(&hi2c2); + /* USER CODE BEGIN I2C2_EV_IRQn 1 */ + + /* USER CODE END I2C2_EV_IRQn 1 */ +} + +/** + * @brief This function handles I2C2 error interrupt. + */ +void I2C2_ER_IRQHandler(void) +{ + /* USER CODE BEGIN I2C2_ER_IRQn 0 */ + + /* USER CODE END I2C2_ER_IRQn 0 */ + HAL_I2C_ER_IRQHandler(&hi2c2); + /* USER CODE BEGIN I2C2_ER_IRQn 1 */ + + /* USER CODE END I2C2_ER_IRQn 1 */ +} + /** * @brief This function handles SPI1 global interrupt. */ diff --git a/firmware/c_board/bsp/cubemx/cmake/stm32cubemx/CMakeLists.txt b/firmware/c_board/bsp/cubemx/cmake/stm32cubemx/CMakeLists.txt index 88575a9..7b0baf4 100644 --- a/firmware/c_board/bsp/cubemx/cmake/stm32cubemx/CMakeLists.txt +++ b/firmware/c_board/bsp/cubemx/cmake/stm32cubemx/CMakeLists.txt @@ -23,6 +23,7 @@ set(MX_Application_Src ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/gpio.c ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/can.c ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/dma.c + ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/i2c.c ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/spi.c ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/tim.c ${CMAKE_CURRENT_SOURCE_DIR}/../../Core/Src/usart.c @@ -51,6 +52,8 @@ set(STM32_Drivers_Src ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_cortex.c ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal.c ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_exti.c + ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_i2c.c + ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_i2c_ex.c ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_spi.c ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_tim.c ${LIBRMCS_STM32_HAL_DRIVER_ROOT}/Src/stm32f4xx_hal_tim_ex.c diff --git a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc index db0edd6..255cea8 100644 --- a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc +++ b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc @@ -1,493 +1,505 @@ -#MicroXplorer Configuration settings - do not modify -CAD.formats= -CAD.pinconfig= -CAD.provider= -CAN1.BS1=CAN_BS1_9TQ -CAN1.BS2=CAN_BS2_4TQ -CAN1.CalculateBaudRate=1000000 -CAN1.CalculateTimeBit=1000 -CAN1.CalculateTimeQuantum=71.42857142857143 -CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,BS2,Prescaler,NART -CAN1.NART=DISABLE -CAN1.Prescaler=3 -CAN2.BS1=CAN_BS1_9TQ -CAN2.BS2=CAN_BS2_4TQ -CAN2.CalculateBaudRate=1000000 -CAN2.CalculateTimeBit=1000 -CAN2.CalculateTimeQuantum=71.42857142857143 -CAN2.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,BS2,Prescaler,NART -CAN2.NART=DISABLE -CAN2.Prescaler=3 -Dma.Request0=SPI1_RX -Dma.Request1=SPI1_TX -Dma.Request2=USART1_RX -Dma.Request3=USART1_TX -Dma.Request4=USART3_RX -Dma.Request5=USART3_TX -Dma.Request6=USART6_RX -Dma.Request7=USART6_TX -Dma.RequestsNb=8 -Dma.SPI1_RX.0.Direction=DMA_PERIPH_TO_MEMORY -Dma.SPI1_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.SPI1_RX.0.Instance=DMA2_Stream0 -Dma.SPI1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.SPI1_RX.0.MemInc=DMA_MINC_ENABLE -Dma.SPI1_RX.0.Mode=DMA_NORMAL -Dma.SPI1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.SPI1_RX.0.PeriphInc=DMA_PINC_DISABLE -Dma.SPI1_RX.0.Priority=DMA_PRIORITY_MEDIUM -Dma.SPI1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.SPI1_TX.1.Direction=DMA_MEMORY_TO_PERIPH -Dma.SPI1_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.SPI1_TX.1.Instance=DMA2_Stream3 -Dma.SPI1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.SPI1_TX.1.MemInc=DMA_MINC_ENABLE -Dma.SPI1_TX.1.Mode=DMA_NORMAL -Dma.SPI1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.SPI1_TX.1.PeriphInc=DMA_PINC_DISABLE -Dma.SPI1_TX.1.Priority=DMA_PRIORITY_MEDIUM -Dma.SPI1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.USART1_RX.2.Direction=DMA_PERIPH_TO_MEMORY -Dma.USART1_RX.2.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.USART1_RX.2.Instance=DMA2_Stream5 -Dma.USART1_RX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.USART1_RX.2.MemInc=DMA_MINC_ENABLE -Dma.USART1_RX.2.Mode=DMA_CIRCULAR -Dma.USART1_RX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART1_RX.2.PeriphInc=DMA_PINC_DISABLE -Dma.USART1_RX.2.Priority=DMA_PRIORITY_HIGH -Dma.USART1_RX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.USART1_TX.3.Direction=DMA_MEMORY_TO_PERIPH -Dma.USART1_TX.3.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.USART1_TX.3.Instance=DMA2_Stream7 -Dma.USART1_TX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.USART1_TX.3.MemInc=DMA_MINC_ENABLE -Dma.USART1_TX.3.Mode=DMA_NORMAL -Dma.USART1_TX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART1_TX.3.PeriphInc=DMA_PINC_DISABLE -Dma.USART1_TX.3.Priority=DMA_PRIORITY_LOW -Dma.USART1_TX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.USART3_RX.4.Direction=DMA_PERIPH_TO_MEMORY -Dma.USART3_RX.4.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.USART3_RX.4.Instance=DMA1_Stream1 -Dma.USART3_RX.4.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.USART3_RX.4.MemInc=DMA_MINC_ENABLE -Dma.USART3_RX.4.Mode=DMA_CIRCULAR -Dma.USART3_RX.4.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART3_RX.4.PeriphInc=DMA_PINC_DISABLE -Dma.USART3_RX.4.Priority=DMA_PRIORITY_HIGH -Dma.USART3_RX.4.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.USART3_TX.5.Direction=DMA_MEMORY_TO_PERIPH -Dma.USART3_TX.5.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.USART3_TX.5.Instance=DMA1_Stream3 -Dma.USART3_TX.5.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.USART3_TX.5.MemInc=DMA_MINC_ENABLE -Dma.USART3_TX.5.Mode=DMA_NORMAL -Dma.USART3_TX.5.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART3_TX.5.PeriphInc=DMA_PINC_DISABLE -Dma.USART3_TX.5.Priority=DMA_PRIORITY_LOW -Dma.USART3_TX.5.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.USART6_RX.6.Direction=DMA_PERIPH_TO_MEMORY -Dma.USART6_RX.6.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.USART6_RX.6.Instance=DMA2_Stream1 -Dma.USART6_RX.6.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.USART6_RX.6.MemInc=DMA_MINC_ENABLE -Dma.USART6_RX.6.Mode=DMA_CIRCULAR -Dma.USART6_RX.6.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART6_RX.6.PeriphInc=DMA_PINC_DISABLE -Dma.USART6_RX.6.Priority=DMA_PRIORITY_HIGH -Dma.USART6_RX.6.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -Dma.USART6_TX.7.Direction=DMA_MEMORY_TO_PERIPH -Dma.USART6_TX.7.FIFOMode=DMA_FIFOMODE_DISABLE -Dma.USART6_TX.7.Instance=DMA2_Stream6 -Dma.USART6_TX.7.MemDataAlignment=DMA_MDATAALIGN_BYTE -Dma.USART6_TX.7.MemInc=DMA_MINC_ENABLE -Dma.USART6_TX.7.Mode=DMA_NORMAL -Dma.USART6_TX.7.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART6_TX.7.PeriphInc=DMA_PINC_DISABLE -Dma.USART6_TX.7.Priority=DMA_PRIORITY_LOW -Dma.USART6_TX.7.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode -File.Version=6 -GPIO.groupedBy=Group By Peripherals -KeepUserPlacement=true -Mcu.CPN=STM32F407IGH6 -Mcu.Family=STM32F4 -Mcu.IP0=CAN1 -Mcu.IP1=CAN2 -Mcu.IP10=TIM8 -Mcu.IP11=TIM9 -Mcu.IP12=USART1 -Mcu.IP13=USART3 -Mcu.IP14=USART6 -Mcu.IP15=USB_OTG_FS -Mcu.IP2=DMA -Mcu.IP3=NVIC -Mcu.IP4=RCC -Mcu.IP5=SPI1 -Mcu.IP6=SYS -Mcu.IP7=TIM1 -Mcu.IP8=TIM2 -Mcu.IP9=TIM5 -Mcu.IPNb=16 -Mcu.Name=STM32F407I(E-G)Hx -Mcu.Package=UFBGA176 -Mcu.Pin0=PB5 -Mcu.Pin1=PG14 -Mcu.Pin10=PC10 -Mcu.Pin11=PA12 -Mcu.Pin12=PI7 -Mcu.Pin13=PI6 -Mcu.Pin14=PG9 -Mcu.Pin15=PD1 -Mcu.Pin16=PA11 -Mcu.Pin17=PA9 -Mcu.Pin18=PH0-OSC_IN -Mcu.Pin19=PH1-OSC_OUT -Mcu.Pin2=PB4 -Mcu.Pin20=PC6 -Mcu.Pin21=PH12 -Mcu.Pin22=PH11 -Mcu.Pin23=PH10 -Mcu.Pin24=PA4 -Mcu.Pin25=PC4 -Mcu.Pin26=PE13 -Mcu.Pin27=PC5 -Mcu.Pin28=PE9 -Mcu.Pin29=PE11 -Mcu.Pin3=PB3 -Mcu.Pin30=PE14 -Mcu.Pin31=PA7 -Mcu.Pin32=PB0 -Mcu.Pin33=VP_SYS_VS_Systick -Mcu.Pin34=VP_TIM1_VS_ClockSourceINT -Mcu.Pin35=VP_TIM2_VS_ClockSourceINT -Mcu.Pin36=VP_TIM5_VS_ClockSourceINT -Mcu.Pin37=VP_TIM8_VS_ClockSourceINT -Mcu.Pin38=VP_TIM9_VS_ControllerModeClock -Mcu.Pin39=VP_TIM9_VS_ClockSourceITR -Mcu.Pin4=PA14 -Mcu.Pin5=PA13 -Mcu.Pin6=PB7 -Mcu.Pin7=PB6 -Mcu.Pin8=PD0 -Mcu.Pin9=PC11 -Mcu.PinsNb=40 -Mcu.ThirdPartyNb=0 -Mcu.UserConstants= -Mcu.UserName=STM32F407IGHx -MxCube.Version=6.16.1 -MxDb.Version=DB.6.0.161 -NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.CAN1_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true -NVIC.CAN2_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true -NVIC.DMA1_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA1_Stream3_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream0_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream3_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream5_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream6_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream7_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true -NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.EXTI4_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true -NVIC.EXTI9_5_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true -NVIC.ForceEnableDMAVector=true -NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.OTG_FS_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true -NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 -NVIC.SPI1_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true -NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false -NVIC.USART1_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true -NVIC.USART3_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true -NVIC.USART6_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true -NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -PA11.Locked=true -PA11.Mode=Device_Only -PA11.Signal=USB_OTG_FS_DM -PA12.Locked=true -PA12.Mode=Device_Only -PA12.Signal=USB_OTG_FS_DP -PA13.Locked=true -PA13.Mode=Serial_Wire -PA13.Signal=SYS_JTMS-SWDIO -PA14.Locked=true -PA14.Mode=Serial_Wire -PA14.Signal=SYS_JTCK-SWCLK -PA4.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label -PA4.GPIO_Label=CS1_ACCEL -PA4.GPIO_PuPd=GPIO_PULLUP -PA4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH -PA4.Locked=true -PA4.PinState=GPIO_PIN_SET -PA4.Signal=GPIO_Output -PA7.GPIOParameters=GPIO_Label -PA7.GPIO_Label=SPI1_MOSI -PA7.Locked=true -PA7.Mode=Full_Duplex_Master -PA7.Signal=SPI1_MOSI -PA9.Locked=true -PA9.Mode=Asynchronous -PA9.Signal=USART1_TX -PB0.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label -PB0.GPIO_Label=CS1_GYRO -PB0.GPIO_PuPd=GPIO_PULLUP -PB0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH -PB0.Locked=true -PB0.PinState=GPIO_PIN_SET -PB0.Signal=GPIO_Output -PB3.GPIOParameters=GPIO_Label -PB3.GPIO_Label=SPI1_SCK -PB3.Locked=true -PB3.Mode=Full_Duplex_Master -PB3.Signal=SPI1_SCK -PB4.GPIOParameters=GPIO_Label -PB4.GPIO_Label=SPI1_MISO -PB4.Locked=true -PB4.Mode=Full_Duplex_Master -PB4.Signal=SPI1_MISO -PB5.Locked=true -PB5.Mode=CAN_Activate -PB5.Signal=CAN2_RX -PB6.Locked=true -PB6.Mode=CAN_Activate -PB6.Signal=CAN2_TX -PB7.Locked=true -PB7.Mode=Asynchronous -PB7.Signal=USART1_RX -PC10.Locked=true -PC10.Mode=Asynchronous -PC10.Signal=USART3_TX -PC11.Locked=true -PC11.Mode=Asynchronous -PC11.Signal=USART3_RX -PC4.GPIOParameters=GPIO_Label,GPIO_ModeDefaultEXTI -PC4.GPIO_Label=INT1_ACC -PC4.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING -PC4.Locked=true -PC4.Signal=GPXTI4 -PC5.GPIOParameters=GPIO_Label,GPIO_ModeDefaultEXTI -PC5.GPIO_Label=INT1_GYRO -PC5.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING -PC5.Locked=true -PC5.Signal=GPXTI5 -PC6.GPIOParameters=GPIO_Label -PC6.GPIO_Label=CHANNEL5 -PC6.Locked=true -PC6.Signal=S_TIM8_CH1 -PCC.Checker=false -PCC.Line=STM32F407/417 -PCC.MCU=STM32F407I(E-G)Hx -PCC.PartNumber=STM32F407IGHx -PCC.Series=STM32F4 -PCC.Temperature=25 -PCC.Vdd=3.3 -PD0.Locked=true -PD0.Mode=CAN_Activate -PD0.Signal=CAN1_RX -PD1.Locked=true -PD1.Mode=CAN_Activate -PD1.Signal=CAN1_TX -PE11.GPIOParameters=GPIO_Label -PE11.GPIO_Label=CHANNEL2 -PE11.Locked=true -PE11.Signal=S_TIM1_CH2 -PE13.GPIOParameters=GPIO_Label -PE13.GPIO_Label=CHANNEL3 -PE13.Locked=true -PE13.Signal=S_TIM1_CH3 -PE14.GPIOParameters=GPIO_Label -PE14.GPIO_Label=CHANNEL4 -PE14.Locked=true -PE14.Signal=S_TIM1_CH4 -PE9.GPIOParameters=GPIO_Label -PE9.GPIO_Label=CHANNEL1 -PE9.Locked=true -PE9.Signal=S_TIM1_CH1 -PG14.Locked=true -PG14.Mode=Asynchronous -PG14.Signal=USART6_TX -PG9.Locked=true -PG9.Mode=Asynchronous -PG9.Signal=USART6_RX -PH0-OSC_IN.Locked=true -PH0-OSC_IN.Mode=HSE-External-Oscillator -PH0-OSC_IN.Signal=RCC_OSC_IN -PH1-OSC_OUT.Locked=true -PH1-OSC_OUT.Mode=HSE-External-Oscillator -PH1-OSC_OUT.Signal=RCC_OSC_OUT -PH10.GPIOParameters=GPIO_Label -PH10.GPIO_Label=LED_B -PH10.Locked=true -PH10.Signal=S_TIM5_CH1 -PH11.GPIOParameters=GPIO_Label -PH11.GPIO_Label=LED_G -PH11.Locked=true -PH11.Signal=S_TIM5_CH2 -PH12.GPIOParameters=GPIO_Label -PH12.GPIO_Label=LED_R -PH12.Locked=true -PH12.Signal=S_TIM5_CH3 -PI6.GPIOParameters=GPIO_Label -PI6.GPIO_Label=CHANNEL6 -PI6.Locked=true -PI6.Signal=S_TIM8_CH2 -PI7.GPIOParameters=GPIO_Label -PI7.GPIO_Label=CHANNEL7 -PI7.Locked=true -PI7.Signal=S_TIM8_CH3 -PinOutPanel.CurrentBGAView=Top -PinOutPanel.RotationAngle=0 -ProjectManager.AskForMigrate=true -ProjectManager.BackupPrevious=false -ProjectManager.CompilerLinker=GCC -ProjectManager.CompilerOptimize=6 -ProjectManager.ComputerToolchain=false -ProjectManager.CoupleFile=true -ProjectManager.CustomerFirmwarePackage= -ProjectManager.DefaultFWLocation=true -ProjectManager.DeletePrevious=true -ProjectManager.DeviceId=STM32F407IGHx -ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3 -ProjectManager.FreePins=false -ProjectManager.FreePinsContext= -ProjectManager.HalAssertFull=false -ProjectManager.HeapSize=0x200 -ProjectManager.KeepUserCode=true -ProjectManager.LastFirmware=true -ProjectManager.LibraryCopy=2 -ProjectManager.MainLocation=Core/Src -ProjectManager.NoMain=true -ProjectManager.PreviousToolchain= -ProjectManager.ProjectBuild=false -ProjectManager.ProjectFileName=rmcs_slave.ioc -ProjectManager.ProjectName=rmcs_slave -ProjectManager.ProjectStructure= -ProjectManager.RegisterCallBack= -ProjectManager.StackSize=0x400 -ProjectManager.TargetToolchain=CMake -ProjectManager.ToolChainLocation= -ProjectManager.UAScriptAfterPath= -ProjectManager.UAScriptBeforePath= -ProjectManager.UnderRoot=false -ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_SPI1_Init-SPI1-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_CAN2_Init-CAN2-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true,8-MX_USART3_UART_Init-USART3-false-HAL-true,9-MX_USART6_UART_Init-USART6-false-HAL-true,10-MX_TIM5_Init-TIM5-false-HAL-true,11-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_TIM9_Init-TIM9-false-HAL-true,14-MX_TIM1_Init-TIM1-false-HAL-true,15-MX_TIM8_Init-TIM8-false-HAL-true -RCC.48MHZClocksFreq_Value=48000000 -RCC.AHBFreq_Value=168000000 -RCC.APB1CLKDivider=RCC_HCLK_DIV4 -RCC.APB1Freq_Value=42000000 -RCC.APB1TimFreq_Value=84000000 -RCC.APB2CLKDivider=RCC_HCLK_DIV2 -RCC.APB2Freq_Value=84000000 -RCC.APB2TimFreq_Value=168000000 -RCC.CortexFreq_Value=168000000 -RCC.EthernetFreq_Value=168000000 -RCC.FCLKCortexFreq_Value=168000000 -RCC.FamilyName=M -RCC.HCLKFreq_Value=168000000 -RCC.HSE_VALUE=12000000 -RCC.HSI_VALUE=16000000 -RCC.I2SClocksFreq_Value=192000000 -RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S -RCC.LSE_VALUE=32768 -RCC.LSI_VALUE=32000 -RCC.MCO2PinFreq_Value=168000000 -RCC.PLLCLKFreq_Value=168000000 -RCC.PLLM=6 -RCC.PLLN=168 -RCC.PLLQ=7 -RCC.PLLQCLKFreq_Value=48000000 -RCC.RTCFreq_Value=32000 -RCC.RTCHSEDivFreq_Value=6000000 -RCC.SYSCLKFreq_VALUE=168000000 -RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK -RCC.VCOI2SOutputFreq_Value=384000000 -RCC.VCOInputFreq_Value=2000000 -RCC.VCOOutputFreq_Value=336000000 -RCC.VcooutputI2S=192000000 -SH.GPXTI4.0=GPIO_EXTI4 -SH.GPXTI4.ConfNb=1 -SH.GPXTI5.0=GPIO_EXTI5 -SH.GPXTI5.ConfNb=1 -SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 -SH.S_TIM1_CH1.ConfNb=1 -SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2 -SH.S_TIM1_CH2.ConfNb=1 -SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3 -SH.S_TIM1_CH3.ConfNb=1 -SH.S_TIM1_CH4.0=TIM1_CH4,PWM Generation4 CH4 -SH.S_TIM1_CH4.ConfNb=1 -SH.S_TIM5_CH1.0=TIM5_CH1,PWM Generation1 CH1 -SH.S_TIM5_CH1.ConfNb=1 -SH.S_TIM5_CH2.0=TIM5_CH2,PWM Generation2 CH2 -SH.S_TIM5_CH2.ConfNb=1 -SH.S_TIM5_CH3.0=TIM5_CH3,PWM Generation3 CH3 -SH.S_TIM5_CH3.ConfNb=1 -SH.S_TIM8_CH1.0=TIM8_CH1,PWM Generation1 CH1 -SH.S_TIM8_CH1.ConfNb=1 -SH.S_TIM8_CH2.0=TIM8_CH2,PWM Generation2 CH2 -SH.S_TIM8_CH2.ConfNb=1 -SH.S_TIM8_CH3.0=TIM8_CH3,PWM Generation3 CH3 -SH.S_TIM8_CH3.ConfNb=1 -SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8 -SPI1.CLKPhase=SPI_PHASE_2EDGE -SPI1.CLKPolarity=SPI_POLARITY_HIGH -SPI1.CalculateBaudRate=10.5 MBits/s -SPI1.Direction=SPI_DIRECTION_2LINES -SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPhase,CLKPolarity -SPI1.Mode=SPI_MODE_MASTER -SPI1.VirtualType=VM_MASTER -TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 -TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 -TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 -TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4 -TIM1.IPParameters=Prescaler,Period,Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4 -TIM1.Period=59999 -TIM1.Prescaler=56 - 1 -TIM2.IPParameters=TIM_MasterSlaveMode,TIM_MasterOutputTrigger,Prescaler -TIM2.Prescaler=21 - 1 -TIM2.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE -TIM2.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE -TIM5.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 -TIM5.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 -TIM5.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 -TIM5.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Period,Prescaler,Channel-PWM Generation3 CH3 -TIM5.Period=256-1 -TIM5.Prescaler=84-1 -TIM8.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 -TIM8.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 -TIM8.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 -TIM8.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Period,Prescaler -TIM8.Period=59999 -TIM8.Prescaler=56 - 1 -TIM9.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE -TIM9.IPParameters=AutoReloadPreload -USART1.IPParameters=VirtualMode -USART1.VirtualMode=VM_ASYNC -USART3.BaudRate=100000 -USART3.IPParameters=VirtualMode,StopBits,Parity,WordLength,BaudRate -USART3.Parity=PARITY_EVEN -USART3.StopBits=STOPBITS_1 -USART3.VirtualMode=VM_ASYNC -USART3.WordLength=WORDLENGTH_9B -USART6.IPParameters=VirtualMode -USART6.VirtualMode=VM_ASYNC -USB_OTG_FS.IPParameters=VirtualMode -USB_OTG_FS.VirtualMode=Device_Only -VP_SYS_VS_Systick.Mode=SysTick -VP_SYS_VS_Systick.Signal=SYS_VS_Systick -VP_TIM1_VS_ClockSourceINT.Mode=Internal -VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT -VP_TIM2_VS_ClockSourceINT.Mode=Internal -VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT -VP_TIM5_VS_ClockSourceINT.Mode=Internal -VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT -VP_TIM8_VS_ClockSourceINT.Mode=Internal -VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT -VP_TIM9_VS_ClockSourceITR.Mode=TriggerSource_ITR0 -VP_TIM9_VS_ClockSourceITR.Signal=TIM9_VS_ClockSourceITR -VP_TIM9_VS_ControllerModeClock.Mode=Clock Mode -VP_TIM9_VS_ControllerModeClock.Signal=TIM9_VS_ControllerModeClock -board=custom +#MicroXplorer Configuration settings - do not modify +CAD.formats= +CAD.pinconfig= +CAD.provider= +CAN1.BS1=CAN_BS1_9TQ +CAN1.BS2=CAN_BS2_4TQ +CAN1.CalculateBaudRate=1000000 +CAN1.CalculateTimeBit=1000 +CAN1.CalculateTimeQuantum=71.42857142857143 +CAN1.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,BS2,Prescaler,NART +CAN1.NART=DISABLE +CAN1.Prescaler=3 +CAN2.BS1=CAN_BS1_9TQ +CAN2.BS2=CAN_BS2_4TQ +CAN2.CalculateBaudRate=1000000 +CAN2.CalculateTimeBit=1000 +CAN2.CalculateTimeQuantum=71.42857142857143 +CAN2.IPParameters=CalculateTimeQuantum,CalculateTimeBit,CalculateBaudRate,BS1,BS2,Prescaler,NART +CAN2.NART=DISABLE +CAN2.Prescaler=3 +Dma.Request0=SPI1_RX +Dma.Request1=SPI1_TX +Dma.Request2=USART1_RX +Dma.Request3=USART1_TX +Dma.Request4=USART3_RX +Dma.Request5=USART3_TX +Dma.Request6=USART6_RX +Dma.Request7=USART6_TX +Dma.RequestsNb=8 +Dma.SPI1_RX.0.Direction=DMA_PERIPH_TO_MEMORY +Dma.SPI1_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.SPI1_RX.0.Instance=DMA2_Stream0 +Dma.SPI1_RX.0.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.SPI1_RX.0.MemInc=DMA_MINC_ENABLE +Dma.SPI1_RX.0.Mode=DMA_NORMAL +Dma.SPI1_RX.0.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.SPI1_RX.0.PeriphInc=DMA_PINC_DISABLE +Dma.SPI1_RX.0.Priority=DMA_PRIORITY_MEDIUM +Dma.SPI1_RX.0.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.SPI1_TX.1.Direction=DMA_MEMORY_TO_PERIPH +Dma.SPI1_TX.1.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.SPI1_TX.1.Instance=DMA2_Stream3 +Dma.SPI1_TX.1.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.SPI1_TX.1.MemInc=DMA_MINC_ENABLE +Dma.SPI1_TX.1.Mode=DMA_NORMAL +Dma.SPI1_TX.1.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.SPI1_TX.1.PeriphInc=DMA_PINC_DISABLE +Dma.SPI1_TX.1.Priority=DMA_PRIORITY_MEDIUM +Dma.SPI1_TX.1.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART1_RX.2.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART1_RX.2.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART1_RX.2.Instance=DMA2_Stream5 +Dma.USART1_RX.2.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_RX.2.MemInc=DMA_MINC_ENABLE +Dma.USART1_RX.2.Mode=DMA_CIRCULAR +Dma.USART1_RX.2.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_RX.2.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_RX.2.Priority=DMA_PRIORITY_HIGH +Dma.USART1_RX.2.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART1_TX.3.Direction=DMA_MEMORY_TO_PERIPH +Dma.USART1_TX.3.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART1_TX.3.Instance=DMA2_Stream7 +Dma.USART1_TX.3.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART1_TX.3.MemInc=DMA_MINC_ENABLE +Dma.USART1_TX.3.Mode=DMA_NORMAL +Dma.USART1_TX.3.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART1_TX.3.PeriphInc=DMA_PINC_DISABLE +Dma.USART1_TX.3.Priority=DMA_PRIORITY_LOW +Dma.USART1_TX.3.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART3_RX.4.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART3_RX.4.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART3_RX.4.Instance=DMA1_Stream1 +Dma.USART3_RX.4.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART3_RX.4.MemInc=DMA_MINC_ENABLE +Dma.USART3_RX.4.Mode=DMA_CIRCULAR +Dma.USART3_RX.4.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART3_RX.4.PeriphInc=DMA_PINC_DISABLE +Dma.USART3_RX.4.Priority=DMA_PRIORITY_HIGH +Dma.USART3_RX.4.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART3_TX.5.Direction=DMA_MEMORY_TO_PERIPH +Dma.USART3_TX.5.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART3_TX.5.Instance=DMA1_Stream3 +Dma.USART3_TX.5.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART3_TX.5.MemInc=DMA_MINC_ENABLE +Dma.USART3_TX.5.Mode=DMA_NORMAL +Dma.USART3_TX.5.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART3_TX.5.PeriphInc=DMA_PINC_DISABLE +Dma.USART3_TX.5.Priority=DMA_PRIORITY_LOW +Dma.USART3_TX.5.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART6_RX.6.Direction=DMA_PERIPH_TO_MEMORY +Dma.USART6_RX.6.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART6_RX.6.Instance=DMA2_Stream1 +Dma.USART6_RX.6.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART6_RX.6.MemInc=DMA_MINC_ENABLE +Dma.USART6_RX.6.Mode=DMA_CIRCULAR +Dma.USART6_RX.6.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART6_RX.6.PeriphInc=DMA_PINC_DISABLE +Dma.USART6_RX.6.Priority=DMA_PRIORITY_HIGH +Dma.USART6_RX.6.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART6_TX.7.Direction=DMA_MEMORY_TO_PERIPH +Dma.USART6_TX.7.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.USART6_TX.7.Instance=DMA2_Stream6 +Dma.USART6_TX.7.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.USART6_TX.7.MemInc=DMA_MINC_ENABLE +Dma.USART6_TX.7.Mode=DMA_NORMAL +Dma.USART6_TX.7.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART6_TX.7.PeriphInc=DMA_PINC_DISABLE +Dma.USART6_TX.7.Priority=DMA_PRIORITY_LOW +Dma.USART6_TX.7.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +File.Version=6 +GPIO.groupedBy=Group By Peripherals +KeepUserPlacement=true +Mcu.CPN=STM32F407IGH6 +Mcu.Family=STM32F4 +Mcu.IP0=CAN1 +Mcu.IP1=CAN2 +Mcu.IP10=TIM5 +Mcu.IP11=TIM8 +Mcu.IP12=TIM9 +Mcu.IP13=USART1 +Mcu.IP14=USART3 +Mcu.IP15=USART6 +Mcu.IP16=USB_OTG_FS +Mcu.IP2=DMA +Mcu.IP3=I2C2 +Mcu.IP4=NVIC +Mcu.IP5=RCC +Mcu.IP6=SPI1 +Mcu.IP7=SYS +Mcu.IP8=TIM1 +Mcu.IP9=TIM2 +Mcu.IPNb=17 +Mcu.Name=STM32F407I(E-G)Hx +Mcu.Package=UFBGA176 +Mcu.Pin0=PB5 +Mcu.Pin1=PG14 +Mcu.Pin10=PC10 +Mcu.Pin11=PA12 +Mcu.Pin12=PI7 +Mcu.Pin13=PI6 +Mcu.Pin14=PG9 +Mcu.Pin15=PD1 +Mcu.Pin16=PA11 +Mcu.Pin17=PF0 +Mcu.Pin18=PA9 +Mcu.Pin19=PH0-OSC_IN +Mcu.Pin2=PB4 +Mcu.Pin20=PH1-OSC_OUT +Mcu.Pin21=PF1 +Mcu.Pin22=PC6 +Mcu.Pin23=PH12 +Mcu.Pin24=PH11 +Mcu.Pin25=PH10 +Mcu.Pin26=PA4 +Mcu.Pin27=PC4 +Mcu.Pin28=PE13 +Mcu.Pin29=PC5 +Mcu.Pin3=PB3 +Mcu.Pin30=PE9 +Mcu.Pin31=PE11 +Mcu.Pin32=PE14 +Mcu.Pin33=PA7 +Mcu.Pin34=PB0 +Mcu.Pin35=VP_SYS_VS_Systick +Mcu.Pin36=VP_TIM1_VS_ClockSourceINT +Mcu.Pin37=VP_TIM2_VS_ClockSourceINT +Mcu.Pin38=VP_TIM5_VS_ClockSourceINT +Mcu.Pin39=VP_TIM8_VS_ClockSourceINT +Mcu.Pin4=PA14 +Mcu.Pin40=VP_TIM9_VS_ControllerModeClock +Mcu.Pin41=VP_TIM9_VS_ClockSourceITR +Mcu.Pin5=PA13 +Mcu.Pin6=PB7 +Mcu.Pin7=PB6 +Mcu.Pin8=PD0 +Mcu.Pin9=PC11 +Mcu.PinsNb=42 +Mcu.ThirdPartyNb=0 +Mcu.UserConstants= +Mcu.UserName=STM32F407IGHx +MxCube.Version=6.16.1 +MxDb.Version=DB.6.0.161 +NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.CAN1_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true +NVIC.CAN2_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true +NVIC.DMA1_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream3_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream0_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream3_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream5_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream6_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream7_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true +NVIC.DebugMonitor_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.EXTI4_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true +NVIC.EXTI9_5_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true +NVIC.ForceEnableDMAVector=true +NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.I2C2_ER_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true +NVIC.I2C2_EV_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true +NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.OTG_FS_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true +NVIC.PendSV_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.PriorityGroup=NVIC_PRIORITYGROUP_4 +NVIC.SPI1_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true +NVIC.SVCall_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +NVIC.SysTick_IRQn=true\:15\:0\:false\:false\:true\:false\:true\:false +NVIC.USART1_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true +NVIC.USART3_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true +NVIC.USART6_IRQn=true\:1\:0\:true\:false\:true\:true\:true\:true +NVIC.UsageFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false +PA11.Locked=true +PA11.Mode=Device_Only +PA11.Signal=USB_OTG_FS_DM +PA12.Locked=true +PA12.Mode=Device_Only +PA12.Signal=USB_OTG_FS_DP +PA13.Locked=true +PA13.Mode=Serial_Wire +PA13.Signal=SYS_JTMS-SWDIO +PA14.Locked=true +PA14.Mode=Serial_Wire +PA14.Signal=SYS_JTCK-SWCLK +PA4.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PA4.GPIO_Label=CS1_ACCEL +PA4.GPIO_PuPd=GPIO_PULLUP +PA4.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PA4.Locked=true +PA4.PinState=GPIO_PIN_SET +PA4.Signal=GPIO_Output +PA7.GPIOParameters=GPIO_Label +PA7.GPIO_Label=SPI1_MOSI +PA7.Locked=true +PA7.Mode=Full_Duplex_Master +PA7.Signal=SPI1_MOSI +PA9.Locked=true +PA9.Mode=Asynchronous +PA9.Signal=USART1_TX +PB0.GPIOParameters=GPIO_Speed,PinState,GPIO_PuPd,GPIO_Label +PB0.GPIO_Label=CS1_GYRO +PB0.GPIO_PuPd=GPIO_PULLUP +PB0.GPIO_Speed=GPIO_SPEED_FREQ_VERY_HIGH +PB0.Locked=true +PB0.PinState=GPIO_PIN_SET +PB0.Signal=GPIO_Output +PB3.GPIOParameters=GPIO_Label +PB3.GPIO_Label=SPI1_SCK +PB3.Locked=true +PB3.Mode=Full_Duplex_Master +PB3.Signal=SPI1_SCK +PB4.GPIOParameters=GPIO_Label +PB4.GPIO_Label=SPI1_MISO +PB4.Locked=true +PB4.Mode=Full_Duplex_Master +PB4.Signal=SPI1_MISO +PB5.Locked=true +PB5.Mode=CAN_Activate +PB5.Signal=CAN2_RX +PB6.Locked=true +PB6.Mode=CAN_Activate +PB6.Signal=CAN2_TX +PB7.Locked=true +PB7.Mode=Asynchronous +PB7.Signal=USART1_RX +PC10.Locked=true +PC10.Mode=Asynchronous +PC10.Signal=USART3_TX +PC11.Locked=true +PC11.Mode=Asynchronous +PC11.Signal=USART3_RX +PC4.GPIOParameters=GPIO_Label,GPIO_ModeDefaultEXTI +PC4.GPIO_Label=INT1_ACC +PC4.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PC4.Locked=true +PC4.Signal=GPXTI4 +PC5.GPIOParameters=GPIO_Label,GPIO_ModeDefaultEXTI +PC5.GPIO_Label=INT1_GYRO +PC5.GPIO_ModeDefaultEXTI=GPIO_MODE_IT_FALLING +PC5.Locked=true +PC5.Signal=GPXTI5 +PC6.GPIOParameters=GPIO_Label +PC6.GPIO_Label=CHANNEL5 +PC6.Locked=true +PC6.Signal=S_TIM8_CH1 +PCC.Checker=false +PCC.Display=Plot\: All Steps +PCC.Line=STM32F407/417 +PCC.MCU=STM32F407I(E-G)Hx +PCC.PartNumber=STM32F407IGHx +PCC.Series=STM32F4 +PCC.Temperature=25 +PCC.Vdd=3.3 +PD0.Locked=true +PD0.Mode=CAN_Activate +PD0.Signal=CAN1_RX +PD1.Locked=true +PD1.Mode=CAN_Activate +PD1.Signal=CAN1_TX +PE11.GPIOParameters=GPIO_Label +PE11.GPIO_Label=CHANNEL2 +PE11.Locked=true +PE11.Signal=S_TIM1_CH2 +PE13.GPIOParameters=GPIO_Label +PE13.GPIO_Label=CHANNEL3 +PE13.Locked=true +PE13.Signal=S_TIM1_CH3 +PE14.GPIOParameters=GPIO_Label +PE14.GPIO_Label=CHANNEL4 +PE14.Locked=true +PE14.Signal=S_TIM1_CH4 +PE9.GPIOParameters=GPIO_Label +PE9.GPIO_Label=CHANNEL1 +PE9.Locked=true +PE9.Signal=S_TIM1_CH1 +PF0.Locked=true +PF0.Mode=I2C +PF0.Signal=I2C2_SDA +PF1.Locked=true +PF1.Mode=I2C +PF1.Signal=I2C2_SCL +PG14.Locked=true +PG14.Mode=Asynchronous +PG14.Signal=USART6_TX +PG9.Locked=true +PG9.Mode=Asynchronous +PG9.Signal=USART6_RX +PH0-OSC_IN.Locked=true +PH0-OSC_IN.Mode=HSE-External-Oscillator +PH0-OSC_IN.Signal=RCC_OSC_IN +PH1-OSC_OUT.Locked=true +PH1-OSC_OUT.Mode=HSE-External-Oscillator +PH1-OSC_OUT.Signal=RCC_OSC_OUT +PH10.GPIOParameters=GPIO_Label +PH10.GPIO_Label=LED_B +PH10.Locked=true +PH10.Signal=S_TIM5_CH1 +PH11.GPIOParameters=GPIO_Label +PH11.GPIO_Label=LED_G +PH11.Locked=true +PH11.Signal=S_TIM5_CH2 +PH12.GPIOParameters=GPIO_Label +PH12.GPIO_Label=LED_R +PH12.Locked=true +PH12.Signal=S_TIM5_CH3 +PI6.GPIOParameters=GPIO_Label +PI6.GPIO_Label=CHANNEL6 +PI6.Locked=true +PI6.Signal=S_TIM8_CH2 +PI7.GPIOParameters=GPIO_Label +PI7.GPIO_Label=CHANNEL7 +PI7.Locked=true +PI7.Signal=S_TIM8_CH3 +PinOutPanel.CurrentBGAView=Top +PinOutPanel.RotationAngle=0 +ProjectManager.AskForMigrate=true +ProjectManager.BackupPrevious=false +ProjectManager.CompilerLinker=GCC +ProjectManager.CompilerOptimize=6 +ProjectManager.ComputerToolchain=false +ProjectManager.CoupleFile=true +ProjectManager.CustomerFirmwarePackage= +ProjectManager.DefaultFWLocation=true +ProjectManager.DeletePrevious=true +ProjectManager.DeviceId=STM32F407IGHx +ProjectManager.FirmwarePackage=STM32Cube FW_F4 V1.28.3 +ProjectManager.FreePins=false +ProjectManager.FreePinsContext= +ProjectManager.HalAssertFull=false +ProjectManager.HeapSize=0x200 +ProjectManager.KeepUserCode=true +ProjectManager.LastFirmware=true +ProjectManager.LibraryCopy=2 +ProjectManager.MainLocation=Core/Src +ProjectManager.NoMain=true +ProjectManager.PreviousToolchain= +ProjectManager.ProjectBuild=false +ProjectManager.ProjectFileName=rmcs_slave.ioc +ProjectManager.ProjectName=rmcs_slave +ProjectManager.ProjectStructure= +ProjectManager.RegisterCallBack= +ProjectManager.StackSize=0x400 +ProjectManager.TargetToolchain=CMake +ProjectManager.ToolChainLocation= +ProjectManager.UAScriptAfterPath= +ProjectManager.UAScriptBeforePath= +ProjectManager.UnderRoot=false +ProjectManager.functionlistsort=1-SystemClock_Config-RCC-false-HAL-false,2-MX_GPIO_Init-GPIO-false-HAL-true,3-MX_DMA_Init-DMA-false-HAL-true,4-MX_SPI1_Init-SPI1-false-HAL-true,5-MX_CAN1_Init-CAN1-false-HAL-true,6-MX_CAN2_Init-CAN2-false-HAL-true,7-MX_USART1_UART_Init-USART1-false-HAL-true,8-MX_USART3_UART_Init-USART3-false-HAL-true,9-MX_USART6_UART_Init-USART6-false-HAL-true,10-MX_TIM5_Init-TIM5-false-HAL-true,11-MX_USB_OTG_FS_PCD_Init-USB_OTG_FS-false-HAL-true,12-MX_TIM2_Init-TIM2-false-HAL-true,13-MX_TIM9_Init-TIM9-false-HAL-true,14-MX_TIM1_Init-TIM1-false-HAL-true,15-MX_TIM8_Init-TIM8-false-HAL-true,16-MX_I2C2_Init-I2C2-false-HAL-true +RCC.48MHZClocksFreq_Value=48000000 +RCC.AHBFreq_Value=168000000 +RCC.APB1CLKDivider=RCC_HCLK_DIV4 +RCC.APB1Freq_Value=42000000 +RCC.APB1TimFreq_Value=84000000 +RCC.APB2CLKDivider=RCC_HCLK_DIV2 +RCC.APB2Freq_Value=84000000 +RCC.APB2TimFreq_Value=168000000 +RCC.CortexFreq_Value=168000000 +RCC.EthernetFreq_Value=168000000 +RCC.FCLKCortexFreq_Value=168000000 +RCC.FamilyName=M +RCC.HCLKFreq_Value=168000000 +RCC.HSE_VALUE=12000000 +RCC.HSI_VALUE=16000000 +RCC.I2SClocksFreq_Value=192000000 +RCC.IPParameters=48MHZClocksFreq_Value,AHBFreq_Value,APB1CLKDivider,APB1Freq_Value,APB1TimFreq_Value,APB2CLKDivider,APB2Freq_Value,APB2TimFreq_Value,CortexFreq_Value,EthernetFreq_Value,FCLKCortexFreq_Value,FamilyName,HCLKFreq_Value,HSE_VALUE,HSI_VALUE,I2SClocksFreq_Value,LSE_VALUE,LSI_VALUE,MCO2PinFreq_Value,PLLCLKFreq_Value,PLLM,PLLN,PLLQ,PLLQCLKFreq_Value,RTCFreq_Value,RTCHSEDivFreq_Value,SYSCLKFreq_VALUE,SYSCLKSource,VCOI2SOutputFreq_Value,VCOInputFreq_Value,VCOOutputFreq_Value,VcooutputI2S +RCC.LSE_VALUE=32768 +RCC.LSI_VALUE=32000 +RCC.MCO2PinFreq_Value=168000000 +RCC.PLLCLKFreq_Value=168000000 +RCC.PLLM=6 +RCC.PLLN=168 +RCC.PLLQ=7 +RCC.PLLQCLKFreq_Value=48000000 +RCC.RTCFreq_Value=32000 +RCC.RTCHSEDivFreq_Value=6000000 +RCC.SYSCLKFreq_VALUE=168000000 +RCC.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK +RCC.VCOI2SOutputFreq_Value=384000000 +RCC.VCOInputFreq_Value=2000000 +RCC.VCOOutputFreq_Value=336000000 +RCC.VcooutputI2S=192000000 +SH.GPXTI4.0=GPIO_EXTI4 +SH.GPXTI4.ConfNb=1 +SH.GPXTI5.0=GPIO_EXTI5 +SH.GPXTI5.ConfNb=1 +SH.S_TIM1_CH1.0=TIM1_CH1,PWM Generation1 CH1 +SH.S_TIM1_CH1.ConfNb=1 +SH.S_TIM1_CH2.0=TIM1_CH2,PWM Generation2 CH2 +SH.S_TIM1_CH2.ConfNb=1 +SH.S_TIM1_CH3.0=TIM1_CH3,PWM Generation3 CH3 +SH.S_TIM1_CH3.ConfNb=1 +SH.S_TIM1_CH4.0=TIM1_CH4,PWM Generation4 CH4 +SH.S_TIM1_CH4.ConfNb=1 +SH.S_TIM5_CH1.0=TIM5_CH1,PWM Generation1 CH1 +SH.S_TIM5_CH1.ConfNb=1 +SH.S_TIM5_CH2.0=TIM5_CH2,PWM Generation2 CH2 +SH.S_TIM5_CH2.ConfNb=1 +SH.S_TIM5_CH3.0=TIM5_CH3,PWM Generation3 CH3 +SH.S_TIM5_CH3.ConfNb=1 +SH.S_TIM8_CH1.0=TIM8_CH1,PWM Generation1 CH1 +SH.S_TIM8_CH1.ConfNb=1 +SH.S_TIM8_CH2.0=TIM8_CH2,PWM Generation2 CH2 +SH.S_TIM8_CH2.ConfNb=1 +SH.S_TIM8_CH3.0=TIM8_CH3,PWM Generation3 CH3 +SH.S_TIM8_CH3.ConfNb=1 +SPI1.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_8 +SPI1.CLKPhase=SPI_PHASE_2EDGE +SPI1.CLKPolarity=SPI_POLARITY_HIGH +SPI1.CalculateBaudRate=10.5 MBits/s +SPI1.Direction=SPI_DIRECTION_2LINES +SPI1.IPParameters=VirtualType,Mode,Direction,CalculateBaudRate,BaudRatePrescaler,CLKPhase,CLKPolarity +SPI1.Mode=SPI_MODE_MASTER +SPI1.VirtualType=VM_MASTER +TIM1.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM1.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM1.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM1.Channel-PWM\ Generation4\ CH4=TIM_CHANNEL_4 +TIM1.IPParameters=Prescaler,Period,Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Channel-PWM Generation4 CH4 +TIM1.Period=59999 +TIM1.Prescaler=56 - 1 +TIM2.IPParameters=TIM_MasterSlaveMode,TIM_MasterOutputTrigger,Prescaler +TIM2.Prescaler=21 - 1 +TIM2.TIM_MasterOutputTrigger=TIM_TRGO_UPDATE +TIM2.TIM_MasterSlaveMode=TIM_MASTERSLAVEMODE_DISABLE +TIM5.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM5.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM5.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM5.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Period,Prescaler,Channel-PWM Generation3 CH3 +TIM5.Period=256-1 +TIM5.Prescaler=84-1 +TIM8.Channel-PWM\ Generation1\ CH1=TIM_CHANNEL_1 +TIM8.Channel-PWM\ Generation2\ CH2=TIM_CHANNEL_2 +TIM8.Channel-PWM\ Generation3\ CH3=TIM_CHANNEL_3 +TIM8.IPParameters=Channel-PWM Generation1 CH1,Channel-PWM Generation2 CH2,Channel-PWM Generation3 CH3,Period,Prescaler +TIM8.Period=59999 +TIM8.Prescaler=56 - 1 +TIM9.AutoReloadPreload=TIM_AUTORELOAD_PRELOAD_DISABLE +TIM9.IPParameters=AutoReloadPreload +USART1.IPParameters=VirtualMode +USART1.VirtualMode=VM_ASYNC +USART3.BaudRate=100000 +USART3.IPParameters=VirtualMode,StopBits,Parity,WordLength,BaudRate +USART3.Parity=PARITY_EVEN +USART3.StopBits=STOPBITS_1 +USART3.VirtualMode=VM_ASYNC +USART3.WordLength=WORDLENGTH_9B +USART6.IPParameters=VirtualMode +USART6.VirtualMode=VM_ASYNC +USB_OTG_FS.IPParameters=VirtualMode +USB_OTG_FS.VirtualMode=Device_Only +VP_SYS_VS_Systick.Mode=SysTick +VP_SYS_VS_Systick.Signal=SYS_VS_Systick +VP_TIM1_VS_ClockSourceINT.Mode=Internal +VP_TIM1_VS_ClockSourceINT.Signal=TIM1_VS_ClockSourceINT +VP_TIM2_VS_ClockSourceINT.Mode=Internal +VP_TIM2_VS_ClockSourceINT.Signal=TIM2_VS_ClockSourceINT +VP_TIM5_VS_ClockSourceINT.Mode=Internal +VP_TIM5_VS_ClockSourceINT.Signal=TIM5_VS_ClockSourceINT +VP_TIM8_VS_ClockSourceINT.Mode=Internal +VP_TIM8_VS_ClockSourceINT.Signal=TIM8_VS_ClockSourceINT +VP_TIM9_VS_ClockSourceITR.Mode=TriggerSource_ITR0 +VP_TIM9_VS_ClockSourceITR.Signal=TIM9_VS_ClockSourceITR +VP_TIM9_VS_ControllerModeClock.Mode=Clock Mode +VP_TIM9_VS_ControllerModeClock.Signal=TIM9_VS_ControllerModeClock +board=custom diff --git a/host/include/librmcs/agent/c_board.hpp b/host/include/librmcs/agent/c_board.hpp index 882e8d0..75d0ce1 100644 --- a/host/include/librmcs/agent/c_board.hpp +++ b/host/include/librmcs/agent/c_board.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -51,6 +52,19 @@ class CBoard : private data::DataCallback { return *this; } + PacketBuilder& i2c0_write(const librmcs::data::I2cDataView& data) { + if (data.payload.empty() || !builder_.write_i2c(data::DataId::kI2c0, data)) [[unlikely]] + throw std::invalid_argument{"I2C0 write failed: Invalid I2C data"}; + return *this; + } + + PacketBuilder& i2c0_read(const librmcs::data::I2cReadConfigView& data) { + if (data.read_length == 0 || !builder_.write_i2c_read_config(data::DataId::kI2c0, data)) + [[unlikely]] + throw std::invalid_argument{"I2C0 read failed: Invalid I2C read config"}; + return *this; + } + PacketBuilder& gpio_digital_write(const librmcs::data::GpioDigitalDataView& data) { if (data.channel < 1 || data.channel > 7 || !builder_.write_gpio_digital_data(data)) [[unlikely]] @@ -121,16 +135,23 @@ class CBoard : private data::DataCallback { } bool i2c_receive_callback(data::DataId id, const data::I2cDataView& data) final { - (void)id; - (void)data; - return false; + switch (id) { + case data::DataId::kI2c0: i2c0_receive_callback(data); return true; + default: return false; + } } void i2c_error_callback(data::DataId id, uint8_t slave_address) final { - (void)id; - (void)slave_address; + switch (id) { + case data::DataId::kI2c0: i2c0_error_callback(slave_address); break; + default: break; + } } + virtual void i2c0_receive_callback(const librmcs::data::I2cDataView& data) { (void)data; } + + virtual void i2c0_error_callback(uint8_t slave_address) { (void)slave_address; } + host::protocol::Handler handler_; }; diff --git a/host/include/librmcs/agent/rmcs_board.hpp b/host/include/librmcs/agent/rmcs_board.hpp index 157de51..6d10408 100644 --- a/host/include/librmcs/agent/rmcs_board.hpp +++ b/host/include/librmcs/agent/rmcs_board.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include From 12bce2b35f853047ea192fd04099e74db394b2df Mon Sep 17 00:00:00 2001 From: tcd <1369013595@qq.com> Date: Thu, 9 Apr 2026 12:42:34 +0000 Subject: [PATCH 3/7] fix(c_board): Replace queued I2C with blocking transfers --- firmware/c_board/app/src/i2c/i2c.cpp | 40 ------- firmware/c_board/app/src/i2c/i2c.hpp | 151 +++++++-------------------- 2 files changed, 37 insertions(+), 154 deletions(-) delete mode 100644 firmware/c_board/app/src/i2c/i2c.cpp diff --git a/firmware/c_board/app/src/i2c/i2c.cpp b/firmware/c_board/app/src/i2c/i2c.cpp deleted file mode 100644 index bbb7ccb..0000000 --- a/firmware/c_board/app/src/i2c/i2c.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include "firmware/c_board/app/src/i2c/i2c.hpp" - -#include - -#include "core/src/utility/assert.hpp" - -namespace librmcs::firmware::i2c { - -namespace { - -I2c& get_i2c_instance(I2C_HandleTypeDef* hal_i2c_handle) { - if (hal_i2c_handle == &hi2c2) - return *i2c0; - - core::utility::assert_failed_debug(); -} - -} // namespace - -extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).tx_complete_callback(); -} - -extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).rx_complete_callback(); -} - -extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).tx_complete_callback(); -} - -extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).rx_complete_callback(); -} - -extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).error_callback(); -} - -} // namespace librmcs::firmware::i2c diff --git a/firmware/c_board/app/src/i2c/i2c.hpp b/firmware/c_board/app/src/i2c/i2c.hpp index 5a5b45d..aef592e 100644 --- a/firmware/c_board/app/src/i2c/i2c.hpp +++ b/firmware/c_board/app/src/i2c/i2c.hpp @@ -1,10 +1,8 @@ #pragma once #include -#include #include #include -#include #include #include @@ -14,10 +12,8 @@ #include "core/src/protocol/serializer.hpp" #include "core/src/utility/assert.hpp" #include "core/src/utility/immovable.hpp" -#include "firmware/c_board/app/src/led/led.hpp" #include "firmware/c_board/app/src/usb/helper.hpp" #include "firmware/c_board/app/src/utility/lazy.hpp" -#include "firmware/c_board/app/src/utility/ring_buffer.hpp" namespace librmcs::firmware::i2c { @@ -38,23 +34,9 @@ class I2c : private core::utility::Immovable { return; } - if (request_queue_.emplace_back_n( - [&data](std::byte* storage) noexcept { - auto& request = *new (storage) Request{}; - request.operation = Operation::kWrite; - request.slave_address = data.slave_address; - request.length = static_cast(data.payload.size()); - request.has_register = data.has_register; - request.reg_address = data.reg_address; - std::memcpy(request.payload.data(), data.payload.data(), data.payload.size()); - }, - 1) - != 0) { - return; - } - - led::led->downlink_buffer_full(); - write_error(data.slave_address); + const auto status = write_blocking(data); + if (status != HAL_OK) + write_error(data.slave_address); } void handle_downlink_read_config(const data::I2cReadConfigView& data) { @@ -63,111 +45,55 @@ class I2c : private core::utility::Immovable { return; } - if (request_queue_.emplace_back_n( - [&data](std::byte* storage) noexcept { - auto& request = *new (storage) Request{}; - request.operation = Operation::kRead; - request.slave_address = data.slave_address; - request.length = data.read_length; - request.has_register = data.has_register; - request.reg_address = data.reg_address; - }, - 1) - != 0) { + const auto status = read_blocking(data); + if (status != HAL_OK) { + write_error(data.slave_address); return; } - led::led->downlink_buffer_full(); - write_error(data.slave_address); - } - - void update() { - while (!transfer_in_progress_.load(std::memory_order::acquire) - && request_queue_.pop_front([this](const Request& request) noexcept { - active_request_ = request; - if (!start_active_request()) - write_error(active_request_.slave_address); - })) {} - } - - void tx_complete_callback() { - core::utility::assert_debug(transfer_in_progress_.load(std::memory_order::acquire)); - transfer_in_progress_.store(false, std::memory_order::release); - } - - void rx_complete_callback() { - core::utility::assert_debug(transfer_in_progress_.load(std::memory_order::acquire)); - core::utility::assert_debug(active_request_.operation == Operation::kRead); - auto& serializer = usb::get_serializer(); const data::I2cDataView result{ - .slave_address = active_request_.slave_address, - .payload = std::span{read_buffer_.data(), active_request_.length}, - .has_register = active_request_.has_register, - .reg_address = active_request_.reg_address, + .slave_address = data.slave_address, + .payload = std::span{read_buffer_.data(), data.read_length}, + .has_register = data.has_register, + .reg_address = data.reg_address, }; core::utility::assert_always( serializer.write_i2c_read_result(data_id_, result) != core::protocol::Serializer::SerializeResult::kInvalidArgument); - - transfer_in_progress_.store(false, std::memory_order::release); } - void error_callback() { - core::utility::assert_debug(transfer_in_progress_.load(std::memory_order::acquire)); - write_error(active_request_.slave_address); - transfer_in_progress_.store(false, std::memory_order::release); - } + void update() {} private: static constexpr uint16_t kMaxDataLength = (1U << 9) - 1U; - static constexpr size_t kRequestQueueSize = 4; - - enum class Operation : uint8_t { - kWrite, - kRead, - }; - - struct Request { - Operation operation = Operation::kWrite; - uint8_t slave_address = 0; - uint16_t length = 0; - bool has_register = false; - uint8_t reg_address = 0; - std::array payload{}; - }; - - bool start_active_request() { - const auto hal_slave_address = to_hal_slave_address(active_request_.slave_address); - - transfer_in_progress_.store(true, std::memory_order::release); - - if (active_request_.operation == Operation::kWrite) { - auto* payload = reinterpret_cast(active_request_.payload.data()); - const auto status = - active_request_.has_register - ? HAL_I2C_Mem_Write_IT( - hal_i2c_handle_, hal_slave_address, active_request_.reg_address, - I2C_MEMADD_SIZE_8BIT, payload, active_request_.length) - : HAL_I2C_Master_Transmit_IT( - hal_i2c_handle_, hal_slave_address, payload, active_request_.length); - if (status == HAL_OK) - return true; - } else { - auto* payload = reinterpret_cast(read_buffer_.data()); - const auto status = - active_request_.has_register - ? HAL_I2C_Mem_Read_IT( - hal_i2c_handle_, hal_slave_address, active_request_.reg_address, - I2C_MEMADD_SIZE_8BIT, payload, active_request_.length) - : HAL_I2C_Master_Receive_IT( - hal_i2c_handle_, hal_slave_address, payload, active_request_.length); - if (status == HAL_OK) - return true; - } + static constexpr uint32_t kTransferTimeoutMs = 100U; + + HAL_StatusTypeDef write_blocking(const data::I2cDataView& data) { + const auto hal_slave_address = to_hal_slave_address(data.slave_address); + auto* payload = const_cast(reinterpret_cast(data.payload.data())); + const auto payload_length = static_cast(data.payload.size()); + + return data.has_register + ? HAL_I2C_Mem_Write( + hal_i2c_handle_, hal_slave_address, data.reg_address, I2C_MEMADD_SIZE_8BIT, + payload, payload_length, kTransferTimeoutMs) + : HAL_I2C_Master_Transmit( + hal_i2c_handle_, hal_slave_address, payload, payload_length, + kTransferTimeoutMs); + } - transfer_in_progress_.store(false, std::memory_order::release); - return false; + HAL_StatusTypeDef read_blocking(const data::I2cReadConfigView& data) { + const auto hal_slave_address = to_hal_slave_address(data.slave_address); + auto* payload = reinterpret_cast(read_buffer_.data()); + + return data.has_register + ? HAL_I2C_Mem_Read( + hal_i2c_handle_, hal_slave_address, data.reg_address, I2C_MEMADD_SIZE_8BIT, + payload, data.read_length, kTransferTimeoutMs) + : HAL_I2C_Master_Receive( + hal_i2c_handle_, hal_slave_address, payload, data.read_length, + kTransferTimeoutMs); } static uint16_t to_hal_slave_address(uint8_t slave_address) { @@ -183,9 +109,6 @@ class I2c : private core::utility::Immovable { const data::DataId data_id_; I2C_HandleTypeDef* hal_i2c_handle_; - utility::RingBuffer request_queue_; - std::atomic transfer_in_progress_ = false; - Request active_request_{}; std::array read_buffer_{}; }; From 20ea882728e23bd0716043fd559d1b5c0215d8f6 Mon Sep 17 00:00:00 2001 From: tcd <1369103595@qq.com> Date: Sat, 11 Apr 2026 07:28:45 +0000 Subject: [PATCH 4/7] fix(c_board): Recover i2c dma transfers on timeout --- firmware/c_board/app/src/i2c/i2c.cpp | 40 +++ firmware/c_board/app/src/i2c/i2c.hpp | 232 +++++++++++++++--- firmware/c_board/bsp/cubemx/Core/Inc/i2c.h | 4 +- .../bsp/cubemx/Core/Inc/stm32f4xx_it.h | 20 +- firmware/c_board/bsp/cubemx/Core/Src/dma.c | 24 +- firmware/c_board/bsp/cubemx/Core/Src/i2c.c | 68 ++++- .../bsp/cubemx/Core/Src/stm32f4xx_it.c | 56 ++++- firmware/c_board/bsp/cubemx/rmcs_slave.ioc | 48 +++- firmware/rmcs_board/app/src/i2c/i2c.hpp | 25 +- 9 files changed, 413 insertions(+), 104 deletions(-) create mode 100644 firmware/c_board/app/src/i2c/i2c.cpp diff --git a/firmware/c_board/app/src/i2c/i2c.cpp b/firmware/c_board/app/src/i2c/i2c.cpp new file mode 100644 index 0000000..43e8013 --- /dev/null +++ b/firmware/c_board/app/src/i2c/i2c.cpp @@ -0,0 +1,40 @@ +#include "firmware/c_board/app/src/i2c/i2c.hpp" + +#include + +#include "core/src/utility/assert.hpp" + +namespace librmcs::firmware::i2c { + +namespace { + +I2c& get_i2c_instance(I2C_HandleTypeDef* hal_i2c_handle) { + if (hal_i2c_handle == &hi2c2) + return *i2c0; + + core::utility::assert_failed_debug(); +} + +} // namespace + +extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).tx_complete_callback(); +} + +extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).tx_complete_callback(); +} + +extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).rx_complete_callback(); +} + +extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).rx_complete_callback(); +} + +extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c) { + get_i2c_instance(hi2c).error_callback(); +} + +} // namespace librmcs::firmware::i2c diff --git a/firmware/c_board/app/src/i2c/i2c.hpp b/firmware/c_board/app/src/i2c/i2c.hpp index aef592e..71e12f7 100644 --- a/firmware/c_board/app/src/i2c/i2c.hpp +++ b/firmware/c_board/app/src/i2c/i2c.hpp @@ -1,19 +1,26 @@ #pragma once #include +#include #include #include +#include #include #include #include +#include #include "core/include/librmcs/data/datas.hpp" #include "core/src/protocol/serializer.hpp" #include "core/src/utility/assert.hpp" #include "core/src/utility/immovable.hpp" +#include "firmware/c_board/app/src/led/led.hpp" +#include "firmware/c_board/app/src/timer/timer.hpp" #include "firmware/c_board/app/src/usb/helper.hpp" +#include "firmware/c_board/app/src/utility/interrupt_lock.hpp" #include "firmware/c_board/app/src/utility/lazy.hpp" +#include "firmware/c_board/app/src/utility/ring_buffer.hpp" namespace librmcs::firmware::i2c { @@ -23,7 +30,11 @@ class I2c : private core::utility::Immovable { I2c(data::DataId data_id, I2C_HandleTypeDef* hal_i2c_handle) : data_id_(data_id) - , hal_i2c_handle_(hal_i2c_handle) {} + , hal_i2c_handle_(hal_i2c_handle) { + core::utility::assert_always(hal_i2c_handle_ != nullptr); + core::utility::assert_always(hal_i2c_handle_->hdmarx != nullptr); + core::utility::assert_always(hal_i2c_handle_->hdmatx != nullptr); + } void handle_downlink_write(const data::I2cDataView& data) { if (data.payload.empty()) @@ -34,9 +45,10 @@ class I2c : private core::utility::Immovable { return; } - const auto status = write_blocking(data); - if (status != HAL_OK) + if (!enqueue_write_request(data)) { + led::led->downlink_buffer_full(); write_error(data.slave_address); + } } void handle_downlink_read_config(const data::I2cReadConfigView& data) { @@ -45,55 +57,193 @@ class I2c : private core::utility::Immovable { return; } - const auto status = read_blocking(data); - if (status != HAL_OK) { + if (!enqueue_read_request(data)) { + led::led->downlink_buffer_full(); write_error(data.slave_address); + } + } + + void update() { + if (transfer_state_.load(std::memory_order::acquire) != TransferState::kIdle) { + recover_timed_out_transfer(); + if (transfer_state_.load(std::memory_order::acquire) != TransferState::kIdle) + return; + } + + Request request{}; + const auto popped = + request_queue_.pop_front([&request](Request pending) noexcept { request = pending; }); + if (!popped) return; + + active_request_ = request; + transfer_start_timepoint_ = timer::timer->timepoint(); + transfer_state_.store(request.transfer_state(), std::memory_order::release); + + if (!start_dma_transfer(active_request_)) { + finish_active_request(); + write_error(active_request_.slave_address); } + } - auto& serializer = usb::get_serializer(); - const data::I2cDataView result{ - .slave_address = data.slave_address, - .payload = std::span{read_buffer_.data(), data.read_length}, - .has_register = data.has_register, - .reg_address = data.reg_address, - }; - core::utility::assert_always( - serializer.write_i2c_read_result(data_id_, result) - != core::protocol::Serializer::SerializeResult::kInvalidArgument); + void tx_complete_callback() { + const auto state = transfer_state_.load(std::memory_order::acquire); + core::utility::assert_debug(state == TransferState::kWrite); + finish_active_request(); + } + + void rx_complete_callback() { + const auto state = transfer_state_.load(std::memory_order::acquire); + core::utility::assert_debug(state == TransferState::kRead); + const auto request = active_request_; + finish_active_request(); + write_read_result(request); } - void update() {} + void error_callback() { + const auto state = transfer_state_.load(std::memory_order::acquire); + if (state == TransferState::kIdle) + return; + + const auto slave_address = active_request_.slave_address; + finish_active_request(); + write_error(slave_address); + } private: static constexpr uint16_t kMaxDataLength = (1U << 9) - 1U; - static constexpr uint32_t kTransferTimeoutMs = 100U; + static constexpr size_t kRequestQueueSize = 8; + static constexpr timer::Timer::Duration kTransferTimeout{timer::Timer::kClockFrequency / 10}; - HAL_StatusTypeDef write_blocking(const data::I2cDataView& data) { - const auto hal_slave_address = to_hal_slave_address(data.slave_address); - auto* payload = const_cast(reinterpret_cast(data.payload.data())); - const auto payload_length = static_cast(data.payload.size()); + enum class RequestType : uint8_t { + kWrite, + kRead, + }; + + enum class TransferState : uint8_t { + kIdle, + kWrite, + kRead, + }; + + struct Request { + RequestType type = RequestType::kWrite; + uint8_t slave_address = 0; + uint16_t data_length = 0; + bool has_register = false; + uint8_t reg_address = 0; + alignas(uint32_t) std::array payload{}; + + TransferState transfer_state() const { + return type == RequestType::kWrite ? TransferState::kWrite : TransferState::kRead; + } + }; + + bool enqueue_write_request(const data::I2cDataView& data) { + return request_queue_.emplace_back_n( + [&data](std::byte* storage) noexcept { + auto& request = *new (storage) Request{}; + request.type = RequestType::kWrite; + request.slave_address = data.slave_address; + request.data_length = static_cast(data.payload.size()); + request.has_register = data.has_register; + request.reg_address = data.reg_address; + std::memcpy( + request.payload.data(), data.payload.data(), data.payload.size()); + }, + 1, true) + == 1; + } - return data.has_register - ? HAL_I2C_Mem_Write( - hal_i2c_handle_, hal_slave_address, data.reg_address, I2C_MEMADD_SIZE_8BIT, - payload, payload_length, kTransferTimeoutMs) - : HAL_I2C_Master_Transmit( - hal_i2c_handle_, hal_slave_address, payload, payload_length, - kTransferTimeoutMs); + bool enqueue_read_request(const data::I2cReadConfigView& data) { + return request_queue_.emplace_back_n( + [&data](std::byte* storage) noexcept { + auto& request = *new (storage) Request{}; + request.type = RequestType::kRead; + request.slave_address = data.slave_address; + request.data_length = data.read_length; + request.has_register = data.has_register; + request.reg_address = data.reg_address; + }, + 1, true) + == 1; } - HAL_StatusTypeDef read_blocking(const data::I2cReadConfigView& data) { - const auto hal_slave_address = to_hal_slave_address(data.slave_address); - auto* payload = reinterpret_cast(read_buffer_.data()); + bool start_dma_transfer(Request& request) { + const auto hal_slave_address = to_hal_slave_address(request.slave_address); - return data.has_register - ? HAL_I2C_Mem_Read( - hal_i2c_handle_, hal_slave_address, data.reg_address, I2C_MEMADD_SIZE_8BIT, - payload, data.read_length, kTransferTimeoutMs) - : HAL_I2C_Master_Receive( - hal_i2c_handle_, hal_slave_address, payload, data.read_length, - kTransferTimeoutMs); + HAL_StatusTypeDef status; + if (request.type == RequestType::kWrite) { + auto* payload = reinterpret_cast(request.payload.data()); + status = request.has_register + ? HAL_I2C_Mem_Write_DMA( + hal_i2c_handle_, hal_slave_address, request.reg_address, + I2C_MEMADD_SIZE_8BIT, payload, request.data_length) + : HAL_I2C_Master_Transmit_DMA( + hal_i2c_handle_, hal_slave_address, payload, request.data_length); + } else { + auto* payload = reinterpret_cast(read_buffer_.data()); + status = request.has_register + ? HAL_I2C_Mem_Read_DMA( + hal_i2c_handle_, hal_slave_address, request.reg_address, + I2C_MEMADD_SIZE_8BIT, payload, request.data_length) + : HAL_I2C_Master_Receive_DMA( + hal_i2c_handle_, hal_slave_address, payload, request.data_length); + } + + return status == HAL_OK; + } + + void recover_timed_out_transfer() { + if (!timer::timer->check_expired(transfer_start_timepoint_, kTransferTimeout)) + return; + + uint8_t slave_address; + { + const utility::InterruptLockGuard guard; + + if (transfer_state_.load(std::memory_order::relaxed) == TransferState::kIdle) + return; + + if (!timer::timer->check_expired(transfer_start_timepoint_, kTransferTimeout)) + return; + + slave_address = active_request_.slave_address; + abort_dma_if_enabled(hal_i2c_handle_->hdmarx); + abort_dma_if_enabled(hal_i2c_handle_->hdmatx); + core::utility::assert_always(HAL_I2C_DeInit(hal_i2c_handle_) == HAL_OK); + core::utility::assert_always(HAL_I2C_Init(hal_i2c_handle_) == HAL_OK); + finish_active_request(); + } + + write_error(slave_address); + } + + static void abort_dma_if_enabled(DMA_HandleTypeDef* hal_dma_handle) { + core::utility::assert_debug(hal_dma_handle != nullptr); + + if (hal_dma_handle->State == HAL_DMA_STATE_READY) + return; + + core::utility::assert_always(HAL_DMA_Abort(hal_dma_handle) == HAL_OK); + } + + void finish_active_request() { + transfer_start_timepoint_ = timer::Timer::TimePoint::min(); + transfer_state_.store(TransferState::kIdle, std::memory_order::release); + } + + void write_read_result(const Request& request) { + auto& serializer = usb::get_serializer(); + const data::I2cDataView result{ + .slave_address = request.slave_address, + .payload = std::span{read_buffer_.data(), request.data_length}, + .has_register = request.has_register, + .reg_address = request.reg_address, + }; + core::utility::assert_always( + serializer.write_i2c_read_result(data_id_, result) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); } static uint16_t to_hal_slave_address(uint8_t slave_address) { @@ -109,7 +259,11 @@ class I2c : private core::utility::Immovable { const data::DataId data_id_; I2C_HandleTypeDef* hal_i2c_handle_; - std::array read_buffer_{}; + utility::RingBuffer request_queue_; + Request active_request_{}; + std::atomic transfer_state_{TransferState::kIdle}; + timer::Timer::TimePoint transfer_start_timepoint_{timer::Timer::TimePoint::min()}; + alignas(uint32_t) std::array read_buffer_{}; }; inline constinit I2c::Lazy i2c0{data::DataId::kI2c0, &hi2c2}; diff --git a/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h b/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h index ef87b7e..80f59c4 100644 --- a/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h +++ b/firmware/c_board/bsp/cubemx/Core/Inc/i2c.h @@ -32,7 +32,9 @@ extern "C" { #include "stm32f4xx_hal_i2c.h" // IWYU pragma: export /* USER CODE END Includes */ -extern I2C_HandleTypeDef hi2c2; +extern I2C_HandleTypeDef hi2c2; +extern DMA_HandleTypeDef hdma_i2c2_rx; +extern DMA_HandleTypeDef hdma_i2c2_tx; /* USER CODE BEGIN Private defines */ diff --git a/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h b/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h index 195c454..081bc60 100644 --- a/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h +++ b/firmware/c_board/bsp/cubemx/Core/Inc/stm32f4xx_it.h @@ -55,10 +55,11 @@ void SVC_Handler(void); void DebugMon_Handler(void); void PendSV_Handler(void); void SysTick_Handler(void); -void EXTI4_IRQHandler(void); -void DMA1_Stream1_IRQHandler(void); -void DMA1_Stream3_IRQHandler(void); -void CAN1_RX0_IRQHandler(void); +void EXTI4_IRQHandler(void); +void DMA1_Stream1_IRQHandler(void); +void DMA1_Stream2_IRQHandler(void); +void DMA1_Stream3_IRQHandler(void); +void CAN1_RX0_IRQHandler(void); void EXTI9_5_IRQHandler(void); void I2C2_EV_IRQHandler(void); void I2C2_ER_IRQHandler(void); @@ -69,11 +70,12 @@ void DMA2_Stream0_IRQHandler(void); void DMA2_Stream1_IRQHandler(void); void DMA2_Stream3_IRQHandler(void); void CAN2_RX0_IRQHandler(void); -void OTG_FS_IRQHandler(void); -void DMA2_Stream5_IRQHandler(void); -void DMA2_Stream6_IRQHandler(void); -void DMA2_Stream7_IRQHandler(void); -void USART6_IRQHandler(void); +void OTG_FS_IRQHandler(void); +void DMA2_Stream5_IRQHandler(void); +void DMA2_Stream6_IRQHandler(void); +void DMA1_Stream7_IRQHandler(void); +void DMA2_Stream7_IRQHandler(void); +void USART6_IRQHandler(void); /* USER CODE BEGIN EFP */ /* USER CODE END EFP */ diff --git a/firmware/c_board/bsp/cubemx/Core/Src/dma.c b/firmware/c_board/bsp/cubemx/Core/Src/dma.c index 48a934a..bd7034f 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/dma.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/dma.c @@ -44,15 +44,21 @@ void MX_DMA_Init(void) __HAL_RCC_DMA1_CLK_ENABLE(); /* DMA interrupt init */ - /* DMA1_Stream1_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0); - HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); - /* DMA1_Stream3_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 6, 0); - HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); - /* DMA2_Stream0_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 4, 0); - HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); + /* DMA1_Stream1_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); + /* DMA1_Stream2_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); + /* DMA1_Stream3_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 6, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); + /* DMA1_Stream7_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn); + /* DMA2_Stream0_IRQn interrupt configuration */ + HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 4, 0); + HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); /* DMA2_Stream1_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn); diff --git a/firmware/c_board/bsp/cubemx/Core/Src/i2c.c b/firmware/c_board/bsp/cubemx/Core/Src/i2c.c index 6c195b8..e69b8f4 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/i2c.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/i2c.c @@ -24,7 +24,9 @@ /* USER CODE END 0 */ -I2C_HandleTypeDef hi2c2; +I2C_HandleTypeDef hi2c2; +DMA_HandleTypeDef hdma_i2c2_rx; +DMA_HandleTypeDef hdma_i2c2_tx; /* I2C2 init function */ void MX_I2C2_Init(void) @@ -78,12 +80,49 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) GPIO_InitStruct.Alternate = GPIO_AF4_I2C2; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); - /* I2C2 clock enable */ - __HAL_RCC_I2C2_CLK_ENABLE(); - - /* I2C2 interrupt Init */ - HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); + /* I2C2 clock enable */ + __HAL_RCC_I2C2_CLK_ENABLE(); + + /* I2C2 DMA Init */ + /* I2C2_RX Init */ + hdma_i2c2_rx.Instance = DMA1_Stream2; + hdma_i2c2_rx.Init.Channel = DMA_CHANNEL_7; + hdma_i2c2_rx.Init.Direction = DMA_PERIPH_TO_MEMORY; + hdma_i2c2_rx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_i2c2_rx.Init.MemInc = DMA_MINC_ENABLE; + hdma_i2c2_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_i2c2_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_i2c2_rx.Init.Mode = DMA_NORMAL; + hdma_i2c2_rx.Init.Priority = DMA_PRIORITY_MEDIUM; + hdma_i2c2_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_i2c2_rx) != HAL_OK) + { + Error_Handler(); + } + + __HAL_LINKDMA(i2cHandle,hdmarx,hdma_i2c2_rx); + + /* I2C2_TX Init */ + hdma_i2c2_tx.Instance = DMA1_Stream7; + hdma_i2c2_tx.Init.Channel = DMA_CHANNEL_7; + hdma_i2c2_tx.Init.Direction = DMA_MEMORY_TO_PERIPH; + hdma_i2c2_tx.Init.PeriphInc = DMA_PINC_DISABLE; + hdma_i2c2_tx.Init.MemInc = DMA_MINC_ENABLE; + hdma_i2c2_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; + hdma_i2c2_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE; + hdma_i2c2_tx.Init.Mode = DMA_NORMAL; + hdma_i2c2_tx.Init.Priority = DMA_PRIORITY_MEDIUM; + hdma_i2c2_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE; + if (HAL_DMA_Init(&hdma_i2c2_tx) != HAL_OK) + { + Error_Handler(); + } + + __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c2_tx); + + /* I2C2 interrupt Init */ + HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0); + HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0); HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); /* USER CODE BEGIN I2C2_MspInit 1 */ @@ -107,12 +146,15 @@ void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle) PF0 ------> I2C2_SDA PF1 ------> I2C2_SCL */ - HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0); - - HAL_GPIO_DeInit(GPIOF, GPIO_PIN_1); - - /* I2C2 interrupt Deinit */ - HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); + HAL_GPIO_DeInit(GPIOF, GPIO_PIN_0); + + HAL_GPIO_DeInit(GPIOF, GPIO_PIN_1); + + HAL_DMA_DeInit(i2cHandle->hdmarx); + HAL_DMA_DeInit(i2cHandle->hdmatx); + + /* I2C2 interrupt Deinit */ + HAL_NVIC_DisableIRQ(I2C2_EV_IRQn); HAL_NVIC_DisableIRQ(I2C2_ER_IRQn); /* USER CODE BEGIN I2C2_MspDeInit 1 */ diff --git a/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c b/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c index 935cb65..b9ec281 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/stm32f4xx_it.c @@ -59,11 +59,13 @@ void tusb_int_handler(uint8_t rhport, bool in_isr); /* USER CODE END 0 */ /* External variables --------------------------------------------------------*/ -extern CAN_HandleTypeDef hcan1; -extern CAN_HandleTypeDef hcan2; -extern I2C_HandleTypeDef hi2c2; -extern DMA_HandleTypeDef hdma_spi1_rx; -extern DMA_HandleTypeDef hdma_spi1_tx; +extern CAN_HandleTypeDef hcan1; +extern CAN_HandleTypeDef hcan2; +extern I2C_HandleTypeDef hi2c2; +extern DMA_HandleTypeDef hdma_i2c2_rx; +extern DMA_HandleTypeDef hdma_i2c2_tx; +extern DMA_HandleTypeDef hdma_spi1_rx; +extern DMA_HandleTypeDef hdma_spi1_tx; extern SPI_HandleTypeDef hspi1; extern DMA_HandleTypeDef hdma_usart1_rx; extern DMA_HandleTypeDef hdma_usart1_tx; @@ -245,10 +247,24 @@ void DMA1_Stream1_IRQHandler(void) /* USER CODE END DMA1_Stream1_IRQn 1 */ } -/** - * @brief This function handles DMA1 stream3 global interrupt. - */ -void DMA1_Stream3_IRQHandler(void) +/** + * @brief This function handles DMA1 stream2 global interrupt. + */ +void DMA1_Stream2_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Stream2_IRQn 0 */ + + /* USER CODE END DMA1_Stream2_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_i2c2_rx); + /* USER CODE BEGIN DMA1_Stream2_IRQn 1 */ + + /* USER CODE END DMA1_Stream2_IRQn 1 */ +} + +/** + * @brief This function handles DMA1 stream3 global interrupt. + */ +void DMA1_Stream3_IRQHandler(void) { /* USER CODE BEGIN DMA1_Stream3_IRQn 0 */ @@ -415,10 +431,24 @@ void CAN2_RX0_IRQHandler(void) /* USER CODE END CAN2_RX0_IRQn 1 */ } -/** - * @brief This function handles USB On The Go FS global interrupt. - */ -void OTG_FS_IRQHandler(void) +/** + * @brief This function handles DMA1 stream7 global interrupt. + */ +void DMA1_Stream7_IRQHandler(void) +{ + /* USER CODE BEGIN DMA1_Stream7_IRQn 0 */ + + /* USER CODE END DMA1_Stream7_IRQn 0 */ + HAL_DMA_IRQHandler(&hdma_i2c2_tx); + /* USER CODE BEGIN DMA1_Stream7_IRQn 1 */ + + /* USER CODE END DMA1_Stream7_IRQn 1 */ +} + +/** + * @brief This function handles USB On The Go FS global interrupt. + */ +void OTG_FS_IRQHandler(void) { /* USER CODE BEGIN OTG_FS_IRQn 0 */ tusb_int_handler(0, true); diff --git a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc index 255cea8..421c001 100644 --- a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc +++ b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc @@ -22,11 +22,13 @@ Dma.Request0=SPI1_RX Dma.Request1=SPI1_TX Dma.Request2=USART1_RX Dma.Request3=USART1_TX -Dma.Request4=USART3_RX -Dma.Request5=USART3_TX -Dma.Request6=USART6_RX -Dma.Request7=USART6_TX -Dma.RequestsNb=8 +Dma.Request4=USART3_RX +Dma.Request5=USART3_TX +Dma.Request6=USART6_RX +Dma.Request7=USART6_TX +Dma.Request8=I2C2_RX +Dma.Request9=I2C2_TX +Dma.RequestsNb=10 Dma.SPI1_RX.0.Direction=DMA_PERIPH_TO_MEMORY Dma.SPI1_RX.0.FIFOMode=DMA_FIFOMODE_DISABLE Dma.SPI1_RX.0.Instance=DMA2_Stream0 @@ -103,10 +105,30 @@ Dma.USART6_TX.7.Instance=DMA2_Stream6 Dma.USART6_TX.7.MemDataAlignment=DMA_MDATAALIGN_BYTE Dma.USART6_TX.7.MemInc=DMA_MINC_ENABLE Dma.USART6_TX.7.Mode=DMA_NORMAL -Dma.USART6_TX.7.PeriphDataAlignment=DMA_PDATAALIGN_BYTE -Dma.USART6_TX.7.PeriphInc=DMA_PINC_DISABLE -Dma.USART6_TX.7.Priority=DMA_PRIORITY_LOW -Dma.USART6_TX.7.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.USART6_TX.7.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.USART6_TX.7.PeriphInc=DMA_PINC_DISABLE +Dma.USART6_TX.7.Priority=DMA_PRIORITY_LOW +Dma.USART6_TX.7.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.I2C2_RX.8.Direction=DMA_PERIPH_TO_MEMORY +Dma.I2C2_RX.8.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.I2C2_RX.8.Instance=DMA1_Stream2 +Dma.I2C2_RX.8.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.I2C2_RX.8.MemInc=DMA_MINC_ENABLE +Dma.I2C2_RX.8.Mode=DMA_NORMAL +Dma.I2C2_RX.8.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.I2C2_RX.8.PeriphInc=DMA_PINC_DISABLE +Dma.I2C2_RX.8.Priority=DMA_PRIORITY_MEDIUM +Dma.I2C2_RX.8.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode +Dma.I2C2_TX.9.Direction=DMA_MEMORY_TO_PERIPH +Dma.I2C2_TX.9.FIFOMode=DMA_FIFOMODE_DISABLE +Dma.I2C2_TX.9.Instance=DMA1_Stream7 +Dma.I2C2_TX.9.MemDataAlignment=DMA_MDATAALIGN_BYTE +Dma.I2C2_TX.9.MemInc=DMA_MINC_ENABLE +Dma.I2C2_TX.9.Mode=DMA_NORMAL +Dma.I2C2_TX.9.PeriphDataAlignment=DMA_PDATAALIGN_BYTE +Dma.I2C2_TX.9.PeriphInc=DMA_PINC_DISABLE +Dma.I2C2_TX.9.Priority=DMA_PRIORITY_MEDIUM +Dma.I2C2_TX.9.RequestParameters=Instance,Direction,PeriphInc,MemInc,PeriphDataAlignment,MemDataAlignment,Mode,Priority,FIFOMode File.Version=6 GPIO.groupedBy=Group By Peripherals KeepUserPlacement=true @@ -183,9 +205,11 @@ MxDb.Version=DB.6.0.161 NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.CAN1_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true NVIC.CAN2_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true -NVIC.DMA1_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA1_Stream3_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA2_Stream0_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream2_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream3_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream7_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA2_Stream0_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream3_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream5_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true diff --git a/firmware/rmcs_board/app/src/i2c/i2c.hpp b/firmware/rmcs_board/app/src/i2c/i2c.hpp index 1917c95..9b46564 100644 --- a/firmware/rmcs_board/app/src/i2c/i2c.hpp +++ b/firmware/rmcs_board/app/src/i2c/i2c.hpp @@ -33,6 +33,11 @@ class I2c : private core::utility::Immovable { if (data.payload.empty()) return; + if (data.payload.size() > kMaxDataLength) { + write_error(data.slave_address); + return; + } + const auto* payload = reinterpret_cast(data.payload.data()); hpm_stat_t status = status_fail; if (data.has_register) { @@ -47,17 +52,16 @@ class I2c : private core::utility::Immovable { } if (status != status_success) { - auto& serializer = usb::get_serializer(); - core::utility::assert_always( - serializer.write_i2c_error(data_id_, data.slave_address) - != core::protocol::Serializer::SerializeResult::kInvalidArgument); + write_error(data.slave_address); return; } } void handle_downlink_read_config(const data::I2cReadConfigView& data) { - if (data.read_length == 0 || data.read_length > kMaxDataLength) + if (data.read_length == 0 || data.read_length > kMaxDataLength) { + write_error(data.slave_address); return; + } auto* payload = reinterpret_cast(read_buffer_.data()); hpm_stat_t status = status_fail; @@ -72,9 +76,7 @@ class I2c : private core::utility::Immovable { auto& serializer = usb::get_serializer(); if (status != status_success) { - core::utility::assert_always( - serializer.write_i2c_error(data_id_, data.slave_address) - != core::protocol::Serializer::SerializeResult::kInvalidArgument); + write_error(data.slave_address); return; } @@ -93,6 +95,13 @@ class I2c : private core::utility::Immovable { private: static constexpr uint16_t kMaxDataLength = (1U << 9) - 1U; + void write_error(uint8_t slave_address) { + auto& serializer = usb::get_serializer(); + core::utility::assert_always( + serializer.write_i2c_error(data_id_, slave_address) + != core::protocol::Serializer::SerializeResult::kInvalidArgument); + } + const data::DataId data_id_; I2C_Type* i2c_base_; std::array read_buffer_{}; From 9e7d481594183368133b4ddf6ee534c284246ce4 Mon Sep 17 00:00:00 2001 From: tcd <1369103595@qq.com> Date: Sat, 11 Apr 2026 12:56:19 +0000 Subject: [PATCH 5/7] refactor(c_board): Clarify logical i2c0 to i2c2 mapping --- firmware/c_board/app/src/app.cpp | 1 + firmware/c_board/app/src/i2c/i2c.cpp | 14 +- firmware/c_board/app/src/i2c/i2c.hpp | 217 +++++++++++++++++----- host/include/librmcs/agent/c_board.hpp | 13 +- host/include/librmcs/agent/rmcs_board.hpp | 12 +- host/src/protocol/handler.cpp | 21 ++- 6 files changed, 212 insertions(+), 66 deletions(-) diff --git a/firmware/c_board/app/src/app.cpp b/firmware/c_board/app/src/app.cpp index cccff55..ed97b59 100644 --- a/firmware/c_board/app/src/app.cpp +++ b/firmware/c_board/app/src/app.cpp @@ -50,6 +50,7 @@ App::App() { MX_SPI1_Init(); MX_CAN1_Init(); MX_CAN2_Init(); + // c_board routes the protocol-facing logical I2C0 channel through STM32 I2C2. MX_I2C2_Init(); MX_USART1_UART_Init(); MX_USART3_UART_Init(); diff --git a/firmware/c_board/app/src/i2c/i2c.cpp b/firmware/c_board/app/src/i2c/i2c.cpp index 43e8013..a147b6e 100644 --- a/firmware/c_board/app/src/i2c/i2c.cpp +++ b/firmware/c_board/app/src/i2c/i2c.cpp @@ -8,7 +8,9 @@ namespace librmcs::firmware::i2c { namespace { -I2c& get_i2c_instance(I2C_HandleTypeDef* hal_i2c_handle) { +// HAL callbacks carry the physical STM32 I2C handle. Map it back to the +// protocol-facing logical I2C channel used by the rest of the firmware. +I2c& get_logical_i2c_instance(I2C_HandleTypeDef* hal_i2c_handle) { if (hal_i2c_handle == &hi2c2) return *i2c0; @@ -18,23 +20,23 @@ I2c& get_i2c_instance(I2C_HandleTypeDef* hal_i2c_handle) { } // namespace extern "C" void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).tx_complete_callback(); + get_logical_i2c_instance(hi2c).tx_complete_callback(); } extern "C" void HAL_I2C_MemTxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).tx_complete_callback(); + get_logical_i2c_instance(hi2c).tx_complete_callback(); } extern "C" void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).rx_complete_callback(); + get_logical_i2c_instance(hi2c).rx_complete_callback(); } extern "C" void HAL_I2C_MemRxCpltCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).rx_complete_callback(); + get_logical_i2c_instance(hi2c).rx_complete_callback(); } extern "C" void HAL_I2C_ErrorCallback(I2C_HandleTypeDef* hi2c) { - get_i2c_instance(hi2c).error_callback(); + get_logical_i2c_instance(hi2c).error_callback(); } } // namespace librmcs::firmware::i2c diff --git a/firmware/c_board/app/src/i2c/i2c.hpp b/firmware/c_board/app/src/i2c/i2c.hpp index 71e12f7..edd2e56 100644 --- a/firmware/c_board/app/src/i2c/i2c.hpp +++ b/firmware/c_board/app/src/i2c/i2c.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -48,6 +49,8 @@ class I2c : private core::utility::Immovable { if (!enqueue_write_request(data)) { led::led->downlink_buffer_full(); write_error(data.slave_address); + } else { + try_start_next_request(); } } @@ -60,44 +63,37 @@ class I2c : private core::utility::Immovable { if (!enqueue_read_request(data)) { led::led->downlink_buffer_full(); write_error(data.slave_address); + } else { + try_start_next_request(); } } void update() { - if (transfer_state_.load(std::memory_order::acquire) != TransferState::kIdle) { + if (transfer_state_.load(std::memory_order::acquire) != TransferState::kIdle) recover_timed_out_transfer(); - if (transfer_state_.load(std::memory_order::acquire) != TransferState::kIdle) - return; - } - - Request request{}; - const auto popped = - request_queue_.pop_front([&request](Request pending) noexcept { request = pending; }); - if (!popped) - return; - - active_request_ = request; - transfer_start_timepoint_ = timer::timer->timepoint(); - transfer_state_.store(request.transfer_state(), std::memory_order::release); - if (!start_dma_transfer(active_request_)) { - finish_active_request(); - write_error(active_request_.slave_address); - } + try_start_next_request(); } void tx_complete_callback() { const auto state = transfer_state_.load(std::memory_order::acquire); core::utility::assert_debug(state == TransferState::kWrite); + finish_active_request(); + try_start_next_request(); } void rx_complete_callback() { const auto state = transfer_state_.load(std::memory_order::acquire); core::utility::assert_debug(state == TransferState::kRead); + const auto request = active_request_; + std::memcpy(read_result_buffer_.data(), read_dma_buffer_.data(), request.data_length); + finish_active_request(); - write_read_result(request); + try_start_next_request(); + write_read_result( + request, {read_result_buffer_.data(), static_cast(request.data_length)}); } void error_callback() { @@ -107,14 +103,20 @@ class I2c : private core::utility::Immovable { const auto slave_address = active_request_.slave_address; finish_active_request(); + try_start_next_request(); write_error(slave_address); } private: static constexpr uint16_t kMaxDataLength = (1U << 9) - 1U; - static constexpr size_t kRequestQueueSize = 8; + static constexpr size_t kRequestQueueSize = 32; + static constexpr size_t kPayloadChunkSize = 64; + static constexpr size_t kPayloadChunkCount = 32; + static constexpr size_t kPayloadChunkMask = kPayloadChunkCount - 1; static constexpr timer::Timer::Duration kTransferTimeout{timer::Timer::kClockFrequency / 10}; + static_assert((kPayloadChunkCount & (kPayloadChunkCount - 1)) == 0); + enum class RequestType : uint8_t { kWrite, kRead, @@ -132,41 +134,134 @@ class I2c : private core::utility::Immovable { uint16_t data_length = 0; bool has_register = false; uint8_t reg_address = 0; - alignas(uint32_t) std::array payload{}; + uint8_t payload_first_chunk = 0; + uint8_t payload_chunk_count = 0; TransferState transfer_state() const { return type == RequestType::kWrite ? TransferState::kWrite : TransferState::kRead; } }; + static uint8_t required_payload_chunks(size_t payload_size) { + return static_cast((payload_size + kPayloadChunkSize - 1) / kPayloadChunkSize); + } + + static uint8_t advance_chunk_index(uint8_t index, uint8_t chunk_count) { + return static_cast((index + chunk_count) & kPayloadChunkMask); + } + + size_t writable_payload_chunks() const { + return kPayloadChunkCount - static_cast(used_payload_chunks_); + } + bool enqueue_write_request(const data::I2cDataView& data) { - return request_queue_.emplace_back_n( - [&data](std::byte* storage) noexcept { - auto& request = *new (storage) Request{}; - request.type = RequestType::kWrite; - request.slave_address = data.slave_address; - request.data_length = static_cast(data.payload.size()); - request.has_register = data.has_register; - request.reg_address = data.reg_address; - std::memcpy( - request.payload.data(), data.payload.data(), data.payload.size()); - }, - 1, true) - == 1; + const auto required_chunks = required_payload_chunks(data.payload.size()); + + const utility::InterruptLockGuard guard; + if (request_queue_.writable() == 0 || required_chunks > writable_payload_chunks()) + return false; + + Request request{}; + request.type = RequestType::kWrite; + request.slave_address = data.slave_address; + request.data_length = static_cast(data.payload.size()); + request.has_register = data.has_register; + request.reg_address = data.reg_address; + request.payload_first_chunk = payload_chunk_head_; + request.payload_chunk_count = required_chunks; + + copy_payload_to_pool(request, data.payload); + reserve_payload_chunks(required_chunks); + + core::utility::assert_always(request_queue_.emplace_back(request)); + return true; } bool enqueue_read_request(const data::I2cReadConfigView& data) { - return request_queue_.emplace_back_n( - [&data](std::byte* storage) noexcept { - auto& request = *new (storage) Request{}; - request.type = RequestType::kRead; - request.slave_address = data.slave_address; - request.data_length = data.read_length; - request.has_register = data.has_register; - request.reg_address = data.reg_address; - }, - 1, true) - == 1; + const utility::InterruptLockGuard guard; + if (request_queue_.writable() == 0) + return false; + + Request request{}; + request.type = RequestType::kRead; + request.slave_address = data.slave_address; + request.data_length = data.read_length; + request.has_register = data.has_register; + request.reg_address = data.reg_address; + + core::utility::assert_always(request_queue_.emplace_back(request)); + return true; + } + + void copy_payload_to_pool(const Request& request, std::span payload) { + size_t copied_size = 0; + size_t remaining_size = payload.size(); + + for (uint8_t chunk = 0; chunk < request.payload_chunk_count; ++chunk) { + const auto chunk_index = advance_chunk_index(request.payload_first_chunk, chunk); + const auto chunk_size = std::min(remaining_size, kPayloadChunkSize); + std::memcpy( + payload_chunks_[chunk_index].data(), payload.data() + copied_size, chunk_size); + copied_size += chunk_size; + remaining_size -= chunk_size; + } + } + + void copy_payload_to_dma_buffer(const Request& request) { + size_t copied_size = 0; + size_t remaining_size = request.data_length; + + for (uint8_t chunk = 0; chunk < request.payload_chunk_count; ++chunk) { + const auto chunk_index = advance_chunk_index(request.payload_first_chunk, chunk); + const auto chunk_size = std::min(remaining_size, kPayloadChunkSize); + std::memcpy( + write_dma_buffer_.data() + copied_size, payload_chunks_[chunk_index].data(), + chunk_size); + copied_size += chunk_size; + remaining_size -= chunk_size; + } + } + + void reserve_payload_chunks(uint8_t chunk_count) { + payload_chunk_head_ = advance_chunk_index(payload_chunk_head_, chunk_count); + used_payload_chunks_ = static_cast(used_payload_chunks_ + chunk_count); + } + + void release_payload_chunks(const Request& request) { + if (request.type != RequestType::kWrite || request.payload_chunk_count == 0) + return; + + core::utility::assert_debug(request.payload_first_chunk == payload_chunk_tail_); + payload_chunk_tail_ = advance_chunk_index(payload_chunk_tail_, request.payload_chunk_count); + used_payload_chunks_ = + static_cast(used_payload_chunks_ - request.payload_chunk_count); + } + + void try_start_next_request() { + if (transfer_state_.load(std::memory_order::acquire) != TransferState::kIdle) + return; + + Request request{}; + { + const utility::InterruptLockGuard guard; + if (transfer_state_.load(std::memory_order::relaxed) != TransferState::kIdle) + return; + + const auto popped = request_queue_.pop_front( + [&request](Request pending) noexcept { request = pending; }); + if (!popped) + return; + + active_request_ = request; + transfer_start_timepoint_ = timer::timer->timepoint(); + transfer_state_.store(request.transfer_state(), std::memory_order::release); + } + + if (!start_dma_transfer(active_request_)) { + const auto slave_address = active_request_.slave_address; + finish_active_request(); + write_error(slave_address); + } } bool start_dma_transfer(Request& request) { @@ -174,7 +269,8 @@ class I2c : private core::utility::Immovable { HAL_StatusTypeDef status; if (request.type == RequestType::kWrite) { - auto* payload = reinterpret_cast(request.payload.data()); + copy_payload_to_dma_buffer(request); + auto* payload = reinterpret_cast(write_dma_buffer_.data()); status = request.has_register ? HAL_I2C_Mem_Write_DMA( hal_i2c_handle_, hal_slave_address, request.reg_address, @@ -182,7 +278,7 @@ class I2c : private core::utility::Immovable { : HAL_I2C_Master_Transmit_DMA( hal_i2c_handle_, hal_slave_address, payload, request.data_length); } else { - auto* payload = reinterpret_cast(read_buffer_.data()); + auto* payload = reinterpret_cast(read_dma_buffer_.data()); status = request.has_register ? HAL_I2C_Mem_Read_DMA( hal_i2c_handle_, hal_slave_address, request.reg_address, @@ -213,10 +309,11 @@ class I2c : private core::utility::Immovable { abort_dma_if_enabled(hal_i2c_handle_->hdmatx); core::utility::assert_always(HAL_I2C_DeInit(hal_i2c_handle_) == HAL_OK); core::utility::assert_always(HAL_I2C_Init(hal_i2c_handle_) == HAL_OK); - finish_active_request(); + finish_active_request_locked(); } write_error(slave_address); + try_start_next_request(); } static void abort_dma_if_enabled(DMA_HandleTypeDef* hal_dma_handle) { @@ -229,15 +326,22 @@ class I2c : private core::utility::Immovable { } void finish_active_request() { + const utility::InterruptLockGuard guard; + finish_active_request_locked(); + } + + void finish_active_request_locked() { + release_payload_chunks(active_request_); + active_request_ = {}; transfer_start_timepoint_ = timer::Timer::TimePoint::min(); transfer_state_.store(TransferState::kIdle, std::memory_order::release); } - void write_read_result(const Request& request) { + void write_read_result(const Request& request, std::span payload) { auto& serializer = usb::get_serializer(); const data::I2cDataView result{ .slave_address = request.slave_address, - .payload = std::span{read_buffer_.data(), request.data_length}, + .payload = payload, .has_register = request.has_register, .reg_address = request.reg_address, }; @@ -263,9 +367,20 @@ class I2c : private core::utility::Immovable { Request active_request_{}; std::atomic transfer_state_{TransferState::kIdle}; timer::Timer::TimePoint transfer_start_timepoint_{timer::Timer::TimePoint::min()}; - alignas(uint32_t) std::array read_buffer_{}; + + uint8_t payload_chunk_head_{0}; + uint8_t payload_chunk_tail_{0}; + uint8_t used_payload_chunks_{0}; + + alignas(uint32_t) + std::array, kPayloadChunkCount> payload_chunks_{}; + alignas(uint32_t) std::array write_dma_buffer_{}; + alignas(uint32_t) std::array read_dma_buffer_{}; + alignas(uint32_t) std::array read_result_buffer_{}; }; +// Keep the logical protocol name (`I2C0`) in firmware/host APIs. +// On c_board, that logical channel is implemented by STM32 `I2C2`. inline constinit I2c::Lazy i2c0{data::DataId::kI2c0, &hi2c2}; } // namespace librmcs::firmware::i2c diff --git a/host/include/librmcs/agent/c_board.hpp b/host/include/librmcs/agent/c_board.hpp index 75d0ce1..f000457 100644 --- a/host/include/librmcs/agent/c_board.hpp +++ b/host/include/librmcs/agent/c_board.hpp @@ -25,6 +25,8 @@ class CBoard : private data::DataCallback { friend class CBoard; public: + static constexpr uint16_t kI2cMaxDataLength = (1U << 9) - 1U; + PacketBuilder& can1_transmit(const librmcs::data::CanDataView& data) { if (!builder_.write_can(data::DataId::kCan1, data)) [[unlikely]] throw std::invalid_argument{"CAN1 transmission failed: Invalid CAN data"}; @@ -53,15 +55,20 @@ class CBoard : private data::DataCallback { } PacketBuilder& i2c0_write(const librmcs::data::I2cDataView& data) { - if (data.payload.empty() || !builder_.write_i2c(data::DataId::kI2c0, data)) [[unlikely]] + if (data.payload.empty() || data.payload.size() > kI2cMaxDataLength + || data.slave_address > 0x7FU) [[unlikely]] throw std::invalid_argument{"I2C0 write failed: Invalid I2C data"}; + if (!builder_.write_i2c(data::DataId::kI2c0, data)) [[unlikely]] + throw std::runtime_error{"I2C0 write failed: Transmit buffer unavailable"}; return *this; } PacketBuilder& i2c0_read(const librmcs::data::I2cReadConfigView& data) { - if (data.read_length == 0 || !builder_.write_i2c_read_config(data::DataId::kI2c0, data)) - [[unlikely]] + if (data.read_length == 0 || data.read_length > kI2cMaxDataLength + || data.slave_address > 0x7FU) [[unlikely]] throw std::invalid_argument{"I2C0 read failed: Invalid I2C read config"}; + if (!builder_.write_i2c_read_config(data::DataId::kI2c0, data)) [[unlikely]] + throw std::runtime_error{"I2C0 read failed: Transmit buffer unavailable"}; return *this; } diff --git a/host/include/librmcs/agent/rmcs_board.hpp b/host/include/librmcs/agent/rmcs_board.hpp index 6d10408..241e964 100644 --- a/host/include/librmcs/agent/rmcs_board.hpp +++ b/host/include/librmcs/agent/rmcs_board.hpp @@ -25,6 +25,8 @@ class RmcsBoard : private data::DataCallback { friend class RmcsBoard; public: + static constexpr uint16_t kI2cMaxDataLength = (1U << 9) - 1U; + PacketBuilder& can0_transmit(const librmcs::data::CanDataView& data) { if (!builder_.write_can(data::DataId::kCan0, data)) [[unlikely]] throw std::invalid_argument{"CAN0 transmission failed: Invalid CAN data"}; @@ -73,14 +75,20 @@ class RmcsBoard : private data::DataCallback { } PacketBuilder& i2c0_write(const librmcs::data::I2cDataView& data) { - if (data.payload.empty() || !builder_.write_i2c(data::DataId::kI2c0, data)) + if (data.payload.empty() || data.payload.size() > kI2cMaxDataLength + || data.slave_address > 0x7FU) throw std::invalid_argument{"I2C0 write failed: Invalid I2C data"}; + if (!builder_.write_i2c(data::DataId::kI2c0, data)) + throw std::runtime_error{"I2C0 write failed: Transmit buffer unavailable"}; return *this; } PacketBuilder& i2c0_read(const librmcs::data::I2cReadConfigView& data) { - if (data.read_length == 0 || !builder_.write_i2c_read_config(data::DataId::kI2c0, data)) + if (data.read_length == 0 || data.read_length > kI2cMaxDataLength + || data.slave_address > 0x7FU) throw std::invalid_argument{"I2C0 read failed: Invalid I2C read config"}; + if (!builder_.write_i2c_read_config(data::DataId::kI2c0, data)) + throw std::runtime_error{"I2C0 read failed: Transmit buffer unavailable"}; return *this; } diff --git a/host/src/protocol/handler.cpp b/host/src/protocol/handler.cpp index 53e10f0..feb042d 100644 --- a/host/src/protocol/handler.cpp +++ b/host/src/protocol/handler.cpp @@ -129,7 +129,7 @@ struct PacketBuilderImpl { PacketBuilderImpl& operator=(const PacketBuilderImpl&) = delete; ~PacketBuilderImpl() = default; - // `write_*` returns `true` if args are valid; it never reports transport/resource issues. + // Non-I2C writes keep the historical behavior: // - `kInvalidArgument` => `false` (user error) // - `kBadAlloc` => logged and ignored (`true`) (internal/transient) [[nodiscard]] bool write_can(data::DataId field_id, const data::CanDataView& view) noexcept { @@ -162,17 +162,17 @@ struct PacketBuilderImpl { } [[nodiscard]] bool write_i2c(data::DataId field_id, const data::I2cDataView& view) noexcept { - return process_result(serializer_.write_i2c_write(field_id, view)); + return process_result_strict(serializer_.write_i2c_write(field_id, view)); } [[nodiscard]] bool write_i2c_read_config(data::DataId field_id, const data::I2cReadConfigView& view) noexcept { - return process_result(serializer_.write_i2c_read_config(field_id, view)); + return process_result_strict(serializer_.write_i2c_read_config(field_id, view)); } [[nodiscard]] bool write_i2c_read_result(data::DataId field_id, const data::I2cDataView& view) noexcept { - return process_result(serializer_.write_i2c_read_result(field_id, view)); + return process_result_strict(serializer_.write_i2c_read_result(field_id, view)); } private: @@ -184,6 +184,19 @@ struct PacketBuilderImpl { logging::get_logger().error("Transmit buffer unavailable (acquire failed)"); return true; } + if (result == Serializer::SerializeResult::kInvalidArgument) + return false; + core::utility::assert_failed_debug(); + } + + static bool process_result_strict(core::protocol::Serializer::SerializeResult result) { + using core::protocol::Serializer; + if (result == Serializer::SerializeResult::kSuccess) [[likely]] + return true; + if (result == Serializer::SerializeResult::kBadAlloc) { + logging::get_logger().error("Transmit buffer unavailable (acquire failed)"); + return false; + } if (result == Serializer::SerializeResult::kInvalidArgument) { return false; } From c561efe2c8d4ded004785fbd8762634fd1e610e5 Mon Sep 17 00:00:00 2001 From: tcd <1369103595@qq.com> Date: Sat, 11 Apr 2026 13:32:29 +0000 Subject: [PATCH 6/7] fix(c_board): Lower i2c irq priority to avoid usb conflicts --- firmware/c_board/bsp/cubemx/Core/Src/dma.c | 4 ++-- firmware/c_board/bsp/cubemx/Core/Src/i2c.c | 6 +++--- firmware/c_board/bsp/cubemx/rmcs_slave.ioc | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/firmware/c_board/bsp/cubemx/Core/Src/dma.c b/firmware/c_board/bsp/cubemx/Core/Src/dma.c index bd7034f..4ea62ba 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/dma.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/dma.c @@ -48,13 +48,13 @@ void MX_DMA_Init(void) HAL_NVIC_SetPriority(DMA1_Stream1_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA1_Stream1_IRQn); /* DMA1_Stream2_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 0, 0); + HAL_NVIC_SetPriority(DMA1_Stream2_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn); /* DMA1_Stream3_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA1_Stream3_IRQn, 6, 0); HAL_NVIC_EnableIRQ(DMA1_Stream3_IRQn); /* DMA1_Stream7_IRQn interrupt configuration */ - HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 0, 0); + HAL_NVIC_SetPriority(DMA1_Stream7_IRQn, 1, 0); HAL_NVIC_EnableIRQ(DMA1_Stream7_IRQn); /* DMA2_Stream0_IRQn interrupt configuration */ HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 4, 0); diff --git a/firmware/c_board/bsp/cubemx/Core/Src/i2c.c b/firmware/c_board/bsp/cubemx/Core/Src/i2c.c index e69b8f4..6bbc739 100644 --- a/firmware/c_board/bsp/cubemx/Core/Src/i2c.c +++ b/firmware/c_board/bsp/cubemx/Core/Src/i2c.c @@ -121,10 +121,10 @@ void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) __HAL_LINKDMA(i2cHandle,hdmatx,hdma_i2c2_tx); /* I2C2 interrupt Init */ - HAL_NVIC_SetPriority(I2C2_EV_IRQn, 0, 0); + HAL_NVIC_SetPriority(I2C2_EV_IRQn, 1, 0); HAL_NVIC_EnableIRQ(I2C2_EV_IRQn); - HAL_NVIC_SetPriority(I2C2_ER_IRQn, 0, 0); - HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); + HAL_NVIC_SetPriority(I2C2_ER_IRQn, 1, 0); + HAL_NVIC_EnableIRQ(I2C2_ER_IRQn); /* USER CODE BEGIN I2C2_MspInit 1 */ /* USER CODE END I2C2_MspInit 1 */ diff --git a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc index 421c001..46b17a7 100644 --- a/firmware/c_board/bsp/cubemx/rmcs_slave.ioc +++ b/firmware/c_board/bsp/cubemx/rmcs_slave.ioc @@ -206,9 +206,9 @@ NVIC.BusFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.CAN1_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true NVIC.CAN2_RX0_IRQn=true\:2\:0\:true\:false\:true\:true\:true\:true NVIC.DMA1_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA1_Stream2_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream2_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true NVIC.DMA1_Stream3_IRQn=true\:6\:0\:true\:false\:true\:false\:true\:true -NVIC.DMA1_Stream7_IRQn=true\:0\:0\:true\:false\:true\:false\:true\:true +NVIC.DMA1_Stream7_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream0_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream1_IRQn=true\:1\:0\:true\:false\:true\:false\:true\:true NVIC.DMA2_Stream3_IRQn=true\:4\:0\:true\:false\:true\:false\:true\:true @@ -220,8 +220,8 @@ NVIC.EXTI4_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true NVIC.EXTI9_5_IRQn=true\:4\:0\:true\:false\:true\:true\:true\:true NVIC.ForceEnableDMAVector=true NVIC.HardFault_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false -NVIC.I2C2_ER_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true -NVIC.I2C2_EV_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true +NVIC.I2C2_ER_IRQn=true\:1\:0\:false\:false\:true\:true\:true\:true +NVIC.I2C2_EV_IRQn=true\:1\:0\:false\:false\:true\:true\:true\:true NVIC.MemoryManagement_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.NonMaskableInt_IRQn=true\:0\:0\:false\:false\:true\:false\:false\:false NVIC.OTG_FS_IRQn=true\:0\:0\:false\:false\:true\:true\:true\:true From 13b60a835198c5cbfab444f917f450f31eb840c6 Mon Sep 17 00:00:00 2001 From: tcd <1369103595@qq.com> Date: Sat, 11 Apr 2026 14:40:12 +0000 Subject: [PATCH 7/7] fix(rmcs_board): Update hpm_sdk to restore hpm5300evk board definitions --- firmware/rmcs_board/bsp/hpm_sdk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/firmware/rmcs_board/bsp/hpm_sdk b/firmware/rmcs_board/bsp/hpm_sdk index 132349c..a82a535 160000 --- a/firmware/rmcs_board/bsp/hpm_sdk +++ b/firmware/rmcs_board/bsp/hpm_sdk @@ -1 +1 @@ -Subproject commit 132349c9ddad3cbeca7211345d5d6086355f20b9 +Subproject commit a82a53544d5679a43b70f390c8bbbb8e91f6b8c1