ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_touch.c
Go to the documentation of this file.
1
19
20#include "ra8_touch.h"
21
22#include <stddef.h>
23#include <stdint.h>
24
25#include "ra8_attributes.h"
26#include "ra8_check.h"
27#include "ra8_err.h"
28#include "ra8_i2c_bus_ops.h"
29#include "ra8_icu.h"
30#include "ra8_log.h"
32
34static const char* s_tag = "TOUCH";
35
46
60
70
71/* ===========================================================================
72 * Helpers -- decoding + I2C transport
73 * ===========================================================================
74 */
75
92RA8_INTERNAL static inline void internal_pack_reg(uint16_t reg, uint8_t* out_buf)
93{
94 out_buf[0] = (uint8_t)(((uint32_t)reg >> k_ra8_touch_byte_shift) & k_ra8_touch_byte_mask);
95 out_buf[1] = (uint8_t)((uint32_t)reg & k_ra8_touch_byte_mask);
96}
97
121RA8_INTERNAL static ra8_err_t internal_gt911_read(uint16_t reg, uint8_t* buf, uint32_t len)
122{
123 uint8_t reg_bytes[k_ra8_touch_gt911_reg_ptr_bytes];
124 internal_pack_reg(reg, reg_bytes);
125 return s_state.bus.transfer(s_state.bus.ctx,
126 s_state.target_7b,
127 reg_bytes,
129 buf,
130 len);
131}
132
151RA8_INTERNAL static ra8_err_t internal_gt911_write_byte(uint16_t reg, uint8_t value)
152{
153 enum : uint8_t {
154 k_payload_len = k_ra8_touch_gt911_reg_ptr_bytes + 1U,
155 };
156 uint8_t payload[k_payload_len];
157 internal_pack_reg(reg, payload);
158 payload[k_ra8_touch_gt911_reg_ptr_bytes] = value;
159 return s_state.bus.write(s_state.bus.ctx,
160 s_state.target_7b,
161 payload,
162 (uint32_t)k_payload_len,
163 /*send_stop=*/true);
164}
165
181RA8_INTERNAL static void internal_decode_one(const uint8_t* raw, ra8_touch_point_t* out)
182{
184 out->x = (uint16_t)((uint32_t)raw[k_ra8_touch_gt911_point_off_x_lsb] |
186 out->y = (uint16_t)((uint32_t)raw[k_ra8_touch_gt911_point_off_y_lsb] |
188 /* Pressure is the low byte of the 16-bit "size" field; the high byte
189 * is rarely populated and is dropped here so the public type stays
190 * one byte. */
192}
193
212RA8_INTERNAL static void internal_decode_block(const uint8_t* raw,
213 uint8_t n_points,
215 uint8_t max_count,
216 uint8_t* got_count)
217{
218 uint8_t emit = n_points;
219 if (emit > max_count) {
220 emit = max_count;
221 }
222 if (emit > k_ra8_touch_gt911_max_points) {
224 }
225 for (uint8_t i = 0U; i < emit; i++) {
226 const size_t off = (size_t)i * (size_t)k_ra8_touch_gt911_point_bytes;
227 internal_decode_one(&raw[off], &out[i]);
228 }
229 *got_count = emit;
230}
231
232/* ===========================================================================
233 * Lifecycle
234 * ===========================================================================
235 */
236
254{
255 if ((cfg->bus.write == nullptr) || (cfg->bus.transfer == nullptr)) {
257 }
261 }
262 return k_ra8_ok;
263}
264
283{
284 if ((uint32_t)irq_pin >= k_ra8_touch_irq_pin_count) {
285 /* Either the sentinel value or any other "no pin" marker. */
286 return k_ra8_ok;
287 }
288 const ra8_icu_irq_cfg_t cfg = {
290 .filter_div = k_ra8_icu_fclksel_pclkb,
291 .filter_en = false,
292 };
293 return ra8_icu_configure_irq_pin(irq_pin, &cfg);
294}
295
310{
311 s_state.bus = cfg->bus;
312 s_state.target_7b = cfg->target_7b;
313 s_state.irq_pin = cfg->irq_pin;
314 s_state.max_points = cfg->max_points;
315 if ((s_state.max_points == 0U) || (s_state.max_points > k_ra8_touch_max_points)) {
316 s_state.max_points = k_ra8_touch_max_points;
317 }
318}
319
344{
345 uint8_t product[k_ra8_touch_gt911_id_bytes] = {};
346 const ra8_err_t pid_err =
347 internal_gt911_read(k_ra8_touch_gt911_reg_product, product, sizeof(product));
348 if (pid_err != k_ra8_ok) {
350 }
351 if ((uint32_t)product[0] != k_ra8_touch_product_id_byte0) {
353 }
354 return k_ra8_ok;
355}
356
386
387[[nodiscard]] ra8_err_t ra8_touch_open(const ra8_touch_cfg_t* cfg)
388{
389 RA8_CHECK_NULL_PTR(cfg, s_tag, "ra8_touch_open: cfg");
390 if (s_state.opened) {
392 }
393 const ra8_err_t cfg_err = internal_validate_cfg(cfg);
394 RA8_RETURN_ON_ERROR(cfg_err, s_tag, "ra8_touch_open: cfg validation");
395
397
398 const ra8_err_t fin_err = internal_open_finalise(cfg);
399 RA8_RETURN_ON_ERROR(fin_err, s_tag, "ra8_touch_open: finalise");
400
401 s_state.cb = nullptr;
402 s_state.ctx = nullptr;
403 s_state.opened = true;
404 ra8_log_info(s_tag, "ra8_touch_open");
405 return k_ra8_ok;
406}
407
408[[nodiscard]] ra8_err_t ra8_touch_close(void)
409{
410 if (!s_state.opened) {
412 }
413 s_state.cb = nullptr;
414 s_state.ctx = nullptr;
415 s_state.opened = false;
416 return k_ra8_ok;
417}
418
419/* ===========================================================================
420 * Event handler attach / dispatch
421 * ===========================================================================
422 */
423
425{
426 if (!s_state.opened) {
428 }
429 s_state.cb = fn;
430 s_state.ctx = ctx;
431 return k_ra8_ok;
432}
433
435{
436 const ra8_touch_event_fn_t fn = s_state.cb;
437 void* const ctx = s_state.ctx;
438 if (fn != nullptr) {
439 fn(ctx);
440 }
441}
442
443/* ===========================================================================
444 * Touch-point read
445 * ===========================================================================
446 */
447
464RA8_INTERNAL static uint8_t internal_clamp_emit(uint8_t status_byte, uint8_t max_count)
465{
466 uint8_t emit = status_byte & k_ra8_touch_gt911_status_count_mask;
467 if (emit > max_count) {
468 emit = max_count;
469 }
470 if (emit > s_state.max_points) {
471 emit = s_state.max_points;
472 }
473 return emit;
474}
475
492
511internal_read_inner(ra8_touch_point_t* out_points, uint8_t max_count, uint8_t* got_count)
512{
513 /* Step 1: read the status byte. */
514 uint8_t status = 0U;
515 const ra8_err_t status_err = internal_gt911_read(k_ra8_touch_gt911_reg_status, &status, 1U);
516 if (status_err != k_ra8_ok) {
517 *got_count = 0U;
518 return k_ra8_err_hw_error;
519 }
520
521 /* Step 2: bit7 must be set, otherwise no frame is ready. */
522 if ((status & k_ra8_touch_gt911_status_ready_mask) == 0U) {
523 *got_count = 0U;
524 return k_ra8_ok;
525 }
526
527 /* Step 3 + 4: clamp, pull the per-point block, decode. */
528 const uint8_t emit = internal_clamp_emit(status, max_count);
529 if (emit > 0U) {
530 uint8_t raw[(size_t)k_ra8_touch_gt911_max_points * (size_t)k_ra8_touch_gt911_point_bytes] = {};
531 const uint32_t bytes = (uint32_t)emit * (uint32_t)k_ra8_touch_gt911_point_bytes;
533 if (blk_err != k_ra8_ok) {
534 *got_count = 0U;
536 return k_ra8_err_hw_error;
537 }
538 internal_decode_block(raw, emit, out_points, max_count, got_count);
539 } else {
540 /* Frame-ready with zero contacts: a full-release frame. Nothing to
541 * decode -- fall through to the ack so the IC latches the next one. */
542 *got_count = 0U;
543 }
544
545 /* Step 5: ack the frame so the IC latches the next one. */
547 return k_ra8_ok;
548}
549
550[[nodiscard]] ra8_err_t
551ra8_touch_read(ra8_touch_point_t* out_points, uint8_t max_count, uint8_t* got_count)
552{
553 RA8_CHECK_NULL_PTR(out_points, s_tag, "ra8_touch_read: out_points");
554 RA8_CHECK_NULL_PTR(got_count, s_tag, "ra8_touch_read: got_count");
555 if (max_count == 0U) {
556 *got_count = 0U;
558 }
559 if (!s_state.opened) {
560 *got_count = 0U;
562 }
563 return internal_read_inner(out_points, max_count, got_count);
564}
565
567{
568 /* GT911 is factory-calibrated. Nothing to do. */
569 return k_ra8_ok;
570}
571
572#ifdef UNIT_TEST
573[[nodiscard]] ra8_err_t ra8_touch_test_decode(const uint8_t* raw,
574 uint8_t n_points,
575 ra8_touch_point_t* out_points,
576 uint8_t max_count,
577 uint8_t* got_count)
578{
579 RA8_CHECK_NULL_PTR(raw, s_tag, "test_decode: raw");
580 RA8_CHECK_NULL_PTR(out_points, s_tag, "test_decode: out_points");
581 RA8_CHECK_NULL_PTR(got_count, s_tag, "test_decode: got_count");
582 if (max_count == 0U) {
583 *got_count = 0U;
585 }
586 internal_decode_block(raw, n_points, out_points, max_count, got_count);
587 return k_ra8_ok;
588}
589#endif /* UNIT_TEST */
static const char * s_tag
Logging / check tag.
Definition ra8_app.c:17
Annotation-attribute framework macros for ra8-firmware.
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
Validation and Error-Checking Macros for ra8-firmware.
#define RA8_RETURN_ON_ERROR(err, tag, message)
Early return on error, propagating the code upward.
Definition ra8_check.h:184
#define RA8_CHECK_NULL_PTR(ptr, tag, message)
Reject nullptr pointer, returning k_ra8_err_null_ptr.
Definition ra8_check.h:243
Error Code Definitions for ra8-firmware.
@ k_ra8_err_hw_init_failed
Hardware peripheral failed to initialise.
Definition ra8_err.h:290
@ k_ra8_err_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_err_invalid_state
Module in wrong state for requested operation.
Definition ra8_err.h:161
@ k_ra8_err_not_initialized
Module not initialized – _init() not yet called successfully.
Definition ra8_err.h:235
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
@ k_ra8_err_hw_error
Generic hardware fault detected (error flag set, fault interrupt).
Definition ra8_err.h:310
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
Injected I2C-bus seam consumed by Ring-3 I2C device drivers.
Interrupt Control Unit driver (IRQ pins, NMI).
ra8_err_t ra8_icu_configure_irq_pin(uint8_t irq_num, const ra8_icu_irq_cfg_t *cfg)
Programme one IRQCRi register.
Definition ra8_icu.c:76
@ k_ra8_icu_fclksel_pclkb
00: sample every PCLKB cycle.
@ k_ra8_icu_irqmd_falling
00: falling edge.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info(tag, message)
RA8 log info.
Definition ra8_log.h:364
static uint32_t s_state
ra8_err_t ra8_touch_close(void)
Tear the driver down and detach any registered handler.
Definition ra8_touch.c:408
static ra8_err_t internal_gt911_read(uint16_t reg, uint8_t *buf, uint32_t len)
Read len bytes from the GT911 starting at reg.
Definition ra8_touch.c:121
static uint8_t internal_clamp_emit(uint8_t status_byte, uint8_t max_count)
Compute the actual number of touch records to drain.
Definition ra8_touch.c:464
ra8_err_t ra8_touch_open(const ra8_touch_cfg_t *cfg)
Bring up the touch IC over the injected I2C bus seam.
Definition ra8_touch.c:387
ra8_touch_internal_t
Implementation-only constants (no magic numbers).
Definition ra8_touch.c:40
@ k_ra8_touch_byte_shift
Bits per byte.
Definition ra8_touch.c:44
@ k_ra8_touch_product_id_byte0
First char of "911".
Definition ra8_touch.c:41
@ k_ra8_touch_irq_pin_count
Total ICU IRQ channels.
Definition ra8_touch.c:42
@ k_ra8_touch_byte_mask
8-bit byte mask.
Definition ra8_touch.c:43
static void internal_pack_reg(uint16_t reg, uint8_t *out_buf)
Pack a 16-bit GT911 register pointer into MSB-first wire order.
Definition ra8_touch.c:92
static void internal_decode_block(const uint8_t *raw, uint8_t n_points, ra8_touch_point_t *out, uint8_t max_count, uint8_t *got_count)
Decode n GT911 point records from a flat raw buffer.
Definition ra8_touch.c:212
static ra8_err_t internal_check_product_id(void)
Read the GT911 product id and verify the first byte is '9'.
Definition ra8_touch.c:343
static ra8_err_t internal_validate_cfg(const ra8_touch_cfg_t *cfg)
Validate a config descriptor.
Definition ra8_touch.c:253
ra8_err_t ra8_touch_read(ra8_touch_point_t *out_points, uint8_t max_count, uint8_t *got_count)
Drain the current touch frame.
Definition ra8_touch.c:551
static void internal_ack_frame(void)
Acknowledge the current frame; ignore I2C errors.
Definition ra8_touch.c:488
static void internal_decode_one(const uint8_t *raw, ra8_touch_point_t *out)
Decode one 8-byte GT911 point record.
Definition ra8_touch.c:181
static ra8_err_t internal_attach_irq_pin(uint8_t irq_pin)
Optional ICU IRQ-pin programming for the GT911 INT line.
Definition ra8_touch.c:282
void ra8_touch_dispatch_irq(void)
Test-callable IRQ dispatch shim.
Definition ra8_touch.c:434
static ra8_err_t internal_read_inner(ra8_touch_point_t *out_points, uint8_t max_count, uint8_t *got_count)
Inner read: assumes args validated and driver opened.
Definition ra8_touch.c:511
ra8_err_t ra8_touch_attach_handler(ra8_touch_event_fn_t fn, void *ctx)
Register a touch event callback.
Definition ra8_touch.c:424
static ra8_err_t internal_open_finalise(const ra8_touch_cfg_t *cfg)
Post-validate bring-up: product-id check, status ack, IRQ pin.
Definition ra8_touch.c:377
static ra8_err_t internal_gt911_write_byte(uint16_t reg, uint8_t value)
Write a single byte value into 16-bit register reg.
Definition ra8_touch.c:151
ra8_err_t ra8_touch_calibrate(void)
Run any backend-specific calibration routine.
Definition ra8_touch.c:566
static void internal_stash_state(const ra8_touch_cfg_t *cfg)
Stash the validated config into the state slot.
Definition ra8_touch.c:309
Multi-touch input driver – GoodIX GT911 backend.
void(* ra8_touch_event_fn_t)(void *ctx)
Touch-event callback signature.
Definition ra8_touch.h:130
@ k_ra8_touch_max_points
Hard cap (matches GT911 capacity).
Definition ra8_touch.h:71
Register layout for the GoodIX GT911 capacitive touch controller.
@ k_ra8_touch_gt911_cmd_clear_status
Acknowledge a touch frame.
@ k_ra8_touch_gt911_point_off_track
track_id field.
@ k_ra8_touch_gt911_point_off_y_lsb
Y low byte.
@ k_ra8_touch_gt911_point_off_size_lsb
Size low byte.
@ k_ra8_touch_gt911_point_off_y_msb
Y high byte.
@ k_ra8_touch_gt911_point_off_x_lsb
X low byte.
@ k_ra8_touch_gt911_point_off_x_msb
X high byte.
@ k_ra8_touch_gt911_max_points
Max simultaneous contacts.
@ k_ra8_touch_gt911_point_bytes
Bytes per per-point record.
@ k_ra8_touch_gt911_id_bytes
Length of PRODUCT_ID payload.
@ k_ra8_touch_gt911_reg_ptr_bytes
16-bit register-pointer width.
@ k_ra8_touch_gt911_status_ready_mask
bit7 buffer-ready.
@ k_ra8_touch_gt911_status_count_mask
bits[3:0] active touch count.
@ k_ra8_touch_gt911_addr_high
Alternate 7-bit target address.
@ k_ra8_touch_gt911_addr_low
Default 7-bit target address.
@ k_ra8_touch_gt911_reg_product
4-byte product id.
@ k_ra8_touch_gt911_reg_status
Status / point-count byte.
@ k_ra8_touch_gt911_reg_point0
First per-point record.
Caller-filled I2C controller-transfer seam (write / read / write-then-read).
ra8_err_t(* transfer)(void *ctx, uint8_t addr, const uint8_t *wr, uint32_t wr_len, uint8_t *rd, uint32_t rd_len)
Combined write-then-RESTART-then-read in one transaction.
ra8_err_t(* write)(void *ctx, uint8_t addr, const uint8_t *data, uint32_t len, bool send_stop)
Controller write of len bytes to 7-bit address addr.
One external-IRQ-pin configuration descriptor.
Definition ra8_icu.h:65
Configuration descriptor for ra8_touch_open.
Definition ra8_touch.h:109
uint8_t max_points
Cap on touches reported (clamped to 5).
Definition ra8_touch.h:114
ra8_i2c_bus_ops_t bus
Injected I2C transfer seam (app-bound).
Definition ra8_touch.h:110
uint8_t target_7b
7-bit GT911 address (0x5D or 0x14).
Definition ra8_touch.h:111
uint8_t irq_pin
IRQ pin 0..31, or k_ra8_touch_irq_pin_unset for polling-only.
Definition ra8_touch.h:112
One decoded touch contact.
Definition ra8_touch.h:93
uint16_t x
Panel X coordinate.
Definition ra8_touch.h:94
uint16_t y
Panel Y coordinate.
Definition ra8_touch.h:95
uint8_t track_id
Persistent contact id (0..15).
Definition ra8_touch.h:96
uint8_t pressure
Approximate pressure / contact-area, 0..255.
Definition ra8_touch.h:97
Driver-private state slot.
Definition ra8_touch.c:51
void * ctx
Callback context.
Definition ra8_touch.c:53
uint8_t irq_pin
IRQ pin or k_ra8_touch_irq_pin_unset.
Definition ra8_touch.c:57
ra8_i2c_bus_ops_t bus
Injected I2C transfer seam.
Definition ra8_touch.c:54
uint8_t target_7b
7-bit GT911 address.
Definition ra8_touch.c:55
ra8_touch_event_fn_t cb
Registered callback or NULL.
Definition ra8_touch.c:52
bool opened
True between open() and close().
Definition ra8_touch.c:58
uint8_t max_points
Cap on touches reported.
Definition ra8_touch.c:56