Thursday, August 17, 2017

Model 100 micro SD Card reader, the MyTeSed

After the initial testing with a full sized SD card reader shield and Ardunio Uno, I wanted to know how easy it would be to shrink the TRS-80 Model 100 SD card interfaces size down to something a little more acceptable. I thought about building the whole design from the ground up, in the end the abundance of cheap modules from China can't be beaten on price (or convenience).

Before getting into the excitement of the details, the other major half of the fun of building these projects is naming them, so I'm calling this interface the 'MyTeSed', standing for My Model 'T' Serial Drive. Now that out of the way, on with where I'm up to with the project to date.

Testing the functionality of the MyTeSed on a Breadboard 

The Hardware


I've gone with a Arduino Nano for the heart of the project, the footprint of the Nano is barely larger than a atmega328p chip and far smaller if including the ancillary components. The Nano also nicely takes care of power regulation, has a USB port for easy re-programming, and behaves identically to a Uno. Thus making the Nano one of the most inclusive of the reduced sized Arduinos' to use.

Micro SD Card Reader Module
The revised hardware also substitutes the full sized SD card shield with an all in one micro USB card module. The SD module accommodates either 5v or 3.3v signals, making it an ideal choice for use with the Nano. It's a standard module avaliable from just about anywhere, including Ebay and various online Chinese merchants of all things electronica.

After a little experimentation I've also decided to set up software serial on pins D8 and D9 of the Nano. Using software serial as the conduit to the T100 / T102 / T200 leaves the Nanos' standard serial pins D1 and D2 free to use as a pass-through (actually via the Nanos' USB) which will be used as direct connections to a PC. As in the previous version (blog entry Using SD Cards with the TRS-80 Model 100) a MAX323 IC handles the RS232 to TTL serial conversion.

The when complete the MyTeSeD can be powered from a 6v to 9v battery supply (like most Arduino projects), in addition usage of the Nano conveniently provides a means to power the interface via the mini USB port, allowing battery packs or a USB power source etc.


MyTeSed Circuit Diagram

Arduino Code


This is not by any measure the final code to be using with the interface, for the moment it serves as proof of concept. I'm still yet to go back a write up a more permanent solution, it does however work for now, just expect some drastic changes for the foreseeable future.

In essence the current idea is for MyTeSed to listen for instructions in plain text over the serial line, 'LOAD' and 'SAVE' for example, then either send data back or shift files around on the SD card. Regardless there is a lot left to implement, such as file deletion, access to directories and error checking.
// **************************************************************************
// **** MyTeSed: T100 SD Card Reader for Arduino Nano and SD Card Reader ****
// **************************************************************************
// ** David Stephenson 2017-08-23  **
// ** Version 0.01                 **
// **********************************
#include <SPI.h>
#include <SD.h>
#include <SoftwareSerial.h>

enum SERIAL_MODE {FREE, COMMAND, DATA_IN, DATA_OUT, FILES_OUT};

const byte LF=10;
const byte CR=13;
const byte EF=26;

SoftwareSerial mySerial(12, 13); // RX, TX

class CardReader {
 private:
  SERIAL_MODE eSerialMode = FREE;
  //DRIVE_COMMAND eDriveMode = NONE;

  File MyFile;
  
  String sFileName;
  String sInString;
  
  unsigned long TimeLastUpdate = 0;
  
  // Class Private Functions
  void LoadBas() {
   
   char cRead, cLast;

   if(eSerialMode == DATA_OUT){
    MyFile = SD.open(sFileName);

    if(MyFile){
     while(MyFile.available()){
      cRead=MyFile.read();
      if (cRead== LF){
       if (cLast != CR){
        mySerial.write(CR);
       }
       mySerial.write(LF);
      } else {
       mySerial.write(cRead);
       cLast = cRead;
      }
     }
    }
    MyFile.close();
    mySerial.write(EF);
    eSerialMode = FREE;
   }
  }

  void SaveBas(char cInChar) {
   
   if(eSerialMode == DATA_IN){
    if(cInChar != EF){
     MyFile.print(cInChar);
    } else { 
     MyFile.close();
     eSerialMode = FREE;
    }
   }  
  }
  
  void FilesOut() {
   
  }
  
  
  void commandIn(){
   String KEYWORDS[7] = {"LOAD","SAVE","KILL","FILES","MOVE","CP2SD","CP2R"};
   String sInSubString;

   sInString.trim();

   Serial.print(sInString);

   if (sInString.length() >= 3){
    for (byte bKeyword = 0 ; bKeyword < 8 ; bKeyword++){
     sInSubString = sInString.substring(0,KEYWORDS[bKeyword].length() );
     sInSubString.toUpperCase();
     if (sInSubString.indexOf(KEYWORDS[bKeyword])!=-1){
      if (KEYWORDS[bKeyword] == "LOAD") {
       sFileName = sInString.substring(4);
       sFileName.trim();
       delay(500);
       eSerialMode = DATA_OUT;
       LoadBas();
      }

      else if (KEYWORDS[bKeyword] == "SAVE" || KEYWORDS[bKeyword] == "CP2D") {
       sFileName = sInString.substring(4);
       sFileName.trim();
       if (SD.exists(sFileName)) {
        SD.remove(sFileName);
       }
       MyFile = SD.open(sFileName, FILE_WRITE);
       eSerialMode = DATA_IN;
      }
      
      else if (KEYWORDS[bKeyword] == "FILES") {
       eSerialMode = FILES_OUT;
       FilesOut();
      }
     }
    }
   }

   //sInCommand = false;
   sInString = "";
   
  }
 
 public:
 
 void SerialIn(char cInChar){
  switch(eSerialMode) {
   case FREE:
    if(cInChar == CR){
     eSerialMode = COMMAND;
     commandIn();
    } else {
     sInString += cInChar;
    }
    break;
   case DATA_IN:
     SaveBas(cInChar);
    break;
  }
 }

};

CardReader MyCard;

void setup()

{
  // Open serial communications and wait for port to open:
  Serial.begin(1200);
    //57I1D
   while (!Serial) {
    ; // wait for serial port to connect. Needed for Leonardo only
  }

  // set the data rate for the SoftwareSerial port
  mySerial.begin(1200);

  if(!SD.begin(10)){
   mySerial.println("fail");
    return;
  } else {
 mySerial.println("mango");
 Serial.println("mangos");
  }
}



void loop()
{
 char cInChar;
 if (mySerial.available()) {
  cInChar = (char)mySerial.read();
  //sInString += cInChar;
  MyCard.SerialIn(cInChar);
  Serial.write(cInChar);
 }
}

Talking With a Model 100


Saving, loading and copying files from the micro SD card requires first sending a command and a filename to the serial port, then engaging the normal BASIC save / load to serial command. The COM port should be set to 1200 Baud, 7 Bit Word length, Ignore parity.

For example, saving the active BASIC file:
OPEN "COM:57I1D" FOR OUTPUT AS 1: PRINT #1,"SAVE MYFILE.BA": CLOSE 1: SAVE "COM:57I1D"

Or loading a BASIC file from the Interface:
OPEN "COM:57I1D" FOR OUTPUT AS 1: PRINT #1,"LOAD MYFILE.BA": CLOSE 1: LOAD "COM:57I1D"

Possibly the easiest method to save or load  BASIC program is to add some of the below lines to a program listings. Alternatively an option once the code base is a little more on the stable side would be the development of a menu-ing  system, but that's for latter.

Save a BASIC file to SD Card

900 OPEN "COM:57I1D" FOR OUTPUT AS 1
910 PRINT #1,"save testme.ba"
920 CLOSE 1
930 SAVE "COM:57I1D"

Load BASIC file to SD Card

10 OPEN "COM:57I1D" FOR OUTPUT AS 1
20 PRINT #1,"load testme.ba"
30 CLOSE 1
40 LOAD "COM:57I1D"

Copy a RAM Text File to the SD Card

10 MAXFILES=2
20 OPEN "RAM:TXT2RD.DO" FOR INPUT AS 1
30 OPEN "COM:57I1D" FOR OUTPUT AS 2
40 PRINT #2, "SAVE TXTFIL.DO"
50 LINE INPUT #1, Z$
60 PRINT #2,Z$
70 IF EOF(1) THEN GOTO 90
80 GOTO 50
90 PRINT #2, CHR$(26)
100 CLOSE 1: CLOSE 2

Copy a File from the SD Card to a RAM Text File

10 MAXFILES=2
20 OPEN "RAM:TXT2RD.DO" FOR OUTPUT AS 1
30 OPEN "COM:57I1D" FOR OUTPUT AS 2
40 PRINT #2, "LOAD TXTFIL.DO"
50 LINE INPUT #2, Z$
60 PRINT #1,Z$
70 IF EOF(1) THEN GOTO 90
80 GOTO 50
90 PRINT #1, CHR$(26)
100 CLOSE 1: CLOSE 2

Next Time


The next stage of proceedings is to design a circuit board, should be a simple enough task. Unlike all the other projects in this blog I'm planning on getting the PCB produced by a fabrication house, and hopefully all that will go well.


7 comments:

  1. How is the project coming? I would like to build one myself. Can you offer any suggestions.

    ReplyDelete
  2. Got it working: https://www.zx81keyboardadventure.com/2017/09/the-trs-80-model-100-mytesed-is-alive.html :-) I'll need to do a follow up, as I got it to do xmodem file transfers for binary files as well.

    At the moment though I'm using a REX for file transfers and storage. https://www.arcadeshopper.com/wp/?page_id=11#!/REX/p/102954443/category=28313042

    ReplyDelete
  3. Wow that sounds great sense the t102 disk drive fail and atr impossable to repair or replace. My freind is gifting me a 32K 102. thanks for your work When can I order one from You? thanks Darrell

    ReplyDelete
  4. Hello! Please tell me, can I open and edit files recorded on the SD card in the Virtual T program on my PC?
    Can I create a * .BA file on my PS (in Virtual T program) and write this file to the SD card, and then open it in my Tandy?

    ReplyDelete
    Replies
    1. Yes you can import files, the *.BA files are plain text and the SD card is readable on a PC.

      Delete
  5. Hi David, What is the license for this project? I would like to put up a modified version of it on github.

    thanks

    ReplyDelete
    Replies
    1. Hi Saltima,

      The project is free to use as long as I'm accredited. The latest version of the project can be found:
      http://dasteph.com/cgi/T100/files/MyTeSed_03.zip

      Delete