ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
board_periph_i2c.c
Go to the documentation of this file.
1
35
36#include <stdint.h>
37#include <stdio.h>
38
39#include "board_console.h"
40#include "board_periph.h"
41#include "board_periph_block.h"
44
56typedef enum : uint64_t {
57 k_i3c_base = 0x4035F000UL,
58 k_i3c_span = 0x214UL,
59 k_i3c_off_msdvad = 0x018UL,
60 k_i3c_off_cndctl = 0x140UL,
62 k_i3c_off_bst = 0x1D0UL,
63 k_i3c_off_ntst = 0x1E0UL,
64 k_i3c_off_bcst = 0x210UL,
65 k_i3c_reg_words = 0x214UL / 4UL,
66} i3c_map_t;
67
69typedef enum : uint32_t {
70 k_i3c_cndctl_stcnd = 0x00000001U,
71 k_i3c_cndctl_srcnd = 0x00000002U,
72 k_i3c_cndctl_spcnd = 0x00000004U,
74
76typedef enum : uint32_t {
77 k_i3c_bst_stcnddf = 0x00000001U,
78 k_i3c_bst_spcnddf = 0x00000002U,
79 k_i3c_bst_nackdf = 0x00000010U,
80 k_i3c_bst_tendf = 0x00000100U,
81 k_i3c_bst_alf = 0x00010000U,
82 k_i3c_bst_todf = 0x00100000U,
84
86typedef enum : uint32_t {
87 k_i3c_ntst_tdbef0 = 0x00000001U,
88 k_i3c_ntst_rdbff0 = 0x00000002U,
90
92typedef enum : uint32_t {
93 k_i3c_bcst_bfref = 0x00000001U,
95
97typedef enum : uint32_t {
104} i3c_addr_t;
105
124
126typedef enum : uint32_t {
130
143typedef enum : uint16_t {
149
165
175
188typedef struct {
190 bool busy;
192 bool acked;
193 bool reading;
194 uint8_t target_7b;
195 uint32_t ntst;
196 uint32_t bst;
198 uint32_t rx_len;
199 uint32_t rx_pos;
201 /* Target (peripheral) mode: the model is the EXTERNAL controller. */
204 uint8_t periph_phase;
206 uint32_t periph_xfers;
209
227typedef struct {
228 uint16_t reg_ptr;
229 uint8_t ptr_bytes;
231 uint16_t click_x;
232 uint16_t click_y;
233 uint32_t reported;
236 uint8_t seq_len;
237 uint8_t seq_pos;
239
240/* =============================================================================
241 * I2C bus device registry -- map a 7-bit address to a device model.
242 * =============================================================================
243 */
244
255typedef struct {
256 bool present;
257 uint8_t addr_7b;
258 void (*write)(void* ctx, uint8_t byte);
259 uint32_t (*read)(void* ctx, uint8_t* buf, uint32_t max);
260 void (*stop)(void* ctx);
261 void* ctx;
263
267
270{
271 for (uint32_t i = 0U; i < (uint32_t)k_i3c_dev_max; i++) {
272 if (s_i2c_dev[i].present && (s_i2c_dev[i].addr_7b == addr_7b)) {
273 return &s_i2c_dev[i];
274 }
275 }
276 return nullptr;
277}
278
280void priv_i2c_device_register(uint8_t addr_7b,
281 void (*wr)(void*, uint8_t),
282 uint32_t (*rd)(void*, uint8_t*, uint32_t),
283 void (*stop)(void*),
284 void* ctx)
285{
286 for (uint32_t i = 0U; i < (uint32_t)k_i3c_dev_max; i++) {
287 if (!s_i2c_dev[i].present) {
288 s_i2c_dev[i] = (i2c_device_t){.present = true,
289 .addr_7b = addr_7b,
290 .write = wr,
291 .read = rd,
292 .stop = stop,
293 .ctx = ctx};
294 return;
295 }
296 }
297}
298
299/* =============================================================================
300 * GT911 touch device model -- 16-bit register pointer, product id, touch frame.
301 * =============================================================================
302 */
303
304void board_periph_touch_inject(uint16_t x, uint16_t y)
305{
306 s_gt911.click_x = x;
307 s_gt911.click_y = y;
308 s_gt911.click_pending = true;
309}
310
312{
313 s_gt911.seq_len = 0U;
314 s_gt911.seq_pos = 0U;
315 s_gt911.click_pending = false;
316}
317
318bool board_periph_touch_seq_push(uint16_t x, uint16_t y)
319{
320 if (s_gt911.seq_len >= (uint8_t)k_gt911_seq_max) {
321 return false;
322 }
323 s_gt911.seq_x[s_gt911.seq_len] = x;
324 s_gt911.seq_y[s_gt911.seq_len] = y;
325 s_gt911.seq_len++;
326 return true;
327}
328
339{
340 if (!g->click_pending && (g->seq_pos < g->seq_len)) {
341 g->click_x = g->seq_x[g->seq_pos];
342 g->click_y = g->seq_y[g->seq_pos];
343 g->click_pending = true;
344 g->seq_pos++;
345 }
346}
347
349{
350 return s_gt911.reported;
351}
352
353bool board_periph_touch_last(uint16_t* x, uint16_t* y)
354{
355 if ((x == nullptr) || (y == nullptr) || (s_gt911.reported == 0U)) {
356 return false;
357 }
358 *x = s_gt911.click_x;
359 *y = s_gt911.click_y;
360 return true;
361}
362
373RA8_INTERNAL static void internal_gt911_write(void* ctx, uint8_t byte)
374{
375 gt911_state_t* g = (gt911_state_t*)ctx;
376 if (g->ptr_bytes < (uint8_t)k_gt911_ptr_bytes) {
377 /* 16-bit pointer arrives MSB first: byte 0 is the high byte, byte 1 the low. */
378 g->reg_ptr = (uint16_t)(((uint32_t)g->reg_ptr << 8U) | (uint32_t)byte);
379 g->ptr_bytes++;
380 return;
381 }
382 /* Payload after the pointer: a 0 written to STATUS acks the current frame so
383 * the IC can latch the next one (ra8_touch's priv_ack_frame). */
384 if ((g->reg_ptr == (uint16_t)k_gt911_reg_status) && (byte == 0U)) {
385 g->click_pending = false;
386 }
387 if (g->reg_ptr == (uint16_t)k_gt911_reg_command) {
388 /* Wake / soft-reset commands are accepted (no observable side effect). */
389 }
390}
391
405{
406 /* Auto-arm the next queued raw point (multi-tap sequence path) so a status
407 * read reports buffer-ready while the FIFO is non-empty. A single-shot
408 * --click (seq_len == 0) is unaffected: the arm is a no-op and the directly
409 * injected contact still reports ready on its own. */
411 buf[0] = g->click_pending ? (uint8_t)(k_gt911_status_ready | k_gt911_status_one) : 0U;
412 return 1U;
413}
414
428RA8_INTERNAL static uint32_t
429internal_gt911_read_point0(gt911_state_t* g, uint8_t* buf, uint32_t max)
430{
431 if (max < (uint32_t)k_gt911_point_bytes) {
432 return 0U;
433 }
434 for (uint32_t i = 0U; i < (uint32_t)k_gt911_point_bytes; i++) {
435 buf[i] = 0U;
436 }
437 buf[k_gt911_pt_track] = 0U;
438 buf[k_gt911_pt_x_lsb] = (uint8_t)(g->click_x & (uint16_t)k_i3c_byte_mask);
439 buf[k_gt911_pt_x_msb] = (uint8_t)((uint32_t)g->click_x >> 8U);
440 buf[k_gt911_pt_y_lsb] = (uint8_t)(g->click_y & (uint16_t)k_i3c_byte_mask);
441 buf[k_gt911_pt_y_msb] = (uint8_t)((uint32_t)g->click_y >> 8U);
442 buf[k_gt911_pt_sz_lsb] = (uint8_t)k_gt911_press;
443 /* The coordinate has now been delivered to the firmware -- count it and drop
444 * the contact so the next frame reads "not ready", exactly as the GT911 does
445 * once a tap is drained. */
446 g->click_pending = false;
447 g->reported++;
448 return (uint32_t)k_gt911_point_bytes;
449}
450
464RA8_INTERNAL static uint32_t internal_gt911_read(void* ctx, uint8_t* buf, uint32_t max)
465{
466 gt911_state_t* g = (gt911_state_t*)ctx;
467 if (g->reg_ptr == (uint16_t)k_gt911_reg_product) {
468 const uint8_t id[k_gt911_id_bytes] = {(uint8_t)k_gt911_id0,
469 (uint8_t)k_gt911_id1,
470 (uint8_t)k_gt911_id2,
471 (uint8_t)k_gt911_id3};
472 const uint32_t n = (max < (uint32_t)k_gt911_id_bytes) ? max : (uint32_t)k_gt911_id_bytes;
473 for (uint32_t i = 0U; i < n; i++) {
474 buf[i] = id[i];
475 }
476 return n;
477 }
478 if (g->reg_ptr == (uint16_t)k_gt911_reg_status) {
479 return internal_gt911_read_status(g, buf);
480 }
481 if (g->reg_ptr == (uint16_t)k_gt911_reg_point0) {
482 return internal_gt911_read_point0(g, buf, max);
483 }
484 return 0U;
485}
486
496RA8_INTERNAL static void internal_gt911_stop(void* ctx)
497{
498 gt911_state_t* g = (gt911_state_t*)ctx;
499 g->ptr_bytes = 0U;
500}
501
502/* =============================================================================
503 * LSM6DSO IMU device model -- 8-bit auto-incrementing register file.
504 * =============================================================================
505 */
506
507/* =============================================================================
508 * I3C-in-I2C-mode (IIC_B) controller model -- the transfer state machine the
509 * ra8_i3c_i2c.c polling driver drives (START / addr / write / read / STOP).
510 * =============================================================================
511 */
512
524RA8_INTERNAL static uint32_t internal_i3c_word(uint64_t off)
525{
526 return (uint32_t)(off / 4U);
527}
528
538{
539 s_i3c.busy = true;
540 s_i3c.addr_done = false;
541 s_i3c.acked = false;
542 s_i3c.reading = false;
543 s_i3c.rx_len = 0U;
544 s_i3c.rx_pos = 0U;
545 s_i3c.rx_primed = false;
546 /* TX buffer is empty so the driver can write the address byte; clear stale
547 * NACK/TEND so the new address phase reports its own outcome. */
548 s_i3c.ntst = (uint32_t)k_i3c_ntst_tdbef0;
549 s_i3c.bst &= ~((uint32_t)k_i3c_bst_nackdf | (uint32_t)k_i3c_bst_tendf);
550}
551
553typedef enum : uint32_t {
556
566{
567 if (s_i3c.acked) {
569 if (dev != nullptr) {
570 if (dev->stop != nullptr) {
571 dev->stop(dev->ctx);
572 }
573 }
574 /* Console I2C tab: one line per completed (ACKed) transaction at STOP --
575 * 7-bit address + R/W + read byte count. Bounded to one push per STOP. */
576 char ln[k_i2c_console_line_cap];
577 if (s_i3c.reading) {
578 (void)snprintf(ln,
579 sizeof(ln),
580 "IIC addr=0x%02X R %uB",
581 (unsigned)s_i3c.target_7b,
582 (unsigned)s_i3c.rx_len);
583 } else {
584 (void)snprintf(ln, sizeof(ln), "IIC addr=0x%02X W", (unsigned)s_i3c.target_7b);
585 }
587 }
588 s_i3c.busy = false;
589 s_i3c.addr_done = false;
590 s_i3c.ntst = (uint32_t)k_i3c_ntst_tdbef0;
591}
592
602RA8_INTERNAL static void internal_i3c_address_phase(uint8_t address_byte)
603{
604 s_i3c.target_7b =
605 (uint8_t)((uint32_t)address_byte >> (uint32_t)k_i3c_addr_shift) & (uint8_t)k_i3c_addr_mask7;
606 s_i3c.reading = ((uint32_t)address_byte & (uint32_t)k_i3c_addr_rnw) != 0U;
607 s_i3c.addr_done = true;
608
610 if (dev == nullptr) {
611 /* No device at this address: NACK the address (scan reports ack=0). */
612 s_i3c.acked = false;
613 s_i3c.bst |= (uint32_t)k_i3c_bst_nackdf;
614 return;
615 }
616 s_i3c.acked = true;
617 s_i3c.bst |= (uint32_t)k_i3c_bst_tendf; /* address ACKed -> scan sees TENDF */
618 if (s_i3c.reading) {
619 /* Pre-fetch the device's response for this read so NTDTBP0 reads serve it. */
620 s_i3c.rx_len = dev->read(dev->ctx, s_i3c.rx, (uint32_t)k_i3c_dev_rx_max);
621 s_i3c.rx_pos = 0U;
622 s_i3c.rx_primed = false;
623 s_i3c.ntst |= (uint32_t)k_i3c_ntst_rdbff0; /* RX data ready */
624 } else {
625 s_i3c.ntst |= (uint32_t)k_i3c_ntst_tdbef0; /* ready for the first data byte */
626 }
627}
628
629/* =============================================================================
630 * Target (peripheral) mode -- the model plays the EXTERNAL I2C controller that
631 * drives the firmware's IIC_B target (i3c_i2c_peripheral_demo). The firmware
632 * polls NTST and moves bytes through NTDTBP0; the controller path here is idle
633 * (the firmware issues no CNDCTL START), so these handlers own NTST/NTDTBP0 for
634 * the channel whenever target mode is active. See ::i3c_periph_phase_t.
635 * =============================================================================
636 */
637
647RA8_INTERNAL static void internal_i3c_periph_open(uint32_t msdvad)
648{
649 const uint8_t addr =
650 (uint8_t)(((uint32_t)msdvad >> (uint32_t)k_i3c_addr_shift) & (uint32_t)k_i3c_addr_mask7);
651 s_i3c.periph_addr_7b = addr;
652 s_i3c.periph_mode = (addr != 0U); /* MSDVAD == 0 (close) leaves target mode. */
653 s_i3c.periph_phase = (uint8_t)k_i3c_periph_idle;
654}
655
669{
670 if (s_i3c.periph_phase == (uint8_t)k_i3c_periph_idle) {
671 s_i3c.periph_rx_byte =
672 (uint8_t)(((uint32_t)k_i3c_periph_seed + (s_i3c.periph_xfers * (uint32_t)k_i3c_periph_step)) &
673 (uint32_t)k_i3c_byte_mask);
674 s_i3c.periph_phase = (uint8_t)k_i3c_periph_rx_armed;
675 }
676 if (s_i3c.periph_phase == (uint8_t)k_i3c_periph_rx_armed) {
677 return (uint32_t)k_i3c_ntst_rdbff0; /* controller-written byte is waiting */
678 }
679 return (uint32_t)k_i3c_ntst_tdbef0; /* tx_armed: controller is reading the echo */
680}
681
693{
694 s_i3c.periph_phase = (uint8_t)k_i3c_periph_tx_armed;
695 return (uint32_t)s_i3c.periph_rx_byte;
696}
697
708{
709 if (byte != s_i3c.periph_rx_byte) {
710 s_i3c.periph_echo_bad = true;
711 }
712 s_i3c.periph_xfers++;
713 s_i3c.periph_phase = (uint8_t)k_i3c_periph_idle;
714}
715
725RA8_INTERNAL static void internal_i3c_ntdtbp0_write(uint32_t value)
726{
727 const uint8_t byte = (uint8_t)(value & (uint32_t)k_i3c_byte_mask);
728 if (s_i3c.periph_mode) {
729 /* Target mode: the firmware is the peripheral pushing its echo byte. */
731 return;
732 }
733 if (!s_i3c.addr_done) {
735 return;
736 }
737 if (!s_i3c.acked) {
738 return; /* NACKed address: swallow further writes until STOP */
739 }
741 if ((dev != nullptr) && (dev->write != nullptr)) {
742 dev->write(dev->ctx, byte);
743 }
744 s_i3c.ntst |= (uint32_t)k_i3c_ntst_tdbef0; /* buffer empty again for the next */
745}
746
758{
759 if (s_i3c.periph_mode) {
760 /* Target mode: the firmware is the peripheral draining the written byte. */
762 }
763 if (!s_i3c.rx_primed) {
764 /* FSP's controller RXI handler drops the first RDBFF0 read before real payload. */
765 s_i3c.rx_primed = true;
766 return 0U;
767 }
768 uint8_t b = 0U;
769 if (s_i3c.rx_pos < s_i3c.rx_len) {
770 b = s_i3c.rx[s_i3c.rx_pos];
771 s_i3c.rx_pos++;
772 }
773 s_i3c.ntst |= (uint32_t)k_i3c_ntst_rdbff0; /* keep RX-ready for the next byte */
774 return (uint32_t)b;
775}
776
786RA8_INTERNAL static void internal_i3c_cndctl_write(uint32_t value)
787{
788 if ((value & ((uint32_t)k_i3c_cndctl_stcnd | (uint32_t)k_i3c_cndctl_srcnd)) != 0U) {
790 } else if ((value & (uint32_t)k_i3c_cndctl_spcnd) != 0U) {
792 }
793}
794
806RA8_INTERNAL static uint64_t internal_i3c_reg_read(uint64_t off)
807{
808 if (off == (uint64_t)k_i3c_off_ntst) {
809 if (s_i3c.periph_mode) {
811 }
812 return s_i3c.ntst;
813 }
814 if (off == (uint64_t)k_i3c_off_bst) {
815 return s_i3c.bst;
816 }
817 if (off == (uint64_t)k_i3c_off_bcst) {
818 /* BFREF: 1 when the bus is free. The driver gates new transactions on it. */
819 return s_i3c.busy ? 0U : (uint32_t)k_i3c_bcst_bfref;
820 }
821 if (off == (uint64_t)k_i3c_off_ntdtbp0) {
823 }
824 return s_i3c.reg[internal_i3c_word(off)]; /* reflect every other register */
825}
826
837RA8_INTERNAL static void internal_i3c_reg_write(uint64_t off, uint32_t value)
838{
839 s_i3c.reg[internal_i3c_word(off)] = value; /* shadow keeps "configure then verify" working */
840 if (off == (uint64_t)k_i3c_off_msdvad) {
841 /* Own-address programming = the firmware is coming up as an addressed
842 * target. The controller path never writes MSDVAD, so this cleanly selects
843 * target mode (the external-controller stimulus in i3c_periph_*). */
845 } else if (off == (uint64_t)k_i3c_off_cndctl) {
847 } else if (off == (uint64_t)k_i3c_off_ntdtbp0) {
849 } else if (off == (uint64_t)k_i3c_off_bst) {
850 /* BST condition / fault flags are write-0-to-clear: keep only bits still
851 * written as 1 (the driver clears by reading then masking the bit out). */
852 s_i3c.bst &= value;
853 }
854}
855
869RA8_INTERNAL static uint64_t internal_i3c_read(uc_engine* uc, uint64_t addr, unsigned size)
870{
871 (void)uc;
872 (void)size;
873 return internal_i3c_reg_read(addr - (uint64_t)k_i3c_base);
874}
875
888RA8_INTERNAL static void
889internal_i3c_write(uc_engine* uc, uint64_t addr, unsigned size, uint64_t value)
890{
891 (void)uc;
892 (void)size;
893 internal_i3c_reg_write(addr - (uint64_t)k_i3c_base, (uint32_t)value);
894}
895
905{
906 s_i3c = (i3c_state_t){};
908 priv_board_i2c_imu_fuel_reset(); /* lay the IMU + fuel-gauge register files (CLI-set SOC) */
909 /* Populate the modelled I2C bus: the EK-RA8D2 carrier's GT911 touch
910 * controller answers at its default 7-bit address on I3C/IIC_B channel 0, so
911 * the firmware's real ra8_touch -> ra8_i3c_transfer -> GT911 path returns data
912 * instead of needing a function-level touch stub. The LSM6DSO IMU answers at
913 * 0x6B so imu_lsm6dso_demo's WHO_AM_I probe + sample reads succeed too. */
914 for (uint32_t i = 0U; i < (uint32_t)k_i3c_dev_max; i++) {
915 s_i2c_dev[i] = (i2c_device_t){};
916 }
921 &s_gt911);
922 /* LSM6DSO IMU at 0x6B + MAX17048-class fuel gauge at 0x36 (battery SOC +
923 * charge direction) register themselves from the devices TU. */
925}
926
936{
937 if (s_gt911.reported > 0U) {
938 (void)priv_emu_io_errf(" I3C/I2C GT911 : %u touch frame(s) drained via ra8_touch -> I3C\n",
939 s_gt911.reported);
940 }
941 if (priv_board_i2c_imu_reads() > 0U) {
942 (void)priv_emu_io_errf(" I3C/I2C LSM6DSO: %u register read(s) answered (WHO_AM_I + samples)\n",
944 }
945 if (s_i3c.periph_mode) {
946 /* Target mode: report how many controller write+read round-trips the
947 * firmware's IIC_B peripheral accepted, and whether every byte it echoed
948 * back matched the byte the synthetic controller wrote. */
949 const bool echo_ok = (s_i3c.periph_xfers > 0U) && !s_i3c.periph_echo_bad;
950 (void)priv_emu_io_errf(
951 " I3C/I2C target: addr=0x%02X %u peripheral write+read xfer(s) accepted,"
952 " echo=%s\n",
953 (unsigned)s_i3c.periph_addr_7b,
954 (unsigned)s_i3c.periph_xfers,
955 echo_ok ? "Y" : "N");
956 }
957}
958
961 .base = (uint64_t)k_i3c_base,
962 .span = (uint64_t)k_i3c_span,
963 .order = (uint32_t)k_block_order_i2c,
964 .read = internal_i3c_read,
966 .tick = nullptr,
967 .reset = internal_i3c_reset,
968 .report = internal_i3c_report,
969 .name = "I3C/I2C+GT911",
970};
971
973[[gnu::constructor]] RA8_INTERNAL static void internal_board_periph_i2c_register(void)
974{
976}
Multi-channel console log store backing the board view's tabbed console.
void board_console_push(board_console_ch_t ch, const char *line)
Append one completed line to a channel ring and the ALL ring.
@ k_board_console_ch_i2c
I2C (IIC_B + RIIC) transfer summaries.
Register-accurate peripheral-model framework for the board emulator.
Decentralized peripheral-block registry for the board emulator core.
void board_periph_register_block(const board_periph_block_t *block)
Register a peripheral block's descriptor with the core registry.
@ k_block_order_i2c
I3C/I2C + GT911 (no tick today).
static void internal_gt911_write(void *ctx, uint8_t byte)
Controller -> GT911: pointer bytes first (MSB,LSB), then payload.
static void internal_i3c_address_phase(uint8_t address_byte)
Consume the address byte after a (re)START: select + ACK a device.
gt911_reg_t
GoodIX GT911 protocol constants (ra8_touch_gt911_regs.h + ra8_touch.c).
@ k_gt911_reg_command
Command register (sleep/wake/ack).
@ k_gt911_reg_status
Status: bit7 ready, bits[3:0] count.
@ k_gt911_reg_point0
First 8-byte per-point record.
@ k_gt911_reg_product
4-byte ASCII product id "911\0".
static void internal_gt911_stop(void *ctx)
STOP / transfer end: reset the GT911 pointer-capture state.
static void internal_i3c_write(uc_engine *uc, uint64_t addr, unsigned size, uint64_t value)
MMIO write inside the I3C/IIC_B window.
bool board_periph_touch_last(uint16_t *x, uint16_t *y)
Report the coordinates of the most recently drained touch contact.
static uint32_t internal_gt911_read_status(gt911_state_t *g, uint8_t *buf)
Fill buf with the GT911 status byte for the current frame.
i3c_addr_t
I2C address-byte layout on the wire (addr<<1 | R/W).
@ k_i3c_dev_rx_max
Per-read device response staging cap.
@ k_i3c_addr_shift
7-bit address occupies bits [7:1].
@ k_i3c_dev_max
Device-registry capacity on the bus.
@ k_i3c_addr_mask7
7-bit target-address mask.
@ k_i3c_addr_rnw
LSB: 1 == read, 0 == write.
@ k_i3c_byte_mask
One data byte.
i3c_periph_phase_t
Target (peripheral) mode transaction phase.
@ k_i3c_periph_idle
No target transaction armed.
@ k_i3c_periph_tx_armed
Controller is reading: TDBEF0 raised.
@ k_i3c_periph_rx_armed
Controller wrote a byte: RDBFF0 raised.
static void internal_i3c_reset(void)
Clear the I3C channel + GT911 state and (re)populate the bus.
i3c_map_t
I3C-in-I2C-mode (IIC_B) block geometry (ra8_i3c_i2c_regs.h).
@ k_i3c_off_ntdtbp0
NTDTBP0 transfer data buffer port.
@ k_i3c_span
Through BCST at +0x210.
@ k_i3c_off_ntst
NTST normal-transfer status.
@ k_i3c_off_cndctl
CNDCTL START/RESTART/STOP request.
@ k_i3c_off_msdvad
MSDVAD own/target device address.
@ k_i3c_off_bcst
BCST bus condition status (BFREF).
@ k_i3c_base
I3C0 base (== IIC_B channel 0).
@ k_i3c_off_bst
BST bus status (W0C flags).
@ k_i3c_reg_words
Shadow word count for the window.
gt911_const_t
GT911 magic byte values + record geometry.
@ k_gt911_status_one
One active contact in bits[3:0].
@ k_gt911_ptr_bytes
16-bit register-pointer width.
@ k_gt911_id1
'1'.
@ k_gt911_point_bytes
Bytes per per-point record.
@ k_gt911_addr_7b
EK-RA8D2 carrier GT911 default address.
@ k_gt911_id2
'1'.
@ k_gt911_status_ready
Buffer-ready (bit 7).
@ k_gt911_id_bytes
PRODUCT_ID payload length.
@ k_gt911_id3
NUL terminator.
@ k_gt911_id0
'9' – first product-id byte ra8_touch checks.
@ k_gt911_seq_max
Injected raw-point sequence FIFO depth.
@ k_gt911_press
Synthetic contact pressure (size lsb).
static void internal_i3c_report(void)
Print the GT911 touch line when the firmware drained any contact.
bool board_periph_touch_seq_push(uint16_t x, uint16_t y)
Queue one raw touch point onto the modelled GT911 injection FIFO.
static const board_periph_block_t s_k_i3c_block
This block's descriptor (static lifetime; the core keeps the pointer).
i3c_bst_bit_t
BST (Bus Status) flags the polling driver observes / clears (W0C).
@ k_i3c_bst_spcnddf
STOP-condition detected (bit 1).
@ k_i3c_bst_todf
Timeout detected (bit 20).
@ k_i3c_bst_alf
Arbitration lost (bit 16).
@ k_i3c_bst_tendf
Transfer-end / address ACK (bit 8).
@ k_i3c_bst_nackdf
NACK detected (bit 4).
@ k_i3c_bst_stcnddf
START-condition detected (bit 0).
static void internal_i3c_cndctl_write(uint32_t value)
Dispatch a CNDCTL write -> START / repeated-START / STOP.
static void internal_i3c_close_transfer(void)
Close a transaction (STOP): release the bus and notify the device.
i3c_ntst_bit_t
NTST (Normal Transfer Status) flags.
@ k_i3c_ntst_rdbff0
RX data-buffer full (bit 1).
@ k_i3c_ntst_tdbef0
TX data-buffer empty (bit 0).
static void internal_i3c_periph_tx_write(uint8_t byte)
Target-mode NTDTBP0 write: capture + verify the firmware echo, end xfer.
static gt911_state_t s_gt911
i3c_cndctl_bit_t
CNDCTL condition-request bits (ra8_i3c_i2c_regs.h).
@ k_i3c_cndctl_stcnd
STCND issue START.
@ k_i3c_cndctl_srcnd
SRCND issue repeated-START.
@ k_i3c_cndctl_spcnd
SPCND issue STOP.
static void internal_i3c_reg_write(uint64_t off, uint32_t value)
Write a register on the modelled I3C/IIC_B channel.
static void internal_gt911_arm_next_from_seq(gt911_state_t *g)
Arm the head of the injected sequence FIFO when nothing is pending.
static uint32_t internal_i3c_ntdtbp0_read(void)
Serve one NTDTBP0 read from the staged device response.
gt911_pt_off_t
Byte offsets inside one 8-byte GT911 point record (ra8_touch.c).
@ k_gt911_pt_track
track_id.
@ k_gt911_pt_x_lsb
X low byte.
@ k_gt911_pt_sz_lsb
size low (pressure).
@ k_gt911_pt_x_msb
X high byte.
@ k_gt911_pt_y_lsb
Y low byte.
@ k_gt911_pt_y_msb
Y high byte.
static void internal_i3c_open_transfer(void)
Begin a transaction (START or repeated-START): arm the address phase.
static void internal_i3c_periph_open(uint32_t msdvad)
Enter / leave target mode when the firmware (re)programmes MSDVAD.
static uint32_t internal_gt911_read(void *ctx, uint8_t *buf, uint32_t max)
GT911 -> controller: answer a read at the current register pointer.
void board_periph_touch_seq_reset(void)
Clear the modelled GT911 injected-touch sequence FIFO.
void priv_i2c_device_register(uint8_t addr_7b, void(*wr)(void *, uint8_t), uint32_t(*rd)(void *, uint8_t *, uint32_t), void(*stop)(void *), void *ctx)
Register a device model in the first free bus slot (drop if full).
i2c_console_t
Console-tap line buffer capacity for an I2C transaction summary.
@ k_i2c_console_line_cap
Max chars in an "I2C addr=.. .." line.
static i3c_state_t s_i3c
static void internal_i3c_ntdtbp0_write(uint32_t value)
Handle a write to NTDTBP0 (address byte, then controller TX payload).
i3c_bcst_bit_t
BCST (Bus Condition Status) flags.
@ k_i3c_bcst_bfref
Bus-free flag (bit 0): 1 == idle.
static uint32_t internal_gt911_read_point0(gt911_state_t *g, uint8_t *buf, uint32_t max)
Fill buf with one GT911 point0 record for the armed contact.
uint32_t board_periph_touch_reported(void)
Count of touch contacts the firmware has drained from the GT911 model.
i3c_periph_stim_t
Synthetic controller-write byte stream for the target-mode model.
@ k_i3c_periph_step
Per-transaction increment of that byte.
@ k_i3c_periph_seed
First byte the external controller writes.
static i2c_device_t * internal_i2c_device_find(uint8_t addr_7b)
Find the registered device answering addr_7b, or NULL.
static uint64_t internal_i3c_reg_read(uint64_t off)
Read a register from the modelled I3C/IIC_B channel.
static i2c_device_t s_i2c_dev[k_i3c_dev_max]
static void internal_board_periph_i2c_register(void)
Self-register the I3C/I2C block before main runs (decentralized).
static uint64_t internal_i3c_read(uc_engine *uc, uint64_t addr, unsigned size)
MMIO read inside the I3C/IIC_B window.
void board_periph_touch_inject(uint16_t x, uint16_t y)
Arm a pending touch contact for the modelled GT911 device.
static uint32_t internal_i3c_word(uint64_t off)
Index of the I3C shadow word for off (already range-checked).
static uint32_t internal_i3c_periph_rx_read(void)
Target-mode NTDTBP0 read: hand the firmware the written byte, go to TX.
static uint32_t internal_i3c_periph_ntst(void)
Target-mode NTST: arm a fresh controller write when idle, else reflect.
Module-private interfaces shared by the board_periph_i2c TUs.
void priv_board_i2c_imu_fuel_reset(void)
Re-lay the IMU + fuel-gauge register files (block reset path).
uint32_t priv_board_i2c_imu_reads(void)
IMU register reads answered this run (report telemetry).
void priv_board_i2c_imu_fuel_register(void)
Register the LSM6DSO + MAX17048 devices on the modelled bus.
Bounded raw-descriptor I/O seam for the RA8 emulator.
emu_io_result_t priv_emu_io_errf(const char *format,...)
Format bounded text and write it to the injected error descriptor.
-proof
#define RA8_INTERNAL
Marker that a function is intended to be static (file-local).
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
A modelled peripheral block's self-description for the core registry.
One GoodIX GT911 touch device on the modelled I2C bus.
uint32_t reported
Contacts the firmware has drained.
uint16_t click_x
Armed contact X.
uint8_t seq_pos
Next queued point to arm.
uint16_t click_y
Armed contact Y.
uint16_t seq_y[k_gt911_seq_max]
Queued raw-point Y sequence.
bool click_pending
A contact is armed and unread.
uint8_t seq_len
Points queued in the FIFO.
uint16_t reg_ptr
Active 16-bit register pointer.
uint8_t ptr_bytes
Pointer bytes captured this write (0..2).
uint16_t seq_x[k_gt911_seq_max]
Queued raw-point X sequence.
A device on the modelled I2C bus: 7-bit address + read/write callbacks.
void(* stop)(void *ctx)
STOP/transfer end.
uint32_t(* read)(void *ctx, uint8_t *buf, uint32_t max)
Device->controller.
uint8_t addr_7b
7-bit address.
bool present
Slot occupied.
void(* write)(void *ctx, uint8_t byte)
Controller->device.
void * ctx
Device state.
One I3C-in-I2C-mode channel: register shadow + a transfer state machine.
uint8_t periph_rx_byte
Synthetic controller-write byte for this xfer.
bool busy
True between START and STOP.
uint8_t periph_addr_7b
Own 7-bit address the firmware claimed in MSDVAD.
bool periph_echo_bad
A firmware echo did not match the written byte.
uint32_t periph_xfers
Completed controller write+read target xfers.
uint32_t rx_len
Valid bytes in rx.
uint32_t reg[k_i3c_reg_words]
Reflect-on-read register shadow.
bool acked
The addressed target ACKed.
uint32_t ntst
NTST flags (TDBEF0 / RDBFF0).
bool rx_primed
The FSP dummy first read was consumed.
uint8_t periph_phase
i3c_periph_phase_t – target-xfer position.
bool addr_done
Address phase of the current (re)START done.
uint8_t target_7b
7-bit address selected this transfer.
bool periph_mode
IIC_B opened as an addressed target (MSDVAD set).
uint32_t bst
BST flags (NACKDF / TENDF / ...).
uint32_t rx_pos
Next byte index served from rx.
uint8_t rx[k_i3c_dev_rx_max]
Staged device response for a read.
bool reading
Current transfer direction is read.