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.
- The professional tool from ARM, called the ARM Developer Suite. You can
get a free copy of the evaluation version from ARM just by filling out a
form. The evaluation version is fully capable but limited to 45
days. This suite runs on Win32.
- There is a semi-professional development suite available from SN Systems, a maker of development software
for consoles. I found this software on a third-party web page. One
would assume that the software comes with the full Playstation
development suite. However, I do not want to purchase the
development suite (obviously), and I cannot find a page which claims this
tool. That being said, the software is based on gcc, and as I'm sure you
all know, that means it's GPL. So without further ado, here is some development
software.
- There is also available a version of gcc which has been compiled and made
available for BSD. This is what is commonly used in Japan. I don't
know much about this software, since all the information available about it is
in Japanese. All I can do is point you to the following web page, which discusses
the software.
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 compiles arbitrary signed division to an assembly call to a
routine, '_divsi3'. Unfortunately this routine is not included - no external
libraries are. I attempted to write my own copy and include it, however
despite my best efforts I could not get it to work - it correctly evaluates
29/10 = 2, but it says 30/10 = 2 as well. If you want to work on it, it's
called 'divide' and it's in 'newstart.s'. So, for the moment, the compiler
itself is only capable of doing static divisions (i.e. #define FOO 36 / 9) or
simple unsigned divisions by powers of 2, which are encoded as shifts. I have
written my own C routine for doing arbitrary unsigned division and remainder,
but it is slow.
- The compiler doesn't really understand signed quantities. It doesn't
complain, but it doesn't get the right answer either. Signed comparisons
almost always fail and definitely don't do what you want. Comparing less than
0 doesn't even work. Simple math - addition and subtraction - seems to work,
but signed multiply doesn't. For comparing signed quantities I add a large
positive number to both sides - that seems to work, unless there is overflow,
of course. I recommend avoiding negative numbers if possible.
- Global non-const variables are not initialized, even if you ask that they
be. The solution to this is simple - initialize them first thing in main.
- Global arrays of 8-bit quantities (bytes) are not initialized properly
even if they are const. They also don't seem to work that well. If you really
want to use arrays of bytes, try "initializing" them in assembly, and writing
byte access routines. I have found that the "unsigned char" datatype is
unreliable, especially when dereferencing a pointer.
- In the emulator, you can rest a timer's count after you start it. In the
real PocketStation, you can't, and if you try it's just ignored. Also, the
emulator's timer is approximately 3-4 times as fast as the real PocketStation,
although it's not consistent and may very well vary depending on the machine
you run it on.
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:
- This routine only draws a pixel. To clear a pixel, use
VIDEO_MEMORY[31 - y] &= ~(1 << (31 - x)). To reverse
a pixel, use VIDEO_MEMORY ^= (1 << (31 - x)).
- This routine is not double-buffered, which is definitely
recommended. A good way to achieve double-buffering is to set up 32
unsigned ints of ram and write to that. Then use a routine once per
logical round which blits the data. One such routine is included in my
tic-tac-toe program, called BlitScreen.
- If you're writing a full-screen image, don't use this! Define the
image as 32 ints and blit the data directly onto the screen - remembering that
the top row is memory location 31. This routine is called DrawScreen in
my code.
- Note that with some pocket devices - the VMS, notably - 'keeping up with'
the display is a real concern. Some devices also require that the data
in the video memory be constantly 'refreshed', a la the Atari 2600. That
is not the case here - the processor is plenty fast, and the video ram is not
volatile.
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:
- Write an interrupt handler for the corresponding interrupt.
- Register it in the system interrupt table.
- Activate the desired interrupt.
- 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:
- IrDA. IrDA is a modern infrared-based protocol for transmitting
large (read: computer-oriented) amounts of data quickly. It is
bidirectional. You may think of it as a sort of "XModem" for infrared
devices. Although it has several configurable options (for example,
there are two available speeds), it specifies the pulse lengths, carrier
waves, etc. This sort of protocol is what you would use if you wanted 2
PocketStations to talk to each other. It works best when the data to be
sent is "discrete" - i.e., I want to send my high-score table to you, as
opposed to "continuous", as in a real 2-player game, like Pong.
- 'Legacy'. Legacy is a bad name for this because it is still very
much in use. This is the system used by most consumer devices - TVs,
stereos, etc. In this mode, there is no specified pulse length, carrier
wave - anything. Just 'on' and 'off'. Different devices have
different ways of coding pulses, and there is no real "standard".
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:
- Writing a 1 to the LSB turns the beam on, a 0 turns it off. The rest
of the bits don't matter.
- 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.
- An ARM7TDMI disassembler. Here is the source code,
and here is a Windows binary.
- The game of tic-tac-toe, for
the pocket station. A good starter. Here is just the binary,
in MCX format.
- Minesweeper
for the pocketstation, complete with scrolling playfield. Here is the binary. Note:
there is a bug in this game. It's nasty. Play for a while and you'll find it.
Anyone who can fix it earns my undying gratitude. I find it crashes once every
5 or 6 games, and always at the beginning. You may have to reset your
pocketstation.
- A very simple clock which shows
the time. Here is the binary. This
clock is very simple but instructional. I think the year is displayed
incorrectly - somebody fix it! Plus the code contains timing portions which
can be used to get accurate timings of timer0.
- A clone of space invaders.
Here is the binary.
- An infrared test
program, which is a first attempt at making a remote control. It
doesn't work.
Links
- tripmode - a somewhat
outdated page. I don't know who runs it, but it has the best information
in English, and a link to the SN Systems development tools.
- Aruka - a page about
developing on the ARM and the PocketStation which looks to be very informative
but is unfortunately in Japanese.