AN0319: SHIPTide – Implementing Calibration for Resistive Touch SIMs

Calibrating Resistive Touch Screens — the Concepts

Resistive touch screens are made of two planes of resistive gradient plastic, aligned 90 degrees from each other, separated by a tiny gap with microscopic beads to keep them apart. When you press down, these layers connect and the resistance gradient can be measured in both XY directions by an analog to digital converter (ADC).

These ADC XY readings must be offset/scaled to overlay the pixel coordinates of the screen in order to extract the XY location of the touch in pixels (rather than ADC values).

The “calibration” of a resistive touch screen, therefore, is all about getting the X and Y offsets+scaling values in order to translate ADC values to XY pixel values.

The most straight forward way to do this is to ask the user to sequentially touch two opposing corners of the screen. Knowing you expect a touch (for example) in the upper left at pixel XY [0,0], if you see (for example) ADC XY values of [20,103], then you know your offset is [20,103] to translate from ADC values to XY pixel values. Once you have the opposite corner (for example, the ADC coordinates on the bottom right of the screen press at pixel XY [glass width – 1, glass height – 1], you now can calculate the XY scaling factor.

However, it is critical that the calibration process be as accurate as possible, so several additional steps can be added:

  • sequentially touching each of the 4 corners, so as to get redundant ADC readings for each edge
  • asking for multiple touches in the same location and averaging the result

Once all the calibration ADC values have been obtained, the result must be either (a) committed to non-volatile storage for future use or (b) abandoned to revert to prior values if it is determined the calibration was not very accurate.

The demo project uses several of these techniques.

Calibration “Commands”

Assigning a 32-bit value to the touch port’s port variable calibrate delivers calibration commands to the touch controller. On most SIMs, this is the TOUCH.calibrate port variable.

The 32-bit value has a high 16-bit portion and a low 16-bit portion, and there are 4 types of calibration commands accepted by the touch controller:

(X<<16)|(Y)enter/continue calibration mode and expect this pixel coordinate as next touch down
0x80000001process the calibration sequence and start using; do not yet save in NV memory
0x80000000cancel calibration sequence and revert to prior values
0x80000002save in NV memory the new calibration values

Once the calibration mode has been entered, you will not receive TOUCH.DN/TOUCH.MV/TOUCH.UP events on TOUCH0.event.e. You will receive TOUCH.CALIBRATE events only on the press down. This allows your GUI to index to the next touch point. After the 0x80000001 (“process”) command, the TOUCH0.event.e resumes functioning as normal.

Entering Calibration Mode and Acquiring Calibration Points

The first step in calibration is to acquire a sequence of physical touches associated with known pixel locations in the 4 corners of the screen.

The demo project sequences through a simple software-driven state machine. Each corner is handled in a different state of the state machine. For example, the first corner is the left top (LT) corner and the GUI drives this sequence of events for this corner:

  1. The GUI makes the target visible and moves it so that its center is in the top left corner (location 0,0) on the LCD
  2. The GUI then send assigns TOUCH0.calibrate = (0<<16)|0;, which sends the location 0,0 to the touch driver’s special port variable. This assignment tells the touch driver to enter calibration mode (if not already there), and expect future touches at this coordinate
  3. The GUI displays a message on the screen telling the user to press the target
  4. The user now presses the screen, hopefully somewhere in the general region of that target!
  5. The touch driver, instead of sending the normal TOUCH.DN event to the GUI, instead (since it is in calibration mode) sends a special TOUCH.CALIBRATE event to the GUI
  6. The GUI’s touch listener “hears” that event, and uses that event to advance to the next corner

The next corner in the demo, for example, is the right top, which is at location [GLASS0.width-1,0], so makes the assignment TOUCH0.calibrate = ((GLASS0.width-1)<<16)|0;.

You can optionally ask for repeat touches in each corner by re-sending the same coordinate command and the touch controller will expect the next touch to be again in that same location. This will cause the two ADC readings to be averaged.

Exiting Calibration Mode

When all four corners have been acquired, the demo sends 0x80000001 to the touch driver calibration system (via the script assignment TOUCH0.calibrate = 0x80000001;), telling the touch driver to process all the ADC to Pixel relationships and generate the new offset/scaling values. The “calibration mode” is exited and the new calibration is in force, albeit temporarily.

The new calibration at this point has not been committed to NV memory. There is no assurance at this point that the user did a good job and that the calibration is accurate. At this point, the GUI needs to test for accuracy; only with some assurance of accuracy should the result be committed. Otherwise, the calibration sequence must be rejected and revert to the original values prior to the calibration cycle.

Committing/Cancelling Calibration Data

At this point in the process, the new calibration data (scaling+offset) is in force and is driving the conversion of touch ADC values to pixel values. Assuming the sequence was done well, the readings in the low level touch driver, translated by the scaling+offset, should yield pixel values very close to the correct location.

If this is true, the user should be able to easily hit a small icon on the screen.

If, however, the calibration data is inaccurate, the touch ADC values with scaling and offset will not line up with the pixels on the screen, and therefore even if a user thinks they are pressing an icon on the screen, the touch driver is calculating a very different XY pixel location which the GUI will map far away from that icon.

Therefore, the decision to “commit to non-volatile memory” the calibration data should be made after getting confirmation by a button hit that the calibration data is, indeed, resulting in a good mapping between the ADC driver values and the visible pixel locations.

The way this is normally done is two touch listeners. The first is assigned to the whole page, looking for any touch anywhere on the screen. This will trap all touches, regardless of good or bad calibration data. The second touch listener, further down in the layout, should be mapped to a button on the screen. Since SHIP uses a “last-best-touch” algorithm, the second touch listener will only get the event if the user touches on the button and the ADC calibration aligns that touch with the visual button on the screen. That should drive the commit event. However, if the user presses the button (or anywhere else) and the calibration data is misaligned, the first touch listener will get the event and should issue the cancel command which will discard all the new calibration data and revert back to the old calibration.

Example Project

Unpack the attached project to your local drive and open the project in SHIPTide. It’s written for the SIM231, but easily adaptable to other SIMs.