ra8-firmware 0.1.0
Bare-metal firmware for the Renesas RA8 family (RA8D2 / RA8P1)
Loading...
Searching...
No Matches
ra8_i2c_config.c
Go to the documentation of this file.
1
27
28#include <stdint.h>
29
30#include "ra8_attributes.h"
31#include "ra8_check.h"
32#include "ra8_err.h"
33#include "ra8_i2c.h"
34#include "ra8_i2c_internal.h"
35#include "ra8_i2c_regs.h"
36#include "ra8_log.h"
37#include "ra8_mstp.h"
38
53
75{
76 if (channel == 0U) {
77 return k_ra8_mstp_iic0;
78 }
79 if (channel == 1U) {
80 return k_ra8_mstp_iic1;
81 }
82 return k_ra8_mstp_iic2;
83}
84
107RA8_INTERNAL static uint8_t internal_i2c_pick_cks(uint32_t* total)
108{
109 uint32_t cks = 0U;
110 for (uint32_t i = 0U; i <= (uint32_t)k_ra8_i2c_cks_max; i++) {
111 const uint32_t half = *total / (uint32_t)k_ra8_i2c_period_split;
112 if (half <= ((uint32_t)k_ra8_i2c_br_field_max + 1U)) {
113 break;
114 }
115 cks = i + 1U;
116 *total = *total >> 1U;
117 }
118 if (cks > (uint32_t)k_ra8_i2c_cks_max) {
119 cks = (uint32_t)k_ra8_i2c_cks_max;
120 }
121 return (uint8_t)cks;
122}
123
143RA8_INTERNAL static uint8_t internal_i2c_clamp_half(uint32_t total)
144{
145 uint32_t half = total / (uint32_t)k_ra8_i2c_period_split;
146 if (half == 0U) {
147 half = 1U;
148 }
149 uint32_t field = half - 1U;
150 if (field > (uint32_t)k_ra8_i2c_br_field_max) {
151 field = (uint32_t)k_ra8_i2c_br_field_max;
152 }
153 return (uint8_t)field;
154}
155
184 uint32_t pclkb_hz,
185 uint8_t* out_cks,
186 uint8_t* out_brh,
187 uint8_t* out_brl)
188{
189 RA8_CHECK_NULL_PTR(out_cks, g_i2c_tag, "bitrate: out_cks");
190 RA8_CHECK_NULL_PTR(out_brh, g_i2c_tag, "bitrate: out_brh");
191 if (priv_ra8_i2c_internal_clk_invalid(bus_hz, pclkb_hz)) {
193 }
194
195 /* Each transferred bit needs (BRH+1)+(BRL+1) IICphi cycles. Pick the
196 * smallest CKS that fits both half-periods in the 5-bit field, then
197 * derive the clamped half-period count for ICBRL / ICBRH. */
198 uint32_t total = pclkb_hz / bus_hz;
199 const uint8_t cks = internal_i2c_pick_cks(&total);
200 const uint8_t field = internal_i2c_clamp_half(total);
201
202 *out_cks = cks;
203 *out_brh = (uint8_t)((uint32_t)k_ra8_i2c_br_reserved_hi | (uint32_t)field);
204 *out_brl = (uint8_t)((uint32_t)k_ra8_i2c_br_reserved_hi | (uint32_t)field);
205 return k_ra8_ok;
206}
207
227RA8_INTERNAL static uint8_t internal_i2c_decode_errors(uint8_t icsr2)
228{
229 uint8_t mask = (uint8_t)k_ra8_i2c_err_none;
230 if ((icsr2 & (uint8_t)k_ra8_i2c_msk_icsr2_al) != 0U) {
231 mask |= (uint8_t)k_ra8_i2c_err_arb_lost;
232 }
233 if ((icsr2 & (uint8_t)k_ra8_i2c_msk_icsr2_nackf) != 0U) {
234 mask |= (uint8_t)k_ra8_i2c_err_nack;
235 }
236 /* TMOF lives in ICSR2 bit 0; reuse the timeout mask via the position. */
237 if ((icsr2 & (uint8_t)(1U << (uint8_t)k_ra8_i2c_icsr2_tmof_pos)) != 0U) {
238 mask |= (uint8_t)k_ra8_i2c_err_timeout;
239 }
240 return mask;
241}
242
243/* =============================================================================
244 * Init / deinit -- mirrors HUM Ch 39.3.2 "Initial Settings" p 2395.
245 * =============================================================================
246 */
247
271 uint8_t cks,
272 uint8_t brh,
273 uint8_t brl,
274 bool fast_plus)
275{
276 /* Initial-settings step 1 (Figure 39.5): ICE = 0, pins inactive.
277 * HUM Ch 39.2.1 "ICCR1 : I2C Bus Control Register 1" p 2369 */
278 reg->ICCR1 = 0U;
279 /* Initial-settings step 2: IICRST = 1 (IIC reset, ICE still 0).
280 * HUM Ch 39.2.1 "ICCR1 : I2C Bus Control Register 1" p 2369 */
281 reg->ICCR1 = (uint8_t)k_ra8_i2c_msk_iccr1_iicrst;
282 /* Initial-settings step 3: ICE = 1 (internal reset, pins active).
283 * HUM Ch 39.2.1 "ICCR1 : I2C Bus Control Register 1" p 2369 */
284 reg->ICCR1 = (uint8_t)((uint8_t)k_ra8_i2c_msk_iccr1_iicrst | (uint8_t)k_ra8_i2c_msk_iccr1_ice);
285
286 /* HUM Ch 39.2.3 "ICMR1 : I2C Bus Mode Register 1 -- CKS[6:4]" p 2374 */
287 reg->ICMR1 = (uint8_t)((uint32_t)cks << (uint32_t)k_ra8_i2c_icmr1_cks_pos);
288 /* HUM Ch 39.2.15 "ICBRL : I2C Bus Bit Rate Low-Level Register" p 2391 */
289 reg->ICBRL = brl;
290 /* HUM Ch 39.2.16 "ICBRH : I2C Bus Bit Rate High-Level Register" p 2392 */
291 reg->ICBRH = brh;
292
293 /* Enable arbitration-lost detection, NACK transfer suspension, the SCL
294 * synchronous circuit, and (for Fm+) the slope-control circuit.
295 * HUM Ch 39.2.6 "ICFER : I2C Bus Function Enable Register" p 2378 */
296 uint8_t icfer = (uint8_t)((uint8_t)k_ra8_i2c_msk_icfer_male | (uint8_t)k_ra8_i2c_msk_icfer_nacke |
297 (uint8_t)k_ra8_i2c_msk_icfer_scle);
298 if (fast_plus) {
299 icfer |= (uint8_t)k_ra8_i2c_msk_icfer_fmpe;
300 }
301 reg->ICFER = icfer;
302
303 /* Initial-settings step 5: release the internal reset (IICRST = 0).
304 * HUM Ch 39.2.1 "ICCR1 : I2C Bus Control Register 1" p 2369 */
305 reg->ICCR1 = (uint8_t)k_ra8_i2c_msk_iccr1_ice;
306}
307
308ra8_err_t ra8_i2c_init(uint8_t channel, const ra8_i2c_cfg_t* cfg)
309{
310 RA8_CHECK_NULL_PTR(cfg, g_i2c_tag, "i2c_init: cfg");
311 uint8_t cks = 0U;
312 uint8_t brh = 0U;
313 uint8_t brl = 0U;
314 const ra8_err_t br_err = internal_i2c_bitrate(cfg->bus_hz, cfg->pclkb_hz, &cks, &brh, &brl);
315 RA8_RETURN_ON_ERROR(br_err, g_i2c_tag, "i2c_init: bitrate");
316
317 volatile r_i2c_regs_t* reg = ra8_i2c_regs(channel);
318 if (reg == nullptr) {
320 }
321
322 const ra8_err_t mst_err = ra8_mstp_enable(internal_i2c_mstp_id(channel));
323 RA8_RETURN_ON_ERROR(mst_err, g_i2c_tag, "i2c_init: mstp");
324
326 cks,
327 brh,
328 brl,
329 cfg->bus_hz >= (uint32_t)k_ra8_i2c_speed_fast_plus);
330
331 s_i2c_state[channel].initialized = true;
332 s_i2c_state[channel].bus_held = false;
333
334 ra8_log_info_val(g_i2c_tag, "i2c_init channel", (uint32_t)channel);
335 return k_ra8_ok;
336}
337
338ra8_err_t ra8_i2c_deinit(uint8_t channel)
339{
340 volatile r_i2c_regs_t* reg = ra8_i2c_regs(channel);
341 if (reg == nullptr) {
343 }
344 /* ICE = 0: place the SCL/SDA pins back in the inactive state.
345 * HUM Ch 39.2.1 "ICCR1 : I2C Bus Control Register 1" p 2369 */
346 reg->ICCR1 = 0U;
347 s_i2c_state[channel].initialized = false;
348 s_i2c_state[channel].bus_held = false;
349 return ra8_mstp_disable(internal_i2c_mstp_id(channel));
350}
351
352ra8_err_t ra8_i2c_set_clock(uint8_t channel, uint32_t bus_hz, uint32_t pclkb_hz)
353{
354 volatile r_i2c_regs_t* reg = ra8_i2c_regs(channel);
355 if (reg == nullptr) {
357 }
358 uint8_t cks = 0U;
359 uint8_t brh = 0U;
360 uint8_t brl = 0U;
361 const ra8_err_t br_err = internal_i2c_bitrate(bus_hz, pclkb_hz, &cks, &brh, &brl);
362 if (br_err != k_ra8_ok) {
363 return br_err;
364 }
365 /* HUM Ch 39.2.3 "ICMR1 : I2C Bus Mode Register 1 -- CKS[6:4]" p 2374 */
366 reg->ICMR1 = (uint8_t)(((uint32_t)reg->ICMR1 & ~((uint32_t)(uint8_t)k_ra8_i2c_cks_max
367 << (uint32_t)k_ra8_i2c_icmr1_cks_pos)) |
368 ((uint32_t)cks << (uint32_t)k_ra8_i2c_icmr1_cks_pos));
369 /* HUM Ch 39.2.15 "ICBRL : I2C Bus Bit Rate Low-Level Register" p 2391 */
370 reg->ICBRL = brl;
371 /* HUM Ch 39.2.16 "ICBRH : I2C Bus Bit Rate High-Level Register" p 2392 */
372 reg->ICBRH = brh;
373 return k_ra8_ok;
374}
375
376/* =============================================================================
377 * Status helpers.
378 * =============================================================================
379 */
380
381ra8_err_t ra8_i2c_get_errors(uint8_t channel, uint8_t* out_mask)
382{
383 RA8_CHECK_NULL_PTR(out_mask, g_i2c_tag, "i2c_get_errors: out_mask");
384 volatile const r_i2c_regs_t* reg = ra8_i2c_regs(channel);
385 if (reg == nullptr) {
387 }
388 /* HUM Ch 39.2.10 "ICSR2 : I2C Bus Status Register 2" p 2384 */
389 *out_mask = internal_i2c_decode_errors(reg->ICSR2);
390 return k_ra8_ok;
391}
392
394{
395 volatile r_i2c_regs_t* reg = ra8_i2c_regs(channel);
396 if (reg == nullptr) {
398 }
399 enum : uint8_t {
400 k_ra8_i2c_err_clear_mask =
401 (uint8_t)((uint8_t)k_ra8_i2c_msk_icsr2_al | (uint8_t)k_ra8_i2c_msk_icsr2_nackf |
402 (uint8_t)(1U << (uint8_t)
404 };
405 /* HUM Ch 39.2.10 "ICSR2 : I2C Bus Status Register 2 -- W0C" p 2384 */
406 reg->ICSR2 = (uint8_t)(reg->ICSR2 & (uint8_t)~(uint8_t)k_ra8_i2c_err_clear_mask);
407 return k_ra8_ok;
408}
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_invalid_arg
Invalid function argument.
Definition ra8_err.h:152
@ k_ra8_ok
Success – operation completed with all postconditions satisfied.
Definition ra8_err.h:119
ra8_err_codes_t ra8_err_t
Canonical error-return type used by every ra8-firmware API.
Definition ra8_err.h:546
ra8_i2c_state_t s_i2c_state[k_ra8_i2c_channel_count]
Per-channel state table indexed by channel.
Definition ra8_i2c.c:132
bool priv_ra8_i2c_internal_clk_invalid(uint32_t bus_hz, uint32_t pclkb_hz)
Pure predicate: either clock argument is zero.
Definition ra8_i2c.c:114
const char *const g_i2c_tag
Log tag for this driver, shared with ra8_i2c_config.c.
Definition ra8_i2c.c:65
I2C Bus Interface (IIC) controller driver – polling mode.
@ k_ra8_i2c_speed_fast_plus
1 MHz Fast-mode Plus (Fm+).
Definition ra8_i2c.h:82
@ k_ra8_i2c_err_none
No latched error.
Definition ra8_i2c.h:111
@ k_ra8_i2c_err_arb_lost
ICSR2.AL set (arbitration lost).
Definition ra8_i2c.h:112
@ k_ra8_i2c_err_nack
ICSR2.NACKF set (NACK received).
Definition ra8_i2c.h:113
@ k_ra8_i2c_err_timeout
ICSR2.TMOF set (bus timeout).
Definition ra8_i2c.h:114
static ra8_err_t internal_i2c_bitrate(uint32_t bus_hz, uint32_t pclkb_hz, uint8_t *out_cks, uint8_t *out_brh, uint8_t *out_brl)
Compute the CKS divider and ICBRH/ICBRL half-period counts.
static ra8_mstp_t internal_i2c_mstp_id(uint8_t channel)
Map a channel index to its MSTP gate id.
static uint8_t internal_i2c_decode_errors(uint8_t icsr2)
Decode latched ICSR2 error bits into a k_ra8_i2c_err_* mask.
ra8_err_t ra8_i2c_deinit(uint8_t channel)
Tear down an IIC channel.
static uint8_t internal_i2c_clamp_half(uint32_t total)
Clamp one SCL half-period count to the 5-bit BR field.
ra8_err_t ra8_i2c_init(uint8_t channel, const ra8_i2c_cfg_t *cfg)
Initialise an IIC channel as a controller and bring the bus up.
ra8_err_t ra8_i2c_get_errors(uint8_t channel, uint8_t *out_mask)
Read latched error flags from ICSR2 (AL / NACKF / TMOF).
ra8_err_t ra8_i2c_clear_errors(uint8_t channel)
Clear latched error flags in ICSR2.
static uint8_t internal_i2c_pick_cks(uint32_t *total)
Pick the smallest CKS divider and divide *total to match.
ra8_i2c_brate_t
Bit-rate divider field limits (HUM Ch 39.2.15 / 39.2.16).
@ k_ra8_i2c_br_reserved_hi
Upper 3 reserved bits of ICBRL / ICBRH read as 1.
@ k_ra8_i2c_cks_max
CKS divider exponent ceiling (CKS[2:0] selects PCLKB / 2^CKS).
@ k_ra8_i2c_br_field_max
ICBRL / ICBRH counter fields are 5 bits ([4:0]).
@ k_ra8_i2c_period_split
Period split between SCL high and low halves.
ra8_err_t ra8_i2c_set_clock(uint8_t channel, uint32_t bus_hz, uint32_t pclkb_hz)
Update the bus clock without tearing the channel down.
static void internal_i2c_apply_init_regs(volatile r_i2c_regs_t *reg, uint8_t cks, uint8_t brh, uint8_t brl, bool fast_plus)
Apply the bring-up register sequence for an IIC channel.
Test-access surface for ra8_i2c internal helpers (MC/DC).
I2C Bus Interface (IIC) register layout for the Renesas RA8D2.
@ k_ra8_i2c_icmr1_cks_pos
Internal reference clock select [6:4].
@ k_ra8_i2c_msk_icsr2_al
HUM 39.2.10 ICSR2.AL, p 2384.
@ k_ra8_i2c_msk_icfer_fmpe
HUM 39.2.6 ICFER.FMPE, p 2378.
@ k_ra8_i2c_msk_icfer_nacke
HUM 39.2.6 ICFER.NACKE, p 2378.
@ k_ra8_i2c_msk_icsr2_nackf
HUM 39.2.10 ICSR2.NACKF, p 2384.
@ k_ra8_i2c_msk_iccr1_iicrst
HUM 39.2.1 ICCR1.IICRST, p 2369.
@ k_ra8_i2c_msk_iccr1_ice
HUM 39.2.1 ICCR1.ICE, p 2369.
@ k_ra8_i2c_msk_icfer_scle
HUM 39.2.6 ICFER.SCLE, p 2378.
@ k_ra8_i2c_msk_icfer_male
HUM 39.2.6 ICFER.MALE, p 2378.
static volatile r_i2c_regs_t * ra8_i2c_regs(uint8_t channel)
Get a pointer to the IIC channel channel register block.
@ k_ra8_i2c_icsr2_tmof_pos
Timeout detection flag.
Lightweight Logging Interface for ra8-firmware.
#define ra8_log_info_val(tag, message, value)
RA8 log info val.
Definition ra8_log.h:366
Ref-counted Module Stop Control wrapper for the RA8D2.
ra8_err_t ra8_mstp_enable(ra8_mstp_t id)
Reference-counted "ungate this peripheral" request.
Definition ra8_mstp.c:343
ra8_err_t ra8_mstp_disable(ra8_mstp_t id)
Reference-counted "gate this peripheral" request.
Definition ra8_mstp.c:382
ra8_mstp_t
Packed (reg << 8) | bit module-stop identifier.
@ k_ra8_mstp_iic2
MSTPB7 IIC2.
@ k_ra8_mstp_iic0
MSTPB9 IIC0.
@ k_ra8_mstp_iic1
MSTPB8 IIC1.
Memory-mapped register block for one IIC channel.
volatile uint8_t ICMR1
+0x02 Bus Mode Register 1 (HUM 39.2.3, p 2374).
volatile uint8_t ICBRL
+0x10 Bit Rate Low-Level (HUM 39.2.15, p 2391).
volatile uint8_t ICFER
+0x05 Bus Function Enable (HUM 39.2.6, p 2378).
volatile uint8_t ICCR1
+0x00 Bus Control Register 1 (HUM 39.2.1, p 2369).
volatile uint8_t ICBRH
+0x11 Bit Rate High-Level (HUM 39.2.16, p 2392).
volatile uint8_t ICSR2
+0x09 Bus Status Register 2 (HUM 39.2.10, p 2384).
Configuration descriptor for ra8_i2c_init.
Definition ra8_i2c.h:97
uint32_t bus_hz
Target I2C clock rate in Hz.
Definition ra8_i2c.h:98
uint32_t pclkb_hz
Current PCLKB frequency in Hz for bit-rate calc.
Definition ra8_i2c.h:99