Using SERCOM within a library

Hi all,

Thought I had this figured out once, but ust can't get it to work again.

What I am trying to do is use SERCOM from within a library to set up a second SPI port on a Zero clone. I am trying to set up this second SPI to handle a touchscreen on a display. I am using the XPT2046_Touchscreen library found here: GitHub - PaulStoffregen/XPT2046_Touchscreen: Touchscreen Arduino Library for XPT2046 Touch Controller Chip

Here's the Zero sketch that I am using:

#include <XPT2046_Touchscreen.h>

#define CS_PIN  7
// MOSI=11, MISO=12, SCK=13

XPT2046_Touchscreen ts(CS_PIN);
//#define TIRQ_PIN  2
//XPT2046_Touchscreen ts(CS_PIN);  // Param 2 - NULL - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, 255);  // Param 2 - 255 - No interrupts
//XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling

void setup() {
  SerialUSB.begin(9600);
  
  ts.begin();
  
  ts.setRotation(1);
  while (!SerialUSB || (millis() <= 5000));

  SerialUSB.println("TouchTest - started.\n");
}

void loop() {
  if (ts.touched()) {
    TS_Point p = ts.getPoint();
    SerialUSB.print("Pressure = ");
    SerialUSB.print(p.z);
    SerialUSB.print(", x = ");
    SerialUSB.print(p.x);
    SerialUSB.print(", y = ");
    SerialUSB.print(p.y);
    delay(20);
    SerialUSB.println();
  }
  delay(100);
}

Here's where I am trying to define the SPI port at in the 2046XPT_touchscreen.cpp file at:

#include "XPT2046_Touchscreen.h"
#include "wiring_private.h" // pinPeripheral() function

#include <SPI.h>

SPIClass tsSPI (&sercom1, 12, 13, 11, SPI_PAD_0_SCK_1, SERCOM_RX_PAD_3);


#define Z_THRESHOLD     400
#define Z_THRESHOLD_INT	75
#define MSEC_THRESHOLD  3
#define SPI_SETTING     SPISettings(2000000, MSBFIRST, SPI_MODE0)

static XPT2046_Touchscreen 	*isrPinptr;
void isrPin(void);

bool XPT2046_Touchscreen::begin()
{
	

	
	
	tsSPI.begin();
	// Assign pins 11, 12, 13 to SERCOM functionality
	pinPeripheral(11, PIO_SERCOM);
	pinPeripheral(12, PIO_SERCOM);
	pinPeripheral(13, PIO_SERCOM);

	pinMode(csPin, OUTPUT);
	digitalWrite(csPin, HIGH);
	if (255 != tirqPin) {
		pinMode( tirqPin, INPUT );
		attachInterrupt(digitalPinToInterrupt(tirqPin), isrPin, FALLING);
		isrPinptr = this;
	}
	return true;
}

I am attaching my sketch and the library files as I am using them currently.

Could someone enlighten me as to where I am going wrong?

Thanks,
Randy

2.8_zero_TouchTest.ino (860 Bytes)

XPT2046_Touchscreen.h (2.44 KB)

XPT2046_Touchscreen.cpp (5.05 KB)

Hi Randy,

The code for the additional SPI looks good. I compared it against the Adafruit tutorial code: Creating a new SPI | Using ATSAMD21 SERCOM for more SPI, I2C and Serial ports | Adafruit Learning System. This contains the same example code that you're using.

Swapping out SPI for your own SPI object, plus the additional pinPeripheral() functions in the library, should allow it to work with the new SPI port.

You mention you're using a Zero clone. Are digital pins D11, D12 and D13 using port pins PA16, PA19 and PA17 repectively?

Hi MartinL,

Thanks for your reply. Yes, the zero clone is using the correct digital pins to port pins. In fact, I have just solved my problem, and feel a bit stupid....

It was a simple typo, or a find & replace gone bad....

From XPT2046_Touchscreen.cpp -

void XPT2046_Touchscreen_Zero::update()
{
	int16_t data[6];

	if (!isrWake) return;
	uint32_t now = millis();
	if (now - msraw < MSEC_THRESHOLD) return;
	
	tsSPI.beginTransaction(SPI_SETTING);
	digitalWrite(csPin, LOW);
	tsSPI.transfer(0xB1 /* Z1 */);
	int16_t z1 = SPI.transfer16(0xC1 /* Z2 */) >> 3;
	int z = z1 + 4095;
	int16_t z2 = SPI.transfer16(0x91 /* X */) >> 3;
	z -= z2;
	if (z >= Z_THRESHOLD) {
		tsSPI.transfer16(0x91 /* X */);  // dummy X measure, 1st is always noisy
		data[0] = tsSPI.transfer16(0xD1 /* Y */) >> 3;
		data[1] = tsSPI.transfer16(0x91 /* X */) >> 3; // make 3 x-y measurements
		data[2] = tsSPI.transfer16(0xD1 /* Y */) >> 3;
		data[3] = tsSPI.transfer16(0x91 /* X */) >> 3;
	}
	else data[0] = data[1] = data[2] = data[3] = 0;	// Compiler warns these values may be used unset on early exit.
	data[4] = tsSPI.transfer16(0xD0 /* Y */) >> 3;	// Last Y touch power down
	data[5] = tsSPI.transfer16(0) >> 3;
	digitalWrite(csPin, HIGH);
	tsSPI.endTransaction();
	//Serial.printf("z=%d  ::  z1=%d,  z2=%d  ", z, z1, z2);
	if (z < 0) z = 0;
	if (z < Z_THRESHOLD) { //	if ( !touched ) {
		// Serial.println();
		zraw = 0;
		if (z < Z_THRESHOLD_INT) { //	if ( !touched ) {
			if (255 != tirqPin) isrWake = false;
		}
		return;
	}

After - tsSPI.transfer(0xB1 /* Z1 */);
the next two SPI calls used 'SPI', not my new 'tsSPI', so the data was going to the wrong SPI port.

I don't know how I missed that, and now feel stoopid....

Thank you very mush for your time!

Randy