![]() |
Forum Index : Microcontroller and PC projects : MM2 and ARMmite touch screen routines
Author | Message | ||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10246 |
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 KingdomPosts: 10246 |
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 KingdomPosts: 2933 |
You genius! ![]() ![]() ![]() |
||||
Zonker![]() Guru ![]() Joined: 18/08/2012 Location: United StatesPosts: 767 |
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..! ![]() |
||||
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |