23#ifdef _ARCH_CORTEXM7_STM32F7
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 =
68I2CTimings calculateTimings(uint32_t f, uint32_t fi2c)
70 I2CTimings i2cTimings;
75 uint32_t temp_presc = f / (64 * fi2c);
77#if defined(STM32F756xx)
78 const uint16_t correction = 10;
79#elif defined(STM32F767xx)
80 const uint16_t correction = 7;
82 const uint16_t correction = 0;
84 "I2C Timings not corrected, actual frequency could be lower than nominal"
89 i2cTimings.presc = 15;
90 else if (temp_presc == 0)
93 i2cTimings.presc = temp_presc - 1;
98 i2cTimings.sclh = i2cTimings.scll =
99 (f / (fi2c * 2 * (i2cTimings.presc + 1)) - 1) -
100 (correction / (i2cTimings.presc + 1));
105 uint32_t scldly = 0, sdadly = 0;
108 scldly = 1250 * f / (i2cTimings.presc + 1) / 1000000;
109 sdadly = (3450 - 1000 - 260) * f / (i2cTimings.presc + 1) / 1000000;
111 else if (fi2c == 400)
113 scldly = 400 * f / (i2cTimings.presc + 1) / 1000000;
114 sdadly = (900 - 300 - 260) * f / (i2cTimings.presc + 1) / 1000000;
116 else if (fi2c == 1000)
118 scldly = 170 * f / (i2cTimings.presc + 1) / 1000000;
119 sdadly = (450 - 120 - 260) * f / (i2cTimings.presc + 1) / 1000000;
123 i2cTimings.scldel = ((scldly < 16) ? (scldly - 1) : 15);
126 i2cTimings.sdadel = ((sdadly < 16) ? (sdadly - 1) : 15);
147 static const I2CTimings i2cTimingsStd = calculateTimings(f, 100);
148 static const I2CTimings i2cTimingsFast = calculateTimings(f, 400);
149 static const I2CTimings i2cTimingsFastPlus = calculateTimings(f, 1000);
156 return i2cTimingsStd;
158 return i2cTimingsFast;
159 case Boardcore::I2CDriver::Speed::FAST_PLUS:
160 return i2cTimingsFastPlus;
162 D(assert(
false &&
"Speed mode not supported!"));
163 return i2cTimingsStd;
174 asm volatile(
"bl _Z15I2C1HandlerImplv");
183 auto* port = I2CConsts::ports[0];
185 port->IRQhandleInterrupt();
194 asm volatile(
"bl _Z18I2C1errHandlerImplv");
203 auto* port = I2CConsts::ports[0];
205 port->IRQhandleErrInterrupt();
216 asm volatile(
"bl _Z15I2C2HandlerImplv");
225 auto* port = I2CConsts::ports[1];
227 port->IRQhandleInterrupt();
236 asm volatile(
"bl _Z18I2C2errHandlerImplv");
245 auto* port = I2CConsts::ports[1];
247 port->IRQhandleErrInterrupt();
258 asm volatile(
"bl _Z15I2C3HandlerImplv");
267 auto* port = I2CConsts::ports[2];
269 port->IRQhandleInterrupt();
278 asm volatile(
"bl _Z18I2C3errHandlerImplv");
287 auto* port = I2CConsts::ports[2];
289 port->IRQhandleErrInterrupt();
300 asm volatile(
"bl _Z15I2C4HandlerImplv");
309 auto* port = I2CConsts::ports[3];
311 port->IRQhandleInterrupt();
320 asm volatile(
"bl _Z18I2C4errHandlerImplv");
329 auto* port = I2CConsts::ports[3];
331 port->IRQhandleErrInterrupt();
339 : i2c(i2c), scl(scl), sda(sda), transaction()
342 switch (
reinterpret_cast<uint32_t
>(i2c))
347 irqnEv = I2C1_EV_IRQn;
348 irqnErr = I2C1_ER_IRQn;
354 irqnEv = I2C2_EV_IRQn;
355 irqnErr = I2C2_ER_IRQn;
361 irqnEv = I2C3_EV_IRQn;
362 irqnErr = I2C3_ER_IRQn;
368 irqnEv = I2C4_EV_IRQn;
369 irqnErr = I2C4_ER_IRQn;
375 "I2C peripheral not present in this architecture"));
380 miosix::FastInterruptDisableLock dLock;
386 scl.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
387 sda.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
388 scl.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
389 sda.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
394 D(assert(I2CConsts::ports[
id - 1] ==
nullptr));
397 ClockUtils::enablePeripheralClock(i2c);
402 I2CConsts::ports[
id - 1] =
this;
405 NVIC_SetPriority(irqnEv, 15);
406 NVIC_ClearPendingIRQ(irqnEv);
407 NVIC_EnableIRQ(irqnEv);
408 NVIC_SetPriority(irqnErr, 15);
409 NVIC_ClearPendingIRQ(irqnErr);
410 NVIC_EnableIRQ(irqnErr);
413I2CDriver::~I2CDriver()
416 I2CConsts::ports[
id - 1] =
nullptr;
419 NVIC_DisableIRQ(irqnEv);
420 NVIC_DisableIRQ(irqnErr);
423 i2c->CR1 &= ~I2C_CR1_PE;
426 ClockUtils::disablePeripheralClock(i2c);
429void I2CDriver::init()
436 getTimings(I2CDriver::Speed::STANDARD);
439 i2c->CR1 |= I2C_CR1_PE;
442bool I2CDriver::read(
const I2CSlaveConfig& slaveConfig,
void* buffer,
443 const size_t& nBytes)
446 transaction.operation = Operation::READ;
447 transaction.buffWrite =
nullptr;
448 transaction.buffRead =
static_cast<uint8_t*
>(buffer);
449 transaction.nBytes = nBytes;
450 transaction.nBytesDone = 0;
451 transaction.generateStop =
true;
454 i2c->CR1 &= ~I2C_CR1_TXIE;
455 i2c->CR1 |= I2C_CR1_RXIE;
458 return doOperation(slaveConfig);
461bool I2CDriver::write(
const I2CSlaveConfig& slaveConfig,
const void* buffer,
462 const size_t& nBytes,
bool generateStop)
465 transaction.operation = Operation::WRITE;
466 transaction.buffWrite =
static_cast<const uint8_t*
>(buffer);
467 transaction.buffRead =
nullptr;
468 transaction.nBytes = nBytes;
469 transaction.nBytesDone = 0;
470 transaction.generateStop = generateStop;
473 i2c->CR1 &= ~I2C_CR1_RXIE;
474 i2c->CR1 |= I2C_CR1_TXIE;
477 return doOperation(slaveConfig);
480bool I2CDriver::doOperation(
const I2CSlaveConfig& slaveConfig)
483 D(assert(slaveConfig.addressing == Addressing::BIT7 &&
484 "Only 7-bit addressing supported!"));
487 if (lastError & Errors::BUS_LOCKED)
499 for (; (i < I2CConsts::MAX_N_POLLING) && (i2c->ISR & I2C_ISR_BUSY); ++i)
503 if (i == I2CConsts::MAX_N_POLLING)
505 lastError = Errors::BUS_LOCKED;
506 LOG_ERR(logger, fmt::format(
"I2C{} bus locked state detected",
id));
512 setupPeripheral(slaveConfig);
523 i2c->ICR |= (I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
524 I2C_ICR_OVRCF | I2C_ICR_STOPCF);
530 miosix::FastInterruptDisableLock dLock;
537 i2c->CR2 |= I2C_CR2_START;
543 if (transaction.generateStop)
544 i2c->CR2 |= I2C_CR2_AUTOEND;
546 i2c->CR2 &= ~I2C_CR2_AUTOEND;
552 return IRQwaitForOperationCompletion(dLock);
556void I2CDriver::setupPeripheral(
const I2CSlaveConfig& slaveConfig)
561 i2c->CR1 &= ~I2C_CR1_PE;
563 const auto i2cTimings = getTimings(slaveConfig.speed);
567 i2c->TIMINGR = (i2cTimings.presc << I2C_TIMINGR_PRESC_Pos) |
568 (i2cTimings.scll << I2C_TIMINGR_SCLL_Pos) |
569 (i2cTimings.sclh << I2C_TIMINGR_SCLH_Pos) |
570 (i2cTimings.scldel << I2C_TIMINGR_SCLDEL_Pos) |
571 (i2cTimings.sdadel << I2C_TIMINGR_SDADEL_Pos);
576 (slaveConfig.addressing == Addressing::BIT10 ? I2C_CR2_ADD10 : 0) |
577 (slaveConfig.slaveAddress << (I2C_CR2_SADD_Pos + 1));
580 i2c->CR1 |= I2C_CR1_PE;
583void I2CDriver::setupTransaction()
586 if (transaction.operation == Operation::READ)
587 i2c->CR2 |= I2C_CR2_RD_WRN;
589 i2c->CR2 &= ~I2C_CR2_RD_WRN;
595void I2CDriver::setupReload()
600 if ((transaction.nBytes - transaction.nBytesDone) <= 0xffu)
603 (i2c->CR2 & ~(I2C_CR2_NBYTES_Msk |
605 ((transaction.nBytes - transaction.nBytesDone)
606 << I2C_CR2_NBYTES_Pos);
610 i2c->CR2 |= (I2C_CR2_RELOAD |
615void I2CDriver::flushBus()
618 if (!((lastError & (Errors::BUS_LOCKED | Errors::BERR)) &&
619 ((i2c->ISR & I2C_ISR_BUSY))))
625 uint8_t toggleDelay = 5;
628 miosix::FastInterruptDisableLock dLock;
633 scl.mode(miosix::Mode::OPEN_DRAIN_PULL_UP);
636 for (
size_t c = 0; c < I2CConsts::N_SCL_BITBANG; c++)
639 miosix::delayUs(toggleDelay);
641 miosix::delayUs(toggleDelay);
645 miosix::FastInterruptDisableLock dLock;
648 scl.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
649 scl.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
657 lastError = Errors::NO_ERROR;
659 LOG_WARN(logger, fmt::format(
"I2C{} Bus flushed",
id));
662uint16_t I2CDriver::getLastError() {
return lastError; }
664inline bool I2CDriver::IRQwaitForOperationCompletion(
665 miosix::FastInterruptDisableLock& dLock)
668 waiting = miosix::Thread::IRQgetCurrentThread();
671 i2c->CR1 |= (I2C_CR1_ERRIE |
681 miosix::FastInterruptEnableLock eLock(dLock);
689 lastError |= ((error & I2C_ISR_OVR) ? Errors::OVR : 0) |
690 ((error & I2C_ISR_BERR) ? Errors::BERR : 0) |
691 ((error & I2C_ISR_ARLO) ? Errors::ARLO : 0);
697 lastError = Errors::NO_ERROR;
701inline void I2CDriver::IRQwakeUpWaitingThread()
705 transaction.buffRead =
nullptr;
706 transaction.buffWrite =
nullptr;
709 i2c->CR1 &= ~(I2C_CR1_ERRIE |
718 waiting->IRQwakeup();
720 if (waiting->IRQgetPriority() >
721 miosix::Thread::IRQgetCurrentThread()->IRQgetPriority())
723 miosix::Scheduler::IRQfindNextThread();
730void I2CDriver::IRQhandleInterrupt()
733 if (i2c->ISR & I2C_ISR_NACKF)
738 lastError |= Errors::AF;
739 i2c->ICR |= I2C_ICR_NACKCF;
740 IRQwakeUpWaitingThread();
745 if (i2c->ISR & I2C_ISR_TCR)
748 if (transaction.nBytesDone < transaction.nBytes)
751 if (i2c->ISR & I2C_ISR_RXNE)
754 transaction.buffRead[transaction.nBytesDone] =
755 static_cast<uint8_t
>(i2c->RXDR);
756 transaction.nBytesDone++;
758 else if (i2c->ISR & (I2C_ISR_TXIS | I2C_ISR_TXE))
761 i2c->TXDR =
static_cast<uint32_t
>(
762 transaction.buffWrite[transaction.nBytesDone]);
763 transaction.nBytesDone++;
768 if (i2c->ISR & I2C_ISR_STOPF)
771 i2c->ICR |= I2C_ICR_STOPCF;
773 if (transaction.nBytesDone < transaction.nBytes)
776 lastError |= Errors::BERR;
780 IRQwakeUpWaitingThread();
785 if ((i2c->ISR & I2C_ISR_TC) &&
786 (transaction.nBytesDone >= transaction.nBytes))
788 if (transaction.generateStop)
791 i2c->CR2 |= I2C_CR2_STOP;
797 IRQwakeUpWaitingThread();
803void I2CDriver::IRQhandleErrInterrupt()
805 error = (i2c->ISR | (1 << 24));
808 i2c->ICR |= (I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
809 I2C_ICR_OVRCF | I2C_ICR_STOPCF);
812 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.
uint32_t getAPBPeripheralsClock(APB bus)
Computes the output clock frequency for peripherals on the given APB.
This file includes all the types the logdecoder script will decode.