Graphics tablets for Wii

Introduction

As far as I know, two different types of graphics tablets were available for Wii and for a project I'm working on, I need to be able to communicate with both models. So I acquired them and figured out how they communicate. The process is documented on this page.

Here is a quick external comparison between the two tables:

uDraw tablet

uDraw tablet

Drawsome tablet

Drawsome tablet




They are quite similar. Both will connect to a Wiimote and have a recess for it.

The uDraw tablet pen offers two lateral buttons:

uDraw pen

uDraw pen



But the Drawsome pen has none:
Drawsome pen

Drawsome pen



uDraw tablet protocol

I connected the tablet to the raphnet-tech Classique controller to USB adapter which I designed. This adapter has advanced functions which enables direct controller communication. In the case of Wiimote peripherals, the procotol is I2C. So in other words: I use the adapter as an USB I2C interface.

If you are not familiar with how Wiimote peripheral work, here is an excellent reference:

https://wiibrew.org/wiki/Wiimote/Extension_Controllers


The adapter manager I developed for raphnet-tech adapters includes a command-line tool able to dump the memory content of Wiimote peripherals using I2C. At startup, it displays the 256 bytes of memory like this:



The type of peripheral is identified by the 6 last bytes. According to the documentation at wiibrew.org, the Drawsome tablet is identified by: 00 A4 20 00 13. As I expected, the uDraw tablet has a different ID: 00 A4 20 01 12.

All Wiimote peripherals I ever worked with report their state (button status, axes position, etc) with a series of bytes starting at address 0. My command-line tool continuously reads the 16 first bytes and displays them on a new line whenever they change.

At this point, I just had to move the pen around while looking at the screen to deduce how the data was encoded:

Événemenet bruts

Événemenet bruts



The X/Y pen position is encoded using 12 bits, the tip pressure over 8 bits, and each button uses 1 bit.

ByteUse
0X (The 8 least significant bits)
1Y (The 8 least significant bits)
2Bits 7-4: Y (The 4 most significant bits)
Bits 3-0: X (The most significant bits).
3Tip pressure. Varies between 0x08 (no pressure) and 0xFB (high pressure)
4??? (Always 0xFF)
5Button status:
  • Tip: Bit 3 (1 when pressed)
  • Bit 1: Button 1 (0 when pressed)
  • Bit 0: Button 2 (0 when pressed)
With 12 bits, values ranging from 0 to 4095 can be reported. But in practise, the tablet range of value is narrower:
  • X: Varies between 95 and 1960
  • Y: Varies between 95 and 1440
When the pen is outside the active zone, the tablet reports 4095,4095.

To make sure I got it right, I wrote code to extract the fields and display them in an easier to read format:
void wusbmotelib_bufferToUdrawData(const uint8_t *buf, udraw_tablet_data *dst)
{
	dst->x = ((buf[2] & 0x0f) << 8) | buf[0];
	dst->y = ((buf[2] & 0xf0) << 4) | buf[1];
	dst->pressure = buf[3];
	dst->buttons = buf[5] ^ 0xfb;
}
...

	case ID_UDRAW:
		wusbmotelib_bufferToUdrawData(status, &udraw_data);
		printf("X: %6d, Y: %6d, P=%3d, Buttons: 0x%02x  (%3d %3d)\n",
				udraw_data.x,
				udraw_data.y,
				udraw_data.pressure,
				udraw_data.buttons,
				(udraw_data.x - 90 - (1440-90)/2),
				(udraw_data.y - 90 - (1920-90)/2));
...

And here is what the above outputs. Everything seems fine!



Thanks to the above info, firmare version 2.2. of the Classic controller to USB adapter (raphnet-tech) will support this tablet for use as a mouse.



Drawsome tablet protocol

For the Drawsome tablet, I began with the same steps as before (see above). Here is the memory dump:



The extension ID bytes (the last 6 bytes) were exactly as documented at wiibrew.org: 00 A4 20 00 13. Great!

But there things got more complicated. Unlike the uDraw tablet, nothing happens when I move the pen around. The first 6 bytes remain fixed at the values shown above: 00 00 00 00 00 c0.

Fearing that I might have a defective tablet, I tried it out with the bundled game on a Wii. But it worked perfectly, so I concluded that I probably had to send a message to the tablet to enable it first. But what message exactly and how?

The easiest way to find out would have been to use my logic analyzer to capture the exchange between the Wiimote and the tablet when in use. But as I did not have my analyzer with me, I used a brute force approach: Write all possible values at all addresses while monitoring the first 6 bytes for changes.

In pseudo-code, this is:
for (value=0; value <= 255; value++) {
	for (address=0; address <= 0xFF; address++) {
		write_byte(address, value);

		printf("0x%02x: %d\n", address, value);

		readbytes(0, 6, buffer);
		print_bytes_if_changed(buffer);
	}
}
After staring at the scrolling screen while continuously moving the pen over the tablet for a few minutes, it suddenly began showing data!



It began working right after a value of 85 (0x55) had been written to address 0xF0. Could it be that simple? Unfortunately no. I tried just writing 0x55 to address 0xF0 but it did not work. This meant that writing another value before that one was probably necessary.

I then narrowed the range of tested addresses to 0xF0 - 0xFF (16 locations).
for (value=0; value <= 255; value++) {
	for (address=0xF0; address <= 0xFF; address++) {
		write_byte(address, value);

		printf("0x%02x: %d\n", address, value);

		readbytes(0, 6, buffer);
		print_bytes_if_changed(buffer);
	}
}
It still worked, and it was much faster. I then experimented a bit with the values and soon discovered that writing a value of 0x01 somewhere prior to the final 0x55 was required:

// Step 1
value = 0x01;
for (address=0xF0; address <= 0xFF; address++) {
	write_byte(address, value);
}

// Step 2
value = 0x55;
address=0xF0;
write_byte(address, value);
The above writes 0x01 to all addresses from 0xF0 to 0xFF, and then writes 0x55 at address 0xF0. This enables the tablet.

OK, but is writing 0x01 at 16 different locations really necessary? I found out by trial and error:
  • 0xF8 - 0xFF : Still works
  • 0xFC - 0xFF : Does not work
  • 0xF8 - 0xFC : Works
  • 0xF8 - 0xFA : Doesn't
  • 0xFB alone : It works!
So the magic recipe to enable the tablet appears to be:
  1. Write 0x01 to address 0xFB
  2. Write 0x55 to address 0xF0
Excellent! So with this small problem out of the way, I proceeded to observe how the bytes would change according to how the pen moves:

Événemenet bruts

Événemenet bruts



The X/Y pen position is transmitted over 16 bits and pressure using 12 bits. And there is one status bit that indicates if the pen is in-range.

ByteUse
0X (LSB)
1X (MSB)
2Y (LSB)
3Y (MSB)
4Pressure (LSB)
5Bits 7-4: Status bits (0x4 when the pen is in-range, otherwise 0xC)
Bits 3-0: Pressure (top 4 bits)
  • X varies from 0 to 10206 (left to right)
  • Y varies from 0 to 7422 (top to bottom)
  • Pressure varies from 0 (no pressure) to 2047
Again I wrote code to extract the fields and display them in an easier to read format:
void wusbmotelib_bufferToDrawsomeData(const uint8_t *buf, drawsome_tablet_data *dst)
{
	dst->x = buf[0] | buf[1]<<8;
	dst->y = buf[2] | buf[3]<<8;
	dst->pressure = buf[4] | (buf[5]&0x0f)<<8;
	dst->status = buf[5]>>4;
}
...

	case ID_DRAWSOME:
		wusbmotelib_bufferToDrawsomeData(status, &drawsome_data);
		printf("X: %6d, Y: %6d, P=%3d, status: 0x%02x (%s)\n",
				drawsome_data.x,
				drawsome_data.y,
				drawsome_data.pressure,
				drawsome_data.status,
				drawsome_data.status & 0x08 ? "Pen out of range":"Pen in range"
				);
...
And everything is in place. Success!



Thanks to the above info, firmare version 2.2. of the Classic controller to USB adapter (raphnet-tech) will support this tablet for use as a mouse.



References

Note: As of now (March 14 2019) the information on Wiibrew.org regarding the Drawsome tablet is incorrect. What is shown is in fact the uDraw format... But as soon as I get the chance, I'll try to update the wiki.