libuav original

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers can.cpp Source File

can.cpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #include <uavcan_lpc11c24/can.hpp>
00006 #include <uavcan_lpc11c24/clock.hpp>
00007 #include <uavcan/util/templates.hpp>
00008 #include <chip.h>
00009 #include "c_can.hpp"
00010 #include "internal.hpp"
00011 
00012 /**
00013  * The default value should be OK for any use case.
00014  */
00015 #ifndef UAVCAN_LPC11C24_RX_QUEUE_LEN
00016 # define UAVCAN_LPC11C24_RX_QUEUE_LEN   8
00017 #endif
00018 
00019 #if UAVCAN_LPC11C24_RX_QUEUE_LEN > 254
00020 # error UAVCAN_LPC11C24_RX_QUEUE_LEN is too large
00021 #endif
00022 
00023 extern "C" void canRxCallback(std::uint8_t msg_obj_num);
00024 extern "C" void canTxCallback(std::uint8_t msg_obj_num);
00025 extern "C" void canErrorCallback(std::uint32_t error_info);
00026 
00027 namespace uavcan_lpc11c24
00028 {
00029 namespace
00030 {
00031 /**
00032  * Hardware message objects are allocated as follows:
00033  *  - 1 - Single TX object
00034  *  - 2..32 - RX objects
00035  * TX priority is defined by the message object number, not by the CAN ID (chapter 16.7.3.5 of the user manual),
00036  * hence we can't use more than one object because that would cause priority inversion on long transfers.
00037  */
00038 constexpr unsigned NumberOfMessageObjects   = 32;
00039 constexpr unsigned NumberOfTxMessageObjects = 1;
00040 constexpr unsigned NumberOfRxMessageObjects = NumberOfMessageObjects - NumberOfTxMessageObjects;
00041 constexpr unsigned TxMessageObjectNumber    = 1;
00042 
00043 /**
00044  * Total number of CAN errors.
00045  * Does not overflow.
00046  */
00047 volatile std::uint32_t error_cnt = 0;
00048 
00049 /**
00050  * False if there's no pending TX frame, i.e. write is possible.
00051  */
00052 volatile bool tx_pending = false;
00053 
00054 /**
00055  * Currently pending frame must be aborted on first error.
00056  */
00057 volatile bool tx_abort_on_error = false;
00058 
00059 /**
00060  * Gets updated every time the CAN IRQ handler is being called.
00061  */
00062 volatile std::uint64_t last_irq_utc_timestamp = 0;
00063 
00064 /**
00065  * Set by the driver on every successful TX or RX; reset by the application.
00066  */
00067 volatile bool had_activity = false;
00068 
00069 /**
00070  * After a received message gets extracted from C_CAN, it will be stored in the RX queue until libuavcan
00071  * reads it via select()/receive() calls.
00072  */
00073 class RxQueue
00074 {
00075     struct Item
00076     {
00077         std::uint64_t utc_usec = 0;
00078         uavcan::CanFrame frame;
00079     };
00080 
00081     Item buf_[UAVCAN_LPC11C24_RX_QUEUE_LEN];
00082     std::uint32_t overflow_cnt_ = 0;
00083     std::uint8_t in_ = 0;
00084     std::uint8_t out_ = 0;
00085     std::uint8_t len_ = 0;
00086 
00087 public:
00088     void push(const uavcan::CanFrame& frame, const volatile std::uint64_t& utc_usec)
00089     {
00090         buf_[in_].frame    = frame;
00091         buf_[in_].utc_usec = utc_usec;
00092         in_++;
00093         if (in_ >= UAVCAN_LPC11C24_RX_QUEUE_LEN)
00094         {
00095             in_ = 0;
00096         }
00097         len_++;
00098         if (len_ > UAVCAN_LPC11C24_RX_QUEUE_LEN)
00099         {
00100             len_ = UAVCAN_LPC11C24_RX_QUEUE_LEN;
00101             if (overflow_cnt_ < 0xFFFFFFFF)
00102             {
00103                 overflow_cnt_++;
00104             }
00105             out_++;
00106             if (out_ >= UAVCAN_LPC11C24_RX_QUEUE_LEN)
00107             {
00108                 out_ = 0;
00109             }
00110         }
00111     }
00112 
00113     void pop(uavcan::CanFrame& out_frame, std::uint64_t& out_utc_usec)
00114     {
00115         if (len_ > 0)
00116         {
00117             out_frame    = buf_[out_].frame;
00118             out_utc_usec = buf_[out_].utc_usec;
00119             out_++;
00120             if (out_ >= UAVCAN_LPC11C24_RX_QUEUE_LEN)
00121             {
00122                 out_ = 0;
00123             }
00124             len_--;
00125         }
00126     }
00127 
00128     unsigned getLength() const { return len_; }
00129 
00130     std::uint32_t getOverflowCount() const { return overflow_cnt_; }
00131 };
00132 
00133 RxQueue rx_queue;
00134 
00135 
00136 struct BitTimingSettings
00137 {
00138     std::uint32_t canclkdiv;
00139     std::uint32_t canbtr;
00140 
00141     bool isValid() const { return canbtr != 0; }
00142 };
00143 
00144 /**
00145  * http://www.bittiming.can-wiki.info
00146  */
00147 BitTimingSettings computeBitTimings(std::uint32_t bitrate)
00148 {
00149     if (Chip_Clock_GetSystemClockRate() == 48000000) // 48 MHz is optimal for CAN timings
00150     {
00151         switch (bitrate)
00152         {
00153         case 1000000: return BitTimingSettings{ 0, 0x0505 }; // 8  quanta, 87.5%
00154         case 500000:  return BitTimingSettings{ 0, 0x1c05 }; // 16 quanta, 87.5%
00155         case 250000:  return BitTimingSettings{ 0, 0x1c0b }; // 16 quanta, 87.5%
00156         case 125000:  return BitTimingSettings{ 0, 0x1c17 }; // 16 quanta, 87.5%
00157         case 100000:  return BitTimingSettings{ 0, 0x1c1d }; // 16 quanta, 87.5%
00158         default:      return BitTimingSettings{ 0, 0 };
00159         }
00160     }
00161     else
00162     {
00163         return BitTimingSettings{ 0, 0 };
00164     }
00165 }
00166 
00167 } // namespace
00168 
00169 CanDriver CanDriver::self;
00170 
00171 uavcan::uint32_t CanDriver::detectBitRate(void (*idle_callback)())
00172 {
00173     static constexpr uavcan::uint32_t BitRatesToTry[] =
00174     {
00175         1000000,
00176         500000,
00177         250000,
00178         125000,
00179         100000
00180     };
00181 
00182     const auto ListeningDuration = uavcan::MonotonicDuration::fromMSec(1050);
00183 
00184     NVIC_DisableIRQ(CAN_IRQn );
00185     Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN );
00186 
00187     for (auto bitrate : BitRatesToTry)
00188     {
00189         // Computing bit timings
00190         const auto bit_timings = computeBitTimings(bitrate);
00191         if (!bit_timings.isValid())
00192         {
00193             return 0;
00194         }
00195 
00196         // Configuring the CAN controller
00197         {
00198             CriticalSectionLocker locker;
00199 
00200             LPC_SYSCTL->PRESETCTRL |= (1U << RESET_CAN0 );
00201 
00202             // Entering initialization mode
00203             c_can::CAN.CNTL = c_can::CNTL_INIT | c_can::CNTL_CCE;
00204 
00205             while ((c_can::CAN.CNTL & c_can::CNTL_INIT) == 0)
00206             {
00207                 ; // Nothing to do
00208             }
00209 
00210             // Configuring bit rate
00211             c_can::CAN.CLKDIV = bit_timings.canclkdiv;
00212             c_can::CAN.BT     = bit_timings.canbtr;
00213             c_can::CAN.BRPE   = 0;
00214 
00215             // Configuring silent mode
00216             c_can::CAN.CNTL |= c_can::CNTL_TEST;
00217             c_can::CAN.TEST = c_can::TEST_SILENT;
00218 
00219             // Configuring status monitor
00220             c_can::CAN.STAT = (unsigned(c_can::StatLec::Unused) << c_can::STAT_LEC_SHIFT);
00221 
00222             // Leaving initialization mode
00223             c_can::CAN.CNTL &= ~(c_can::CNTL_INIT | c_can::CNTL_CCE);
00224 
00225             while ((c_can::CAN.CNTL & c_can::CNTL_INIT) != 0)
00226             {
00227                 ; // Nothing to do
00228             }
00229         }
00230 
00231         // Listening
00232         const auto deadline = clock::getMonotonic() + ListeningDuration;
00233         bool match_detected = false;
00234         while (clock::getMonotonic() < deadline)
00235         {
00236             if (idle_callback != nullptr)
00237             {
00238                 idle_callback();
00239             }
00240 
00241             const auto LastErrorCode = (c_can::CAN.STAT >> c_can::STAT_LEC_SHIFT) & c_can::STAT_LEC_MASK;
00242 
00243             if (LastErrorCode == unsigned(c_can::StatLec::NoError))
00244             {
00245                 match_detected = true;
00246                 break;
00247             }
00248         }
00249 
00250         // De-configuring the CAN controller back to reset state
00251         {
00252             CriticalSectionLocker locker;
00253 
00254             c_can::CAN.CNTL = c_can::CNTL_INIT;
00255 
00256             while ((c_can::CAN.CNTL & c_can::CNTL_INIT) == 0)
00257             {
00258                 ; // Nothing to do
00259             }
00260 
00261             LPC_SYSCTL->PRESETCTRL &= ~(1U << RESET_CAN0 );
00262         }
00263 
00264         // Termination condition
00265         if (match_detected)
00266         {
00267             return bitrate;
00268         }
00269     }
00270 
00271     return 0;   // No match
00272 }
00273 
00274 int CanDriver::init(uavcan::uint32_t bitrate)
00275 {
00276     {
00277         auto bit_timings = computeBitTimings(bitrate);
00278         if (!bit_timings.isValid())
00279         {
00280             return -1;
00281         }
00282 
00283         CriticalSectionLocker locker;
00284 
00285         error_cnt = 0;
00286         tx_abort_on_error = false;
00287         tx_pending = false;
00288         last_irq_utc_timestamp = 0;
00289         had_activity = false;
00290 
00291         /*
00292          * C_CAN init
00293          */
00294         Chip_Clock_EnablePeriphClock(SYSCTL_CLOCK_CAN );
00295 
00296         LPC_CCAN_API->init_can(reinterpret_cast<std::uint32_t*>(&bit_timings), true);
00297 
00298         static CCAN_CALLBACKS_T ccan_callbacks =
00299         {
00300             canRxCallback,
00301             canTxCallback,
00302             canErrorCallback,
00303             nullptr,
00304             nullptr,
00305             nullptr,
00306             nullptr,
00307             nullptr
00308         };
00309         LPC_CCAN_API->config_calb(&ccan_callbacks);
00310 
00311         /*
00312          * Interrupts
00313          */
00314         c_can::CAN.CNTL |= c_can::CNTL_SIE;         // This is necessary for transmission aborts on error
00315 
00316         NVIC_EnableIRQ(CAN_IRQn );
00317     }
00318 
00319     /*
00320      * Applying default filter configuration (accept all)
00321      */
00322     if (configureFilters(nullptr, 0) < 0)
00323     {
00324         return -1;
00325     }
00326 
00327     return 0;
00328 }
00329 
00330 bool CanDriver::hasReadyRx() const
00331 {
00332     CriticalSectionLocker locker;
00333     return rx_queue.getLength() > 0;
00334 }
00335 
00336 bool CanDriver::hasEmptyTx() const
00337 {
00338     CriticalSectionLocker locker;
00339     return !tx_pending;
00340 }
00341 
00342 bool CanDriver::hadActivity()
00343 {
00344     CriticalSectionLocker locker;
00345     const bool ret = had_activity;
00346     had_activity = false;
00347     return ret;
00348 }
00349 
00350 uavcan::uint32_t CanDriver::getRxQueueOverflowCount() const
00351 {
00352     CriticalSectionLocker locker;
00353     return rx_queue.getOverflowCount();
00354 }
00355 
00356 bool CanDriver::isInBusOffState() const
00357 {
00358     return (c_can::CAN.STAT & c_can::STAT_BOFF) != 0;
00359 }
00360 
00361 uavcan::int16_t CanDriver::send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline,
00362                                 uavcan::CanIOFlags flags)
00363 {
00364     if (frame.isErrorFrame() ||
00365         frame.dlc > 8 ||
00366         (flags & uavcan::CanIOFlagLoopback) != 0)   // TX timestamping is not supported by this driver.
00367     {
00368         return -1;
00369     }
00370 
00371     /*
00372      * Frame conversion
00373      */
00374     CCAN_MSG_OBJ_T msgobj = CCAN_MSG_OBJ_T();
00375     msgobj.mode_id = frame.id & uavcan::CanFrame::MaskExtID;
00376     if (frame.isExtended())
00377     {
00378         msgobj.mode_id |= CAN_MSGOBJ_EXT;
00379     }
00380     if (frame.isRemoteTransmissionRequest())
00381     {
00382         msgobj.mode_id |= CAN_MSGOBJ_RTR;
00383     }
00384     msgobj.dlc = frame.dlc;
00385     uavcan::copy(frame.data, frame.data + frame.dlc, msgobj.data);
00386 
00387     /*
00388      * Transmission
00389      */
00390     (void)tx_deadline;               // TX timeouts are not supported by this driver yet (and hardly going to be).
00391 
00392     CriticalSectionLocker locker;
00393 
00394     if (!tx_pending)
00395     {
00396         tx_pending = true;   // Mark as pending - will be released in TX callback
00397         tx_abort_on_error = (flags & uavcan::CanIOFlagAbortOnError) != 0;
00398         msgobj.msgobj = TxMessageObjectNumber;
00399         LPC_CCAN_API->can_transmit(&msgobj);
00400         return 1;
00401     }
00402     return 0;
00403 }
00404 
00405 uavcan::int16_t CanDriver::receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
00406                                    uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags)
00407 {
00408     out_ts_monotonic = clock::getMonotonic();
00409     out_flags = 0;                                            // We don't support any IO flags
00410 
00411     CriticalSectionLocker locker;
00412     if (rx_queue.getLength() == 0)
00413     {
00414         return 0;
00415     }
00416     std::uint64_t ts_utc = 0;
00417     rx_queue.pop(out_frame, ts_utc);
00418     out_ts_utc = uavcan::UtcTime::fromUSec(ts_utc);
00419     return 1;
00420 }
00421 
00422 uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks,
00423                                   const uavcan::CanFrame* (&)[uavcan::MaxCanIfaces],
00424                                   uavcan::MonotonicTime blocking_deadline)
00425 {
00426     const bool bus_off = isInBusOffState();
00427     if (bus_off)                                // Recover automatically on bus-off
00428     {
00429         CriticalSectionLocker locker;
00430         if ((c_can::CAN.CNTL & c_can::CNTL_INIT) != 0)
00431         {
00432             c_can::CAN.CNTL &= ~c_can::CNTL_INIT;
00433         }
00434     }
00435 
00436     const bool noblock = ((inout_masks.read  == 1) && hasReadyRx()) ||
00437                          ((inout_masks.write == 1) && hasEmptyTx());
00438 
00439     if (!noblock && (clock::getMonotonic() > blocking_deadline))
00440     {
00441 #if defined(UAVCAN_LPC11C24_USE_WFE) && UAVCAN_LPC11C24_USE_WFE
00442         /*
00443          * It's not cool (literally) to burn cycles in a busyloop, and we have no OS to pass control to other
00444          * tasks, thus solution is to halt the core until a hardware event occurs - e.g. clock timer overflow.
00445          * Upon such event the select() call will return, even if no requested IO operations became available.
00446          * It's OK to do that, libuavcan can handle such behavior.
00447          *
00448          * Note that it is not possible to precisely control the sleep duration with WFE, since we can't predict when
00449          * the next hardware event occurs. Worst case conditions:
00450          *  - WFE gets executed right after the clock timer interrupt;
00451          *  - CAN bus is completely silent (no traffic);
00452          *  - User's application has no interrupts and generates no hardware events.
00453          * In such scenario execution will stuck here for one period of the clock timer interrupt, even if
00454          * blocking_deadline expires sooner.
00455          * If the user's application requires higher timing precision, an extra dummy IRQ can be added just to
00456          * break WFE every once in a while.
00457          */
00458         __WFE();
00459 #endif
00460     }
00461 
00462     inout_masks.read  = hasReadyRx() ? 1 : 0;
00463 
00464     inout_masks.write = (hasEmptyTx() && !bus_off) ? 1 : 0;     // Disable write while in bus-off
00465 
00466     return 0;           // Return value doesn't matter as long as it is non-negative
00467 }
00468 
00469 uavcan::int16_t CanDriver::configureFilters(const uavcan::CanFilterConfig* filter_configs,
00470                                             uavcan::uint16_t num_configs)
00471 {
00472     CriticalSectionLocker locker;
00473 
00474     /*
00475      * If C_CAN is active (INIT=0) and the CAN bus has intensive traffic, RX object configuration may fail.
00476      * The solution is to disable the controller while configuration is in progress.
00477      * The documentation, as always, doesn't bother to mention this detail. Shame on you, NXP.
00478      */
00479     struct RAIIDisabler
00480     {
00481         RAIIDisabler()
00482         {
00483             c_can::CAN.CNTL |= c_can::CNTL_INIT;
00484         }
00485         ~RAIIDisabler()
00486         {
00487             c_can::CAN.CNTL &= ~c_can::CNTL_INIT;
00488         }
00489     } can_disabler;    // Must be instantiated AFTER the critical section locker
00490 
00491     if (num_configs == 0)
00492     {
00493         auto msg_obj = CCAN_MSG_OBJ_T();
00494         msg_obj.msgobj = NumberOfTxMessageObjects + 1;
00495         LPC_CCAN_API->config_rxmsgobj(&msg_obj);    // all STD frames
00496 
00497         msg_obj.mode_id = CAN_MSGOBJ_EXT;
00498         msg_obj.msgobj = NumberOfTxMessageObjects + 2;
00499         LPC_CCAN_API->config_rxmsgobj(&msg_obj);    // all EXT frames
00500     }
00501     else if (num_configs <= NumberOfRxMessageObjects)
00502     {
00503         // Making sure the configs use only EXT frames; otherwise we can't accept them
00504         for (unsigned i = 0; i < num_configs; i++)
00505         {
00506             auto& f = filter_configs[i];
00507             if ((f.id & f.mask & uavcan::CanFrame::FlagEFF) == 0)
00508             {
00509                 return -1;
00510             }
00511         }
00512 
00513         // Installing the configuration
00514         for (unsigned i = 0; i < NumberOfRxMessageObjects; i++)
00515         {
00516             auto msg_obj = CCAN_MSG_OBJ_T();
00517             msg_obj.msgobj = std::uint8_t(i + 1U + NumberOfTxMessageObjects);   // Message objects are numbered from 1
00518 
00519             if (i < num_configs)
00520             {
00521                 msg_obj.mode_id = (filter_configs[i].id & uavcan::CanFrame::MaskExtID) | CAN_MSGOBJ_EXT; // Only EXT
00522                 msg_obj.mask    = filter_configs[i].mask & uavcan::CanFrame::MaskExtID;
00523             }
00524             else
00525             {
00526                 msg_obj.mode_id = CAN_MSGOBJ_RTR;               // Using this configuration to disable the object
00527                 msg_obj.mask    = uavcan::CanFrame::MaskStdID;
00528             }
00529 
00530             LPC_CCAN_API->config_rxmsgobj(&msg_obj);
00531         }
00532     }
00533     else
00534     {
00535         return -1;
00536     }
00537 
00538     return 0;
00539 }
00540 
00541 uavcan::uint64_t CanDriver::getErrorCount() const
00542 {
00543     CriticalSectionLocker locker;
00544     return std::uint64_t(error_cnt) + std::uint64_t(rx_queue.getOverflowCount());
00545 }
00546 
00547 uavcan::uint16_t CanDriver::getNumFilters() const
00548 {
00549     return NumberOfRxMessageObjects;
00550 }
00551 
00552 uavcan::ICanIface* CanDriver::getIface(uavcan::uint8_t iface_index)
00553 {
00554     return (iface_index == 0) ? this : nullptr;
00555 }
00556 
00557 uavcan::uint8_t CanDriver::getNumIfaces() const
00558 {
00559     return 1;
00560 }
00561 
00562 }
00563 
00564 /*
00565  * C_CAN handlers
00566  */
00567 extern "C"
00568 {
00569 
00570 void canRxCallback(std::uint8_t msg_obj_num)
00571 {
00572     using namespace uavcan_lpc11c24;
00573 
00574     auto msg_obj = CCAN_MSG_OBJ_T();
00575     msg_obj.msgobj = msg_obj_num;
00576     LPC_CCAN_API->can_receive(&msg_obj);
00577 
00578     uavcan::CanFrame frame;
00579 
00580     // CAN ID, EXT or not
00581     if (msg_obj.mode_id & CAN_MSGOBJ_EXT)
00582     {
00583         frame.id = msg_obj.mode_id & uavcan::CanFrame::MaskExtID;
00584         frame.id |= uavcan::CanFrame::FlagEFF;
00585     }
00586     else
00587     {
00588         frame.id = msg_obj.mode_id & uavcan::CanFrame::MaskStdID;
00589     }
00590 
00591     // RTR
00592     if (msg_obj.mode_id & CAN_MSGOBJ_RTR)
00593     {
00594         frame.id |= uavcan::CanFrame::FlagRTR;
00595     }
00596 
00597     // Payload
00598     frame.dlc = msg_obj.dlc;
00599     uavcan::copy(msg_obj.data, msg_obj.data + msg_obj.dlc, frame.data);
00600 
00601     rx_queue.push(frame, last_irq_utc_timestamp);
00602     had_activity = true;
00603 }
00604 
00605 void canTxCallback(std::uint8_t msg_obj_num)
00606 {
00607     using namespace uavcan_lpc11c24;
00608 
00609     (void)msg_obj_num;
00610 
00611     tx_pending = false;
00612     had_activity = true;
00613 }
00614 
00615 void canErrorCallback(std::uint32_t error_info)
00616 {
00617     using namespace uavcan_lpc11c24;
00618 
00619     // Updating the error counter
00620     if ((error_info != 0) && (error_cnt < 0xFFFFFFFFUL))
00621     {
00622         error_cnt++;
00623     }
00624 
00625     // Serving abort requests
00626     if (tx_pending && tx_abort_on_error)
00627     {
00628         tx_pending = false;
00629         tx_abort_on_error = false;
00630 
00631         // Using the first interface, because this approach seems to be compliant with the BASIC mode (just in case)
00632         c_can::CAN.IF[0].CMDREQ = TxMessageObjectNumber;
00633         c_can::CAN.IF[0].CMDMSK.W = c_can::IF_CMDMSK_W_WR_RD;   // Clearing IF_CMDMSK_W_TXRQST
00634         c_can::CAN.IF[0].MCTRL &= ~c_can::IF_MCTRL_TXRQST;      // Clearing IF_MCTRL_TXRQST
00635     }
00636 }
00637 
00638 void CAN_IRQHandler();
00639 
00640 void CAN_IRQHandler()
00641 {
00642     using namespace uavcan_lpc11c24;
00643 
00644     last_irq_utc_timestamp = clock::getUtcUSecFromCanInterrupt();
00645 
00646     LPC_CCAN_API->isr();
00647 }
00648 
00649 }