From 1f8d0f81639572aeca86ee44f9f6164e021a8837 Mon Sep 17 00:00:00 2001 From: Andrew Makousky Date: Fri, 4 Sep 2020 06:28:46 -0500 Subject: [PATCH] Fix a bunch of issues with ATTiny85 RTC implementation. Decouple from Arduino libraries, use a small header file instead. Now compiles with plain avr-gcc. Still needs more work. --- firmware/rtc/{MacPlusRTC.cpp => MacRTC.cpp} | 217 ++++++++++---------- firmware/rtc/arduino_sdef.h | 78 +++++++ firmware/rtc/domake.sh | 3 + 3 files changed, 192 insertions(+), 106 deletions(-) rename firmware/rtc/{MacPlusRTC.cpp => MacRTC.cpp} (53%) create mode 100644 firmware/rtc/arduino_sdef.h create mode 100755 firmware/rtc/domake.sh diff --git a/firmware/rtc/MacPlusRTC.cpp b/firmware/rtc/MacRTC.cpp similarity index 53% rename from firmware/rtc/MacPlusRTC.cpp rename to firmware/rtc/MacRTC.cpp index 796c708..5718ff0 100644 --- a/firmware/rtc/MacPlusRTC.cpp +++ b/firmware/rtc/MacRTC.cpp @@ -1,6 +1,9 @@ +#include #include #include -#include +#include + +#include "arduino_sdef.h" /**************************************** * * @@ -17,101 +20,53 @@ * * ****************************************/ -const int ONE_SEC_PIN = 1; // A 1Hz square wave on PB5 -const int RTC_ENABLE_PIN = 5; // Active low chip enable on PB0 -const int SERIAL_DATA_PIN = 6; // Bi-directional serial data line on PB1 -const int SERIAL_CLOCK_PIN = 7; // Serial clock input on PB2 +/********************************************* + * ATMEL ATTINY85 / ARDUINO * + * * + * +-\/-+ * + * Ain0 (D 5) PB5 1| |8 Vcc * + * Ain3 (D 3) PB3 2| |7 PB2 (D 2) Ain1 * + * Ain2 (D 4) PB4 3| |6 PB1 (D 1) pwm1 * + * GND 4| |5 PB0 (D 0) pwm0 * + * +----+ * + *********************************************/ -const int PRAM_SIZE = 256; // Mac Plus used the xPRAM chip with 256 bytes, time is a separate 4 additional bytes -//const int PRAM_SIZE = 20; // Models earlier than the Plus had 20 bytes of PRAM +const int ONE_SEC_PIN = 5; // A 1Hz square wave on PB5 +const int RTC_ENABLE_PIN = 0; // Active low chip enable on PB0 +const int SERIAL_DATA_PIN = 1; // Bi-directional serial data line on PB1 +const int SERIAL_CLOCK_PIN = 2; // Serial clock input on PB2 +#if NoXPRAM +// Models earlier than the Plus had 20 bytes of PRAM +const int PRAM_SIZE = 20; +#else +// Mac Plus used the xPRAM chip with 256 bytes +const int PRAM_SIZE = 256; +#endif + +volatile boolean lastSerClock = 0; volatile byte serialBitNum = 0; volatile byte address = 0; volatile byte serialData = 0; - -enum SerialStateType { SERIAL_DISABLED, RECEIVING_COMMAND, SENDING_DATA, RECEIVING_DATA }; +enum SerialStateType { SERIAL_DISABLED, RECEIVING_COMMAND, + SENDING_DATA, RECEIVING_DATA }; volatile SerialStateType serialState = SERIAL_DISABLED; -volatile unsigned long seconds = 0; -volatile byte pram[PRAM_SIZE] = {}; // 256 Bytes of PRAM, the first four of which count the number of seconds since 1/1/1904 - -/* - * The following is potential locations of various bits of PRAM data, none of this is in any way certain: - * Sound volume is in pram[0x08] - * Alert sound is in param[0x7c - 0x7d] - * Machine location and timezone is in pram[0xE4 - 0xEF] - */ - - -/* - * An interrupt to both increment the seconds counter and generate the square wave - */ -void halfSecondInterrupt() { - PINB = 1<>(8*i))&0xff); - } - interrupts(); // Go ahead and interrupt us while we save the rest - for(int i = 0; i < PRAM_SIZE; i++) { - EEPROM.update(i+4,pram[i]); - } -} - - -void goToSleep() { - bitClear(MCUCR,SM0); // The two SM bits must be set to 00 to enter idle mode - bitClear(MCUCR,SM1); // Sleeping in other modes will disable the timer - bitSet(MCUCR,SE); - __asm__("sleep" "\n\t"); - bitClear(MCUCR,SE); -} +// Number of seconds since midnight, January 1, 1904. Clock is +// initialized to January 1st, 1984? Or is this done by the ROM when +// the validity status is invalid? +volatile unsigned long seconds = 60 * 60 * 24 * (365 * 4 + 1) * 20; +volatile byte pram[PRAM_SIZE] = {}; // PRAM initialized as zeroed data void setup() { noInterrupts(); // Disable interrupts while we set things up - - pinMode(ONE_SEC_PIN, OUTPUT); // The 1Hz square wave (used, I think, for interrupts elsewhere in the system) - pinMode(RTC_ENABLE_PIN, INPUT_PULLUP); // The processor pulls this pin low when it wants access - pinMode(SERIAL_CLOCK_PIN, INPUT_PULLUP); // The serial clock is driven by the processor - pinMode(SERIAL_DATA_PIN, INPUT_PULLUP); // We'll need to switch this to output when sending data - + + pinModePB(ONE_SEC_PIN, OUTPUT); // The 1Hz square wave (used, I think, for interrupts elsewhere in the system) + pinModePB(RTC_ENABLE_PIN, INPUT_PULLUP); // The processor pulls this pin low when it wants access + pinModePB(SERIAL_CLOCK_PIN, INPUT_PULLUP); // The serial clock is driven by the processor + pinModePB(SERIAL_DATA_PIN, INPUT_PULLUP); // We'll need to switch this to output when sending data + wdt_disable(); // Disable watchdog bitSet(ACSR,ACD); // Disable Analog Comparator, don't need it, saves power bitSet(PRR,PRTIM1); // Disable Timer 1, only using Timer 0, Timer 1 uses around ten times as much current @@ -121,38 +76,77 @@ void setup() { bitSet(GIMSK,PCIE); // Pin Change Interrupt Enable bitSet(PCMSK,PCINT0); // turn on RTC enable interrupt -// for(int i = 0; i < 4; i++) { -// seconds += ((unsigned long)EEPROM.read(i))<<(8*i); -// } -// for(int i = 0; i < PRAM_SIZE; i--) { // Preload PRAM with saved values -// pram[i] = EEPROM.read(i+4); -// } - //set up timer bitSet(GTCCR,TSM); // Turns off timers while we set it up bitSet(TIMSK,TOIE0); // Set Timer/Counter0 Overflow Interrupt Enable TCCR0B = 0b111; // Set prescaler, 32,768Hz/64 = 512Hz, fills up the 8-bit counter (256) once every half second TCNT0 = 0; // Clear the counter bitClear(GTCCR,TSM); // Turns timers back on - + interrupts(); //We're done setting up, enable those interrupts again } +void clearState() { + // Return the pin to input mode, set pullup resistor + pinModePB(SERIAL_DATA_PIN, INPUT_PULLUP); + serialState = SERIAL_DISABLED; + lastSerClock = 0; + serialBitNum = 0; + address = 0; + serialData = 0; +} + +/* + * An interrupt to both increment the seconds counter and generate the + * square wave + */ +void halfSecondInterrupt() { + PINB = 1< 7) { boolean writeRequest = address&(1<<7); // the MSB determines if it's a write request or not address &= ~(1<<7); // Discard the first bit, it's not part of the address serialBitNum = 0; - if(writeRequest) { + if(writeRequest) { serialState = RECEIVING_DATA; serialBitNum = 0; } else { @@ -163,13 +157,13 @@ void loop() { } serialState = SENDING_DATA; serialBitNum = 0; - pinMode(SERIAL_DATA_PIN, OUTPUT); // Set the pin to output mode + pinModePB(SERIAL_DATA_PIN, OUTPUT); // Set the pin to output mode } } break; - + case RECEIVING_DATA: - bitWrite(serialData,7-serialBitNum,digitalRead(SERIAL_DATA_PIN)); + bitWrite(serialData,7-serialBitNum,digitalReadPB(SERIAL_DATA_PIN)); serialBitNum++; if(serialBitNum > 7) { if(address < 4) { @@ -179,17 +173,17 @@ void loop() { } else { pram[address] = serialData; } -// savePRAM(); clearState(); } break; - + case SENDING_DATA: - digitalWrite(SERIAL_DATA_PIN,bitRead(serialData,7-serialBitNum)); + digitalWritePB(SERIAL_DATA_PIN,bitRead(serialData,7-serialBitNum)); serialBitNum++; if(serialBitNum > 7) { clearState(); } + } } } } @@ -204,3 +198,14 @@ ISR(PCINT0_vect) { ISR(TIMER0_OVF) { halfSecondInterrupt(); } + +// Arduino main function. +int main(void) { + setup(); + + for (;;) { + loop(); + } + + return 0; +} diff --git a/firmware/rtc/arduino_sdef.h b/firmware/rtc/arduino_sdef.h new file mode 100644 index 0000000..db5704d --- /dev/null +++ b/firmware/rtc/arduino_sdef.h @@ -0,0 +1,78 @@ +#ifndef ARDUINO_SDEF_H +#define ARDUINO_SDEF_H + +/********************************************************************/ +// Simplified Arduino.h definitions. +typedef bool boolean; +typedef uint8_t byte; + +#define HIGH 0x1 +#define LOW 0x0 + +#define INPUT 0x0 +#define OUTPUT 0x1 +#define INPUT_PULLUP 0x2 + +#define interrupts() sei() +#define noInterrupts() cli() + +#define bitRead(value, bit) (((value) >> (bit)) & 0x01) +#define bitSet(value, bit) ((value) |= (1UL << (bit))) +#define bitClear(value, bit) ((value) &= ~(1UL << (bit))) +#define bitWrite(value, bit, bitvalue) ((bitvalue) ? bitSet(value, bit) : bitClear(value, bit)) +// END simplified Arduino.h definitions. + +/********************************************************************/ +// Simplified wiring_digital.c definitions. +// Only suitable for single source code file projects. + +void pinModePB(uint8_t portbit, uint8_t mode) +{ + uint8_t bit = _BV(portbit); + + if (mode == INPUT) { + uint8_t oldSREG = SREG; + cli(); + DDRB &= ~bit; + PORTB &= ~bit; + SREG = oldSREG; + } else if (mode == INPUT_PULLUP) { + uint8_t oldSREG = SREG; + cli(); + DDRB &= ~bit; + PORTB |= bit; + SREG = oldSREG; + } else { + uint8_t oldSREG = SREG; + cli(); + DDRB |= bit; + SREG = oldSREG; + } +} + +void digitalWritePB(uint8_t portbit, uint8_t val) +{ + uint8_t bit = _BV(portbit); + + uint8_t oldSREG = SREG; + cli(); + + if (val == LOW) { + PORTB &= ~bit; + } else { + PORTB |= bit; + } + + SREG = oldSREG; +} + +int digitalReadPB(uint8_t portbit) +{ + uint8_t bit = _BV(portbit); + + if (PINB & bit) return HIGH; + return LOW; +} +// END simplified wiring_digital.c definitions. + +#endif /* not ARDUINO_SDEF_H */ diff --git a/firmware/rtc/domake.sh b/firmware/rtc/domake.sh new file mode 100755 index 0000000..26af9c9 --- /dev/null +++ b/firmware/rtc/domake.sh @@ -0,0 +1,3 @@ +#! /bin/sh +avr-gcc -c -Os -mmcu=attiny85 MacRTC.cpp +avr-gcc -mmcu=attiny85 -o MacRTC.axf MacRTC.o