Jump to content
IGNORED

Atari 1050 - Track Display


macsonny

Recommended Posts

Ok this need more testing but anyways... Tandon Drive ARDUINO UNO only ATmega328 AVR Pin Change Interrupt in use 🙂

/*********************************************************************
  MIT License
  Copyright (c) [2023] [Chris O.]
  Atari 1050 - Track Display, ver 03. For Tandon Drive.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*********************************************************************/

// https://github.com/wonho-maker/Adafruit_SH1106
/*********************************************************************
  Change the adafruit SSD1306 to SH1106
  SH1106 driver don't provide several functions such as scroll commands.
*********************************************************************/
// Teensy SH1106 driver fix https://forum.pjrc.com/threads/68174-OLED-problems

#pragma message("Tandon Drive ARDUINO UNO only ATmega328 AVR Pin Change Interrupt in use")

#define DEBUG 0 // Serial(115200) SET TO 0 REMOVE DEBUG, 1 DEBUG ON

const byte VER = 03;

// NOTE: It is a good idea to connect OUTPUT-INPUT pins to other devices with
//  470ohm or 1k resistors for Short circuit current-limiting.

// ARDUINO UNO
const byte interruptPin_NS01 = 4; // NS01 @  U2 ic pin 2, NOT USED FOR interrupt.
const byte interruptPin_NS02 = 2; // NS02 @  U2 ic pin 7  Hardware interrupt.
const byte interruptPin_NS03 = 5; // NS03 @  U3 ic pin 2  For PCINT interrupt. PCINT21 -- ATmega328
const byte interruptPin_NS04 = 3; // NS04 @  U3 ic pin 7  Hardware interrupt.
const byte N_TRACK00_Pin =     6; // Look for Q5 and C47,C50 on 1050 motherboard
// connect closer to the C47,C50 side @ R#59 Track 00 sensor.
//
// MCU GND to 1050 TP15 GND (test point 15).
// Optional +5v available @ 1050 TP13.

// ATmega328 AVR HACK, PCINT pin change interrupt
bool D4_state = false;
bool D5_state = false;

volatile byte Tcount = 0;
volatile unsigned long timeNS01 = 0; // PCINT pin change interrupt TIME
volatile unsigned long timeNS02 = 0;
volatile unsigned long timeNS03 = 0; // PCINT pin change interrupt TIME
volatile unsigned long timeNS04 = 0;
bool received  = false; //

byte NewTcount = Tcount;
byte OldTcount = Tcount;

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
//TODO #include <Adafruit_SSD1306> // 0.91 Inch I2C OLED Display
#include <Adafruit_SH1106.h> // OLED 1.30" @ I2C addr. 0x3C

#define OLED_RESET -1 // -1, NO RESET
Adafruit_SH1106 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000
};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.print("Basic ARDUINO UNO 1050(For Tandon Drive) Test: v.0");
  Serial.println(VER);

  // SH1106 driver
  display.begin(SH1106_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64), SH1106 addr 0x3C.

  display.SH1106_command(0X81); // SETCONTRAST
  display.SH1106_command(255);  // VALUE 0 TO 255

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();

  display.setTextSize(2);
  // display.setTextColor(WHITE);
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setCursor(0, 5);
  display.println("Atari 1050");
  //
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 30);
  display.println("Track Display Test");
  //
  display.setCursor(10, 55);
  display.print("V.0");
  display.println(VER);
  display.display();
  // display setup for loop()
  display.clearDisplay();
  display.setCursor(5, 5);
  display.setTextSize(9);
  delay(1000);
  if (NewTcount < 10) {
    display.print("0");
  }
  display.print(NewTcount);
  display.display();

  display.SH1106_command(0X81); // SETCONTRAST
  display.SH1106_command(50);  // CONTRAST VALUE 0 TO 255

  pinMode(LED_BUILTIN, OUTPUT); // NOTE: on UNO pin 13
  pinMode(N_TRACK00_Pin, INPUT_PULLUP);
  pinMode(interruptPin_NS01, INPUT_PULLUP);
  pinMode(interruptPin_NS02, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS02), IRQ_NS02, FALLING); //RISING, CHANGE, FALLING
  pinMode(interruptPin_NS03, INPUT_PULLUP);
  pinMode(interruptPin_NS04, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS04), IRQ_NS04, RISING); //RISING, CHANGE, FALLING

  // For ATmega328 AVR ONLY, PCINT Pin Change Interrupt
  PCICR |= B00000100;      //Bit2 = 1 -> "PCIE2" enabeled (PCINT16 to PCINT23)
  PCMSK2 |= B00100000;      //Bit5 = 1 -> "PCINT21" enabeled
}


void loop() {
  // put your main code here, to run repeatedly:
  noInterrupts();
  NewTcount = Tcount;
  interrupts();

  if (digitalRead(N_TRACK00_Pin) == HIGH) { // if Track 0 sensor @5volts then set TRACK count to 0
    NewTcount = 0;
    noInterrupts();
    Tcount = 0;
    interrupts();
    received = false;
  }

  if (OldTcount != NewTcount) {

    // for debug only
    /*
      if (NewTcount > 240) {
      Serial.println("BUG1");
      Tcount = 0;
      NewTcount = 0; //
      }
      if (NewTcount > 39) { // new
      Serial.println("BUG2");
      Tcount = Tcount - 1;
      NewTcount = NewTcount - 1; //
      }
    */

    OldTcount = NewTcount;
    display.clearDisplay();
    display.setCursor(10, 4);
    if (NewTcount < 10) {
      display.print("0");
      //Serial.print("0");
    }
    display.print(NewTcount);
    display.display();
    Serial.print(" TK");
    Serial.println(NewTcount);
  }
}

// For ATmega328 AVR only
ISR (PCINT2_vect)
{
  // Another thing, during the execution of an interrupt, Arduino does not update the value of the millis and micros function.
  // So, the execution time of the ISR is not counted and the Arduino has a time lag.
  // You can use the millis and micros function to count time between two interrupts.
  // But during the interruption the time is not updated.

  // For PCINT of pins D0 a D7

  // int NS03
  if (digitalRead(5) == HIGH) {
    timeNS03 = micros();
    D5_state = true;
#if DEBUG
    Serial.print(" +N3sh:");
    Serial.print(timeNS03);
    Serial.print(" N2sh:");
    Serial.print(timeNS02);
    Serial.print(" N4sh:");
    Serial.println(timeNS04);
#endif
    if  (timeNS03 < (timeNS02 + 1200))  {
#if DEBUG
      Serial.println("  --N3sH:"); //
#endif
      if (timeNS04 < (timeNS03 + 40000)) {
        Tcount --;
      }
    }
  } else if (digitalRead(5) == LOW) {
    timeNS03 = micros();
    D5_state = false;
#if DEBUG
    Serial.print(" -N3sl:");
    Serial.print(timeNS03);
    Serial.print(" N4s:");
    Serial.println(timeNS04);
#endif
    if (timeNS03 < timeNS04 + 600 ) {
#if DEBUG
      Serial.print ("  --N3sL ");
      Serial.print(" N2s:");
      Serial.println(timeNS02);
#endif
      Tcount --;
      if (timeNS03 < timeNS02 + 31200 ) { // 31028 FOWARD Glitch Fix
        Tcount ++;
#if DEBUG
        Serial.print ("  ++N3sL");
#endif
      }
    }
  }
}

void IRQ_NS02() {
  digitalWrite(LED_BUILTIN, LOW);

  timeNS02 = micros(); // only need this for timing.
}

void IRQ_NS04() {
  digitalWrite(LED_BUILTIN, HIGH);

  timeNS04 = micros();
#if DEBUG
  Serial.print(" N4f: ");
  Serial.println(timeNS04);
#endif
  if (D5_state == true) {
    if (timeNS04 < (timeNS03 + 10400)) // 20400    10,152
    {
      Tcount ++;
#if DEBUG
      Serial.println("  ++N4f: ");
#endif
    }
  }
}

 

Link to comment
Share on other sites

11 minutes ago, Chri O. said:

Ok this need more testing but anyways... Tandon Drive ARDUINO UNO only ATmega328 AVR Pin Change Interrupt in use 🙂

/*********************************************************************
  MIT License
  Copyright (c) [2023] [Chris O.]
  Atari 1050 - Track Display, ver 03. For Tandon Drive.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*********************************************************************/

// https://github.com/wonho-maker/Adafruit_SH1106
/*********************************************************************
  Change the adafruit SSD1306 to SH1106
  SH1106 driver don't provide several functions such as scroll commands.
*********************************************************************/
// Teensy SH1106 driver fix https://forum.pjrc.com/threads/68174-OLED-problems

#pragma message("Tandon Drive ARDUINO UNO only ATmega328 AVR Pin Change Interrupt in use")

#define DEBUG 0 // Serial(115200) SET TO 0 REMOVE DEBUG, 1 DEBUG ON

const byte VER = 03;

// NOTE: It is a good idea to connect OUTPUT-INPUT pins to other devices with
//  470ohm or 1k resistors for Short circuit current-limiting.

// ARDUINO UNO
const byte interruptPin_NS01 = 4; // NS01 @  U2 ic pin 2, NOT USED FOR interrupt.
const byte interruptPin_NS02 = 2; // NS02 @  U2 ic pin 7  Hardware interrupt.
const byte interruptPin_NS03 = 5; // NS03 @  U3 ic pin 2  For PCINT interrupt. PCINT21 -- ATmega328
const byte interruptPin_NS04 = 3; // NS04 @  U3 ic pin 7  Hardware interrupt.
const byte N_TRACK00_Pin =     6; // Look for Q5 and C47,C50 on 1050 motherboard
// connect closer to the C47,C50 side @ R#59 Track 00 sensor.
//
// MCU GND to 1050 TP15 GND (test point 15).
// Optional +5v available @ 1050 TP13.

// ATmega328 AVR HACK, PCINT pin change interrupt
bool D4_state = false;
bool D5_state = false;

volatile byte Tcount = 0;
volatile unsigned long timeNS01 = 0; // PCINT pin change interrupt TIME
volatile unsigned long timeNS02 = 0;
volatile unsigned long timeNS03 = 0; // PCINT pin change interrupt TIME
volatile unsigned long timeNS04 = 0;
bool received  = false; //

byte NewTcount = Tcount;
byte OldTcount = Tcount;

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
//TODO #include <Adafruit_SSD1306> // 0.91 Inch I2C OLED Display
#include <Adafruit_SH1106.h> // OLED 1.30" @ I2C addr. 0x3C

#define OLED_RESET -1 // -1, NO RESET
Adafruit_SH1106 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000
};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.print("Basic ARDUINO UNO 1050(For Tandon Drive) Test: v.0");
  Serial.println(VER);

  // SH1106 driver
  display.begin(SH1106_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64), SH1106 addr 0x3C.

  display.SH1106_command(0X81); // SETCONTRAST
  display.SH1106_command(255);  // VALUE 0 TO 255

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();

  display.setTextSize(2);
  // display.setTextColor(WHITE);
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setCursor(0, 5);
  display.println("Atari 1050");
  //
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 30);
  display.println("Track Display Test");
  //
  display.setCursor(10, 55);
  display.print("V.0");
  display.println(VER);
  display.display();
  // display setup for loop()
  display.clearDisplay();
  display.setCursor(5, 5);
  display.setTextSize(9);
  delay(1000);
  if (NewTcount < 10) {
    display.print("0");
  }
  display.print(NewTcount);
  display.display();

  display.SH1106_command(0X81); // SETCONTRAST
  display.SH1106_command(50);  // CONTRAST VALUE 0 TO 255

  pinMode(LED_BUILTIN, OUTPUT); // NOTE: on UNO pin 13
  pinMode(N_TRACK00_Pin, INPUT_PULLUP);
  pinMode(interruptPin_NS01, INPUT_PULLUP);
  pinMode(interruptPin_NS02, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS02), IRQ_NS02, FALLING); //RISING, CHANGE, FALLING
  pinMode(interruptPin_NS03, INPUT_PULLUP);
  pinMode(interruptPin_NS04, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS04), IRQ_NS04, RISING); //RISING, CHANGE, FALLING

  // For ATmega328 AVR ONLY, PCINT Pin Change Interrupt
  PCICR |= B00000100;      //Bit2 = 1 -> "PCIE2" enabeled (PCINT16 to PCINT23)
  PCMSK2 |= B00100000;      //Bit5 = 1 -> "PCINT21" enabeled
}


void loop() {
  // put your main code here, to run repeatedly:
  noInterrupts();
  NewTcount = Tcount;
  interrupts();

  if (digitalRead(N_TRACK00_Pin) == HIGH) { // if Track 0 sensor @5volts then set TRACK count to 0
    NewTcount = 0;
    noInterrupts();
    Tcount = 0;
    interrupts();
    received = false;
  }

  if (OldTcount != NewTcount) {

    // for debug only
    /*
      if (NewTcount > 240) {
      Serial.println("BUG1");
      Tcount = 0;
      NewTcount = 0; //
      }
      if (NewTcount > 39) { // new
      Serial.println("BUG2");
      Tcount = Tcount - 1;
      NewTcount = NewTcount - 1; //
      }
    */

    OldTcount = NewTcount;
    display.clearDisplay();
    display.setCursor(10, 4);
    if (NewTcount < 10) {
      display.print("0");
      //Serial.print("0");
    }
    display.print(NewTcount);
    display.display();
    Serial.print(" TK");
    Serial.println(NewTcount);
  }
}

// For ATmega328 AVR only
ISR (PCINT2_vect)
{
  // Another thing, during the execution of an interrupt, Arduino does not update the value of the millis and micros function.
  // So, the execution time of the ISR is not counted and the Arduino has a time lag.
  // You can use the millis and micros function to count time between two interrupts.
  // But during the interruption the time is not updated.

  // For PCINT of pins D0 a D7

  // int NS03
  if (digitalRead(5) == HIGH) {
    timeNS03 = micros();
    D5_state = true;
#if DEBUG
    Serial.print(" +N3sh:");
    Serial.print(timeNS03);
    Serial.print(" N2sh:");
    Serial.print(timeNS02);
    Serial.print(" N4sh:");
    Serial.println(timeNS04);
#endif
    if  (timeNS03 < (timeNS02 + 1200))  {
#if DEBUG
      Serial.println("  --N3sH:"); //
#endif
      if (timeNS04 < (timeNS03 + 40000)) {
        Tcount --;
      }
    }
  } else if (digitalRead(5) == LOW) {
    timeNS03 = micros();
    D5_state = false;
#if DEBUG
    Serial.print(" -N3sl:");
    Serial.print(timeNS03);
    Serial.print(" N4s:");
    Serial.println(timeNS04);
#endif
    if (timeNS03 < timeNS04 + 600 ) {
#if DEBUG
      Serial.print ("  --N3sL ");
      Serial.print(" N2s:");
      Serial.println(timeNS02);
#endif
      Tcount --;
      if (timeNS03 < timeNS02 + 31200 ) { // 31028 FOWARD Glitch Fix
        Tcount ++;
#if DEBUG
        Serial.print ("  ++N3sL");
#endif
      }
    }
  }
}

void IRQ_NS02() {
  digitalWrite(LED_BUILTIN, LOW);

  timeNS02 = micros(); // only need this for timing.
}

void IRQ_NS04() {
  digitalWrite(LED_BUILTIN, HIGH);

  timeNS04 = micros();
#if DEBUG
  Serial.print(" N4f: ");
  Serial.println(timeNS04);
#endif
  if (D5_state == true) {
    if (timeNS04 < (timeNS03 + 10400)) // 20400    10,152
    {
      Tcount ++;
#if DEBUG
      Serial.println("  ++N4f: ");
#endif
    }
  }
}

 

Fantastic!

 

Any chance you can take some photos of the actual Arduino board and also the floppy drive main board to see exact wiring points?

 

Link to comment
Share on other sites

// ARDUINO UNO
Pin NS01 = 4;   // NS01 @  U2 ic pin 2, NOT USED FOR interrupt.
Pin NS02 = 2;   // NS02 @  U2 ic pin 7  Hardware interrupt.
Pin NS03 = 5;   // NS03 @  U3 ic pin 2  For PCINT interrupt. PCINT21 -- ATmega328
Pin NS04 = 3;   // NS04 @  U3 ic pin 7  Hardware interrupt.
N_TRACK00 Pin =  6; Look for Q5 and C47,C50 on 1050 motherboard connect closer to the C47,C50 side @ R#59 Track 00 sensor.
ARDUINO UNO GND to 1050 TP15 GND (test point 15).
!!!! Optional +5v available @ 1050 TP13.

Link to comment
Share on other sites

Spoiler
/*********************************************************************
  MIT License
  Copyright (c) [2023] [Chris O.]
  Atari 1050 - Track Display, ver 04. For Tandon Drive.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*********************************************************************/
const byte VER = 04;

#pragma message("Tandon Drive ARDUINO UNO only ATmega328 AVR Pin Change Interrupt in use")

// --------------------------------------------------------------------------------------------------------------
// -- Adjust as you like here -----------------------------------------------------------------------------------
// --------------------------------------------------------------------------------------------------------------
#define DEBUG 0 // Serial(115200) SET TO 0 REMOVE DEBUG, 1 DEBUG ON
// --
#define SetLib 1 // ---> 1 Adafruit_SSD1306, ---> 0 Adafruit_SH1106.
// --
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3D //<-
// See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32, 1.31 128x64 SH1106 addr 0x3C.
// --
// OLED Auto-dimming
unsigned long interval = 10000; // 10sec
const byte ContrastValueMAX = 0x7F; // MAX 127 see datasheet https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
// --------------------------------------------------------------------------------------------------------------
unsigned long preMillis = 0;
byte ContrastValue = ContrastValueMAX;
volatile byte curContrastValue = ContrastValueMAX;

// NOTE: It is a good idea to connect OUTPUT-INPUT pins to other devices with
//  470ohm or 1k resistors for Short circuit current-limiting.

// ARDUINO UNO
const byte interruptPin_NS01 = 4; // NS01 @  U2 ic pin 2, NOT USED FOR interrupt.
const byte interruptPin_NS02 = 2; // NS02 @  U2 ic pin 7  Hardware interrupt.
const byte interruptPin_NS03 = 5; // NS03 @  U3 ic pin 2  For PCINT interrupt. PCINT21 -- ATmega328
const byte interruptPin_NS04 = 3; // NS04 @  U3 ic pin 7  Hardware interrupt.
const byte N_TRACK00_Pin =     6; // Look for Q5 and C47,C50 on 1050 motherboard
// connect closer to the C47,C50 side @ R#59 Track 00 sensor.
//
// MCU GND to 1050 TP15 GND (test point 15).
// Optional +5v available @ 1050 TP13.

// ATmega328, PCINT pin change interrupt
bool D5_state = false;

volatile byte Tcount = 0;
volatile unsigned long timeNS01 = 0; //
volatile unsigned long timeNS02 = 0;
volatile unsigned long timeNS03 = 0; // PCINT pin change interrupt TIME
volatile unsigned long timeNS04 = 0;

byte NewTcount = Tcount;
byte OldTcount = Tcount;

// https://github.com/wonho-maker/Adafruit_SH1106
/*********************************************************************
  Change the adafruit SSD1306 to SH1106
  SH1106 driver don't provide several functions such as scroll commands.
*********************************************************************/
// Teensy SH1106 driver fix https://forum.pjrc.com/threads/68174-OLED-problems

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>

#if SetLib // SSD1306 driver
#include <Adafruit_SSD1306.h> // 0.91 Inch I2C OLED Display or 0.96" OLED Module I2C.
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#else // SH1106 driver
#include <Adafruit_SH1106.h> // OLED 1.30" @ I2C addr. 0x3C
Adafruit_SH1106 display(OLED_RESET);
#endif

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000
};

// -------------------------------------------------------------------------------------------------------------------------------
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 2000 );
  Serial.print("Basic ARDUINO UNO 1050(For Tandon Drive) Test: v.0");
  Serial.println(VER);

#if SetLib // SSD1306 driver
  if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
    Serial.println(F("SSD1306 allocation failed"));
    for (;;); // Don't proceed, loop forever
  }

  display.ssd1306_command(0X81); // SETCONTRAST
  display.ssd1306_command(ContrastValueMAX);  // 0 to 127

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();

  display.setTextSize(2);
  // display.setTextColor(WHITE);
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setCursor(0, 5);
  display.println("Atari 1050");
  //
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 30);
  display.println("Track Display Test");
  //
  display.setCursor(10, 55);
  display.print("V.0");
  display.println(VER);
  display.display();
  delay(1000);

  // display setup for loop()
  display.clearDisplay();
  display.setCursor(10, 4);
  display.setTextSize(9);
  if (NewTcount < 10) {
    display.print("0");
  }
  display.print(NewTcount);
  display.display();

#else // // SH1106 driver
  display.begin(SH1106_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64), SH1106 addr 0x3C.
  // display.begin(SH1106_SWITCHCAPVCC, SCREEN_ADDRESS);

  // 127 max ? see datasheet https://cdn-shop.adafruit.com/datasheets/SSD1306.pdf
  display.SH1106_command(0X81); // SETCONTRAST
  display.SH1106_command(ContrastValueMAX);

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();

  display.setTextSize(2);
  // display.setTextColor(WHITE);
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setCursor(0, 5);
  display.println("Atari 1050");
  //
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 30);
  display.println("Track Display Test");
  //
  display.setCursor(10, 55);
  display.print("V.0");
  display.println(VER);
  display.display();
  delay(1000);

  // display setup for loop()
  display.clearDisplay();
  display.setCursor(10, 4);
  display.setTextSize(9);
  if (NewTcount < 10) {
    display.print("0");
  }
  display.print(NewTcount);
  display.display();
#endif

  pinMode(LED_BUILTIN, OUTPUT); // NOTE: on UNO pin 13
  pinMode(12, OUTPUT); // 2ND LED pin 12

  pinMode(N_TRACK00_Pin, INPUT_PULLUP);
  pinMode(interruptPin_NS01, INPUT_PULLUP);
  pinMode(interruptPin_NS02, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS02), IRQ_NS02, FALLING); //RISING, CHANGE, FALLING
  pinMode(interruptPin_NS03, INPUT_PULLUP);
  pinMode(interruptPin_NS04, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS04), IRQ_NS04, RISING); //RISING, CHANGE, FALLING

  // For ATmega328 AVR ONLY, PCINT Pin Change Interrupt
  PCICR |= B00000100;      //Bit2 = 1 -> "PCIE2" enabeled (PCINT16 to PCINT23)
  PCMSK2 |= B00100000;      //Bit5 = 1 -> "PCINT21" enabeled
}

// -------------------------------------------------------------------------------------------------------------------------------
void loop() {
  // put your main code here, to run repeatedly:
  noInterrupts();
  NewTcount = Tcount;
  interrupts();

  OLED_CONTRAST(); // Oled Auto-dimming

  if (digitalRead(N_TRACK00_Pin) == HIGH) { // if Track 0 sensor @5volts then set TRACK count to 0
    NewTcount = 0;
    noInterrupts();
    Tcount = 0;
    interrupts();
  }

  if (OldTcount != NewTcount) {

    // for debug only
    /*
      if (NewTcount > 240) {
      Serial.println("BUG1");
      Tcount = 0;
      NewTcount = 0; //
      }
      if (NewTcount > 39) { // new
      Serial.println("BUG2");
      Tcount = Tcount - 1;
      NewTcount = NewTcount - 1; //
      }
    */

    OldTcount = NewTcount;
    display.clearDisplay();
    display.setCursor(10, 4);
    if (NewTcount < 10) {
      display.print("0");
      //Serial.print("0");
    }
    display.print(NewTcount);
    display.display();
    Serial.print(" TK");
    Serial.println(NewTcount);

    unsigned long curMillis = millis();
    preMillis = curMillis; //for OLED Auto-dimming
  }
}

// ------ OLED Auto-dimming-------------------------------------------------------------------------------------------------------
void OLED_CONTRAST() {
  unsigned long curMillis = millis();
  if (curMillis - preMillis >= interval) {
    preMillis = curMillis;
    ContrastValue = 0; // MIN contrast.
    curContrastValue = 0;
#if SetLib // SSD1306 driver
    display.ssd1306_command(0X81); // SETCONTRAST
    display.ssd1306_command(ContrastValue);
#else // // SH1106 driver
    display.SH1106_command(0X81);
    display.SH1106_command(ContrastValue);
#endif
    Serial.println(" OLED Auto-dimming");
  }

  if (ContrastValue != curContrastValue) {
    ContrastValue = curContrastValue;
#if SetLib // SSD1306 driver
    display.ssd1306_command(0X81); // SETCONTRAST
    display.ssd1306_command(curContrastValue);
#else // // SH1106 driver
    display.SH1106_command(0X81);
    display.SH1106_command(curContrastValue);
#endif
  }
}

// -------------------------------------------------------------------------------------------------------------------------------
// For ATmega328 AVR only
ISR (PCINT2_vect)
{
  // Another thing, during the execution of an interrupt, Arduino does not update the value of the millis and micros function.
  // So, the execution time of the ISR is not counted and the Arduino has a time lag.
  // You can use the millis and micros function to count time between two interrupts.
  // But during the interruption the time is not updated.

  // For PCINT of pins D0 a D7

  // int NS03
  if (digitalRead(5) == HIGH) {
    timeNS03 = micros();
    D5_state = true;
#if DEBUG
    Serial.print(" +N3sh:");
    Serial.print(timeNS03);
    Serial.print(" N2sh:");
    Serial.print(timeNS02);
    Serial.print(" N4sh:");
    Serial.println(timeNS04);
#endif
    if  (timeNS03 < (timeNS02 + 1200))  {
#if DEBUG
      Serial.println("  --N3sH:"); //
#endif
      if (timeNS04 < (timeNS03 + 40000)) {
        Tcount --;
      }
    }
  } else if (digitalRead(5) == LOW) {
    timeNS03 = micros();
    D5_state = false;
#if DEBUG
    Serial.print(" -N3sl:");
    Serial.print(timeNS03);
    Serial.print(" N4s:");
    Serial.println(timeNS04);
#endif
    if (timeNS03 < timeNS04 + 600 ) {
#if DEBUG
      Serial.print ("  --N3sL ");
      Serial.print(" N2s:");
      Serial.println(timeNS02);
#endif
      Tcount --;
      if (timeNS03 < timeNS02 + 31200 ) { // 31028 FOWARD Glitch Fix
        Tcount ++;
#if DEBUG
        Serial.print ("  ++N3sL");
#endif
      }
    }
  }
}

void IRQ_NS02() {
  digitalWrite(LED_BUILTIN, LOW); // 1st led
  digitalWrite(12, HIGH); // 2nd led
  timeNS02 = micros(); // only need this for timing.
  curContrastValue = ContrastValueMAX;
}

void IRQ_NS04() {
  digitalWrite(LED_BUILTIN, HIGH); // 1st led
  digitalWrite(12, LOW); // 2nd led
  timeNS04 = micros();
  curContrastValue = ContrastValueMAX;
#if DEBUG
  Serial.print(" N4f: ");
  Serial.println(timeNS04);
#endif
  if (D5_state == true) {
    if (timeNS04 < (timeNS03 + 10400)) // 20400    10,152
    {
      Tcount ++;
#if DEBUG
      Serial.println("  ++N4f: ");
#endif
    }
  }
}

 

 

Link to comment
Share on other sites

So question. I have already upgraded all my TANDON drives with MegaSpeedy that has the LED track display already. I have two World Drives. One has a Happy upgrade and the other is stock.

 

How would your code for the track display differ for a World Drive mechanism?

Edited by macsonny
Link to comment
Share on other sites

3 hours ago, xrbrevin said:

great work! but is a pico or nano viable instead of the uno? they are easier to accommodate

 

Have a look at this much earlier in this thread, unfortunately, not had time to get much further, using a Pico

Edited by TGB1718
Link to comment
Share on other sites

2 hours ago, Chri O. said:

Arduino Nano should work right out of the box it is basically using the same MCU ATmega328P-MUR as Arduino UNO.

cheers, i have a few of those and a smaller OLED (as used in goteks) so i'll have a build in the next few days and let you know how it goes 🤔

  • Like 1
Link to comment
Share on other sites

Yes and No .. 😁

For World Drive use this firmware v01 I posted this about year ago on page #4.

This is using the same wiring connection for arduino uno so you just need to flush different firmware.

 

On 5/10/2022 at 12:58 PM, Chri O. said:

Arduino uno code.

/*********************************************************************
  MIT License
  Copyright (c) [2022] [Chris O.]
  Atari 1050 - Track Display, ver 01.

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
*********************************************************************/

// https://github.com/wonho-maker/Adafruit_SH1106
/*********************************************************************
  Change the adafruit SSD1306 to SH1106
  SH1106 driver don't provide several functions such as scroll commands.
*********************************************************************/
// Teensy SH1106 driver fix https://forum.pjrc.com/threads/68174-OLED-problems

const byte VER = 2;

// ARDUINO UNO
const byte interruptPin_NS01 = 4; // NS01 @  U2 ic pin 2, NOT USED FOR interrupt.
const byte interruptPin_NS02 = 2; // NS02 @  U2 ic pin 7
const byte interruptPin_NS03 = 5; // NS03 @  U3 ic pin 2  NOT USED FOR interrupt.
const byte interruptPin_NS04 = 3; // NS04 @  U3 ic pin 7
const byte N_TRACK00_Pin =     6; // Q5 @ R#59 Track 00 sensor.

/* // TEENSY 4.0
  const byte interruptPin_NS01 = 2; // NS01 @  U2 ic pin 2, NOT USED FOR interrupt.
  const byte interruptPin_NS02 = 3; // NS02 @  U2 ic pin 7
  const byte interruptPin_NS03 = 4; // NS03 @  U3 ic pin 2  NOT USED FOR interrupt.
  const byte interruptPin_NS04 = 5; // NS04 @  U3 ic pin 7
  const byte N_TRACK00_Pin =     6; // Q5 @ R#59 Track 00 sensor.
*/

volatile byte Tcount = 0;
byte NewTcount = Tcount;
byte OldTcount = Tcount;

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SH1106.h> // OLED 1.30" @ I2C addr. 0x3C

#define OLED_RESET -1 // -1, NO RESET
Adafruit_SH1106 display(OLED_RESET);

#define LOGO16_GLCD_HEIGHT 16
#define LOGO16_GLCD_WIDTH  16
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000
};

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  while (!Serial && millis() < 4000 );
  Serial.println("Basic ARDUINO UNO 1050 Test:");

  display.begin(SH1106_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3D (for the 128x64), SH1106 addr 0x3C.

  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(1000);

  // Clear the buffer.
  display.clearDisplay();
  // Show the display buffer on the hardware.
  // NOTE: You _must_ call display after making any drawing commands
  // to make them visible on the display hardware!
  display.display();

  display.setTextSize(2);
  // display.setTextColor(WHITE);
  display.setTextColor(BLACK, WHITE); // 'inverted' text
  display.setCursor(0, 5);
  display.println("Atari 1050");
  //
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(10, 30);
  display.println("Track Display Test");
  //
  display.setCursor(10, 55);
  display.print("V.0");
  display.println(VER);
  display.display();
  // display setup for loop()
  display.clearDisplay();
  display.setCursor(5, 5);
  display.setTextSize(9);
  delay(1000);
  if (NewTcount < 10) {
    display.print("0");
  }
  display.print(NewTcount);
  display.display();

  //pinMode(ledPin, OUTPUT);
  pinMode(N_TRACK00_Pin, INPUT_PULLUP);
  pinMode(interruptPin_NS01, INPUT_PULLUP);
  pinMode(interruptPin_NS02, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS02), IRQ_NS02, RISING); //RISING, CHANGE, FALLING
  pinMode(interruptPin_NS03, INPUT_PULLUP);
  pinMode(interruptPin_NS04, INPUT_PULLUP);
  // edge-triggered interrupt on rising edge (low to high).
  attachInterrupt(digitalPinToInterrupt(interruptPin_NS04), IRQ_NS04, RISING); //RISING, CHANGE, FALLING
}

void loop() {
  // put your main code here, to run repeatedly:
  noInterrupts();
  NewTcount = Tcount;
  interrupts();


  if (digitalRead(N_TRACK00_Pin) == HIGH) { // if Track 0 sensor @5volts then set TRACK count to 0
    NewTcount = 0;
    //noInterrupts();
    //Tcount = 0;
    //interrupts();
  }

  if (OldTcount != NewTcount) {
    OldTcount = NewTcount;
    display.clearDisplay();
    display.setCursor(10, 4);
    if (NewTcount < 10) {
      display.print("0");
      Serial.print("0");
    }
    display.print(NewTcount);
    display.display();
    Serial.println(NewTcount);
  }
}

void IRQ_NS02() {
  digitalWrite(LED_BUILTIN, LOW);
  if (digitalRead(interruptPin_NS01) == HIGH) {
    Tcount ++;
  } else {
    Tcount --;
  }
  //digitalWrite(LED_BUILTIN, LOW);
  //Serial.print("T NS02 :"); // debug print
  //Serial.println(Tcount); // debug print
}

void IRQ_NS04() {
  digitalWrite(LED_BUILTIN, LOW);
  if (digitalRead(interruptPin_NS03) == HIGH) {
    Tcount ++;
  } else {
    Tcount --;
  }
  //digitalWrite(LED_BUILTIN, LOW);
  //Serial.print("T NS04 :"); // debug print
  //Serial.println(Tcount); // debug print
}

 

 

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...