B4R Question ESP8266 2.8 TFT 240x320 Working Code Example

KiloBravo

Active Member
Licensed User
I was working on another project and decided to add a TFT Display. I had a 240x320 TFT laying around so decided to wire it up and Test it on a esp8266.
Code below is ONLY for the Display. Touch is not working. I ran out of Pins on the ESP8266 for the Touch to work. I used Erel's Lib Wrap of the ILI9341, STMPE610, and GFX.
I modified Erel's Lib to Add a RESET Pin to the Init/Constructor. I did this because I read in a post somewhere that Adafruit's docs say you don't need the RESET pin.
However they use it in their code and if you don't have it defined and use a knockoff board it can cause the board to crash. YMMV :)

My board does not have a STMPE610 Touch Chip. It uses an XPT2046 Touch Chip. So ignore the warning about STMPE610 not used from the compiler.

I am incorporating the display and touch into my current project with an ESP32. I ran out of pins to do it on the ESP8266.
I am working on wrapping the LCDWIKI_Touch Library to use in B4R. I will post that Lib when/if I get it working. :cool:

Besides the RESET pin, I think another gotcha for folks may have been that most code I saw says to use D8 (GPIO15) for CS (Chip Select). CS is ACTIVE LOW, PIN D8 has PULLDOWN Resistor tied to it. IMHO that won't work. Use another Pin for CS. This CODE uses the SPI Hardware defined pins. (D5 SCLock GPIO14, D6 MISO GPIO12, D7 MOSI GPIO13).

Another gotcha is I read posts where it says you don't need to have the MISO pin connected. But, you DO if you are using this Library.
SPI usually indicates a 4 wire interface CS, MISO, MOSI, Sclk, this is NOT the same as IIC/I2C which is a two wire interface SCL, and SDA. I read numerous posts on other sites where people use the terms interchangeably and incorrectly, which is why most of THEIR code does not work. YMMV.

Finally the Touch Chip on some TFT boards use STMPE610 or a clone which can be interfaced with SPI or I2C like the above mentioned Lib.

My TFT board uses the Touch Chip XPT2046. This has a completely different interface. It requires a four wire SPI interface and an ADDITIONAL Interrupt Pin. This is why I am wrapping the LCDWIKI_TOUCH Library so I can interface with the XPT2046 and use the Touch Screen.

I am going to post my Working code in the next post. Comments at the end list websites and resources I used to get it working. I will also attached my Lib with my changes to Erel's Wrap.

A long post but I hope some folks find the information provided useful in there projects. Any mistakes I made or critiques of what I said are welcome.



Live Long and Prosper!
 
Last edited:

KiloBravo

Active Member
Licensed User
My working code for the TFT Display.

Esp8266 TFT 240x320:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 300
#End Region

Sub Process_Globals
    Public Serial1 As Serial
    Private ILI As AdafruitILI93411
    Private Timer1 As Timer
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    Delay(100)
''
    Log("ILI9341 Init")
    ILI.Initialize(16,4,0)
    ' LED Pin Always ON, tied to 3.3V protoboard powersupply, power for TFT not driven by ESP8266
    ' Remember to tie the Grounds together :-)
    Delay(120) ''''''' Only INIT the TFT Once and the 120 ms delay IS needed or it fails ****
    Log("ILI9341 Init Done")
'
    Timer1.Initialize("TickSub_1",1000)
    Timer1.Enabled = True
    
End Sub

Sub TickSub_1  '''''''''' Works Up To Here   
    Log("Red")
    ILI.FillScreen(ILI.COLOR_RED)
    Delay(500)
    Log("White")   
    ILI.FillScreen(ILI.COLOR_WHITE)
    Delay(500)
    Log("Blue")
    ILI.FillScreen(ILI.COLOR_BLUE)
    Delay(500)
    Log("Done")
    ILI.FillScreen(ILI.COLOR_WHITE)
    Delay(500)
    Log("Draw Text")
    Delay(500)
    ILI.GFX.ConfigureText(2, ILI.COLOR_BLACK, True)
       ILI.GFX.SetCursor(2, 2)
       ILI.GFX.DrawText("This is a test")
    Log("Draw Text Done")
    Log("Height: ", ILI.GFX.Height)
    Log("Width: ", ILI.GFX.Width)
    Delay(500)
'''''''''''''''''''''''''''''''   
    ILI.GFX.DrawCircle(120, 160, 100, ILI.COLOR_RED,True)
    Delay(5000)
    
End Sub

'''''''''' Notes '''''''''''
' B4R v3.90
' Arduino v1.8.12
' Board Lolin D1 Mini Pro
' https://www.wemos.cc/en/latest/d1/d1_mini_pro.html#

' I2C Bus Esp8266
' D1 is GPI05 SCL  ''' Check This But Not Used In This Project
' D2 is GPI04 SDA  ''' Check This But Not Used In This Project
'
' SPI Bus   
' D5 GPI014 SCK                    ''' Standard on Lolin D1 Mini Pro
' D6 GPI012 MISO                   ''' Standard on Lolin D1 Mini Pro
' D7 GPI013 MOSI                   ''' Standard on Lolin D1 Mini Pro
' D0 GPI016 Chp Select SS/CS    ''' Changed See Below ''' KB :-)

'// Constructor when using hardware SPI.  Faster, but must use SPI pins
'Adafruit_ILI9341::Adafruit_ILI9341(int8_t cs, int8_t dc, int8_t rst) : Adafruit_GFX(ILI9341_TFTWIDTH, ILI9341_TFTHEIGHT) {
' // _cs   = cs;
' // _dc   = dc;
' // _rst  = rst;
' // hwSPI = true;
' // _mosi  = _sclk = 0;
' Modified Erel's Wrap to INCLUDE the RST in the CONSTRUCTOR ********
'  _cs   = 16;     // D0     I0 **** Can't use "D8" Has A pull Down Resistor CS is Active Low which means Chip will alsways be selected ****
'  _rst  = 0;    // D3     IO, 10k Pull-up
'  _dc   = 4;      // D2     IO, SDA
'  _mosi  = 13;    // D7
'  _sclk = 14;    // D5
'  _Led = Backlight Hardwired to +3.3V 
'  _miso = 12;    // D6
'  hwSPI = True;
'}   

'Lolin D1 Mini Pro Pinout '' https://www.wemos.cc/en/latest/d1/d1_mini_pro.html#pin
'
'Pin     Function         ESP-8266 Pin
'TX         TXD             TXD
'RX         RXD             RXD
'A0         Analog              A0        input Max 3.2V
'D0         IO                 GPIO16
'D1         IO, SCL         GPIO5
'D2         IO, SDA         GPIO4
'D3         IO,             GPIO0    10k Pull-up
'D4         IO,             GPIO2      10k Pull-up BUILTIN_LED
'D5         IO, SCK         GPIO14
'D6         IO, MISO         GPIO12
'D7         IO, MOSI         GPIO13
'D8         IO, 10k         GPIO15     10K Pull-down,
'G         Ground             GND
'5V         5V     -
'3V3     3.3V             3.3V
'RST     Reset             RST

'2.8 TFT SPI 240x320 V1.2 '' http://www.lcdwiki.com/2.8inch_SPI_Module_ILI9341_SKU:MSP2807
' TFT/Display Chip Unknown but works with ILI93411
' Touch Chip XPT2046  NOT --- STMPE610
'' Below Not Used in this Project
'' https://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf
'' Datasheet lists http://http://xptek.com.cn/  As the Chip Maker
'' https://github.com/spapadim/XPT2046  Driver Code
 

Attachments

  • TFT_Lib.zip
    45.7 KB · Views: 59
Upvote 0

KiloBravo

Active Member
Licensed User
Just wanted to add on my module the Display chip is in/or under the Display board and can not be identified by sight.
There is an SPI command in the Library to determine the Display Chip. But I did not use it.
Try my code and if it works it is compatible with the ILI9341.

The Touch Chip is visible on the back of the board and wired to the T_ pin outs. You can just look at that one and see what it is.

Enjoy!
 
Upvote 0

KiloBravo

Active Member
Licensed User
This is the working code for the ESP32 uses the same Libs as above.

Lolin32 V1.0.0 ESP32 TFT - No Touch yet:
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 600
#End Region

Sub Process_Globals
    Public Serial1 As Serial
    Private ILI As AdafruitILI93411
    Private Timer1 As Timer
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    Delay(100)
''
    Log("ILI9341 Init")
'
'     TFT_MISO 19
'     TFT_MOSI 23
'     TFT_SCLK 18
'     TFT_CS    5   // Chip Select control pin
'     TFT_DC    16  // Data Command control pin
'     TFT_RST   17  // Reset pin (could connect To RST pin)
'
    ILI.Initialize(5,16,17)
    ' LED Pin Always ON, tied to 3.3V protoboard powersupply, power for TFT not driven by ESP32
    ' Remember to tie the Grounds together :-)
    Delay(120) ''''''' Only INIT the TFT Once and the 120 ms delay IS needed or it fails ****
    Log("ILI9341 Init Done")
'
    Timer1.Initialize("TickSub_1",1000)
    Timer1.Enabled = True
   
End Sub

Sub TickSub_1    
    Log("Red")
    ILI.FillScreen(ILI.COLOR_RED)
    Delay(500)
    Log("White")  
    ILI.FillScreen(ILI.COLOR_WHITE)
    Delay(500)
    Log("Blue")
    ILI.FillScreen(ILI.COLOR_BLUE)
    Delay(500)
    Log("Done")
    ILI.FillScreen(ILI.COLOR_WHITE)
    Delay(500)
    Log("Draw Text")
    Delay(500)
    ILI.GFX.ConfigureText(2, ILI.COLOR_BLACK, True)
       ILI.GFX.SetCursor(2, 2)
       ILI.GFX.DrawText("This is a test")
    Log("Draw Text Done")
    Log("Height: ", ILI.GFX.Height)
    Log("Width: ", ILI.GFX.Width)
    Delay(500)
'''''''''''''''''''''''''''''''  
    ILI.GFX.DrawCircle(120, 160, 100, ILI.COLOR_RED,True)
    Delay(5000)
   
End Sub
 
Upvote 0

KiloBravo

Active Member
Licensed User
I spent a little time on writing some code to read the XPT2046. I followed this example ...
https://www.ccsinfo.com/forum/viewtopic.php?t=58912 for A PIC Chip. He also mentions ...
"This is a functional driver you can use on the XPT2046 or the TI TSC2046, it MAY also work with the ADS7843"

I can read the Data (x,y,z). My XY rotation seems to be off from the ILI9341. Could be my bit manipulation or the Select Case.
I did not calibrate anything. I just wanted to see if I could pull the point location off of the screen which it seems to do. But not in the right orientation.
I did not use an interupt. I am just polling the tirq pin with a timer.

Thanks to whoever ported the rSPI32 Library it worked great ! 🍻

I will post the code but it is very raw and not a driver just some quick and dirty code to read the point on the touch screen.
Probably lots of Code Smells in there as well! 🙃
"If" I clean it up I will update the code on this thread. Enjoy!

Use At Your Own Risk ! XPT2046 read code :-):
#Region Project Attributes
    #AutoFlushLogs: True
    #CheckArrayBounds: True
    #StackBufferSize: 600
#End Region

Sub Process_Globals
    Public Serial1 As Serial
    Private ILI As AdafruitILI93411
    Private Timer1 As Timer

    Public tirqPin As Pin
    Public X_COMMAND_BYTE As Byte = 0xD0  ' get X values
     Public Y_COMMAND_BYTE As Byte = 0x90  ' get Y values
     Public Z1_COMMAND_BYTE As Byte = 0xB1 ' get Z1 value
     Public Z2_COMMAND_BYTE As Byte = 0xC1 '  get Z2 value
     Public MSB_BIT_MASK As Byte =  0x7F   '     Bit mask For MSB byte
     Public Z_THRESHOLD  As Byte =   400
    Public Z_THRESHOLD_INT    As Int = 75
    Public X_Val, Y_Val As UInt
     Public Z_Val, Z1, Z2 As Int
     Public xraw, yraw As Int
     Public ScreenRotation As Byte = 3 'screen rotation
     Public TOUCH_FLAG As Boolean = False
End Sub
' Followed the example below from "cbarberis" Written for a PIC Chip. 
'https://www.ccsinfo.com/forum/viewtopic.php?t=58912
'//For resolution 240x320,the calibration parameter is 663,-13,894,-30
' XFAC      663
' XOFFSET   (-13)
' YFAC      894
' YOFFSET   (-30)

Private Sub AppStart
    Serial1.Initialize(115200)
    Log("AppStart")
    Delay(100)
''
    Log("ILI9341 Init")
    ILI.Initialize(5,16,17)
    ILI.SetRotation(1)
    
    ' LED Pin Always ON, tied to 3.3V protoboard powersupply, power for TFT not driven by ESP8266
    ' Remember to tie the Grounds together :-)
    Delay(120) ''''''' Only INIT the TFT Once and the 120 ms delay IS needed or it fails ****
    Log("ILI9341 Init Done")
    Delay(120) ''''''' Only INIT the TFT Once and the 120 ms delay IS needed or it fails ****
'
    ScreenSet
'
    SPI.CheckIfThisBoardIsSupported
    'CHANGE HERE THE PIN NUMBERS (SCK, MISO, MOSI, CS)
    'SS/CS =15 MISO=12 MOSI=13 SCK =14 T_IRQ = 0
    SPI.ESP32_SPI_Set_Pins(14,12,13,15)
    SPI.CSPinDeActivate(SPI.CS__SPI)   
'   
    tirqPin.Initialize(0,tirqPin.MODE_INPUT)

    Timer1.Initialize("TickSub_1",100)
    Timer1.Enabled = True

End Sub

Sub TickSub_1
    If tirqPin.digitalread = True Then
        ReadTouch_XYZData
            If Z_Val > Z_THRESHOLD_INT Then
                Log("XRaw value: ",xraw)
                    Log("YRaw value: ",yraw)
                Log("X value: ",X_Val)
                Log("Y value: ",Y_Val)
                Log("Z value: ",Z_Val)
                Log("Done XYZ Data")
            End If
    End If   
End Sub
    
Sub ReadTouch_XYZData  ' read 12 Bit data from SPI bus after sending a command byte For X,Y,Z1&Z2 measurements
    
  Dim MSB, LSB As Byte = 0 ' was Uin_8t
 '  output_low(PIN_B8);
 '  delay_us(2);     
 '  /////////////////////Gather Z pressure readings////////////////////////////////////
   SPI.Begin_Transaction(2000000, SPI.MSBFIRST, SPI.SPI_MODE0) 
   SPI.CSPinActivate(SPI.CS__SPI)
  
   SPI.Transfer_Byte(Z1_COMMAND_BYTE) ' send command byte
   MSB = SPI.Transfer_Byte(0)
   LSB = SPI.Transfer_Byte(0)
'  Z1 = (((MSB & MSB_BIT_MASK) << 8)+ LSB) >> 3;
   Z1 =  Bit.ShiftLeft(Bit.And(MSB,MSB_BIT_MASK),8)
   Z1 = Z1 + LSB
   Z1 = Bit.ShiftRight(Z1,3)
'
   SPI.Transfer_Byte(Z2_COMMAND_BYTE) ' send command byte
   MSB = SPI.Transfer_Byte(0)
   LSB = SPI.Transfer_Byte(0)
'  Z2 = (((MSB & MSB_BIT_MASK) << 8)+ LSB) >> 3;
   Z2 =  Bit.ShiftLeft(Bit.And(MSB,MSB_BIT_MASK),8)
   Z2 = Z2 + LSB
   Z2 =  Bit.ShiftRight(Z2,3)   
'
   Z_Val =  Z1 + 4095
   Z_Val = Z_Val - Z2
'
   If(Z_Val >= Z_THRESHOLD) Then  ' If we have more than the pressure threshold Then read X&Y data
   SPI.Transfer_Byte(X_COMMAND_BYTE) ' send command byte
   MSB = SPI.Transfer_Byte(0)
   LSB = SPI.Transfer_Byte(0)
   xraw = Bit.ShiftLeft(Bit.And(MSB,MSB_BIT_MASK),8)
   xraw = xraw + LSB
   xraw = Bit.ShiftRight(xraw,3)
  
   SPI.Transfer_Byte(Y_COMMAND_BYTE) ' send command byte
   MSB = SPI.Transfer_Byte(0)
   LSB = SPI.Transfer_Byte(0)
   yraw = Bit.ShiftLeft(Bit.And(MSB,MSB_BIT_MASK),8)
   yraw = yraw + LSB
   yraw = Bit.ShiftRight(yraw,3)
   End If

'output_high(PIN_B8); // in Case Z_Val did Not qualify lets bring CS high
     SPI.CSPinDeActivate(SPI.CS__SPI)
    SPI.End_Transaction
     ' We need To know the display rotation To compensate For X,Y locations
      Select Case True  ' We need To know the display rotation To compensate For X,Y locations
 
      Case ScreenRotation = 1
      X_Val = 4095 - yraw
      Y_Val = 4095 - xraw

      Case ScreenRotation = 2
      X_Val = xraw
      Y_Val = yraw

      Case ScreenRotation = 3
      X_Val = yraw
      Y_Val = 4095 - xraw

      Case ScreenRotation = 4
      X_Val = 4095 - xraw
      Y_Val = 4095 - yraw

      End Select
End Sub

Sub ScreenSet     
    Log("Blue")
    ILI.FillScreen(ILI.COLOR_BLUE)
    Delay(500)
    Log("Done")
    ILI.FillScreen(ILI.COLOR_WHITE)
    Delay(500)
    Log("Draw Text")
    Delay(500)
    ILI.GFX.ConfigureText(2, ILI.COLOR_BLACK, True)
       ILI.GFX.SetCursor(2, 2)
       ILI.GFX.DrawText("This is a test")
    Log("Draw Text Done")
    Log("Height: ", ILI.GFX.Height-10)
    Log("Width: ", ILI.GFX.Width)
End Sub

'//For resolution 240x320,the calibration parameter is 663,-13,894,-30
'//For resolution 320x480,the calibration parameter is 852,-14,1284,-30
'
'#define XFAC      663 //852
'#define XOFFSET   (-13) //(-14)
'#define YFAC      894 //1284
'#define YOFFSET   (-30)
''
 
Upvote 0
Top