From 0a5edf314c60cbebd2871fc2dd9f885446cda9a0 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sat, 25 Jul 2015 00:52:09 +0300 Subject: [PATCH] STM32: auto bit rate in silent mode --- .../stm32/driver/include/uavcan_stm32/can.hpp | 22 +++++++++----- .../stm32/driver/src/uc_stm32_can.cpp | 30 +++++++++++++++---- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/libuavcan_drivers/stm32/driver/include/uavcan_stm32/can.hpp b/libuavcan_drivers/stm32/driver/include/uavcan_stm32/can.hpp index c7bca82042..473a76a960 100644 --- a/libuavcan_drivers/stm32/driver/include/uavcan_stm32/can.hpp +++ b/libuavcan_drivers/stm32/driver/include/uavcan_stm32/can.hpp @@ -56,6 +56,8 @@ class CanIface : public uavcan::ICanIface, uavcan::Noncopyable void push(const uavcan::CanFrame& frame, const uint64_t& utc_usec, uavcan::CanIOFlags flags); void pop(uavcan::CanFrame& out_frame, uavcan::uint64_t& out_utc_usec, uavcan::CanIOFlags& out_flags); + void reset(); + unsigned getLength() const { return len_; } uavcan::uint32_t getOverflowCount() const { return overflow_cnt_; } @@ -127,6 +129,12 @@ class CanIface : public uavcan::ICanIface, uavcan::Noncopyable public: enum { MaxRxQueueCapacity = 254 }; + enum OperatingMode + { + NormalMode, + SilentMode + }; + CanIface(bxcan::CanType* can, BusEvent& update_event, uavcan::uint8_t self_index, CanRxItem* rx_queue_buffer, uavcan::uint8_t rx_queue_capacity) : rx_queue_(rx_queue_buffer, rx_queue_capacity) @@ -149,7 +157,7 @@ public: * - Iface has been resetted via RCC * - Caller will configure NVIC by itself */ - int init(uavcan::uint32_t bitrate); + int init(const uavcan::uint32_t bitrate, const OperatingMode mode); void handleTxInterrupt(uavcan::uint64_t utc_usec); void handleRxInterrupt(uavcan::uint8_t fifo_index, uavcan::uint64_t utc_usec); @@ -241,7 +249,7 @@ public: * Returns zero if OK. * Returns negative value if failed (e.g. invalid bitrate). */ - int init(uavcan::uint32_t bitrate); + int init(const uavcan::uint32_t bitrate, const CanIface::OperatingMode mode); virtual CanIface* getIface(uavcan::uint8_t iface_index); @@ -277,8 +285,6 @@ public: * This function can either initialize the driver at a fixed bit rate, or it can perform * automatic bit rate detection. For theory please refer to the CiA application note #801. * - * TODO FIXME: During bit rate detection, the CAN controller must be initialized in listen-only mode. - * * @param delay_callable A callable entity that suspends execution for strictly more than one second. * The callable entity will be invoked without arguments. * @ref getRecommendedListeningDelay(). @@ -294,7 +300,7 @@ public: { if (inout_bitrate > 0) { - return driver.init(inout_bitrate); + return driver.init(inout_bitrate, CanIface::NormalMode); } else { @@ -310,8 +316,7 @@ public: { inout_bitrate = StandardBitRates[br]; - // TODO: listen-only mode - const int res = driver.init(inout_bitrate); + const int res = driver.init(inout_bitrate, CanIface::SilentMode); delay_callable(); @@ -321,7 +326,8 @@ public: { if (!driver.getIface(iface)->isRxBufferEmpty()) { - return res; + // Re-initializing in normal mode + return driver.init(inout_bitrate, CanIface::NormalMode); } } } diff --git a/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp b/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp index 99f9293a96..14bf0a392c 100644 --- a/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp +++ b/libuavcan_drivers/stm32/driver/src/uc_stm32_can.cpp @@ -160,6 +160,14 @@ void CanIface::RxQueue::pop(uavcan::CanFrame& out_frame, uavcan::uint64_t& out_u else { UAVCAN_ASSERT(0); } } +void CanIface::RxQueue::reset() +{ + in_ = 0; + out_ = 0; + len_ = 0; + overflow_cnt_ = 0; +} + /* * CanIface */ @@ -446,10 +454,21 @@ bool CanIface::waitMsrINakBitStateChange(bool target_state) return false; } -int CanIface::init(uavcan::uint32_t bitrate) +int CanIface::init(const uavcan::uint32_t bitrate, const OperatingMode mode) { int res = 0; + /* + * Object state + */ + rx_queue_.reset(); + error_cnt_ = 0; + served_aborts_cnt_ = 0; + uavcan::fill_n(pending_tx_, NumTxMailboxes, TxItem()); + last_hw_error_code_ = 0; + peak_tx_mailbox_index_ = 0; + had_activity_ = false; + /* * CAN timings for this bitrate */ @@ -480,7 +499,8 @@ int CanIface::init(uavcan::uint32_t bitrate) can_->BTR = ((timings.sjw & 3U) << 24) | ((timings.bs1 & 15U) << 16) | ((timings.bs2 & 7U) << 20) | - (timings.prescaler & 1023U); + (timings.prescaler & 1023U) | + ((mode == SilentMode) ? bxcan::BTR_SILM : 0); can_->IER = bxcan::IER_TMEIE | // TX mailbox empty bxcan::IER_FMPIE0 | // RX FIFO 0 is not empty @@ -812,7 +832,7 @@ uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks, return 1; // Return value doesn't matter as long as it is non-negative } -int CanDriver::init(uavcan::uint32_t bitrate) +int CanDriver::init(const uavcan::uint32_t bitrate, const CanIface::OperatingMode mode) { int res = 0; @@ -835,7 +855,7 @@ int CanDriver::init(uavcan::uint32_t bitrate) } UAVCAN_STM32_LOG("Initing iface 0..."); - res = if0_.init(bitrate); + res = if0_.init(bitrate, mode); if (res < 0) { UAVCAN_STM32_LOG("Iface 0 init failed %i", res); @@ -861,7 +881,7 @@ int CanDriver::init(uavcan::uint32_t bitrate) } UAVCAN_STM32_LOG("Initing iface 1..."); - res = if1_.init(bitrate); + res = if1_.init(bitrate, mode); if (res < 0) { UAVCAN_STM32_LOG("Iface 1 init failed %i", res);