|
| 1 | +//! |
| 2 | +//! Generic driver for the ams AS5600 Position Sensor. |
| 3 | +//! |
| 4 | +//! Datasheet: |
| 5 | +//! * https://www.mouser.com/datasheet/2/588/AS5600_DS000365_5-00-1877365.pdf |
| 6 | +//! |
| 7 | +const std = @import("std"); |
| 8 | +const mdf = @import("../framework.zig"); |
| 9 | + |
| 10 | +pub const AS5600 = struct { |
| 11 | + const Self = @This(); |
| 12 | + const address: mdf.base.I2C_Device.Address = @enumFromInt(0x36); |
| 13 | + dev: mdf.base.I2C_Device, |
| 14 | + |
| 15 | + const register = enum(u8) { |
| 16 | + ZMCO = 0x00, |
| 17 | + ZPOS = 0x01, |
| 18 | + MPOS = 0x03, |
| 19 | + MANG = 0x05, |
| 20 | + CONF = 0x07, |
| 21 | + RAW_ANGLE = 0x0C, |
| 22 | + ANGLE = 0x0E, |
| 23 | + STATUS = 0x0B, |
| 24 | + AGC = 0x1A, |
| 25 | + MAGNITUDE = 0x1B, |
| 26 | + BURN = 0xFF, |
| 27 | + }; |
| 28 | + |
| 29 | + pub const Configuration = packed struct(u14) { |
| 30 | + PM: enum(u2) { |
| 31 | + nom = 0b00, |
| 32 | + lpm1 = 0b01, |
| 33 | + lpm2 = 0b10, |
| 34 | + lpm3 = 0b11, |
| 35 | + } = .nom, |
| 36 | + HYST: enum(u2) { |
| 37 | + off = 0b00, |
| 38 | + @"1lsb" = 0b01, |
| 39 | + @"2lsbs" = 0b10, |
| 40 | + @"3lsbs" = 0b11, |
| 41 | + } = .off, |
| 42 | + OUTS: enum(u2) { |
| 43 | + full_analog = 0b00, |
| 44 | + reduced_analog = 0b01, |
| 45 | + digital_pwm = 0b10, |
| 46 | + } = .full_analog, |
| 47 | + PWMF: enum(u2) { |
| 48 | + @"115Hz" = 0b00, |
| 49 | + @"230Hz" = 0b01, |
| 50 | + @"460Hz" = 0b10, |
| 51 | + @"920Hz" = 0b11, |
| 52 | + } = .@"115Hz", |
| 53 | + SF: enum(u2) { |
| 54 | + @"2x" = 0b11, |
| 55 | + @"4x" = 0b10, |
| 56 | + @"8x" = 0b01, |
| 57 | + @"16x" = 0b00, |
| 58 | + } = .@"16x", |
| 59 | + FTH: enum(u3) { |
| 60 | + slow = 0b000, |
| 61 | + @"6lsbs" = 0b001, |
| 62 | + @"7lsbs" = 0b010, |
| 63 | + @"9lsbs" = 0b011, |
| 64 | + @"10lsbs" = 0b111, |
| 65 | + @"18lsbs" = 0b100, |
| 66 | + @"21lsbs" = 0b101, |
| 67 | + @"24lsbs" = 0b110, |
| 68 | + } = .slow, |
| 69 | + WD: enum(u1) { off = 0, on = 1 } = .off, |
| 70 | + }; |
| 71 | + |
| 72 | + pub const Status = packed struct(u8) { |
| 73 | + reserved0: u3 = 0, |
| 74 | + // Magnet too strong |
| 75 | + MH: u1 = 0, |
| 76 | + // Magnet too weak |
| 77 | + ML: u1 = 0, |
| 78 | + // Magnet detected |
| 79 | + MD: u1 = 0, |
| 80 | + reserved6: u2 = 0, |
| 81 | + }; |
| 82 | + |
| 83 | + pub fn init(dev: mdf.base.I2C_Device) Self { |
| 84 | + return Self{ .dev = dev }; |
| 85 | + } |
| 86 | + |
| 87 | + pub fn read1_raw(self: *const Self, reg: Self.register) !u8 { |
| 88 | + try self.dev.write(Self.address, &[_]u8{@intFromEnum(reg)}); |
| 89 | + var buf: [1]u8 = undefined; |
| 90 | + const size = try self.dev.read(Self.address, &buf); |
| 91 | + if (size != 1) return error.ReadError; |
| 92 | + return buf[0]; |
| 93 | + } |
| 94 | + |
| 95 | + pub fn read2_raw(self: *const Self, reg: Self.register) !u16 { |
| 96 | + try self.dev.write(Self.address, &[_]u8{@intFromEnum(reg)}); |
| 97 | + var buf: [2]u8 = undefined; |
| 98 | + const size = try self.dev.read(Self.address, &buf); |
| 99 | + if (size != 2) return error.ReadError; |
| 100 | + return std.mem.readInt(u16, &buf, .big); |
| 101 | + } |
| 102 | + |
| 103 | + pub fn write_raw(self: *const Self, reg: Self.register, v: u16) !void { |
| 104 | + return self.dev.write( |
| 105 | + Self.address, |
| 106 | + &([1]u8{@intFromEnum(reg)} ++ @as([2]u8, @bitCast(std.mem.nativeToBig(u16, v)))), |
| 107 | + ); |
| 108 | + } |
| 109 | + |
| 110 | + pub fn read_zero_position(self: *const Self) !u16 { |
| 111 | + const zpos = self.read2_raw(register.ZPOS); |
| 112 | + return zpos & 0xFFF; |
| 113 | + } |
| 114 | + |
| 115 | + pub fn write_zero_position(self: *const Self, position: u12) !void { |
| 116 | + // Read-modify-write because the high 4 bits might store config |
| 117 | + var zpos = try self.read2_raw(register.ZPOS); |
| 118 | + zpos = (zpos & 0xF000) | position; |
| 119 | + try self.write_raw(register.ZPOS, zpos); |
| 120 | + } |
| 121 | + |
| 122 | + pub fn read_max_position(self: *const Self) !u16 { |
| 123 | + const mpos = self.read2_raw(register.MPOS); |
| 124 | + return mpos & 0xFFF; |
| 125 | + } |
| 126 | + |
| 127 | + pub fn write_max_position(self: *const Self, max: u12) !void { |
| 128 | + // Read-modify-write because the high 4 bits might store config |
| 129 | + var mpos = try self.read2_raw(register.MPOS); |
| 130 | + mpos = (mpos & 0xF000) | max; |
| 131 | + try self.write_raw(register.MPOS, mpos); |
| 132 | + } |
| 133 | + |
| 134 | + pub fn read_max_angle(self: *const Self) !u16 { |
| 135 | + const mang = self.read2_raw(register.MANG); |
| 136 | + return mang & 0xFFF; |
| 137 | + } |
| 138 | + |
| 139 | + pub fn write_max_angle(self: *const Self, max: u12) !void { |
| 140 | + // Read-modify-write because the high 4 bits might store config |
| 141 | + var mang = try self.read2_raw(register.MANG); |
| 142 | + mang = (mang & 0xF000) | max; |
| 143 | + try self.write_raw(register.MANG, mang); |
| 144 | + } |
| 145 | + |
| 146 | + pub fn read_configuration(self: *const Self) !u16 { |
| 147 | + const configuration = self.read2_raw(register.CONF); |
| 148 | + return @bitCast(configuration); |
| 149 | + } |
| 150 | + |
| 151 | + pub fn write_configuration(self: *const Self, config: Configuration) !void { |
| 152 | + return self.write_raw(Self.register.CONF, @bitCast(config)); |
| 153 | + } |
| 154 | + |
| 155 | + pub fn read_raw_angle(self: *const Self) !f32 { |
| 156 | + const angle = (try self.read2_raw(register.ANGLE)) & 0xFFF; |
| 157 | + return @as(f32, @floatFromInt(angle)) * 360 / 4096; |
| 158 | + } |
| 159 | + |
| 160 | + pub fn read_angle(self: *const Self) !f32 { |
| 161 | + const angle = (try self.read2_raw(register.ANGLE)) & 0xFFF; |
| 162 | + return @as(f32, @floatFromInt(angle)) * 360 / 4096; |
| 163 | + } |
| 164 | + |
| 165 | + pub fn read_status(self: *const Self) !Status { |
| 166 | + const s = try self.read1_raw(register.STATUS); |
| 167 | + return @bitCast(s & (0b111 << 3)); |
| 168 | + } |
| 169 | + |
| 170 | + pub fn read_magnitude(self: *const Self) !u16 { |
| 171 | + return self.read2_raw(register.MAGNITUDE); |
| 172 | + } |
| 173 | + |
| 174 | + // TODO: Write burn functions. Scary. |
| 175 | +}; |
0 commit comments