XPT2046 SPI Smartpin driver
cheezus
Posts: 298
in Propeller 2
I wanted to share this bit of code I've been working on for reading X-Y from the touch panel ADC. It could be generalized into an SPI driver but I think I'm going the other route and creating a SPI cog for my platform. I have 3 spi devices +1 spare external, with muxed cs creating an object to handle all of it makes sense. I have some crazy ideas for later.. Maybe someone will find it useful as is, (and I need to check what the RPI display I have uses...)
I'm thinking of pre-encoding the x,y config registers since these don't change... I'm thinking about keeping the bit-time conversion though, since I could be changing the clock dynamically in the future. It might make sense to pre-compute as much of the bit-time calc as possible, but haven't really looked at that yet. I also am inverting the clock pin using the out register. This is a residual from testing, as is the removal of the GetMask and hard-coding of the b-pin.
It works for now and I hope to not have to revisit this until I'm writing a driver for the SPI flash. Two down (the important 2), one to go! Now I just need to refine the touch panel calibration program and it's almost demo time!
I'm thinking of pre-encoding the x,y config registers since these don't change... I'm thinking about keeping the bit-time conversion though, since I could be changing the clock dynamically in the future. It might make sense to pre-compute as much of the bit-time calc as possible, but haven't really looked at that yet. I also am inverting the clock pin using the out register. This is a residual from testing, as is the removal of the GetMask and hard-coding of the b-pin.
It works for now and I hope to not have to revisit this until I'm writing a driver for the SPI flash. Two down (the important 2), one to go! Now I just need to refine the touch panel calibration program and it's almost demo time!
CON {{ ============================================================= Basic X-Y driver for XPT 2046 Touch Screen Controller Inline Smartpin SPI v0.5 - 11-26-19 Cheezus Slice - Cheezusslicedj@gmail.com This driver uses hard-coded pins but should be easy to make dynamic if you wish. Only reads X-Y ============================================================= }} _CS = 15 '+ 32 ' chip select _CLK = 13 '+ 32 ' Pins A, uncomment +32 for Pins B _DI = 14 '+ 32 ' MOSI _DO = 12 '+ 32 ' MISO '' config register '' S A2__A1__A0 MODE SER PD1__PDO y_cfg = %1__1___0___1___0____0____0____0 ' X DIFF x_cfg = %1__0___0___1___0____0____0____0 ' Y DIFF { z1_cfg = %1__0___1___1___0____0____0____0 ' Z1 DIFF z2_cfg = %1__1___0___0___0____0____0____0 ' Z2 DIFF t_cfg = %1__0___0___0___0____1____0____0 ' temperature b_cfg = %1__0___1___0___0____1____0____0 ' battery a_cfg = %1__1___1___0___0____1____0____0 ' battery } '' spi stuff spi_clk_max = 2_000_000 '%AAAA_BBBB_FFF_PPPP_PPP_PPP_PPP_TT_MMMMM_0 'ppp =___xxxx_CIO_HHH_LLL sp_inv_pin = %0000_001_000_000 << 8 'smartpin modes TT_MMMMM_0 sp_stx = %01_11100_0 + (%1111 << 24) ' -1 b pin - clk sp_srx = %00_11101_0 + (%0001 << 24) ' +1 b pin - clk sp_clk = %01_00101_0 '+ sp_inv_pin 'sp configs stx_c = (%1 << 5) + (numBits - 1) ' start-stop mode srx_c = (%0 << 5) + (numBits - 1) ' pre-clock sample clks = numBits * 2 numBits = 24 ' 24 bits conversion PUB TouchXY| x, y, xo, yo, b b := GetBitTime(spi_clk_max) asm '' prepare data out x ?should pre-encode? mov xo, #x_cfg ' type is conversion SHL xo, #32-8 ' Set MSB First REV xo ' Set MSB First '' prepare data out y mov yo, #y_cfg SHL yo, #32-8 REV yo '' clk - transition dirl #_CLK outh #_CLK ' mode 1,1 - clock starts high wrpin #sp_clk, #_CLK wxpin b, #_CLK ' set base period (*2) dirh #_CLK '' do - srx dirl #_DO wrpin #sp_srx, #_DO ' sync rx wxpin #srx_c, #_DO ' stop/start mode dirh #_DO '' di - stx dirl #_DI wrpin #sp_stx, #_DI ' sync tx wxpin #stx_c, #_DI ' stop/start mode wypin #$FF, #_DI dirh #_DI drvl #_CS '' prepare to read rdpin pa, #_DO ' clear RX buffer wypin xo, #_DI ' data !! '' start clock rdpin pa, #_CLK wypin #clks, #_CLK ' start clock .busy testp #_CLK wc if_nc jmp #.busy rdpin x, #_DO ' get data '' prepare to read rdpin pa, #_DO ' clear RX buffer wypin yo, #_DI ' data !! '' start clock rdpin pa, #_CLK wypin #clks, #_CLK ' start clock .busy2 testp #_CLK wc if_nc jmp #.busy2 rdpin y, #_DO ' get data drvh #_CS ' drive CS high ' now handle data shl x, #3 ' throw away msb rev x and x, #$ffff ' isolate 12b ' now handle data shl y, #3 ' throw away msb rev y and y, #$ffff ' isolate 12b wypin #0, #_DI ' clear buffer wrpin #0, #_CLK wrpin #0, #_DO wrpin #0, #_DI dirl #_CLK dirl #_DO dirl #_DI endasm result := x + (y << 16) PRI getmask(clk, data) : t ' get mask to add to smartpin mode t := clk - data if ( || t ) <> t t := ( || t ) + %0100 PRI GetBitTime(max_clkfreq) : bt bt :=((clkfreq / max_clkfreq) /2 )+1 ' SPI bit time if bt < 2 ' make sure at least sysclock /2 bt := 2
Comments
Thanks loads for this! I've been able to get most of the way converting this to general-purpose usage. Are the number of clock pulses calculated by numBits and clks meant to cover both the register address write as well as the 16b read in your original code? I ask because initially, my knee-jerk reaction was to change it to 8 (well, change numBits to 8) for my device but this yielded no data with my device. Setting it back to 24 gets the expected value back from the reg, but along with some other junk before and after.
Cheers
Yes, numBits covered the 8 bit write, as well as the 16 bit read to make a 24 bit transfer. I'm not seeing anything that should prevent you from just changing numBits to 8, although I do have that nagging feeling there might be a gotcha somewhere. If i can think of anything I'll update this post when i do!
After a few days of working on bits and pieces, I was able to get a general-purpose smart pin SPI engine going, based on your code. (com.spi.spin2 at https://github.com/avsa242/p2-spin-standard-library/tree/testing/library). Limitations are it only does mode 0...couldn't figure out how to get CPOL 1 working...I was able to invert the clock pin output, but the number of bits shifted out ended up being incorrect...will have to revisit this at some point. Also only MSB-first data. It's translated to FastSpin spin2 also, so it looks much different than your original code, but I felt it should be credited in the header, anyway.
Cheers,
Jesse
MSB/LSB should be fairly easy, although i'm not sure I have any LSB devices to test with.
In READ, remove result := (result rev 31) & $FF ' Reverse bit order and discard
In WRITE, remove val <<= (32-8) ' Move byte to MSB position
val := val rev 31 ' Reverse bit order
Polarity as I said is trickier, but i think change sampling from pre to post?
A comment for anyone that wants to use this code:
If your DI pin is not immediately before the CLK pin, you will need to adjust the clock pin offset (%1111) below: Likewise, if your DO pin is not immediately after the CLK pin, you will need to adjust the clock pin offset (%0001) below: