22#ifndef I2C_HANDLER_ATTINY_HH
23#define I2C_HANDLER_ATTINY_HH
25#include <util/delay_basic.h>
35#error "i2c_handler_attiny.h shall not be directly included! Include 'i2c_handler.h' instead."
39#error "i2c_handler_attiny.h cannot be included in an ATmega program!"
47#define I2C_TRUE_ASYNC 0
55 template<I2CMode MODE_,
bool HAS_STATUS_ = false,
typename STATUS_HOOK_ = I2C_STATUS_HOOK>
56 class ATtinyI2CSyncHandler
59 using MODE_TRAIT = I2CMode_trait<MODE_>;
60 using I2C_TRAIT = board_traits::TWI_trait;
61 using REG8 = board_traits::REG8;
62 using STATUS = I2CStatusSupport<HAS_STATUS_, STATUS_HOOK_>;
65 explicit ATtinyI2CSyncHandler(STATUS_HOOK_ status_hook =
nullptr) : status_hook_{status_hook}
68 I2C_TRAIT::PORT |= I2C_TRAIT::SCL_SDA_MASK;
69 I2C_TRAIT::DDR |= I2C_TRAIT::SCL_SDA_MASK;
78 USICR_ =
bits::BV8(USIWM1, USICS1, USICLK);
80 USISR_ =
bits::BV8(USISIF, USIOIF, USIPF, USIDC);
96 return notify_status(send_start_(),
97 Status::START_TRANSMITTED, Status::ARBITRATION_LOST);
100 bool exec_repeat_start_()
102 return notify_status(send_start_(),
103 Status::REPEAT_START_TRANSMITTED, Status::ARBITRATION_LOST);
106 bool exec_send_slar_(uint8_t target)
108 return notify_status(send_byte_impl(target | 0x01U),
109 Status::SLA_R_TRANSMITTED_ACK, Status::SLA_R_TRANSMITTED_NACK);
112 bool exec_send_slaw_(uint8_t target)
114 return notify_status(send_byte_impl(target),
115 Status::SLA_W_TRANSMITTED_ACK, Status::SLA_W_TRANSMITTED_NACK);
118 bool exec_send_data_(uint8_t data)
120 return notify_status(send_byte_impl(data),
121 Status::DATA_TRANSMITTED_ACK, Status::DATA_TRANSMITTED_NACK);
124 bool exec_receive_data_(
bool last_byte, uint8_t& data)
127 data = transfer(USISR_DATA);
129 USIDR_ = (last_byte ? UINT8_MAX : 0x00);
132 return notify_status(
true, Status::DATA_RECEIVED_ACK, Status::DATA_RECEIVED_NACK);
141 _delay_loop_1(MODE_TRAIT::T_SU_STO);
144 _delay_loop_1(MODE_TRAIT::T_BUF);
148 static constexpr const REG8 USIDR_{USIDR};
149 static constexpr const REG8 USISR_{USISR};
150 static constexpr const REG8 USICR_{USICR};
154 static constexpr const uint8_t USISR_DATA =
bits::BV8(USISIF, USIOIF, USIPF, USIDC);
156 static constexpr const uint8_t USISR_ACK = USISR_DATA | (0x0E << USICNT0);
158 bool notify_status(
bool as_expected, Status good, Status bad)
160 status_hook_.call_hook(good, (as_expected ? good : bad));
166 I2C_TRAIT::PORT |=
bits::BV8(I2C_TRAIT::BIT_SCL);
167 I2C_TRAIT::PIN.loop_until_bit_set(I2C_TRAIT::BIT_SCL);
172 I2C_TRAIT::PORT &=
bits::CBV8(I2C_TRAIT::BIT_SCL);
177 I2C_TRAIT::PORT |=
bits::BV8(I2C_TRAIT::BIT_SDA);
182 I2C_TRAIT::PORT &=
bits::CBV8(I2C_TRAIT::BIT_SDA);
187 I2C_TRAIT::DDR &=
bits::CBV8(I2C_TRAIT::BIT_SDA);
192 I2C_TRAIT::DDR |=
bits::BV8(I2C_TRAIT::BIT_SDA);
200 _delay_loop_1(MODE_TRAIT::T_SU_STA);
204 _delay_loop_1(MODE_TRAIT::T_HD_STA);
213 bool send_byte_impl(uint8_t data)
219 transfer(USISR_DATA);
222 return ((transfer(USISR_ACK) & 0x01U) == 0);
225 uint8_t transfer(uint8_t USISR_count)
229 USISR_ = USISR_count;
232 _delay_loop_1(MODE_TRAIT::T_LOW);
234 USICR_ =
bits::BV8(USIWM1, USICS1, USICLK, USITC);
235 I2C_TRAIT::PIN.loop_until_bit_set(I2C_TRAIT::BIT_SCL);
236 _delay_loop_1(MODE_TRAIT::T_HIGH);
238 USICR_ =
bits::BV8(USIWM1, USICS1, USICLK, USITC);
240 while ((USISR_ &
bits::BV8(USIOIF)) == 0);
241 _delay_loop_1(MODE_TRAIT::T_LOW);
243 uint8_t data = USIDR_;
277 template<I2CMode MODE_,
bool HAS_STATUS_,
typename STATUS_HOOK_,
bool HAS_DEBUG_,
typename DEBUG_HOOK_>
280 MODE_, STATUS_HOOK_, HAS_DEBUG_, DEBUG_HOOK_>
284 MODE_, STATUS_HOOK_, HAS_DEBUG_, DEBUG_HOOK_>;
295 STATUS_HOOK_ status_hook =
nullptr, DEBUG_HOOK_ debug_hook =
nullptr)
296 :
PARENT{status_hook, debug_hook} {}
299 template<
typename>
friend class I2CDevice;
310 template<I2CMode MODE_>
332 template<I2CMode MODE_,
typename STATUS_HOOK_ = I2C_STATUS_HOOK>
333 class I2CSyncStatusManager :
334 public AbstractI2CSyncATtinyManager<MODE_, true, STATUS_HOOK_, false, I2C_DEBUG_HOOK>
336 using PARENT = AbstractI2CSyncATtinyManager<MODE_, true, STATUS_HOOK_, false, I2C_DEBUG_HOOK>;
339 explicit I2CSyncStatusManager(STATUS_HOOK_ status_hook) : PARENT{status_hook} {}
354 template<I2CMode MODE_,
typename DEBUG_HOOK_ = I2C_DEBUG_HOOK>
355 class I2CSyncDebugManager :
356 public AbstractI2CSyncATtinyManager<MODE_, false, I2C_STATUS_HOOK, true, DEBUG_HOOK_>
358 using PARENT = AbstractI2CSyncATtinyManager<MODE_, false, I2C_STATUS_HOOK, true, DEBUG_HOOK_>;
361 explicit I2CSyncDebugManager(DEBUG_HOOK_ debug_hook) : PARENT{nullptr, debug_hook} {}
380 template<I2CMode MODE_,
typename STATUS_HOOK_ = I2C_STATUS_HOOK,
typename DEBUG_HOOK_ = I2C_DEBUG_HOOK>
381 class I2CSyncStatusDebugManager :
382 public AbstractI2CSyncATtinyManager<MODE_, true, STATUS_HOOK_, true, DEBUG_HOOK_>
384 using PARENT = AbstractI2CSyncATtinyManager<MODE_, true, STATUS_HOOK_, true, DEBUG_HOOK_>;
387 explicit I2CSyncStatusDebugManager(STATUS_HOOK_ status_hook, DEBUG_HOOK_ debug_hook)
388 : PARENT{status_hook, debug_hook} {}
Useful bits manipulation utilities.
Base class for all FakeFutures.
Actual FakeFuture, it has the exact same API as Future and can be used in lieu of Future.
Abstract synchronous I2C Manager for ATtiny architecture.
Abstract synchronous I2C Manager for all MCU architectures.
future::AbstractFakeFuture ABSTRACT_FUTURE
The abstract base class of all futures to be defined for this I2C Manager.
Base class for all I2C devices.
Synchronous I2C Manager for ATmega architecture.
Utility API to handle the concept of futures.
I2C API common definitions.
static constexpr uint8_t CBV8(uint8_t bit)
Create a uint8_t inverted bitmask for the given bit number.
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Define API to define and manage I2C devices.
General utilities API that have broad application in programs.