25#include <kernel/scheduler/scheduler.h>
62 can->MCR &= ~CAN_MCR_SLEEP;
63 can->MCR |= CAN_MCR_INRQ;
65 while ((can->MSR & CAN_MSR_INAK) == 0)
70 can->MCR |= CAN_MCR_AWUM;
74 can->MCR |= CAN_MCR_ABOM;
78 can->MCR |= CAN_MCR_NART;
81 can->BTR &= ~CAN_BTR_BRP;
82 can->BTR &= ~CAN_BTR_TS1;
83 can->BTR &= ~CAN_BTR_TS2;
84 can->BTR &= ~CAN_BTR_SJW;
86 can->BTR |= bitTiming.BRP & 0x3FF;
87 can->BTR |= ((bitTiming.BS1 - 1) & 0xF) << 16;
88 can->BTR |= ((bitTiming.BS2 - 1) & 0x7) << 20;
89 can->BTR |= ((bitTiming.SJW - 1) & 0x3) << 24;
92 can->BTR |= CAN_BTR_LBKM;
95 can->FMR |= CAN_FMR_FINIT;
103 can->IER |= CAN_IER_FMPIE0 | CAN_IER_FMPIE1 | CAN_IER_TMEIE;
108 NVIC_EnableIRQ(CAN1_RX0_IRQn);
109 NVIC_SetPriority(CAN1_RX0_IRQn, 14);
111 NVIC_EnableIRQ(CAN1_RX1_IRQn);
112 NVIC_SetPriority(CAN1_RX1_IRQn, 14);
114 NVIC_EnableIRQ(CAN1_TX_IRQn);
115 NVIC_SetPriority(CAN1_TX_IRQn, 14);
117 else if (can == CAN2)
119 NVIC_EnableIRQ(CAN2_RX0_IRQn);
120 NVIC_SetPriority(CAN2_RX0_IRQn, 14);
122 NVIC_EnableIRQ(CAN2_RX1_IRQn);
123 NVIC_SetPriority(CAN2_RX1_IRQn, 14);
125 NVIC_EnableIRQ(CAN2_TX_IRQn);
126 NVIC_SetPriority(CAN2_TX_IRQn, 14);
131 LOG_ERR(ls,
"Not supported peripheral");
147 float costOpt = 1000;
156 for (uint8_t N = 3; N <= 25; N++)
159 cfgIter.BRP = std::max(
160 std::min((
int)roundf(apbclk * 1.0f / (autoBt.baudRate * N) - 1),
167 std::min(std::max((
int)roundf(autoBt.samplePoint * N - 1), 1),
168 std::min(N - 2, 16));
170 cfgIter.BS2 = N - cfgIter.BS1 - 1;
173 fabs(apbclk * 1.0f / (N * (cfgIter.BRP + 1)) - autoBt.baudRate) /
175 float sp = (1 + cfgIter.BS1) * 1.0f / (1 + cfgIter.BS1 + cfgIter.BS2);
177 float spErrPercent = fabs(sp - autoBt.samplePoint) / autoBt.samplePoint;
180 float cost = BR_ERR_WEIGHT * brErrPercent +
181 SP_ERR_WEIGHT * spErrPercent +
182 N_ERR_WEIGHT * fabs(N - 10) / 25;
193 cfgOpt.SJW = fminf(ceilf(NOpt * 1.0f / 5), 4);
196 "Optimal Bit Timing Registers: BRP={}, BS1={}, BS2={}, SJW={}",
197 cfgOpt.BRP, cfgOpt.BS1, cfgOpt.BS2, cfgOpt.SJW);
199 float brTrue = apbclk * 1.0f / ((cfgOpt.BRP + 1) * NOpt);
200 float spTrue = (1 + cfgOpt.BS1) * 1.0f / (1 + cfgOpt.BS1 + cfgOpt.BS2);
203 "Optimal Bit Timing: BR_true={:.2f}, spTrue:{:.2f}%, "
204 "BR_error={:.2f}%, SP_error={:.2f}%",
205 brTrue / 1000, spTrue * 100,
206 fabsf(brTrue - autoBt.baudRate) / autoBt.baudRate * 100,
207 fabs(spTrue - autoBt.samplePoint) / autoBt.samplePoint * 100);
219 can->FMR &= ~CAN_FMR_FINIT;
220 can->MCR &= ~CAN_MCR_INRQ;
224 LOG_DEBUG(ls,
"Waiting for canbus synchronization...");
225 while ((can->MSR & CAN_MSR_INAK) > 0)
228 LOG_INFO(ls,
"Canbus synchronized! Init done!");
236 uint8_t index = filterIndex;
244 LOG_ERR(ls,
"Cannot add filter: canbus already initialized");
248 if (index >= NUM_FILTER_BANKS)
250 LOG_ERR(ls,
"Cannot add filter: no more filter banks available");
256 CAN1->sFilterRegister[index].FR1 = filter.
FR1;
257 CAN1->sFilterRegister[index].FR2 = filter.
FR2;
261 CAN1->FFA1R |= (filter.
fifo & 0x1) << index;
264 CAN1->FA1R |= 1 << index;
277 LOG_ERR(ls,
"Canbus is not initialized!");
281 bool didWait =
false;
284 miosix::FastInterruptDisableLock d;
287 while ((can->TSR & CAN_TSR_TME) == 0)
290 waiting = Thread::IRQgetCurrentThread();
293 miosix::FastInterruptEnableLock e(d);
306 uint8_t mbxCode = (can->TSR & CAN_TSR_CODE) >> 24;
310 LOG_ERR(ls,
"Error! Invalid TSR_CODE!");
314 uint32_t seq = txSeq++;
315 txMailboxSeq[mbxCode] = seq;
317 CAN_TxMailBox_TypeDef* mailbox = &can->sTxMailBox[mbxCode];
319 can->sTxMailBox[mbxCode].TIR &= CAN_TI0R_TXRQ;
322 can->sTxMailBox[mbxCode].TIR |= ((packet.
id & 0x1FFFFFFF) << 3);
323 can->sTxMailBox[mbxCode].TIR |= 1 << 2;
327 can->sTxMailBox[mbxCode].TIR |= ((packet.
id & 0x7FF) << 21);
330 can->sTxMailBox[mbxCode].TIR |= (packet.
rtr ? 1 : 0) << 1;
332 mailbox->TDTR = (packet.
length & 0xF);
339 for (uint8_t i = 0; i < packet.
length; ++i)
341 mailbox->TDLR |= packet.
data[i] << i * 8;
343 mailbox->TDHR |= packet.
data[i] << (i - 4) * 8;
346 can->sTxMailBox[mbxCode].TIR |= CAN_TI0R_TXRQ;
355 volatile uint32_t* RFR;
356 CAN_FIFOMailBox_TypeDef* mailbox;
358 mailbox = &can->sFIFOMailBox[
fifo];
365 status.
fifoFull = (*RFR & CAN_RF0R_FULL0) > 0;
373 if ((*RFR & CAN_RF0R_FMP0) > 0)
377 status.
rxStatus = *RFR & (CAN_RF0R_FULL0 | CAN_RF0R_FOVR0) >> 3;
378 status.
errCode = (can->ESR | CAN_ESR_LEC) >> 4;
381 p.ext = (mailbox->RIR & CAN_RI0R_IDE) > 0;
382 p.rtr = (mailbox->RIR & CAN_RI0R_RTR) > 0;
385 p.id = (mailbox->RIR >> 3) & 0x1FFFFFFF;
387 p.id = (mailbox->RIR >> 21) & 0x7FF;
389 p.length = mailbox->RDTR & CAN_RDT0R_DLC;
391 for (uint8_t i = 0; i < p.length; i++)
393 p.data[i] = (mailbox->RDLR >> (i * 8)) & 0xFF;
395 p.data[i] = (mailbox->RDHR >> ((i - 4) * 8)) & 0xFF;
397 *RFR |= CAN_RF0R_RFOM0;
404 miosix::Scheduler::IRQfindNextThread();
411 waiting->IRQwakeup();
#define LOG_INFO(logger,...)
#define LOG_ERR(logger,...)
#define LOG_WARN_ASYNC(logger,...)
#define LOG_DEBUG(logger,...)
Low level CanBus driver, with support for both peripherals (CAN1 and CAN2) on stm32f4 microcontroller...
uint32_t send(CanPacket packet)
Sends a packet on the bus. This function blocks until the message has been successfully put into a TX...
CanbusDriver(CAN_TypeDef *can, CanbusConfig config, AutoBitTiming bitTiming)
Construct a new Canbus object, automatically calculating timing register values from high level requi...
void handleRXInterrupt(int fifo)
Handles an incoming RX interrupt. ONLY to be called from the Canbus RX interrupt handler routine.
bool addFilter(FilterBank filter)
Adds a new filter to the bus, or returns false if there are no more filter banks available.
~CanbusDriver()
Disables the peripheral clock.
void init()
Exits initialization mode and starts CanBus operation.
void wakeTXThread()
Wakes the transmission thread. ONLY to be called from the Canbus TX interrupt handler routine.
static PrintLogger getLogger(const string &name)
PrintLogger getChild(const string &name)
CanbusDriver * canDrivers[2]
bool disablePeripheralClock(void *peripheral)
Disables a peripheral clock source from the APB1 and APB2 peripheral buses.
bool enablePeripheralClock(void *peripheral)
Enables a peripheral clock source from the APB1 and APB2 peripheral buses.
uint32_t getAPBPeripheralsClock(APB bus)
Computes the output clock frequency for peripherals on the given APB.
long long IRQgetOldTick()
Get the current time in milliseconds.
This file includes all the types the logdecoder script will decode.
bool ext
Whether to use extended packet id.
Struct defining high level bit timing requirements. Register values will then be calculated automatic...
Struct specifying exact bit timing registers values.
Configuration struct for basic CanBus operation.
Base class for a Canbus filter bank.