Skip to main content
Associate II
May 16, 2026
Question

Touch controller on Adafruit 2478 display and ADC reading

  • May 16, 2026
  • 1 reply
  • 143 views

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);
}
 

 

 

1 reply

Technical Moderator
May 18, 2026

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"
clar123Author
Associate II
May 20, 2026

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);
}