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;