343 lines
10 KiB
C++
343 lines
10 KiB
C++
/***************************************************
|
|
Arduino library for the Allegro A1335 Magnetic angle sensor
|
|
The A1335 sensor detects the absolute angular position of a
|
|
permanent magnet, typically a diametrically
|
|
magnetized cylinder on the rotating shaft.
|
|
|
|
* by Florian von Bertrab
|
|
****************************************************/
|
|
|
|
#include "A1335.h"
|
|
|
|
|
|
bytes_2::bytes_2(){
|
|
data.integer = 0;
|
|
}
|
|
|
|
bytes_2::bytes_2(int16_t integ){
|
|
data.integer = integ;
|
|
}
|
|
|
|
int16_t& bytes_2::in(){
|
|
return data.integer;
|
|
}
|
|
|
|
byte& bytes_2::lsBy(byte n){
|
|
if (n > 1) {
|
|
n = 1;
|
|
} else if (n < 0) {
|
|
n = 0;
|
|
}
|
|
return data.bytes[n];
|
|
}
|
|
|
|
byte& bytes_2::msBy(byte n){
|
|
if (n > 1) {
|
|
n = 1;
|
|
} else if (n < 0) {
|
|
n = 0;
|
|
}
|
|
return data.bytes[1-n];
|
|
}
|
|
|
|
bytes_4::bytes_4(){
|
|
data.integer = 0;
|
|
}
|
|
|
|
bytes_4::bytes_4(int32_t integ){
|
|
data.integer = integ;
|
|
}
|
|
|
|
int32_t& bytes_4::in(){
|
|
return data.integer;
|
|
}
|
|
|
|
byte& bytes_4::lsBy(byte n){
|
|
if (n > 3) {
|
|
n = 3;
|
|
} else if (n < 0) {
|
|
n = 0;
|
|
}
|
|
return data.bytes[n];
|
|
}
|
|
|
|
byte& bytes_4::msBy(byte n){
|
|
if (n > 3) {
|
|
n = 3;
|
|
} else if (n < 0) {
|
|
n = 0;
|
|
}
|
|
return data.bytes[3-n];
|
|
}
|
|
|
|
//--- Normal Write Registers ---//
|
|
|
|
const byte EWA = 0x02; // Extended Write Address
|
|
const byte EWD = 0x04; // Extended Write Data
|
|
const byte EWCS = 0x08; // Extended Write Control and Status
|
|
const byte ERA = 0x0A; // Extended Read Address
|
|
const byte ERCS = 0x0C; // Extended Read Control and Status
|
|
const byte ERD = 0x0E; // Extended Read Data
|
|
const byte CTRL = 0x1E; // Device control
|
|
const byte ANG = 0x20; // Current angle and related data
|
|
const byte STA = 0x22; // Device status
|
|
const byte ERR = 0x24; // Device error status
|
|
const byte XERR = 0x26; // Extended error status
|
|
const byte TSEN = 0x28; // Temperature sensor data
|
|
const byte FIELD = 0x2A; // Magnetic field strength
|
|
const byte ERM = 0x34; // Device error status masking
|
|
const byte XERM = 0x36; // Extended error status masking
|
|
|
|
//--- Extended Write Registers ---//
|
|
|
|
const int16_t ORATE = 0xFFD0; // Output Rate
|
|
|
|
|
|
// Control bytes and their respective keycodes:
|
|
|
|
// CTRL(0x1E) KEY(0x1F)
|
|
// Processor State
|
|
const byte ipm[] = { B10000000, 0x46 }; // Idle mode
|
|
const byte rpm[] = { B11000000, 0x46 }; // Run mode
|
|
// Hard Reset
|
|
const byte hre[] = { B00100000, 0xB9 }; // Hard reset
|
|
// Soft Reset
|
|
const byte sre[] = { B00010000, 0xB9 }; // Soft reset
|
|
// Clear STA
|
|
const byte csta[] = { B00000100, 0x46 }; // Clear (STA) registers
|
|
// Hard Reset
|
|
const byte cxerr[] = { B00000010, 0x46 }; // Clear (XERR) registers
|
|
// Hard Reset
|
|
const byte cerr[] = { B00000001, 0x46 }; // Clear (ERR) registers
|
|
|
|
|
|
// Angle Register read masks
|
|
|
|
// ANG(0x20) ANG+1(0x21)
|
|
// Register Identifier Code
|
|
const byte ria[] = { B10000000, B00000000}; // Always 0
|
|
// Error Flag
|
|
const byte efa[] = { B01000000, B00000000}; // At least one error in register 0x24
|
|
// New Flag
|
|
const byte nfa[] = { B00100000, B00000000}; // A new angle is in the angle register
|
|
// Parity
|
|
const byte par[] = { B00010000, B00000000}; // Odd parity bit for the whole register
|
|
// Angle
|
|
const byte ang[] = { B00001111, B11111111}; // Encoded angle reading (n * 360/4096 = angle in deg.)
|
|
|
|
|
|
// Status Register read masks
|
|
|
|
// STA(0x20) STA+1(0x21)
|
|
// Register Identifier Code
|
|
const byte ris[] = { B11110000, B00000000}; // Always 1000
|
|
// Power-On Reset Flag
|
|
const byte por[] = { B00001000, B00000000}; // There was a power-on reset since last field reset
|
|
// Soft Reset Flag
|
|
const byte srf[] = { B00000100, B00000000}; // There was a soft reset since last field reset
|
|
// New Flag
|
|
const byte nfs[] = { B00000010, B00000000}; // A new angle is in the angle register
|
|
// Current Error Flag
|
|
const byte efs[] = { B00000001, B00000000}; // At least one error in register 0x24
|
|
// Processor Processing Status
|
|
const byte mps[] = { B00000000, B11110000}; // 0000 Booting; 0001 Idle or Processing angles; 1110 Self-testmode
|
|
// Processor Phase Status
|
|
const byte phase[] = { B00000000, B00001111}; // 0000 Idle; 0001 Processing angles; Only in Self-test mode [0100 Built in self test; 0110 ROM checksum; 0111 CVH self test]
|
|
|
|
|
|
// Temperature Register read masks
|
|
|
|
// TSEN(0x28) TSEN+1(0x29)
|
|
// Register Identifier Code
|
|
const byte rit[] = { B11110000, B00000000}; // Always 1111
|
|
// Temperature
|
|
const byte temp[] = { B00001111, B11111111}; // Encoded temperature reading (n / 8 = temperature in K)
|
|
|
|
|
|
// Field Strenght Register read masks
|
|
|
|
// FIELD(0x28) FIELD+1(0x29)
|
|
// Register Identifier Code
|
|
const byte rif[] = { B11110000, B00000000}; // Always 1110
|
|
// Magnetic field strenght
|
|
const byte field[] = { B00001111, B11111111}; // Magnetic field strenght reading (n = field strenght in Gauss (1/10000 T))
|
|
|
|
|
|
A1335::A1335(){
|
|
|
|
}
|
|
|
|
int16_t A1335::getAddress(){ // returns I2C address of the sensor
|
|
return address;
|
|
}
|
|
|
|
byte A1335::getProcessorState(){ // returns current processor state of the sensor
|
|
return processorState;
|
|
}
|
|
|
|
byte A1335::getOutputRate(){ // returns the current sample rate of the sensor
|
|
return outputRate;
|
|
}
|
|
|
|
byte A1335::start(int16_t address_){ // Initializes the sensor at the address given and fills the private variables
|
|
Wire.beginTransmission(address);
|
|
byte error = Wire.endTransmission();
|
|
if (error) {
|
|
processorState = 4;
|
|
return error;
|
|
}
|
|
address = address_;
|
|
bytes_2 state(normalRead(STA));
|
|
bytes_4 orate(extendedRead(ORATE));
|
|
|
|
byte processing_status = (state.msBy(1) & mps[1]) >> 4;
|
|
byte processing_phase = (state.msBy(1) & phase[1]) >> 0;
|
|
switch (processing_status) {
|
|
case B00000000:
|
|
processorState = 0;
|
|
break;
|
|
case B00000001:
|
|
if (processing_phase == 0){
|
|
processorState = 1;
|
|
} else {
|
|
processorState = 2;
|
|
}
|
|
break;
|
|
case B00001110:
|
|
processorState = 3;
|
|
break;
|
|
}
|
|
outputRate = orate.msBy(3);
|
|
delay(1);
|
|
return error;
|
|
}
|
|
|
|
double A1335::readAngle(){ // returns Angle in Degrees
|
|
return double(readAngleRaw()) * 360.0 / 4096.0;
|
|
}
|
|
uint16_t A1335::readAngleRaw(){ // returns raw angle data
|
|
bytes_2 angReg(normalRead(ANG));
|
|
|
|
int16_t parityCheck = angReg.in();
|
|
parityCheck ^= parityCheck >> 8;
|
|
parityCheck ^= parityCheck >> 4;
|
|
parityCheck ^= parityCheck >> 2;
|
|
parityCheck ^= parityCheck >> 1;
|
|
parityCheck &= 1; // parity Check now contains the parity of all bits in angReg
|
|
if(!parityCheck) { // odd Parity in this register => a 0 means an error
|
|
return 0;
|
|
}
|
|
|
|
angReg.msBy(0) &= ang[0]; // mutes bits, that dont contain the angle data
|
|
return angReg.in();
|
|
}
|
|
|
|
double A1335::readTemp(){ // returns temperature in Kelvin
|
|
return double(readTempRaw())/8.0;
|
|
}
|
|
|
|
uint16_t A1335::readTempRaw(){ // returns raw temperature data
|
|
bytes_2 tempReg(normalRead(TSEN));
|
|
tempReg.msBy(0) &= temp[0]; // mutes bits, that dont contain temperature data
|
|
return tempReg.in();
|
|
}
|
|
|
|
double A1335::readField(){ // returns field strenght in Tesla
|
|
return double(readFieldRaw())/10000.0;
|
|
}
|
|
|
|
uint16_t A1335::readFieldRaw(){ // returns raw field strenght data
|
|
bytes_2 fieldReg(normalRead(FIELD));
|
|
fieldReg.msBy(0) &= field[0]; // mutes bits, that dont contain temperature data
|
|
return fieldReg.in();
|
|
}
|
|
|
|
byte A1335::readOutputRate(){ // reads the log2() of the sample rate
|
|
bytes_4 oRate(extendedRead(ORATE));
|
|
return oRate.msBy(3); // !!! I don't know yet, which byte holds the output rate !!!
|
|
}
|
|
|
|
byte A1335::setOutputRate(byte rate){ // sets the log2() of the sample rate => (ORate = 2^rate)
|
|
if (rate < 0) {
|
|
rate = 0;
|
|
} else if (rate >=8) {
|
|
rate = 7;
|
|
}
|
|
bytes_2 idle_mode;
|
|
bytes_2 run_mode;
|
|
for (int i = 0; i < 2; i++){
|
|
idle_mode.msBy(i) = ipm[i];
|
|
run_mode.msBy(i) = rpm[i];
|
|
}
|
|
normalWrite(CTRL, idle_mode.in());
|
|
delayMicroseconds(150);
|
|
bytes_4 oRate;
|
|
oRate.msBy(3) = rate;
|
|
extendedWrite(ORATE, oRate.in()); // !!! I don't know yet, which byte gets the output rate !!!
|
|
delayMicroseconds(50);
|
|
normalWrite(CTRL, run_mode.in());
|
|
delayMicroseconds(150);
|
|
}
|
|
|
|
byte A1335::normalWrite(byte reg, int16_t data){ // writes the 2 bytes in "bytes" to the register with address reg to the sensor with I2C address adress.
|
|
bytes_2 data_bytes(data);
|
|
Wire.beginTransmission(address);
|
|
Wire.write(reg); // choose target register
|
|
for (int i = 0; i<2; i++){
|
|
Wire.write(data_bytes.msBy(i)); // Writes data MSB first
|
|
}
|
|
return Wire.endTransmission();
|
|
}
|
|
|
|
byte A1335::extendedWrite(int16_t reg, int32_t data){ // writes the 4 bytes in "bytes" to the extended register with address reg to the sensor with I2C address adress.
|
|
bytes_4 data_bytes(data);
|
|
Wire.beginTransmission(address);
|
|
Wire.write(EWA); // choose write Register
|
|
Wire.write(byte(reg >> 8)); // Fill with target address
|
|
Wire.write(byte(reg));
|
|
for (int i = 0; i<4; i++){
|
|
Wire.write(data_bytes.msBy(i)); // Writes data MSB first
|
|
}
|
|
Wire.write(0x80); // Confirm write
|
|
Wire.endTransmission();
|
|
delayMicroseconds(10);
|
|
Wire.requestFrom(address, 1);
|
|
return Wire.read(); // Returns 1 if it works
|
|
}
|
|
|
|
int16_t A1335::normalRead(byte reg){
|
|
bytes_2 data;
|
|
Wire.beginTransmission(address);
|
|
Wire.write(reg); // choose target Register
|
|
Wire.endTransmission();
|
|
Wire.requestFrom(address, 2);
|
|
for(int i=0; i< 2; i++){
|
|
if (Wire.available()){
|
|
data.msBy(i) = Wire.read(); // read data bytes
|
|
}
|
|
}
|
|
return data.in();
|
|
}
|
|
|
|
int32_t A1335::extendedRead(int16_t reg){
|
|
bytes_4 data;
|
|
byte rstate;
|
|
Wire.beginTransmission(address);
|
|
Wire.write(ERA); // choose write Register
|
|
Wire.write(byte(reg >> 8)); // Fill with target address
|
|
Wire.write(byte(reg));
|
|
Wire.write(0x80); // Confirm read
|
|
Wire.endTransmission();
|
|
delayMicroseconds(10);
|
|
Wire.requestFrom(address,5);
|
|
rstate = Wire.read(); // Reads status byte
|
|
for(int i=0; i < 4; i++){
|
|
if (Wire.available()){
|
|
data.msBy(i) = Wire.read(); // Reads data bytes
|
|
}
|
|
}
|
|
return data.in();
|
|
}
|
|
|
|
|