| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230 |
- #include <Arduino.h>
- #include <avr/boot.h>
- #include <avr/eeprom.h>
- #include <avr/pgmspace.h>
- #include <firmware_runtime.h>
- #include <hardware_seam.h>
- #include "board_profile.h"
- static_assert(F_CPU == meCoffee::hardware::board::kClockFrequency, "Clock frequency does not match the board profile");
- static_assert(meCoffee::hardware::board::kAdcPrescaler == 128, "ADC register configuration requires prescaler 128");
- // Optional start-up padding that lines this image up with the original's start-up time in
- // differential runs. Zero in the default build.
- #ifndef MECOFFEE_CONSTRUCTION_ALIGNMENT_MICROSECONDS
- #define MECOFFEE_CONSTRUCTION_ALIGNMENT_MICROSECONDS 0
- #endif
- #ifndef MECOFFEE_SETUP_ALIGNMENT_MICROSECONDS
- #define MECOFFEE_SETUP_ALIGNMENT_MICROSECONDS 0
- #endif
- #include <mains_events.h>
- #include <pulse_tick.h>
- namespace meCoffee::hardware {
- void beginSerialLink(uint32_t baudRate) {
- #if MECOFFEE_SETUP_ALIGNMENT_MICROSECONDS > 0
- static bool isFirstCall = true;
- if (isFirstCall) {
- isFirstCall = false;
- delayMicroseconds(MECOFFEE_SETUP_ALIGNMENT_MICROSECONDS);
- }
- #endif
- Serial.begin(baudRate);
- }
- void writeSerialByte(uint8_t byteToTransmit) { Serial.write(byteToTransmit); }
- int readSerialByte() { return Serial.read(); }
- void waitForSerialTransmitCompletion() { Serial.flush(); }
- uint32_t readMillisecondCounter() { return millis(); }
- uint32_t readMicrosecondCounter() { return micros(); }
- void blockForMilliseconds(uint32_t durationInMilliseconds) { delay(durationInMilliseconds); }
- uint8_t readPersistentByte(uint16_t persistentAddress) {
- return eeprom_read_byte(reinterpret_cast<const uint8_t*>(persistentAddress));
- }
- void writePersistentByte(uint16_t persistentAddress, uint8_t byteToStore) {
- eeprom_write_byte(reinterpret_cast<uint8_t*>(persistentAddress), byteToStore);
- }
- uint8_t readProgramMemoryByte(const void* programMemoryAddress) { return pgm_read_byte(programMemoryAddress); }
- uint8_t readDeviceSignatureByte(uint8_t signatureByteIndex) {
- // The signature read must complete within a few cycles of the control write.
- const uint8_t savedStatusRegister = SREG;
- cli();
- const uint8_t signatureByte = boot_signature_byte_get(signatureByteIndex);
- SREG = savedStatusRegister;
- return signatureByte;
- }
- void configureLogicalPin(uint8_t logicalPin, PinConfiguration configuration) {
- const uint8_t physicalPin = board::physicalPin(logicalPin);
- switch (configuration) {
- case PinConfiguration::Input: pinMode(physicalPin, INPUT); break;
- case PinConfiguration::InputWithPullUp: pinMode(physicalPin, INPUT_PULLUP); break;
- case PinConfiguration::Output: pinMode(physicalPin, OUTPUT); break;
- }
- }
- void writeLogicalPin(uint8_t logicalPin, bool isHigh) { digitalWrite(board::physicalPin(logicalPin), isHigh ? HIGH : LOW); }
- bool readLogicalPin(uint8_t logicalPin) { return digitalRead(board::physicalPin(logicalPin)) != LOW; }
- void selectAnalogChannel(uint8_t channelNumber) { ADMUX = static_cast<uint8_t>(0xc0 | (board::analogChannel(channelNumber) & 0x0f)); }
- void startAnalogConversion() { ADCSRA |= _BV(ADSC); }
- bool isAnalogConversionRunning() { return (ADCSRA & _BV(ADSC)) != 0; }
- uint16_t readAnalogConversionResult() {
- const uint8_t lowByte = ADCL;
- const uint8_t highByte = ADCH;
- return static_cast<uint16_t>(lowByte | (highByte << 8));
- }
- void clearPulseOutputPins() {
- #if MECOFFEE_ARDUINO_16MHZ
- PORTD &= static_cast<uint8_t>(~(_BV(PD3) | _BV(PD4) | _BV(PD5)));
- #else
- PORTB &= static_cast<uint8_t>(~(_BV(PB1) | _BV(PB2)));
- PORTD &= static_cast<uint8_t>(~_BV(PD3));
- #endif
- }
- void writeRangeIndicatorPin(uint8_t rangeSelector, bool isHigh) {
- #if MECOFFEE_ARDUINO_16MHZ
- const uint8_t rangeMask = rangeSelector == 0 ? _BV(PC2) : _BV(PC3);
- if (isHigh) {
- PORTC |= rangeMask;
- } else {
- PORTC &= static_cast<uint8_t>(~rangeMask);
- }
- #else
- if (rangeSelector == 0) {
- if (isHigh) {
- PORTB |= _BV(PB7);
- } else {
- PORTB &= static_cast<uint8_t>(~_BV(PB7));
- }
- } else if (isHigh) {
- PORTD |= _BV(PD7);
- } else {
- PORTD &= static_cast<uint8_t>(~_BV(PD7));
- }
- #endif
- }
- void writeGenerationParityPin(bool isHigh) {
- #if MECOFFEE_ARDUINO_16MHZ
- if (isHigh) {
- PORTB |= _BV(PB3);
- } else {
- PORTB &= static_cast<uint8_t>(~_BV(PB3));
- }
- #else
- if (isHigh) {
- PORTC |= _BV(PC0);
- } else {
- PORTC &= static_cast<uint8_t>(~_BV(PC0));
- }
- #endif
- }
- void startPulseTimerAndMainsInterrupt() {
- // Mains edge: logical pin 2 (INT0), no pull-up, both edges.
- pinMode(2, INPUT);
- EICRA = static_cast<uint8_t>((EICRA & ~(_BV(ISC01) | _BV(ISC00))) | _BV(ISC00));
- EIMSK |= _BV(INT0);
- // Output pins that follow the sensor range flags and generation parity.
- #if MECOFFEE_ARDUINO_16MHZ
- DDRC |= _BV(PC2) | _BV(PC3);
- PORTC &= static_cast<uint8_t>(~(_BV(PC2) | _BV(PC3)));
- DDRB |= _BV(PB3);
- PORTB |= _BV(PB3);
- #else
- DDRB |= _BV(PB7);
- PORTB &= static_cast<uint8_t>(~_BV(PB7));
- DDRC |= _BV(PC0);
- PORTC |= _BV(PC0);
- #endif
- // Pulse timer: Timer 1, CTC, no prescaling, compare interrupt every 16.125 microseconds.
- TCCR1A = 0;
- TCCR1B = 0;
- TCNT1 = 0;
- OCR1A = board::kPulseTimerCompare;
- TCCR1B = _BV(WGM12) | _BV(CS10);
- TIMSK1 = _BV(OCIE1A);
- // Analog converter: internal reference, first temperature channel, prescaler 128.
- selectAnalogChannel(3);
- ADCSRA = _BV(ADEN) | _BV(ADPS2) | _BV(ADPS1) | _BV(ADPS0);
- }
- void disableInterrupts() { cli(); }
- void enableInterrupts() { sei(); }
- uint8_t readOscillatorCalibrationRegister() { return OSCCAL; }
- void writeOscillatorCalibrationRegister(uint8_t calibrationValue) {
- if (!board::kUsesExternalClock) {
- OSCCAL = calibrationValue;
- }
- }
- } // namespace meCoffee::hardware
- ISR(TIMER1_COMPA_vect) {
- const meCoffee::PulseTickResult tickResult = meCoffee::advancePulseTick(&meCoffee::firmwareStateStorage);
- if ((tickResult.toggleMask & 0x01) != 0) {
- PIND = _BV(PD3);
- }
- if ((tickResult.toggleMask & 0x02) != 0) {
- #if MECOFFEE_ARDUINO_16MHZ
- PIND = _BV(PD4);
- #else
- PINB = _BV(PB2);
- #endif
- }
- if ((tickResult.toggleMask & 0x04) != 0) {
- #if MECOFFEE_ARDUINO_16MHZ
- PIND = _BV(PD5);
- #else
- PINB = _BV(PB1);
- #endif
- }
- if (tickResult.shouldStartConversion) {
- ADCSRA |= _BV(ADSC);
- }
- }
- ISR(INT0_vect) { meCoffee::processMainsEdge(&meCoffee::firmwareStateStorage); }
- namespace {
- // Mirrors the original's static constructors: settings are restored before the
- // Arduino runtime starts its millisecond timer.
- struct ConstructionTimeInitializer {
- ConstructionTimeInitializer() {
- meCoffee::initializeAtConstruction();
- #if MECOFFEE_CONSTRUCTION_ALIGNMENT_MICROSECONDS > 0
- delayMicroseconds(MECOFFEE_CONSTRUCTION_ALIGNMENT_MICROSECONDS);
- #endif
- }
- };
- const ConstructionTimeInitializer constructionTimeInitializer;
- } // namespace
|