Skyward boardcore
Loading...
Searching...
No Matches
I2CDriver-f7.cpp
Go to the documentation of this file.
1/* Copyright (c) 2022 Skyward Experimental Rocketry
2 * Author: Emilio Corigliano
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#ifdef _ARCH_CORTEXM7_STM32F7
24
25#include <assert.h>
26#include <kernel/scheduler/scheduler.h>
27#include <utils/ClockUtils.h>
28#include <utils/Debug.h>
29
30#include "I2CDriver.h"
31
32namespace I2CConsts
33{
34static Boardcore::I2CDriver* ports[N_I2C_PORTS] =
35 {};
37static const int MAX_N_POLLING =
38 2000;
39static const int N_SCL_BITBANG =
40 16;
41static const uint8_t I2C_PIN_ALTERNATE_FUNCTION =
42 4;
43} // namespace I2CConsts
44
49typedef struct
50{
51 uint8_t presc;
52 uint8_t sclh;
53 uint8_t scll;
54 uint8_t scldel;
55 uint8_t sdadel;
56} I2CTimings;
57
68I2CTimings calculateTimings(uint32_t f, uint32_t fi2c)
69{
70 I2CTimings i2cTimings;
71 // calculating the "smallest" prescaler so that we can handle in a more
72 // refined way (with SCLL and SCLH) the length of high and low phases. We
73 // "limit" SCLL and SCLH to 64 because like so we can have acceptable values
74 // for SCLDEL and SDADEL
75 uint32_t temp_presc = f / (64 * fi2c);
76
77#if defined(STM32F756xx)
78 const uint16_t correction = 10;
79#elif defined(STM32F767xx)
80 const uint16_t correction = 7;
81#else
82 const uint16_t correction = 0;
83#warning \
84 "I2C Timings not corrected, actual frequency could be lower than nominal"
85#endif
86
87 // presc is 4 bit long, so avoiding overflow
88 if (temp_presc >= 16)
89 i2cTimings.presc = 15;
90 else if (temp_presc == 0)
91 i2cTimings.presc = 0;
92 else
93 i2cTimings.presc = temp_presc - 1;
94
95 // calculating SCLL and SCLH in order to have duty cycle of 50%. Also,
96 // correcting for the 250ns delay of the peripheral (250ns = 12 I2C clocks)
97 // distributing the correction on SCLL and SCLH
98 i2cTimings.sclh = i2cTimings.scll =
99 (f / (fi2c * 2 * (i2cTimings.presc + 1)) - 1) -
100 (correction / (i2cTimings.presc + 1));
101
102 // SCLDEL >= (t_r + t_su) / ((PRESC+1)*t_i2c) - 1 ; approximated without
103 // subtracting 1. scldly and sdadly are calculated using values taken from
104 // the reference manual
105 uint32_t scldly = 0, sdadly = 0;
106 if (fi2c == 100)
107 {
108 scldly = 1250 * f / (i2cTimings.presc + 1) / 1000000;
109 sdadly = (3450 - 1000 - 260) * f / (i2cTimings.presc + 1) / 1000000;
110 }
111 else if (fi2c == 400)
112 {
113 scldly = 400 * f / (i2cTimings.presc + 1) / 1000000;
114 sdadly = (900 - 300 - 260) * f / (i2cTimings.presc + 1) / 1000000;
115 }
116 else if (fi2c == 1000)
117 {
118 scldly = 170 * f / (i2cTimings.presc + 1) / 1000000;
119 sdadly = (450 - 120 - 260) * f / (i2cTimings.presc + 1) / 1000000;
120 }
121
122 // max value of scldel is 15
123 i2cTimings.scldel = ((scldly < 16) ? (scldly - 1) : 15);
124
125 // max value of sdadel is 15
126 i2cTimings.sdadel = ((sdadly < 16) ? (sdadly - 1) : 15);
127
128 return i2cTimings;
129}
130
138const I2CTimings& getTimings(Boardcore::I2CDriver::Speed speed)
139{
140 // Retrieving the frequency of the APB relative to the I2C peripheral
141 // [kHz] (I2C peripherals are always connected to APB1, Low speed bus). In
142 // fact by default the I2C peripheral is clocked by the APB1 bus; anyway HSI
143 // and SYSCLK can be chosen.
144 static const uint32_t f = Boardcore::ClockUtils::getAPBPeripheralsClock(
146 1000;
147 static const I2CTimings i2cTimingsStd = calculateTimings(f, 100);
148 static const I2CTimings i2cTimingsFast = calculateTimings(f, 400);
149 static const I2CTimings i2cTimingsFastPlus = calculateTimings(f, 1000);
150
151 // Calculating for all the speed modes the clock parameters (so we won't
152 // have to calculate them again for every transaction)
153 switch (speed)
154 {
156 return i2cTimingsStd;
158 return i2cTimingsFast;
159 case Boardcore::I2CDriver::Speed::FAST_PLUS:
160 return i2cTimingsFastPlus;
161 default:
162 D(assert(false && "Speed mode not supported!"));
163 return i2cTimingsStd;
164 }
165}
166
167#ifdef I2C1
171void __attribute__((naked)) I2C1_EV_IRQHandler()
172{
173 saveContext();
174 asm volatile("bl _Z15I2C1HandlerImplv");
175 restoreContext();
176}
177
181void __attribute__((used)) I2C1HandlerImpl()
182{
183 auto* port = I2CConsts::ports[0];
184 if (port)
185 port->IRQhandleInterrupt();
186}
187
191void __attribute__((naked)) I2C1_ER_IRQHandler()
192{
193 saveContext();
194 asm volatile("bl _Z18I2C1errHandlerImplv");
195 restoreContext();
196}
197
201void __attribute__((used)) I2C1errHandlerImpl()
202{
203 auto* port = I2CConsts::ports[0];
204 if (port)
205 port->IRQhandleErrInterrupt();
206}
207#endif
208
209#ifdef I2C2
213void __attribute__((naked)) I2C2_EV_IRQHandler()
214{
215 saveContext();
216 asm volatile("bl _Z15I2C2HandlerImplv");
217 restoreContext();
218}
219
223void __attribute__((used)) I2C2HandlerImpl()
224{
225 auto* port = I2CConsts::ports[1];
226 if (port)
227 port->IRQhandleInterrupt();
228}
229
233void __attribute__((naked)) I2C2_ER_IRQHandler()
234{
235 saveContext();
236 asm volatile("bl _Z18I2C2errHandlerImplv");
237 restoreContext();
238}
239
243void __attribute__((used)) I2C2errHandlerImpl()
244{
245 auto* port = I2CConsts::ports[1];
246 if (port)
247 port->IRQhandleErrInterrupt();
248}
249#endif
250
251#ifdef I2C3
255void __attribute__((naked)) I2C3_EV_IRQHandler()
256{
257 saveContext();
258 asm volatile("bl _Z15I2C3HandlerImplv");
259 restoreContext();
260}
261
265void __attribute__((used)) I2C3HandlerImpl()
266{
267 auto* port = I2CConsts::ports[2];
268 if (port)
269 port->IRQhandleInterrupt();
270}
271
275void __attribute__((naked)) I2C3_ER_IRQHandler()
276{
277 saveContext();
278 asm volatile("bl _Z18I2C3errHandlerImplv");
279 restoreContext();
280}
281
285void __attribute__((used)) I2C3errHandlerImpl()
286{
287 auto* port = I2CConsts::ports[2];
288 if (port)
289 port->IRQhandleErrInterrupt();
290}
291#endif
292
293#ifdef I2C4
297void __attribute__((naked)) I2C4_EV_IRQHandler()
298{
299 saveContext();
300 asm volatile("bl _Z15I2C4HandlerImplv");
301 restoreContext();
302}
303
307void __attribute__((used)) I2C4HandlerImpl()
308{
309 auto* port = I2CConsts::ports[3];
310 if (port)
311 port->IRQhandleInterrupt();
312}
313
317void __attribute__((naked)) I2C4_ER_IRQHandler()
318{
319 saveContext();
320 asm volatile("bl _Z18I2C4errHandlerImplv");
321 restoreContext();
322}
323
327void __attribute__((used)) I2C4errHandlerImpl()
328{
329 auto* port = I2CConsts::ports[3];
330 if (port)
331 port->IRQhandleErrInterrupt();
332}
333#endif
334
335namespace Boardcore
336{
337
338I2CDriver::I2CDriver(I2C_TypeDef* i2c, miosix::GpioPin scl, miosix::GpioPin sda)
339 : i2c(i2c), scl(scl), sda(sda), transaction()
340{
341 // Setting the id and irqn of the right i2c peripheral
342 switch (reinterpret_cast<uint32_t>(i2c))
343 {
344#ifdef I2C1
345 case I2C1_BASE:
346 this->id = 1;
347 irqnEv = I2C1_EV_IRQn;
348 irqnErr = I2C1_ER_IRQn;
349 break;
350#endif
351#ifdef I2C2
352 case I2C2_BASE:
353 this->id = 2;
354 irqnEv = I2C2_EV_IRQn;
355 irqnErr = I2C2_ER_IRQn;
356 break;
357#endif
358#ifdef I2C3
359 case I2C3_BASE:
360 this->id = 3;
361 irqnEv = I2C3_EV_IRQn;
362 irqnErr = I2C3_ER_IRQn;
363 break;
364#endif
365#ifdef I2C4
366 case I2C4_BASE:
367 this->id = 4;
368 irqnEv = I2C4_EV_IRQn;
369 irqnErr = I2C4_ER_IRQn;
370 break;
371#endif
372 default:
373 // Checking that the peripheral is present in this architecture
374 D(assert(false &&
375 "I2C peripheral not present in this architecture"));
376 break;
377 }
378
379 {
380 miosix::FastInterruptDisableLock dLock;
381
382 // Initializing the alternate function and mode of the pins so we won't
383 // forget the open-drain mode, avoiding eventual short-circuits between
384 // master and slaves when they both drive the same bus on two different
385 // logical values.
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);
390 }
391
392 // Checking that this particular I2C port hasn't been already instantiated
393 D(assert(id > 0));
394 D(assert(I2CConsts::ports[id - 1] == nullptr));
395
396 // Enabling the peripheral's clock
397 ClockUtils::enablePeripheralClock(i2c);
398
399 init();
400
401 // Add to the array of i2c peripherals so that the interrupts can see it
402 I2CConsts::ports[id - 1] = this;
403
404 // Enabling the interrupts (Ev and Err) in the NVIC
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);
411}
412
413I2CDriver::~I2CDriver()
414{
415 // Removing the relative i2c port from the array
416 I2CConsts::ports[id - 1] = nullptr;
417
418 // Disabling the interrupts (Ev and Err) in the NVIC
419 NVIC_DisableIRQ(irqnEv);
420 NVIC_DisableIRQ(irqnErr);
421
422 // Disabling the peripheral
423 i2c->CR1 &= ~I2C_CR1_PE;
424
425 // Disabling the peripheral on the bus
426 ClockUtils::disablePeripheralClock(i2c);
427}
428
429void I2CDriver::init()
430{
431 // Resetting the I2C peripheral before setting the registers (resetting PE
432 // bit resets the peripheral)
433 i2c->CR1 = 0;
434
435 // Calling getTimings so that all his static variables are initialized
436 getTimings(I2CDriver::Speed::STANDARD);
437
438 // Enabling the peripheral after initialization
439 i2c->CR1 |= I2C_CR1_PE;
440}
441
442bool I2CDriver::read(const I2CSlaveConfig& slaveConfig, void* buffer,
443 const size_t& nBytes)
444{
445 // Setting up the read transaction
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;
452
453 // enabling only the RX interrupts
454 i2c->CR1 &= ~I2C_CR1_TXIE;
455 i2c->CR1 |= I2C_CR1_RXIE;
456
457 // Sending doOperation when the channel isn't busy
458 return doOperation(slaveConfig);
459};
460
461bool I2CDriver::write(const I2CSlaveConfig& slaveConfig, const void* buffer,
462 const size_t& nBytes, bool generateStop)
463{
464 // Setting up the write transaction
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;
471
472 // enabling only the TX interrupts
473 i2c->CR1 &= ~I2C_CR1_RXIE;
474 i2c->CR1 |= I2C_CR1_TXIE;
475
476 // Sending doOperation when the channel isn't busy
477 return doOperation(slaveConfig);
478};
479
480bool I2CDriver::doOperation(const I2CSlaveConfig& slaveConfig)
481{
482 // 10-bit addressing not supported
483 D(assert(slaveConfig.addressing == Addressing::BIT7 &&
484 "Only 7-bit addressing supported!"));
485
486 // If already detected a locked state return directly without loosing time
487 if (lastError & Errors::BUS_LOCKED)
488 {
489 reStarting = false;
490 return false;
491 }
492
493 // If starting a new transaction (so STOP bit sent in previous transaction),
494 // wait for the bus to be clear
495 if (!reStarting)
496 {
497 // Waiting for the bus to be clear
498 uint32_t i{0};
499 for (; (i < I2CConsts::MAX_N_POLLING) && (i2c->ISR & I2C_ISR_BUSY); ++i)
500 ;
501
502 // Locked state detected after N polling cycles
503 if (i == I2CConsts::MAX_N_POLLING)
504 {
505 lastError = Errors::BUS_LOCKED;
506 LOG_ERR(logger, fmt::format("I2C{} bus locked state detected", id));
507 return false;
508 }
509
510 // Setting up the peripheral when the bus is clear in order to
511 // communicate in the mode wanted by the slave device
512 setupPeripheral(slaveConfig);
513 }
514
515 // Setting up transaction
516 setupTransaction();
517
518 // Now proceeding as every other transaction (re-starting specific code
519 // already executed)
520 reStarting = false;
521
522 // clearing pending flags
523 i2c->ICR |= (I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
524 I2C_ICR_OVRCF | I2C_ICR_STOPCF);
525
526 // Starting the transaction with the START bit
527 // From the wait till the end of transaction it will all be executed in the
528 // event Interrupt Service Routine
529 {
530 miosix::FastInterruptDisableLock dLock;
531
532 // Sending the start condition
533 // [WARNING]: In F7 the START condition is not generated immediately
534 // when set the flag, but the peripheral waits that the bus is free for
535 // sending the START condition + slave address. This could be bad since
536 // the peripheral isn't deterministic in time.
537 i2c->CR2 |= I2C_CR2_START;
538
539 // Setting automatic stop generation if we have to generate STOP
540 // condition. This MUST be done after the START condition generation
541 // since, in case of a reStart, this would immediately end the previous
542 // transaction before the start condition is generated.
543 if (transaction.generateStop)
544 i2c->CR2 |= I2C_CR2_AUTOEND;
545 else
546 i2c->CR2 &= ~I2C_CR2_AUTOEND;
547
548 // Making the thread wait for the operation completion. The next steps
549 // will be performed in the ISR while the thread stays in waiting state.
550 // The only way the thread will be waken up are the completion of the
551 // operation or an error during the transaction.
552 return IRQwaitForOperationCompletion(dLock);
553 }
554}
555
556void I2CDriver::setupPeripheral(const I2CSlaveConfig& slaveConfig)
557{
558 // Disabling the I2C peripheral before setting the registers.
559 // This will also perform a software reset, useful to restore the internal
560 // state machines and flags in order to start with a clear environment
561 i2c->CR1 &= ~I2C_CR1_PE;
562
563 const auto i2cTimings = getTimings(slaveConfig.speed);
564
565 // Setting PRESC, SCLH, SCLL, SCLDEL and SDADEL bits in I2C_TIMINGR register
566 // to generate correct timings for each speed mode
567 i2c->TIMINGR = (i2cTimings.presc << I2C_TIMINGR_PRESC_Pos) | // PRESC
568 (i2cTimings.scll << I2C_TIMINGR_SCLL_Pos) | // SCLL
569 (i2cTimings.sclh << I2C_TIMINGR_SCLH_Pos) | // SCLH
570 (i2cTimings.scldel << I2C_TIMINGR_SCLDEL_Pos) | // SCLDEL
571 (i2cTimings.sdadel << I2C_TIMINGR_SDADEL_Pos); // SDADEL
572
573 // setting addressing mode and slave address (for 7-Bit addressing the 7
574 // bits have to be set on SADD[7:1])
575 i2c->CR2 =
576 (slaveConfig.addressing == Addressing::BIT10 ? I2C_CR2_ADD10 : 0) |
577 (slaveConfig.slaveAddress << (I2C_CR2_SADD_Pos + 1));
578
579 // Re-enabling the peripheral
580 i2c->CR1 |= I2C_CR1_PE;
581}
582
583void I2CDriver::setupTransaction()
584{
585 // Setting the direction of the transaction
586 if (transaction.operation == Operation::READ)
587 i2c->CR2 |= I2C_CR2_RD_WRN;
588 else
589 i2c->CR2 &= ~I2C_CR2_RD_WRN;
590
591 // setting registers for the remaining bytes
592 setupReload();
593}
594
595void I2CDriver::setupReload()
596{
597 // If we are left with a communication of less than 256 bytes, we can do it
598 // without reloading, otherwise we must perform the transaction with the
599 // first 255 bytes and then perform a reload operation
600 if ((transaction.nBytes - transaction.nBytesDone) <= 0xffu)
601 {
602 i2c->CR2 =
603 (i2c->CR2 & ~(I2C_CR2_NBYTES_Msk |
604 I2C_CR2_RELOAD)) | // clearing NBYTES and RELOAD
605 ((transaction.nBytes - transaction.nBytesDone)
606 << I2C_CR2_NBYTES_Pos); // Reloading right number of bytes
607 }
608 else
609 {
610 i2c->CR2 |= (I2C_CR2_RELOAD | // There must be a reload
611 I2C_CR2_NBYTES_Msk); // maximum bytes that can be sent
612 }
613}
614
615void I2CDriver::flushBus()
616{
617 // If there isn't any locked state or bus error return immediately
618 if (!((lastError & (Errors::BUS_LOCKED | Errors::BERR)) &&
619 ((i2c->ISR & I2C_ISR_BUSY))))
620 {
621 return;
622 }
623
624 // Set the period of the bit-banged clock (Default to standard mode)
625 uint8_t toggleDelay = 5;
626
627 {
628 miosix::FastInterruptDisableLock dLock;
629
630 // Recovery from the locked state due to a stuck Slave.
631 // We bit-bang 16 clocks on the scl line in order to restore pending
632 // packets of the slaves.
633 scl.mode(miosix::Mode::OPEN_DRAIN_PULL_UP);
634 }
635
636 for (size_t c = 0; c < I2CConsts::N_SCL_BITBANG; c++)
637 {
638 scl.low();
639 miosix::delayUs(toggleDelay);
640 scl.high();
641 miosix::delayUs(toggleDelay);
642 }
643
644 {
645 miosix::FastInterruptDisableLock dLock;
646
647 // We set again the scl pin to the correct Alternate function
648 scl.mode(miosix::Mode::ALTERNATE_OD_PULL_UP);
649 scl.alternateFunction(I2CConsts::I2C_PIN_ALTERNATE_FUNCTION);
650 }
651
652 // Re-initializing the peripheral in order to avoid inconsistent state
653 init();
654
655 // Assuming the locked state is solved. If it is not the case, only when
656 // it will be the case it will be detected again
657 lastError = Errors::NO_ERROR;
658
659 LOG_WARN(logger, fmt::format("I2C{} Bus flushed", id));
660}
661
662uint16_t I2CDriver::getLastError() { return lastError; }
663
664inline bool I2CDriver::IRQwaitForOperationCompletion(
665 miosix::FastInterruptDisableLock& dLock)
666{
667 // Saving the current thread in order to be waken up by interrupts
668 waiting = miosix::Thread::IRQgetCurrentThread();
669
670 // enabling interrupts for errors
671 i2c->CR1 |= (I2C_CR1_ERRIE | // interrupt for errors
672 I2C_CR1_NACKIE | // interrupt for NACKs
673 I2C_CR1_TCIE | // interrupt for TC and TCR
674 I2C_CR1_STOPIE); // interrupt for STOP detected
675
676 // flag thread as waiting, enable interrupts in I2C peripheral and yield
677 // till an interrupt doesn't wake up the thread
678 while (waiting)
679 {
680 waiting->IRQwait();
681 miosix::FastInterruptEnableLock eLock(dLock);
682 waiting->yield();
683 }
684
685 // If error occurred, parse it to notify the error(s); otherwise reset
686 // lastError parameter
687 if (error)
688 {
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);
692 error = 0;
693
694 return false;
695 }
696
697 lastError = Errors::NO_ERROR;
698 return true;
699}
700
701inline void I2CDriver::IRQwakeUpWaitingThread()
702{
703 // invalidating the buffer pointers (avoiding to keep a pointer to an old
704 // memory location)
705 transaction.buffRead = nullptr;
706 transaction.buffWrite = nullptr;
707
708 // disabling interrupts for errors
709 i2c->CR1 &= ~(I2C_CR1_ERRIE | // interrupt for errors
710 I2C_CR1_NACKIE | // interrupt for NACKs
711 I2C_CR1_TCIE | // interrupt for TC and TCR
712 I2C_CR1_STOPIE | // interrupt for STOP detected
713 I2C_CR1_TXIE | // interrupt for tx buffer
714 I2C_CR1_RXIE); // interrupt for rx buffer
715
716 if (waiting)
717 {
718 waiting->IRQwakeup();
719
720 if (waiting->IRQgetPriority() >
721 miosix::Thread::IRQgetCurrentThread()->IRQgetPriority())
722 {
723 miosix::Scheduler::IRQfindNextThread();
724 }
725
726 waiting = nullptr;
727 }
728}
729
730void I2CDriver::IRQhandleInterrupt()
731{
732 // If NACK reception, return error
733 if (i2c->ISR & I2C_ISR_NACKF)
734 {
735 // "reserved" bit in the ISR register, so we don't collide with
736 // other fields. Set to force an error
737 error = 1 << 14;
738 lastError |= Errors::AF;
739 i2c->ICR |= I2C_ICR_NACKCF;
740 IRQwakeUpWaitingThread();
741 return;
742 }
743
744 // Transfer complete reload: setting registers for the remaining bytes
745 if (i2c->ISR & I2C_ISR_TCR)
746 setupReload();
747
748 if (transaction.nBytesDone < transaction.nBytes)
749 {
750 // Performing the read/write
751 if (i2c->ISR & I2C_ISR_RXNE)
752 {
753 // READ
754 transaction.buffRead[transaction.nBytesDone] =
755 static_cast<uint8_t>(i2c->RXDR);
756 transaction.nBytesDone++;
757 }
758 else if (i2c->ISR & (I2C_ISR_TXIS | I2C_ISR_TXE))
759 {
760 // WRITE
761 i2c->TXDR = static_cast<uint32_t>(
762 transaction.buffWrite[transaction.nBytesDone]);
763 transaction.nBytesDone++;
764 }
765 }
766
767 // when stop detected on the bus
768 if (i2c->ISR & I2C_ISR_STOPF)
769 {
770 // clearing STOPF
771 i2c->ICR |= I2C_ICR_STOPCF;
772
773 if (transaction.nBytesDone < transaction.nBytes)
774 {
775 error = 1 << 14;
776 lastError |= Errors::BERR;
777 }
778
779 // waking up the waiting thread
780 IRQwakeUpWaitingThread();
781 return;
782 }
783
784 // Transfer complete (RELOAD = 0, AUTOEND = 0, NBYTES transferred)
785 if ((i2c->ISR & I2C_ISR_TC) &&
786 (transaction.nBytesDone >= transaction.nBytes))
787 {
788 if (transaction.generateStop)
789 {
790 // stop and wait for STOPF event
791 i2c->CR2 |= I2C_CR2_STOP;
792 }
793 else
794 {
795 reStarting = true;
796 // waking up the waiting thread
797 IRQwakeUpWaitingThread();
798 return;
799 }
800 }
801}
802
803void I2CDriver::IRQhandleErrInterrupt()
804{
805 error = (i2c->ISR | (1 << 24));
806
807 // Clearing all the errors in the register
808 i2c->ICR |= (I2C_ICR_ADDRCF | I2C_ICR_ARLOCF | I2C_ICR_BERRCF |
809 I2C_ICR_OVRCF | I2C_ICR_STOPCF);
810
811 // Waking up the waiting thread
812 IRQwakeUpWaitingThread();
813}
814
815} // namespace Boardcore
816
817#endif // _ARCH_CORTEXM7_STM32F7
void __attribute__((naked)) CAN1_RX0_IRQHandler()
#define D(x)
Definition Debug.h:57
#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
Definition USART.cpp:39
Low level driver for I2C peripherals.
Definition I2CDriver.h:57
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.
Definition ClockUtils.h:73
This file includes all the types the logdecoder script will decode.