STMPE610 Driver Problem with nRF52840

Description

Dear all,
I have an Adafruit’s 2.4" FeatherWing touchscreen (320x240) with ILI9341 and STMPE610. I have successfully created the HAL for the ILI9341 tft controller and it seems to work fine with the LVGL library. Now I want to activate the touch capabilities of the aforementioned display. To this end, I have created the required drivers based on the provided esp32 drivers with necessary modifications.
However, the touch controller does not seem to operate correctly. It seems that the stmpe610_read() function stucks at the buffer_empty() loop indefinitely. The STMPE_FIFO_STA returns 0x10 constantly, instead of 0x20. According to the STMPE610 datasheet the 0x10 reading means that the FIFO remains above the preset threshold indefinitely, even though that the data from the controller are read.

Thank you in advance for your help,
Aris.

What MCU/Processor/Board and compiler are you using?

Nordic’s nRF52840

What do you want to achieve?

Port STMPE610 Touchscreen with nRF52840

What have you tried so far?

I have modified the available esp32 drivers to be used with the nRF52840 MCU, but the STMPE610 stucks in the buffer_empty() loop, located in stmpe610_read() routine.

Code to reproduce

STMPE Initialization Routine

void stmpe610_init(void)
{
    uint8_t u8;
    uint16_t u16;

    // Attempt a software reset
    write_8bit_reg(STMPE_SYS_CTRL1, STMPE_SYS_CTRL1_RESET);
    nrf_delay_ms(10U);

    // Reset the SPI configuration, making sure auto-increment is set
    u8 = read_8bit_reg(STMPE_SPI_CFG);
    write_8bit_reg(STMPE_SPI_CFG, u8 | STMPE_SPI_CFG_AA);
    u8 = read_8bit_reg(STMPE_SPI_CFG);

    // Verify SPI communication
    u16 = read_16bit_reg(STMPE_CHIP_ID);
    if (u16 != 0x811) {
            NRF_LOG_ERROR("Invalid CHIP ID");
    }

    write_8bit_reg(STMPE_SYS_CTRL2, 0x00); // Disable clocks
    write_8bit_reg(STMPE_TSC_CTRL, 0);     // Disable to allow writing

    write_8bit_reg(STMPE_TSC_CTRL,
                               STEMP_TSC_CTRL_TRACK_0 | 
               STMPE_TSC_CTRL_XYZ |
               STMPE_TSC_CTRL_EN);

    write_8bit_reg(STMPE_TSC_CFG, STMPE_TSC_CFG_4SAMPLE |
                               STMPE_TSC_CFG_DELAY_1MS |
               STMPE_TSC_CFG_SETTLE_5MS);
           
    write_8bit_reg(STMPE_TSC_FRACTION_Z, 0x7);
    write_8bit_reg(STMPE_TSC_I_DRIVE, STMPE_TSC_I_DRIVE_50MA);

    write_8bit_reg(STMPE_SYS_CTRL2, 0x04); // GPIO clock off, TSC clock on, ADC clock on

    write_8bit_reg(STMPE_ADC_CTRL1, STMPE_ADC_CTRL1_12BIT | 
    STMPE_ADC_CTRL1_80CLK);
    write_8bit_reg(STMPE_ADC_CTRL2, STMPE_ADC_CTRL2_3_25MHZ);

    write_8bit_reg(STMPE_GPIO_ALT_FUNCT, 0x00);  // Disable GPIO

    write_8bit_reg(STMPE_FIFO_TH, 1);                      // Set FIFO threshold
    write_8bit_reg(STMPE_FIFO_STA, STMPE_FIFO_STA_RESET);  // Assert FIFO reset
    write_8bit_reg(STMPE_FIFO_STA, 0);                     // Deassert FIFO reset

    write_8bit_reg(STMPE_INT_EN, 0x00);  // No interrupts
    write_8bit_reg(STMPE_INT_STA, 0xFF); // reset all ints
}

STMPE610 Read routine

bool stmpe610_read(lv_indev_drv_t * drv, lv_indev_data_t * data)
{
    static int16_t last_x = 0;
    static int16_t last_y = 0;
    bool valid = true;
	int c = 0;
    int16_t x = 0;
    int16_t y = 0;
    uint8_t z;

    if ((read_8bit_reg(STMPE_TSC_CTRL) & STMPE_TSC_TOUCHED) == STMPE_TSC_TOUCHED) {
		// Making sure that we read all data and return the latest point
		while (!buffer_empty()) {       // <------ The execution stucks here !
			read_data(&x, &y, &z);
			c++;
		}
		
		if (c > 0) {
			//ESP_LOGI(TAG, "%d: %d %d %d", c, x, y, z);
		
			adjust_data(&x, &y);
    		last_x = x;
    		last_y = y;
    		//ESP_LOGI(TAG, "  ==> %d %d", x, y);
    	}
    	
    	z = read_8bit_reg(STMPE_INT_STA);  // Clear interrupts
    	z = read_8bit_reg(STMPE_FIFO_STA);
    	if ((z & STMPE_FIFO_STA_OFLOW) == STMPE_FIFO_STA_OFLOW) {
    		// Clear the FIFO if we discover an overflow
    		write_8bit_reg(STMPE_FIFO_STA, STMPE_FIFO_STA_RESET);
			write_8bit_reg(STMPE_FIFO_STA, 0); // unreset
			NRF_LOG_INFO("Fifo overflow");
		}
    }
    
    if (c == 0) {
        x = last_x;
        y = last_y;
        valid = false;
    }

    data->point.x = (int16_t) x;
    data->point.y = (int16_t) y;
    data->state = valid == false ? LV_INDEV_STATE_REL : LV_INDEV_STATE_PR;

    return false;
}

SPI Write & Read routines

static void write_8bit_reg(uint8_t reg, uint8_t val)
{
	volatile uint8_t data_send[2];
	
	data_send[0] = reg;
	data_send[1] = val;

        nrf_gpio_pin_clear(STMPE610_SS_PIN);
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &data_send, 2U, NULL, 0U));
        nrf_gpio_pin_set(STMPE610_SS_PIN);
}


static uint16_t read_16bit_reg(uint8_t reg)
{
	uint8_t data_recv[3] = {0x0U, 0x0U, 0x0U};

        uint8_t data_send[3] = {(0x80U | reg), 0x0U, 0x0U};
	
        nrf_gpio_pin_clear(STMPE610_SS_PIN);
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data_send, 3U, data_recv, 3U));
        nrf_gpio_pin_set(STMPE610_SS_PIN);
	
	return ((uint16_t)data_recv[1] << 8U) | ((uint16_t)data_recv[2] & 0xFFU);
}


static uint8_t read_8bit_reg(uint8_t reg)
{	
	uint8_t data_recv[2] = {0x0U, 0x0U};

        uint8_t data_send[2] = {(0x80U | reg), 0x0U};
	

        nrf_gpio_pin_clear(STMPE610_SS_PIN);
        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, data_send, 2U, data_recv, 2U));
        nrf_gpio_pin_set(STMPE610_SS_PIN);
	
	return data_recv[1];
}