23#ifdef _ARCH_CORTEXM4_STM32F4
26#include <kernel/scheduler/scheduler.h>
37static const int MAX_N_POLLING =
39static const int N_SCL_BITBANG =
41static const uint8_t I2C_PIN_ALTERNATE_FUNCTION =
53 asm volatile(
"bl _Z15I2C1HandlerImplv");
62 auto* port = I2CConsts::ports[0];
64 port->IRQhandleInterrupt();
73 asm volatile(
"bl _Z18I2C1errHandlerImplv");
82 auto* port = I2CConsts::ports[0];
84 port->IRQhandleErrInterrupt();
95 asm volatile(
"bl _Z15I2C2HandlerImplv");
104 auto* port = I2CConsts::ports[1];
106 port->IRQhandleInterrupt();
115 asm volatile(
"bl _Z18I2C2errHandlerImplv");
124 auto* port = I2CConsts::ports[1];
126 port->IRQhandleErrInterrupt();
137 asm volatile(
"bl _Z15I2C3HandlerImplv");
146 auto* port = I2CConsts::ports[2];
148 port->IRQhandleInterrupt();
157 asm volatile(
"bl _Z18I2C3errHandlerImplv");
166 auto* port = I2CConsts::ports[2];
168 port->IRQhandleErrInterrupt();
179 asm volatile(
"bl _Z15I2C4HandlerImplv");
188 auto* port = I2CConsts::ports[3];
190 port->IRQhandleInterrupt();
199 asm volatile(
"bl _Z18I2C4errHandlerImplv");
208 auto* port = I2CConsts::ports[3];
210 port->IRQhandleErrInterrupt();
218 : i2c(i2c), scl(scl), sda(sda), transaction()
221 switch (
reinterpret_cast<uint32_t
>(i2c))
226 irqnEv = I2C1_EV_IRQn;
227 irqnErr = I2C1_ER_IRQn;
233 irqnEv = I2C2_EV_IRQn;
234 irqnErr = I2C2_ER_IRQn;
240 irqnEv = I2C3_EV_IRQn;
241 irqnErr = I2C3_ER_IRQn;
247 irqnEv = I2C4_EV_IRQn;
248 irqnErr = I2C4_ER_IRQn;
254 "I2C peripheral not present in this architecture"));
259 miosix::FastInterruptDisableLock dLock;
265 scl.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
266 sda.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
267 scl.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
268 sda.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
273 D(assert(I2CConsts::ports[
id - 1] ==
nullptr));
276 ClockUtils::enablePeripheralClock(i2c);
281 I2CConsts::ports[
id - 1] =
this;
284 NVIC_SetPriority(irqnEv, 15);
285 NVIC_ClearPendingIRQ(irqnEv);
286 NVIC_EnableIRQ(irqnEv);
287 NVIC_SetPriority(irqnErr, 15);
288 NVIC_ClearPendingIRQ(irqnErr);
289 NVIC_EnableIRQ(irqnErr);
292I2CDriver::~I2CDriver()
295 I2CConsts::ports[
id - 1] =
nullptr;
298 NVIC_DisableIRQ(irqnEv);
299 NVIC_DisableIRQ(irqnErr);
302 i2c->CR1 &= ~I2C_CR1_PE;
305 ClockUtils::disablePeripheralClock(i2c);
308void I2CDriver::init()
311 i2c->CR1 = I2C_CR1_SWRST;
317 ClockUtils::getAPBPeripheralsClock(ClockUtils::APB::APB1) / 1000000;
320 D(assert(I2CConsts::f <= 50));
324 i2c->CR2 = (I2CConsts::f & I2C_CR2_FREQ) |
328void I2CDriver::setupPeripheral(
const I2CSlaveConfig& slaveConfig)
332 D(assert((slaveConfig.speed == STANDARD && I2CConsts::f >= 2) ||
333 (slaveConfig.speed == FAST && I2CConsts::f >= 4)));
336 i2c->CR1 &= ~I2C_CR1_PE;
339 if (slaveConfig.speed == Speed::STANDARD)
348 else if (slaveConfig.speed == Speed::FAST)
351 i2c->CCR = I2C_CCR_FS |
352 I2CConsts::f * 5 / 6;
361 D(assert(
false &&
"speed not supported!"));
365 i2c->TRISE = (I2CConsts::f & I2C_CR2_FREQ) + 1;
368 i2c->OAR1 = (slaveConfig.addressing << 15);
371 i2c->CR1 |= I2C_CR1_PE;
374bool I2CDriver::read(
const I2CSlaveConfig& slaveConfig,
void* buffer,
375 const size_t& nBytes)
378 transaction.operation = Operation::READ;
379 transaction.buffWrite =
nullptr;
380 transaction.buffRead =
static_cast<uint8_t*
>(buffer);
381 transaction.nBytes = nBytes;
382 transaction.nBytesDone = 0;
383 transaction.generateStop =
true;
388 ((nBytes <= 1) ? (i2c->CR1 & ~I2C_CR1_ACK) : (i2c->CR1 | I2C_CR1_ACK));
391 return doOperation(slaveConfig);
394bool I2CDriver::write(
const I2CSlaveConfig& slaveConfig,
const void* buffer,
395 const size_t& nBytes,
bool generateStop)
398 transaction.operation = Operation::WRITE;
399 transaction.buffWrite =
static_cast<const uint8_t*
>(buffer);
400 transaction.buffRead =
nullptr;
401 transaction.nBytes = nBytes;
402 transaction.nBytesDone = 0;
403 transaction.generateStop = generateStop;
406 return doOperation(slaveConfig);
409bool I2CDriver::doOperation(
const I2CSlaveConfig& slaveConfig)
412 D(assert(slaveConfig.addressing == Addressing::BIT7 &&
413 "Only 7-bit addressing supported!"));
416 if (lastError & Errors::BUS_LOCKED)
428 for (; (i < I2CConsts::MAX_N_POLLING) && (i2c->SR2 & I2C_SR2_BUSY); ++i)
432 if (i == I2CConsts::MAX_N_POLLING)
434 lastError = Errors::BUS_LOCKED;
435 LOG_ERR(logger, fmt::format(
"I2C{} bus locked state detected",
id));
441 setupPeripheral(slaveConfig);
450 miosix::PauseKernelLock dLock;
460 i2c->CR1 |= I2C_CR1_START;
463 for (; (i < I2CConsts::MAX_N_POLLING) &&
464 (!(i2c->SR1 & I2C_SR1_SB) || !(i2c->SR2 & I2C_SR2_MSL));
469 if (i == I2CConsts::MAX_N_POLLING)
471 lastError |= Errors::SB_NOT_SENT;
473 fmt::format(
"I2C{} bus didn't send the start bit",
id));
478 transaction.nBytesDone = 0;
482 miosix::FastInterruptDisableLock dLock;
485 i2c->DR = ((slaveConfig.slaveAddress << 1) | transaction.operation);
491 return IRQwaitForOperationCompletion(dLock);
495void I2CDriver::flushBus()
498 if (!(lastError & Errors::BUS_LOCKED))
502 uint8_t toggleDelay = 5;
505 miosix::FastInterruptDisableLock dLock;
510 scl.mode(miosix::Mode::OPEN_DRAIN_PULL_UP);
513 for (
size_t c = 0; c < I2CConsts::N_SCL_BITBANG; c++)
516 miosix::delayUs(toggleDelay);
518 miosix::delayUs(toggleDelay);
522 miosix::FastInterruptDisableLock dLock;
525 scl.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
526 scl.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
534 lastError = Errors::NO_ERROR;
536 LOG_WARN(logger, fmt::format(
"I2C{} Bus flushed",
id));
539uint16_t I2CDriver::getLastError() {
return lastError; }
541inline bool I2CDriver::IRQwaitForOperationCompletion(
542 miosix::FastInterruptDisableLock& dLock)
545 waiting = miosix::Thread::IRQgetCurrentThread();
552 i2c->CR2 |= I2C_CR2_ITEVTEN | I2C_CR2_ITERREN;
553 miosix::FastInterruptEnableLock eLock(dLock);
561 lastError |= ((error & I2C_SR1_OVR) ? Errors::OVR : 0) |
562 ((error & I2C_SR1_BERR) ? Errors::BERR : 0) |
563 ((error & I2C_SR1_ARLO) ? Errors::ARLO : 0) |
564 ((error & I2C_SR1_AF) ? Errors::AF : 0);
570 lastError = Errors::NO_ERROR;
576inline void I2CDriver::IRQwakeUpWaitingThread()
580 i2c->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITERREN);
584 transaction.buffRead =
nullptr;
585 transaction.buffWrite =
nullptr;
589 waiting->IRQwakeup();
591 if (waiting->IRQgetPriority() >
592 miosix::Thread::IRQgetCurrentThread()->IRQgetPriority())
594 miosix::Scheduler::IRQfindNextThread();
601void I2CDriver::IRQhandleInterrupt()
604 if ((i2c->SR1 & I2C_SR1_ADDR))
607 if (!(i2c->SR2 & I2C_SR2_BUSY) ||
608 !(i2c->SR2 & I2C_SR2_MSL) ||
609 !((i2c->SR2 & I2C_SR2_TRA) != transaction.operation))
614 lastError |= ADDR_ERROR;
615 IRQwakeUpWaitingThread();
621 if (transaction.operation == Operation::READ)
624 if (i2c->SR1 & (I2C_SR1_BTF | I2C_SR1_RXNE))
628 if (transaction.nBytesDone >= transaction.nBytes - 2)
629 i2c->CR1 &= ~I2C_CR1_ACK;
631 if (transaction.nBytesDone < transaction.nBytes)
633 transaction.buffRead[transaction.nBytesDone] = i2c->DR;
634 transaction.nBytesDone++;
641 if (i2c->SR1 & (I2C_SR1_BTF | I2C_SR1_TXE))
643 if (transaction.nBytesDone < transaction.nBytes)
645 i2c->DR = transaction.buffWrite[transaction.nBytesDone];
646 transaction.nBytesDone++;
653 if (transaction.nBytesDone >= transaction.nBytes)
657 if (transaction.generateStop)
659 i2c->CR1 |= I2C_CR1_STOP;
668 IRQwakeUpWaitingThread();
672void I2CDriver::IRQhandleErrInterrupt()
682 if (!(error & I2C_SR1_ARLO))
683 i2c->CR1 |= I2C_CR1_STOP;
686 IRQwakeUpWaitingThread();
void __attribute__((naked)) CAN1_RX0_IRQHandler()
#define LOG_WARN(logger,...)
#define LOG_ERR(logger,...)
Boardcore::USART * ports[N_USART_PORTS]
< Pointer to serial port classes to let interrupts access the classes
Low level driver for I2C peripherals.
I2CDriver(I2C_TypeDef *i2c, miosix::GpioPin scl, miosix::GpioPin sda)
Constructor for the I2C low-level driver.
This file includes all the types the logdecoder script will decode.