Руслан Урядинский / libuavcan

Dependents:   UAVCAN UAVCAN_Subscriber

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers uc_stm32_can.cpp Source File

uc_stm32_can.cpp

00001 /*
00002  * Copyright (C) 2014 Pavel Kirienko <pavel.kirienko@gmail.com>
00003  */
00004 
00005 #include <cassert>
00006 #include <cstring>
00007 #include <uavcan_stm32/can.hpp>
00008 #include <uavcan_stm32/clock.hpp>
00009 #include "internal.hpp"
00010 
00011 #if UAVCAN_STM32_CHIBIOS
00012 # include <hal.h>
00013 #elif UAVCAN_STM32_NUTTX
00014 # include <nuttx/arch.h>
00015 # include <nuttx/irq.h>
00016 # include <arch/board/board.h>
00017 #elif UAVCAN_STM32_BAREMETAL
00018 #include <chip.h>   // See http://uavcan.org/Implementations/Libuavcan/Platforms/STM32/
00019 #elif UAVCAN_STM32_FREERTOS
00020 #else
00021 # error "Unknown OS"
00022 #endif
00023 
00024 #if (UAVCAN_STM32_CHIBIOS && CH_KERNEL_MAJOR == 2) || UAVCAN_STM32_BAREMETAL
00025 # if !(defined(STM32F10X_CL) || defined(STM32F2XX) || defined(STM32F3XX)  || defined(STM32F4XX))
00026 // IRQ numbers
00027 #  define CAN1_RX0_IRQn USB_LP_CAN1_RX0_IRQn
00028 #  define CAN1_TX_IRQn USB_HP_CAN1_TX_IRQn
00029 // IRQ vectors
00030 #  if !defined(CAN1_RX0_IRQHandler) || !defined(CAN1_TX_IRQHandler)
00031 #   define CAN1_TX_IRQHandler   USB_HP_CAN1_TX_IRQHandler
00032 #   define CAN1_RX0_IRQHandler  USB_LP_CAN1_RX0_IRQHandler
00033 #  endif
00034 # endif
00035 #endif
00036 
00037 #if (UAVCAN_STM32_CHIBIOS && (CH_KERNEL_MAJOR == 3 || CH_KERNEL_MAJOR == 4 || CH_KERNEL_MAJOR == 5))
00038 #define CAN1_TX_IRQHandler      STM32_CAN1_TX_HANDLER
00039 #define CAN1_RX0_IRQHandler     STM32_CAN1_RX0_HANDLER
00040 #define CAN1_RX1_IRQHandler     STM32_CAN1_RX1_HANDLER
00041 #define CAN2_TX_IRQHandler      STM32_CAN2_TX_HANDLER
00042 #define CAN2_RX0_IRQHandler     STM32_CAN2_RX0_HANDLER
00043 #define CAN2_RX1_IRQHandler     STM32_CAN2_RX1_HANDLER
00044 #endif
00045 
00046 #if UAVCAN_STM32_NUTTX
00047 # if !defined(STM32_IRQ_CAN1TX) && !defined(STM32_IRQ_CAN1RX0)
00048 #  define STM32_IRQ_CAN1TX      STM32_IRQ_USBHPCANTX
00049 #  define STM32_IRQ_CAN1RX0     STM32_IRQ_USBLPCANRX0
00050 # endif
00051 extern "C"
00052 {
00053 static int can1_irq(const int irq, void*);
00054 #if UAVCAN_STM32_NUM_IFACES > 1
00055 static int can2_irq(const int irq, void*);
00056 #endif
00057 }
00058 #endif
00059 
00060 /* STM32F3's only CAN inteface does not have a number. */
00061 #if defined(STM32F3XX)
00062 #define RCC_APB1ENR_CAN1EN     RCC_APB1ENR_CANEN
00063 #define RCC_APB1RSTR_CAN1RST   RCC_APB1RSTR_CANRST
00064 #define CAN1_TX_IRQn           CAN_TX_IRQn
00065 #define CAN1_RX0_IRQn          CAN_RX0_IRQn
00066 #define CAN1_RX1_IRQn          CAN_RX1_IRQn
00067 # if UAVCAN_STM32_BAREMETAL
00068 #  define CAN1_TX_IRQHandler   CAN_TX_IRQHandler
00069 #  define CAN1_RX0_IRQHandler  CAN_RX0_IRQHandler
00070 #  define CAN1_RX1_IRQHandler  CAN_RX1_IRQHandler
00071 # endif
00072 #endif
00073 
00074 
00075 namespace uavcan_stm32
00076 {
00077 namespace
00078 {
00079 
00080 CanIface* ifaces[UAVCAN_STM32_NUM_IFACES] =
00081 {
00082     UAVCAN_NULLPTR
00083 #if UAVCAN_STM32_NUM_IFACES > 1
00084     , UAVCAN_NULLPTR
00085 #endif
00086 };
00087 
00088 inline void handleTxInterrupt(uavcan::uint8_t iface_index)
00089 {
00090     UAVCAN_ASSERT(iface_index < UAVCAN_STM32_NUM_IFACES);
00091     uavcan::uint64_t utc_usec = clock::getUtcUSecFromCanInterrupt();
00092     if (utc_usec > 0)
00093     {
00094         utc_usec--;
00095     }
00096     if (ifaces[iface_index] != UAVCAN_NULLPTR)
00097     {
00098         ifaces[iface_index]->handleTxInterrupt(utc_usec);
00099     }
00100     else
00101     {
00102         UAVCAN_ASSERT(0);
00103     }
00104 }
00105 
00106 inline void handleRxInterrupt(uavcan::uint8_t iface_index, uavcan::uint8_t fifo_index)
00107 {
00108     UAVCAN_ASSERT(iface_index < UAVCAN_STM32_NUM_IFACES);
00109     uavcan::uint64_t utc_usec = clock::getUtcUSecFromCanInterrupt();
00110     if (utc_usec > 0)
00111     {
00112         utc_usec--;
00113     }
00114     if (ifaces[iface_index] != UAVCAN_NULLPTR)
00115     {
00116         ifaces[iface_index]->handleRxInterrupt(fifo_index, utc_usec);
00117     }
00118     else
00119     {
00120         UAVCAN_ASSERT(0);
00121     }
00122 }
00123 
00124 } // namespace
00125 
00126 /*
00127  * CanIface::RxQueue
00128  */
00129 void CanIface::RxQueue::registerOverflow()
00130 {
00131     if (overflow_cnt_ < 0xFFFFFFFF)
00132     {
00133         overflow_cnt_++;
00134     }
00135 }
00136 
00137 void CanIface::RxQueue::push(const uavcan::CanFrame& frame, const uint64_t& utc_usec, uavcan::CanIOFlags flags)
00138 {
00139     buf_[in_].frame    = frame;
00140     buf_[in_].utc_usec = utc_usec;
00141     buf_[in_].flags    = flags;
00142     in_++;
00143     if (in_ >= capacity_)
00144     {
00145         in_ = 0;
00146     }
00147     len_++;
00148     if (len_ > capacity_)
00149     {
00150         len_ = capacity_;
00151         registerOverflow();
00152         out_++;
00153         if (out_ >= capacity_)
00154         {
00155             out_ = 0;
00156         }
00157     }
00158 }
00159 
00160 void CanIface::RxQueue::pop(uavcan::CanFrame& out_frame, uavcan::uint64_t& out_utc_usec, uavcan::CanIOFlags& out_flags)
00161 {
00162     if (len_ > 0)
00163     {
00164         out_frame    = buf_[out_].frame;
00165         out_utc_usec = buf_[out_].utc_usec;
00166         out_flags    = buf_[out_].flags;
00167         out_++;
00168         if (out_ >= capacity_)
00169         {
00170             out_ = 0;
00171         }
00172         len_--;
00173     }
00174     else { UAVCAN_ASSERT(0); }
00175 }
00176 
00177 void CanIface::RxQueue::reset()
00178 {
00179     in_ = 0;
00180     out_ = 0;
00181     len_ = 0;
00182     overflow_cnt_ = 0;
00183 }
00184 
00185 /*
00186  * CanIface
00187  */
00188 const uavcan::uint32_t CanIface::TSR_ABRQx[CanIface::NumTxMailboxes] =
00189 {
00190     bxcan::TSR_ABRQ0,
00191     bxcan::TSR_ABRQ1,
00192     bxcan::TSR_ABRQ2
00193 };
00194 
00195 int CanIface::computeTimings(const uavcan::uint32_t target_bitrate, Timings& out_timings)
00196 {
00197     if (target_bitrate < 1)
00198     {
00199         return -ErrInvalidBitRate;
00200     }
00201 
00202     /*
00203      * Hardware configuration
00204      */
00205 #if UAVCAN_STM32_BAREMETAL
00206     const uavcan::uint32_t pclk = STM32_PCLK1;
00207 #elif UAVCAN_STM32_CHIBIOS
00208     const uavcan::uint32_t pclk = STM32_PCLK1;
00209 #elif UAVCAN_STM32_NUTTX
00210     const uavcan::uint32_t pclk = STM32_PCLK1_FREQUENCY;
00211 #elif UAVCAN_STM32_FREERTOS
00212     const uavcan::uint32_t pclk = HAL_RCC_GetPCLK1Freq();
00213 #else
00214 # error "Unknown OS"
00215 #endif
00216 
00217     static const int MaxBS1 = 16;
00218     static const int MaxBS2 = 8;
00219 
00220     /*
00221      * Ref. "Automatic Baudrate Detection in CANopen Networks", U. Koppe, MicroControl GmbH & Co. KG
00222      *      CAN in Automation, 2003
00223      *
00224      * According to the source, optimal quanta per bit are:
00225      *   Bitrate        Optimal Maximum
00226      *   1000 kbps      8       10
00227      *   500  kbps      16      17
00228      *   250  kbps      16      17
00229      *   125  kbps      16      17
00230      */
00231     const int max_quanta_per_bit = (target_bitrate >= 1000000) ? 10 : 17;
00232 
00233     UAVCAN_ASSERT(max_quanta_per_bit <= (MaxBS1 + MaxBS2));
00234 
00235     static const int MaxSamplePointLocation = 900;
00236 
00237     /*
00238      * Computing (prescaler * BS):
00239      *   BITRATE = 1 / (PRESCALER * (1 / PCLK) * (1 + BS1 + BS2))       -- See the Reference Manual
00240      *   BITRATE = PCLK / (PRESCALER * (1 + BS1 + BS2))                 -- Simplified
00241      * let:
00242      *   BS = 1 + BS1 + BS2                                             -- Number of time quanta per bit
00243      *   PRESCALER_BS = PRESCALER * BS
00244      * ==>
00245      *   PRESCALER_BS = PCLK / BITRATE
00246      */
00247     const uavcan::uint32_t prescaler_bs = pclk / target_bitrate;
00248 
00249     /*
00250      * Searching for such prescaler value so that the number of quanta per bit is highest.
00251      */
00252     uavcan::uint8_t bs1_bs2_sum = uavcan::uint8_t(max_quanta_per_bit - 1);
00253 
00254     while ((prescaler_bs % (1 + bs1_bs2_sum)) != 0)
00255     {
00256         if (bs1_bs2_sum <= 2)
00257         {
00258             return -ErrInvalidBitRate;          // No solution
00259         }
00260         bs1_bs2_sum--;
00261     }
00262 
00263     const uavcan::uint32_t prescaler = prescaler_bs / (1 + bs1_bs2_sum);
00264     if ((prescaler < 1U) || (prescaler > 1024U))
00265     {
00266         return -ErrInvalidBitRate;              // No solution
00267     }
00268 
00269     /*
00270      * Now we have a constraint: (BS1 + BS2) == bs1_bs2_sum.
00271      * We need to find the values so that the sample point is as close as possible to the optimal value.
00272      *
00273      *   Solve[(1 + bs1)/(1 + bs1 + bs2) == 7/8, bs2]  (* Where 7/8 is 0.875, the recommended sample point location *)
00274      *   {{bs2 -> (1 + bs1)/7}}
00275      *
00276      * Hence:
00277      *   bs2 = (1 + bs1) / 7
00278      *   bs1 = (7 * bs1_bs2_sum - 1) / 8
00279      *
00280      * Sample point location can be computed as follows:
00281      *   Sample point location = (1 + bs1) / (1 + bs1 + bs2)
00282      *
00283      * Since the optimal solution is so close to the maximum, we prepare two solutions, and then pick the best one:
00284      *   - With rounding to nearest
00285      *   - With rounding to zero
00286      */
00287     struct BsPair
00288     {
00289         uavcan::uint8_t bs1;
00290         uavcan::uint8_t bs2;
00291         uavcan::uint16_t sample_point_permill;
00292 
00293         BsPair() :
00294             bs1(0),
00295             bs2(0),
00296             sample_point_permill(0)
00297         { }
00298 
00299         BsPair(uavcan::uint8_t bs1_bs2_sum, uavcan::uint8_t arg_bs1) :
00300             bs1(arg_bs1),
00301             bs2(uavcan::uint8_t(bs1_bs2_sum - bs1)),
00302             sample_point_permill(uavcan::uint16_t(1000 * (1 + bs1) / (1 + bs1 + bs2)))
00303         {
00304             UAVCAN_ASSERT(bs1_bs2_sum > arg_bs1);
00305         }
00306 
00307         bool isValid() const { return (bs1 >= 1) && (bs1 <= MaxBS1) && (bs2 >= 1) && (bs2 <= MaxBS2); }
00308     };
00309 
00310     // First attempt with rounding to nearest
00311     BsPair solution(bs1_bs2_sum, uavcan::uint8_t(((7 * bs1_bs2_sum - 1) + 4) / 8));
00312 
00313     if (solution.sample_point_permill > MaxSamplePointLocation)
00314     {
00315         // Second attempt with rounding to zero
00316         solution = BsPair(bs1_bs2_sum, uavcan::uint8_t((7 * bs1_bs2_sum - 1) / 8));
00317     }
00318 
00319     /*
00320      * Final validation
00321      * Helpful Python:
00322      * def sample_point_from_btr(x):
00323      *     assert 0b0011110010000000111111000000000 & x == 0
00324      *     ts2,ts1,brp = (x>>20)&7, (x>>16)&15, x&511
00325      *     return (1+ts1+1)/(1+ts1+1+ts2+1)
00326      *
00327      */
00328     if ((target_bitrate != (pclk / (prescaler * (1 + solution.bs1 + solution.bs2)))) || !solution.isValid())
00329     {
00330         UAVCAN_ASSERT(0);
00331         return -ErrLogic;
00332     }
00333 
00334     UAVCAN_STM32_LOG("Timings: quanta/bit: %d, sample point location: %.1f%%",
00335                      int(1 + solution.bs1 + solution.bs2), float(solution.sample_point_permill) / 10.F);
00336 
00337     out_timings.prescaler = uavcan::uint16_t(prescaler - 1U);
00338     out_timings.sjw = 0;                                        // Which means one
00339     out_timings.bs1 = uavcan::uint8_t(solution.bs1 - 1);
00340     out_timings.bs2 = uavcan::uint8_t(solution.bs2 - 1);
00341     return 0;
00342 }
00343 
00344 uavcan::int16_t CanIface::send(const uavcan::CanFrame& frame, uavcan::MonotonicTime tx_deadline,
00345                                uavcan::CanIOFlags flags)
00346 {
00347     if (frame.isErrorFrame() || frame.dlc > 8)
00348     {
00349         return -ErrUnsupportedFrame;
00350     }
00351 
00352     /*
00353      * Normally we should perform the same check as in @ref canAcceptNewTxFrame(), because
00354      * it is possible that the highest-priority frame between select() and send() could have been
00355      * replaced with a lower priority one due to TX timeout. But we don't do this check because:
00356      *
00357      *  - It is a highly unlikely scenario.
00358      *
00359      *  - Frames do not timeout on a properly functioning bus. Since frames do not timeout, the new
00360      *    frame can only have higher priority, which doesn't break the logic.
00361      *
00362      *  - If high-priority frames are timing out in the TX queue, there's probably a lot of other
00363      *    issues to take care of before this one becomes relevant.
00364      *
00365      *  - It takes CPU time. Not just CPU time, but critical section time, which is expensive.
00366      */
00367     CriticalSectionLocker lock;
00368 
00369     /*
00370      * Seeking for an empty slot
00371      */
00372     uavcan::uint8_t txmailbox = 0xFF;
00373     if ((can_->TSR & bxcan::TSR_TME0) == bxcan::TSR_TME0)
00374     {
00375         txmailbox = 0;
00376     }
00377     else if ((can_->TSR & bxcan::TSR_TME1) == bxcan::TSR_TME1)
00378     {
00379         txmailbox = 1;
00380     }
00381     else if ((can_->TSR & bxcan::TSR_TME2) == bxcan::TSR_TME2)
00382     {
00383         txmailbox = 2;
00384     }
00385     else
00386     {
00387         return 0;       // No transmission for you.
00388     }
00389 
00390     peak_tx_mailbox_index_ = uavcan::max(peak_tx_mailbox_index_, txmailbox);    // Statistics
00391 
00392     /*
00393      * Setting up the mailbox
00394      */
00395     bxcan::TxMailboxType& mb = can_->TxMailbox[txmailbox];
00396     if (frame.isExtended())
00397     {
00398         mb.TIR = ((frame.id & uavcan::CanFrame::MaskExtID) << 3) | bxcan::TIR_IDE;
00399     }
00400     else
00401     {
00402         mb.TIR = ((frame.id & uavcan::CanFrame::MaskStdID) << 21);
00403     }
00404 
00405     if (frame.isRemoteTransmissionRequest())
00406     {
00407         mb.TIR |= bxcan::TIR_RTR;
00408     }
00409 
00410     mb.TDTR = frame.dlc;
00411 
00412     mb.TDHR = (uavcan::uint32_t(frame.data[7]) << 24) |
00413               (uavcan::uint32_t(frame.data[6]) << 16) |
00414               (uavcan::uint32_t(frame.data[5]) << 8)  |
00415               (uavcan::uint32_t(frame.data[4]) << 0);
00416     mb.TDLR = (uavcan::uint32_t(frame.data[3]) << 24) |
00417               (uavcan::uint32_t(frame.data[2]) << 16) |
00418               (uavcan::uint32_t(frame.data[1]) << 8)  |
00419               (uavcan::uint32_t(frame.data[0]) << 0);
00420 
00421     mb.TIR |= bxcan::TIR_TXRQ;  // Go.
00422 
00423     /*
00424      * Registering the pending transmission so we can track its deadline and loopback it as needed
00425      */
00426     TxItem& txi = pending_tx_[txmailbox];
00427     txi.deadline       = tx_deadline;
00428     txi.frame          = frame;
00429     txi.loopback       = (flags & uavcan::CanIOFlagLoopback) != 0;
00430     txi.abort_on_error = (flags & uavcan::CanIOFlagAbortOnError) != 0;
00431     txi.pending        = true;
00432     return 1;
00433 }
00434 
00435 uavcan::int16_t CanIface::receive(uavcan::CanFrame& out_frame, uavcan::MonotonicTime& out_ts_monotonic,
00436                                   uavcan::UtcTime& out_ts_utc, uavcan::CanIOFlags& out_flags)
00437 {
00438     out_ts_monotonic = clock::getMonotonic();  // High precision is not required for monotonic timestamps
00439     uavcan::uint64_t utc_usec = 0;
00440     {
00441         CriticalSectionLocker lock;
00442         if (rx_queue_.getLength() == 0)
00443         {
00444             return 0;
00445         }
00446         rx_queue_.pop(out_frame, utc_usec, out_flags);
00447     }
00448     out_ts_utc = uavcan::UtcTime::fromUSec(utc_usec);
00449     return 1;
00450 }
00451 
00452 uavcan::int16_t CanIface::configureFilters(const uavcan::CanFilterConfig* filter_configs,
00453                                            uavcan::uint16_t num_configs)
00454 {
00455     if (num_configs <= NumFilters)
00456     {
00457         CriticalSectionLocker lock;
00458 
00459         can_->FMR |= bxcan::FMR_FINIT;
00460 
00461         // Slave (CAN2) gets half of the filters
00462         can_->FMR &= ~0x00003F00UL;
00463         can_->FMR |= static_cast<uint32_t>(NumFilters) << 8;
00464 
00465         can_->FFA1R = 0x0AAAAAAA; // FIFO's are interleaved between filters
00466         can_->FM1R = 0; // Identifier Mask mode
00467         can_->FS1R = 0x7ffffff; // Single 32-bit for all
00468 
00469         const uint8_t filter_start_index = (self_index_ == 0) ? 0 : NumFilters;
00470 
00471         if (num_configs == 0)
00472         {
00473             can_->FilterRegister[filter_start_index].FR1 = 0;
00474             can_->FilterRegister[filter_start_index].FR2 = 0;
00475             // We can't directly overwrite FA1R because that breaks the other CAN interface
00476             can_->FA1R |= 1U << filter_start_index;              // Other filters may still be enabled, we don't care
00477         }
00478         else
00479         {
00480             for (uint8_t i = 0; i < NumFilters; i++)
00481             {
00482                 if (i < num_configs)
00483                 {
00484                     uint32_t id   = 0;
00485                     uint32_t mask = 0;
00486 
00487                     const uavcan::CanFilterConfig* const cfg = filter_configs + i;
00488 
00489                     if ((cfg->id & uavcan::CanFrame::FlagEFF) || !(cfg->mask & uavcan::CanFrame::FlagEFF))
00490                     {
00491                         id   = (cfg->id   & uavcan::CanFrame::MaskExtID) << 3;
00492                         mask = (cfg->mask & uavcan::CanFrame::MaskExtID) << 3;
00493                         id |= bxcan::RIR_IDE;
00494                     }
00495                     else
00496                     {
00497                         id   = (cfg->id   & uavcan::CanFrame::MaskStdID) << 21;  // Regular std frames, nothing fancy.
00498                         mask = (cfg->mask & uavcan::CanFrame::MaskStdID) << 21;  // Boring.
00499                     }
00500 
00501                     if (cfg->id & uavcan::CanFrame::FlagRTR)
00502                     {
00503                         id |= bxcan::RIR_RTR;
00504                     }
00505 
00506                     if (cfg->mask & uavcan::CanFrame::FlagEFF)
00507                     {
00508                         mask |= bxcan::RIR_IDE;
00509                     }
00510 
00511                     if (cfg->mask & uavcan::CanFrame::FlagRTR)
00512                     {
00513                         mask |= bxcan::RIR_RTR;
00514                     }
00515 
00516                     can_->FilterRegister[filter_start_index + i].FR1 = id;
00517                     can_->FilterRegister[filter_start_index + i].FR2 = mask;
00518 
00519                     can_->FA1R |= (1 << (filter_start_index + i));
00520                 }
00521                 else
00522                 {
00523                     can_->FA1R &= ~(1 << (filter_start_index + i));
00524                 }
00525             }
00526         }
00527 
00528         can_->FMR &= ~bxcan::FMR_FINIT;
00529 
00530         return 0;
00531     }
00532 
00533     return -ErrFilterNumConfigs;
00534 }
00535 
00536 bool CanIface::waitMsrINakBitStateChange(bool target_state)
00537 {
00538 #if UAVCAN_STM32_NUTTX || UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_FREERTOS
00539     const unsigned Timeout = 1000;
00540 #else
00541     const unsigned Timeout = 2000000;
00542 #endif
00543     for (unsigned wait_ack = 0; wait_ack < Timeout; wait_ack++)
00544     {
00545         const bool state = (can_->MSR & bxcan::MSR_INAK) != 0;
00546         if (state == target_state)
00547         {
00548             return true;
00549         }
00550 #if UAVCAN_STM32_NUTTX
00551         ::usleep(1000);
00552 #endif
00553 #if UAVCAN_STM32_CHIBIOS
00554         ::chThdSleep(MS2ST(1));
00555 #endif
00556 #if UAVCAN_STM32_FREERTOS
00557         ::osDelay(1);
00558 #endif
00559     }
00560     return false;
00561 }
00562 
00563 int CanIface::init(const uavcan::uint32_t bitrate, const OperatingMode mode)
00564 {
00565     /*
00566      * We need to silence the controller in the first order, otherwise it may interfere with the following operations.
00567      */
00568     {
00569         CriticalSectionLocker lock;
00570 
00571         can_->MCR &= ~bxcan::MCR_SLEEP; // Exit sleep mode
00572         can_->MCR |= bxcan::MCR_INRQ;   // Request init
00573 
00574         can_->IER = 0;                  // Disable interrupts while initialization is in progress
00575     }
00576 
00577     if (!waitMsrINakBitStateChange(true))
00578     {
00579         UAVCAN_STM32_LOG("MSR INAK not set");
00580         can_->MCR = bxcan::MCR_RESET;
00581         return -ErrMsrInakNotSet;
00582     }
00583 
00584     /*
00585      * Object state - interrupts are disabled, so it's safe to modify it now
00586      */
00587     rx_queue_.reset();
00588     error_cnt_ = 0;
00589     served_aborts_cnt_ = 0;
00590     uavcan::fill_n(pending_tx_, NumTxMailboxes, TxItem());
00591     peak_tx_mailbox_index_ = 0;
00592     had_activity_ = false;
00593 
00594     /*
00595      * CAN timings for this bitrate
00596      */
00597     Timings timings;
00598     const int timings_res = computeTimings(bitrate, timings);
00599     if (timings_res < 0)
00600     {
00601         can_->MCR = bxcan::MCR_RESET;
00602         return timings_res;
00603     }
00604     UAVCAN_STM32_LOG("Timings: presc=%u sjw=%u bs1=%u bs2=%u",
00605                      unsigned(timings.prescaler), unsigned(timings.sjw), unsigned(timings.bs1), unsigned(timings.bs2));
00606 
00607     /*
00608      * Hardware initialization (the hardware has already confirmed initialization mode, see above)
00609      */
00610     can_->MCR = bxcan::MCR_ABOM | bxcan::MCR_AWUM | bxcan::MCR_INRQ;  // RM page 648
00611 
00612     can_->BTR = ((timings.sjw & 3U)  << 24) |
00613                 ((timings.bs1 & 15U) << 16) |
00614                 ((timings.bs2 & 7U)  << 20) |
00615                 (timings.prescaler & 1023U) |
00616                 ((mode == SilentMode) ? bxcan::BTR_SILM : 0);
00617 
00618     can_->IER = bxcan::IER_TMEIE |   // TX mailbox empty
00619                 bxcan::IER_FMPIE0 |  // RX FIFO 0 is not empty
00620                 bxcan::IER_FMPIE1;   // RX FIFO 1 is not empty
00621 
00622     can_->MCR &= ~bxcan::MCR_INRQ;   // Leave init mode
00623 
00624     if (!waitMsrINakBitStateChange(false))
00625     {
00626         UAVCAN_STM32_LOG("MSR INAK not cleared");
00627         can_->MCR = bxcan::MCR_RESET;
00628         return -ErrMsrInakNotCleared;
00629     }
00630 
00631     /*
00632      * Default filter configuration
00633      */
00634     if (self_index_ == 0)
00635     {
00636         can_->FMR |= bxcan::FMR_FINIT;
00637 
00638         can_->FMR &= 0xFFFFC0F1;
00639         can_->FMR |= static_cast<uavcan::uint32_t>(NumFilters) << 8;  // Slave (CAN2) gets half of the filters
00640 
00641         can_->FFA1R = 0;                           // All assigned to FIFO0 by default
00642         can_->FM1R = 0;                            // Indentifier Mask mode
00643 
00644 #if UAVCAN_STM32_NUM_IFACES > 1
00645         can_->FS1R = 0x7ffffff;                    // Single 32-bit for all
00646         can_->FilterRegister[0].FR1 = 0;          // CAN1 accepts everything
00647         can_->FilterRegister[0].FR2 = 0;
00648         can_->FilterRegister[NumFilters].FR1 = 0; // CAN2 accepts everything
00649         can_->FilterRegister[NumFilters].FR2 = 0;
00650         can_->FA1R = 1 | (1 << NumFilters);        // One filter per each iface
00651 #else
00652         can_->FS1R = 0x1fff;
00653         can_->FilterRegister[0].FR1 = 0;
00654         can_->FilterRegister[0].FR2 = 0;
00655         can_->FA1R = 1;
00656 #endif
00657 
00658         can_->FMR &= ~bxcan::FMR_FINIT;
00659     }
00660 
00661     return 0;
00662 }
00663 
00664 void CanIface::handleTxMailboxInterrupt(uavcan::uint8_t mailbox_index, bool txok, const uavcan::uint64_t utc_usec)
00665 {
00666     UAVCAN_ASSERT(mailbox_index < NumTxMailboxes);
00667 
00668     had_activity_ = had_activity_ || txok;
00669 
00670     TxItem& txi = pending_tx_[mailbox_index];
00671 
00672     if (txi.loopback && txok && txi.pending)
00673     {
00674         rx_queue_.push(txi.frame, utc_usec, uavcan::CanIOFlagLoopback);
00675     }
00676 
00677     txi.pending = false;
00678 }
00679 
00680 void CanIface::handleTxInterrupt(const uavcan::uint64_t utc_usec)
00681 {
00682     // TXOK == false means that there was a hardware failure
00683     if (can_->TSR & bxcan::TSR_RQCP0)
00684     {
00685         const bool txok = can_->TSR & bxcan::TSR_TXOK0;
00686         can_->TSR = bxcan::TSR_RQCP0;
00687         handleTxMailboxInterrupt(0, txok, utc_usec);
00688     }
00689     if (can_->TSR & bxcan::TSR_RQCP1)
00690     {
00691         const bool txok = can_->TSR & bxcan::TSR_TXOK1;
00692         can_->TSR = bxcan::TSR_RQCP1;
00693         handleTxMailboxInterrupt(1, txok, utc_usec);
00694     }
00695     if (can_->TSR & bxcan::TSR_RQCP2)
00696     {
00697         const bool txok = can_->TSR & bxcan::TSR_TXOK2;
00698         can_->TSR = bxcan::TSR_RQCP2;
00699         handleTxMailboxInterrupt(2, txok, utc_usec);
00700     }
00701     update_event_.signalFromInterrupt();
00702 
00703     pollErrorFlagsFromISR();
00704 
00705     #if UAVCAN_STM32_FREERTOS
00706     update_event_.yieldFromISR();
00707     #endif
00708 }
00709 
00710 void CanIface::handleRxInterrupt(uavcan::uint8_t fifo_index, uavcan::uint64_t utc_usec)
00711 {
00712     UAVCAN_ASSERT(fifo_index < 2);
00713 
00714     volatile uavcan::uint32_t* const rfr_reg = (fifo_index == 0) ? &can_->RF0R : &can_->RF1R;
00715     if ((*rfr_reg & bxcan::RFR_FMP_MASK) == 0)
00716     {
00717         UAVCAN_ASSERT(0);  // Weird, IRQ is here but no data to read
00718         return;
00719     }
00720 
00721     /*
00722      * Register overflow as a hardware error
00723      */
00724     if ((*rfr_reg & bxcan::RFR_FOVR) != 0)
00725     {
00726         error_cnt_++;
00727     }
00728 
00729     /*
00730      * Read the frame contents
00731      */
00732     uavcan::CanFrame frame;
00733     const bxcan::RxMailboxType& rf = can_->RxMailbox[fifo_index];
00734 
00735     if ((rf.RIR & bxcan::RIR_IDE) == 0)
00736     {
00737         frame.id = uavcan::CanFrame::MaskStdID & (rf.RIR >> 21);
00738     }
00739     else
00740     {
00741         frame.id = uavcan::CanFrame::MaskExtID & (rf.RIR >> 3);
00742         frame.id |= uavcan::CanFrame::FlagEFF;
00743     }
00744 
00745     if ((rf.RIR & bxcan::RIR_RTR) != 0)
00746     {
00747         frame.id |= uavcan::CanFrame::FlagRTR;
00748     }
00749 
00750     frame.dlc = rf.RDTR & 15;
00751 
00752     frame.data[0] = uavcan::uint8_t(0xFF & (rf.RDLR >> 0));
00753     frame.data[1] = uavcan::uint8_t(0xFF & (rf.RDLR >> 8));
00754     frame.data[2] = uavcan::uint8_t(0xFF & (rf.RDLR >> 16));
00755     frame.data[3] = uavcan::uint8_t(0xFF & (rf.RDLR >> 24));
00756     frame.data[4] = uavcan::uint8_t(0xFF & (rf.RDHR >> 0));
00757     frame.data[5] = uavcan::uint8_t(0xFF & (rf.RDHR >> 8));
00758     frame.data[6] = uavcan::uint8_t(0xFF & (rf.RDHR >> 16));
00759     frame.data[7] = uavcan::uint8_t(0xFF & (rf.RDHR >> 24));
00760 
00761     *rfr_reg = bxcan::RFR_RFOM | bxcan::RFR_FOVR | bxcan::RFR_FULL;  // Release FIFO entry we just read
00762 
00763     /*
00764      * Store with timeout into the FIFO buffer and signal update event
00765      */
00766     rx_queue_.push(frame, utc_usec, 0);
00767     had_activity_ = true;
00768     update_event_.signalFromInterrupt();
00769 
00770     pollErrorFlagsFromISR();
00771 
00772     #if UAVCAN_STM32_FREERTOS
00773     update_event_.yieldFromISR();
00774     #endif
00775 }
00776 
00777 void CanIface::pollErrorFlagsFromISR()
00778 {
00779     const uavcan::uint8_t lec = uavcan::uint8_t((can_->ESR & bxcan::ESR_LEC_MASK) >> bxcan::ESR_LEC_SHIFT);
00780     if (lec != 0)
00781     {
00782         can_->ESR = 0;
00783         error_cnt_++;
00784 
00785         // Serving abort requests
00786         for (int i = 0; i < NumTxMailboxes; i++)    // Dear compiler, may I suggest you to unroll this loop please.
00787         {
00788             TxItem& txi = pending_tx_[i];
00789             if (txi.pending && txi.abort_on_error)
00790             {
00791                 can_->TSR = TSR_ABRQx[i];
00792                 txi.pending = false;
00793                 served_aborts_cnt_++;
00794             }
00795         }
00796     }
00797 }
00798 
00799 void CanIface::discardTimedOutTxMailboxes(uavcan::MonotonicTime current_time)
00800 {
00801     CriticalSectionLocker lock;
00802     for (int i = 0; i < NumTxMailboxes; i++)
00803     {
00804         TxItem& txi = pending_tx_[i];
00805         if (txi.pending && txi.deadline < current_time)
00806         {
00807             can_->TSR = TSR_ABRQx[i];  // Goodnight sweet transmission
00808             txi.pending = false;
00809             error_cnt_++;
00810         }
00811     }
00812 }
00813 
00814 bool CanIface::canAcceptNewTxFrame(const uavcan::CanFrame& frame) const
00815 {
00816     /*
00817      * We can accept more frames only if the following conditions are satisfied:
00818      *  - There is at least one TX mailbox free (obvious enough);
00819      *  - The priority of the new frame is higher than priority of all TX mailboxes.
00820      */
00821     {
00822         static const uavcan::uint32_t TME = bxcan::TSR_TME0 | bxcan::TSR_TME1 | bxcan::TSR_TME2;
00823         const uavcan::uint32_t tme = can_->TSR & TME;
00824 
00825         if (tme == TME)     // All TX mailboxes are free (as in freedom).
00826         {
00827             return true;
00828         }
00829 
00830         if (tme == 0)       // All TX mailboxes are busy transmitting.
00831         {
00832             return false;
00833         }
00834     }
00835 
00836     /*
00837      * The second condition requires a critical section.
00838      */
00839     CriticalSectionLocker lock;
00840 
00841     for (int mbx = 0; mbx < NumTxMailboxes; mbx++)
00842     {
00843         if (pending_tx_[mbx].pending && !frame.priorityHigherThan(pending_tx_[mbx].frame))
00844         {
00845             return false;       // There's a mailbox whose priority is higher or equal the priority of the new frame.
00846         }
00847     }
00848 
00849     return true;                // This new frame will be added to a free TX mailbox in the next @ref send().
00850 }
00851 
00852 bool CanIface::isRxBufferEmpty() const
00853 {
00854     CriticalSectionLocker lock;
00855     return rx_queue_.getLength() == 0;
00856 }
00857 
00858 uavcan::uint64_t CanIface::getErrorCount() const
00859 {
00860     CriticalSectionLocker lock;
00861     return error_cnt_ + rx_queue_.getOverflowCount();
00862 }
00863 
00864 unsigned CanIface::getRxQueueLength() const
00865 {
00866     CriticalSectionLocker lock;
00867     return rx_queue_.getLength();
00868 }
00869 
00870 bool CanIface::hadActivity()
00871 {
00872     CriticalSectionLocker lock;
00873     const bool ret = had_activity_;
00874     had_activity_ = false;
00875     return ret;
00876 }
00877 
00878 /*
00879  * CanDriver
00880  */
00881 uavcan::CanSelectMasks CanDriver::makeSelectMasks(const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces]) const
00882 {
00883     uavcan::CanSelectMasks msk;
00884 
00885     // Iface 0
00886     msk.read  = if0_.isRxBufferEmpty() ? 0 : 1;
00887 
00888     if (pending_tx[0] != UAVCAN_NULLPTR)
00889     {
00890         msk.write = if0_.canAcceptNewTxFrame(*pending_tx[0]) ? 1 : 0;
00891     }
00892 
00893     // Iface 1
00894 #if UAVCAN_STM32_NUM_IFACES > 1
00895     if (!if1_.isRxBufferEmpty())
00896     {
00897         msk.read |= 1 << 1;
00898     }
00899 
00900     if (pending_tx[1] != UAVCAN_NULLPTR)
00901     {
00902         if (if1_.canAcceptNewTxFrame(*pending_tx[1]))
00903         {
00904             msk.write |= 1 << 1;
00905         }
00906     }
00907 #endif
00908     return msk;
00909 }
00910 
00911 bool CanDriver::hasReadableInterfaces() const
00912 {
00913 #if UAVCAN_STM32_NUM_IFACES == 1
00914     return !if0_.isRxBufferEmpty();
00915 #elif UAVCAN_STM32_NUM_IFACES == 2
00916     return !if0_.isRxBufferEmpty() || !if1_.isRxBufferEmpty();
00917 #else
00918 # error UAVCAN_STM32_NUM_IFACES
00919 #endif
00920 }
00921 
00922 uavcan::int16_t CanDriver::select(uavcan::CanSelectMasks& inout_masks,
00923                                   const uavcan::CanFrame* (& pending_tx)[uavcan::MaxCanIfaces],
00924                                   const uavcan::MonotonicTime blocking_deadline)
00925 {
00926     const uavcan::CanSelectMasks in_masks = inout_masks;
00927     const uavcan::MonotonicTime time = clock::getMonotonic();
00928 
00929     if0_.discardTimedOutTxMailboxes(time);              // Check TX timeouts - this may release some TX slots
00930     {
00931         CriticalSectionLocker cs_locker;
00932         if0_.pollErrorFlagsFromISR();
00933     }
00934 
00935 #if UAVCAN_STM32_NUM_IFACES > 1
00936     if1_.discardTimedOutTxMailboxes(time);
00937     {
00938         CriticalSectionLocker cs_locker;
00939         if1_.pollErrorFlagsFromISR();
00940     }
00941 #endif
00942 
00943     inout_masks = makeSelectMasks(pending_tx);          // Check if we already have some of the requested events
00944     if ((inout_masks.read  & in_masks.read)  != 0 ||
00945         (inout_masks.write & in_masks.write) != 0)
00946     {
00947         return 1;
00948     }
00949 
00950     (void)update_event_.wait(blocking_deadline - time); // Block until timeout expires or any iface updates
00951     inout_masks = makeSelectMasks(pending_tx);  // Return what we got even if none of the requested events are set
00952     return 1;                                   // Return value doesn't matter as long as it is non-negative
00953 }
00954 
00955 
00956 #if UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
00957 
00958 static void nvicEnableVector(IRQn_Type irq,  uint8_t prio)
00959 {
00960     #if !defined (USE_HAL_DRIVER)
00961       NVIC_InitTypeDef NVIC_InitStructure;
00962       NVIC_InitStructure.NVIC_IRQChannel = irq;
00963       NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = prio;
00964       NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
00965       NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
00966       NVIC_Init(&NVIC_InitStructure);
00967     #else
00968       HAL_NVIC_SetPriority(irq, prio, 0);
00969       HAL_NVIC_EnableIRQ(irq);
00970     #endif
00971 }
00972 
00973 #endif
00974 
00975 void CanDriver::initOnce()
00976 {
00977     /*
00978      * CAN1, CAN2
00979      */
00980     {
00981         CriticalSectionLocker lock;
00982 #if UAVCAN_STM32_NUTTX
00983         modifyreg32(STM32_RCC_APB1ENR,  0, RCC_APB1ENR_CAN1EN);
00984         modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_CAN1RST);
00985         modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_CAN1RST, 0);
00986 # if UAVCAN_STM32_NUM_IFACES > 1
00987         modifyreg32(STM32_RCC_APB1ENR,  0, RCC_APB1ENR_CAN2EN);
00988         modifyreg32(STM32_RCC_APB1RSTR, 0, RCC_APB1RSTR_CAN2RST);
00989         modifyreg32(STM32_RCC_APB1RSTR, RCC_APB1RSTR_CAN2RST, 0);
00990 # endif
00991 #else
00992         RCC->APB1ENR  |=  RCC_APB1ENR_CAN1EN;
00993         RCC->APB1RSTR |=  RCC_APB1RSTR_CAN1RST;
00994         RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN1RST;
00995 # if UAVCAN_STM32_NUM_IFACES > 1
00996         RCC->APB1ENR  |=  RCC_APB1ENR_CAN2EN;
00997         RCC->APB1RSTR |=  RCC_APB1RSTR_CAN2RST;
00998         RCC->APB1RSTR &= ~RCC_APB1RSTR_CAN2RST;
00999 # endif
01000 #endif
01001     }
01002 
01003     /*
01004      * IRQ
01005      */
01006 #if UAVCAN_STM32_NUTTX
01007 # define IRQ_ATTACH(irq, handler)                          \
01008     {                                                      \
01009         const int res = irq_attach(irq, handler);          \
01010         (void)res;                                         \
01011         assert(res >= 0);                                  \
01012         up_enable_irq(irq);                                \
01013     }
01014     IRQ_ATTACH(STM32_IRQ_CAN1TX,  can1_irq);
01015     IRQ_ATTACH(STM32_IRQ_CAN1RX0, can1_irq);
01016     IRQ_ATTACH(STM32_IRQ_CAN1RX1, can1_irq);
01017 # if UAVCAN_STM32_NUM_IFACES > 1
01018     IRQ_ATTACH(STM32_IRQ_CAN2TX,  can2_irq);
01019     IRQ_ATTACH(STM32_IRQ_CAN2RX0, can2_irq);
01020     IRQ_ATTACH(STM32_IRQ_CAN2RX1, can2_irq);
01021 # endif
01022 # undef IRQ_ATTACH
01023 #elif UAVCAN_STM32_CHIBIOS || UAVCAN_STM32_BAREMETAL || UAVCAN_STM32_FREERTOS
01024     {
01025         CriticalSectionLocker lock;
01026         nvicEnableVector(CAN1_TX_IRQn,  UAVCAN_STM32_IRQ_PRIORITY_MASK);
01027         nvicEnableVector(CAN1_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
01028         nvicEnableVector(CAN1_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
01029 # if UAVCAN_STM32_NUM_IFACES > 1
01030         nvicEnableVector(CAN2_TX_IRQn,  UAVCAN_STM32_IRQ_PRIORITY_MASK);
01031         nvicEnableVector(CAN2_RX0_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
01032         nvicEnableVector(CAN2_RX1_IRQn, UAVCAN_STM32_IRQ_PRIORITY_MASK);
01033 # endif
01034     }
01035 #endif
01036 }
01037 
01038 int CanDriver::init(const uavcan::uint32_t bitrate, const CanIface::OperatingMode mode)
01039 {
01040     int res = 0;
01041 
01042     UAVCAN_STM32_LOG("Bitrate %lu mode %d", static_cast<unsigned long>(bitrate), static_cast<int>(mode));
01043 
01044     static bool initialized_once = false;
01045     if (!initialized_once)
01046     {
01047         initialized_once = true;
01048         UAVCAN_STM32_LOG("First initialization");
01049         initOnce();
01050     }
01051 
01052     /*
01053      * CAN1
01054      */
01055     UAVCAN_STM32_LOG("Initing iface 0...");
01056     ifaces[0] = &if0_;                          // This link must be initialized first,
01057     res = if0_.init(bitrate, mode);             // otherwise an IRQ may fire while the interface is not linked yet;
01058     if (res < 0)                                // a typical race condition.
01059     {
01060         UAVCAN_STM32_LOG("Iface 0 init failed %i", res);
01061         ifaces[0] = UAVCAN_NULLPTR;
01062         goto fail;
01063     }
01064 
01065     /*
01066      * CAN2
01067      */
01068 #if UAVCAN_STM32_NUM_IFACES > 1
01069     UAVCAN_STM32_LOG("Initing iface 1...");
01070     ifaces[1] = &if1_;                          // Same thing here.
01071     res = if1_.init(bitrate, mode);
01072     if (res < 0)
01073     {
01074         UAVCAN_STM32_LOG("Iface 1 init failed %i", res);
01075         ifaces[1] = UAVCAN_NULLPTR;
01076         goto fail;
01077     }
01078 #endif
01079 
01080     UAVCAN_STM32_LOG("CAN drv init OK");
01081     UAVCAN_ASSERT(res >= 0);
01082     return res;
01083 
01084 fail:
01085     UAVCAN_STM32_LOG("CAN drv init failed %i", res);
01086     UAVCAN_ASSERT(res < 0);
01087     return res;
01088 }
01089 
01090 CanIface* CanDriver::getIface(uavcan::uint8_t iface_index)
01091 {
01092     if (iface_index < UAVCAN_STM32_NUM_IFACES)
01093     {
01094         return ifaces[iface_index];
01095     }
01096     return UAVCAN_NULLPTR;
01097 }
01098 
01099 bool CanDriver::hadActivity()
01100 {
01101     bool ret = if0_.hadActivity();
01102 #if UAVCAN_STM32_NUM_IFACES > 1
01103     ret |= if1_.hadActivity();
01104 #endif
01105     return ret;
01106 }
01107 
01108 } // namespace uavcan_stm32
01109 
01110 /*
01111  * Interrupt handlers
01112  */
01113 extern "C"
01114 {
01115 
01116 #if UAVCAN_STM32_NUTTX
01117 
01118 static int can1_irq(const int irq, void*)
01119 {
01120     if (irq == STM32_IRQ_CAN1TX)
01121     {
01122         uavcan_stm32::handleTxInterrupt(0);
01123     }
01124     else if (irq == STM32_IRQ_CAN1RX0)
01125     {
01126         uavcan_stm32::handleRxInterrupt(0, 0);
01127     }
01128     else if (irq == STM32_IRQ_CAN1RX1)
01129     {
01130         uavcan_stm32::handleRxInterrupt(0, 1);
01131     }
01132     else
01133     {
01134         PANIC();
01135     }
01136     return 0;
01137 }
01138 
01139 # if UAVCAN_STM32_NUM_IFACES > 1
01140 
01141 static int can2_irq(const int irq, void*)
01142 {
01143     if (irq == STM32_IRQ_CAN2TX)
01144     {
01145         uavcan_stm32::handleTxInterrupt(1);
01146     }
01147     else if (irq == STM32_IRQ_CAN2RX0)
01148     {
01149         uavcan_stm32::handleRxInterrupt(1, 0);
01150     }
01151     else if (irq == STM32_IRQ_CAN2RX1)
01152     {
01153         uavcan_stm32::handleRxInterrupt(1, 1);
01154     }
01155     else
01156     {
01157         PANIC();
01158     }
01159     return 0;
01160 }
01161 
01162 # endif
01163 
01164 #else // UAVCAN_STM32_NUTTX
01165 
01166 #if !defined(CAN1_TX_IRQHandler) ||\
01167     !defined(CAN1_RX0_IRQHandler) ||\
01168     !defined(CAN1_RX1_IRQHandler)
01169 # error "Misconfigured build"
01170 #endif
01171 
01172 UAVCAN_STM32_IRQ_HANDLER(CAN1_TX_IRQHandler);
01173 UAVCAN_STM32_IRQ_HANDLER(CAN1_TX_IRQHandler)
01174 {
01175     UAVCAN_STM32_IRQ_PROLOGUE();
01176     uavcan_stm32::handleTxInterrupt(0);
01177     UAVCAN_STM32_IRQ_EPILOGUE();
01178 }
01179 
01180 UAVCAN_STM32_IRQ_HANDLER(CAN1_RX0_IRQHandler);
01181 UAVCAN_STM32_IRQ_HANDLER(CAN1_RX0_IRQHandler)
01182 {
01183     UAVCAN_STM32_IRQ_PROLOGUE();
01184     uavcan_stm32::handleRxInterrupt(0, 0);
01185     UAVCAN_STM32_IRQ_EPILOGUE();
01186 }
01187 
01188 UAVCAN_STM32_IRQ_HANDLER(CAN1_RX1_IRQHandler);
01189 UAVCAN_STM32_IRQ_HANDLER(CAN1_RX1_IRQHandler)
01190 {
01191     UAVCAN_STM32_IRQ_PROLOGUE();
01192     uavcan_stm32::handleRxInterrupt(0, 1);
01193     UAVCAN_STM32_IRQ_EPILOGUE();
01194 }
01195 
01196 # if UAVCAN_STM32_NUM_IFACES > 1
01197 
01198 #if !defined(CAN2_TX_IRQHandler) ||\
01199     !defined(CAN2_RX0_IRQHandler) ||\
01200     !defined(CAN2_RX1_IRQHandler)
01201 # error "Misconfigured build"
01202 #endif
01203 
01204 UAVCAN_STM32_IRQ_HANDLER(CAN2_TX_IRQHandler);
01205 UAVCAN_STM32_IRQ_HANDLER(CAN2_TX_IRQHandler)
01206 {
01207     UAVCAN_STM32_IRQ_PROLOGUE();
01208     uavcan_stm32::handleTxInterrupt(1);
01209     UAVCAN_STM32_IRQ_EPILOGUE();
01210 }
01211 
01212 UAVCAN_STM32_IRQ_HANDLER(CAN2_RX0_IRQHandler);
01213 UAVCAN_STM32_IRQ_HANDLER(CAN2_RX0_IRQHandler)
01214 {
01215     UAVCAN_STM32_IRQ_PROLOGUE();
01216     uavcan_stm32::handleRxInterrupt(1, 0);
01217     UAVCAN_STM32_IRQ_EPILOGUE();
01218 }
01219 
01220 UAVCAN_STM32_IRQ_HANDLER(CAN2_RX1_IRQHandler);
01221 UAVCAN_STM32_IRQ_HANDLER(CAN2_RX1_IRQHandler)
01222 {
01223     UAVCAN_STM32_IRQ_PROLOGUE();
01224     uavcan_stm32::handleRxInterrupt(1, 1);
01225     UAVCAN_STM32_IRQ_EPILOGUE();
01226 }
01227 
01228 # endif
01229 #endif // UAVCAN_STM32_NUTTX
01230 
01231 } // extern "C"