Serial Connection to Gameboy Thermal Printer [Hardware + Software]

Another suggestion:

Try this with printer connected and disconnected.

From Gralin’s last post, 0xff can mean there’s no response, since the pull-ups are ensuring you get that value. It’s only when the device responds you get a non-255 value

I haven’t had time to do all the testing you mentioned above, I’ll tackle that later tonight, however. I did try sending the null packet…

   
           var initRequest = new byte[] { 0x0F };
            var initResponse = new byte[initRequest.Length];
           spi.Write(initRequest);

My local variables in the debug are
initRequest[0] = 0x0f
initResponse[0] = 0x00 – nice but stayed 0x00 even when unplugged, now it will return 0xff or 0x0f

   
      var initRequest = new byte[] { 0x88, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00 };
            var initResponse = new byte[initRequest.Length];
            spi.WriteRead(initRequest, initResponse);

In the debugger I get a bunch of random codes. even when unplugged

someone I talked to suggested code very similar to yours Gralin, but structuring like his didn’t seem to make any difference. I was still seeing pretty odd debug stuff for the Read command.

Here is how I used his code, I can post how I’m using yours too if you’d like. I tried adding dummy bytes and going byte by byte, but it didn’t seem to help and I never saw an 0x80 or 0x81 in response. Could it still b a hardware thing?

 GT.Socket socket = GT.Socket.GetSocket(6, true, null, null);

            // Would need to double-check these settings for the printer itself...
            GT.Interfaces.SPI.Configuration spiConfiguration = new GT.Interfaces.SPI.Configuration(false, 0, 0, true, true,1);
           
            spi = new GT.Interfaces.SPI(socket, spiConfiguration, GT.Interfaces.SPI.Sharing.Exclusive, null);


            Send intialization commands to the printer...
byte[]initCommand = new byte[] { 0x88, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00 };
           // byte[] initCommand = new byte[] { 0x0f};
          byte[] initResponse = new byte[initCommand.Length];
           spi.WriteRead(initCommand, initResponse);

            SendCommand();

            Debug.Print("Program Started");
        }

      //  private void SendInitCommands()
     //   {
          //  byte[] randomCommands = new byte[] { 0x88, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00 };
          //  byte[] readCommands = new byte[randomCommands.Length];
          //  spi.WriteRead(randomCommands,readCommands);
     //   }

        private void SendCommand()
        {
            byte[] randomCommands = new byte[] { 0x88, 0x33, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00 };
            byte[] readCommands = new byte[randomCommands.Length];
            spi.WriteRead(randomCommands, readCommands);
        }


This is very weird. For sure you there should be a difference between printer connected and disconnected. Do you have a scope and know how to use it? It would be great if you could show us the DIN, DOUT and CLOCK signals when you do the WriteRead.

If you have pullups properly soldered on you should get 0xff return code with nothing else connected, because by definition the pin must be held high. If you aren’t getting that then there’s some problem you need to resolve before worrying about the printer :slight_smile: As Gralin says, a scope would be helpful, but at least can you confirm with a multimeter that the MOSI and MISO lines are high without the printer connected?

Do you have another SPI device at all, that you can at least test and confirm you are able to use SPI correctly?

hit it again, but I still can’t get it consistant. I dont really know how to do a scope, I’ll try to do it tomorrow though. I’m just looking at the float values during at break points right now and watching the init values. They still fluctuate pretty wildly. As far as the meter. the pins go up to ~2.3v when it’s deploying/ debugging/running the code, but drop to .6-0 in slight pulses when idle. The rest semm pretty normal ie 3v3 = 3v 5v5 =5

Ack = 128
Status = 0
SUCCESS

da code

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;
using Microsoft.SPOT.Hardware;

using Gadgeteer;
using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.GHIElectronics;


 
namespace GadgeteerApp1
{
    public partial class Program
    {
        void ProgramStarted()
        {
           GT.Socket socket = GT.Socket.GetSocket(6, true, null, null);
           //var socket = Socket.GetSocket(extender1.ExtenderSocketNumber, true, extender1, null);
            var spiConfig = new SPI.Configuration(socket.CpuPins[6],false, 0, 0, true, false, 1, socket.SPIModule);
            var spi = new SPI(spiConfig);


           // var initRequest1 = new byte[] { 0x00 };
            //var initResponse1 = new byte[initRequest1.Length];
            //spi.WriteRead(initRequest1, initResponse1);

            byte [] initRequest1 = new byte[] { 0x88, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00 };
            byte[] initResponse1 = new byte[initRequest1.Length];
            spi.WriteRead(initRequest1, initResponse1);


            byte[] initRequest = new byte[] { 0x88, 0x33, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
             byte[] initResponse = new byte[initRequest.Length];
            spi.WriteRead(initRequest, initResponse);

 
            //var initRequest = new byte[] {0x88, 0x33, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
            //spi.Write(initRequest);
 
            var ack = ReadByte(spi);
            var status = ReadByte(spi);
 
            Debug.Print("Ack = " + ack);
            Debug.Print("Status = " + status);
 
            var initialized = ack == 0x80 || ack == 0x81;

            Debug.Print(initialized ? "SUCCESS" : "ERROR");

        }
 
        private static byte ReadByte(SPI spi)
        {
            var dummyByte = new byte[] { 0x00 };
            var result = new byte[1];
            spi.WriteRead(dummyByte, result);
            return result[0];
    
        }

        
    }

}
 

Unplug the printer. Turn power on. Measure MISO and MOSI. They should be pulled high.

Then if you test while using the printer and they go up/down, then that’s a good sign.

I’d try showing the responses:

byte [] initRequest1 = new byte[] { 0x88, 0x33, 0x0f, 0x00, 0x00, 0x00, 0x0f, 0x00 };
byte[] initResponse1 = new byte[initRequest1.Length];
spi.WriteRead(initRequest1, initResponse1);
for (i=0;i<initResponse1.Length;i++)
{
Debug.Print(" resp("+i+")="+initResponse1[i]);
}
 
byte[] initRequest = new byte[] { 0x88, 0x33, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00};
byte[] initResponse = new byte[initRequest.Length];
spi.WriteRead(initRequest, initResponse);
for (i=0;i<initResponse.Length;i++)
{
Debug.Print(" resp("+i+")="+initResponse[i]);
}

Do you know the response is the same # of bytes as each command?

OK, so I dug a bit deeper into some of the links you sent earlier. In particular, this one:
http://furrtek.free.fr/index.php?p=crea&a=gbpcable&i=2

Perhaps we can do the simple test and just try sending the commands it shows?

pseudo-code:

Send "?"
Print the response.
Send a "!"
Wait for "a" response
Woo Hoo, happy days !

@ Brett, you got two things mixed up. What we are dealing with is connection between the printer and FEZ using SPI. The link you mentioned describes how to communicate with the printer using ATTiny45 and Prolific chip. The first one acts as a SPI<->UART converter and the second does UART<->USB. This way when you send ‘?’ to you serial port the program in ATTiny does this:

while(1) {
	cmd = SerialGet();

	if (cmd == '?') {
		GBSerialOut(0x88);
		GBSerialOut(0x33);
		GBSerialOut(0x01);
		GBSerialOut(0x00);
		GBSerialOut(0x00);
		GBSerialOut(0x00);
		GBSerialOut(0x01);
		GBSerialOut(0x00);
		repl = GBSerialOut(0);
		GBSerialOut(0);
		if (repl == 129) {
			SerialPut('1');
		} else {
			SerialPut('0');
		}
	}
	
	...

Question two hardware guys: If the printer operates on 5V will it recognize when FEZ is sending bit 0 and bit 1 using SPI and 0-3.3 voltage level ? Maybe we should do this using RLP and bit banging ?

5V devices may or may not understand 3.3V levels. Most do but not all.

Ok if you don’t have a scope we could skip SPI and try to bit bang the transmission. With RLP you should be able to use the arduino code to do this but how about this:

[quote]The GBPrinter always responds when the Gameboy sends 0x00 data.
The Gameboy sends 0x00 when waiting for data from the GBPrinter.[/quote]

We are unable to bit bang the transmission because it requires synchronization of two outputs (data and clock) with micro second precision. However if we are sending 0x00 value the data output always stays low so we only need to generate the proper clock and record what occurs on data in pin. Since Spider has GHI premium libs we can use OutputCompare and PinCapture classes. This is what i came up with:

using System.Threading;
using GHIElectronics.NETMF.Hardware;
using Gadgeteer;
using Microsoft.SPOT;
using Microsoft.SPOT.Hardware;

namespace GadgeteerApp4
{
    public partial class Program
    {
        public static OutputPort DataOut { get; set; }
        public static OutputCompare Clock { get; set; }
        public static PinCapture DataIn { get; set; }
        
        public static uint[] Response { get; set; }
        public static int ResponseLength;

        public void ProgramStarted()
        {
            Initialize();
            SendData();
            CheckResponse();
        }

        private void Initialize()
        {
            var socket = Socket.GetSocket(extender.ExtenderSocketNumber, true, extender, null);
            var dataOutPin = socket.CpuPins[7];
            var dataInPin = socket.CpuPins[8];
            var clockPin = socket.CpuPins[9];

            DataOut = new OutputPort(dataOutPin, false);
            Clock = new OutputCompare(clockPin, true, 32);
            DataIn = new PinCapture(dataInPin, Port.ResistorMode.PullUp);
        }

        private static void SendData()
        {
            DataOut.Write(false); // bit 0

            Response = new uint[32];

            var responseThread = new Thread(() => 
                ResponseLength = DataIn.Read(false, Response, 0, Response.Length, 1000));

            responseThread.Start();
            Thread.Sleep(5);

            var clockPulses = GetClockPulses();
            Clock.SetBlocking(true, clockPulses, 0, clockPulses.Length, 120, false);

            responseThread.Join();
        }

        private static uint[] GetClockPulses()
        {
            const uint bitTime = 120; // 120μs per bit
            var pulses = new uint[8*2];
            for (var i = 0; i < pulses.Length; i++)
                pulses[i] = bitTime/2;
            return pulses;
        }

        private static void CheckResponse()
        {
            if (ResponseLength == 0)
            {
                Debug.Print("No response");
                return;
            }

            for (var i = 0; i < ResponseLength; i++)
                Debug.Print(Response[i] + " ");
        }
    }
}

Of course i have to way to check this but it should show you the idea. This way please confirm that you don’t get any pulses on data in when the printer is not connected and you do see some activity when the printer is connected. Maybe try adding the extra resistor to data in as described in those documents.

@ Gralin, ah right, you are correct, the atmel chip was indeed doing stuff.

3v3 vs 5v, I guess that may be causing an issue, so the way to deal with that unfortunately will be a level shifter. If the bitbanging doesn’t show any improvement, then perhaps that will be the only next step.