From 5decf35aed15de0fdc49827457385bfc17010802 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 20 Aug 2015 06:57:16 +0300 Subject: [PATCH 01/30] LPC11C24: C++11 in the demo app --- .../test_olimex_lpc_p11c24/src/sys/board.cpp | 18 +++++++++--------- .../test_olimex_lpc_p11c24/src/sys/board.hpp | 6 +++--- .../src/sys/libstubs.cpp | 4 ++-- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index 8a4125599c..9f6fee17e0 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -12,21 +12,21 @@ #define PDRUNCFGUSEMASK 0x0000ED00 #define PDRUNCFGMASKTMP 0x000000FF -const uint32_t OscRateIn = 12000000; ///< External crystal -const uint32_t ExtRateIn = 0; +const std::uint32_t OscRateIn = 12000000; ///< External crystal +const std::uint32_t ExtRateIn = 0; -uint32_t SystemCoreClock = 12000000; ///< Initialized to default clock value, will be changed on init +std::uint32_t SystemCoreClock = 12000000; ///< Initialized to default clock value, will be changed on init namespace board { namespace { -const unsigned ErrorLedPort = 1; -const unsigned ErrorLedPin = 10; +constexpr unsigned ErrorLedPort = 1; +constexpr unsigned ErrorLedPin = 10; -const unsigned StatusLedPort = 1; -const unsigned StatusLedPin = 11; +constexpr unsigned StatusLedPort = 1; +constexpr unsigned StatusLedPin = 11; struct PinMuxGroup { @@ -34,7 +34,7 @@ struct PinMuxGroup unsigned modefunc : 24; }; -const PinMuxGroup pinmux[] = +constexpr PinMuxGroup pinmux[] = { { IOCON_PIO1_10, IOCON_FUNC0 | IOCON_MODE_INACT }, // Error LED { IOCON_PIO1_11, IOCON_FUNC0 | IOCON_MODE_INACT } // Status LED @@ -126,7 +126,7 @@ void init() #if __GNUC__ __attribute__((optimize(0))) // Optimization must be disabled lest it hardfaults in the IAP call #endif -void readUniqueID(uint8_t out_uid[UniqueIDSize]) +void readUniqueID(std::uint8_t out_uid[UniqueIDSize]) { unsigned aligned_array[4] = {}; // out_uid may be unaligned, so we need to use temp array unsigned iap_command = 58; diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp index 0882f4b60e..f0da90533a 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp @@ -2,14 +2,14 @@ * Pavel Kirienko, 2014 */ -#include +#include namespace board { -static const unsigned UniqueIDSize = 16; +static constexpr unsigned UniqueIDSize = 16; -void readUniqueID(uint8_t out_uid[UniqueIDSize]); +void readUniqueID(std::uint8_t out_uid[UniqueIDSize]); void setStatusLed(bool state); void setErrorLed(bool state); diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/libstubs.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/libstubs.cpp index 888ef02ab1..ca63b91640 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/libstubs.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/libstubs.cpp @@ -13,13 +13,13 @@ void* __dso_handle; -void* operator new(size_t) +void* operator new(std::size_t) { std::abort(); return reinterpret_cast(0xFFFFFFFF); } -void* operator new[](size_t) +void* operator new[](std::size_t) { std::abort(); return reinterpret_cast(0xFFFFFFFF); From c24aca186c1ea08a724735456a54ba826f0f6dc9 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 20 Aug 2015 07:09:23 +0300 Subject: [PATCH 02/30] LPC11C24 driver: Proper use of std:: --- .../driver/include/uavcan_lpc11c24/can.hpp | 29 +++++---- .../driver/include/uavcan_lpc11c24/clock.hpp | 6 +- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 64 ++++++++----------- .../lpc11c24/driver/src/clock.cpp | 38 +++++------ .../lpc11c24/driver/src/internal.hpp | 3 +- 5 files changed, 68 insertions(+), 72 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp index 9e4816fa69..94da2eb151 100644 --- a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp @@ -44,26 +44,29 @@ public: */ bool hadActivity(); - virtual uavcan::int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, - uavcan::CanIOFlags flags); + uavcan::int16_t send(const uavcan::CanFrame& frame, + uavcan::MonotonicTime tx_deadline, + uavcan::CanIOFlags flags) override; - virtual uavcan::int16_t receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic, - uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags); + uavcan::int16_t receive(uavcan::CanFrame& out_frame, + uavcan::MonotonicTime& out_ts_monotonic, + uavcan::UtcTime& out_ts_utc, + uavcan::CanIOFlags& out_flags) override; - virtual uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks, - const uavcan::CanFrame* (&)[uavcan::MaxCanIfaces], - uavcan::MonotonicTime blocking_deadline); + uavcan::int16_t select(uavcan::CanSelectMasks& inout_masks, + const uavcan::CanFrame* (&)[uavcan::MaxCanIfaces], + uavcan::MonotonicTime blocking_deadline) override; - virtual uavcan::int16_t configureFilters(const uavcan::CanFilterConfig* filter_configs, - uavcan::uint16_t num_configs); + uavcan::int16_t configureFilters(const uavcan::CanFilterConfig* filter_configs, + uavcan::uint16_t num_configs) override; - virtual uavcan::uint64_t getErrorCount() const; + uavcan::uint64_t getErrorCount() const override; - virtual uavcan::uint16_t getNumFilters() const; + uavcan::uint16_t getNumFilters() const override; - virtual uavcan::ICanIface* getIface(uavcan::uint8_t iface_index); + uavcan::ICanIface* getIface(uavcan::uint8_t iface_index) override; - virtual uavcan::uint8_t getNumIfaces() const; + uavcan::uint8_t getNumIfaces() const override; }; } diff --git a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/clock.hpp b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/clock.hpp index 3ff6b4d127..47f3b5fea5 100644 --- a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/clock.hpp +++ b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/clock.hpp @@ -51,9 +51,9 @@ class SystemClock : public uavcan::ISystemClock, uavcan::Noncopyable SystemClock() { } - virtual uavcan::MonotonicTime getMonotonic() const { return clock::getMonotonic(); } - virtual uavcan::UtcTime getUtc() const { return clock::getUtc(); } - virtual void adjustUtc(uavcan::UtcDuration adjustment) { clock::adjustUtc(adjustment); } + uavcan::MonotonicTime getMonotonic() const override { return clock::getMonotonic(); } + uavcan::UtcTime getUtc() const override { return clock::getUtc(); } + void adjustUtc(uavcan::UtcDuration adjustment) override { clock::adjustUtc(adjustment); } public: /** diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index fb1d80f63c..ebb4e73c71 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -19,9 +19,9 @@ # error UAVCAN_LPC11C24_RX_QUEUE_LEN is too large #endif -extern "C" void canRxCallback(uint8_t msg_obj_num); -extern "C" void canTxCallback(uint8_t msg_obj_num); -extern "C" void canErrorCallback(uint32_t error_info); +extern "C" void canRxCallback(std::uint8_t msg_obj_num); +extern "C" void canTxCallback(std::uint8_t msg_obj_num); +extern "C" void canErrorCallback(std::uint32_t error_info); namespace uavcan_lpc11c24 { @@ -40,7 +40,7 @@ const unsigned NumMsgObjects = 32; * Total number of CAN errors. * Does not overflow. */ -uint32_t error_cnt; +std::uint32_t error_cnt = 0; /** * True if there's no pending TX frame, i.e. write is possible. @@ -50,7 +50,7 @@ bool tx_free = true; /** * Gets updated every time the CAN IRQ handler is being called. */ -uint64_t last_irq_utc_timestamp = 0; +std::uint64_t last_irq_utc_timestamp = 0; bool had_activity; @@ -62,26 +62,18 @@ class RxQueue { struct Item { - uint64_t utc_usec; + std::uint64_t utc_usec = 0; uavcan::CanFrame frame; - Item() : utc_usec(0) { } }; Item buf_[UAVCAN_LPC11C24_RX_QUEUE_LEN]; - uint32_t overflow_cnt_; - uint8_t in_; - uint8_t out_; - uint8_t len_; + std::uint32_t overflow_cnt_ = 0; + std::uint8_t in_ = 0; + std::uint8_t out_ = 0; + std::uint8_t len_ = 0; public: - RxQueue() - : overflow_cnt_(0) - , in_(0) - , out_(0) - , len_(0) - { } - - void push(const uavcan::CanFrame& frame, const uint64_t& utc_usec) + void push(const uavcan::CanFrame& frame, const std::uint64_t& utc_usec) { buf_[in_].frame = frame; buf_[in_].utc_usec = utc_usec; @@ -106,7 +98,7 @@ public: } } - void pop(uavcan::CanFrame& out_frame, uint64_t& out_utc_usec) + void pop(uavcan::CanFrame& out_frame, std::uint64_t& out_utc_usec) { if (len_ > 0) { @@ -123,28 +115,28 @@ public: unsigned getLength() const { return len_; } - uint32_t getOverflowCount() const { return overflow_cnt_; } + std::uint32_t getOverflowCount() const { return overflow_cnt_; } }; RxQueue rx_queue; -int computeBaudrate(uint32_t baud_rate, uint32_t can_api_timing_cfg[2]) +int computeBaudrate(std::uint32_t baud_rate, std::uint32_t can_api_timing_cfg[2]) { - const uint32_t pclk = Chip_Clock_GetMainClockRate(); - const uint32_t clk_per_bit = pclk / baud_rate; - for (uint32_t div = 0; div <= 15; div++) + const std::uint32_t pclk = Chip_Clock_GetMainClockRate(); + const std::uint32_t clk_per_bit = pclk / baud_rate; + for (std::uint32_t div = 0; div <= 15; div++) { - for (uint32_t quanta = 1; quanta <= 32; quanta++) + for (std::uint32_t quanta = 1; quanta <= 32; quanta++) { - for (uint32_t segs = 3; segs <= 17; segs++) + for (std::uint32_t segs = 3; segs <= 17; segs++) { if (clk_per_bit == (segs * quanta * (div + 1))) { segs -= 3; - const uint32_t seg1 = segs / 2; - const uint32_t seg2 = segs - seg1; - const uint32_t can_sjw = (seg1 > 3) ? 3 : seg1; + const std::uint32_t seg1 = segs / 2; + const std::uint32_t seg2 = segs - seg1; + const std::uint32_t can_sjw = (seg1 > 3) ? 3 : seg1; can_api_timing_cfg[0] = div; can_api_timing_cfg[1] = ((quanta - 1) & 0x3F) | (can_sjw & 0x03) << 6 | @@ -175,7 +167,7 @@ int CanDriver::init(uavcan::uint32_t baudrate) * C_CAN init */ Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); - static uint32_t can_api_init_table[2]; + static std::uint32_t can_api_init_table[2]; if (computeBaudrate(baudrate, can_api_init_table) != 0) { return -1; @@ -285,7 +277,7 @@ uavcan::int16_t CanDriver::receive(uavcan::CanFrame& out_frame, uavcan::Monotoni { return 0; } - uint64_t ts_utc = 0; + std::uint64_t ts_utc = 0; rx_queue.pop(out_frame, ts_utc); out_ts_utc = uavcan::UtcTime::fromUSec(ts_utc); return 1; @@ -337,7 +329,7 @@ uavcan::int16_t CanDriver::configureFilters(const uavcan::CanFilterConfig* filte uavcan::uint64_t CanDriver::getErrorCount() const { CriticalSectionLocker locker; - return uint64_t(error_cnt) + uint64_t(rx_queue.getOverflowCount()); + return std::uint64_t(error_cnt) + std::uint64_t(rx_queue.getOverflowCount()); } uavcan::uint16_t CanDriver::getNumFilters() const @@ -363,7 +355,7 @@ uavcan::uint8_t CanDriver::getNumIfaces() const extern "C" { -void canRxCallback(uint8_t msg_obj_num) +void canRxCallback(std::uint8_t msg_obj_num) { CCAN_MSG_OBJ_T msg_obj = CCAN_MSG_OBJ_T(); msg_obj.msgobj = msg_obj_num; @@ -396,14 +388,14 @@ void canRxCallback(uint8_t msg_obj_num) uavcan_lpc11c24::had_activity = true; } -void canTxCallback(uint8_t msg_obj_num) +void canTxCallback(std::uint8_t msg_obj_num) { (void)msg_obj_num; uavcan_lpc11c24::tx_free = true; uavcan_lpc11c24::had_activity = true; } -void canErrorCallback(uint32_t error_info) +void canErrorCallback(std::uint32_t error_info) { (void)error_info; if (uavcan_lpc11c24::error_cnt < 0xFFFFFFFF) diff --git a/libuavcan_drivers/lpc11c24/driver/src/clock.cpp b/libuavcan_drivers/lpc11c24/driver/src/clock.cpp index 2230635e8f..07098d6c5e 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/clock.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/clock.cpp @@ -17,18 +17,18 @@ namespace bool initialized = false; bool utc_set = false; -int32_t utc_correction_usec_per_overflow_x16 = 0; -int64_t prev_adjustment = 0; +std::int32_t utc_correction_usec_per_overflow_x16 = 0; +std::int64_t prev_adjustment = 0; -uint64_t time_mono = 0; -uint64_t time_utc = 0; +std::uint64_t time_mono = 0; +std::uint64_t time_utc = 0; /** * If this value is too large for the given core clock, reload value will be out of the 24-bit integer range. * This will be detected at run time during timer initialization - refer to SysTick_Config(). */ -const uint32_t USecPerOverflow = 65536 * 2; -const int32_t MaxUtcSpeedCorrectionX16 = 100 * 16; +constexpr std::uint32_t USecPerOverflow = 65536 * 2; +constexpr std::int32_t MaxUtcSpeedCorrectionX16 = 100 * 16; } @@ -59,30 +59,30 @@ void init() } } -static uint64_t sampleFromCriticalSection(const volatile uint64_t* const value) +static std::uint64_t sampleFromCriticalSection(const volatile std::uint64_t* const value) { - const uint32_t reload = SysTick->LOAD + 1; // SysTick counts downwards, hence the value subtracted from reload + const std::uint32_t reload = SysTick->LOAD + 1; // SysTick counts downwards, hence the value subtracted from reload - volatile uint64_t time = *value; - volatile uint32_t cycles = reload - SysTick->VAL; + volatile std::uint64_t time = *value; + volatile std::uint32_t cycles = reload - SysTick->VAL; if ((SCB->ICSR & SCB_ICSR_PENDSTSET_Msk) == SCB_ICSR_PENDSTSET_Msk) { cycles = reload - SysTick->VAL; time += USecPerOverflow; } - const uint32_t cycles_per_usec = SystemCoreClock / 1000000; + const std::uint32_t cycles_per_usec = SystemCoreClock / 1000000; return time + (cycles / cycles_per_usec); } -uint64_t getUtcUSecFromCanInterrupt() +std::uint64_t getUtcUSecFromCanInterrupt() { return utc_set ? sampleFromCriticalSection(&time_utc) : 0; } uavcan::MonotonicTime getMonotonic() { - uint64_t usec = 0; + std::uint64_t usec = 0; { CriticalSectionLocker locker; usec = sampleFromCriticalSection(&time_mono); @@ -92,7 +92,7 @@ uavcan::MonotonicTime getMonotonic() uavcan::UtcTime getUtc() { - uint64_t usec = 0; + std::uint64_t usec = 0; if (utc_set) { CriticalSectionLocker locker; @@ -108,7 +108,7 @@ uavcan::UtcDuration getPrevUtcAdjustment() void adjustUtc(uavcan::UtcDuration adjustment) { - const int64_t adj_delta = adjustment.toUSec() - prev_adjustment; // This is the P term + const std::int64_t adj_delta = adjustment.toUSec() - prev_adjustment; // This is the P term prev_adjustment = adjustment.toUSec(); utc_correction_usec_per_overflow_x16 += adjustment.isPositive() ? 1 : -1; // I @@ -121,16 +121,16 @@ void adjustUtc(uavcan::UtcDuration adjustment) if (adjustment.getAbs().toMSec() > 9 || !utc_set) { - const int64_t adj_usec = adjustment.toUSec(); + const std::int64_t adj_usec = adjustment.toUSec(); { CriticalSectionLocker locker; - if ((adj_usec < 0) && uint64_t(-adj_usec) > time_utc) + if ((adj_usec < 0) && std::uint64_t(-adj_usec) > time_utc) { time_utc = 1; } else { - time_utc = uint64_t(int64_t(time_utc) + adj_usec); + time_utc = std::uint64_t(std::int64_t(time_utc) + adj_usec); } } if (!utc_set) @@ -170,7 +170,7 @@ void SysTick_Handler() if (utc_set) { // Values below 16 are ignored - time_utc += uint64_t(int32_t(USecPerOverflow) + (utc_correction_usec_per_overflow_x16 / 16)); + time_utc += std::uint64_t(std::int32_t(USecPerOverflow) + (utc_correction_usec_per_overflow_x16 / 16)); } } else diff --git a/libuavcan_drivers/lpc11c24/driver/src/internal.hpp b/libuavcan_drivers/lpc11c24/driver/src/internal.hpp index 3bcf0d82c8..92577ad7ee 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/internal.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/internal.hpp @@ -4,6 +4,7 @@ #pragma once +#include #include namespace uavcan_lpc11c24 @@ -31,7 +32,7 @@ struct CriticalSectionLocker namespace clock { -uint64_t getUtcUSecFromCanInterrupt(); +std::uint64_t getUtcUSecFromCanInterrupt(); } From 16800376af7992539c140fd98bcba1ee037ced93 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Thu, 20 Aug 2015 07:11:52 +0300 Subject: [PATCH 03/30] LPC11C24: removed #define-s --- .../lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index 9f6fee17e0..21b0b2bbcb 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -9,8 +9,8 @@ #include #include -#define PDRUNCFGUSEMASK 0x0000ED00 -#define PDRUNCFGMASKTMP 0x000000FF +static constexpr unsigned long PDRUNCFGUSEMASK = 0x0000ED00U; +static constexpr unsigned long PDRUNCFGMASKTMP = 0x000000FFU; const std::uint32_t OscRateIn = 12000000; ///< External crystal const std::uint32_t ExtRateIn = 0; From 03ed261477d4cfaf2e6ff6e0aaf3648293418fec Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 15:43:16 +0300 Subject: [PATCH 04/30] LPC11C24: Proper CAN timings --- .../driver/include/uavcan_lpc11c24/can.hpp | 2 +- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 53 ++++++++++--------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp index 94da2eb151..6dae53f215 100644 --- a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp @@ -33,7 +33,7 @@ public: * Returns negative value if the requested baudrate can't be used. * Returns zero if OK. */ - int init(uavcan::uint32_t baudrate); + int init(uavcan::uint32_t bitrate); bool hasReadyRx() const; bool hasEmptyTx() const; diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index ebb4e73c71..76e102c45e 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -121,40 +121,41 @@ public: RxQueue rx_queue; -int computeBaudrate(std::uint32_t baud_rate, std::uint32_t can_api_timing_cfg[2]) +struct BitTimingSettings { - const std::uint32_t pclk = Chip_Clock_GetMainClockRate(); - const std::uint32_t clk_per_bit = pclk / baud_rate; - for (std::uint32_t div = 0; div <= 15; div++) + std::uint32_t canclkdiv; + std::uint32_t canbtr; + + bool isValid() const { return canbtr != 0; } +}; + +/** + * http://www.bittiming.can-wiki.info + */ +BitTimingSettings computeBitTimings(std::uint32_t bitrate) +{ + if (Chip_Clock_GetSystemClockRate() == 48000000) // 48 MHz is optimal for CAN timings { - for (std::uint32_t quanta = 1; quanta <= 32; quanta++) + switch (bitrate) { - for (std::uint32_t segs = 3; segs <= 17; segs++) - { - if (clk_per_bit == (segs * quanta * (div + 1))) - { - segs -= 3; - const std::uint32_t seg1 = segs / 2; - const std::uint32_t seg2 = segs - seg1; - const std::uint32_t can_sjw = (seg1 > 3) ? 3 : seg1; - can_api_timing_cfg[0] = div; - can_api_timing_cfg[1] = ((quanta - 1) & 0x3F) | - (can_sjw & 0x03) << 6 | - (seg1 & 0x0F) << 8 | - (seg2 & 0x07) << 12; - return 0; - } - } + case 1000000: return BitTimingSettings{ 0, 0x0505 }; // 8 quanta, 87.5% + case 500000: return BitTimingSettings{ 0, 0x1c05 }; // 16 quanta, 87.5% + case 250000: return BitTimingSettings{ 0, 0x1c0b }; // 16 quanta, 87.5% + case 125000: return BitTimingSettings{ 0, 0x1c17 }; // 16 quanta, 87.5% + default: return BitTimingSettings{ 0, 0 }; } } - return -1; + else + { + return BitTimingSettings{ 0, 0 }; + } } } // namespace CanDriver CanDriver::self; -int CanDriver::init(uavcan::uint32_t baudrate) +int CanDriver::init(uavcan::uint32_t bitrate) { CriticalSectionLocker locker; @@ -167,12 +168,12 @@ int CanDriver::init(uavcan::uint32_t baudrate) * C_CAN init */ Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); - static std::uint32_t can_api_init_table[2]; - if (computeBaudrate(baudrate, can_api_init_table) != 0) + auto bit_timings = computeBitTimings(bitrate); + if (!bit_timings.isValid()) { return -1; } - LPC_CCAN_API->init_can(can_api_init_table, true); + LPC_CCAN_API->init_can(reinterpret_cast(&bit_timings), true); static CCAN_CALLBACKS_T ccan_callbacks = { canRxCallback, From c856236a4abcc4a877853f96cda662f6b4f22ac3 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 16:37:16 +0300 Subject: [PATCH 05/30] LPC11C24 UART --- .../lpc_chip_11cxx_lib/src/uart_11xx.c | 289 ++++++++++++++++++ .../test_olimex_lpc_p11c24/src/sys/board.cpp | 21 +- .../test_olimex_lpc_p11c24/src/sys/board.hpp | 2 + 3 files changed, 310 insertions(+), 2 deletions(-) create mode 100644 libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/lpc_chip_11cxx_lib/src/uart_11xx.c diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/lpc_chip_11cxx_lib/src/uart_11xx.c b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/lpc_chip_11cxx_lib/src/uart_11xx.c new file mode 100644 index 0000000000..ae404b0dc0 --- /dev/null +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/lpc_chip_11cxx_lib/src/uart_11xx.c @@ -0,0 +1,289 @@ +/* + * @brief LPC11xx UART chip driver + * + * @note + * Copyright(C) NXP Semiconductors, 2012 + * All rights reserved. + * + * @par + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * LPC products. This software is supplied "AS IS" without any warranties of + * any kind, and NXP Semiconductors and its licensor disclaim any and + * all warranties, express or implied, including all implied warranties of + * merchantability, fitness for a particular purpose and non-infringement of + * intellectual property rights. NXP Semiconductors assumes no responsibility + * or liability for the use of the software, conveys no license or rights under any + * patent, copyright, mask work right, or any other intellectual property rights in + * or to any products. NXP Semiconductors reserves the right to make changes + * in the software without notification. NXP Semiconductors also makes no + * representation or warranty that such application will be suitable for the + * specified use without further testing or modification. + * + * @par + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, under NXP Semiconductors' and its + * licensor's relevant copyrights in the software, without fee, provided that it + * is used in conjunction with NXP Semiconductors microcontrollers. This + * copyright, permission, and disclaimer notice must appear in all copies of + * this code. + */ + +#include "chip.h" + +#if __GNUC__ +# pragma GCC diagnostic ignored "-Wsign-conversion" +# pragma GCC diagnostic ignored "-Wconversion" +# pragma GCC diagnostic ignored "-Wmissing-declarations" +# pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + +/***************************************************************************** + * Private types/enumerations/variables + ****************************************************************************/ + +/***************************************************************************** + * Public types/enumerations/variables + ****************************************************************************/ + +/***************************************************************************** + * Private functions + ****************************************************************************/ + +/***************************************************************************** + * Public functions + ****************************************************************************/ + +/* Initializes the pUART peripheral */ +void Chip_UART_Init(LPC_USART_T *pUART) +{ + Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_UART0); + Chip_Clock_SetUARTClockDiv(1); + + /* Enable FIFOs by default, reset them */ + Chip_UART_SetupFIFOS(pUART, (UART_FCR_FIFO_EN | UART_FCR_RX_RS | UART_FCR_TX_RS)); + + /* Default 8N1, with DLAB disabled */ + Chip_UART_ConfigData(pUART, (UART_LCR_WLEN8 | UART_LCR_SBS_1BIT | UART_LCR_PARITY_DIS)); + + /* Disable fractional divider */ + pUART->FDR = 0x10; +} + +/* De-initializes the pUART peripheral */ +void Chip_UART_DeInit(LPC_USART_T *pUART) +{ + Chip_Clock_DisablePeriphClock(SYSCTL_CLOCK_UART0); +} + +/* Transmit a byte array through the UART peripheral (non-blocking) */ +int Chip_UART_Send(LPC_USART_T *pUART, const void *data, int numBytes) +{ + int sent = 0; + uint8_t *p8 = (uint8_t *) data; + + /* Send until the transmit FIFO is full or out of bytes */ + while ((sent < numBytes) && + ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) != 0)) { + Chip_UART_SendByte(pUART, *p8); + p8++; + sent++; + } + + return sent; +} + +/* Transmit a byte array through the UART peripheral (blocking) */ +int Chip_UART_SendBlocking(LPC_USART_T *pUART, const void *data, int numBytes) +{ + int pass, sent = 0; + uint8_t *p8 = (uint8_t *) data; + + while (numBytes > 0) { + pass = Chip_UART_Send(pUART, p8, numBytes); + numBytes -= pass; + sent += pass; + p8 += pass; + } + + return sent; +} + +/* Read data through the UART peripheral (non-blocking) */ +int Chip_UART_Read(LPC_USART_T *pUART, void *data, int numBytes) +{ + int readBytes = 0; + uint8_t *p8 = (uint8_t *) data; + + /* Send until the transmit FIFO is full or out of bytes */ + while ((readBytes < numBytes) && + ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_RDR) != 0)) { + *p8 = Chip_UART_ReadByte(pUART); + p8++; + readBytes++; + } + + return readBytes; +} + +/* Read data through the UART peripheral (blocking) */ +int Chip_UART_ReadBlocking(LPC_USART_T *pUART, void *data, int numBytes) +{ + int pass, readBytes = 0; + uint8_t *p8 = (uint8_t *) data; + + while (readBytes < numBytes) { + pass = Chip_UART_Read(pUART, p8, numBytes); + numBytes -= pass; + readBytes += pass; + p8 += pass; + } + + return readBytes; +} + +/* Determines and sets best dividers to get a target bit rate */ +uint32_t Chip_UART_SetBaud(LPC_USART_T *pUART, uint32_t baudrate) +{ + uint32_t div, divh, divl, clkin; + + /* Determine UART clock in rate without FDR */ + clkin = Chip_Clock_GetMainClockRate(); + div = clkin / (baudrate * 16); + + /* High and low halves of the divider */ + divh = div / 256; + divl = div - (divh * 256); + + Chip_UART_EnableDivisorAccess(pUART); + Chip_UART_SetDivisorLatches(pUART, divl, divh); + Chip_UART_DisableDivisorAccess(pUART); + + /* Fractional FDR alreadt setup for 1 in UART init */ + + return clkin / div; +} + +/* UART receive-only interrupt handler for ring buffers */ +void Chip_UART_RXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB) +{ + /* New data will be ignored if data not popped in time */ + while (Chip_UART_ReadLineStatus(pUART) & UART_LSR_RDR) { + uint8_t ch = Chip_UART_ReadByte(pUART); + RingBuffer_Insert(pRB, &ch); + } +} + +/* UART transmit-only interrupt handler for ring buffers */ +void Chip_UART_TXIntHandlerRB(LPC_USART_T *pUART, RINGBUFF_T *pRB) +{ + uint8_t ch; + + /* Fill FIFO until full or until TX ring buffer is empty */ + while ((Chip_UART_ReadLineStatus(pUART) & UART_LSR_THRE) != 0 && + RingBuffer_Pop(pRB, &ch)) { + Chip_UART_SendByte(pUART, ch); + } +} + +/* Populate a transmit ring buffer and start UART transmit */ +uint32_t Chip_UART_SendRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, const void *data, int bytes) +{ + uint32_t ret; + uint8_t *p8 = (uint8_t *) data; + + /* Don't let UART transmit ring buffer change in the UART IRQ handler */ + Chip_UART_IntDisable(pUART, UART_IER_THREINT); + + /* Move as much data as possible into transmit ring buffer */ + ret = RingBuffer_InsertMult(pRB, p8, bytes); + Chip_UART_TXIntHandlerRB(pUART, pRB); + + /* Add additional data to transmit ring buffer if possible */ + ret += RingBuffer_InsertMult(pRB, (p8 + ret), (bytes - ret)); + + /* Enable UART transmit interrupt */ + Chip_UART_IntEnable(pUART, UART_IER_THREINT); + + return ret; +} + +/* Copy data from a receive ring buffer */ +int Chip_UART_ReadRB(LPC_USART_T *pUART, RINGBUFF_T *pRB, void *data, int bytes) +{ + (void) pUART; + + return RingBuffer_PopMult(pRB, (uint8_t *) data, bytes); +} + +/* UART receive/transmit interrupt handler for ring buffers */ +void Chip_UART_IRQRBHandler(LPC_USART_T *pUART, RINGBUFF_T *pRXRB, RINGBUFF_T *pTXRB) +{ + /* Handle transmit interrupt if enabled */ + if (pUART->IER & UART_IER_THREINT) { + Chip_UART_TXIntHandlerRB(pUART, pTXRB); + + /* Disable transmit interrupt if the ring buffer is empty */ + if (RingBuffer_IsEmpty(pTXRB)) { + Chip_UART_IntDisable(pUART, UART_IER_THREINT); + } + } + + /* Handle receive interrupt */ + Chip_UART_RXIntHandlerRB(pUART, pRXRB); +} + +/* Determines and sets best dividers to get a target baud rate */ +uint32_t Chip_UART_SetBaudFDR(LPC_USART_T *pUART, uint32_t baudrate) + +{ + uint32_t uClk = 0; + uint32_t dval = 0; + uint32_t mval = 0; + uint32_t dl = 0; + uint32_t rate16 = 16 * baudrate; + uint32_t actualRate = 0; + + /* Get Clock rate */ + uClk = Chip_Clock_GetMainClockRate(); + + /* The fractional is calculated as (PCLK % (16 * Baudrate)) / (16 * Baudrate) + * Let's make it to be the ratio DivVal / MulVal + */ + dval = uClk % rate16; + + /* The PCLK / (16 * Baudrate) is fractional + * => dval = pclk % rate16 + * mval = rate16; + * now mormalize the ratio + * dval / mval = 1 / new_mval + * new_mval = mval / dval + * new_dval = 1 + */ + if (dval > 0) { + mval = rate16 / dval; + dval = 1; + + /* In case mval still bigger then 4 bits + * no adjustment require + */ + if (mval > 12) { + dval = 0; + } + } + dval &= 0xf; + mval &= 0xf; + dl = uClk / (rate16 + rate16 *dval / mval); + + /* Update UART registers */ + Chip_UART_EnableDivisorAccess(pUART); + Chip_UART_SetDivisorLatches(pUART, UART_LOAD_DLL(dl), UART_LOAD_DLM(dl)); + Chip_UART_DisableDivisorAccess(pUART); + + /* Set best fractional divider */ + pUART->FDR = (UART_FDR_MULVAL(mval) | UART_FDR_DIVADDVAL(dval)); + + /* Return actual baud rate */ + actualRate = uClk / (16 * dl + 16 * dl * dval / mval); + return actualRate; +} diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index 21b0b2bbcb..ddf96183e4 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -36,8 +36,9 @@ struct PinMuxGroup constexpr PinMuxGroup pinmux[] = { - { IOCON_PIO1_10, IOCON_FUNC0 | IOCON_MODE_INACT }, // Error LED - { IOCON_PIO1_11, IOCON_FUNC0 | IOCON_MODE_INACT } // Status LED + { IOCON_PIO1_10, IOCON_FUNC0 | IOCON_MODE_INACT }, // Error LED + { IOCON_PIO1_11, IOCON_FUNC0 | IOCON_MODE_INACT }, // Status LED + { IOCON_PIO1_7, IOCON_FUNC1 | IOCON_HYS_EN | IOCON_MODE_PULLUP }, // UART_TXD }; @@ -109,6 +110,13 @@ void initGpio() LPC_GPIO[StatusLedPort].DIR |= 1 << StatusLedPin; } +void initUart() +{ + Chip_UART_Init(LPC_USART); + Chip_UART_SetBaud(LPC_USART, 115200); + Chip_UART_TXEnable(LPC_USART); +} + void init() { Chip_SYSCTL_SetBODLevels(SYSCTL_BODRSTLVL_2_06V, SYSCTL_BODINTVAL_RESERVED1); @@ -117,6 +125,7 @@ void init() initWatchdog(); initClock(); initGpio(); + initUart(); resetWatchdog(); } @@ -149,6 +158,14 @@ void resetWatchdog() Chip_WWDT_Feed(LPC_WWDT); } +#if __GNUC__ +__attribute__((optimize(0))) // Optimization must be disabled lest it hardfaults in the IAP call +#endif +void syslog(const char* msg) +{ + Chip_UART_SendBlocking(LPC_USART, msg, static_cast(std::strlen(msg))); +} + } // namespace board extern "C" diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp index f0da90533a..ab58c7da0a 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp @@ -16,4 +16,6 @@ void setErrorLed(bool state); void resetWatchdog(); +void syslog(const char* msg); + } From 42b48d9626554954ef5a0e7ffb6f4c42265b2d46 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 16:42:54 +0300 Subject: [PATCH 06/30] LPC11C24 wrong optimization setting --- .../lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index ddf96183e4..169dd35758 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -158,9 +158,6 @@ void resetWatchdog() Chip_WWDT_Feed(LPC_WWDT); } -#if __GNUC__ -__attribute__((optimize(0))) // Optimization must be disabled lest it hardfaults in the IAP call -#endif void syslog(const char* msg) { Chip_UART_SendBlocking(LPC_USART, msg, static_cast(std::strlen(msg))); From 8eac06c9dcf9588ed4813819c5fac7457373a761 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 16:44:58 +0300 Subject: [PATCH 07/30] LPC11C24 test: some GCC flags were removed, which fixed hardfault and reduced code size by ~300 bytes --- libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/Makefile | 2 -- 1 file changed, 2 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/Makefile b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/Makefile index 818975feca..9a503bc4ef 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/Makefile +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/Makefile @@ -49,10 +49,8 @@ DEPDIR = $(BUILDDIR)/dep DEF += -DNDEBUG -DCHIP_LPC11CXX -DCORE_M0 -DTHUMB_NO_INTERWORKING -U__STRICT_ANSI__ -# Removing -fconserve-stack reduces code size a little FLAGS = -mthumb -mcpu=cortex-m0 -mno-thumb-interwork -flto -Os -g3 -Wall -Wextra -Werror -Wundef -ffunction-sections \ -fdata-sections -fno-common -fno-exceptions -fno-unwind-tables -fno-stack-protector -fomit-frame-pointer \ - -ftracer -ftree-loop-distribute-patterns -frename-registers -freorder-blocks -fconserve-stack \ -Wfloat-equal -Wconversion -Wsign-conversion -Wmissing-declarations C_CPP_FLAGS = $(FLAGS) -MD -MP -MF $(DEPDIR)/$(@F).d From d82213504f8d799d79c31bbdbe499b67451f2c2b Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 18:03:01 +0300 Subject: [PATCH 08/30] LPC11C24 PoC UART logging --- libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index 0f1ff0125c..03f84f331f 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -47,11 +47,13 @@ __attribute__((noinline)) void init() { board::resetWatchdog(); + board::syslog("Boot\r\n"); if (uavcan_lpc11c24::CanDriver::instance().init(1000000) < 0) { die(); } + board::syslog("CAN init ok\r\n"); board::resetWatchdog(); From b7aa3109bc98edf25a2dad1625d249b092f70e2b Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 18:05:19 +0300 Subject: [PATCH 09/30] LPC11C24: Consistent use of nullptr --- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index 76e102c45e..d6bc0cf93e 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -179,11 +179,11 @@ int CanDriver::init(uavcan::uint32_t bitrate) canRxCallback, canTxCallback, canErrorCallback, - 0, - 0, - 0, - 0, - 0 + nullptr, + nullptr, + nullptr, + nullptr, + nullptr }; LPC_CCAN_API->config_calb(&ccan_callbacks); NVIC_EnableIRQ(CAN_IRQn); @@ -340,7 +340,7 @@ uavcan::uint16_t CanDriver::getNumFilters() const uavcan::ICanIface* CanDriver::getIface(uavcan::uint8_t iface_index) { - return (iface_index == 0) ? this : NULL; + return (iface_index == 0) ? this : nullptr; } uavcan::uint8_t CanDriver::getNumIfaces() const From dedefdc6a876f707dbb47c267996443ea9812884 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 19:35:02 +0300 Subject: [PATCH 10/30] LPC11C24: Added C_CAN definitions; they are still unused --- .../lpc11c24/driver/src/c_can.hpp | 160 ++++++++++++++++++ libuavcan_drivers/lpc11c24/driver/src/can.cpp | 1 + 2 files changed, 161 insertions(+) create mode 100644 libuavcan_drivers/lpc11c24/driver/src/c_can.hpp diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp new file mode 100644 index 0000000000..e41653bc24 --- /dev/null +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -0,0 +1,160 @@ +/* + * Bosch C_CAN controller API. + * + * Copyright (C) 2015 Pavel Kirienko + */ + +#pragma once + +#include +#include + +namespace uavcan_lpc11c24 +{ +namespace c_can +{ + +struct MsgIfaceType +{ + std::uint32_t CMDREQ; + + union + { + std::uint32_t W; + std::uint32_t R; + } CMDMSK; + + std::uint32_t MSK1; + std::uint32_t MSK2; + + std::uint32_t ARB1; + std::uint32_t ARB2; + + std::uint32_t MCTRL; + + std::uint32_t DA1; + std::uint32_t DA2; + std::uint32_t DB1; + std::uint32_t DB2; + + const std::uint32_t _skip[13]; +}; + +static_assert(offsetof(MsgIfaceType, CMDMSK) == 0x04, "C_CAN offset"); +static_assert(offsetof(MsgIfaceType, MSK1) == 0x08, "C_CAN offset"); +static_assert(offsetof(MsgIfaceType, ARB1) == 0x10, "C_CAN offset"); +static_assert(offsetof(MsgIfaceType, MCTRL) == 0x18, "C_CAN offset"); +static_assert(offsetof(MsgIfaceType, DA1) == 0x1c, "C_CAN offset"); +static_assert(offsetof(MsgIfaceType, DB2) == 0x28, "C_CAN offset"); + +static_assert(sizeof(MsgIfaceType) == 96, "C_CAN size"); + + +struct Type +{ + std::uint32_t CNTL; + std::uint32_t STAT; + const std::uint32_t EC; + std::uint32_t BT; + const std::uint32_t INT; + std::uint32_t TEST; + std::uint32_t BRPE; + + const std::uint32_t _skip_a[1]; + + MsgIfaceType IF[2]; // [0] @ 0x020, [1] @ 0x080 + + const std::uint32_t _skip_b[8]; + + const std::uint32_t TXREQ[2]; // 0x100 + + const std::uint32_t _skip_c[6]; + + const std::uint32_t ND[2]; // 0x120 + + const std::uint32_t _skip_d[6]; + + const std::uint32_t IR[2]; // 0x140 + + const std::uint32_t _skip_e[6]; + + const std::uint32_t MSGV[2]; // 0x160 + + const std::uint32_t _skip_f[6]; + + std::uint32_t CLKDIV; // 0x180 +}; + +static_assert(offsetof(Type, BRPE) == 0x018, "C_CAN offset"); +static_assert(offsetof(Type, IF[0]) == 0x020, "C_CAN offset"); +static_assert(offsetof(Type, IF[1]) == 0x080, "C_CAN offset"); +static_assert(offsetof(Type, TXREQ) == 0x100, "C_CAN offset"); +static_assert(offsetof(Type, ND) == 0x120, "C_CAN offset"); +static_assert(offsetof(Type, IR) == 0x140, "C_CAN offset"); +static_assert(offsetof(Type, MSGV) == 0x160, "C_CAN offset"); +static_assert(offsetof(Type, CLKDIV) == 0x180, "C_CAN offset"); + +static_assert(offsetof(Type, IF[0].DB2) == 0x048, "C_CAN offset"); +static_assert(offsetof(Type, IF[1].DB2) == 0x0A8, "C_CAN offset"); + + +Type* const Can = reinterpret_cast(0x40050000); + + +/* + * CNTL + */ +static constexpr std::uint16_t CNTL_TEST = 1 << 7; +static constexpr std::uint16_t CNTL_CCE = 1 << 6; +static constexpr std::uint16_t CNTL_DAR = 1 << 5; +static constexpr std::uint16_t CNTL_EIE = 1 << 3; +static constexpr std::uint16_t CNTL_SIE = 1 << 2; +static constexpr std::uint16_t CNTL_IE = 1 << 1; +static constexpr std::uint16_t CNTL_INIT = 1 << 0; + +static constexpr std::uint16_t CNTL_IRQ_MASK = CNTL_EIE | CNTL_IE | CNTL_SIE; + +/* + * TEST + */ +static constexpr std::uint16_t TEST_RX = 1 << 7; +static constexpr std::uint16_t TEST_LBACK = 1 << 4; +static constexpr std::uint16_t TEST_SILENT = 1 << 3; +static constexpr std::uint16_t TEST_BASIC = 1 << 2; +static constexpr std::uint16_t TEST_TX_SHIFT = 5; + +enum class TestTx : std::uint16_t +{ + Controller = 0, + SamplePoint = 1, + Low = 2, + High = 3 +}; + +/* + * STAT + */ +static constexpr std::uint16_t STAT_BOFF = 1 << 7; +static constexpr std::uint16_t STAT_EWARN = 1 << 6; +static constexpr std::uint16_t STAT_EPASS = 1 << 5; +static constexpr std::uint16_t STAT_RXOK = 1 << 4; +static constexpr std::uint16_t STAT_TXOK = 1 << 3; +static constexpr std::uint16_t STAT_LEC_MASK = 7; +static constexpr std::uint16_t STAT_LEC_SHIFT = 0; + +/* + * IF.MCTRL + */ +static constexpr std::uint16_t IF_MCTRL_NEWDAT = 1 << 15; +static constexpr std::uint16_t IF_MCTRL_MSGLST = 1 << 14; +static constexpr std::uint16_t IF_MCTRL_INTPND = 1 << 13; +static constexpr std::uint16_t IF_MCTRL_UMASK = 1 << 12; +static constexpr std::uint16_t IF_MCTRL_TXIE = 1 << 11; +static constexpr std::uint16_t IF_MCTRL_RXIE = 1 << 10; +static constexpr std::uint16_t IF_MCTRL_RMTEN = 1 << 9; +static constexpr std::uint16_t IF_MCTRL_TXRQST = 1 << 8; +static constexpr std::uint16_t IF_MCTRL_EOB = 1 << 7; +static constexpr std::uint16_t IF_MCTRL_DLC_MASK = 15; + +} +} diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index d6bc0cf93e..46fff1b386 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -6,6 +6,7 @@ #include #include #include +#include "c_can.hpp" #include "internal.hpp" /** From d75e76555de74f075518b716d98bf23202136038 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 24 Aug 2015 19:44:47 +0300 Subject: [PATCH 11/30] LPC11C24: CanDriver::detectBitRate() - NOT TESTED, NOT FINISHED --- .../driver/include/uavcan_lpc11c24/can.hpp | 9 ++++ .../lpc11c24/driver/src/c_can.hpp | 2 +- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 51 +++++++++++++++++++ 3 files changed, 61 insertions(+), 1 deletion(-) diff --git a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp index 6dae53f215..ae4f90194e 100644 --- a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp @@ -29,6 +29,15 @@ public: */ static CanDriver& instance() { return self; } + /** + * Attempts to detect bit rate of the CAN bus. + * This function may block for up to X seconds, where X is the number of bit rates to try. + * This function is NOT guaranteed to reset the CAN controller upon return. + * @return On success: detected bit rate, in bits per second. + * On failure: zero. + */ + static uavcan::uint32_t detectBitRate(void (*idle_callback)() = nullptr); + /** * Returns negative value if the requested baudrate can't be used. * Returns zero if OK. diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index e41653bc24..e5f1987ee1 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -98,7 +98,7 @@ static_assert(offsetof(Type, IF[0].DB2) == 0x048, "C_CAN offset"); static_assert(offsetof(Type, IF[1].DB2) == 0x0A8, "C_CAN offset"); -Type* const Can = reinterpret_cast(0x40050000); +Type& Can = *reinterpret_cast(0x40050000); /* diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index 46fff1b386..c60ead46ab 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -156,6 +156,57 @@ BitTimingSettings computeBitTimings(std::uint32_t bitrate) CanDriver CanDriver::self; +uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) +{ + static constexpr uavcan::uint32_t BitRatesToTry[] = + { + 1000000, + 500000, + 250000, + 125000 + }; + + const auto ListeningDuration = uavcan::MonotonicDuration::fromMSec(1050); + + Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); + + for (auto bitrate : BitRatesToTry) + { + // Computing bit timings + const auto bit_timings = computeBitTimings(bitrate); + if (!bit_timings.isValid()) + { + return 0; + } + + // Configuring the CAN controller + { + CriticalSectionLocker locker; + + c_can::Can.CNTL = c_can::CNTL_DAR | c_can::CNTL_CCE; + + c_can::Can.BT = bit_timings.canbtr; + c_can::Can.CLKDIV = bit_timings.canclkdiv; + + c_can::Can.TEST = c_can::TEST_SILENT; + + c_can::Can.CNTL = c_can::CNTL_DAR; + } + + // Listening + const auto deadline = clock::getMonotonic() + ListeningDuration; + while (clock::getMonotonic() < deadline) + { + if (idle_callback != nullptr) + { + idle_callback(); + } + } + } + + return 0; +} + int CanDriver::init(uavcan::uint32_t bitrate) { CriticalSectionLocker locker; From 5a649eb11bd64a3ef6166703f229eef1bcb560a8 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Sun, 11 Oct 2015 20:40:32 +0300 Subject: [PATCH 12/30] LPC11C24 clock initialization validation --- libuavcan_drivers/lpc11c24/driver/src/clock.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libuavcan_drivers/lpc11c24/driver/src/clock.cpp b/libuavcan_drivers/lpc11c24/driver/src/clock.cpp index 07098d6c5e..a9d299f063 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/clock.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/clock.cpp @@ -82,6 +82,10 @@ std::uint64_t getUtcUSecFromCanInterrupt() uavcan::MonotonicTime getMonotonic() { + if (!initialized) + { + fail(); + } std::uint64_t usec = 0; { CriticalSectionLocker locker; @@ -92,6 +96,10 @@ uavcan::MonotonicTime getMonotonic() uavcan::UtcTime getUtc() { + if (!initialized) + { + fail(); + } std::uint64_t usec = 0; if (utc_set) { From 800f245be798ad8465501d7129c848e9bd9cdfa8 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 00:12:52 +0300 Subject: [PATCH 13/30] LPC11C24 automatic CAN bit rate detection --- .../lpc11c24/driver/src/c_can.hpp | 22 +++- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 30 ++++- .../test_olimex_lpc_p11c24/src/main.cpp | 122 ++++++++++-------- .../test_olimex_lpc_p11c24/src/sys/board.cpp | 5 + .../test_olimex_lpc_p11c24/src/sys/board.hpp | 5 + 5 files changed, 121 insertions(+), 63 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index e5f1987ee1..9354941f88 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -98,7 +98,7 @@ static_assert(offsetof(Type, IF[0].DB2) == 0x048, "C_CAN offset"); static_assert(offsetof(Type, IF[1].DB2) == 0x0A8, "C_CAN offset"); -Type& Can = *reinterpret_cast(0x40050000); +Type& CAN = *reinterpret_cast(0x40050000); /* @@ -125,10 +125,10 @@ static constexpr std::uint16_t TEST_TX_SHIFT = 5; enum class TestTx : std::uint16_t { - Controller = 0, - SamplePoint = 1, - Low = 2, - High = 3 + Controller = 0, + SamplePoint = 1, + LowDominant = 2, + HighRecessive = 3 }; /* @@ -142,6 +142,18 @@ static constexpr std::uint16_t STAT_TXOK = 1 << 3; static constexpr std::uint16_t STAT_LEC_MASK = 7; static constexpr std::uint16_t STAT_LEC_SHIFT = 0; +enum class StatLec : std::uint16_t +{ + NoError = 0, + StuffError = 1, + FormError = 2, + AckError = 3, + Bit1Error = 4, + Bit0Error = 5, + CRCError = 6, + Unused = 7 +}; + /* * IF.MCTRL */ diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index c60ead46ab..2b263f9572 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -183,28 +183,46 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) { CriticalSectionLocker locker; - c_can::Can.CNTL = c_can::CNTL_DAR | c_can::CNTL_CCE; + c_can::CAN.CNTL = c_can::CNTL_INIT | c_can::CNTL_DAR | c_can::CNTL_CCE | c_can::CNTL_TEST; - c_can::Can.BT = bit_timings.canbtr; - c_can::Can.CLKDIV = bit_timings.canclkdiv; + c_can::CAN.BT = bit_timings.canbtr; + c_can::CAN.CLKDIV = bit_timings.canclkdiv; - c_can::Can.TEST = c_can::TEST_SILENT; + c_can::CAN.TEST = c_can::TEST_SILENT | (unsigned(c_can::TestTx::HighRecessive) << c_can::TEST_TX_SHIFT); - c_can::Can.CNTL = c_can::CNTL_DAR; + c_can::CAN.STAT = (unsigned(c_can::StatLec::Unused) << c_can::STAT_LEC_SHIFT); + + c_can::CAN.CNTL = c_can::CNTL_DAR | c_can::CNTL_TEST; } // Listening const auto deadline = clock::getMonotonic() + ListeningDuration; + bool match_detected = false; while (clock::getMonotonic() < deadline) { if (idle_callback != nullptr) { idle_callback(); } + + if ((c_can::CAN.STAT >> c_can::STAT_LEC_SHIFT) == unsigned(c_can::StatLec::NoError)) + { + match_detected = true; + break; + } + } + + // De-configuring the CAN controller back to reset state + c_can::CAN.CNTL = c_can::CNTL_INIT; + + // Termination condition + if (match_detected) + { + return bitrate; } } - return 0; + return 0; // No match } int CanDriver::init(uavcan::uint32_t bitrate) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index 03f84f331f..a80f832a79 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -13,11 +13,42 @@ namespace { -typedef uavcan::Node<2800> Node; +static constexpr unsigned NodeMemoryPoolSize = 2800; -Node& getNode() +/** + * This is a compact, reentrant and thread-safe replacement to standard llto(). + * It returns the string by value, no extra storage is needed. + */ +typename uavcan::MakeString<22>::Type intToString(long long n) { - static Node node(uavcan_lpc11c24::CanDriver::instance(), uavcan_lpc11c24::SystemClock::instance()); + char buf[24] = {}; + const short sign = (n < 0) ? -1 : 1; + if (sign < 0) + { + n = -n; + } + unsigned pos = 0; + do + { + buf[pos++] = char(n % 10 + '0'); + } + while ((n /= 10) > 0); + if (sign < 0) + { + buf[pos++] = '-'; + } + buf[pos] = '\0'; + for (unsigned i = 0, j = pos - 1U; i < j; i++, j--) + { + std::swap(buf[i], buf[j]); + } + return static_cast(buf); +} + +uavcan::Node& getNode() +{ + static uavcan::Node node(uavcan_lpc11c24::CanDriver::instance(), + uavcan_lpc11c24::SystemClock::instance()); return node; } @@ -33,14 +64,6 @@ uavcan::Logger& getLogger() return logger; } -#if __GNUC__ -__attribute__((noreturn)) -#endif -void die() -{ - while (true) { } -} - #if __GNUC__ __attribute__((noinline)) #endif @@ -49,15 +72,38 @@ void init() board::resetWatchdog(); board::syslog("Boot\r\n"); - if (uavcan_lpc11c24::CanDriver::instance().init(1000000) < 0) + board::setErrorLed(false); + board::setStatusLed(true); + + /* + * Configuring the clock - this must be done before the CAN controller is initialized + */ + uavcan_lpc11c24::clock::init(); + + /* + * Configuring the CAN controller + */ + std::uint32_t bit_rate = 0; + while (bit_rate == 0) { - die(); + board::syslog("CAN bitrate detection...\r\n"); + bit_rate = uavcan_lpc11c24::CanDriver::detectBitRate(&board::resetWatchdog); + } + board::syslog("CAN bitrate: "); + board::syslog(intToString(bit_rate).c_str()); + board::syslog("\r\n"); + + if (uavcan_lpc11c24::CanDriver::instance().init(bit_rate) < 0) + { + board::die(); } board::syslog("CAN init ok\r\n"); board::resetWatchdog(); - getNode().setNodeID(72); + /* + * Configuring the node + */ getNode().setName("org.uavcan.lpc11c24_test"); uavcan::protocol::SoftwareVersion swver; @@ -75,6 +121,14 @@ void init() board::resetWatchdog(); + /* + * Performing dynamic node ID allocation + */ + getNode().setNodeID(72); // TODO + + /* + * Starting the node + */ while (getNode().start() < 0) { } @@ -93,37 +147,6 @@ void init() board::resetWatchdog(); } -void reverse(char* s) -{ - for (int i = 0, j = int(std::strlen(s)) - 1; i < j; i++, j--) - { - const char c = s[i]; - s[i] = s[j]; - s[j] = c; - } -} - -void lltoa(long long n, char buf[24]) -{ - const short sign = (n < 0) ? -1 : 1; - if (sign < 0) - { - n = -n; - } - unsigned i = 0; - do - { - buf[i++] = char(n % 10 + '0'); - } - while ((n /= 10) > 0); - if (sign < 0) - { - buf[i++] = '-'; - } - buf[i] = '\0'; - reverse(buf); -} - } int main() @@ -144,17 +167,12 @@ int main() if ((ts - prev_log_at).toMSec() >= 1000) { prev_log_at = ts; - // We don't want to use formatting functions provided by libuavcan because they rely on std::snprintf() - char buf[24]; - lltoa(uavcan_lpc11c24::clock::getPrevUtcAdjustment().toUSec(), buf); - buf[sizeof(buf) - 1] = '\0'; - - // ...hence we need to construct the message manually: + // hence we need to construct the message manually: uavcan::protocol::debug::LogMessage logmsg; logmsg.level.value = uavcan::protocol::debug::LogLevel::INFO; logmsg.source = "app"; - logmsg.text = buf; + logmsg.text = intToString(uavcan_lpc11c24::clock::getPrevUtcAdjustment().toUSec()).c_str(); (void)getLogger().log(logmsg); } diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index 169dd35758..63d4f8ac54 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -132,6 +132,11 @@ void init() } // namespace +void die() +{ + while (true) { } +} + #if __GNUC__ __attribute__((optimize(0))) // Optimization must be disabled lest it hardfaults in the IAP call #endif diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp index ab58c7da0a..cdb84fe331 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp @@ -7,6 +7,11 @@ namespace board { +#if __GNUC__ +__attribute__((noreturn)) +#endif +void die(); + static constexpr unsigned UniqueIDSize = 16; void readUniqueID(std::uint8_t out_uid[UniqueIDSize]); From 972d895f88aa3755d2088317365380f26777ba9e Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 01:12:42 +0300 Subject: [PATCH 14/30] LPC11C24 C_CAN paranoid offset checks --- libuavcan_drivers/lpc11c24/driver/src/c_can.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index 9354941f88..3f802b06e5 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -85,6 +85,9 @@ struct Type std::uint32_t CLKDIV; // 0x180 }; +static_assert(offsetof(Type, CNTL) == 0x000, "C_CAN offset"); +static_assert(offsetof(Type, STAT) == 0x004, "C_CAN offset"); +static_assert(offsetof(Type, TEST) == 0x014, "C_CAN offset"); static_assert(offsetof(Type, BRPE) == 0x018, "C_CAN offset"); static_assert(offsetof(Type, IF[0]) == 0x020, "C_CAN offset"); static_assert(offsetof(Type, IF[1]) == 0x080, "C_CAN offset"); From 851b0c7c29b9ae60e2b197823dc2895bd258fd76 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 02:34:00 +0300 Subject: [PATCH 15/30] LPC11C24 C_CAN 32 bit constants allow to use ~ without explicit cast --- .../lpc11c24/driver/src/c_can.hpp | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index 3f802b06e5..fe2ef1ccf2 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -107,26 +107,26 @@ Type& CAN = *reinterpret_cast(0x40050000); /* * CNTL */ -static constexpr std::uint16_t CNTL_TEST = 1 << 7; -static constexpr std::uint16_t CNTL_CCE = 1 << 6; -static constexpr std::uint16_t CNTL_DAR = 1 << 5; -static constexpr std::uint16_t CNTL_EIE = 1 << 3; -static constexpr std::uint16_t CNTL_SIE = 1 << 2; -static constexpr std::uint16_t CNTL_IE = 1 << 1; -static constexpr std::uint16_t CNTL_INIT = 1 << 0; +static constexpr std::uint32_t CNTL_TEST = 1 << 7; +static constexpr std::uint32_t CNTL_CCE = 1 << 6; +static constexpr std::uint32_t CNTL_DAR = 1 << 5; +static constexpr std::uint32_t CNTL_EIE = 1 << 3; +static constexpr std::uint32_t CNTL_SIE = 1 << 2; +static constexpr std::uint32_t CNTL_IE = 1 << 1; +static constexpr std::uint32_t CNTL_INIT = 1 << 0; -static constexpr std::uint16_t CNTL_IRQ_MASK = CNTL_EIE | CNTL_IE | CNTL_SIE; +static constexpr std::uint32_t CNTL_IRQ_MASK = CNTL_EIE | CNTL_IE | CNTL_SIE; /* * TEST */ -static constexpr std::uint16_t TEST_RX = 1 << 7; -static constexpr std::uint16_t TEST_LBACK = 1 << 4; -static constexpr std::uint16_t TEST_SILENT = 1 << 3; -static constexpr std::uint16_t TEST_BASIC = 1 << 2; -static constexpr std::uint16_t TEST_TX_SHIFT = 5; +static constexpr std::uint32_t TEST_RX = 1 << 7; +static constexpr std::uint32_t TEST_LBACK = 1 << 4; +static constexpr std::uint32_t TEST_SILENT = 1 << 3; +static constexpr std::uint32_t TEST_BASIC = 1 << 2; +static constexpr std::uint32_t TEST_TX_SHIFT = 5; -enum class TestTx : std::uint16_t +enum class TestTx : std::uint32_t { Controller = 0, SamplePoint = 1, @@ -137,15 +137,15 @@ enum class TestTx : std::uint16_t /* * STAT */ -static constexpr std::uint16_t STAT_BOFF = 1 << 7; -static constexpr std::uint16_t STAT_EWARN = 1 << 6; -static constexpr std::uint16_t STAT_EPASS = 1 << 5; -static constexpr std::uint16_t STAT_RXOK = 1 << 4; -static constexpr std::uint16_t STAT_TXOK = 1 << 3; -static constexpr std::uint16_t STAT_LEC_MASK = 7; -static constexpr std::uint16_t STAT_LEC_SHIFT = 0; +static constexpr std::uint32_t STAT_BOFF = 1 << 7; +static constexpr std::uint32_t STAT_EWARN = 1 << 6; +static constexpr std::uint32_t STAT_EPASS = 1 << 5; +static constexpr std::uint32_t STAT_RXOK = 1 << 4; +static constexpr std::uint32_t STAT_TXOK = 1 << 3; +static constexpr std::uint32_t STAT_LEC_MASK = 7; +static constexpr std::uint32_t STAT_LEC_SHIFT = 0; -enum class StatLec : std::uint16_t +enum class StatLec : std::uint32_t { NoError = 0, StuffError = 1, @@ -160,16 +160,16 @@ enum class StatLec : std::uint16_t /* * IF.MCTRL */ -static constexpr std::uint16_t IF_MCTRL_NEWDAT = 1 << 15; -static constexpr std::uint16_t IF_MCTRL_MSGLST = 1 << 14; -static constexpr std::uint16_t IF_MCTRL_INTPND = 1 << 13; -static constexpr std::uint16_t IF_MCTRL_UMASK = 1 << 12; -static constexpr std::uint16_t IF_MCTRL_TXIE = 1 << 11; -static constexpr std::uint16_t IF_MCTRL_RXIE = 1 << 10; -static constexpr std::uint16_t IF_MCTRL_RMTEN = 1 << 9; -static constexpr std::uint16_t IF_MCTRL_TXRQST = 1 << 8; -static constexpr std::uint16_t IF_MCTRL_EOB = 1 << 7; -static constexpr std::uint16_t IF_MCTRL_DLC_MASK = 15; +static constexpr std::uint32_t IF_MCTRL_NEWDAT = 1 << 15; +static constexpr std::uint32_t IF_MCTRL_MSGLST = 1 << 14; +static constexpr std::uint32_t IF_MCTRL_INTPND = 1 << 13; +static constexpr std::uint32_t IF_MCTRL_UMASK = 1 << 12; +static constexpr std::uint32_t IF_MCTRL_TXIE = 1 << 11; +static constexpr std::uint32_t IF_MCTRL_RXIE = 1 << 10; +static constexpr std::uint32_t IF_MCTRL_RMTEN = 1 << 9; +static constexpr std::uint32_t IF_MCTRL_TXRQST = 1 << 8; +static constexpr std::uint32_t IF_MCTRL_EOB = 1 << 7; +static constexpr std::uint32_t IF_MCTRL_DLC_MASK = 15; } } From fc2a4527d31186a584694d100548bfc17787a365 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 02:37:13 +0300 Subject: [PATCH 16/30] LPC11C24 fixes and some debug output to bit rate detection routine --- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 35 ++++++++++++++++--- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index 2b263f9572..cc8aadd53d 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -156,6 +156,9 @@ BitTimingSettings computeBitTimings(std::uint32_t bitrate) CanDriver CanDriver::self; +#if __GNUC__ +__attribute__((optimize(1))) +#endif uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) { static constexpr uavcan::uint32_t BitRatesToTry[] = @@ -168,6 +171,8 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) const auto ListeningDuration = uavcan::MonotonicDuration::fromMSec(1050); + NVIC_DisableIRQ(CAN_IRQn); + LPC_SYSCTL->PRESETCTRL |= (1 << RESET_CAN0); Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); for (auto bitrate : BitRatesToTry) @@ -183,16 +188,24 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) { CriticalSectionLocker locker; - c_can::CAN.CNTL = c_can::CNTL_INIT | c_can::CNTL_DAR | c_can::CNTL_CCE | c_can::CNTL_TEST; + c_can::CAN.CNTL = c_can::CNTL_INIT | c_can::CNTL_CCE | c_can::CNTL_TEST; - c_can::CAN.BT = bit_timings.canbtr; c_can::CAN.CLKDIV = bit_timings.canclkdiv; - c_can::CAN.TEST = c_can::TEST_SILENT | (unsigned(c_can::TestTx::HighRecessive) << c_can::TEST_TX_SHIFT); + c_can::CAN.BRPE = 0; + c_can::CAN.BT = bit_timings.canbtr; + + c_can::CAN.TEST = c_can::TEST_SILENT; c_can::CAN.STAT = (unsigned(c_can::StatLec::Unused) << c_can::STAT_LEC_SHIFT); - c_can::CAN.CNTL = c_can::CNTL_DAR | c_can::CNTL_TEST; + c_can::CAN.CNTL = c_can::CNTL_TEST; + } + + // TODO THIS IS TEMPORARY, REMOVE LATER + if (c_can::CAN.BT != bit_timings.canbtr) + { + Chip_UART_SendBlocking(LPC_USART, "BT\r\n", 4); } // Listening @@ -205,7 +218,19 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) idle_callback(); } - if ((c_can::CAN.STAT >> c_can::STAT_LEC_SHIFT) == unsigned(c_can::StatLec::NoError)) + const auto LastErrorCode = (c_can::CAN.STAT >> c_can::STAT_LEC_SHIFT) & c_can::STAT_LEC_MASK; + + // TODO THIS IS TEMPORARY, REMOVE LATER + if (LastErrorCode != unsigned(c_can::StatLec::Unused) && + LastErrorCode != unsigned(c_can::StatLec::NoError)) + { + const char txt[] = { 'E', char('0' + LastErrorCode), ' ', + 'R', (((c_can::CAN.STAT & c_can::STAT_RXOK) != 0) ? '1' : '0'), + '\r', '\n' }; + Chip_UART_SendBlocking(LPC_USART, txt, sizeof(txt)); + } + + if (LastErrorCode == unsigned(c_can::StatLec::NoError)) { match_detected = true; break; From 563ec45c6e69080b06446a1461d277564f47cac3 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 04:07:13 +0300 Subject: [PATCH 17/30] LPC11C24 auto bit rate detection is sort of working --- .../lpc11c24/driver/src/c_can.hpp | 2 +- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 58 +++++++++++-------- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index fe2ef1ccf2..cbeb035ea5 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -101,7 +101,7 @@ static_assert(offsetof(Type, IF[0].DB2) == 0x048, "C_CAN offset"); static_assert(offsetof(Type, IF[1].DB2) == 0x0A8, "C_CAN offset"); -Type& CAN = *reinterpret_cast(0x40050000); +volatile Type& CAN = *reinterpret_cast(0x40050000); /* diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index cc8aadd53d..0ab31fc3d6 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -156,9 +156,6 @@ BitTimingSettings computeBitTimings(std::uint32_t bitrate) CanDriver CanDriver::self; -#if __GNUC__ -__attribute__((optimize(1))) -#endif uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) { static constexpr uavcan::uint32_t BitRatesToTry[] = @@ -172,7 +169,6 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) const auto ListeningDuration = uavcan::MonotonicDuration::fromMSec(1050); NVIC_DisableIRQ(CAN_IRQn); - LPC_SYSCTL->PRESETCTRL |= (1 << RESET_CAN0); Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); for (auto bitrate : BitRatesToTry) @@ -188,24 +184,35 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) { CriticalSectionLocker locker; - c_can::CAN.CNTL = c_can::CNTL_INIT | c_can::CNTL_CCE | c_can::CNTL_TEST; + LPC_SYSCTL->PRESETCTRL |= (1U << RESET_CAN0); + // Entering initialization mode + c_can::CAN.CNTL = c_can::CNTL_INIT | c_can::CNTL_CCE; + + while ((c_can::CAN.CNTL & c_can::CNTL_INIT) == 0) + { + ; // Nothing to do + } + + // Configuring bit rate c_can::CAN.CLKDIV = bit_timings.canclkdiv; + c_can::CAN.BT = bit_timings.canbtr; + c_can::CAN.BRPE = 0; - c_can::CAN.BRPE = 0; - c_can::CAN.BT = bit_timings.canbtr; - + // Configuring silent mode + c_can::CAN.CNTL |= c_can::CNTL_TEST; c_can::CAN.TEST = c_can::TEST_SILENT; + // Configuring status monitor c_can::CAN.STAT = (unsigned(c_can::StatLec::Unused) << c_can::STAT_LEC_SHIFT); - c_can::CAN.CNTL = c_can::CNTL_TEST; - } + // Leaving initialization mode + c_can::CAN.CNTL &= ~(c_can::CNTL_INIT | c_can::CNTL_CCE); - // TODO THIS IS TEMPORARY, REMOVE LATER - if (c_can::CAN.BT != bit_timings.canbtr) - { - Chip_UART_SendBlocking(LPC_USART, "BT\r\n", 4); + while ((c_can::CAN.CNTL & c_can::CNTL_INIT) != 0) + { + ; // Nothing to do + } } // Listening @@ -220,16 +227,6 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) const auto LastErrorCode = (c_can::CAN.STAT >> c_can::STAT_LEC_SHIFT) & c_can::STAT_LEC_MASK; - // TODO THIS IS TEMPORARY, REMOVE LATER - if (LastErrorCode != unsigned(c_can::StatLec::Unused) && - LastErrorCode != unsigned(c_can::StatLec::NoError)) - { - const char txt[] = { 'E', char('0' + LastErrorCode), ' ', - 'R', (((c_can::CAN.STAT & c_can::STAT_RXOK) != 0) ? '1' : '0'), - '\r', '\n' }; - Chip_UART_SendBlocking(LPC_USART, txt, sizeof(txt)); - } - if (LastErrorCode == unsigned(c_can::StatLec::NoError)) { match_detected = true; @@ -238,7 +235,18 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) } // De-configuring the CAN controller back to reset state - c_can::CAN.CNTL = c_can::CNTL_INIT; + { + CriticalSectionLocker locker; + + c_can::CAN.CNTL = c_can::CNTL_INIT; + + while ((c_can::CAN.CNTL & c_can::CNTL_INIT) == 0) + { + ; // Nothing to do + } + + LPC_SYSCTL->PRESETCTRL &= ~(1U << RESET_CAN0); + } // Termination condition if (match_detected) From 98000f2076dc6e41f96e2845efd7451014c03bae Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 08:39:22 +0300 Subject: [PATCH 18/30] LPC11C24 driver - removed some literal constants --- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index 0ab31fc3d6..e548e4c915 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -35,7 +35,10 @@ namespace * TX priority is defined by the message object number, not by the CAN ID (chapter 16.7.3.5 of the user manual), * hence we can't use more than one object because that would cause priority inversion on long transfers. */ -const unsigned NumMsgObjects = 32; +constexpr unsigned NumberOfMessageObjects = 32; +constexpr unsigned NumberOfTxMessageObjects = 1; +constexpr unsigned NumberOfRxMessageObjects = NumberOfMessageObjects - NumberOfTxMessageObjects; +constexpr unsigned TxMessageObjectNumber = 1; /** * Total number of CAN errors. @@ -363,7 +366,7 @@ uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::Monotonic if (tx_free) { tx_free = false; // Mark as pending - will be released in TX callback - msgobj.msgobj = 1; + msgobj.msgobj = TxMessageObjectNumber; LPC_CCAN_API->can_transmit(&msgobj); return 1; } @@ -438,7 +441,7 @@ uavcan::uint64_t CanDriver::getErrorCount() const uavcan::uint16_t CanDriver::getNumFilters() const { - return NumMsgObjects - 1; // First msgobj is reserved for TX frame + return NumberOfRxMessageObjects; } uavcan::ICanIface* CanDriver::getIface(uavcan::uint8_t iface_index) From 0e97d7a9ba546634b395ed8b0a9144217ac802ba Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 13:26:13 +0300 Subject: [PATCH 19/30] LPC11C24 support for TX aborts --- .../driver/include/uavcan_lpc11c24/can.hpp | 5 + .../lpc11c24/driver/src/c_can.hpp | 11 +++ libuavcan_drivers/lpc11c24/driver/src/can.cpp | 94 ++++++++++++++----- 3 files changed, 89 insertions(+), 21 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp index ae4f90194e..f17dd6c24d 100644 --- a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp @@ -53,6 +53,11 @@ public: */ bool hadActivity(); + /** + * Returns the number of times the RX queue was overrun. + */ + uavcan::uint32_t getRxQueueOverflowCount() const; + uavcan::int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) override; diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index cbeb035ea5..d33bc69e47 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -157,6 +157,17 @@ enum class StatLec : std::uint32_t Unused = 7 }; +/* + * IF.CMDMSK + */ +static constexpr std::uint32_t IF_CMDMSK_W_DATA_A = 1 << 0; +static constexpr std::uint32_t IF_CMDMSK_W_DATA_B = 1 << 1; +static constexpr std::uint32_t IF_CMDMSK_W_TXRQST = 1 << 2; +static constexpr std::uint32_t IF_CMDMSK_W_CTRL = 1 << 4; +static constexpr std::uint32_t IF_CMDMSK_W_ARB = 1 << 5; +static constexpr std::uint32_t IF_CMDMSK_W_MASK = 1 << 6; +static constexpr std::uint32_t IF_CMDMSK_W_WR_RD = 1 << 7; + /* * IF.MCTRL */ diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index e548e4c915..30daa1f985 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -44,19 +44,27 @@ constexpr unsigned TxMessageObjectNumber = 1; * Total number of CAN errors. * Does not overflow. */ -std::uint32_t error_cnt = 0; +volatile std::uint32_t error_cnt = 0; /** - * True if there's no pending TX frame, i.e. write is possible. + * False if there's no pending TX frame, i.e. write is possible. */ -bool tx_free = true; +volatile bool tx_pending = false; + +/** + * Currently pending frame must be aborted on first error. + */ +volatile bool tx_abort_on_error = false; /** * Gets updated every time the CAN IRQ handler is being called. */ -std::uint64_t last_irq_utc_timestamp = 0; +volatile std::uint64_t last_irq_utc_timestamp = 0; -bool had_activity; +/** + * Set by the driver on every successful TX or RX; reset by the application. + */ +volatile bool had_activity = false; /** * After a received message gets extracted from C_CAN, it will be stored in the RX queue until libuavcan @@ -77,7 +85,7 @@ class RxQueue std::uint8_t len_ = 0; public: - void push(const uavcan::CanFrame& frame, const std::uint64_t& utc_usec) + void push(const uavcan::CanFrame& frame, const volatile std::uint64_t& utc_usec) { buf_[in_].frame = frame; buf_[in_].utc_usec = utc_usec; @@ -263,10 +271,13 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) int CanDriver::init(uavcan::uint32_t bitrate) { + /* + * TODO FIXME Reinitialize the CAN controller after entering the BUS-OFF state + */ CriticalSectionLocker locker; error_cnt = 0; - tx_free = true; + tx_pending = false; last_irq_utc_timestamp = 0; had_activity = false; @@ -274,12 +285,15 @@ int CanDriver::init(uavcan::uint32_t bitrate) * C_CAN init */ Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); + auto bit_timings = computeBitTimings(bitrate); if (!bit_timings.isValid()) { return -1; } + LPC_CCAN_API->init_can(reinterpret_cast(&bit_timings), true); + static CCAN_CALLBACKS_T ccan_callbacks = { canRxCallback, @@ -292,7 +306,6 @@ int CanDriver::init(uavcan::uint32_t bitrate) nullptr }; LPC_CCAN_API->config_calb(&ccan_callbacks); - NVIC_EnableIRQ(CAN_IRQn); /* * Default RX msgobj config: @@ -307,6 +320,13 @@ int CanDriver::init(uavcan::uint32_t bitrate) msg_obj.msgobj = 32; LPC_CCAN_API->config_rxmsgobj(&msg_obj); + /* + * Interrupts + */ + c_can::CAN.CNTL |= c_can::CNTL_SIE; // This is necessary for transmission aborts on error + + NVIC_EnableIRQ(CAN_IRQn); + return 0; } @@ -319,7 +339,7 @@ bool CanDriver::hasReadyRx() const bool CanDriver::hasEmptyTx() const { CriticalSectionLocker locker; - return tx_free; + return !tx_pending; } bool CanDriver::hadActivity() @@ -330,12 +350,18 @@ bool CanDriver::hadActivity() return ret; } +uavcan::uint32_t CanDriver::getRxQueueOverflowCount() const +{ + CriticalSectionLocker locker; + return rx_queue.getOverflowCount(); +} + uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) { if (frame.isErrorFrame() || frame.dlc > 8 || - flags != 0) // Only plain IO is allowed. Loopback, TX timestamping are not supported by this driver. + (flags & uavcan::CanIOFlagLoopback) != 0) // TX timestamping is not supported by this driver. { return -1; } @@ -363,9 +389,10 @@ uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::Monotonic CriticalSectionLocker locker; - if (tx_free) + if (!tx_pending) { - tx_free = false; // Mark as pending - will be released in TX callback + tx_pending = true; // Mark as pending - will be released in TX callback + tx_abort_on_error = (flags & uavcan::CanIOFlagAbortOnError) != 0; msgobj.msgobj = TxMessageObjectNumber; LPC_CCAN_API->can_transmit(&msgobj); return 1; @@ -376,7 +403,7 @@ uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::Monotonic uavcan::int16_t CanDriver::receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic, uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags) { - out_ts_monotonic = uavcan_lpc11c24::clock::getMonotonic(); + out_ts_monotonic = clock::getMonotonic(); out_flags = 0; // We don't support any IO flags CriticalSectionLocker locker; @@ -464,6 +491,8 @@ extern "C" void canRxCallback(std::uint8_t msg_obj_num) { + using namespace uavcan_lpc11c24; + CCAN_MSG_OBJ_T msg_obj = CCAN_MSG_OBJ_T(); msg_obj.msgobj = msg_obj_num; LPC_CCAN_API->can_receive(&msg_obj); @@ -491,23 +520,43 @@ void canRxCallback(std::uint8_t msg_obj_num) frame.dlc = msg_obj.dlc; uavcan::copy(msg_obj.data, msg_obj.data + msg_obj.dlc, frame.data); - uavcan_lpc11c24::rx_queue.push(frame, uavcan_lpc11c24::last_irq_utc_timestamp); - uavcan_lpc11c24::had_activity = true; + rx_queue.push(frame, last_irq_utc_timestamp); + had_activity = true; } void canTxCallback(std::uint8_t msg_obj_num) { + using namespace uavcan_lpc11c24; + (void)msg_obj_num; - uavcan_lpc11c24::tx_free = true; - uavcan_lpc11c24::had_activity = true; + + tx_pending = false; + had_activity = true; } void canErrorCallback(std::uint32_t error_info) { - (void)error_info; - if (uavcan_lpc11c24::error_cnt < 0xFFFFFFFF) + /* + * TODO FIXME Reinitialize the CAN controller after entering the BUS-OFF state + */ + using namespace uavcan_lpc11c24; + + // Updating the error counter + if ((error_info != 0) && (error_cnt < 0xFFFFFFFFUL)) { - uavcan_lpc11c24::error_cnt++; + error_cnt++; + } + + // Serving abort requests + if (tx_pending && tx_abort_on_error) + { + tx_pending = false; + tx_abort_on_error = false; + + // Using the first interface, because this approach seems to be compliant with the BASIC mode (just in case) + c_can::CAN.IF[0].CMDREQ = TxMessageObjectNumber; + c_can::CAN.IF[0].CMDMSK.W = c_can::IF_CMDMSK_W_WR_RD; // Clearing IF_CMDMSK_W_TXRQST + c_can::CAN.IF[0].MCTRL &= ~c_can::IF_MCTRL_TXRQST; // Clearing IF_MCTRL_TXRQST } } @@ -515,7 +564,10 @@ void CAN_IRQHandler(); void CAN_IRQHandler() { - uavcan_lpc11c24::last_irq_utc_timestamp = uavcan_lpc11c24::clock::getUtcUSecFromCanInterrupt(); + using namespace uavcan_lpc11c24; + + last_irq_utc_timestamp = clock::getUtcUSecFromCanInterrupt(); + LPC_CCAN_API->isr(); } From 8a88ea35ccfaf86dade624c9c12ca49a7a5d9776 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 23:06:55 +0300 Subject: [PATCH 20/30] LPC11C24 automatic bus-off recovery --- .../driver/include/uavcan_lpc11c24/can.hpp | 7 +++++ libuavcan_drivers/lpc11c24/driver/src/can.cpp | 27 +++++++++++++------ 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp index f17dd6c24d..35de4619be 100644 --- a/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/include/uavcan_lpc11c24/can.hpp @@ -58,6 +58,13 @@ public: */ uavcan::uint32_t getRxQueueOverflowCount() const; + /** + * Whether the controller is currently in bus off state. + * Note that the driver recovers the CAN controller from the bus off state automatically! + * Therefore, this method serves only monitoring purposes and is not necessary to use. + */ + bool isInBusOffState() const; + uavcan::int16_t send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) override; diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index 30daa1f985..f77b4ee89e 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -271,9 +271,6 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) int CanDriver::init(uavcan::uint32_t bitrate) { - /* - * TODO FIXME Reinitialize the CAN controller after entering the BUS-OFF state - */ CriticalSectionLocker locker; error_cnt = 0; @@ -356,6 +353,11 @@ uavcan::uint32_t CanDriver::getRxQueueOverflowCount() const return rx_queue.getOverflowCount(); } +bool CanDriver::isInBusOffState() const +{ + return (c_can::CAN.STAT & c_can::STAT_BOFF) != 0; +} + uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline, uavcan::CanIOFlags flags) { @@ -421,6 +423,16 @@ uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks, const uavcan::CanFrame* (&)[uavcan::MaxCanIfaces], uavcan::MonotonicTime blocking_deadline) { + const bool bus_off = isInBusOffState(); + if (bus_off) // Recover automatically on bus-off + { + CriticalSectionLocker locker; + if ((c_can::CAN.CNTL & c_can::CNTL_INIT) != 0) + { + c_can::CAN.CNTL &= ~c_can::CNTL_INIT; + } + } + const bool noblock = ((inout_masks.read == 1) && hasReadyRx()) || ((inout_masks.write == 1) && hasEmptyTx()); @@ -448,8 +460,10 @@ uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks, } inout_masks.read = hasReadyRx() ? 1 : 0; - inout_masks.write = hasEmptyTx() ? 1 : 0; - return 0; // Return value doesn't matter as long as it is non-negative + + inout_masks.write = (hasEmptyTx() && !bus_off) ? 1 : 0; // Disable write while in bus-off + + return 0; // Return value doesn't matter as long as it is non-negative } uavcan::int16_t CanDriver::configureFilters(const uavcan::CanFilterConfig* filter_configs, @@ -536,9 +550,6 @@ void canTxCallback(std::uint8_t msg_obj_num) void canErrorCallback(std::uint32_t error_info) { - /* - * TODO FIXME Reinitialize the CAN controller after entering the BUS-OFF state - */ using namespace uavcan_lpc11c24; // Updating the error counter From 367389f728560364372fe9b3e64dbb5c310632bb Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 23:07:17 +0300 Subject: [PATCH 21/30] LPC11C24 temporary test app --- .../test_olimex_lpc_p11c24/src/main.cpp | 34 ++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index a80f832a79..44ba9f9f12 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -159,14 +159,46 @@ int main() while (true) { - const int res = getNode().spin(uavcan::MonotonicDuration::fromMSec(25)); + //const int res = getNode().spin(uavcan::MonotonicDuration::fromMSec(25)); + const int res = getNode().spinOnce(); board::setErrorLed(res < 0); board::setStatusLed(uavcan_lpc11c24::CanDriver::instance().hadActivity()); + if (uavcan_lpc11c24::CanDriver::instance().hasEmptyTx()) + { + // Abort test + static unsigned value = 0; + const std::uint8_t payload[] = { + 0, + 0, + 0, + 0, + std::uint8_t(value >> 24), + std::uint8_t(value >> 16), + std::uint8_t(value >> 8), + std::uint8_t(value >> 0), + }; + value++; + (void)uavcan_lpc11c24::CanDriver::instance().send(uavcan::CanFrame(123U | uavcan::CanFrame::FlagEFF, + payload, sizeof(payload)), + uavcan::MonotonicTime::getMax(), + uavcan::CanIOFlagAbortOnError); + } + const auto ts = uavcan_lpc11c24::clock::getMonotonic(); if ((ts - prev_log_at).toMSec() >= 1000) { prev_log_at = ts; + // CAN bus off state monitoring + board::syslog("CAN bus off: "); + board::syslog(intToString(int(uavcan_lpc11c24::CanDriver::instance().isInBusOffState())).c_str()); + board::syslog("\r\n"); + // CAN error counter, for debugging purposes + board::syslog("CAN errors: "); + board::syslog(intToString(static_cast(uavcan_lpc11c24::CanDriver::instance().getErrorCount())).c_str()); + board::syslog(" "); + board::syslog(intToString(uavcan_lpc11c24::CanDriver::instance().getRxQueueOverflowCount()).c_str()); + board::syslog("\r\n"); // We don't want to use formatting functions provided by libuavcan because they rely on std::snprintf() // hence we need to construct the message manually: uavcan::protocol::debug::LogMessage logmsg; From 6f782b2be2e85d64c1b171bb0c611dd8b1e0d54a Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Mon, 12 Oct 2015 23:09:57 +0300 Subject: [PATCH 22/30] LPC11C24 abort debug code removed --- .../test_olimex_lpc_p11c24/src/main.cpp | 31 +++---------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index 44ba9f9f12..dbc0c1b694 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -159,40 +159,19 @@ int main() while (true) { - //const int res = getNode().spin(uavcan::MonotonicDuration::fromMSec(25)); - const int res = getNode().spinOnce(); + const int res = getNode().spin(uavcan::MonotonicDuration::fromMSec(25)); board::setErrorLed(res < 0); board::setStatusLed(uavcan_lpc11c24::CanDriver::instance().hadActivity()); - if (uavcan_lpc11c24::CanDriver::instance().hasEmptyTx()) - { - // Abort test - static unsigned value = 0; - const std::uint8_t payload[] = { - 0, - 0, - 0, - 0, - std::uint8_t(value >> 24), - std::uint8_t(value >> 16), - std::uint8_t(value >> 8), - std::uint8_t(value >> 0), - }; - value++; - (void)uavcan_lpc11c24::CanDriver::instance().send(uavcan::CanFrame(123U | uavcan::CanFrame::FlagEFF, - payload, sizeof(payload)), - uavcan::MonotonicTime::getMax(), - uavcan::CanIOFlagAbortOnError); - } - const auto ts = uavcan_lpc11c24::clock::getMonotonic(); if ((ts - prev_log_at).toMSec() >= 1000) { prev_log_at = ts; // CAN bus off state monitoring - board::syslog("CAN bus off: "); - board::syslog(intToString(int(uavcan_lpc11c24::CanDriver::instance().isInBusOffState())).c_str()); - board::syslog("\r\n"); + if (uavcan_lpc11c24::CanDriver::instance().isInBusOffState()) + { + board::syslog("CAN BUS OFF\r\n"); + } // CAN error counter, for debugging purposes board::syslog("CAN errors: "); board::syslog(intToString(static_cast(uavcan_lpc11c24::CanDriver::instance().getErrorCount())).c_str()); From d9ca67c84c9451b02befc078568cd3cedaa7de8e Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 12:49:41 +0300 Subject: [PATCH 23/30] LPC11C24 - break on die() --- .../lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index 63d4f8ac54..d5495edbaf 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -134,7 +134,14 @@ void init() void die() { - while (true) { } + static const volatile unsigned& DHCSR = *reinterpret_cast(0xE000EDF0U); + while (true) + { + if ((DHCSR & 1U) != 0) + { + __asm volatile ("bkpt #0\n"); // Break into the debugger + } + } } #if __GNUC__ From 98189950e40a0b87bf21323f1bcb025b3ceaa976 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 14:12:53 +0300 Subject: [PATCH 24/30] LPC11C24 C_CAN IF_CMDREQ_BUSY --- libuavcan_drivers/lpc11c24/driver/src/c_can.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp index d33bc69e47..4882e65f41 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/c_can.hpp @@ -157,6 +157,11 @@ enum class StatLec : std::uint32_t Unused = 7 }; +/* + * IF.CMDREQ + */ +static constexpr std::uint32_t IF_CMDREQ_BUSY = 1 << 15; + /* * IF.CMDMSK */ From 873e38679335023b6826e59edea484986292f7eb Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 14:26:13 +0300 Subject: [PATCH 25/30] LPC11C24 minor cleanup in sys/board* --- .../lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp | 4 +++- .../lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index d5495edbaf..22bb15d010 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -22,6 +22,8 @@ namespace board namespace { +constexpr unsigned TargetSystemCoreClock = 48000000; + constexpr unsigned ErrorLedPort = 1; constexpr unsigned ErrorLedPin = 10; @@ -93,7 +95,7 @@ void initClock() SystemCoreClock = Chip_Clock_GetSystemClockRate(); - while (SystemCoreClock != 48000000) { } // Loop forever if the clock failed to initialize properly + while (SystemCoreClock != TargetSystemCoreClock) { } // Loop forever if the clock failed to initialize properly } void initGpio() diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp index cdb84fe331..21a64c4424 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.hpp @@ -14,6 +14,9 @@ void die(); static constexpr unsigned UniqueIDSize = 16; +/** + * Reads the globally unique 128-bit hardware ID from the MCU. + */ void readUniqueID(std::uint8_t out_uid[UniqueIDSize]); void setStatusLed(bool state); @@ -21,6 +24,9 @@ void setErrorLed(bool state); void resetWatchdog(); +/** + * Sends the string to UART. + */ void syslog(const char* msg); } From df056a7948bc15ca045713b76c245acf6cf0b18a Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 15:29:15 +0300 Subject: [PATCH 26/30] LPC11C24 acceptance filters --- libuavcan_drivers/lpc11c24/driver/src/can.cpp | 160 ++++++++++++------ .../test_olimex_lpc_p11c24/src/main.cpp | 52 +++++- 2 files changed, 158 insertions(+), 54 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/driver/src/can.cpp b/libuavcan_drivers/lpc11c24/driver/src/can.cpp index f77b4ee89e..405588eb76 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/can.cpp +++ b/libuavcan_drivers/lpc11c24/driver/src/can.cpp @@ -271,59 +271,57 @@ uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)()) int CanDriver::init(uavcan::uint32_t bitrate) { - CriticalSectionLocker locker; + { + auto bit_timings = computeBitTimings(bitrate); + if (!bit_timings.isValid()) + { + return -1; + } - error_cnt = 0; - tx_pending = false; - last_irq_utc_timestamp = 0; - had_activity = false; + CriticalSectionLocker locker; + + error_cnt = 0; + tx_abort_on_error = false; + tx_pending = false; + last_irq_utc_timestamp = 0; + had_activity = false; + + /* + * C_CAN init + */ + Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); + + LPC_CCAN_API->init_can(reinterpret_cast(&bit_timings), true); + + static CCAN_CALLBACKS_T ccan_callbacks = + { + canRxCallback, + canTxCallback, + canErrorCallback, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr + }; + LPC_CCAN_API->config_calb(&ccan_callbacks); + + /* + * Interrupts + */ + c_can::CAN.CNTL |= c_can::CNTL_SIE; // This is necessary for transmission aborts on error + + NVIC_EnableIRQ(CAN_IRQn); + } /* - * C_CAN init + * Applying default filter configuration (accept all) */ - Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN); - - auto bit_timings = computeBitTimings(bitrate); - if (!bit_timings.isValid()) + if (configureFilters(nullptr, 0) < 0) { return -1; } - LPC_CCAN_API->init_can(reinterpret_cast(&bit_timings), true); - - static CCAN_CALLBACKS_T ccan_callbacks = - { - canRxCallback, - canTxCallback, - canErrorCallback, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr - }; - LPC_CCAN_API->config_calb(&ccan_callbacks); - - /* - * Default RX msgobj config: - * 31 - all STD - * 32 - all EXT - * RTR ignored - */ - CCAN_MSG_OBJ_T msg_obj = CCAN_MSG_OBJ_T(); - msg_obj.msgobj = 31; - LPC_CCAN_API->config_rxmsgobj(&msg_obj); - msg_obj.mode_id = CAN_MSGOBJ_EXT; - msg_obj.msgobj = 32; - LPC_CCAN_API->config_rxmsgobj(&msg_obj); - - /* - * Interrupts - */ - c_can::CAN.CNTL |= c_can::CNTL_SIE; // This is necessary for transmission aborts on error - - NVIC_EnableIRQ(CAN_IRQn); - return 0; } @@ -469,9 +467,73 @@ uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks, uavcan::int16_t CanDriver::configureFilters(const uavcan::CanFilterConfig* filter_configs, uavcan::uint16_t num_configs) { - (void)filter_configs; - (void)num_configs; - return -1; + CriticalSectionLocker locker; + + /* + * If C_CAN is active (INIT=0) and the CAN bus has intensive traffic, RX object configuration may fail. + * The solution is to disable the controller while configuration is in progress. + * The documentation, as always, doesn't bother to mention this detail. Shame on you, NXP. + */ + struct RAIIDisabler + { + RAIIDisabler() + { + c_can::CAN.CNTL |= c_can::CNTL_INIT; + } + ~RAIIDisabler() + { + c_can::CAN.CNTL &= ~c_can::CNTL_INIT; + } + } can_disabler; // Must be instantiated AFTER the critical section locker + + if (num_configs == 0) + { + auto msg_obj = CCAN_MSG_OBJ_T(); + msg_obj.msgobj = NumberOfTxMessageObjects + 1; + LPC_CCAN_API->config_rxmsgobj(&msg_obj); // all STD frames + + msg_obj.mode_id = CAN_MSGOBJ_EXT; + msg_obj.msgobj = NumberOfTxMessageObjects + 2; + LPC_CCAN_API->config_rxmsgobj(&msg_obj); // all EXT frames + } + else if (num_configs <= NumberOfRxMessageObjects) + { + // Making sure the configs use only EXT frames; otherwise we can't accept them + for (unsigned i = 0; i < num_configs; i++) + { + auto& f = filter_configs[i]; + if ((f.id & f.mask & uavcan::CanFrame::FlagEFF) == 0) + { + return -1; + } + } + + // Installing the configuration + for (unsigned i = 0; i < NumberOfRxMessageObjects; i++) + { + auto msg_obj = CCAN_MSG_OBJ_T(); + msg_obj.msgobj = std::uint8_t(i + 1U + NumberOfTxMessageObjects); // Message objects are numbered from 1 + + if (i < num_configs) + { + msg_obj.mode_id = (filter_configs[i].id & uavcan::CanFrame::MaskExtID) | CAN_MSGOBJ_EXT; // Only EXT + msg_obj.mask = filter_configs[i].mask & uavcan::CanFrame::MaskExtID; + } + else + { + msg_obj.mode_id = CAN_MSGOBJ_RTR; // Using this configuration to disable the object + msg_obj.mask = uavcan::CanFrame::MaskStdID; + } + + LPC_CCAN_API->config_rxmsgobj(&msg_obj); + } + } + else + { + return -1; + } + + return 0; } uavcan::uint64_t CanDriver::getErrorCount() const @@ -507,7 +569,7 @@ void canRxCallback(std::uint8_t msg_obj_num) { using namespace uavcan_lpc11c24; - CCAN_MSG_OBJ_T msg_obj = CCAN_MSG_OBJ_T(); + auto msg_obj = CCAN_MSG_OBJ_T(); msg_obj.msgobj = msg_obj_num; LPC_CCAN_API->can_receive(&msg_obj); diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index dbc0c1b694..a935b600ca 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -65,7 +65,7 @@ uavcan::Logger& getLogger() } #if __GNUC__ -__attribute__((noinline)) +__attribute__((noinline, optimize(2))) // Higher optimization breaks the code. #endif void init() { @@ -97,6 +97,7 @@ void init() { board::die(); } + board::syslog("CAN init ok\r\n"); board::resetWatchdog(); @@ -126,6 +127,38 @@ void init() */ getNode().setNodeID(72); // TODO + /* + * Example filter configuration. + * Can be removed safely. + */ + { + constexpr unsigned NumFilters = 3; + uavcan::CanFilterConfig filters[NumFilters]; + + // Acepting all service transfers addressed to us + filters[0].id = (unsigned(getNode().getNodeID().get()) << 8) | (1U << 7) | uavcan::CanFrame::FlagEFF; + filters[0].mask = 0x7F80 | uavcan::CanFrame::FlagEFF; + + // Accepting time sync messages + filters[1].id = (4U << 8) | uavcan::CanFrame::FlagEFF; + filters[1].mask = 0xFFFF80 | uavcan::CanFrame::FlagEFF; + + // Accepting zero CAN ID (just for the sake of testing) + filters[2].id = 0 | uavcan::CanFrame::FlagEFF; + filters[2].mask = uavcan::CanFrame::MaskExtID | uavcan::CanFrame::FlagEFF; + + const auto before = uavcan_lpc11c24::clock::getMonotonic(); + if (uavcan_lpc11c24::CanDriver::instance().configureFilters(filters, NumFilters) < 0) + { + board::syslog("Filter init failed\r\n"); + board::die(); + } + const auto duration = uavcan_lpc11c24::clock::getMonotonic() - before; + board::syslog("CAN filter configuration took "); + board::syslog(intToString(duration.toUSec()).c_str()); + board::syslog(" usec\r\n"); + } + /* * Starting the node */ @@ -167,19 +200,28 @@ int main() if ((ts - prev_log_at).toMSec() >= 1000) { prev_log_at = ts; - // CAN bus off state monitoring + + /* + * CAN bus off state monitoring + */ if (uavcan_lpc11c24::CanDriver::instance().isInBusOffState()) { board::syslog("CAN BUS OFF\r\n"); } - // CAN error counter, for debugging purposes + + /* + * CAN error counter, for debugging purposes + */ board::syslog("CAN errors: "); board::syslog(intToString(static_cast(uavcan_lpc11c24::CanDriver::instance().getErrorCount())).c_str()); board::syslog(" "); board::syslog(intToString(uavcan_lpc11c24::CanDriver::instance().getRxQueueOverflowCount()).c_str()); board::syslog("\r\n"); - // We don't want to use formatting functions provided by libuavcan because they rely on std::snprintf() - // hence we need to construct the message manually: + + /* + * We don't want to use formatting functions provided by libuavcan because they rely on std::snprintf(), + * so we need to construct the message manually: + */ uavcan::protocol::debug::LogMessage logmsg; logmsg.level.value = uavcan::protocol::debug::LogLevel::INFO; logmsg.source = "app"; From b94246237dc1eff9f84d26fd610612c3de188b40 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 15:39:21 +0300 Subject: [PATCH 27/30] LPC11C24 enforcing GCC 4.9 or newer --- libuavcan_drivers/lpc11c24/driver/src/internal.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libuavcan_drivers/lpc11c24/driver/src/internal.hpp b/libuavcan_drivers/lpc11c24/driver/src/internal.hpp index 92577ad7ee..80be9f1032 100644 --- a/libuavcan_drivers/lpc11c24/driver/src/internal.hpp +++ b/libuavcan_drivers/lpc11c24/driver/src/internal.hpp @@ -7,6 +7,16 @@ #include #include +/* + * Compiler version check + */ +#ifdef __GNUC__ +# if (__GNUC__ * 10 + __GNUC_MINOR__) < 49 +# error "Use GCC 4.9 or newer" +# endif +#endif + + namespace uavcan_lpc11c24 { From d7bd5fc28be0110b6154d0c580f9fff04a662a8d Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 17:01:07 +0300 Subject: [PATCH 28/30] LPC11C24 printing a scary message when the app fails --- .../lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp index 22bb15d010..26703c47ac 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/sys/board.cpp @@ -137,6 +137,9 @@ void init() void die() { static const volatile unsigned& DHCSR = *reinterpret_cast(0xE000EDF0U); + + syslog("FATAL\r\n"); + while (true) { if ((DHCSR & 1U) != 0) From eb104b45bd1f4b71c5e07310f346b4ec957c3998 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 17:08:24 +0300 Subject: [PATCH 29/30] LPC11C24 demo with dynamic node ID allocaiton --- .../test_olimex_lpc_p11c24/src/main.cpp | 66 +++++++++++++++---- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index a935b600ca..45c63f3f58 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -3,13 +3,26 @@ */ #include +#include #include #include #include #include #include +#include #include +/** + * This function re-defines the standard ::rand(), which is used by the class uavcan::DynamicNodeIDClient. + * Redefinition is normally not needed, but GCC 4.9 tends to generate broken binaries if it is not redefined. + */ +int rand() +{ + static int x = 1; + x = x * 48271 % 2147483647; + return x; +} + namespace { @@ -64,6 +77,25 @@ uavcan::Logger& getLogger() return logger; } +uavcan::NodeID performDynamicNodeIDAllocation() +{ + uavcan::DynamicNodeIDClient client(getNode()); + + const int client_start_res = client.start(getNode().getHardwareVersion().unique_id); + if (client_start_res < 0) + { + board::die(); + } + + while (!client.isAllocationComplete()) + { + board::resetWatchdog(); + (void)getNode().spin(uavcan::MonotonicDuration::fromMSec(100)); + } + + return client.getAllocatedNodeID(); +} + #if __GNUC__ __attribute__((noinline, optimize(2))) // Higher optimization breaks the code. #endif @@ -86,10 +118,10 @@ void init() std::uint32_t bit_rate = 0; while (bit_rate == 0) { - board::syslog("CAN bitrate detection...\r\n"); + board::syslog("CAN auto bitrate...\r\n"); bit_rate = uavcan_lpc11c24::CanDriver::detectBitRate(&board::resetWatchdog); } - board::syslog("CAN bitrate: "); + board::syslog("Bitrate: "); board::syslog(intToString(bit_rate).c_str()); board::syslog("\r\n"); @@ -123,9 +155,22 @@ void init() board::resetWatchdog(); /* - * Performing dynamic node ID allocation + * Starting the node and performing dynamic node ID allocation */ - getNode().setNodeID(72); // TODO + if (getNode().start() < 0) + { + board::die(); + } + + board::syslog("Node ID allocation...\r\n"); + + getNode().setNodeID(performDynamicNodeIDAllocation()); + + board::syslog("Node ID "); + board::syslog(intToString(getNode().getNodeID().get()).c_str()); + board::syslog("\r\n"); + + board::resetWatchdog(); /* * Example filter configuration. @@ -160,21 +205,18 @@ void init() } /* - * Starting the node + * Initializing other libuavcan-related objects */ - while (getNode().start() < 0) + if (getTimeSyncSlave().start() < 0) { + board::die(); } - board::resetWatchdog(); - - while (getTimeSyncSlave().start() < 0) + if (getLogger().init() < 0) { + board::die(); } - while (getLogger().init() < 0) - { - } getLogger().setLevel(uavcan::protocol::debug::LogLevel::DEBUG); board::resetWatchdog(); From e06096226183a100bf2cc6625ebb5e310c0bf2d3 Mon Sep 17 00:00:00 2001 From: Pavel Kirienko Date: Tue, 13 Oct 2015 17:15:14 +0300 Subject: [PATCH 30/30] LPC11C24 demo optimization --- .../test_olimex_lpc_p11c24/src/main.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp index 45c63f3f58..9f81263c06 100644 --- a/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp +++ b/libuavcan_drivers/lpc11c24/test_olimex_lpc_p11c24/src/main.cpp @@ -12,6 +12,15 @@ #include #include +/* + * GCC 4.9 cannot generate a working binary with higher optimization levels, although + * rest of the firmware can be compiled with -Os. + * GCC 4.8 and earlier don't work at all on this firmware. + */ +#if __GNUC__ +# pragma GCC optimize 1 +#endif + /** * This function re-defines the standard ::rand(), which is used by the class uavcan::DynamicNodeIDClient. * Redefinition is normally not needed, but GCC 4.9 tends to generate broken binaries if it is not redefined. @@ -96,9 +105,6 @@ uavcan::NodeID performDynamicNodeIDAllocation() return client.getAllocatedNodeID(); } -#if __GNUC__ -__attribute__((noinline, optimize(2))) // Higher optimization breaks the code. -#endif void init() { board::resetWatchdog(); @@ -192,16 +198,11 @@ void init() filters[2].id = 0 | uavcan::CanFrame::FlagEFF; filters[2].mask = uavcan::CanFrame::MaskExtID | uavcan::CanFrame::FlagEFF; - const auto before = uavcan_lpc11c24::clock::getMonotonic(); if (uavcan_lpc11c24::CanDriver::instance().configureFilters(filters, NumFilters) < 0) { board::syslog("Filter init failed\r\n"); board::die(); } - const auto duration = uavcan_lpc11c24::clock::getMonotonic() - before; - board::syslog("CAN filter configuration took "); - board::syslog(intToString(duration.toUSec()).c_str()); - board::syslog(" usec\r\n"); } /*