Dziś odkryłem, że tym co odczytuje zegar na TOSie 1.x to nie jest CONTROL.ACC, tylko... STE_FIX.PRG i robi to pomimo tego, że mam TOS 1.62, do którego ten patch nie jest potrzebny, co komunikuje stosownym błędem.
Odświeżanie ekranu trwa 20ms, więc nie sądzę aby ktokolwiek był w stanie zauważyć te 1,5ms. Daje radę z myszką optyczną 600DPI, więc to też raczej nie jest problemem.
Prototyp jest na płytce stykowej i module Nano v3.
Docelowe Arduino Pro Mini powinno się spokojnie zmieścić w obudowie ST, ale jeśli chcesz zaprojektować płytkę to będę bardzo wdzięczny. ATMega 328P dużym scalakiem nie jest, jest mniejsza niż ATTiny85 w obudowie DIL8. Na upartego można to przenieść na Tiny88 albo Tiny2313, ale nie wiem czy miałoby to sens.
Tak wygląda działający prototyp:
...a tak ostateczna wersja kodu:
/******************************************************************
Created with PROGRAMINO IDE for Arduino - 06.08.2018 15:23:03
Project : Atari ST IKBD clock injector with DS3231 RTC
Libraries : SoftwareSerial, Wire
Author : TzOk
Description : ARD_RX0 from KB_5, ARD_TX1 to ST_5, ARD_D10 from/to KB/ST_6
******************************************************************/
#include <SoftwareSerial.h>
#include <Wire.h>
#define DS3231_ADDRESS (0x68)
#define DS3231_REG_TIME (0x00)
SoftwareSerial Ctrl(10, 11);
byte cmd;
byte inj = 255;
byte dsDate[7];
byte stDate[7] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC};
// ss, mm, hh, DD, MM, YY
void setup()
{
Serial.begin(7812);
Ctrl.begin(7812);
Ctrl.listen();
Wire.begin();
}
void loop()
{
while(true)
{
if (Ctrl.available())
{
cmd = Ctrl.read();
if (cmd == 0x1C)
{
Wire.beginTransmission(DS3231_ADDRESS);
Wire.write(DS3231_REG_TIME);
Wire.endTransmission();
Wire.requestFrom(DS3231_ADDRESS, 7);
while(!Wire.available()) {};
for (byte i = 6; i < 255; i--)
{
dsDate[i] = Wire.read();
}
stDate[5] = (dsDate[0] < 0x80)? dsDate[0] + 0xA0 : dsDate[0]; // YY
stDate[4] = dsDate[1] & 0x1F; // MM
stDate[3] = dsDate[2]; // DD
stDate[2] = dsDate[4] & 0x3F; // hh
stDate[1] = dsDate[5]; // mm
stDate[0] = dsDate[6]; // ss
inj = 6;
}
else if (cmd == 0x1B)
{
for (byte i = 5; i < 255; i--)
{
while(!Ctrl.available()) {};
stDate[i] = Ctrl.read();
}
dsDate[0] = (stDate[5] < 0xA0 ) ? stDate[5] : stDate[5] - 0xA0; // YY
dsDate[1] = stDate[4]; // MM
dsDate[2] = stDate[3]; // DD
dsDate[4] = stDate[2]; // hh
dsDate[5] = stDate[1]; // mm
dsDate[6] = stDate[0]; // ss
Wire.beginTransmission(DS3231_ADDRESS);
Wire.write(DS3231_REG_TIME);
for (byte i = 6; i < 255; i--)
{
Wire.write(dsDate[i]);
}
Wire.endTransmission();
}
}
if (Serial.available())
{
if (inj == 255)
Serial.write(Serial.read());
else
{
Serial.read();
Serial.write(stDate[inj--]);
}
}
}
}
Trik z pętlą while(true) wewnątrz arduinowego loop() eliminuje znakomitą część kodu "dorzucaną" przez Arduino po każdym przejściu pętli głównej programu. Kod ten (SerialEvent) jest odpowiedzialny za obsługę zdarzeń portu szeregowego, z których nie korzystam. Oczywiście ideałem byłoby to przepisać na "czyste" avr-gcc.