While testing on a breadboard is fast, I still want my 68000 on PCBs.
Breadboards are nice for testing, and I use them in the design stage. But they will fail in the end. Loose wires, oxidated contacts and alike.
So when I was testing using breadboard, I drew the schematics in KiCad.
I wanted to use Eurocards for this one. If I divide the whole system in system blocks, I can exchange and experiment parts. (My 6502 uses another method to connect different cards)
CPU and Clock (Plus power-on reset and step mode)
Memory and ROM
Storage
Address decoding
Sound
IRQ Handlers
Led Blinkenlights 🙂
…
I wrote about Eurocards in the past.
So I’m using the VMEbus standard for my new design. (Using the recently bought book I mentioned)
Backplane design is done. And currently being autorouted.
PowerLeds for 5 and 12V. On/Off switch and MOLEX power connector.
Kicad sources will be uploaded
In the past, I dumped my old eurocards and even a nice case I had.
Saw a cool game a while ago, and found some old code. There was no schematic, so I had to reverse engineer it using the Arduino code. This one uses a Micro Pro.
Build a working version, now I can use this as base to create other games. But first i’m going to rebuild it so it can use Wifi and uses a Lipo Battery. Making it usable without wires.
Rotary – set angle/speed (Press resets)
Blue – toggle angle or speed ( was rotary press )
Green – select digit to change
Red – Fire
Led – not completely working yet, shows color of player Wil be changed to addressable leds with more functions (Player color, energy warning and more)
Record player is going to be re-printed at a higher quality.
Put a printed image on the player, and it plays the album
Move the arm, and the next track will be played
Press upper white button, and the music will pause/resume
Press lower button … ??? Don’t know yet
Updated python client (see previous posts)
import paho.mqtt.client as mqtt
import urllib.request
from time import sleep
def on_connect(client, userdata, flags, rc): # The callback for when the client connects to the broker
print("Connected with result code {0}".format(str(rc)))
client.subscribe("spotify/rfid/idlms")
client.subscribe("spotify/rfid/but1")
client.subscribe("spotify/rfid/but2")
client.subscribe("spotify/rfid/arm")
def on_message(client, userdata, msg): # The callback for when a PUBLISH message is received from the server.
print("Message received-> " + msg.topic + " " + str(msg.payload)) # Print a received msg
if msg.topic == "spotify/rfid/idlms":
urllib.request.urlopen("http://LMS-SERVER-IP:9000/anyurl?p0=playlistcontrol&p1=album_id:" + msg.payload.decode() + "&p2=cmd:load&player=00:04:20:16:d9:04")
if msg.topic == "spotify/rfid/but1":
urllib.request.urlopen("http://LMS-SERVER-IP:9000/anyurl?p0=pause&player=00:04:20:16:d9:04")
sleep(1)
if msg.topic == "spotify/rfid/but2":
urllib.request.urlopen("http://LMS-SERVER-IP:9000/anyurl?p0=pause&pt=1&player=00:04:20:16:d9:04")
sleep(1)
if msg.topic == "spotify/rfid/arm":
urllib.request.urlopen("http://LMS-SERVER-IP:9000/status.html?p0=button&p1=jump_fwd&player=00:04:20:16:d9:04")
sleep(1)
client = mqtt.Client("lmsclient") # Create instance of client with client ID “digi_mqtt_test”
client.on_connect = on_connect # Define callback function for successful connection
client.on_message = on_message # Define callback function for receipt of a message
client.connect('MQTTSERVER', 1883)
client.loop_forever() # Start daemon
Wemos INO file
#include <Arduino.h>
#include <SPI.h>
#include <MFRC522.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <PubSubClient.h>
#define SS_PIN 15
#define RST_PIN 0
const int buttonPin1 = D1;
const int buttonPin2 = D2;
int buttonState1 = 0;
int buttonState2 = 0;
MFRC522 mfrc522(SS_PIN, RST_PIN);
MFRC522::StatusCode status; //variable to get card status
byte buffer[18]; //data transfer buffer (16+2 bytes data+CRC)
byte size = sizeof(buffer);
uint8_t pageAddr = 0x06; //In this example we will write/read 16 bytes (page 6,7,8 and 9).
//Ultraligth mem = 16 pages. 4 bytes per page.
//Pages 0 to 4 are for special functions.
unsigned long cardId = 0;
WiFiClient net;
PubSubClient client(net);
const char* mqtt_server = "MQTTBROKER";
const char* ssid = "MYSSID";
const char* password = "MYWIFIPASWORD";
String topicStr = "";
byte buffer2[8];
boolean Rflag=false;
int r_len;
char payload[5];
byte value[5];
void setup() {
Serial.begin(9600);
pinMode(buttonPin1, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP );
SPI.begin();
mfrc522.PCD_Init();
WiFi.mode(WIFI_AP_STA);
WiFi.begin(ssid, password);
client.setServer(mqtt_server, 1883);
delay(100);
client.setCallback(callback);
delay(100);
client.subscribe("spotify/rfid/in/#");
}
void reconnect() {
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
}
while (!client.connected()) {
String clientId = "rfid-";
clientId += String(random(0xffff), HEX);
if (!client.connect(clientId.c_str(), "rfidclient", "...")) {
delay(5000);
}
}
client.subscribe("spotify/rfid/in/#");
}
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print(F("Called"));
Rflag=true; //will use in main loop
r_len=length; //will use in main loop
int j=0;
for (j;j<length;j++) {
buffer2[j]=payload[j];
//Serial.print((char)payload[j]);
}
if (r_len < 3) {
Rflag=false;
Serial.print(F("Set false"));
}
buffer2[j]='\0'; //terminate string
}
void loop() {
if (!client.connected()) {
reconnect();
}
buttonState1 = digitalRead(buttonPin1);
//Serial.print(buttonState1);
if (buttonState1 == 0 ) {
client.publish("spotify/rfid/but1", "0");
}
buttonState2 = digitalRead(buttonPin2);
//Serial.println(buttonState2);
if (buttonState2 == 0 ) {
client.publish("spotify/rfid/but2", "0");
}
int reading = analogRead(0);
//Serial.println(reading);
if (reading > 500 ) {
client.publish("spotify/rfid/arm", "0");
}
client.loop();
if (!mfrc522.PICC_IsNewCardPresent()) {
return;
}
if (!mfrc522.PICC_ReadCardSerial()) {
return;
}
if (Rflag) {
for (int i=0; i < 4; i++) {
//data is writen in blocks of 4 bytes (4 bytes per page)
status = (MFRC522::StatusCode) mfrc522.MIFARE_Ultralight_Write(pageAddr+i, &buffer2[i*4], 4);
if (status != MFRC522::STATUS_OK) {
return;
}
}
Rflag=false;
}
cardId = getCardId();
char buffer3[10];
sprintf(buffer3, "%lu", cardId);
client.publish("spotify/rfid/id", buffer3);
status = (MFRC522::StatusCode) mfrc522.MIFARE_Read(pageAddr, buffer, &size);
if (status != MFRC522::STATUS_OK) {
Serial.println(F("MIFARE_Read() failed: (R)"));
Serial.println(mfrc522.GetStatusCodeName(status));
return;
}
Serial.println(F("Read data: "));
for (byte i = 0; i < 5; i++) {
Serial.write(buffer[i]);
buffer2[i]=buffer[i];
}
client.publish("spotify/rfid/idlms", buffer,5);
delay(1000);
mfrc522.PICC_HaltA();
}
unsigned long getCardId() {
byte readCard[4];
for (int i = 0; i < 4; i++) {
readCard[i] = mfrc522.uid.uidByte[i];
}
return (unsigned long)readCard[0] << 24
| (unsigned long)readCard[1] << 16
| (unsigned long)readCard[2] << 8
| (unsigned long)readCard[3];
}
PROCESSOR FUNCTION CODES (FC0, FC1, FC2) These function code outputs indicate the mode (user or supervisor) and the address space type currently being accessed.
The following table shows the
meaning of these three bits.
FC2 FC1 FC0 Meaning
0 0 0 Not used
0 0 1 User data
0 1 0 User program
0 1 1 Not used
1 0 0 Not used
1 0 1 Supervisor data
1 1 0 Supervisor program
1 1 1 Interrupt Acknowledge
These outputs can therefore inform external circuitry what is happening
inside the 68000. They could, for example, be used to switch in differentbanks of memory.
Using a small 8266 with a display, I wanted to see if it’s useful to monitor this information.
So using a trick with the uln2804/uln2803 as level convertor (don’t connect the VCC, and the output will drop to a level that is around the 3.3v. (I was out of bi-directional level convertors)
Latch demo
I’ve been using latches in the past, but I wanted to show how it works using a little demo setup. Below movie is for the Bus Controller I posted recently.
While busy fixing my business site, and working for a customer, I build a testing rig for the 68000.
I first made a power-on reset schematic. The timing is different from the 6502 power-on reset, and the 68k needs HALT and RESET being pulled low.
Inverted reset signal (before the 74ls06 invertor)
Pulse from A17
Schematic with poweron reset, some leds and 8mhz crystal Lines pulled to GND or VCC are at least needed to get a running CPU. Data bus resistors are needed because data is r/w
All Data lines are pulled low, emulating opcode 00 00 https://68k.hax.com/ORI%20to%20CCR This will do nothing weird, and will increment the address and try to read the next opcode. Resulting in an endless incrementing address bus, I’ve put a Led (Red)on Address A17.
I bought a little notebook while being there. I wrote about 12 pages of ideas, schematics and projects to start.
Rewrite Wozmon to use my composite pcb (Atmega328) access though via
Building a 68000 pcb with a minimal machine code monitor. Using a atf22v10 as address decoder. (Same as my 6502 , I love those devices) Maybe I’ll add a micro sdcard reader
Add a lcd matrix display to my 8088/8086
Creating a PLA alternative for C64 using ath22v10 (again)
Make backplanes for my 6502, so I can plug cards with different POC cards. Clockcard, Latched bus leds, multiple VIA’s, IRQ controller, SID + Buzzer (Maybe also AY-3-8910, see other posts), LCD, composite, serial, Matrix and serial_usb) keyboard)
IRQ controller because I have some devices without opendrain, so I can’t tie all IRQ’s together
Amiga Chip Mem mod for rev 5 (using a ‘new’ 8372A)
8085 Cartridge new approach
C64Pico fix and add backplane + breadboard version for POCs
… more
First version PLA with atf22v10
PCB mockup (two ATF22v10 on top and a wide pin setup for placement in C64
Wide PLA
8085 Cartridge revisited
Working on 8085 cartridge
Problem with cartridge: prg is 17k, exomized 10k. So you need 2 banks of 8k. This disables basic rom, needed for the program. The program needs to be relocated to 0x800 anyway. So my exomizer options will take care of that. But the basic is not being enabled again.
exomizer sfx sys -o data.exo -Di_ram_enter=\$37 -Di_ram_during=\$34 -f'LDA #$37 STA $01' 8085.prg
xa frame.asm -o frame.bin
x64 -cart16 frame.bin
Today we worked on this project again. (Bigred and me)
There were some problems we needed to fix since last time:
It was quite hard to get the correct parts. Our display connector was only fitted with connection pins on the wrong side of the connector. (up/down) So I bought a connector with both positions populated. So we had to replace this hard to solder (40 pin) connector.
It was not clear what the orientation should be of the atmega328pb. We looked at the pinout, and followed the VCC/GND. But these are also available of the opposite side of the chip. (We missed that) Later, we saw a tiny line on the PCB, which showed the pin 1 placement. So we had to remove and replace the chip. When turning on the power, (with incorrect placement) probably fried R5 (10k resistor), on both our boards. Had to replace those also.
Programming the atmega328pb was not easy, see below fixes.
Compiling the pico firmware resulted in a black screen. Below the fixes I had to make to get the screen working.
Other things still to fix.
Bigreds screen.
atmega328p didn’t work for Bigred, so probably needs to replace with the pb version.
My battery controller is not charging. See bottom of page
Some of my buttons are working. The pewpew and some of the cursor keys (not as I expect, there are some up/down issues) And none of the other keys are working.
Some other things we noticed.
sdcard: remove partitions, format using mkfs.exfat Create a c64 directory on this filesystem where you can put the d64 files!
0402 SMD is far too small for me. There is enough room on the board to use 0805 for example. Even THT is possible, there are only a few components.
Some components are TOO close together, removing a component resulted in other small parts disconnecting also.
My friend Bigred said: If I can see it, I can solder it. But it is not easy. This probably keeps a lot of people from building it!