Sony PocketStation


he Sony PocketStation is truly a technological marvel.  Designed to complement the Playstation, the PocketStation represents a moderately bold move by Sony.  Fairly popular in Japan, the device has never made much of an inroad in the US.  Reasons given for this have ranged from manufacturing and distribution difficulties to a general feeling that tinkering with the PSX platform wasn't neccessary given the imminent PS2 launch.  Whatever the case, US gamers who don't own this little device are definitely missing out.
 


Overview

 
Manufacturer: Sony Computer Entertainment Incorporated
Release Date: 19??
Processor: ARM7TDMI
Speed: 33kHz ??
Display: 32x32 LCD
Input/Output: IrDA, Playstation card interface
Memory: 2048 bytes user memory, 128k flash memory in 15 blocks
Sound: 8-bit PCM with 12-bit range
Buttons: 6, 5 user-accessible plus reset
Size: 6cm x 3.5 cm x 1.2 cm
Batteries: 1 CR2032 or compatible 1.5V
Cost: approx. $25 in Japan, approx $50 in US

Development Tools

Fortunately, because the PocketStation is based around the ARM7TDMI core, a modern, supported processor, there are a number of development tools available.

Bugs

The SN Systems compiler/emulator development environment, since it is in beta, has several bugs which I have identified. I list them here in the hopes of saving you some time. The compiler is a viable development tool, but you have to remember it's beta code, and don't trust it too much! If you use the '-S' flag you can see the assembler it generates. That's the final arbiter of correctness.

Display

The Pocket Station has an LCD display which has 32x32 pixels.  It operates at a fixed frequency of ???.  It is backed by a "video memory" which consists of 32 unsigned 32-bit quantities ('unsigned int'), starting at hex address 0x0D000100.  Let's examine a simple routine which draws a pixel on the screen, taken from sample code distributed by SN systems and modified by me for this purpose:

#define VIDEO_MEMORY 0xD000100
void DrawPixel(unsigned int x, unsigned int y)
{
    if((x < 32) && (y < 32))
        VIDEO_MEMORY[31 - y] |= (1 << (31 - x));
}

This routine 'draws' (i.e. fills in) the pixel at (x,y) where (0,0) is in the upper-left hand corner.  Note that since the memory is arranged in reverse order, we must use 31-y and 31-x.  Some things to notice about this routine:


Buttons

The PocketStation has 6 buttons, 5 of which are available for general use.  The one unusable button is a reset button which is located under the cover and must be pressed manually by a sharp implement.  Pressing this button causes a hardware reset and an interrupt for execution at memory location 0x0.  The other 5 buttons, however, are user defined and available for use.

The buttons are attached to a port, location 0x0A000004.  When one of the buttons is pressed, a bit of this memory location is set corresponding to the following table:
 
7 6 5 4 3 2 1 0
Other Purposes Other Purposes Reset?/Unused Up Down Left Right Fire/A

What this means is that, for example, while the down button is pressed, bit 3 of memory location 0x0A000004 is set to 1.  These presses are transient - that is, as soon as down is released, bit 3 goes back to zero.  Consider the following routine, taken partially from the SN systems demo code:

#define BUTTON_MEMORY 0x0A000004
unsigned int getButtons()
{
    return (*((unsigned int *) BUTTON_MEMORY)) & 0x0000001F;
}

Note that in this, standard, mode of operation, the button presses do no generate an interrupt.  The ARM7TDMI has a modern, complex interrupt system which can be used to generate interrupts when these buttons are pressed.  If you want to generate a button interrupt, you must do the following two things:

  1. Write an interrupt handler for the corresponding interrupt.
  2. Register it in the system interrupt table.
  3. Activate the desired interrupt.
  4. De-activate it when the program exits.
Don't leave the interrupts active when the program quits!  That would generate interrupts into your code, which no longer exists.  Very bad.  It turns out that memory location 0x0A000004 is only part of a general system status area of memory, or mechanism, which starts at 0x0A000000 and goes for several words.  Port 0xA000004 is the raw status information.  The full set of ports is here:
 
Location Name Description
0x0A000000 IRQ_RAW ??
0x0A000004 IRQ_STATUS_RAW The raw status of the various ports
0x0A000008 IRQ_ENABLE A volatile port for enabling interrupts
0x0A00000C IRQ_DISABLE A volatile port for disabling interrupts
0x0A000010 IRQ_CLEAR Unclear - most likely to signal interrupt has been serviced?

To enable an interrupt, write a "1" bit to the corresponding bit location of IRQ_ENABLE using the above chart.  For example, to enable all of the button interrupts, write 0x1F to IRQ_ENABLE.  The "volatile" portion of the description means that these written values don't stick.  Make sure to use the "volatile" keyword if using C to ensure that writes occur.  Disabling the interrupt involves writing a 1 to IRQ_DISABLE at the corresponding bit.  After the interrupt has been serviced, write a 1 to the corresponding bit of IRQ_CLEAR.  All interrupts use the same interrupt handler (with a few exceptions, see interrupts above).  See interrupt handling, above.


Clock

The Pocket Station has a clock.  While I have not fully decoded all the specifics of this clock, I can tell you the following:

unsigned int t, hh, mm, ss;
t = *((volatile unsigned int *) 0xb800008;
DrawNumber(0, 0, (hh & 0x00F00000) >> 20);
DrawNumber(4, 0, (hh & 0x000F0000) >> 16);
DrawNumber(8, 0, 10);                         // Draw a colon
DrawNumber(12, 0, (mm & 0x0000F000) >> 12);
DrawNumber(16, 0, (mm & 0x00000F00) >> 8);
DrawNumber(20, 0, 10);
DrawNumber(24, 0, (ss & 0x000000F0) >> 4);
DrawNumber(28, 0, (ss & 0x0000000F));

Displays a clock.  The time portion of the clock corresponds to data location 0xb800008.  The layout of this 32-bit memory location is, in BCD (binary coded decimal):
 
7 6 5 4 3 2 1 0
0xF0000000 0x0F000000 0x00F00000 0x000F0000 0x0000F000 0x00000F00 0x000000F0 0x0000000F
Unused Day of the week Hour, tens digit Hour, ones digit Minute, tens digit Minute, ones digit Seconds, tens digit Seconds, ones digit

There is a similar memory location at 0xb800000 which contains the date, but I'm not sure in what format:
 
7 6 5 4 3 2 1 0
0xF0000000 0x0F000000 0x00F00000 0x000F0000 0x0000F000 0x00000F00 0x000000F0 0x0000000F
Reserved Reserved Year, high digit? Year, low digit? Empty Month Day, top 4 bits Day, bottom 4 bits

I'll do some more experimentation to see what the date business is.  In fact, the Pocket Station has a whole Real-Time Clock (or RTC) mechanism.  There is a RTC-based counter capable of operating at 1/sec or at 4000/sec, but I don't know exactly how it works yet.

Here is some code which operates the clock and shows the time.  With a little more effort it could show the date as well.


Infrared

The PocketStation has a bidirectional infrared port which is capable of operating both in IrDA and normal, what is often inaccurately called 'legacy', mode.  I have attempted to study this device but the information available about it is minimal.  I have attempted, as a driving project, to get the PocketStation to change the channels on my TV, a Sharp.  I obtained information on the method used in the Sharp for transmitting codes from the REMOTE4 project for the old HP-48 series of calculators.  This information indicated, for example, that a '1' consisted of a 275us pulse followed by 1900us of silence.  The key, then, was to get the PocketStation to perform this operation.  But let us back up.  There are two basic infrared modes: The PocketStation should theoretically be capable of both - at least, that's what the marketing brochures say.  But to this point I haven't gotten it to work.  Let me tell you what I do know:  the infrared beam is controlled by a set of memory locations which start at 0xc800000.  Here is a partial table:
 
 
Address Name Purpose
0xc800000 pIRDA_CONTROL Controlling the protocol - send/recv, etc.
0xc800004 pIRDA_BEAM Turning the beam on and off
0xc80000c pIRDA_RESERVED Unknown.

The purpose of pIRDA_BEAM is to turn the actual beam on/off.  Writing a 1 to the LSB of this address seems to turn on the beam, a 0 turns it off.  Based on my disassembly of the Chocobo World program, however, I have two theories about this memory location:

  1. Writing a 1 to the LSB turns the beam on, a 0 turns it off.  The rest of the bits don't matter.
  2. Whatever is written to this location, the IrDA module attempts to send out - so for exampe, if 0x77777777 is put here, a pulse is sent out of mixed 1s and 0s.
I have not been able to verify which theory is correct.  The sensing strips at Radio Shack don't have good enough resolution to be able to tell the difference, except possibly through average intensity, and I can't tell any difference there.

The control location supports a number of operations designed around the IrDA module.  Here is a partial list:
 
Value Name Purpose
IR_MODE_RECV 0x00 Put in receive mode
IR_MODE_SEND 0x01 Put in send mode
IR_STOP 0x02 Turn off the IrDa module - see below
IR_SEND_READY 0x04 ??
IR_RECV_READY 0x08 ??

The purpose of some of these is confusing to me.  I know that, to send a beam, the IR module must be in send mode.  I also know that there is an interrupt which can be caused by the Infrared module - and I would assume that this is used to trigger that a character has been read in RECV mode.  This interrupt is 0x1000 (see interrupts elsewhere in the document).  The last two entries are a mystery to me.  Chocobo World doesn't seem to use them.  They might be synchronization primitives - I don't know.  IR_STOP is also confusing.  Generally it is used when a program exits.  What I don't know is - does this disable the beam entirely, or just disable the IrDA logic around the beam?

So there are still many questions.  But for those of you who want to experiment with making two-player games, this should be enough to get started.
 

A word about resolution and intensity

The beam in the PocketStation is very small and low-powered, maybe a tenth of a normal TV remote.  It also suffers from a pretty high available resolution - the problem I've been having with the TV remote is that if you try to turn it on for just 275us, very little comes out at all.  I've written a pretty tight timing loop, which is available as part of the IR test program, but you don't get much IR beam out when you do this.

Personal Contributions

These are items which I personally have written.  They may be linked at other parts of the page, but I wanted to have them all together in one place.

Links