@@ -11,19 +11,20 @@ const I2C_Device = mdf.base.I2C_Device;
1111const Clock_Device = mdf .base .Clock_Device ;
1212
1313/// TLV493D I2C addresses
14- pub const TLV493D_ADDRESS0 : I2C_Device.Address = @enumFromInt (0x1F );
15- pub const TLV493D_ADDRESS1 : I2C_Device.Address = @enumFromInt (0x5E ); // Default
14+ pub const ADDRESS0 : I2C_Device.Address = @enumFromInt (0x1F );
15+ pub const ADDRESS1 : I2C_Device.Address = @enumFromInt (0x5E ); // Default
1616
1717/// Startup delay in milliseconds
18- pub const TLV493D_STARTUPDELAY_MS : u32 = 40 ;
18+ pub const STARTUPDELAY_MS : u32 = 40 ;
19+ pub const RESETDELAY_MS : u32 = 200 ;
1920
2021/// Conversion factors
21- pub const TLV493D_B_MULT : f32 = 0.098 ; // mT per LSB
22- pub const TLV493D_TEMP_MULT : f32 = 1.1 ; // °C per LSB
23- pub const TLV493D_TEMP_OFFSET = 340 ; // Temperature offset (in LSB)
22+ const B_MULT : f32 = 0.098 ; // mT per LSB
23+ const TEMP_MULT : f32 = 1.1 ; // °C per LSB
24+ const TEMP_OFFSET = 340 ; // Temperature offset (in LSB)
2425
2526/// Default mode for sensor operation
26- pub const TLV493D_DEFAULTMODE = AccessMode .master_controlled ;
27+ pub const DEFAULTMODE = AccessMode .master_controlled ;
2728
2829/// TLV493D Measurement values
2930pub const Values = struct {
@@ -35,19 +36,19 @@ pub const Values = struct {
3536
3637/// TLV493D configuration
3738pub const Config = struct {
38- reset : bool = true ,
39+ reset : bool = false ,
3940 enable_temp : bool = false ,
41+ access_mode : AccessMode = DEFAULTMODE ,
4042};
4143
4244/// TLV493D related errors
4345pub const Error = error {
44- // TODO: We can only detect NoDevice if we get a NACK, which we can only tell with a proper i2c
45- // interface
4646 NoDevice ,
4747 BusError ,
4848 FrameError ,
4949 DatagramError ,
5050 InvalidData ,
51+ Unsupported ,
5152};
5253
5354const ReadRegister = packed struct (u80 ) {
@@ -153,7 +154,7 @@ pub const TLV493D = struct {
153154 z_data : i12 = 0 ,
154155 temp_data : i12 = 0 ,
155156 mode : AccessMode ,
156- expected_frame_count : u8 ,
157+ expected_frame_count : u2 = 0 ,
157158
158159 /// Create a new TLV493D instance
159160 pub fn init (dev : I2C_Device , address : I2C_Device.Address , clock : Clock_Device , config : Config ) Error ! Self {
@@ -163,23 +164,34 @@ pub const TLV493D = struct {
163164 .clock = clock ,
164165 .read_data = @bitCast ([_ ]u8 {0 } ** 10 ),
165166 .write_data = @bitCast ([_ ]u8 {0 } ** 4 ),
166- // TODO: Add to config
167- // .mode = .fast,
168- .mode = TLV493D_DEFAULTMODE ,
169- .expected_frame_count = 0 ,
167+ .mode = config .access_mode ,
170168 };
171169
170+ // We don't support setting the I2C bits for the extra 6 addresses
171+ // In fact, we don't support anything other than the default, since reseting seems to cause
172+ // the device to hang.
173+ if (address != ADDRESS1 )
174+ return Error .Unsupported ;
175+
176+ // TODO: Support other modes
177+ if (self .mode != DEFAULTMODE )
178+ return Error .Unsupported ;
179+
172180 // The first thing we have to do is read out the factory calibration and pack it into the
173181 // write register so that we don't clear it on the first write.
174- self .setup_write_buffer () catch return Error . BusError ;
182+ try self .setup_write_buffer ();
175183
176184 // Sleep for startup delay
177- // TODO: Needed?
178- self .clock .sleep_ms (TLV493D_STARTUPDELAY_MS );
185+ self .clock .sleep_ms (STARTUPDELAY_MS );
179186
180187 // Reset sensor if requested
181- if (config .reset )
182- try self .reset_sensor ();
188+ // TODO: Figure out why when using the broadcast address, the subsequent reads seem to hang
189+ if (config .reset ) {
190+ return Error .Unsupported ;
191+ // try self.reset_sensor();
192+ }
193+
194+ // try self.synchronize_frame_count();
183195
184196 // Get all register data from sensor
185197 try self .read_out ();
@@ -193,8 +205,13 @@ pub const TLV493D = struct {
193205 return self ;
194206 }
195207
196- fn setup_write_buffer (self : * Self ) ! void {
197- try self .read_out ();
208+ fn setup_write_buffer (self : * Self ) Error ! void {
209+ self .read_out () catch | e | switch (e ) {
210+ // The FRAMECOUNTER doesn't seem to correctly reset to 0, so since this is the first
211+ // read we do, we ignore it
212+ Error .FrameError = > {},
213+ else = > return e ,
214+ };
198215
199216 // Section 5.2 of the user manual:
200217 // > After that byte 7, 8 & 9 have to be read out at least one time and stored for later use
@@ -211,36 +228,57 @@ pub const TLV493D = struct {
211228 /// Deinitialize the device
212229 pub fn deinit (self : * Self ) void {
213230 self .disable_interrupt () catch {};
214- self .set_access_mode (AccessMode .powerdown ) catch {};
231+ self .set_access_mode (.powerdown ) catch {};
215232 }
216233
217234 /// Reset the sensor using recovery sequence
235+ // TODO: Figure out why this causes the device to stop responding
218236 fn reset_sensor (self : * Self ) Error ! void {
219237 // On startup the SDA line is sampled. If the line is high, it will listen on address 0x5E.
220238 // Otherwise, it will listen on 0x1F. The line must be kept stable for 200us.
221239 // Because we shouldn't be touching the line that early, and SDA is pulled high, it should
222240 // be assigned 0x5E, but it is better if we can explicitly set it.
223241 // We can explicitly set the address by writing either 0xFF ox 0x00 to address 0
224- var reset_data : u8 = 0x00 ;
225- if (self .address == TLV493D_ADDRESS1 )
226- reset_data = 0xFF ; // Set SDA high for address 0x5E
242+ // Set SDA high for address 0x5E, low for 0x1F
243+ const reset_data : u8 = if (self .address == ADDRESS1 ) 0xFF else 0x00 ;
227244
228245 // Send recovery frame, clearing bad state
229- self .dev .writev (.general_call , &.{&.{reset_data }}) catch return Error .DatagramError ;
246+ self .dev .writev (.general_call , &.{&.{reset_data }}) catch | e |
247+ return map_error (e );
248+ self .clock .sleep_ms (RESETDELAY_MS );
249+
250+ // It seems that this resets the count to 1
251+ self .expected_frame_count = 1 ;
230252 }
231253
232254 /// Read all registers from sensor
233255 fn read_out (self : * Self ) Error ! void {
234256 // Due to padding on the structure, the slice is 16 bytes long, so we have to slice it to 10
235- const bytes_read = self .dev .readv (self .address , &.{std .mem .asBytes (& self .read_data )[0.. 10]}) catch return Error .DatagramError ;
257+ const bytes_read = self .dev .readv (self .address , &.{std .mem .asBytes (& self .read_data )[0.. 10]}) catch | e |
258+ return map_error (e );
236259 if (bytes_read != 10 ) return Error .InvalidData ;
260+
261+ if (self .expected_frame_count != self .read_data .FRAMECOUNTER ) {
262+ // Section 5.6: Corrective action: Reset sensor
263+ // try self.reset_sensor();
264+ }
265+
266+ self .expected_frame_count = @truncate (@as (u8 , self .expected_frame_count ) + 1 );
237267 }
238268
239269 /// Write configuration to sensor
240270 fn write_out (self : * Self ) Error ! void {
241271 self .calc_parity ();
242- self .dev .writev (self .address , &.{std .mem .asBytes (& self .write_data )}) catch
243- return Error .DatagramError ;
272+ self .dev .writev (self .address , &.{std .mem .asBytes (& self .write_data )}) catch | e |
273+ return map_error (e );
274+ }
275+
276+ /// Synchronize the expected_frame_count with whatever the device thinks we're on.
277+ fn synchronize_frame_count (self : * Self ) Error ! void {
278+ const bytes_read = self .dev .readv (self .address , &.{std .mem .asBytes (& self .read_data )[0.. 10]}) catch | e |
279+ return map_error (e );
280+ if (bytes_read != 10 ) return Error .InvalidData ;
281+ self .expected_frame_count = @truncate (@as (u8 , self .read_data .FRAMECOUNTER ) + 1 );
244282 }
245283
246284 /// Set access mode
@@ -292,7 +330,7 @@ pub const TLV493D = struct {
292330 var powerdown = false ;
293331
294332 // In POWERDOWNMODE, sensor has to be switched on for one measurement
295- if (self .mode == AccessMode .powerdown ) {
333+ if (self .mode == .powerdown ) {
296334 self .set_access_mode (AccessMode .master_controlled ) catch return Error .BusError ;
297335
298336 // Wait for measurement delay
@@ -302,7 +340,7 @@ pub const TLV493D = struct {
302340 }
303341
304342 // Read measurement data
305- self .read_out () catch return Error . BusError ;
343+ try self .read_out ();
306344
307345 // Construct results from registers
308346 self .x_data = @as (i12 , self .read_data .BxH ) << 4 | self .read_data .BxL ;
@@ -311,54 +349,52 @@ pub const TLV493D = struct {
311349 self .temp_data = @as (i12 , self .read_data .TEMPH ) << 8 | self .read_data .TEMPL ;
312350
313351 // Switch sensor back to POWERDOWNMODE if it was in POWERDOWNMODE before
314- if (powerdown )
315- self .set_access_mode (AccessMode .powerdown ) catch return Error .BusError ;
352+ if (self . mode == . powerdown )
353+ self .set_access_mode (.powerdown ) catch return Error .BusError ;
316354
317355 // Check for frame errors
318356 if (self .read_data .CHANNEL != 0 )
319357 return Error .FrameError ;
320-
321- self .expected_frame_count = self .read_data .FRAMECOUNTER ;
322358 }
323359
324360 /// Read magnetic field and temperature values
325361 pub fn read (self : * Self ) Error ! Values {
326362 try self .update_data ();
327363
328364 return Values {
329- .x = @as ( f32 , @floatFromInt ( self .x_data )) * TLV493D_B_MULT ,
330- .y = @as ( f32 , @floatFromInt ( self .y_data )) * TLV493D_B_MULT ,
331- .z = @as ( f32 , @floatFromInt ( self .z_data )) * TLV493D_B_MULT ,
332- .temp = ( @as ( f32 , @floatFromInt ( self .temp_data - TLV493D_TEMP_OFFSET ))) * TLV493D_TEMP_MULT ,
365+ .x = self .get_x () ,
366+ .y = self .get_y () ,
367+ .z = self .get_z () ,
368+ .temp = self .get_temp () ,
333369 };
334370 }
335371
336372 /// Get X-axis magnetic field
337- pub fn get_x (self : * Self ) f32 {
338- return @as (f32 , @floatFromInt (self .x_data )) * TLV493D_B_MULT ;
373+ pub inline fn get_x (self : * Self ) f32 {
374+ return @as (f32 , @floatFromInt (self .x_data )) * B_MULT ;
339375 }
340376
341377 /// Get Y-axis magnetic field
342- pub fn get_y (self : * Self ) f32 {
343- return @as (f32 , @floatFromInt (self .y_data )) * TLV493D_B_MULT ;
378+ pub inline fn get_y (self : * Self ) f32 {
379+ return @as (f32 , @floatFromInt (self .y_data )) * B_MULT ;
344380 }
345381
346382 /// Get Z-axis magnetic field
347- pub fn get_z (self : * Self ) f32 {
348- return @as (f32 , @floatFromInt (self .z_data )) * TLV493D_B_MULT ;
383+ pub inline fn get_z (self : * Self ) f32 {
384+ return @as (f32 , @floatFromInt (self .z_data )) * B_MULT ;
349385 }
350386
351387 /// Get temperature in °C
352- pub fn get_temp (self : * Self ) f32 {
353- return (@as (f32 , @floatFromInt (self .temp_data )) - TLV493D_TEMP_OFFSET ) * TLV493D_TEMP_MULT ;
388+ pub inline fn get_temp (self : * Self ) f32 {
389+ return (@as (f32 , @floatFromInt (self .temp_data )) - TEMP_OFFSET ) * TEMP_MULT ;
354390 }
355391
356392 /// Get magnetic field magnitude
357393 pub fn get_magnitude (self : * Self ) f32 {
358394 const x : f32 = @floatFromInt (self .x_data );
359395 const y : f32 = @floatFromInt (self .y_data );
360396 const z : f32 = @floatFromInt (self .z_data );
361- return TLV493D_B_MULT * @sqrt (x * x + y * y + z * z );
397+ return B_MULT * @sqrt (x * x + y * y + z * z );
362398 }
363399
364400 /// Get azimuth angle (atan2(y, x))
@@ -394,3 +430,13 @@ pub const TLV493D = struct {
394430 self .write_data .PARITY = @truncate (y & 0x01 );
395431 }
396432};
433+
434+ /// Map I2C_Device errors to device errors
435+ fn map_error (err : I2C_Device.InterfaceError ) Error {
436+ return switch (err ) {
437+ I2C_Device .Error .NoAcknowledge ,
438+ I2C_Device .Error .Timeout ,
439+ = > Error .NoDevice ,
440+ else = > Error .BusError ,
441+ };
442+ }
0 commit comments