DS Touch Screen Information
It's a TI TSC2046 controller, hooked up to the ARM7 SPI port. News at 9.
Command Format:
bit | name | description |
7 | S | Start bit |
6..4 | A2..A0 | Channel select |
3 | Mode | 12 bit/8 bit conversion mode |
2 | SER/DFR | read type |
1..0 | PD1..PD0 | power-down mode |
Power down mode:
PD1 | PD0 | /PENIRQ | Description |
0 | 0 | Enabled | Power-down between conversions |
0 | 1 | Disabled | Voltage reference off, ADC on |
1 | 0 | Enabled | Voltage reference on, ADC off |
1 | 1 | Disabled | Device always powered. Voltage reference on, ADC on |
/PENIRQ is wired to bit 6 of R2_CR
The DS has wired an external VREF of 3.3 V to the TSC, instead of using the internal 2.5 VREF. This impacts the temperature calculations below, and converting any reading into an actual voltage.
Useful commands:
Constant | Value | Notes |
TSC_MEASURE_TEMP1 | 0x84 | Measures temperature diode 1 |
TSC_MEASURE_Y | 0x94 | Measures Y position |
TSC_MEASURE_BATTERY | 0xA4 | Does not work on DS, VBAT is grounded |
TSC_MEASURE_Z1 | 0xB4 | Measures cross-panel position 1 |
TSC_MEASURE_Z2 | 0xC4 | Measures cross-panel position 2 |
TSC_MEASURE_X | 0xD4 | Measures X position |
TSC_MEASURE_AUX | 0xE4 | Measures ?, its non-zero, but I don't know what |
TSC_MEASURE_TEMP2 | 0xF4 | Measures temperature diode 2 |
A 12-bit measurment cycle consists of 3 SPI byte transfers:
- The first transfer sends the command and returns no meaningful data.
- The second transfer returns 0 measurement(11)..measurment(5)
- The third transfer returns measurment(4..0) 000
Thus, pseudocode for measuring a TSC input is:
BlockingWriteSPI(command); data = BlockingWriteSPI(0); data = (data << 5) | (BlockingWriteSPI(0) >> 3);
Temperature calculation:
Temperature diode two has a 91 times larger current, and the absolute temperature can be calculated based on the measurements of the two sensors. I'll present a fixed point algorithm for computing the temperature in degrees C (see the TSC 2046 datasheet for the original equation).
Reading from the touchscreen controller (SPI)
uint16 touchRead(uint32 command) {
uint16 result;
while (SERIAL_CR & SERIAL_BUSY) swiDelay(1);
// Write the command and wait for it to complete
SERIAL_CR = SERIAL_ENABLE | 0x800 | 0x201;
SERIAL_DATA = command;
while (SERIAL_CR & SERIAL_BUSY) swiDelay(1);
// Write the second command and clock in part of the data
SERIAL_DATA = 0;
while (SERIAL_CR & SERIAL_BUSY) swiDelay(1);
result = SERIAL_DATA;
// Clock in the rest of the data (last transfer)
SERIAL_CR = SERIAL_ENABLE | 0x201;
SERIAL_DATA = 0;
while (SERIAL_CR & SERIAL_BUSY) swiDelay(1);
// Return the result
return ((result & 0x7F) << 5) | (SERIAL_DATA >> 3);
}
To do: figure out what bit 11, bit 9, and bit 0 are doing (bit 0 is probably the CR select, since the firmware reads have this bit cleared)
Position calculation
#define SCREEN_WIDTH 256
#define SCREEN_HEIGHT 192
// those are pixel positions of the two points you click when calibrating
#define TOUCH_CNTRL_X1 (*(vu8*)0x027FFCDC)
#define TOUCH_CNTRL_Y1 (*(vu8*)0x027FFCDD)
#define TOUCH_CNTRL_X2 (*(vu8*)0x027FFCE2)
#define TOUCH_CNTRL_Y2 (*(vu8*)0x027FFCE3)
// those are the corresponding touchscreen values:
#define TOUCH_CAL_X1 (*(vu16*)0x027FFCD8)
#define TOUCH_CAL_Y1 (*(vu16*)0x027FFCDA)
#define TOUCH_CAL_X2 (*(vu16*)0x027FFCDE)
#define TOUCH_CAL_Y2 (*(vu16*)0x027FFCE0)
// linear mapping can be used to go from touchscreen position to pixel position
// precalculate some values
static int16 TOUCH_WIDTH = TOUCH_CAL_X2 - TOUCH_CAL_X1;
static int16 TOUCH_HEIGHT = TOUCH_CAL_Y2 - TOUCH_CAL_Y1;
static int16 CNTRL_WIDTH = TOUCH_CNTRL_X2 - TOUCH_CNTRL_X1;
static int16 CNTRL_HEIGHT = TOUCH_CNTRL_Y2 - TOUCH_CNTRL_Y1;
// reading pixel position:
int16 x = (IPC->touchX - (int16) TOUCH_CAL_X1) * CNTRL_WIDTH / TOUCH_WIDTH + (int16) TOUCH_CNTRL_X1;
int16 y = (IPC->touchY - (int16) TOUCH_CAL_Y1) * CNTRL_HEIGHT / TOUCH_HEIGHT + (int16) TOUCH_CNTRL_Y1;