#pragma once #include #include namespace i2c { #if defined(__AVR_ATmega1284P__) enum class Prescaler { PRESCALER_1 = 0b00, PRESCALER_4 = 0b01, PRESCALER_16 = 0b10, PRESCALER_64 = 0b11, }; template class Hardware { public: static void init() { TWSR = static_cast(Pres); TWBR = calcClock(); } template static bool start(bool read) { TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN); while (!(TWCR & (1 << TWINT))) ; uint8_t status = TW_STATUS & 0xF8; if (status != TW_START && status != TW_REP_START) return false; TWDR = (Addr << 1) | read; TWCR = (1 << TWINT) | (1 << TWEN); while (!(TWCR & (1 << TWINT))) ; status = TW_STATUS & 0xF8; if (status != TW_MT_SLA_ACK && status != TW_MR_SLA_ACK) return false; return true; } static bool write(uint8_t data) { TWDR = data; TWCR = (1 << TWINT) | (1 << TWEN); while (!(TWCR & (1 << TWINT))) ; uint8_t status = TW_STATUS & 0xF8; if (status != TW_MT_DATA_ACK) return false; return true; } template static uint8_t read() { TWCR = (1 << TWINT) | (1 << TWEN) | (!LastByte << TWEA); while (!(TWCR & (1 << TWINT))) ; return TWDR; } static void stop() { TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO); while (TWCR & (1 << TWSTO)) ; } private: static constexpr uint8_t calcClock() { return ((F_CPU / Clock) - 16) / 2; } }; #endif } // namespace i2c