Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: UAVCAN UAVCAN_Subscriber
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"
Generated on Tue Jul 12 2022 17:17:35 by
1.7.2