Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 12:38 13 Jul 2025 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM2 and ARMmite touch screen routines

Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10246
Posted: 10:18am 21 Mar 2015
Copy link to clipboard 
Print this post

Now the various TFT displays can be driven from Basic, I have tidied up the routines I use for driving the touch screen controllers. This code should work on any of the various makes of 2046 resistive touch screen controllers e.g XPT2046.

The key to getting a stable sample is to take multiple readings and then filter them in some way. In this code I'm sampling NSAMPLES times into arrays and then using sort Cfunctions to find the median value - this seems to give a nice stable value. I've included a sort Cfunction for both the MX170/470 and the STM32F4 in the code - just call the one applicable.

The code just returns the raw values from the controller. These then need converting into coordinates to match the screen coordinates. However, the mechanism for this will depend on the calibration of the individual screen, which screen orientation you are using (i.e. x and y may be reversed) and whether the touch screen counts are increasing or decreasing in line with the coordinates or opposite them.

I've tested the code on a couple of displays, the ILI9341 and the SSD1963. Note that if you are using a SPI coupled display you need to use a different SPI channel for the touch screen and display (not possible on the MX170).


option explicit
option default NONE
const NSAMPLES=9
const T_IRQ=59
const t_CS=60
'
init:
spi open 1000000,3,8
dim integer xvalues(NSAMPLES-1),yvalues(NSAMPLES-1),y0,x0,j
setpin t_irq,din
setpin t_cs,dout
main:
do
if T.getxy(xvalues(),yvalues(),1000,9)then
j=shellsortMX(xvalues(),NSAMPLES) 'change to use ARM sort as required
j=shellsortMX(yvalues(),NSAMPLES) 'change to use ARM sort as required
x0=xvalues(NSAMPLES\2) 'get the median x value
y0=yvalues(NSAMPLES\2) 'get the median y value
dosomething(x0,y0)
else
donothing
endif
loop
end
'
sub dosomething( x as integer, y as integer)
print x,y
pause 300
end sub
'
sub donothing( x as integer, y as integer)
print ".";
end sub

function T.Getdata(command as integer) as integer 'get data from the touch controller
local integer i,j,k
pin(T_CS)=0
i=spi(command)
j=spi(0)
k=spi(0)
pin(T_CS)=1
T.Getdata= (j*256+k)>>4
end function
'
function T.getxy(x() as integer, y() as integer, timeout as integer, samples as integer) as integer
local integer i
timer=0
for i=0 to samples-1
do while timer<timeout and pin(T_IRQ)=1:loop
if timer>=timeout then
T.getxy=0
exit function
else
y(i)=T.getdata(&H90)
x(i)=T.getdata(&HD0)
endif
next i
T.getxy=1
end function
'
CFunction shellsortMX
00000000
8ca20000 27bdfff8 afb10004 afb00000 00401821 00032fc2 00a31821 00031843
5060003d 00001021 0062282a 10a0fffa 00032fc2 00036823 000370c0 000d60c0
008e7021 0080c021 008c8021 00607821 0000c821 01e3282a 01c03021 8dd10000
14a0001e 8dcb0004 8f070004 03202821 0167402a 11000034 8f090000 01e04021
000840c0 00884021 00a3502a 02003021 ad090000 1540000f ad070004 8cc70004
8cc90000 0167402a 00ad5021 1100001f 00cc3021 00a04021 01402821 000840c0
00884021 00a3502a ad090000 1140fff3 ad070004 000528c0 00853021 25ef0001
01e2282a acd10000 accb0004 27390001 25ce0008 27180008 14a0ffd6 26100008
00032fc2 00a31821 00031843 1460ffc7 0062282a 00001021 00001821 8fb10004
8fb00000 03e00008 27bd0008 14ebffe9 0229402b 5100ffe8 000528c0 00a04021
1000ffde 01402821 54ebffe5 25ef0001 0229402b 5500ffca 01e04021 1000ffe0
25ef0001
End CFunction

CFunction shellsortARM
00000000
b089b480 6078af00 683b6039 2300e9d3 613b4613 61fb693b 69fbe040 e03961bb
00db69bb 4413687a 2300e9d3 2302e9c7 617b69bb 697be011 687a00db 697a18d1
1ad369fb 687a00db e9d34413 e9c12300 697a2300 1ad369fb 697a617b 429a69fb
697adb0d 1ad369fb 687a00db e9d34413 e9d72300 42900102 0303eb71 697bdbdb
687a00db e9d718d1 e9c12302 69bb2300 61bb3301 693b69ba dbc1429a 0fda69fb
105b4413 69fb61fb d1b62b00 0200f04f 0300f04f 46194610 46bd3724 7b04f85d
bf004770
End CFunction

 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 10246
Posted: 08:40am 02 Apr 2015
Copy link to clipboard 
Print this post

I've done some more development on the touch routines. Once the calibration has been run once the routines will now automatically compensate for all variations in which axis is which irrespective of which end of an axis the higher values are measured. The code also caters for and automatically compensates for any programmer-defined rotation of the screen



The developer must specify three key parameters as global constants
default_orientation must be set to 0 (portrait), or 2 (landscape), depending on the display used
screen_width is the pixel width of the screen in its default orientation
screen_height is the pixel height of the screen in its default orientation

The calibration routine must be run in the default orientation for the screen.
There are six key values which are returned by the calibration routine - T.calibrate:

The first thing it does is establish if the touch axis are the correct or whether X=Y and visa versa. Once it has tested and corrected for this it prints two values XSAMPLE0 and YSAMPLE0. These are output after the screen is touched for the first time together with the value for:
XLEFT0

Then by getting the user to touch the screen in 3 more locations it print values for:
XRIGHT0
YTOP0
YBOTTOM0


These are the values returned by the touch controller for the extreme positions on each of the two axis. It doesn't matter whether left is bigger than right or top is bigger than bottom, the code will compensate for this.

Once the six values have been measured for any particular screen they can be set as constants for future use and the calibration routine removed.

After hardware initialisation, the first call in the production code should then be to T.rotate(rotation).
This sets the screen itself to the desired rotation (0=portrait, 1=portrait inverted, 2=landscape, 3=landscape inverted) and initialises the internal copies of the initialisation constants( xsample, ysample, xleft, xright, ytop, ybottom, width, height) that are used in further processing. These copies will be modified at run-time by subsequent calls to T.rotate to compensate for any further changes in rotation.


There is just one simple user-function T.screenpos(x, y, timeout) that returns the actual screen coordinates as mapped by the current screen rotation. This means irrespective of screen rotation if you draw a box with particular coordinates, touching the screen within the box will return a x,y coordinate pair within the box - it can't get any easier
The timeout is specified in milli-seconds. The function will return a value of 0 if a timeout has occured without the screen being touched and 1 if a touch has occured.

I've attached two copies of the full test program including the calibration routine. One is configured for the ARMmite driving a SSD1963 800x480 screen (default orientation landscape) and one for the 64-pin MX470 driving a 240x320 ILI9341 SPI screen (default orientation portrait) - see the picture above featuring the mighty Skinnymite!

Both are tested as working in all 4 orientations after initial calibration.

The code in both cases is identical other than pin definitions, SPI channel usage, and the binary code for the shellsort Cfunction.

2015-04-02_180855_touch.zip

To run the code in production the intialisation and main program is as simple as:


option explicit
option default NONE
CPU 96
'
const NSAMPLES=9 'number of times to sample each touch point
const t_CS=2 'chip select pin for XPT2046 touch controller
const T_IRQ=3 'interrupt pin for XPT2046 touch controller
const XLEFT0=1859, XRIGHT0=217, YTOP0=181, YBOTTOM0=1795 ' global constants to define calibration values
DIM INTEGER XLEFT, XRIGHT, YTOP, YBOTTOM ' global variables to hold active values
DIM INTEGER xvalues(NSAMPLES-1),yvalues(NSAMPLES-1)' arrays to hold raw sample values
pin(t_CS)=1
setpin t_irq,din
setpin t_cs,dout
CONST default_rotation=0 'default screen orientation for this display type, in this case portrait
' this constant must be either 0 = portrait or 2= landscape
const screen_width=240 'width of display in use
const screen_height=320 'height of display in use
dim integer width, height'active values based on current orientation
' 0=portrait, 1=portrait inverted, 2=landscale, 3=landscape inverted
DIM integer XSAMPLE0=&HD0 'parameters to hold XPT commands, these may be reversed by the calibration routine
'for a particular application these values can be saved and set as constants
DIM integer YSAMPLE0=&H90
DIM INTEGER XSAMPLE, YSAMPLE
'
dim integer x,y 'main program variables
'
spi2 OPEN 1000000,3,8
display open ILI9341S,1,30,32,31,screen_width,screen_height
'
T.rotate(2)
display 2,0,0,&H07E0,0,"Top left"
main:
if t.screenpos(x,y,1000) then
if x>3 and x<width-3 and y>3 and y<height-3 then circle x,y,3,&HFFFF,f
endif
goto main





 
WhiteWizzard
Guru

Joined: 05/04/2013
Location: United Kingdom
Posts: 2933
Posted: 10:12am 02 Apr 2015
Copy link to clipboard 
Print this post

You genius! Edited by WhiteWizzard 2015-04-03
 
Zonker

Guru

Joined: 18/08/2012
Location: United States
Posts: 767
Posted: 10:31am 02 Apr 2015
Copy link to clipboard 
Print this post

WoW...

Taking a look at the 170 C Function code compared to this new "snippet" to do basically (pun) the same thing... Man... That's what I call "easy-peasy" for the end user... I have the same setup here, (big G's Skinny & touch panel) so I will give this try and see if I can get the KBD setup to function... (sweet)..!

Thanks Matherp for making the hard stuff easier..!
 
Print this page


To reply to this topic, you need to log in.

The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2025