cancel
Showing results for 
Search instead for 
Did you mean: 

Touch controller on Adafruit 2478 display and ADC reading

clar123
Associate II

Follow-on from STM32F030K6T6 microcontroller with Adafruit 2478 display and touchscreen.


Hello all, i have a part of code for the touch screen for the 2478 display.

I have found an example made with Arduino and i have adapted It for stm32, i would like to know if my code Is fine or It has some issues to fix and what u would suggest me to do.

 

This part Is only for the touch controller of the display but i got several questions, like how many readings i should make from the ADC? rn i do and average basically.

 

 

#include "main.h"
#include <stdint.h>

/* ================= CONFIGURAZIONE ================= */

#define LCD_W 320
#define LCD_H 240

// PIN TOUCH (MODIFICA!)
#define X1_PORT GPIOA
#define X1_PIN  GPIO_PIN_0
#define X2_PORT GPIOA
#define X2_PIN  GPIO_PIN_1
#define Y1_PORT GPIOA
#define Y1_PIN  GPIO_PIN_2
#define Y2_PORT GPIOA
#define Y2_PIN  GPIO_PIN_3

// CANALI ADC (MODIFICA!)
#define ADC_CH_Y1 ADC_CHANNEL_2
#define ADC_CH_X1 ADC_CHANNEL_0

#define ADC_SAMPLES 8
#define SETTLE_LOOP 3000

/* ================= CALIBRAZIONE ================= */

uint16_t X_MIN = 200,  X_MAX = 3800;
uint16_t Y_MIN = 250,  Y_MAX = 3750;

/* ================= STRUTTURA ================= */

typedef struct {
    uint16_t x_raw;
    uint16_t y_raw;
    uint16_t x;
    uint16_t y;
    uint8_t  pressed;
} touch_point_t;

touch_point_t tp;

/* ================= GPIO ================= */

static void gpio_out(GPIO_TypeDef* port, uint16_t pin)
{
    GPIO_InitTypeDef g = {0};

    g.Pin   = pin;
    g.Mode  = GPIO_MODE_OUTPUT_PP;
    g.Pull  = GPIO_NOPULL;
    g.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(port, &g);
}

static void gpio_in_hiz(GPIO_TypeDef* port, uint16_t pin)
{
    GPIO_InitTypeDef g = {0};

    g.Pin  = pin;
    g.Mode = GPIO_MODE_INPUT;
    g.Pull = GPIO_NOPULL;   // Hi-Z

    HAL_GPIO_Init(port, &g);
}

static void gpio_analog(GPIO_TypeDef* port, uint16_t pin)
{
    GPIO_InitTypeDef g = {0};

    g.Pin  = pin;
    g.Mode = GPIO_MODE_ANALOG;
    g.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(port, &g);
}

/* ================= ADC ================= */

static void adc_sel(ADC_HandleTypeDef* hadc, uint32_t channel)
{
    ADC_ChannelConfTypeDef s = {0};

    s.Channel      = channel;
    s.Rank         = ADC_REGULAR_RANK_1;
    s.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;

    HAL_ADC_ConfigChannel(hadc, &s);
}

static uint16_t adc_once(ADC_HandleTypeDef* hadc)
{
    HAL_ADC_Start(hadc);
    HAL_ADC_PollForConversion(hadc, HAL_MAX_DELAY);

    return (uint16_t)HAL_ADC_GetValue(hadc);
}

static uint16_t adc_avg(ADC_HandleTypeDef* hadc, uint8_t n)
{
    uint32_t sum = 0;

    for (uint8_t i = 0; i < n; i++) {
        sum += adc_once(hadc);
    }

    return (uint16_t)(sum / n);
}

/* ================= UTILS ================= */

static uint16_t clamp_u16(int32_t v, uint16_t lo, uint16_t hi)
{
    if (v < lo) return lo;
    if (v > hi) return hi;
    return (uint16_t)v;
}

static uint16_t map_u16(uint16_t v, uint16_t in_min, uint16_t in_max, uint16_t out_max)
{
    if (in_max <= in_min) return 0;

    int32_t r = (int32_t)(v - in_min) * out_max / (in_max - in_min);

    if (r < 0) r = 0;
    if (r > out_max) r = out_max;

    return (uint16_t)r;
}

/* ================= LETTURA X ================= */

static uint16_t read_x_raw(ADC_HandleTypeDef* hadc)
{
    gpio_analog(Y1_PORT, Y1_PIN);
    adc_sel(hadc, ADC_CH_Y1);

    gpio_in_hiz(Y2_PORT, Y2_PIN);

    gpio_out(X1_PORT, X1_PIN);
    HAL_GPIO_WritePin(X1_PORT, X1_PIN, GPIO_PIN_SET);

    gpio_out(X2_PORT, X2_PIN);
    HAL_GPIO_WritePin(X2_PORT, X2_PIN, GPIO_PIN_RESET);

    for (volatile int i = 0; i < SETTLE_LOOP; i++);

    return adc_avg(hadc, ADC_SAMPLES);
}

/* ================= LETTURA Y ================= */

static uint16_t read_y_raw(ADC_HandleTypeDef* hadc)
{
    gpio_analog(X1_PORT, X1_PIN);
    adc_sel(hadc, ADC_CH_X1);

    gpio_in_hiz(X2_PORT, X2_PIN);

    gpio_out(Y1_PORT, Y1_PIN);
    HAL_GPIO_WritePin(Y1_PORT, Y1_PIN, GPIO_PIN_SET);

    gpio_out(Y2_PORT, Y2_PIN);
    HAL_GPIO_WritePin(Y2_PORT, Y2_PIN, GPIO_PIN_RESET);

    for (volatile int i = 0; i < SETTLE_LOOP; i++);

    return adc_avg(hadc, ADC_SAMPLES);
}

/* ================= FUNZIONE PRINCIPALE ================= */

void touch_read(ADC_HandleTypeDef* hadc)
{
    uint16_t xr = read_x_raw(hadc);
    uint16_t yr = read_y_raw(hadc);

    tp.x_raw = xr;
    tp.y_raw = yr;

    // Detect touch
    if (xr < (X_MIN - 50) || xr > (X_MAX + 50) ||
        yr < (Y_MIN - 50) || yr > (Y_MAX + 50))
    {
        tp.pressed = 0;
        tp.x = 0;
        tp.y = 0;
        return;
    }

    tp.pressed = 1;

    xr = clamp_u16(xr, X_MIN, X_MAX);
    yr = clamp_u16(yr, Y_MIN, Y_MAX);

    tp.x = map_u16(xr, X_MIN, X_MAX, LCD_W - 1);
    tp.y = map_u16(yr, Y_MIN, Y_MAX, LCD_H - 1);
}
 

 

 

4 REPLIES 4
Saket_Om
ST Employee

Hello @clar123 

To improve the conversion accuracy, it is better to perform an automatic calibration using the function HAL_ADCEx_Calibration_Start() before calling HAL_ADC_PollForConversion.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om

Hey like this u mean?:


#include "main.h"
#include <stdint.h>

/* ================= CONFIGURAZIONE ================= */

#define LCD_W 320
#define LCD_H 240


#define X1_PORT GPIOA
#define X1_PIN  GPIO_PIN_0
#define X2_PORT GPIOA
#define X2_PIN  GPIO_PIN_1
#define Y1_PORT GPIOA
#define Y1_PIN  GPIO_PIN_2
#define Y2_PORT GPIOA
#define Y2_PIN  GPIO_PIN_3

#define ADC_CH_Y1 ADC_CHANNEL_2
#define ADC_CH_X1 ADC_CHANNEL_0

#define ADC_SAMPLES 8
#define SETTLE_LOOP 3000


uint16_t X_MIN = 200,  X_MAX = 3800;
uint16_t Y_MIN = 250,  Y_MAX = 3750;

/* ================= STRUTTURA ================= */

typedef struct {
    uint16_t x_raw;
    uint16_t y_raw;
    uint16_t x;
    uint16_t y;
    uint8_t  pressed;
} touch_point_t;

touch_point_t tp;

/* ================= ERROR HANDLER ================= */

void Error_Handler(void)
{
    // Esempio: accende LED errore (modifica pin se diverso)
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);

    while(1)
    {
        // breakpoint qui → debug facile
    }
}

/* ================= ADC INIT ================= */

void touch_adc_init(ADC_HandleTypeDef* hadc)
{
    if (HAL_ADCEx_Calibration_Start(hadc) != HAL_OK)
    {
        Error_Handler();
    }
}

/* ================= GPIO ================= */

static void gpio_out(GPIO_TypeDef* port, uint16_t pin)
{
    GPIO_InitTypeDef g = {0};

    g.Pin   = pin;
    g.Mode  = GPIO_MODE_OUTPUT_PP;
    g.Pull  = GPIO_NOPULL;
    g.Speed = GPIO_SPEED_FREQ_LOW;

    HAL_GPIO_Init(port, &g);
}

static void gpio_in_hiz(GPIO_TypeDef* port, uint16_t pin)
{
    GPIO_InitTypeDef g = {0};

    g.Pin  = pin;
    g.Mode = GPIO_MODE_INPUT;
    g.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(port, &g);
}

static void gpio_analog(GPIO_TypeDef* port, uint16_t pin)
{
    GPIO_InitTypeDef g = {0};

    g.Pin  = pin;
    g.Mode = GPIO_MODE_ANALOG;
    g.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(port, &g);
}

/* ================= ADC ================= */

static void adc_sel(ADC_HandleTypeDef* hadc, uint32_t channel)
{
    ADC_ChannelConfTypeDef s = {0};

    s.Channel      = channel;
    s.Rank         = ADC_REGULAR_RANK_1;
    s.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;

    HAL_ADC_ConfigChannel(hadc, &s);
}

static uint16_t adc_once(ADC_HandleTypeDef* hadc)
{
    HAL_ADC_Start(hadc);
    HAL_ADC_PollForConversion(hadc, HAL_MAX_DELAY);

    return (uint16_t)HAL_ADC_GetValue(hadc);
}

static uint16_t adc_avg(ADC_HandleTypeDef* hadc, uint8_t n)
{
    uint32_t sum = 0;

    for (uint8_t i = 0; i < n; i++) {
        sum += adc_once(hadc);
    }

    return (uint16_t)(sum / n);
}

/* ================= UTILS ================= */

static uint16_t clamp_u16(int32_t v, uint16_t lo, uint16_t hi)
{
    if (v < lo) return lo;
    if (v > hi) return hi;
    return (uint16_t)v;
}

static uint16_t map_u16(uint16_t v, uint16_t in_min, uint16_t in_max, uint16_t out_max)
{
    if (in_max <= in_min) return 0;

    int32_t r = (int32_t)(v - in_min) * out_max / (in_max - in_min);

    if (r < 0) r = 0;
    if (r > out_max) r = out_max;

    return (uint16_t)r;
}

/* ================= LETTURA X ================= */

static uint16_t read_x_raw(ADC_HandleTypeDef* hadc)
{
    gpio_analog(Y1_PORT, Y1_PIN);
    adc_sel(hadc, ADC_CH_Y1);

    gpio_in_hiz(Y2_PORT, Y2_PIN);

    gpio_out(X1_PORT, X1_PIN);
    HAL_GPIO_WritePin(X1_PORT, X1_PIN, GPIO_PIN_SET);

    gpio_out(X2_PORT, X2_PIN);
    HAL_GPIO_WritePin(X2_PORT, X2_PIN, GPIO_PIN_RESET);

    for (volatile int i = 0; i < SETTLE_LOOP; i++);

    return adc_avg(hadc, ADC_SAMPLES);
}

/* ================= LETTURA Y ================= */

static uint16_t read_y_raw(ADC_HandleTypeDef* hadc)
{
    gpio_analog(X1_PORT, X1_PIN);
    adc_sel(hadc, ADC_CH_X1);

    gpio_in_hiz(X2_PORT, X2_PIN);

    gpio_out(Y1_PORT, Y1_PIN);
    HAL_GPIO_WritePin(Y1_PORT, Y1_PIN, GPIO_PIN_SET);

    gpio_out(Y2_PORT, Y2_PIN);
    HAL_GPIO_WritePin(Y2_PORT, Y2_PIN, GPIO_PIN_RESET);

    for (volatile int i = 0; i < SETTLE_LOOP; i++);

    return adc_avg(hadc, ADC_SAMPLES);
}

/* ================= FUNZIONE PRINCIPALE ================= */

void touch_read(ADC_HandleTypeDef* hadc)
{
    uint16_t xr = read_x_raw(hadc);
    uint16_t yr = read_y_raw(hadc);

    tp.x_raw = xr;
    tp.y_raw = yr;

    // Detect touch
    if (xr < (X_MIN - 50) || xr > (X_MAX + 50) ||
        yr < (Y_MIN - 50) || yr > (Y_MAX + 50))
    {
        tp.pressed = 0;
        tp.x = 0;
        tp.y = 0;
        return;
    }

    tp.pressed = 1;

    xr = clamp_u16(xr, X_MIN, X_MAX);
    yr = clamp_u16(yr, Y_MIN, Y_MAX);

    tp.x = map_u16(xr, X_MIN, X_MAX, LCD_W - 1);
    tp.y = map_u16(yr, Y_MIN, Y_MAX, LCD_H - 1);
}

Hello @Saket_Om 

I have modified the code and i added your part, for the rest it looks fine to you?

Thanks a lot.

Hello @clar123 

For the rest it looks fine for me.

To give better visibility on the answered topics, please click on "Accept as Solution" on the reply which solved your issue or answered your question.
Saket_Om