28#ifdef TOUCH_SELFTEST_ENABLE
44#define OUT_ON GPIO_PIN_RESET
46#define OUT_OFF GPIO_PIN_SET
58SPI_HandleTypeDef hspi1;
60UART_HandleTypeDef huart1;
67void SystemClock_Config(
void);
68static void MX_GPIO_Init(
void);
69static void MX_USART1_UART_Init(
void);
70static void MX_SPI1_Init(
void);
74#ifdef TSC2046_DEBUG_POLL
75static void tsc2046RawDebug(
const char *name, uint8_t cmd);
84#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
88 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
117 SystemClock_Config();
125 MX_USART1_UART_Init();
129 printf(
"\x1b[2J\x1b[H");
133 printf(
"TSC2046 touch controller initialized.\r\n");
134#ifdef TOUCH_SELFTEST_ENABLE
137 printf(
"Touch the panel...\r\n");
140 bool wasTouched =
false;
141 uint32_t lastPrintMs = 0;
144 uint8_t candidateCount = 0;
156#ifdef TSC2046_DEBUG_POLL
160 static uint32_t lastDbgMs = 0;
161 if (HAL_GetTick() - lastDbgMs >= 500)
163 lastDbgMs = HAL_GetTick();
164 int16_t dx = 0, dy = 0;
167 printf(
"DBG irq=%d busy=%d raw X=%4d Y=%4d P=%ld\r\n",
168 (
int)HAL_GPIO_ReadPin(TSC2046_IRQ_GPIO_Port, TSC2046_IRQ_Pin),
169 (
int)HAL_GPIO_ReadPin(TSC2046_BUSY_GPIO_Port, TSC2046_BUSY_Pin),
171 tsc2046RawDebug(
"X ", 0xD0);
172 tsc2046RawDebug(
"Y ", 0x90);
173 tsc2046RawDebug(
"Z1", 0xB0);
174 tsc2046RawDebug(
"Z2", 0xC0);
187 static uint32_t lastPollMs = 0;
188 static uint8_t untouchedCount = 0;
189 if (HAL_GetTick() - lastPollMs >= 10)
191 lastPollMs = HAL_GetTick();
192 int16_t x = 0, y = 0;
193 float pressure = 0.0f;
194 bool rawTouched =
false;
199 rawTouched = isfinite(pressure) && pressure >= 40.0f && pressure < 1500.0f
200 && zone != TOUCH_ZONE_NONE;
207 if (zone == candidateZone)
209 if (candidateCount < 255) candidateCount++;
213 candidateZone = zone;
217 if (candidateCount >= 2 && candidateZone != lastZone)
219 lastZone = candidateZone;
224 else if (wasTouched && HAL_GetTick() - lastPrintMs >= 200)
226 lastPrintMs = HAL_GetTick();
227 printf(
"Touch: X=%4d Y=%4d Pressure=%ld ohm\r\n", x, y, (
long)pressure);
232 if (untouchedCount < 255) untouchedCount++;
234 candidateZone = TOUCH_ZONE_NONE;
236 if (wasTouched && untouchedCount >= 3)
239 lastZone = TOUCH_ZONE_NONE;
240 HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin,
OUT_OFF);
241 printf(
"Released\r\n");
253void SystemClock_Config(
void)
255 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
256 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
260 HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY);
264 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0);
266 while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {}
271 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
272 RCC_OscInitStruct.HSIState = RCC_HSI_DIV1;
273 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
274 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
275 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
276 RCC_OscInitStruct.PLL.PLLM = 4;
277 RCC_OscInitStruct.PLL.PLLN = 60;
278 RCC_OscInitStruct.PLL.PLLP = 2;
279 RCC_OscInitStruct.PLL.PLLQ = 5;
280 RCC_OscInitStruct.PLL.PLLR = 2;
281 RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_3;
282 RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE;
283 RCC_OscInitStruct.PLL.PLLFRACN = 0;
284 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
291 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
292 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2
293 |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1;
294 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
295 RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
296 RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2;
297 RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2;
298 RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2;
299 RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2;
300 RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2;
302 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
313static void MX_SPI1_Init(
void)
324 hspi1.Instance = SPI1;
325 hspi1.Init.Mode = SPI_MODE_MASTER;
326 hspi1.Init.Direction = SPI_DIRECTION_2LINES;
327 hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
328 hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
329 hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
330 hspi1.Init.NSS = SPI_NSS_SOFT;
331 hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
332 hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
333 hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
334 hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
335 hspi1.Init.CRCPolynomial = 0x0;
336 hspi1.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
337 hspi1.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
338 hspi1.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
339 hspi1.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
340 hspi1.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
341 hspi1.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
342 hspi1.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
343 hspi1.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
344 hspi1.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
345 hspi1.Init.IOSwap = SPI_IO_SWAP_DISABLE;
346 if (HAL_SPI_Init(&hspi1) != HAL_OK)
361static void MX_USART1_UART_Init(
void)
371 huart1.Instance = USART1;
372 huart1.Init.BaudRate = 19200;
373 huart1.Init.WordLength = UART_WORDLENGTH_8B;
374 huart1.Init.StopBits = UART_STOPBITS_1;
375 huart1.Init.Parity = UART_PARITY_NONE;
376 huart1.Init.Mode = UART_MODE_TX_RX;
377 huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
378 huart1.Init.OverSampling = UART_OVERSAMPLING_16;
379 huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
380 huart1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
381 huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
382 if (HAL_UART_Init(&huart1) != HAL_OK)
386 if (HAL_UARTEx_SetTxFifoThreshold(&huart1, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
390 if (HAL_UARTEx_SetRxFifoThreshold(&huart1, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
394 if (HAL_UARTEx_DisableFifoMode(&huart1) != HAL_OK)
409static void MX_GPIO_Init(
void)
411 GPIO_InitTypeDef GPIO_InitStruct = {0};
417 __HAL_RCC_GPIOC_CLK_ENABLE();
418 __HAL_RCC_GPIOH_CLK_ENABLE();
419 __HAL_RCC_GPIOA_CLK_ENABLE();
420 __HAL_RCC_GPIOF_CLK_ENABLE();
421 __HAL_RCC_GPIOG_CLK_ENABLE();
422 __HAL_RCC_GPIOB_CLK_ENABLE();
423 __HAL_RCC_GPIOE_CLK_ENABLE();
426 HAL_GPIO_WritePin(LED01_GPIO_Port, LED01_Pin, GPIO_PIN_SET);
429 HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, GPIO_PIN_SET);
432 HAL_GPIO_WritePin(LED03_GPIO_Port, LED03_Pin, GPIO_PIN_SET);
435 HAL_GPIO_WritePin(TSC2046_CS_GPIO_Port, TSC2046_CS_Pin, GPIO_PIN_RESET);
438 HAL_GPIO_WritePin(LED02_GPIO_Port, LED02_Pin, GPIO_PIN_SET);
441 GPIO_InitStruct.Pin = LED01_Pin;
442 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
443 GPIO_InitStruct.Pull = GPIO_NOPULL;
444 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
445 HAL_GPIO_Init(LED01_GPIO_Port, &GPIO_InitStruct);
448 GPIO_InitStruct.Pin = Buzzer_Pin|LED03_Pin;
449 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
450 GPIO_InitStruct.Pull = GPIO_NOPULL;
451 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
452 HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);
455 GPIO_InitStruct.Pin = TSC2046_IRQ_Pin;
456 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
457 GPIO_InitStruct.Pull = GPIO_NOPULL;
458 HAL_GPIO_Init(TSC2046_IRQ_GPIO_Port, &GPIO_InitStruct);
461 GPIO_InitStruct.Pin = TSC2046_BUSY_Pin;
462 GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
463 GPIO_InitStruct.Pull = GPIO_NOPULL;
464 HAL_GPIO_Init(TSC2046_BUSY_GPIO_Port, &GPIO_InitStruct);
467 GPIO_InitStruct.Pin = TSC2046_CS_Pin;
468 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
469 GPIO_InitStruct.Pull = GPIO_NOPULL;
470 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
471 HAL_GPIO_Init(TSC2046_CS_GPIO_Port, &GPIO_InitStruct);
474 GPIO_InitStruct.Pin = LED02_Pin;
475 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
476 GPIO_InitStruct.Pull = GPIO_NOPULL;
477 GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
478 HAL_GPIO_Init(LED02_GPIO_Port, &GPIO_InitStruct);
492 HAL_GPIO_WritePin(LED01_GPIO_Port, LED01_Pin,
OUT_OFF);
493 HAL_GPIO_WritePin(LED02_GPIO_Port, LED02_Pin,
OUT_OFF);
494 HAL_GPIO_WritePin(LED03_GPIO_Port, LED03_Pin,
OUT_OFF);
495 HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin,
OUT_OFF);
508 case TOUCH_ZONE_LED1_ON: HAL_GPIO_WritePin(LED01_GPIO_Port, LED01_Pin,
OUT_ON);
break;
509 case TOUCH_ZONE_LED1_OFF: HAL_GPIO_WritePin(LED01_GPIO_Port, LED01_Pin,
OUT_OFF);
break;
510 case TOUCH_ZONE_LED2_ON: HAL_GPIO_WritePin(LED02_GPIO_Port, LED02_Pin,
OUT_ON);
break;
511 case TOUCH_ZONE_LED2_OFF: HAL_GPIO_WritePin(LED02_GPIO_Port, LED02_Pin,
OUT_OFF);
break;
512 case TOUCH_ZONE_LED3_ON: HAL_GPIO_WritePin(LED03_GPIO_Port, LED03_Pin,
OUT_ON);
break;
513 case TOUCH_ZONE_LED3_OFF: HAL_GPIO_WritePin(LED03_GPIO_Port, LED03_Pin,
OUT_OFF);
break;
516 HAL_GPIO_WritePin(Buzzer_GPIO_Port, Buzzer_Pin, (zone == TOUCH_ZONE_BEEP) ?
OUT_ON :
OUT_OFF);
519#ifdef TSC2046_DEBUG_POLL
525static void tsc2046RawDebug(
const char *name, uint8_t cmd)
527 uint8_t tx[3] = { cmd, 0x00, 0x00 };
528 uint8_t rx[3] = { 0xAA, 0xAA, 0xAA };
530 HAL_GPIO_WritePin(TSC2046_CS_GPIO_Port, TSC2046_CS_Pin, GPIO_PIN_RESET);
531 HAL_StatusTypeDef st = HAL_SPI_TransmitReceive(&hspi1, tx, rx, 3, 100);
532 HAL_GPIO_WritePin(TSC2046_CS_GPIO_Port, TSC2046_CS_Pin, GPIO_PIN_SET);
534 unsigned value = (((unsigned)rx[1] << 8 | rx[2]) >> 3) & 0xFFF;
535 printf(
"RAW %s cmd=%02X hal=%d state=%d err=0x%lX rx=%02X %02X %02X -> %4u\r\n",
536 name, cmd, (
int)st, (
int)HAL_SPI_GetState(&hspi1),
537 (
unsigned long)HAL_SPI_GetError(&hspi1), rx[0], rx[1], rx[2], value);
548void _Error_Handler(
const char *file,
int line)
552#ifdef REDIRECT_PRINTF
555 snprintf(buf,
sizeof(buf),
556 "Trapped in _Error_Handler(). Called from: %s, line: %d\r\n",
570#ifdef USE_FULL_ASSERT
578void assert_failed(uint8_t *file, uint32_t line)
589#ifdef REDIRECT_PRINTF
593 snprintf(buf,
sizeof(buf),
594 "assert_param failed: file %s, line %lu\r\n",
595 (
char *)file, (
unsigned long)line);
C-callable entry points bridging CubeMX-generated main.c into the C++ TSC2046 driver.
void initTSC2046(void)
Constructs the TSC2046 driver. Must be called after MX_SPI1_Init() (and therefore after HAL_Init()/Sy...
bool tsc2046GetPoint(int16_t *x, int16_t *y, float *pressure)
Reads the current touch position and pressure.
#define OUT_OFF
Pin level that turns an output OFF (LED dark, buzzer silent).
int main(void)
The application entry point.
static void outputsAllOff(void)
Drives all three LEDs and the buzzer to their OFF level (LEDs dark, buzzer silent).
static void applyZoneAction(touchZone_t zone)
Applies the action for a settled touch zone. LEDs latch: an ON zone turns that LED on and an OFF zone...
#define OUT_ON
Pin level that turns an output ON. LEDs are wired 5V -> resistor -> LED -> GPIO, so low = lit; the bu...
: Header for main.c file. This file contains the common defines of the application.
Startup self-test for the TSC2046 touch controller.
const touchSelfTestReport_t * touchSelfTestRunAll(void)
Runs every self-test in order, stopping at the first failure, and prints progress and a PASS/FAIL ver...
Maps raw TSC2046 X/Y readings to the printed button zones on the panel overlay.
touchZone_t
The button zones on the printed panel, or TOUCH_ZONE_NONE for a point outside them.
const char * touchZoneName(touchZone_t zone)
Gives a short printable name for a zone.
touchZone_t touchZoneFromPoint(int16_t x, int16_t y)
Classifies a raw touch position into a button zone.