As a follow-up to Panasonic JR200 tape wave generation some years back, I now had an opportunity to use my specifications for a quick project. Here I have an Arduino UNO work as a "tape" storage for the Panasonic JR200. As the Panasonic JR200 really likes square waves for input, the Arduino digital pins are ideal for the job.
The Arduino produces the waveform over and over from a series of bytes. Using the MLOAD command from the Panasonic end, the computer will load the data next time it loops around. (Resetting the Arduino obviously restarts the "tape")
I spent some time figuring out how to power the Arduino from the Panasonic External Bus, which would be convenient. The first bottom left pin is the Ground. Checking with the multimeter, then, going right, there are five pins between the Ground pin and what appears to be a 5V pin.
Again, I have to say I like the JR200 more and more for the quality of the hardware. I cannot guarantee the below schematic is good for the health of your Panasonic/Arduino/self, but here goes anyway:
Not to scale. The JR200 connectors are as seen at the back of the computer. |
So, it might take 26 seconds to practically load a loading screen (4K in two files), that would normally take slightly over 30 seconds. Well, it's a small improvement anyway. At 150ms/300ms, the Panasonic stopped recognizing the signal.
If only I could get rid of the trouble of writing the MLOAD keyword. However, I can at least load BASIC keywords directly into the character display, for example A=USR($1000). So, booting JR200 and using MLOAD would result in a more complex command set, waiting "under the cursor". Machine code can be run from the character display, so a tight package could combine both the necessary keywords to run the code and the code itself.
In glorious flicker-o-vision:
Further ideas:
-Take some signal from the Panasonic to Arduino for triggering the loading. Perhaps the "remote" relay. As the Panasonic gives an audible click when using the MLOAD, there's got to be a relay somewhere.
-The Arduino could just load a short code for high-speed receiving from the joystick port(s).
-Saving files to Arduino. It should be simple enough, but I just can't see the point.
The Arduino sketch:
Copy/Paste to the Arduino editor and upload. Use MLOAD from Panasonic. The example loads just 8 bytes to the character memory. This gives a quick visible effect. For sending your own data, change the contents of the g_data array list. The g_length and g_address are used for setting the start address and the length of the data. The g_offset sets the starting point from which the data is sent, within the g_data array. This only matters if you want to send multiple files.
#include <avr/pgmspace.h>
#define OUTPIN 9
#define MSHORT 200 //160
#define MLONG 400 //320
#define MLONGEST 800 //640
// Panaduino
// Uses Arduino pins to send a tape signal to Panasonic JR-200
// 15.7.2014 Dr. TerrorZ
unsigned int g_level,g_chek,g_blok,g_length,g_address,g_offset;
// The data.
// PROGMEM is necessary for anything longer.
// The actual g_length, g_address and g_offset are set in loop()
//
prog_uchar g_data[] PROGMEM={1,2,4,8,16,32,64,128};
void switchlevel()
{
if(g_level==LOW){g_level=HIGH;return;}
g_level=LOW;
}
void send0_600()
{
digitalWrite(OUTPIN,LOW);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,HIGH);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,LOW);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,HIGH);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,LOW);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,HIGH);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,LOW);
delayMicroseconds(MSHORT);
digitalWrite(OUTPIN,HIGH);
delayMicroseconds(MSHORT);
g_level=HIGH;
}
void send1_600()
{
digitalWrite(OUTPIN,LOW);
delayMicroseconds(MLONG);
digitalWrite(OUTPIN,HIGH);
delayMicroseconds(MLONG);
digitalWrite(OUTPIN,LOW);
delayMicroseconds(MLONG);
digitalWrite(OUTPIN,HIGH);
delayMicroseconds(MLONG);
g_level=HIGH;
}
void send0()
{
digitalWrite(OUTPIN,g_level);
delayMicroseconds(MSHORT);
switchlevel();
digitalWrite(OUTPIN,g_level);
delayMicroseconds(MSHORT);
switchlevel();
}
void send1()
{
digitalWrite(OUTPIN,g_level);
delayMicroseconds(MLONG);
switchlevel();
}
void sendlong1()
{
digitalWrite(OUTPIN,g_level);
delayMicroseconds(MLONGEST);
switchlevel();
}
void filler600(int a)
{
int i;
for(i=1;i<=a;i++){
send1_600();
}
}
void filler(int a)
{
int i;
for(i=1;i<=a;i++){
send1();
}
}
void sendbyte(int a)
{
int b,c;
send1();
send1();
send1();
send0();
b=1;c=a&b;
if(c!=0){send1();}else{send0();}
b=2;c=a&b;
if(c!=0){send1();}else{send0();}
b=4;c=a&b;
if(c!=0){send1();}else{send0();}
b=8;c=a&b;
if(c!=0){send1();}else{send0();}
b=16;c=a&b;
if(c!=0){send1();}else{send0();}
b=32;c=a&b;
if(c!=0){send1();}else{send0();}
b=64;c=a&b;
if(c!=0){send1();}else{send0();}
b=128;c=a&b;
if(c!=0){send1();}else{send0();}
g_chek=g_chek+a;
if(g_chek>255){g_chek=g_chek-256;}
}
void sendbyte600(int a)
{
int b,c;
send1_600();
send1_600();
send1_600();
send0_600();
b=1;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=2;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=4;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=8;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=16;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=32;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=64;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
b=128;c=a&b;
if(c!=0){send1_600();}else{send0_600();}
g_chek=g_chek+a;
if(g_chek>255){g_chek=g_chek-256;}
}
void header(int id)
{
//in 600 baud format
g_chek=0;
sendbyte600(2);
sendbyte600(42);
sendbyte600(0);//block#0
sendbyte600(26);//fixed length of data for block #0
sendbyte600(255);
sendbyte600(255);
sendbyte600('P');//filename 16
sendbyte600('D');
sendbyte600(48+id);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(0);
sendbyte600(1);//binary1,basic 0
sendbyte600(0);//baud rate for the rest. 0=2400, 1=600
sendbyte600(255);
sendbyte600(255);
sendbyte600(255);
sendbyte600(255);
sendbyte600(255);
sendbyte600(255);
sendbyte600(255);
sendbyte600(255);
sendbyte600(g_chek);//checksum
}
void datablock(int len)
{
unsigned int i,adhi,adlo,lbytes;
unsigned int bb;
unsigned char cc;
lbytes=len;
if(len==0){lbytes=256;}
g_chek=0;//reset checksum
adhi=g_address/256;
adlo=g_address-(adhi*256);
sendbyte(2);
sendbyte(42);
sendbyte(g_blok);//block nro
sendbyte(len);//length 0=256
sendbyte(adhi);//hi addy
sendbyte(adlo);//lo addy
for(i=0;i<=lbytes-1;i++){
bb=0;
cc=pgm_read_byte_near(g_data+(g_blok-1)*256+i+g_offset);;
bb=int(cc);
sendbyte(bb);
}
g_address=g_address+lbytes;
sendbyte(g_chek);
}
void lead_out()
{
int adhi,adlo;
adhi=g_address/256;
adlo=g_address-(adhi*256);
sendbyte(2);
sendbyte(42);
sendbyte(255);
sendbyte(255);
sendbyte(adhi);//hi addy
sendbyte(adlo);//lo addy
}
void send_tape(int tapeno)
{
int i,dblocks;
int lef;
dblocks=g_length/256;
g_level=LOW;
g_chek=0;
g_blok=1;
//600 baud portion
filler600(850);
header(tapeno);
filler600(51);
//2400 baud portion
for(i=0;i<=dblocks;i++){
if(i==dblocks){
lef=g_length-dblocks*256;
if(lef==0){datablock(1);}
if(lef>0){datablock(g_length-dblocks*256);}
}
if(i<dblocks){datablock(0);filler(196);}
g_blok++;
}
sendlong1();
filler(188);
lead_out();
sendbyte(255);
filler(150);
}
void setup()
{
pinMode(OUTPIN,OUTPUT);
digitalWrite(9,LOW);
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
}
void loop()
{
g_length=8;
g_address=0xd000;
g_offset=0x0000;
send_tape(1);
pinMode(OUTPIN,OUTPUT);
digitalWrite(9,LOW);
delay(100);
//for multiple MLOADs, use separate tape loads.
//delay(1500);
//g_length=0x0800;
//g_address=0xc100;
//g_offset=0x0800;
//send_tape(2);
}
No comments:
Post a Comment