Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
233 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,163 @@ | ||
from machine import I2C,Pin | ||
from micropython import const | ||
from ustruct import unpack, pack | ||
from collections import namedtuple | ||
from time import sleep | ||
|
||
AS5600_id = const(0x36) #Device ID | ||
m12 = const((1<<12)-1) #0xFFF | ||
|
||
|
||
|
||
REGS=namedtuple('REGS','ZMCO ZPOS MPOS MANG CONF RAWANGLE ANGLE STATUS AGC MAGNITUDE BURN') | ||
r = REGS(0,1,3,5,7,0xc,0xe,0x0b,0x1a,0xb,0xff) | ||
|
||
#You cant overwrite __attribute__ in micropython but you can use Descriptors | ||
class RegDescriptor: | ||
"Read and write a bit field from a register" | ||
|
||
def __init__(self,reg,shift,mask,buffsize=2): | ||
"initialise with specific identifiers for the bit field" | ||
|
||
self.reg = reg | ||
self.shift = shift | ||
self.mask = mask | ||
self.buffsize = buffsize | ||
self.writeable = (r.ZMCO,r.ZPOS,r.MPOS,r.MANG,r.CONF,r.BURN) | ||
self.cache={} | ||
#NB the I2c object and the device name come from the main class via an object | ||
|
||
def get_register(self,obj): | ||
"Read an I2C register" | ||
#cache those registers with values that will not change. | ||
#Dont bother caching bit fields. | ||
if self.reg in self.cache: | ||
return self.cache[self.reg] | ||
|
||
#print ('reading now the actual device now') | ||
|
||
buff = obj.i2c.readfrom_mem(obj.device,self.reg,self.buffsize) | ||
|
||
|
||
if self.buffsize == 2: | ||
v = unpack(">H",buff)[0] #2 bytes big endian | ||
else: | ||
v = unpack(">B",buff)[0] | ||
|
||
|
||
#cache writeable values since they are the ones that will not change in useage | ||
if self.reg in self.writeable: | ||
self.cache[self.reg] = v | ||
|
||
return v | ||
|
||
def __get__(self,obj,objtype): | ||
"Get the register then extract the bit field" | ||
v = self.get_register(obj) | ||
if self.reg == 11: | ||
print(self.reg,self.shift,self.mask) | ||
v >>= self.shift | ||
v &= self.mask | ||
return v | ||
|
||
def __set__(self,obj,value): | ||
"Insert a new value into the bit field of the old value then write it back" | ||
if not self.reg in self.writeable: | ||
raise AttributeError('Register is not writable') | ||
oldvalue = self.get_register(obj) | ||
#oldvalue <<= self.shift # get_register() does a shift, so we have to shift it back | ||
insertmask = 0xffff - (self.mask << self.shift) #make a mask for a hole | ||
oldvalue &= insertmask # AND a hole in the old value | ||
value &= self.mask # mask our new value in case it is too big | ||
value <<= self.shift | ||
oldvalue |= value # OR the new value back into the hole | ||
if self.buffsize == 2: | ||
buff = pack(">H",oldvalue) | ||
else: | ||
buff = pack(">B",oldvalue) | ||
|
||
obj.i2c.writeto_mem(obj.device,self.reg,buff) # write result back to the AS5600 | ||
|
||
|
||
|
||
class AS5600: | ||
def __init__(self,i2c,device): | ||
self.i2c = i2c | ||
self.device = device | ||
self.writeable =(r.ZMCO,r.ZPOS,r.MPOS,r.MANG,r.CONF,r.BURN) | ||
|
||
#Use descriptors to read and write a bit field from a register | ||
#1. we read one or two bytes from i2c | ||
#2. We shift the value so that the least significant bit is bit zero | ||
#3. We mask off the bits required (most values are 12 bits hence m12) | ||
ZMCO= RegDescriptor(r.ZMCO,shift=0,mask=3,buffsize=1) #1 bit | ||
ZPOS= RegDescriptor(r.ZPOS,0,m12) | ||
MPOS= RegDescriptor(r.MPOS,0,m12) | ||
MANG= RegDescriptor(r.MANG,0,m12) | ||
CONF= RegDescriptor(r.CONF,0,(1<<14)-1) # this register has 14 bits | ||
RAWANGLE= RegDescriptor(r.RAWANGLE,0,m12) | ||
ANGLE = RegDescriptor(r.ANGLE,0,m12) | ||
STATUS= RegDescriptor(r.STATUS,0,m12) | ||
AGC= RegDescriptor(r.AGC,0,0xF,1) | ||
MAGNITUDE= RegDescriptor(r.MAGNITUDE,0,m12) | ||
BURN= RegDescriptor(r.BURN,0,0xF,1) | ||
|
||
#Configuration bit fields | ||
PM = RegDescriptor(r.CONF,0,0x3) #2bits | ||
HYST = RegDescriptor(r.CONF,2,0x3) | ||
OUTS = RegDescriptor(r.CONF,4,0x3) | ||
PWMF = RegDescriptor(r.CONF,6,0x3) | ||
SF = RegDescriptor(r.CONF,8,0x3) | ||
FTH = RegDescriptor(r.CONF,10,0x7) #3 bits | ||
WD = RegDescriptor(r.CONF,13,0x1) #1 bit | ||
|
||
#status bit fields | ||
MH = RegDescriptor(r.STATUS,3,0x1) #2bits Magnet too strong (high) | ||
ML = RegDescriptor(r.STATUS,4,0x1) #2bits Magnet too weak (low) | ||
MD = RegDescriptor(r.STATUS,5,0x1) #2bits Magnet just right | ||
|
||
def scan(self): | ||
"Debug utility function to check your i2c bus" | ||
devices = self.i2c.scan() | ||
print(devices) | ||
if AS5600_id in devices: | ||
print('Found AS5600 (id =',hex(AS5600_id),')') | ||
print(self.CONF) | ||
|
||
def burn_angle(self): | ||
"Burn ZPOS and MPOS -(can only do this 3 times)" | ||
self.BURN = 0x80 | ||
|
||
def burn_setting(self): | ||
"Burn config and mang- (can only do this once)" | ||
self.BURN = 0x40 | ||
|
||
def magnet_status(self): | ||
s = "Magnet " | ||
# print(self.MD) | ||
return | ||
if self.MD == 1: | ||
s += " detected" | ||
else: | ||
s += " not detected" | ||
|
||
|
||
if self.ML == 1: | ||
s+ " (magnet too weak)" | ||
|
||
if self.MH == 1: | ||
s+ " (magnet too strong)" | ||
return s | ||
|
||
|
||
i2c = I2C(0,scl=Pin(17),sda=Pin(16),freq=400000) | ||
|
||
|
||
z = AS5600(i2c,AS5600_id) | ||
z.scan() | ||
whatever = 89 | ||
while True: | ||
print(z.MD) | ||
sleep(1) | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
from time import sleep | ||
from as5600 import * | ||
|
||
|
||
|
||
#The class AS5600 is pretty low level. | ||
# This inherits adds some higher level functions | ||
|
||
class AS5600_high(AS5600): | ||
|
||
def __init__(self,i2c,device): | ||
super().__init__( i2c,device) | ||
|
||
def scan(self): | ||
"Debug utility function to check your i2c bus" | ||
devices = self.i2c.scan() | ||
print(devices) | ||
if AS5600_id in devices: | ||
print('Found AS5600 (id =',hex(AS5600_id),')') | ||
print(self.CONF) | ||
|
||
def burn_angle(self): | ||
"Burn ZPOS and MPOS -(can only do this 3 times)" | ||
#uncomment if you need it | ||
#self.BURN = 0x80 | ||
|
||
def burn_setting(self): | ||
"Burn config and mang- (can only do this once)" | ||
#uncomment if you need it | ||
#self.BURN = 0x40 | ||
|
||
def magnet_status(self): | ||
"Magnet status - this does not seem to make sense ? why" | ||
s = "Magnet " | ||
|
||
if self.MD == 1: | ||
s += " detected" | ||
else: | ||
s += " not detected" | ||
|
||
if self.ML == 1: | ||
s+ " (magnet too weak)" | ||
|
||
if self.MH == 1: | ||
s+ " (magnet too strong)" | ||
return s | ||
|
||
|
||
i2c = I2C(0,scl=Pin(17),sda=Pin(16),freq=400000) | ||
|
||
|
||
z = AS5600_high(i2c,AS5600_id) | ||
z.scan() | ||
|
||
#read write | ||
#This will probably make your device crazy. Just poweron/poweroff | ||
z.CONF = 0x38 | ||
sleep(2) | ||
print ("should be 0x38", hex(z.CONF)) | ||
sleep(5) | ||
z.CONF = 0x64 | ||
print ("should be 0x64", hex(z.CONF) ) | ||
|
||
|
||
for i in range(10): | ||
#print(z.magnet_status()) | ||
print ('ZANGLE',z.RAWANGLE) | ||
print ('ANGLE', z.ANGLE) | ||
print ('Magnet detected',z.MD) | ||
sleep(1) |