@@ -111,9 +111,9 @@ const OperationType = enum(u1) {
111111};
112112
113113pub const instance = struct {
114- pub const I2C0 : I2C = @as (I2C , @enumFromInt (0 ));
115114 pub fn num (n : u1 ) I2C {
116- return @as (I2C , @enumFromInt (n ));
115+ if (n != 0 ) @compileError ("Only I2C0 is present" );
116+ return .{ .regs = I2C0 };
117117 }
118118};
119119
@@ -124,15 +124,20 @@ const I2C_FIFO_SIZE: usize = 32;
124124const I2C_CHUNK_SIZE : usize = I2C_FIFO_SIZE - 1 ;
125125
126126/// I2C Master peripheral driver
127- pub const I2C = enum (u1 ) {
128- _ ,
127+ pub const I2C = struct {
128+ regs : * volatile I2cRegs ,
129+ frequency : u32 = 100_000 ,
129130
130- inline fn get_regs (i2c : I2C ) * volatile I2cRegs {
131- _ = i2c ;
132- return I2C0 ;
131+ inline fn get_regs (self : I2C ) * volatile I2cRegs {
132+ return self .regs ;
133133 }
134134
135- pub fn apply (self : I2C , frequency : u32 ) ConfigError ! void {
135+ pub fn apply (self : * I2C , frequency : u32 ) ConfigError ! void {
136+ self .frequency = frequency ;
137+ try self .init ();
138+ }
139+
140+ pub fn init (self : I2C ) ConfigError ! void {
136141 const regs = self .get_regs ();
137142
138143 // Enable I2C peripheral clock and take it out of reset
@@ -163,7 +168,7 @@ pub const I2C = enum(u1) {
163168
164169 // Configure frequency
165170 // TODO: Take timeout as extra arg and handle saturation?
166- try self .set_frequency (SOURCE_CLK_FREQ , frequency );
171+ try self .set_frequency (SOURCE_CLK_FREQ , self . frequency );
167172
168173 // Propagate configuration changes
169174 self .update_config ();
@@ -207,6 +212,7 @@ pub const I2C = enum(u1) {
207212 .RX_FIFO_RST = 1 ,
208213 // Esp hal sets these here
209214 .NONFIFO_EN = 0 ,
215+ .FIFO_PRT_EN = 1 ,
210216 // Esp hal sets these, but why?
211217 .RXFIFO_WM_THRHD = 1 ,
212218 .TXFIFO_WM_THRHD = 31 ,
@@ -218,12 +224,6 @@ pub const I2C = enum(u1) {
218224 .RX_FIFO_RST = 0 ,
219225 });
220226
221- // Make sure the FIFO operates in FIFO mode
222- self .get_regs ().FIFO_CONF .modify (.{
223- .NONFIFO_EN = 0 ,
224- .FIFO_PRT_EN = 0 ,
225- });
226-
227227 self .get_regs ().INT_CLR .modify (.{
228228 .RXFIFO_WM_INT_CLR = 1 ,
229229 .TXFIFO_WM_INT_CLR = 1 ,
@@ -302,9 +302,17 @@ pub const I2C = enum(u1) {
302302 });
303303 }
304304
305+ fn reset_fsm (self : I2C ) ! void {
306+ // Even though C2 and C3 have a FSM reset bit, esp-idf does not
307+ // define SOC_I2C_SUPPORT_HW_FSM_RST for them, so include them in the fallback impl.
308+ microzig .hal .system .peripheral_reset (.{ .i2c_ext0 = true });
309+
310+ try self .init ();
311+ }
312+
305313 fn check_errors (self : I2C ) ! void {
306314 // Reset the peripheral in case of error
307- errdefer self .reset () ;
315+ errdefer self .reset_fsm () catch {} ;
308316
309317 const interrupts = self .get_regs ().INT_RAW .read ();
310318 if (interrupts .TIME_OUT_INT_RAW == 1 ) {
@@ -428,44 +436,13 @@ pub const I2C = enum(u1) {
428436 const write_len : u8 = @truncate (if (start ) bytes .len + 1 else bytes .len );
429437
430438 if (write_len > 0 ) {
431- if (write_len < 2 ) {
432- try self .add_cmd (cmd_start_idx , .{ .write = .{
433- .ack_exp = .ack ,
434- .ack_check_en = true ,
435- .length = @bitCast (write_len ),
436- } });
437- } else if (start ) {
438- try self .add_cmd (cmd_start_idx , .{ .write = .{
439- .ack_exp = .ack ,
440- .ack_check_en = true ,
441- .length = @bitCast (write_len - 1 ),
442- } });
443- try self .add_cmd (cmd_start_idx , .{ .write = .{
444- .ack_exp = .ack ,
445- .ack_check_en = true ,
446- .length = 1 ,
447- } });
448- } else {
449- try self .add_cmd (cmd_start_idx , .{ .write = .{
450- .ack_exp = .ack ,
451- .ack_check_en = true ,
452- .length = @bitCast (write_len - 2 ),
453- } });
454- try self .add_cmd (cmd_start_idx , .{ .write = .{
455- .ack_exp = .ack ,
456- .ack_check_en = true ,
457- .length = 1 ,
458- } });
459- try self .add_cmd (cmd_start_idx , .{ .write = .{
460- .ack_exp = .ack ,
461- .ack_check_en = true ,
462- .length = 1 ,
463- } });
464- }
439+ try self .add_cmd (cmd_start_idx , .{ .write = .{
440+ .ack_exp = .ack ,
441+ .ack_check_en = true ,
442+ .length = @bitCast (write_len ),
443+ } });
465444 }
466445
467- self .update_config ();
468-
469446 // Load address and R/W bit
470447 if (start )
471448 self .write_fifo (@as (u8 , @intFromEnum (addr )) << 1 | @intFromEnum (OperationType .write ));
@@ -630,10 +607,12 @@ pub const I2C = enum(u1) {
630607 while (remaining != 0 ) {
631608 const max_chunk_size = if (remaining <= I2C_CHUNK_SIZE )
632609 remaining
633- else if (remaining > I2C_CHUNK_SIZE + 2 )
610+ else if (is_first_chunk )
611+ // Reserve space for start byte
634612 I2C_CHUNK_SIZE
635613 else
636- I2C_CHUNK_SIZE - 2 ;
614+ // Fully use the FIFO
615+ I2C_CHUNK_SIZE + 1 ;
637616
638617 const buffer_remaining = max_chunk_size - buffer_level ;
639618 if (buffer_remaining == 0 ) {
0 commit comments