tinygo.org/x/drivers@v0.27.1-0.20240509133757-7dbca2a54349/xpt2046/xpt2046.go (about)

     1  // Package xpt2046 implements a driver for the XPT2046 resistive touch controller as packaged on the TFT_320QVT board
     2  //
     3  // Datasheet: http://grobotronics.com/images/datasheets/xpt2046-datasheet.pdf
     4  package xpt2046
     5  
     6  import (
     7  	"machine"
     8  	"time"
     9  
    10  	"tinygo.org/x/drivers/touch"
    11  )
    12  
    13  type Device struct {
    14  	t_clk  machine.Pin
    15  	t_cs   machine.Pin
    16  	t_din  machine.Pin
    17  	t_dout machine.Pin
    18  	t_irq  machine.Pin
    19  
    20  	precision uint8
    21  }
    22  
    23  type Config struct {
    24  	Precision uint8
    25  }
    26  
    27  func New(t_clk, t_cs, t_din, t_dout, t_irq machine.Pin) Device {
    28  	return Device{
    29  		precision: 10,
    30  		t_clk:     t_clk,
    31  		t_cs:      t_cs,
    32  		t_din:     t_din,
    33  		t_dout:    t_dout,
    34  		t_irq:     t_irq,
    35  	}
    36  }
    37  
    38  func (d *Device) Configure(config *Config) error {
    39  
    40  	if config.Precision == 0 {
    41  		d.precision = 10
    42  	} else {
    43  		d.precision = config.Precision
    44  	}
    45  
    46  	d.t_clk.Configure(machine.PinConfig{Mode: machine.PinOutput})
    47  	d.t_cs.Configure(machine.PinConfig{Mode: machine.PinOutput})
    48  	d.t_din.Configure(machine.PinConfig{Mode: machine.PinOutput})
    49  
    50  	d.t_dout.Configure(machine.PinConfig{Mode: machine.PinInput})
    51  	d.t_irq.Configure(machine.PinConfig{Mode: machine.PinInput})
    52  
    53  	d.t_clk.Low()
    54  	d.t_cs.High()
    55  	d.t_din.Low()
    56  
    57  	d.readRaw() //Set Powerdown mode to enable T_IRQ
    58  
    59  	return nil
    60  }
    61  
    62  func busSleep() {
    63  	time.Sleep(5 * time.Nanosecond)
    64  }
    65  
    66  func pulseHigh(p machine.Pin) {
    67  	p.High()
    68  	busSleep()
    69  	p.Low()
    70  	busSleep()
    71  }
    72  
    73  func (d *Device) writeCommand(data uint8) {
    74  
    75  	for count := uint8(0); count < 8; count++ {
    76  		d.t_din.Set((data & 0x80) != 0)
    77  		data <<= 1
    78  		pulseHigh(d.t_clk)
    79  	}
    80  
    81  }
    82  
    83  func (d *Device) readData() uint16 {
    84  
    85  	data := uint16(0)
    86  
    87  	for count := uint8(0); count < 12; count++ {
    88  		data <<= 1
    89  		pulseHigh(d.t_clk)
    90  		if d.t_dout.Get() {
    91  			data |= 1
    92  		}
    93  	}
    94  	pulseHigh(d.t_clk) //13
    95  	pulseHigh(d.t_clk) //14
    96  	pulseHigh(d.t_clk) //15
    97  	pulseHigh(d.t_clk) //16
    98  
    99  	return data
   100  }
   101  
   102  func (d *Device) ReadTouchPoint() touch.Point {
   103  
   104  	tx := uint32(0)
   105  	ty := uint32(0)
   106  	tz := uint32(0)
   107  	sampleCount := uint8(0)
   108  
   109  	d.t_cs.Low()
   110  
   111  	for ; sampleCount < d.precision && d.Touched(); sampleCount++ {
   112  		rx, ry, rz := d.readRaw()
   113  		tx += uint32(rx)
   114  		ty += uint32(ry)
   115  		tz += uint32(rz)
   116  	}
   117  	d.t_cs.High()
   118  
   119  	if sampleCount > 0 {
   120  		x := int(tx / uint32(sampleCount))
   121  		y := int(ty / uint32(sampleCount))
   122  		z := int(tz / uint32(sampleCount))
   123  		return touch.Point{
   124  			X: x,
   125  			Y: y,
   126  			Z: z,
   127  		}
   128  	} else {
   129  		return touch.Point{
   130  			X: 0,
   131  			Y: 0,
   132  			Z: 0,
   133  		}
   134  	}
   135  }
   136  
   137  func (d *Device) Touched() bool {
   138  	avail := !d.t_irq.Get()
   139  	return avail
   140  }
   141  
   142  func (d *Device) readRaw() (int32, int32, int32) {
   143  
   144  	d.t_cs.Low()
   145  
   146  	//S       = 1    --> Required Control bit
   147  	//A2-A0   = 001  --> Y-Position
   148  	//MODE    = 0    --> 12 bit conversion
   149  	//SER/DFR = 0    --> Differential preferred for X,Y position
   150  	//PD1-PD0 = 00   --> Powerdown and enable PEN_IRQ
   151  	d.writeCommand(0x90)
   152  	ty := d.readData()
   153  
   154  	//S       = 1    --> Required Control bit
   155  	//A2-A0   = 101  --> X-Position
   156  	//MODE    = 0    --> 12 bit conversion
   157  	//SER/DFR = 0    --> Differential preferred for X,Y position
   158  	//PD1-PD0 = 00   --> Powerdown and enable PEN_IRQ
   159  	d.writeCommand(0xD0)
   160  	tx := d.readData()
   161  
   162  	//S       = 1    --> Required Control bit
   163  	//A2-A0   = 011  --> Z1-position (pressure)
   164  	//MODE    = 0    --> 12 bit conversion
   165  	//SER/DFR = 0    --> Differential preferred for pressure
   166  	//PD1-PD0 = 00   --> Powerdown and enable PEN_IRQ
   167  	d.writeCommand(0xB0)
   168  	tz1 := int32(d.readData())
   169  
   170  	//S       = 1    --> Required Control bit
   171  	//A2-A0   = 100  --> Z2-position (pressure)
   172  	//MODE    = 0    --> 12 bit conversion
   173  	//SER/DFR = 0    --> Differential preferred for pressure
   174  	//PD1-PD0 = 00   --> Powerdown and enable PEN_IRQ
   175  	d.writeCommand(0xC0)
   176  	tz2 := int32(d.readData())
   177  
   178  	tz := int32(0)
   179  	if tz1 != 0 {
   180  		//Touch pressure is proportional to the ratio of z2 to z1 and the x position.
   181  		tz = int32(tx) * ((tz2 << 12) / (tz1 << 12))
   182  	}
   183  
   184  	d.t_cs.High()
   185  
   186  	//Scale X&Y to 16 bit for consistency across touch drivers
   187  	return int32(tx) << 4, int32(4096-ty) << 4, tz
   188  }