diff --git a/.github/workflows/compile-examples.yml b/.github/workflows/compile-examples.yml index 06d5ccb..31510b7 100644 --- a/.github/workflows/compile-examples.yml +++ b/.github/workflows/compile-examples.yml @@ -80,6 +80,10 @@ jobs: platforms: | - name: rp2040:rp2040 source-url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + - fqbn: rp2040:rp2040:rpipico2 + platforms: | + - name: rp2040:rp2040 + source-url: https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json steps: - name: Checkout diff --git a/README.md b/README.md index e422626..2648649 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,13 @@ For more information on the MagAlpha sensor family: * [MagAlpha Support Materials](http://www.monolithicpower.com/Design-Support/Position-Sensors-Design-Support) ## Supported sensors -Supports all 3rd generation MagAlpha magnetic angle sensors from [Monolithic Power Systems](https://www.monolithicpower.com/). +Supports all 3rd, 4th, 6th, 7th, 8th generation MagAlpha magnetic angle sensors from [Monolithic Power Systems](https://www.monolithicpower.com/). | Applications | Part Numbers | | ------------| ------------ | | Turning knob applications (potentiometer replacement) | MA800, MA820, MA850 | | Rotary encoders (optical encoder replacement, Servo motors, ...) | MA702, MA704, MA710, MA730 | -| Position controlled motor drivers (FOC, ...) | MA302, MA310 | +| Position controlled motor drivers (FOC, ...) | MA302, MA310, MA600 | | Motor commutation (hall switches replacement) | MA102 | @@ -39,6 +39,7 @@ MIT license, all text above must be included in any redistribution. ### Serial communication All MagAlpha have a SPI communication interface. Some sensors like the MA702 also have an additional SSI (2-wire) interface. +MagAlpha gen8 possess an I2C interface. #### SPI (4-wire interface) | Arduino | MagAlpha | @@ -54,6 +55,12 @@ All MagAlpha have a SPI communication interface. Some sensors like the MA702 als | MISO | SSD | | SCK | SSCK | +### I2C (2-wire interface) +| Arduino | MagAlpha | +| -------- | -------- | +| SCL | SCL | +| SDA | SDA | + #### Arduino SPI pin mapping | Arduino / Genuino Board | MOSI | MISO | SCK | CS | Voltage Level | | ----------------------- | ---- | ---- | ---- | :---: | ------------- | diff --git a/examples/gen3/gen3.ino b/examples/gen3/gen3.ino new file mode 100644 index 0000000..1f5d91f --- /dev/null +++ b/examples/gen3/gen3.ino @@ -0,0 +1,90 @@ +#include + +#include +#include + +#define SPI_CS_PIN (7) +#define SPI_SCLK_FREQUENCY (1000000) + +MagAlphaGen3 magalpha; + +double angle_real; +uint16_t zero, bct, angle_raw; +uint8_t register_value[2]; +bool error; + +void setup() { + + magalpha.begin(SPI_SCLK_FREQUENCY, MagAlphaSPIMode::MODE_0, SPI_CS_PIN, &SPI); + // Other ways of use of begin() that will set default settings to the SPI peripheral + // magalpha.begin(SPI_CS_PIN, &SPI); + + //magalpha.setSpiClockFrequency(SPI_SCLK_FREQUENCY); + //magalpha.setSpiDataMode(MagAlphaSPIMode::MODE0); + //magalpha.setSpiChipSelectPin(SPI_CS_PIN); + Serial.begin(115200); + while(!Serial); +} + +void loop() { + + // Read & Write registers + register_value[0] = magalpha.writeRegister(0, 0xAA); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.readRegister(0); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.writeRegister(0, 0x00); + + // Read & Write registers in burst mode + register_value[0] = 0xAA; + register_value[1] = 0x55; + magalpha.writeRegisterBurst(0, register_value, 2); + magalpha.readRegisterBurst(0, register_value, 2); + for(uint8_t i = 0; i < sizeof(register_value); i++) { + Serial.print("Register "); + Serial.print(i); + Serial.print(" = "); + Serial.println(register_value[i], HEX); + } + register_value[0] = 0x00; + register_value[1] = 0x00; + magalpha.writeRegisterBurst(0, register_value, 2); + + // Set & Get zero setting + zero = magalpha.setCurrentAngleAsZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + magalpha.setZero(0x0000); + zero = magalpha.getZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + + // Set & Get BCT setting + magalpha.setBct(0xAA55); + bct = magalpha.getBct(); + Serial.print("BCT = "); + Serial.println(bct, HEX); + magalpha.setBct(0x00); + + // Read angle + angle_raw = magalpha.readAngleRaw8(); + Serial.print("Angle raw (8 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw16(); + Serial.print("Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw(&error); + if(error) { + Serial.println("An error occured during readAngleRaw"); + } else { + Serial.print("readAngleRaw succeded, Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + } + + angle_real = magalpha.readAngle(); + Serial.print("Angle in degree = "); + Serial.println(angle_real, DEC); + + // This delay has been added only for visual purpose of the terminal + delay(25); +} \ No newline at end of file diff --git a/examples/gen4/gen4.ino b/examples/gen4/gen4.ino new file mode 100644 index 0000000..443a59f --- /dev/null +++ b/examples/gen4/gen4.ino @@ -0,0 +1,108 @@ +#include + +#include +#include + +#define SPI_CS_PIN (7) +#define SPI_SCLK_FREQUENCY (1000000) + +MagAlphaGen4 magalpha; + +double angle_real; +uint16_t zero, bct, angle_raw; +uint8_t register_value[2]; +bool error; + +void setup() { + + magalpha.begin(SPI_SCLK_FREQUENCY, MagAlphaSPIMode::MODE_0, SPI_CS_PIN, &SPI); + // Other ways of use of begin() that will set default settings to the SPI peripheral + // magalpha.begin(SPI_CS_PIN, &SPI); + + //magalpha.setSpiClockFrequency(SPI_SCLK_FREQUENCY); + //magalpha.setSpiDataMode(MagAlphaSPIMode::MODE0); + //magalpha.setSpiChipSelectPin(SPI_CS_PIN); + Serial.begin(115200); + while(!Serial); +} + +void loop() { + + // Read & Write registers + register_value[0] = magalpha.writeRegister(0, 0xAA); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.readRegister(0); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.writeRegister(0, 0x00); + + // Read & Write registers in burst mode + register_value[0] = 0xAA; + register_value[1] = 0x55; + magalpha.writeRegisterBurst(0, register_value, 2); + magalpha.readRegisterBurst(0, register_value, 2); + for(uint8_t i = 0; i < sizeof(register_value); i++) { + Serial.print("Register "); + Serial.print(i); + Serial.print(" = "); + Serial.println(register_value[i], HEX); + } + register_value[0] = 0x00; + register_value[1] = 0x00; + magalpha.writeRegisterBurst(0, register_value, 2); + + // Set & Get zero setting + zero = magalpha.setCurrentAngleAsZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + magalpha.setZero(0x0000); + zero = magalpha.getZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + + // Set & Get BCT setting + magalpha.setBct(0xAA55); + bct = magalpha.getBct(); + Serial.print("BCT = "); + Serial.println(bct, HEX); + magalpha.setBct(0x00); + + // Memory management + magalpha.writeRegister(0, 0xAA); + magalpha.storeRegister(0); + magalpha.writeRegister(0, 0x00); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0xAA) { + Serial.println("An error occured during restoreAllRegisters"); + } + magalpha.writeRegister(0, 0x00); + magalpha.storeAllRegisters(); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0x00) { + Serial.println("An error occured during storeAllRegisters"); + } + + // Clear error flags + magalpha.clearErrorFlags(); + + // Read angle + angle_raw = magalpha.readAngleRaw8(); + Serial.print("Angle raw (8 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw16(); + Serial.print("Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw(&error); + if(error) { + Serial.println("An error occured during readAngleRaw"); + } else { + Serial.print("readAngleRaw succeded, Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + } + + angle_real = magalpha.readAngle(); + Serial.print("Angle in degree = "); + Serial.println(angle_real, DEC); + + // This delay has been added only for visual purpose of the terminal + delay(25); +} diff --git a/examples/gen6/gen6.ino b/examples/gen6/gen6.ino new file mode 100644 index 0000000..13357d6 --- /dev/null +++ b/examples/gen6/gen6.ino @@ -0,0 +1,113 @@ +#include + +#include +#include + +#define SPI_CS_PIN (7) +#define SPI_SCLK_FREQUENCY (1000000) + +MagAlphaGen6 magalpha; + +double angle_real, speed; +uint16_t zero, bct, angle_raw, turn; +uint8_t register_value[2]; +bool error; + +void setup() { + + magalpha.begin(SPI_SCLK_FREQUENCY, MagAlphaSPIMode::MODE_0, SPI_CS_PIN, &SPI); + // Other ways of use of begin() that will set default settings to the SPI peripheral + // magalpha.begin(SPI_CS_PIN, &SPI); + + //magalpha.setSpiClockFrequency(SPI_SCLK_FREQUENCY); + //magalpha.setSpiDataMode(MagAlphaSPIMode::MODE0); + //magalpha.setSpiChipSelectPin(SPI_CS_PIN); + Serial.begin(115200); + while(!Serial); +} + +void loop() { + + // Read & Write registers + register_value[0] = magalpha.writeRegister(0, 0xAA); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.readRegister(0); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.writeRegister(0, 0x00); + + // Read & Write registers in burst mode + register_value[0] = 0xAA; + register_value[1] = 0x55; + magalpha.writeRegisterBurst(0, register_value, 2); + magalpha.readRegisterBurst(0, register_value, 2); + for(uint8_t i = 0; i < sizeof(register_value); i++) { + Serial.print("Register "); + Serial.print(i); + Serial.print(" = "); + Serial.println(register_value[i], HEX); + } + register_value[0] = 0x00; + register_value[1] = 0x00; + magalpha.writeRegisterBurst(0, register_value, 2); + + // Set & Get zero setting + zero = magalpha.setCurrentAngleAsZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + magalpha.setZero(0x0000); + zero = magalpha.getZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + + // Set & Get BCT setting + magalpha.setBct(0xAA55); + bct = magalpha.getBct(); + Serial.print("BCT = "); + Serial.println(bct, HEX); + magalpha.setBct(0x00); + + // Memory management + magalpha.writeRegister(0, 0xAA); + magalpha.storeRegisterBlock(0); + magalpha.writeRegister(0, 0x00); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0xAA) { + Serial.println("An error occured during restoreAllRegisters"); + } + magalpha.writeRegister(0, 0x00); + magalpha.storeAllRegisters(); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0x00) { + Serial.println("An error occured during storeAllRegisters"); + } + + // Clear error flags + magalpha.clearErrorFlags(); + + speed = magalpha.readSpeed(); + Serial.println(speed); + turn = magalpha.readTurn(); + Serial.println(turn); + + // Read angle + angle_raw = magalpha.readAngleRaw8(); + Serial.print("Angle raw (8 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw16(); + Serial.print("Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw(&error); + if(error) { + Serial.println("An error occured during readAngleRaw"); + } else { + Serial.print("readAngleRaw succeded, Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + } + + angle_real = magalpha.readAngle(); + Serial.print("Angle in degree = "); + Serial.println(angle_real, DEC); + + // This delay has been added only for visual purpose of the terminal + delay(25); +} diff --git a/examples/gen7/gen7.ino b/examples/gen7/gen7.ino new file mode 100644 index 0000000..5192d88 --- /dev/null +++ b/examples/gen7/gen7.ino @@ -0,0 +1,121 @@ +#include + +#include +#include + +#define SPI_CS_PIN (7) +#define SPI_SCLK_FREQUENCY (1000000) + +MagAlphaGen7 magalpha; + +double angle_real, speed; +uint16_t zero, angle_raw, turn; +uint8_t register_value[2]; +bool error; + +void setup() { + + magalpha.begin(SPI_SCLK_FREQUENCY, MagAlphaSPIMode::MODE_0, SPI_CS_PIN, &SPI); + // Other ways of use of begin() that will set default settings to the SPI peripheral + // magalpha.begin(SPI_CS_PIN, &SPI); + + //magalpha.setSpiClockFrequency(SPI_SCLK_FREQUENCY); + //magalpha.setSpiDataMode(MagAlphaSPIMode::MODE0); + //magalpha.setSpiChipSelectPin(SPI_CS_PIN); + Serial.begin(115200); + while(!Serial); +} + +void loop() { + + // Read & Write registers + register_value[0] = magalpha.writeRegister(0, 0xAA); + Serial.print("Register 0 = "); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.readRegister(0); + register_value[0] = magalpha.writeRegister(0, 0x00); + + /* + uint16_t readAngleRaw16(bool *error, bool *inversion, bool isShortRead=false); + uint16_t readAngleCounter(uint16_t *angle, bool *error, bool *inversion); + uint16_t readAngleSpeed(uint16_t *angle, bool *error, bool *inversion); + uint16_t readAngleMultiturn(uint16_t *angle, bool *error, bool *inversion); + uint16_t readAngleTemperature(uint16_t *angle, bool *error, bool *inversion); + uint8_t readRegister(uint8_t address, bool *error, bool *inversion); + uint16_t readRegisterBurst(uint8_t address, uint8_t readbackValueArray[], uint16_t numberOfRegister, bool *error, bool *inversion); + uint8_t writeRegister(uint8_t address, uint8_t value, bool *error, bool *inversion, bool *wrongHandshaking); + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister, bool *error, bool *inversion, bool *wrongHandshaking); + void setCrcCheckSetting(bool enable); + uint16_t appendCrc4(uint16_t data); + void checkCrc4(uint16_t readData, uint16_t *computedCrc, bool *errorDetected, bool *inversionDetected); + */ + + // Read & Write registers in burst mode + register_value[0] = 0x55; + register_value[1] = 0xAA; + magalpha.writeRegisterBurst(0, register_value, 2); + magalpha.readRegisterBurst(0, register_value, 2); + for(uint8_t i = 0; i < sizeof(register_value); i++) { + Serial.print("Register "); + Serial.print(i); + Serial.print(" = "); + Serial.println(register_value[i], HEX); + } + register_value[0] = 0x00; + register_value[1] = 0x00; + magalpha.writeRegisterBurst(0, register_value, 2); + + // Set & Get zero setting + zero = magalpha.setCurrentAngleAsZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + magalpha.setZero(0x0000); + zero = magalpha.getZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + + // Memory management + magalpha.writeRegister(0, 0xAA); + magalpha.storeRegisterBlock(1); + magalpha.writeRegister(0, 0x00); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0xAA) { + Serial.println("An error occured during restoreAllRegisters"); + } + magalpha.writeRegister(0, 0x00); + magalpha.storeAllRegisters(); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0x00) { + Serial.println("An error occured during storeAllRegisters"); + } + + // Clear error flags + magalpha.clearErrorFlags(); + + speed = magalpha.readSpeed(); + Serial.println(speed); + turn = magalpha.readTurn(); + Serial.println(turn); + + // Read angle + angle_raw = magalpha.readAngleRaw8(); + Serial.print("Angle raw (8 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw16(); + Serial.print("Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw(&error); + if(error) { + Serial.println("An error occured during readAngleRaw"); + } else { + Serial.print("readAngleRaw succeded, Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + } + + angle_real = magalpha.readAngle(); + Serial.print("Angle in degree = "); + Serial.println(angle_real, DEC); + + // This delay has been added only for visual purpose of the terminal + delay(1000); +} diff --git a/examples/gen8/gen8.ino b/examples/gen8/gen8.ino new file mode 100644 index 0000000..d799ff9 --- /dev/null +++ b/examples/gen8/gen8.ino @@ -0,0 +1,106 @@ +#include + +#include +#include + +#define SPI_CS_PIN (7) +#define SPI_SCLK_FREQUENCY (1000000) + +MagAlphaGen6 magalpha; + +double angle_real, speed; +uint16_t zero, angle_raw, turn; +uint8_t register_value[2]; +bool error; + +void setup() { + + magalpha.begin(SPI_SCLK_FREQUENCY, MagAlphaSPIMode::MODE_0, SPI_CS_PIN, &SPI); + // Other ways of use of begin() that will set default settings to the SPI peripheral + // magalpha.begin(SPI_CS_PIN, &SPI); + + //magalpha.setSpiClockFrequency(SPI_SCLK_FREQUENCY); + //magalpha.setSpiDataMode(MagAlphaSPIMode::MODE0); + //magalpha.setSpiChipSelectPin(SPI_CS_PIN); + Serial.begin(115200); + while(!Serial); +} + +void loop() { + + // Read & Write registers + register_value[0] = magalpha.writeRegister(0, 0xAA); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.readRegister(0); + Serial.println(register_value[0], HEX); + register_value[0] = magalpha.writeRegister(0, 0x00); + + // Read & Write registers in burst mode + register_value[0] = 0xAA; + register_value[1] = 0x55; + magalpha.writeRegisterBurst(0, register_value, 2); + magalpha.readRegisterBurst(0, register_value, 2); + for(uint8_t i = 0; i < sizeof(register_value); i++) { + Serial.print("Register "); + Serial.print(i); + Serial.print(" = "); + Serial.println(register_value[i], HEX); + } + register_value[0] = 0x00; + register_value[1] = 0x00; + magalpha.writeRegisterBurst(0, register_value, 2); + + // Set & Get zero setting + zero = magalpha.setCurrentAngleAsZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + magalpha.setZero(0x0000); + zero = magalpha.getZero(); + Serial.print("Zero setting = "); + Serial.println(zero, HEX); + + // Memory management + magalpha.writeRegister(0, 0xAA); + magalpha.storeRegister(0); + magalpha.writeRegister(0, 0x00); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0xAA) { + Serial.println("An error occured during restoreAllRegisters"); + } + magalpha.writeRegister(0, 0x00); + magalpha.storeAllRegisters(); + magalpha.restoreAllRegisters(); + if(magalpha.readRegister(0) != 0x00) { + Serial.println("An error occured during storeAllRegisters"); + } + + // Clear error flags + magalpha.clearErrorFlags(); + + speed = magalpha.readSpeed(); + Serial.println(speed); + turn = magalpha.readTurn(); + Serial.println(turn); + + // Read angle + angle_raw = magalpha.readAngleRaw8(); + Serial.print("Angle raw (8 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw16(); + Serial.print("Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + angle_raw = magalpha.readAngleRaw(&error); + if(error) { + Serial.println("An error occured during readAngleRaw"); + } else { + Serial.print("readAngleRaw succeded, Angle raw (16 bits) = "); + Serial.println(angle_raw, HEX); + } + + angle_real = magalpha.readAngle(); + Serial.print("Angle in degree = "); + Serial.println(angle_real, DEC); + + // This delay has been added only for visual purpose of the terminal + delay(25); +} diff --git a/examples/edit-magalpha-config/edit-magalpha-config.ino b/examples/legacy/edit-magalpha-config/edit-magalpha-config.ino similarity index 100% rename from examples/edit-magalpha-config/edit-magalpha-config.ino rename to examples/legacy/edit-magalpha-config/edit-magalpha-config.ino diff --git a/examples/read-magalpha-angle-and-error/read-magalpha-angle-and-error.ino b/examples/legacy/read-magalpha-angle-and-error/read-magalpha-angle-and-error.ino similarity index 100% rename from examples/read-magalpha-angle-and-error/read-magalpha-angle-and-error.ino rename to examples/legacy/read-magalpha-angle-and-error/read-magalpha-angle-and-error.ino diff --git a/examples/read-magalpha-angle-with-ssi-and-error/read-magalpha-angle-with-ssi-and-error.ino b/examples/legacy/read-magalpha-angle-with-ssi-and-error/read-magalpha-angle-with-ssi-and-error.ino similarity index 97% rename from examples/read-magalpha-angle-with-ssi-and-error/read-magalpha-angle-with-ssi-and-error.ino rename to examples/legacy/read-magalpha-angle-with-ssi-and-error/read-magalpha-angle-with-ssi-and-error.ino index 5836070..f0d0afd 100644 --- a/examples/read-magalpha-angle-with-ssi-and-error/read-magalpha-angle-with-ssi-and-error.ino +++ b/examples/legacy/read-magalpha-angle-with-ssi-and-error/read-magalpha-angle-with-ssi-and-error.ino @@ -1,4 +1,4 @@ -#include +#include //Check https://www.arduino.cc/en/reference/SPI for SPI signals connections //Connect SSI SSCK to SPI SCLK signal diff --git a/examples/read-magalpha-angle-with-ssi/read-magalpha-angle-with-ssi.ino b/examples/legacy/read-magalpha-angle-with-ssi/read-magalpha-angle-with-ssi.ino similarity index 97% rename from examples/read-magalpha-angle-with-ssi/read-magalpha-angle-with-ssi.ino rename to examples/legacy/read-magalpha-angle-with-ssi/read-magalpha-angle-with-ssi.ino index 0a7064f..4ec646f 100644 --- a/examples/read-magalpha-angle-with-ssi/read-magalpha-angle-with-ssi.ino +++ b/examples/legacy/read-magalpha-angle-with-ssi/read-magalpha-angle-with-ssi.ino @@ -1,4 +1,4 @@ -#include +#include //Check https://www.arduino.cc/en/reference/SPI for SPI signals connections //Connect SSI SSCK to SPI SCLK signal diff --git a/examples/read-magalpha-angle/read-magalpha-angle.ino b/examples/legacy/read-magalpha-angle/read-magalpha-angle.ino similarity index 100% rename from examples/read-magalpha-angle/read-magalpha-angle.ino rename to examples/legacy/read-magalpha-angle/read-magalpha-angle.ino diff --git a/keywords.txt b/keywords.txt index f6772da..0293773 100644 --- a/keywords.txt +++ b/keywords.txt @@ -7,7 +7,14 @@ ####################################### MagAlpha KEYWORD1 +MagAlphaSPI KEYWORD1 MagAlphaSSI KEYWORD1 +MagAlphaI2C KEYWORD1 +MagAlphaGen3 KEYWORD1 +MagAlphaGen4 KEYWORD1 +MagAlphaGen6 KEYWORD1 +MagAlphaGen7 KEYWORD1 +MagAlphaGen8 KEYWORD1 ####################################### # Methods and Functions (KEYWORD2) diff --git a/library.properties b/library.properties index 33a6805..9fa0503 100644 --- a/library.properties +++ b/library.properties @@ -1,10 +1,10 @@ name=MagAlpha Angle Sensor Library -version=1.0.2 +version=2.0.0 author=Mathieu Kaelin, Monolithic Power Systems maintainer=Mathieu Kaelin sentence=Arduino library for the MPS MagAlpha magnetic angle sensor. -paragraph=Supports MagAlpha 3rd generation Sensors. MagAlpha sensor detects the absolute angular position of a permanent magnet, typically a diametrically magnetized cylinder on the rotating shaft. +paragraph=Supports MagAlpha 3, 4, 6, 7, 8 sensor generation. MagAlpha sensor detects the absolute angular position of a permanent magnet, typically a diametrically magnetized cylinder on the rotating shaft. category=Sensors url=https://github.com/monolithicpower/MagAlpha-Arduino-Library architectures=* -includes=SPI.h +includes=SPI.h,MagAlpha.h,MagAlphaGen3.h,MagAlphaGen4.h,MagAlphaGen6.h,MagAlphaGen7.h,MagAlphaGen8.h,MagAlphaPartProperties.h diff --git a/src/MagAlpha.cpp b/src/MagAlpha.cpp index 793eaee..5a0ecb4 100644 --- a/src/MagAlpha.cpp +++ b/src/MagAlpha.cpp @@ -8,242 +8,37 @@ MIT license, all text above must be included in any redistribution ****************************************************/ +#include #include "MagAlpha.h" //MagAlpha Read/Write Register Command -#define READ_REG_COMMAND (0b010 << 13) -#define WRITE_REG_COMMAND (0b100 << 13) +//#define READ_REG_COMMAND (0b010 << 13) +//#define WRITE_REG_COMMAND (0b100 << 13) #define SSI_MODE SPI_MODE1 +/*====================================================================================*/ +/*========================== MagAlphaGen3 Legacy =====================================*/ +/*====================================================================================*/ MagAlpha::MagAlpha(){ } void MagAlpha::begin(uint8_t spiChipSelectPin){ - setSpiChipSelectPin(spiChipSelectPin); - _speedMaximum = 10000000; - _spiMode = MA_SPI_MODE_3; - SPI.begin(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); + MagAlphaSPI::begin(10000000, MagAlphaSPIMode::MODE_3, spiChipSelectPin, &SPI); } void MagAlpha::begin(int32_t spiSclkFrequency, uint8_t spiMode, uint8_t spiChipSelectPin){ - setSpiChipSelectPin(spiChipSelectPin); - _speedMaximum = spiSclkFrequency; - _spiMode = spiMode; - SPI.begin(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); -} - -void MagAlpha::end(){ - SPI.endTransaction(); - SPI.end(); -} - -double MagAlpha::readAngle(){ - uint16_t angle; - double angleInDegree; - angle = readAngleRaw16(); - angleInDegree = (angle*360.0)/65536.0; - return angleInDegree; -} - -uint16_t MagAlpha::readAngleRaw(){ - return readAngleRaw16(); -} - -uint16_t MagAlpha::readAngleRaw16(){ - uint16_t angle; - digitalWrite(_spiChipSelectPin, LOW); - angle = SPI.transfer16(0x0000); //Read 16-bit angle - digitalWrite(_spiChipSelectPin, HIGH); - return angle; -} - -uint8_t MagAlpha::readAngleRaw8(){ - uint8_t angle; - digitalWrite(_spiChipSelectPin, LOW); - angle = SPI.transfer(0x00); //Read 8-bit angle - digitalWrite(_spiChipSelectPin, HIGH); - return angle; -} - -uint16_t MagAlpha::readAngleRaw(bool* error){ - uint16_t angle; - uint8_t parity; - uint8_t highStateCount = 0; - - digitalWrite(_spiChipSelectPin, LOW); - angle = SPI.transfer16(0x0000); - parity = SPI.transfer(0x00); - digitalWrite(_spiChipSelectPin, HIGH); - - parity = ((parity & 0x80) >> 7); - //Count the number of 1 in the angle binary value - for (int i=0;i<16;++i){ - if ((angle & (1 << i)) != 0){ - highStateCount++; - } - } - //check if parity bit is correct - if ((highStateCount % 2) == 0){ - if (parity == 0){ - *error = false; - } - else{ - *error = true; - } - } - else{ - if (parity == 1){ - *error = false; - } - else{ - *error = true; - } - } - return angle; -} - -uint8_t MagAlpha::readRegister(uint8_t address){ - uint8_t readbackRegisterValue; - digitalWrite(_spiChipSelectPin, LOW); - SPI.transfer16(READ_REG_COMMAND | ((address & 0x1F) << 8) | 0x00); - digitalWrite(_spiChipSelectPin, HIGH); - delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns before register readout - digitalWrite(_spiChipSelectPin, LOW); - readbackRegisterValue = ((SPI.transfer16(0x0000) & 0xFF00) >> 8); - digitalWrite(_spiChipSelectPin, HIGH); - delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns after register readout - return readbackRegisterValue; -} - -uint8_t MagAlpha::writeRegister(uint8_t address, uint8_t value){ - uint8_t readbackRegisterValue; - digitalWrite(_spiChipSelectPin, LOW); - SPI.transfer16(WRITE_REG_COMMAND | ((address & 0x1F) << 8) | value); - digitalWrite(_spiChipSelectPin, HIGH); - delay(20); //Wait for 20ms - digitalWrite(_spiChipSelectPin, LOW); - readbackRegisterValue = ((SPI.transfer16(0x0000) & 0xFF00) >> 8); - digitalWrite(_spiChipSelectPin, HIGH); - //readbackRegisterValue should be equal to the written value - return readbackRegisterValue; -} - -void MagAlpha::setSpiClockFrequency(uint32_t speedMaximum){ - _speedMaximum = speedMaximum; - SPI.endTransaction(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); + MagAlphaSPI::begin(spiSclkFrequency, (MagAlphaSPIMode)spiMode, spiChipSelectPin, &SPI); } void MagAlpha::setSpiDataMode(uint8_t spiMode){ - _spiMode = spiMode; - SPI.endTransaction(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); -} - -void MagAlpha::setSpiChipSelectPin(uint8_t spiChipSelectPin){ - _spiChipSelectPin = spiChipSelectPin; - pinMode(_spiChipSelectPin, OUTPUT); - digitalWrite(_spiChipSelectPin, HIGH); -} - -double MagAlpha::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ - double angleInDegree; - angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); - return angleInDegree; -} - -MagAlphaSSI::MagAlphaSSI(){ -} -void MagAlphaSSI::begin(){ - _speedMaximum = 1000000; - SPI.begin(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); + MagAlphaSPI::setSpiDataMode((MagAlphaSPIMode)spiMode); } -void MagAlphaSSI::begin(int32_t ssiSsckFrequency){ - _speedMaximum = ssiSsckFrequency; - SPI.begin(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +uint16_t MagAlpha::readAngleRaw() { + return MagAlphaGen3::readAngleRaw16(); } -void MagAlphaSSI::end(){ - SPI.endTransaction(); - SPI.end(); -} - -double MagAlphaSSI::readAngle(){ - uint16_t angle; - double angleInDegree; - angle = readAngleRaw(); - angleInDegree = (angle*360.0)/65536.0; - return angleInDegree; -} - -uint16_t MagAlphaSSI::readAngleRaw(){ - uint16_t angle; - uint8_t angle0; - uint8_t angle1; - uint8_t angle2; - - angle0 = SPI.transfer(0x00); - angle1 = SPI.transfer(0x00); - angle2 = SPI.transfer(0x00); - - angle = ((angle0 & 0x7F) << 9) | (angle1 << 1) | ((angle2 & 0x80) >> 7); - return angle; -} - -uint16_t MagAlphaSSI::readAngleRaw(bool* error){ - uint16_t angle; - uint8_t parity; - uint8_t highStateCount = 0; - uint8_t angle0; - uint8_t angle1; - uint8_t angle2; - - angle0 = SPI.transfer(0x00); - angle1 = SPI.transfer(0x00); - angle2 = SPI.transfer(0x00); - - angle = ((angle0 & 0x7F) << 9) | (angle1 << 1) | ((angle2 & 0x80) >> 7); - parity = ((angle2 & 0x40) >> 6); - //Count the number of 1 in the angle binary value - for (int i=0;i<16;++i){ - if ((angle & (1 << i)) != 0){ - highStateCount++; - } - } - //check if parity bit is correct - if ((highStateCount % 2) == 0){ - if (parity == 0){ - *error = false; - } - else{ - *error = true; - } - } - else{ - if (parity == 1){ - *error = false; - } - else{ - *error = true; - } - } - return angle; -} - -void MagAlphaSSI::setSsiClockFrequency(uint32_t speedMaximum){ - _speedMaximum = speedMaximum; - SPI.endTransaction(); - SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); -} - -double MagAlphaSSI::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ - double angleInDegree; - angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); - return angleInDegree; -} +uint16_t MagAlpha::readAngleRaw(bool* error) { + return MagAlphaGen3::readAngleRaw(error); +} \ No newline at end of file diff --git a/src/MagAlpha.h b/src/MagAlpha.h index dcc44ce..2ac74c2 100644 --- a/src/MagAlpha.h +++ b/src/MagAlpha.h @@ -17,46 +17,23 @@ #include "WProgram.h" #endif #include - +#include "MagAlphaGen3.h" +#include "MagAlphaPartProperties.h" //SPI Mode: MagAlpha Gen3 support SPI mode 3 and 0 [SPI_MODE3, SPI_MODE0] #define MA_SPI_MODE_0 SPI_MODE0 #define MA_SPI_MODE_3 SPI_MODE3 -class MagAlpha { +/*====================================================================================*/ +/*========================== MagAlphaGen3 Legacy =====================================*/ +/*====================================================================================*/ +class MagAlpha : public MagAlphaGen3 { public: MagAlpha(); - void begin(uint8_t spiChipSelectPin); - void begin(int32_t spiSclkFrequency, uint8_t spiMode, uint8_t spiChipSelectPin); - void end(); - double readAngle(); - uint16_t readAngleRaw(); - uint16_t readAngleRaw(bool* error); - uint16_t readAngleRaw16(); - uint8_t readAngleRaw8(); - uint8_t readRegister(uint8_t address); - uint8_t writeRegister(uint8_t address, uint8_t value); - void setSpiClockFrequency(uint32_t speedMaximum); + void begin(uint8_t spiChipSelectPin); + void begin(int32_t spiSclkFrequency, uint8_t spiMode, uint8_t spiChipSelectPin); void setSpiDataMode(uint8_t spiMode); - void setSpiChipSelectPin(uint8_t spiChipSelectPin); - double convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle); -private: - uint32_t _speedMaximum; - uint8_t _spiMode; - uint8_t _spiChipSelectPin; -}; - -class MagAlphaSSI { -public: - MagAlphaSSI(); - void begin(); - void begin(int32_t ssiSsckFrequency); - void end(); - double readAngle(); uint16_t readAngleRaw(); uint16_t readAngleRaw(bool* error); - void setSsiClockFrequency(uint32_t speedMaximum); - double convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle); -private: - uint32_t _speedMaximum; }; + #endif //MAGALPHA_H diff --git a/src/MagAlphaBase.cpp b/src/MagAlphaBase.cpp new file mode 100644 index 0000000..efaf6a8 --- /dev/null +++ b/src/MagAlphaBase.cpp @@ -0,0 +1,274 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "MagAlphaBase.h" + +MagAlphaBase::MagAlphaBase(){ +} + +double MagAlphaBase::readAngle(){ + return readAngleRaw16()*(360.0/65536.0); +} + +uint16_t MagAlphaBase::readAngleRaw(){ + return readAngleRaw16(); +} + +void MagAlphaBase::getPartNumber(char *partNumber){ + sprintf(partNumber, "Unknown Part Number"); +} + +double MagAlphaBase::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ + double angleInDegree; + angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); + return angleInDegree; +} + +int16_t MagAlphaBase::twosComplement(uint16_t value, uint8_t numberOfBits){ + int16_t signedValue = static_cast(value); + if ((value & (1 << (numberOfBits - 1))) != 0){ + signedValue = value - (1 << numberOfBits); + } + return signedValue; +} + +uint16_t MagAlphaBase::twosComplementInverse(int16_t value, uint8_t numberOfBits){ + uint16_t unsignedValue = static_cast(value); + if (value < 0){ + unsignedValue = value + (1 << numberOfBits); + } + return unsignedValue; +} + +/*====================================================================================*/ +/*============================== MagAlphaSPI =========================================*/ +/*====================================================================================*/ +MagAlphaSPI::MagAlphaSPI(){ +} + +void MagAlphaSPI::begin(int spiChipSelectPin, SPIClass *spi){ + begin(10000000, (MagAlphaSPIMode)SPI_MODE3, spiChipSelectPin, spi); +} + +void MagAlphaSPI::begin(int32_t spiSclkFrequency, MagAlphaSPIMode spiMode, uint8_t spiChipSelectPin, SPIClass *spi){ + _spi = spi; + _clockFrequency = spiSclkFrequency; + _spiMode = (uint8_t)spiMode; + setSpiChipSelectPin(spiChipSelectPin); + _spi->begin(); + _spi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, _spiMode)); +} + +void MagAlphaSPI::end(){ + _spi->endTransaction(); + _spi->end(); +} + +void MagAlphaSPI::setSpiClockFrequency(uint32_t clockFrequency){ + _clockFrequency = clockFrequency; + _spi->endTransaction(); + _spi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, _spiMode)); +} + +void MagAlphaSPI::setSpiDataMode(MagAlphaSPIMode spiMode){ + _spiMode = (uint8_t)spiMode; + _spi->endTransaction(); + _spi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, _spiMode)); +} + +void MagAlphaSPI::setSpiChipSelectPin(uint8_t spiChipSelectPin){ + _spiChipSelectPin = spiChipSelectPin; + pinMode(_spiChipSelectPin, OUTPUT); + digitalWrite(_spiChipSelectPin, HIGH); +} + +uint16_t MagAlphaSPI::readAngleRaw16Quick(){ + uint16_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); //Read 16-bit angle + //spi0_hw->dr = 0x0000; + //angle = spi0_hw->dr; + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +/*====================================================================================*/ +/*============================== MagAlphaSSI =========================================*/ +/*====================================================================================*/ +MagAlphaSSI::MagAlphaSSI(){ +} + +void MagAlphaSSI::begin(){ + _ssi = &SPI; + _clockFrequency = 1000000; + _ssi->begin(); + _ssi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, MagAlphaSSIMode::MODE_B)); +} + +/* +void MagAlphaSSI::begin(int32_t ssiSsckFrequency){ + _ssi = &SPI; + _clockFrequency = ssiSsckFrequency; + _ssi->begin(); + _ssi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, MagAlphaSSIMode::MODE_B)); +} +*/ + +void MagAlphaSSI::begin(SPIClass *ssi){ + begin(1000000, MagAlphaSSIMode::MODE_A, ssi); +} + +void MagAlphaSSI::begin(int32_t ssiSsckFrequency, SPIClass *ssi){ + begin(ssiSsckFrequency, MagAlphaSSIMode::MODE_A, ssi); +} + +void MagAlphaSSI::begin(int32_t ssiSsckFrequency, MagAlphaSSIMode ssiMode, SPIClass *ssi){ + _ssi = ssi; + _clockFrequency = ssiSsckFrequency; + _ssiMode = (uint8_t)ssiMode; + _ssi->begin(); + _ssi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, _ssiMode)); +} + +void MagAlphaSSI::end(){ + _ssi->endTransaction(); + _ssi->end(); +} + +void MagAlphaSSI::setSsiClockFrequency(uint32_t clockFrequency){ + _clockFrequency = clockFrequency; + _ssi->endTransaction(); + _ssi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, _ssiMode)); +} + +void MagAlphaSSI::setSSiMode(MagAlphaSSIMode ssiMode){ + _ssiMode = (uint8_t)ssiMode; + _ssi->endTransaction(); + _ssi->beginTransaction(SPISettings(_clockFrequency, MSBFIRST, _ssiMode)); +} + +double MagAlphaSSI::readAngle(){ + uint16_t angle; + double angleInDegree; + angle = readAngleRaw16(); + angleInDegree = (angle*360.0)/65536.0; + return angleInDegree; +} + +uint16_t MagAlphaSSI::readAngleRaw(){ + return readAngleRaw16(); +} + +uint16_t MagAlphaSSI::readAngleRaw(bool* error){ + uint16_t data1; + uint8_t data2; + uint8_t highStateCount = 0; + data1 = _ssi->transfer16(0); + data2 = _ssi->transfer(0); + data1 = (data1 << 1); + data1 = data1 + (data2 >> 7); + data2 = ((data2 & 0x40) >> 6); + //Count the number of 1 in the angle binary value + for (int i=0;i<16;++i){ + if (data1 & (1 << i)){ + highStateCount++; + } + } + //check if parity bit is correct + if ((highStateCount % 2) == 0){ + if (data2 == 0){ + *error = false; + } + else{ + *error = true; + } + } + else{ + if (data2 == 1){ + *error = false; + } + else{ + *error = true; + } + } + return data1; +} + +uint16_t MagAlphaSSI::readAngleRaw16(){ + uint16_t data1; + uint8_t data2; + data1 = _ssi->transfer16(0); + data2 = _ssi->transfer(0); + data1 = (data1 << 1); + return data1 + (data2 >> 7); +} + +uint8_t MagAlphaSSI::readAngleRaw8(){ + uint16_t data; + data = _ssi->transfer16(0); + return (data & 0x7F80) >> 7; +} + +/*====================================================================================*/ +/*============================== MagAlphaI2C =========================================*/ +/*====================================================================================*/ +MagAlphaI2C::MagAlphaI2C(){ +} + +void MagAlphaI2C::begin(uint8_t deviceAddress, uint32_t clockFrequency, TwoWire *i2c){ + _i2c = i2c; + _deviceAddress = deviceAddress; + _i2c->begin(); + setClockFrequency(clockFrequency); +} + +void MagAlphaI2C::end(){ + _i2c->end(); +} + +void MagAlphaI2C::setClockFrequency(uint32_t clockFrequency){ + _clockFrequency=clockFrequency; + _i2c->setClock(_clockFrequency); + //100000 = Standard-mode (Sm) + //400000 = Fast-mode (Fm) + //1000000 = Fast-mode Plus (Fm) + //3400000 = High-Speed mode (Hs-mode) + //5000000 = Ulta Fast-mode (UFm) !!! Unidirectional Bus ONLY + //10000 = low speed mode => not supported by the MKRZERO apparently +} + +void MagAlphaI2C::setDeviceAddress(uint8_t deviceAddress){ + _deviceAddress = deviceAddress; +} + +uint8_t MagAlphaI2C::findDeviceAddress(){ + for(int i=0; i<128; i++){ + _i2c->beginTransmission(i); + if (_i2c->endTransmission() == 0){ + setDeviceAddress(i); + return i; + } + } + return 255; +} + +uint8_t MagAlphaI2C::findAllDeviceAddresses(uint8_t detectedDeviceAddresses[], uint8_t arraySize){ + uint8_t numberOfDeviceDetected = 0; + for(int i=0; i<128; i++){ + _i2c->beginTransmission(i); + if (_i2c->endTransmission() == 0){ + if (numberOfDeviceDetected < arraySize){ + detectedDeviceAddresses[numberOfDeviceDetected] = i; + } + numberOfDeviceDetected++; + } + } + if (numberOfDeviceDetected == 1){ + setDeviceAddress(detectedDeviceAddresses[0]); + } + return numberOfDeviceDetected; +} diff --git a/src/MagAlphaBase.h b/src/MagAlphaBase.h new file mode 100644 index 0000000..2129685 --- /dev/null +++ b/src/MagAlphaBase.h @@ -0,0 +1,140 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef MAGALPHABASE_H +#define MAGALPHABASE_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include +#include +#include +#include "MagAlphaPartProperties.h" + + +class MagAlphaBase { +public: + MagAlphaBase(); + + double readAngle(); + uint16_t readAngleRaw(); + + virtual uint16_t readAngleRaw(bool* error){return 0;} + virtual uint16_t readAngleRaw16(){return 0;} + virtual uint8_t readAngleRaw8(){return 0;} + virtual uint8_t readRegister(uint8_t address){return 0;} + virtual uint8_t writeRegister(uint8_t address, uint8_t value){return 0;} + virtual void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){} + virtual void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){} + + //Detect the sensor generation + virtual uint16_t detectSensorGeneration(){return 0;} + + //Set Key Parameters + virtual uint16_t getZero(){return 0;} + virtual void setZero(uint16_t zero){} + virtual uint16_t setCurrentAngleAsZero(){return 0;} + virtual uint16_t getBct(){return 0;} + virtual void setBct(uint16_t bct){} + + //Memory management + virtual void restoreAllRegisters(){} + virtual void storeAllRegisters(){} + virtual void storeRegisterBlock(uint8_t block){} + virtual void storeRegister(uint8_t address){} + + //Advanced features + virtual void clearErrorFlags(){} + virtual double readSpeed(){return 0;} + virtual int16_t readTurn(){return 0;} + virtual void writeTurn(int16_t turn){} + virtual double readTemperature(){return 0.0;} + virtual uint16_t readAcquisitionCounter(){return 0;} + + //Part Information + virtual uint16_t getNumberOfRegisters(){return 0;} + virtual void getLockedRegisters(uint8_t unlockedRegisters[]){} + virtual void getPartNumber(char *partNumber); + virtual uint8_t getSiliconId(){return 0;} + virtual uint8_t getSiliconRevision(){return 0;} + virtual uint8_t getRegisterMapRevision(){return 0;} + + //Utility functions + double convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle); + int16_t twosComplement(uint16_t value, uint8_t numberOfBits); + uint16_t twosComplementInverse(int16_t value, uint8_t numberOfBits); +protected: + // bool _featureSuppored; +}; + +/*====================================================================================*/ +/*============================== MagAlphaSPI =========================================*/ +/*====================================================================================*/ +class MagAlphaSPI : public MagAlphaBase { +public: + MagAlphaSPI(); + void begin(int spiChipSelectPin, SPIClass *spi = &SPI); + void begin(int32_t spiSclkFrequency, MagAlphaSPIMode spiMode, uint8_t spiChipSelectPin, SPIClass *spi = &SPI); + void end(); + void setSpiClockFrequency(uint32_t clockFrequency); + void setSpiDataMode(MagAlphaSPIMode spiMode); + void setSpiChipSelectPin(uint8_t spiChipSelectPin); + virtual uint16_t readAngleRaw16Quick(); +protected: + uint8_t _spiChipSelectPin; + uint32_t _clockFrequency; + uint8_t _spiMode; + SPIClass *_spi; +}; + +/*====================================================================================*/ +/*============================== MagAlphaSSI =========================================*/ +/*====================================================================================*/ +class MagAlphaSSI : public MagAlphaBase { +public: + MagAlphaSSI(); + void begin(); + //void begin(int32_t ssiClkFrequency); + void begin(SPIClass *ssi = &SPI); + void begin(int32_t ssiSsckFrequency, SPIClass *ssi = &SPI); + void begin(int32_t ssiSsckFrequency, MagAlphaSSIMode ssiMode, SPIClass *ssi = &SPI); + void end(); + void setSsiClockFrequency(uint32_t clockFrequency); + void setSSiMode(MagAlphaSSIMode ssiMode); + double readAngle(); + uint16_t readAngleRaw(); + virtual uint16_t readAngleRaw(bool* error); + virtual uint16_t readAngleRaw16(); + virtual uint8_t readAngleRaw8(); +protected: + uint32_t _clockFrequency; + uint8_t _ssiMode; + SPIClass *_ssi; +}; + +/*====================================================================================*/ +/*============================== MagAlphaI2C =========================================*/ +/*====================================================================================*/ +class MagAlphaI2C : public MagAlphaBase { +public: + MagAlphaI2C(); + void begin(uint8_t deviceAddress, uint32_t clockFrequency=400000, TwoWire *i2c = &Wire); + void end(); + void setClockFrequency(uint32_t clockFrequency); + void setDeviceAddress(uint8_t deviceAddress); + uint8_t findDeviceAddress(); + uint8_t findAllDeviceAddresses(uint8_t detectedDeviceAddresses[], uint8_t arraySize); +protected: + uint8_t _deviceAddress; + uint32_t _clockFrequency; + TwoWire *_i2c; +}; + +#endif //MAGALPHABASE_H diff --git a/src/MagAlphaGen3.cpp b/src/MagAlphaGen3.cpp new file mode 100644 index 0000000..4ee0a62 --- /dev/null +++ b/src/MagAlphaGen3.cpp @@ -0,0 +1,409 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 3rd generation Sensors. + Support Part Number includes: MA102, MA302, MA310, MA330, + MA702, MA704, MA710, MA730, MA731, MA732, MA800, MA820, MA850, MAQ430, + MAQ470, MAQ473, MAP790-xxxx, MAP791-xxxx + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "MagAlphaGen3.h" + +//MagAlpha Read/Write Register Command +#define READ_REG_COMMAND (0b010 << 13) +#define WRITE_REG_COMMAND (0b100 << 13) + +#define REG_REGMAPID 23 +#define REG_SID 24 +#define REG_PID 25 +#define REG_LOCK0 28 +#define REG_LOCK1 29 +#define REG_LOCK2 30 +#define REG_LOCK3 31 + +MagAlphaGen3::MagAlphaGen3(){ +} + +uint16_t MagAlphaGen3::readAngleRaw16(){ + uint16_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); //Read 16-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint8_t MagAlphaGen3::readAngleRaw8(){ + uint8_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer(0x00); //Read 8-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint16_t MagAlphaGen3::readAngleRaw(bool* error){ + uint16_t angle; + uint8_t parity; + uint8_t highStateCount = 0; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); + parity = _spi->transfer(0x00); + digitalWrite(_spiChipSelectPin, HIGH); + parity = ((parity & 0x80) >> 7); + //Count the number of 1 in the angle binary value + for (int i=0;i<16;++i){ + if ((angle & (1 << i)) != 0){ + highStateCount++; + } + } + //check if parity bit is correct + if ((highStateCount % 2) == 0){ + if (parity == 0){ + *error = false; + } + else{ + *error = true; + } + } + else{ + if (parity == 1){ + *error = false; + } + else{ + *error = true; + } + } + return angle; +} + +uint8_t MagAlphaGen3::readRegister(uint8_t address){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | ((address & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = ((_spi->transfer16(0x0000) & 0xFF00) >> 8); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns after register readout + return readbackRegisterValue; +} + +uint8_t MagAlphaGen3::writeRegister(uint8_t address, uint8_t value){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(WRITE_REG_COMMAND | ((address & 0x1F) << 8) | value); + digitalWrite(_spiChipSelectPin, HIGH); + delay(20); //Wait for 20ms + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = ((_spi->transfer16(0x0000) & 0xFF00) >> 8); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns after register readout + return readbackRegisterValue; +} + +void MagAlphaGen3::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | (((address) & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns before register readout + for (uint8_t i=0;itransfer16(READ_REG_COMMAND | (((address+i+1) & 0x1F) << 8) | 0x00) >> 8); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns before register readout + } + digitalWrite(_spiChipSelectPin, LOW); + valueArray[numberOfRegister-1] = (_spi->transfer16(0x0000) >> 8); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns after register readout +} + +void MagAlphaGen3::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + for (uint8_t i=0;itransfer16(WRITE_REG_COMMAND | (((address+i) & 0x1F) << 8) | valueArray[i]); + digitalWrite(_spiChipSelectPin, HIGH); + delay(20); //Wait for 20ms + } + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +/* +uint16_t MagAlphaGen3::detectSensorGeneration(){ + uint16_t chipId; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0xFF00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + chipId = _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 750ns after register readout + return chipId; +} +*/ + +uint16_t MagAlphaGen3::getZero() +{ + return (readRegister(1)<<8) + readRegister(0); +} +void MagAlphaGen3::setZero(uint16_t zero){ + writeRegister(0, zero&0xFF); + writeRegister(1, zero>>8); +} + +uint16_t MagAlphaGen3::setCurrentAngleAsZero(){ + uint16_t angle, zero; + setZero(0); + angle=readAngleRaw16(); + zero=65536-angle; + setZero(zero); + return zero; +} + +uint16_t MagAlphaGen3::getBct(){ + return readRegister(2); +} + +void MagAlphaGen3::setBct(uint16_t bct){ + writeRegister(2, bct&0xFF); +} + +uint16_t MagAlphaGen3::getNumberOfRegisters(){ + return 32; +} + +void MagAlphaGen3::getLockedRegisters(uint8_t unlockedRegisters[]){ + uint8_t registerArray[4] = {0}; + readRegisterBurst(REG_LOCK0, registerArray, 4); + for(uint8_t i=0; i<4; i++){ + for(uint8_t j=0; j<8; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + } +} + +void MagAlphaGen3::getPartNumber(char *partNumber){ + uint8_t partId = readRegister(REG_PID); + switch(partId) { + case 1: + sprintf(partNumber, "MA102"); + break; + case 2: + sprintf(partNumber, "MA302"); + break; + case 21: + sprintf(partNumber, "MA302GQ-E"); + break; + case 3: + sprintf(partNumber, "MA310"); + break; + case 4: + sprintf(partNumber, "MA702"); + break; + case 5: + sprintf(partNumber, "MA704"); + break; + case 6: + sprintf(partNumber, "MA710"); + break; + case 7: + sprintf(partNumber, "MA730"); + break; + case 8: + sprintf(partNumber, "MA800"); + break; + case 9: + sprintf(partNumber, "MA820"); + break; + case 10: + sprintf(partNumber, "MA850"); + break; + case 12: + sprintf(partNumber, "MAQ430"); + break; + case 14: + sprintf(partNumber, "MAQ470"); + break; + case 16: + sprintf(partNumber, "MA330"); + break; + case 17: + sprintf(partNumber, "MA731"); + break; + case 18: + sprintf(partNumber, "MA732"); + break; + case 20: + sprintf(partNumber, "MP9961"); + break; + case 22: + sprintf(partNumber, "MAQ473"); + break; + case 23: + sprintf(partNumber, "MA735"); + break; + case 24: + sprintf(partNumber, "MAQ800"); + break; + case 25: + sprintf(partNumber, "MAQ820"); + break; + case 26: + sprintf(partNumber, "MAQ850"); + break; + case 128: + sprintf(partNumber, "MAP790-0000"); + break; + case 129: + sprintf(partNumber, "MAP790-0001"); + break; + case 132: + sprintf(partNumber, "MAP790-0004"); + break; + case 250: + sprintf(partNumber, "MAP790-0010"); + break; + case 251: + sprintf(partNumber, "MAP790-0002"); + break; + case 252: + sprintf(partNumber, "MAP791-0004"); + break; + default: + sprintf(partNumber, "Gen3 [%u] Unknown Part Number", partId); + } +} + +uint8_t MagAlphaGen3::getSiliconId(){ + return (readRegister(REG_SID) & 0xF0) >> 4; +} + +uint8_t MagAlphaGen3::getSiliconRevision(){ + return readRegister(REG_SID) & 0x0F; +} + +uint8_t MagAlphaGen3::getRegisterMapRevision(){ + return readRegister(REG_REGMAPID); +} + +// void MagAlphaGen3::setSpiClockFrequency(uint32_t speedMaximum){ +// _speedMaximum = speedMaximum; +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); +// } + +// void MagAlphaGen3::setSpiDataMode(uint8_t spiMode){ +// _spiMode = spiMode; +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); +// } + +// void MagAlphaGen3::setSpiChipSelectPin(uint8_t spiChipSelectPin){ +// _spiChipSelectPin = spiChipSelectPin; +// pinMode(_spiChipSelectPin, OUTPUT); +// digitalWrite(_spiChipSelectPin, HIGH); +// } + +// double MagAlphaGen3::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ +// double angleInDegree; +// angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); +// return angleInDegree; +// } + +// MagAlphaSSI::MagAlphaSSI(){ +// } +// void MagAlphaSSI::begin(){ +// _speedMaximum = 1000000; +// SPI.begin(); +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +// } + +// void MagAlphaSSI::begin(int32_t ssiSsckFrequency){ +// _speedMaximum = ssiSsckFrequency; +// SPI.begin(); +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +// } + +// void MagAlphaSSI::end(){ +// SPI.end(); +// } + +// double MagAlphaSSI::readAngle(){ +// uint16_t angle; +// double angleInDegree; +// angle = readAngleRaw(); +// angleInDegree = (angle*360.0)/65536.0; +// return angleInDegree; +// } + +// uint16_t MagAlphaSSI::readAngleRaw(){ +// uint16_t angle; +// uint8_t angle0; +// uint8_t angle1; +// uint8_t angle2; + +// angle0 = SPI.transfer(0x00); +// angle1 = SPI.transfer(0x00); +// angle2 = SPI.transfer(0x00); + +// angle = ((angle0 & 0x7F) << 9) | (angle1 << 1) | ((angle2 & 0x80) >> 7); +// return angle; +// } + +// uint16_t MagAlphaSSI::readAngleRaw(bool* error){ +// uint16_t angle; +// uint8_t parity; +// uint8_t highStateCount = 0; +// uint8_t angle0; +// uint8_t angle1; +// uint8_t angle2; + +// angle0 = SPI.transfer(0x00); +// angle1 = SPI.transfer(0x00); +// angle2 = SPI.transfer(0x00); + +// angle = ((angle0 & 0x7F) << 9) | (angle1 << 1) | ((angle2 & 0x80) >> 7); +// parity = ((angle2 & 0x40) >> 6); +// //Count the number of 1 in the angle binary value +// for (int i=0;i<16;++i){ +// if ((angle & (1 << i)) != 0){ +// highStateCount++; +// } +// } +// //check if parity bit is correct +// if ((highStateCount % 2) == 0){ +// if (parity == 0){ +// *error = false; +// } +// else{ +// *error = true; +// } +// } +// else{ +// if (parity == 1){ +// *error = false; +// } +// else{ +// *error = true; +// } +// } +// return angle; +// } + +// void MagAlphaSSI::setSsiClockFrequency(uint32_t speedMaximum){ +// _speedMaximum = speedMaximum; +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +// } + +// double MagAlphaSSI::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ +// double angleInDegree; +// angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); +// return angleInDegree; +// } diff --git a/src/MagAlphaGen3.h b/src/MagAlphaGen3.h new file mode 100644 index 0000000..ea8513a --- /dev/null +++ b/src/MagAlphaGen3.h @@ -0,0 +1,57 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 3rd generation Sensors. + Support Part Number includes: MA102, MA302, MA310, MA330, + MA702, MA704, MA710, MA730, MA731, MA732, MA800, MA820, MA850, MAQ430, + MAQ470, MAQ473, MAP790-xxxx, MAP791-xxxx + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef MAGALPHAGEN3_H +#define MAGALPHAGEN3_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include "MagAlphaBase.h" + +class MagAlphaGen3: public MagAlphaSPI { +public: + MagAlphaGen3(); + uint16_t readAngleRaw(bool* error) override; + uint16_t readAngleRaw16() override; + uint8_t readAngleRaw8() override; + uint8_t readRegister(uint8_t address) override; + uint8_t writeRegister(uint8_t address, uint8_t value) override; + void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + + //Detect the sensor generation + //uint16_t detectSensorGeneration() override; + + //Set Key Parameters + uint16_t getZero() override; + void setZero(uint16_t zero) override; + uint16_t setCurrentAngleAsZero() override; + uint16_t getBct() override; + void setBct(uint16_t bct) override; + + //Part Information + uint16_t getNumberOfRegisters() override; + void getLockedRegisters(uint8_t unlockedRegisters[]) override; + void getPartNumber(char *partNumber) override; + uint8_t getSiliconId() override; + uint8_t getSiliconRevision() override; + uint8_t getRegisterMapRevision() override; +}; + +class MagAlphaSSIGen3: public MagAlphaSSI {}; + +#endif //MAGALPHAGEN3_H diff --git a/src/MagAlphaGen4.cpp b/src/MagAlphaGen4.cpp new file mode 100644 index 0000000..96ad239 --- /dev/null +++ b/src/MagAlphaGen4.cpp @@ -0,0 +1,277 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 4th generation Sensors. + Support Part Number includes: MA780, MA782, MA734 + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "MagAlphaGen4.h" + +//MagAlpha Read/Write Register Command +#define READ_REG_COMMAND (0b010 << 13) +#define WRITE_REG_COMMAND (0b100 << 13) +#define STORE_SINGLE_REGISTER_COMMAND (0b111 << 13) +#define STORE_ALL_REGISTERS_COMMAND (0b110 << 13) +#define RESTORE_ALL_REGISTERS_COMMAND (0b101 << 13) +#define CLEAR_ERROR_FLAGS_COMMAND (0b001 << 13) + +#define REG_REGMAPID 23 +#define REG_SID 24 +#define REG_PID 25 +#define REG_LOCK0 28 +#define REG_LOCK1 29 +#define REG_LOCK2 30 +#define REG_LOCK3 31 + +MagAlphaGen4::MagAlphaGen4(){ +} + +uint16_t MagAlphaGen4::readAngleRaw16(){ + uint16_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); //Read 16-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint8_t MagAlphaGen4::readAngleRaw8(){ + uint8_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer(0x00); //Read 8-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint16_t MagAlphaGen4::readAngleRaw(bool* error){ + uint16_t angle; + uint8_t parity; + uint8_t highStateCount = 0; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); + parity = _spi->transfer(0x00); + digitalWrite(_spiChipSelectPin, HIGH); + parity = ((parity & 0x80) >> 7); + //Count the number of 1 in the angle binary value + for (int i=0;i<16;++i){ + if ((angle & (1 << i)) != 0){ + highStateCount++; + } + } + //check if parity bit is correct + if ((highStateCount % 2) == 0){ + if (parity == 0){ + *error = false; + } + else{ + *error = true; + } + } + else{ + if (parity == 1){ + *error = false; + } + else{ + *error = true; + } + } + return angle; +} + +uint8_t MagAlphaGen4::readRegister(uint8_t address){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | ((address & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return readbackRegisterValue; +} + +uint8_t MagAlphaGen4::writeRegister(uint8_t address, uint8_t value){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(WRITE_REG_COMMAND | ((address & 0x1F) << 8) | value); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return readbackRegisterValue; +} + +void MagAlphaGen4::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | (((address) & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + for (uint8_t i=0;itransfer16(READ_REG_COMMAND | (((address+i+1) & 0x1F) << 8) | 0x00) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + } + digitalWrite(_spiChipSelectPin, LOW); + valueArray[numberOfRegister-1] = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen4::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + for (uint8_t i=0;itransfer16(WRITE_REG_COMMAND | (((address+i) & 0x1F) << 8) | valueArray[i]); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + } + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +/* +uint16_t MagAlphaGen4::detectSensorGeneration(){ + uint16_t chipId; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x6000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + chipId = _spi->transfer16(0x0000) & 0x00FF; + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return chipId; +} +*/ + +uint16_t MagAlphaGen4::getZero() +{ + return (readRegister(1)<<8) + readRegister(0); +} + +void MagAlphaGen4::setZero(uint16_t zero){ + writeRegister(0, zero&0xFF); + writeRegister(1, zero>>8); +} + +uint16_t MagAlphaGen4::setCurrentAngleAsZero(){ + uint16_t zero; + setZero(0); + zero=readAngleRaw16(); + setZero(zero); + return zero; +} + +uint16_t MagAlphaGen4::getBct(){ + return readRegister(2); +} + +void MagAlphaGen4::setBct(uint16_t bct){ + writeRegister(2, bct&0xFF); +} + +void MagAlphaGen4::restoreAllRegisters(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(RESTORE_ALL_REGISTERS_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(240); //Wait for 240us + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen4::storeAllRegisters(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(STORE_ALL_REGISTERS_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delay(704); //Wait for 704ms + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen4::storeRegister(uint8_t address){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(STORE_SINGLE_REGISTER_COMMAND | ((address & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delay(23); //Wait for 23ms + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen4::clearErrorFlags(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(CLEAR_ERROR_FLAGS_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tClearFault of 40ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +uint16_t MagAlphaGen4::getNumberOfRegisters(){ + return 32; +} + +void MagAlphaGen4::getLockedRegisters(uint8_t unlockedRegisters[]){ + uint8_t registerArray[4] = {0}; + readRegisterBurst(REG_LOCK0, registerArray, 4); + for(uint8_t i=0; i<4; i++){ + for(uint8_t j=0; j<8; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + } +} + +void MagAlphaGen4::getPartNumber(char *partNumber){ + uint8_t partId = readRegister(REG_PID); + switch(partId) { + case 1: + sprintf(partNumber, "MA780"); + break; + case 2: + sprintf(partNumber, "MA781"); + break; + case 3: + sprintf(partNumber, "MA782"); + break; + case 248: + sprintf(partNumber, "MA736"); + break; + case 249: + sprintf(partNumber, "MA734"); + break; + case 250: + sprintf(partNumber, "MA734"); + break; + default: + sprintf(partNumber, "Gen4 [%u] Unknown Part Number", partId); + } +} + +uint8_t MagAlphaGen4::getSiliconId(){ + return (readRegister(REG_SID) & 0xF0) >> 4; +} + +uint8_t MagAlphaGen4::getSiliconRevision(){ + return readRegister(REG_SID) & 0x0F; +} + +uint8_t MagAlphaGen4::getRegisterMapRevision(){ + return readRegister(REG_REGMAPID); +} diff --git a/src/MagAlphaGen4.h b/src/MagAlphaGen4.h new file mode 100644 index 0000000..6cf68da --- /dev/null +++ b/src/MagAlphaGen4.h @@ -0,0 +1,63 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 4th generation Sensors. + Support Part Number includes: MA780, MA782, MA734 + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef MAGALPHAGEN4_H +#define MAGALPHAGEN4_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include "MagAlphaBase.h" + +class MagAlphaGen4: public MagAlphaSPI { +public: + MagAlphaGen4(); + uint16_t readAngleRaw(bool* error) override; + uint16_t readAngleRaw16() override; + uint8_t readAngleRaw8() override; + uint8_t readRegister(uint8_t address) override; + uint8_t writeRegister(uint8_t address, uint8_t value) override; + void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + + //Detect the sensor generation + //uint16_t detectSensorGeneration() override; + + //Set Key Parameters + uint16_t getZero() override; + void setZero(uint16_t zero) override; + uint16_t setCurrentAngleAsZero() override; + uint16_t getBct() override; + void setBct(uint16_t bct) override; + + //Memory management + void restoreAllRegisters() override; + void storeAllRegisters() override; + void storeRegister(uint8_t address) override; + + //Advanced features + void clearErrorFlags() override; + + //Part Information + uint16_t getNumberOfRegisters() override; + void getLockedRegisters(uint8_t unlockedRegisters[]) override; + void getPartNumber(char *partNumber) override; + uint8_t getSiliconId() override; + uint8_t getSiliconRevision() override; + uint8_t getRegisterMapRevision() override; +}; + +class MagAlphaSSIGen4: public MagAlphaSSI {}; + +#endif //MAGALPHAGEN4_H diff --git a/src/MagAlphaGen6.cpp b/src/MagAlphaGen6.cpp new file mode 100644 index 0000000..ba1d2e5 --- /dev/null +++ b/src/MagAlphaGen6.cpp @@ -0,0 +1,418 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 6th generation Sensors. + Support Part Number includes: MA600 + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "MagAlphaGen6.h" + +//MagAlpha Read/Write Register Command +#define READ_REG_COMMAND (0b11010010 << 8) +#define WRITE_REG_COMMAND (0b1110101001010100) + +#define REG_REGMAPID 30 +#define REG_PID 31 +#define REG_LOCK0 156 +#define REG_LOCK1 157 +#define REG_LOCK2 158 +#define REG_LOCK3 159 + +MagAlphaGen6::MagAlphaGen6(){ +} + +uint16_t MagAlphaGen6::readAngleRaw16(){ + uint16_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); //Read 16-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint8_t MagAlphaGen6::readAngleRaw8(){ + uint8_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer(0x00); //Read 8-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint16_t MagAlphaGen6::readAngleRaw(bool* error){ + uint16_t angle; + uint8_t parity; + uint8_t highStateCount = 0; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); + parity = _spi->transfer(0x00); + digitalWrite(_spiChipSelectPin, HIGH); + parity = ((parity & 0x80) >> 7); + //Count the number of 1 in the angle binary value + for (int i=0;i<16;++i){ + if ((angle & (1 << i)) != 0){ + highStateCount++; + } + } + //check if parity bit is correct + if ((highStateCount % 2) == 0){ + if (parity == 0){ + *error = false; + } + else{ + *error = true; + } + } + else{ + if (parity == 1){ + *error = false; + } + else{ + *error = true; + } + } + return angle; +} + +uint8_t MagAlphaGen6::readRegister(uint8_t address){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | address); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = _spi->transfer16(0x0000) & 0x00FF; + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return readbackRegisterValue; +} + +uint8_t MagAlphaGen6::writeRegister(uint8_t address, uint8_t value){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(WRITE_REG_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16((address << 8) | value); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return readbackRegisterValue; +} + +void MagAlphaGen6::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | address); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + for (uint8_t i=0;itransfer16(READ_REG_COMMAND | (address+i+1)) & 0x00FF; + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + } + digitalWrite(_spiChipSelectPin, LOW); + valueArray[numberOfRegister-1] = _spi->transfer16(0x0000) & 0x00FF; + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen6::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + for (uint8_t i=0;itransfer16(WRITE_REG_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(((address+i) << 8) | valueArray[i]); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + } + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +/* +uint16_t MagAlphaGen6::detectSensorGeneration(){ + uint16_t chipId; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0xD300); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + digitalWrite(_spiChipSelectPin, LOW); + chipId = _spi->transfer16(0x0000)&0xFF; + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return chipId; +} +*/ + +uint16_t MagAlphaGen6::getZero() +{ + return (readRegister(1)<<8) + readRegister(0); +} +void MagAlphaGen6::setZero(uint16_t zero){ + writeRegister(0, zero&0xFF); + writeRegister(1, zero>>8); +} + +uint16_t MagAlphaGen6::setCurrentAngleAsZero(){ + uint16_t zero; + setZero(0); + zero=readAngleRaw16(); + setZero(zero); + return zero; +} + +uint16_t MagAlphaGen6::getBct(){ + return readRegister(2); +} + +void MagAlphaGen6::setBct(uint16_t bct){ + writeRegister(2, bct&0xFF); +} + +void MagAlphaGen6::restoreAllRegisters(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0b1110101001010110); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(240); //Wait for 240us + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen6::storeAllRegisters(){ + storeRegisterBlock(0); + storeRegisterBlock(1); +} + +void MagAlphaGen6::storeRegisterBlock(uint8_t block){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0b1110101001010101); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0b1110101000000000 | (block & 0x1)); + digitalWrite(_spiChipSelectPin, HIGH); + delay(600); //Wait for 600ms + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen6::clearErrorFlags(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0b1101011100000000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +double MagAlphaGen6::readSpeed(){ + uint16_t angle; + uint16_t multiturnOrSpeed; + //The choice between multiturn and speed is done by settings MTSP + //for multiturn MTSP=0, for speed MTSP=1. This is a volatile settings + //MTSP = 1, PRT = 0, PRTS = 0, APRT=0, FTA(1:0)=0, FTM=0 + writeRegister(28, 0x80); + readAngleAndMultiturnOrSpeedRaw(&angle, &multiturnOrSpeed); + return twosComplement(multiturnOrSpeed, 16) * 5.722; +} + +int16_t MagAlphaGen6::readTurn(){ + uint16_t angle; + uint16_t multiturnOrSpeed; + //The choice between multiturn and speed is done by settings MTSP + //for multiturn MTSP=0, for speed MTSP=1. This is a volatile settings + //MTSP = 0, PRT = 0, PRTS = 0, APRT=0, FTA(1:0)=0, FTM=0 + writeRegister(28, 0x00); + readAngleAndMultiturnOrSpeedRaw(&angle, &multiturnOrSpeed); + return twosComplement(multiturnOrSpeed, 16); +} + +void MagAlphaGen6::readAngleAndMultiturnOrSpeedRaw(uint16_t *angle, uint16_t *multiturnOrSpeed){ + digitalWrite(_spiChipSelectPin, LOW); + *angle = _spi->transfer16(0x0000); //Read 16-bit angle + *multiturnOrSpeed = _spi->transfer16(0x0000); //Read 16-bit angle + digitalWrite(_spiChipSelectPin, HIGH); +} + +void MagAlphaGen6::writeTurn(int16_t turn){ + uint16_t mtoffset = twosComplementInverse(turn, 16); + writeRegister(18, mtoffset&0xFF); + writeRegister(19, mtoffset>>8); +} + +uint16_t MagAlphaGen6::getNumberOfRegisters(){ + return 160; +} + +void MagAlphaGen6::getLockedRegisters(uint8_t unlockedRegisters[]){ + uint8_t i, j; + uint8_t registerArray[4] = {0}; + readRegisterBurst(REG_LOCK0, registerArray, 4); + for(i=0; i<3; i++){ + for(j=0; j<8; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + } + i = 3; + for(j=0; j<2; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + for (j=32; j<64; j++){ + unlockedRegisters[j] = ((registerArray[3]>>2)&0x01) ? 0xFF : 0x00; + } +} + +void MagAlphaGen6::getPartNumber(char *partNumber){ + sprintf(partNumber, "MA600"); +} + +uint8_t MagAlphaGen6::getSiliconId(){ + return readRegister(REG_PID) & 0x3F; +} + +uint8_t MagAlphaGen6::getSiliconRevision(){ + return readRegister(REG_PID) & 0x3F; +} + +uint8_t MagAlphaGen6::getRegisterMapRevision(){ + return readRegister(REG_REGMAPID) & 0x7F; +} + + + + + + + +// void MagAlphaGen6::setSpiClockFrequency(uint32_t speedMaximum){ +// _speedMaximum = speedMaximum; +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); +// } + +// void MagAlphaGen6::setSpiDataMode(uint8_t spiMode){ +// _spiMode = spiMode; +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, _spiMode)); +// } + +// void MagAlphaGen6::setSpiChipSelectPin(uint8_t spiChipSelectPin){ +// _spiChipSelectPin = spiChipSelectPin; +// pinMode(_spiChipSelectPin, OUTPUT); +// digitalWrite(_spiChipSelectPin, HIGH); +// } + +// double MagAlphaGen6::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ +// double angleInDegree; +// angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); +// return angleInDegree; +// } + + +// MagAlphaSSIGen6::MagAlphaSSIGen6(){ +// } +// void MagAlphaSSIGen6::begin(){ +// _speedMaximum = 1000000; +// SPI.begin(); +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +// } + +// void MagAlphaSSIGen6::begin(int32_t ssiSsckFrequency){ +// _speedMaximum = ssiSsckFrequency; +// SPI.begin(); +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +// } + +// void MagAlphaSSIGen6::end(){ +// SPI.end(); +// } + +// double MagAlphaSSIGen6::readAngle(){ +// uint16_t angle; +// double angleInDegree; +// angle = readAngleRaw(); +// angleInDegree = (angle*360.0)/65536.0; +// return angleInDegree; +// } + +// uint16_t MagAlphaSSIGen6::readAngleRaw(){ +// uint16_t angle; +// uint8_t angle0; +// uint8_t angle1; +// uint8_t angle2; + +// angle0 = SPI.transfer(0x00); +// angle1 = SPI.transfer(0x00); +// angle2 = SPI.transfer(0x00); + +// angle = ((angle0 & 0x7F) << 9) | (angle1 << 1) | ((angle2 & 0x80) >> 7); +// return angle; +// } + +// uint16_t MagAlphaSSIGen6::readAngleRaw(bool* error){ +// uint16_t angle; +// uint8_t parity; +// uint8_t highStateCount = 0; +// uint8_t angle0; +// uint8_t angle1; +// uint8_t angle2; + +// angle0 = SPI.transfer(0x00); +// angle1 = SPI.transfer(0x00); +// angle2 = SPI.transfer(0x00); + +// angle = ((angle0 & 0x7F) << 9) | (angle1 << 1) | ((angle2 & 0x80) >> 7); +// parity = ((angle2 & 0x40) >> 6); +// //Count the number of 1 in the angle binary value +// for (int i=0;i<16;++i){ +// if ((angle & (1 << i)) != 0){ +// highStateCount++; +// } +// } +// //check if parity bit is correct +// if ((highStateCount % 2) == 0){ +// if (parity == 0){ +// *error = false; +// } +// else{ +// *error = true; +// } +// } +// else{ +// if (parity == 1){ +// *error = false; +// } +// else{ +// *error = true; +// } +// } +// return angle; +// } + +// void MagAlphaSSIGen6::setSsiClockFrequency(uint32_t speedMaximum){ +// _speedMaximum = speedMaximum; +// SPI.beginTransaction(SPISettings(_speedMaximum, MSBFIRST, SSI_MODE)); +// } + +// double MagAlphaSSIGen6::convertRawAngleToDegree(uint8_t rawAngleDataBitLength, uint16_t rawAngle){ +// double angleInDegree; +// angleInDegree = (rawAngle*360.0)/((double)pow(2, rawAngleDataBitLength)); +// return angleInDegree; +// } diff --git a/src/MagAlphaGen6.h b/src/MagAlphaGen6.h new file mode 100644 index 0000000..73f314d --- /dev/null +++ b/src/MagAlphaGen6.h @@ -0,0 +1,84 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 6th generation Sensors. + Support Part Number includes: MA600 + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef MAGALPHAGEN6_H +#define MAGALPHAGEN6_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include "MagAlphaBase.h" + +class MagAlphaGen6: public MagAlphaSPI { +public: + MagAlphaGen6(); + uint16_t readAngleRaw(bool *error) override; + uint16_t readAngleRaw16() override; + uint8_t readAngleRaw8() override; + uint8_t readRegister(uint8_t address) override; + uint8_t writeRegister(uint8_t address, uint8_t value) override; + void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + + //Detect the sensor generation + //uint16_t detectSensorGeneration() override; + + //Set Key Parameters + uint16_t getZero() override; + void setZero(uint16_t zero) override; + uint16_t setCurrentAngleAsZero() override; + uint16_t getBct() override; + void setBct(uint16_t bct) override; + + //Memory management + void restoreAllRegisters() override; + void storeAllRegisters() override; + /** + * @brief Store register block + * @param block Register block to store. if block=0, it stores register 0 to 31 + * (registers containing the configuration). + * if block=1 it stores register 31 to 63 + * (registers containing the correction table). + */ + void storeRegisterBlock(uint8_t block) override; + + //Advanced features + void clearErrorFlags() override; + double readSpeed() override; + int16_t readTurn() override; + /** + * @brief set a multiturn offset by configuring the MTOFFSET field + * in the configuration register. + * MTOFFSET is set to 0 at the system power up. + * @attention MTOFFSET setting can’t be stored into NVM, + * so user needs to set MTOFFSET after every power up if offset is needed. + * + * + */ + void writeTurn(int16_t turn) override; + void readAngleAndMultiturnOrSpeedRaw(uint16_t *angle, uint16_t *multiturnOrSpeed); + + //Part Information + uint16_t getNumberOfRegisters() override; + void getLockedRegisters(uint8_t unlockedRegisters[]) override; + void getPartNumber(char *partNumber) override; + uint8_t getSiliconId() override; + uint8_t getSiliconRevision() override; + uint8_t getRegisterMapRevision() override; + +}; + +class MagAlphaSSIGen6: public MagAlphaSSI {}; + +#endif //MAGALPHAGEN6_H diff --git a/src/MagAlphaGen7.cpp b/src/MagAlphaGen7.cpp new file mode 100644 index 0000000..5da0809 --- /dev/null +++ b/src/MagAlphaGen7.cpp @@ -0,0 +1,890 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 7th generation Sensors. + Support Part Number includes: MA900 + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "MagAlphaGen7.h" + +//CRC table for poly = x^4 + x^3 + x^2 + 1 (0x1d or 0b11101 or 29) +const uint8_t crc4LookupTable[16] = {0, 13, 7, 10, 14, 3, 9, 4, 1, 12, 6, 11, 15, 2, 8, 5}; + +const uint8_t poly_table[256] = {0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3}; + +#define REG_ZERO0 0 +#define REG_ZERO1 1 +#define REG_SENT0 8 +#define REG_SENT1 9 +#define REG_SENT2 10 +#define REG_INTF 15 +#define REG_FILT 17 +#define REG_SPEEDFILT 18 +#define REG_IOMC 20 +#define REG_ID0 27 +#define REG_ID1 28 +#define REG_ID2 29 +#define REG_ID3 30 +#define REG_PID 31 +#define REG_TS1 39 +#define REG_LOCK0 52 +#define REG_LOCK1 53 +#define REG_LOCK2 54 +#define REG_LOCK3 55 +#define REG_SECRET 79 +#define REG_ANGLE 96 +#define REG_SPEED0 98 +#define REG_MTV0 100 +#define REG_TEMP0 102 +#define REG_READC 107 +#define REG_STATUS 108 +#define REG_MTP 120 +#define REG_FAULT 125 +#define REG_LOCKST 126 +#define REG_LOCK 127 + +#define SENT_FORMAT_H1 0 +#define SENT_FORMAT_H2 1 +#define SENT_FORMAT_H3 2 +#define SENT_FORMAT_H4 3 +#define SENT_FORMAT_H5 4 +#define SENT_FORMAT_H6 5 +#define SENT_FORMAT_H7 6 + +#define IOMC_PULL_DOWN 0 +#define IOMC_ABZ_UVW_PWM 1 +#define IOMC_ABZ_PWM 2 +#define IOMC_ABZ_SSI_PWM 3 +#define IOMC_SSI_UVW 4 +#define IOMC_UVW_DIFF 5 +#define IOMC_ABZ_PBI 6 +#define IOMC_UVW 7 +#define IOMC_MGL_UVW 8 +#define IOMC_SENT 9 +#define IOMC_ABZ_MGL 10 +#define IOMC_PWM_PBI 11 +#define IOMC_MGL_SSI 12 +#define IOMC_TRIG 13 +#define IOMC_GPIO_MODE 15 + +/*====================================================================================*/ +/*====================================== SPI =========================================*/ +/*====================================================================================*/ + +MagAlphaGen7::MagAlphaGen7(){ + _crcCheckEnabled = true; + _crcInitValue = 10; +} + +uint16_t MagAlphaGen7::readAngleRaw(bool* error){ + bool inversion = false; + return readAngleRaw16(error, &inversion, false); +} + +uint16_t MagAlphaGen7::readAngleRaw16(){ + bool error = false; + bool inversion = false; + return readAngleRaw16(&error, &inversion, false); +} + +uint16_t MagAlphaGen7::readAngleRaw16(bool *error, bool *inversion, bool isShortRead){ + uint16_t readbackValue, valueToWrite, computedCrc, angle; + bool errorDetected; + bool inversionDetected; + *error = false; + *inversion = false; + valueToWrite = 0x0300 | REG_READC; + valueToWrite = appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error = errorDetected?true:*error; + *inversion = inversionDetected?true:*inversion; + angle = readbackValue & 0xFFF0; + + if(!isShortRead){ + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + angle |= (readbackValue>>12)&0x000F; + } + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint8_t MagAlphaGen7::readAngleRaw8(){ + bool error = false; + bool inversion = false; + return (readAngleRaw16(&error, &inversion, true) >> 8); +} + +uint8_t MagAlphaGen7::readRegister(uint8_t address){ + bool error, inversion; + return readRegister(address, &error, &inversion); +} + +uint8_t MagAlphaGen7::writeRegister(uint8_t address, uint8_t value){ + bool error, inversion, wrongHandshaking; + return writeRegister(address, value, &error, &inversion, &wrongHandshaking); +} + +void MagAlphaGen7::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + bool error, inversion; + readRegisterBurst(address, valueArray, numberOfRegister, &error, &inversion); +} + +void MagAlphaGen7::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + bool error, inversion, wrongHandshaking; + writeRegisterBurst(address, valueArray, numberOfRegister, &error, &inversion, &wrongHandshaking); +} + +/* +uint16_t MagAlphaGen7::detectSensorGeneration(){ + bool error, inversion; + return readRegister(REG_PID, &error, &inversion) >> 4; +} +*/ + +uint16_t MagAlphaGen7::getZero(){ + bool error, inversion; + return (readRegister(REG_ZERO1, &error, &inversion) << 8) | readRegister(REG_ZERO0, &error, &inversion); +} + +void MagAlphaGen7::setZero(uint16_t zero){ + bool error, inversion, wrongHandshaking; + writeRegister(REG_ZERO0, zero&0x00FF, &error, &inversion, &wrongHandshaking); + writeRegister(REG_ZERO1, zero>>8, &error, &inversion, &wrongHandshaking); +} + +uint16_t MagAlphaGen7::setCurrentAngleAsZero(){ + uint16_t zero; + setZero(0); + delay(10); + zero = readAngleRaw16(); + setZero(zero); + return zero; +} + +void MagAlphaGen7::restoreAllRegisters(){ + bool error, inversion, wrongHandshaking; + uint8_t tempReg; + tempReg = readRegister(REG_MTP, &error, &inversion); + tempReg |= 0x10; + writeRegister(REG_MTP, tempReg, &error, &inversion, &wrongHandshaking); + //wait for MTP DONE Flag to be set to 1 (indicate MTP Store/Restore operation is finished) + tempReg=0; + while((tempReg & 0x80) == 0){ + tempReg = readRegister(REG_MTP, &error, &inversion); + } +} + +void MagAlphaGen7::storeAllRegisters(){ + //Store Page 0 and Page 1 + storeRegisterBlock(3); +} + +void MagAlphaGen7::storeRegisterBlock(uint8_t block){ + bool error, inversion, wrongHandshaking; + uint8_t tempReg = 0; + tempReg = readRegister(REG_MTP, &error, &inversion); + if(block <= 3){ + tempReg &= 0xFC; + tempReg |= 0x20 | block; + writeRegister(REG_MTP, tempReg, &error, &inversion, &wrongHandshaking); + } + //wait for MTP DONE Flag to be set to 1 (indicate MTP Store/Restore operation is finished) + tempReg=0; + while((tempReg & 0x80) == 0){ + tempReg = readRegister(REG_MTP, &error, &inversion); + } +} + +void MagAlphaGen7::clearErrorFlags(){ + bool error, inversion, wrongHandshaking; + writeRegister(REG_STATUS, 0X07, &error, &inversion, &wrongHandshaking); +} + +double MagAlphaGen7::readSpeed(){ + uint16_t angle; + bool error, inversion; + return twosComplement(readAngleSpeed(&angle, &error, &inversion), 16) * 3.57; +} + +int16_t MagAlphaGen7::readTurn(){ + uint16_t angle; + bool error, inversion; + return twosComplement(readAngleMultiturn(&angle, &error, &inversion), 16); +} + +void MagAlphaGen7::writeTurn(int16_t turn){ + bool error, inversion, wrongHandshaking; + uint16_t multiturn = twosComplementInverse(turn, 16); + writeRegister(REG_MTV0, multiturn&0x00FF, &error, &inversion, &wrongHandshaking); + writeRegister(REG_MTV0+1, multiturn>>8, &error, &inversion, &wrongHandshaking); +} + +double MagAlphaGen7::readTemperature(){ + uint16_t angle; + bool error, inversion; + return twosComplement(readAngleTemperature(&angle, &error, &inversion), 16) * 0.125; +} + +uint16_t MagAlphaGen7::readAcquisitionCounter(){ + uint16_t angle; + bool error, inversion; + return readAngleCounter(&angle, &error, &inversion); +} + +uint16_t MagAlphaGen7::readAngleCounter(uint16_t *angle, bool *error, bool *inversion) { + uint16_t readbackValue, valueToWrite, computedCrc, counter; + bool errorDetected; + bool inversionDetected; + *error=false; + *inversion=false; + valueToWrite=(0x0300)|REG_READC; + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle=readbackValue&0xFFF0; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle |= (readbackValue>>12)&0x000F; + counter = (readbackValue>>4)&0x00FF; + digitalWrite(_spiChipSelectPin, HIGH); + return counter; +} + +uint16_t MagAlphaGen7::readAngleSpeed(uint16_t *angle, bool *error, bool *inversion) { + uint16_t readbackValue, valueToWrite, computedCrc, speed; + bool errorDetected; + bool inversionDetected; + *error=false; + *inversion=false; + valueToWrite=(0x0300)|REG_SPEED0; + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle=readbackValue&0xFFF0; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle |= (readbackValue>>12)&0x000F; + speed = (readbackValue>>4)&0x00FF; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + speed |= (readbackValue<<4)&0xFF00; + digitalWrite(_spiChipSelectPin, HIGH); + return speed; +} + +uint16_t MagAlphaGen7::readAngleMultiturn(uint16_t *angle, bool *error, bool *inversion) { + uint16_t readbackValue, valueToWrite, computedCrc, multiturn; + bool errorDetected; + bool inversionDetected; + *error=false; + *inversion=false; + valueToWrite=(0x0300)|REG_MTV0; + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle=readbackValue&0xFFF0; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle |= (readbackValue>>12)&0x000F; + multiturn = (readbackValue>>4)&0x00FF; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + multiturn |= (readbackValue<<4)&0xFF00; + digitalWrite(_spiChipSelectPin, HIGH); + return multiturn; +} + +uint16_t MagAlphaGen7::readAngleTemperature(uint16_t *angle, bool *error, bool *inversion){ + uint16_t readbackValue, valueToWrite, computedCrc, temperature; + bool errorDetected; + bool inversionDetected; + *error=false; + *inversion=false; + valueToWrite=(0x0300)|REG_TEMP0; + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle=readbackValue&0xFFF0; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *angle |= (readbackValue>>12)&0x000F; + temperature = (readbackValue>>4)&0x00FF; + + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + temperature |= (readbackValue<<4)&0xFF00; + digitalWrite(_spiChipSelectPin, HIGH); + return temperature; +} + +uint8_t MagAlphaGen7::readRegister(uint8_t address, bool *error, bool *inversion) { + uint16_t readbackValue, valueToWrite, computedCrc; + bool errorDetected; + bool inversionDetected; + *error=false; + *inversion=false; + valueToWrite=(0x0300)|(address); + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + + //The previously received 16-bit data on CIPO (12-bit AngleMSB + 4-bit CRC4) is returned by the controller on COPI (handshaking protocol). + //We do not compute the CRC of the previously received data we just send the exact same data+CRC back to the peripheral. + valueToWrite=readbackValue; + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + digitalWrite(_spiChipSelectPin, HIGH); + return ((readbackValue>>4)&0x00FF); +} + +uint16_t MagAlphaGen7::readRegisterBurst(uint8_t address, uint8_t readbackValueArray[], uint16_t numberOfRegister, bool *error, bool *inversion) { + uint16_t readbackValue, valueToWrite, computedCrc, angle; + bool errorDetected; + bool inversionDetected; + *error=false; + *inversion=false; + valueToWrite=(0x0300)|(address); + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + angle=readbackValue&0xFFF0; + + for (uint8_t i=0;itransfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + readbackValueArray[i]=(readbackValue>>4)&0xFF; + if (i==0) { + angle=angle | ((readbackValue>>12)&0x000F); + } + } + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint8_t MagAlphaGen7::writeRegister(uint8_t address, uint8_t value, bool *error, bool *inversion, bool *wrongHandshaking) { + uint16_t readbackValue, valueToWrite, writtenValue, computedCrc; + bool errorDetected, inversionDetected; + + *error=false; + *inversion=false; + *wrongHandshaking = false; + + valueToWrite=(0x0C00)|(address); + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + writtenValue = valueToWrite; + + valueToWrite=(0x0000)|(value); + valueToWrite=appendCrc4(valueToWrite); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *wrongHandshaking = ((readbackValue&0x0FF0) != (writtenValue&0x0FF0))?true:*wrongHandshaking; //in this readback we get the angle LSBs instead of OpCode + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + writtenValue = valueToWrite; + + valueToWrite=0x0F00; + valueToWrite=appendCrc4(valueToWrite); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *wrongHandshaking = (readbackValue != writtenValue)?true:*wrongHandshaking; + + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + digitalWrite(_spiChipSelectPin, HIGH); + return (readbackValue & 0x0FF0) >> 4; +} + +void MagAlphaGen7::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister, bool *error, bool *inversion, bool *wrongHandshaking) { + uint16_t readbackValue, valueToWrite, writtenValue, computedCrc; + bool errorDetected, inversionDetected; + + *error=false; + *inversion=false; + *wrongHandshaking = false; + + valueToWrite=(0x0C00)|(address); + valueToWrite=appendCrc4(valueToWrite); + digitalWrite(_spiChipSelectPin, LOW); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + writtenValue = valueToWrite; + + for (uint8_t i=0;itransfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + if(i == 0){ + *wrongHandshaking = ((readbackValue&0x0FF0) != (writtenValue&0x0FF0))?true:*wrongHandshaking; //in this readback I get the angle LSBs instead of OpCode + } + else{ + *wrongHandshaking = (readbackValue != writtenValue)?true:*wrongHandshaking; + } + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + writtenValue = valueToWrite; + } + + valueToWrite=0x0F00; + valueToWrite=appendCrc4(valueToWrite); + readbackValue = _spi->transfer16(valueToWrite); + checkCrc4(readbackValue, &computedCrc, &errorDetected, &inversionDetected); + *error=errorDetected?true:*error; + *inversion=inversionDetected?true:*inversion; + *wrongHandshaking = (readbackValue != writtenValue)?true:*wrongHandshaking; + digitalWrite(_spiChipSelectPin, HIGH); +} + +void MagAlphaGen7::setCrcCheckSetting(bool enable){ + bool error, inversion, wrongHandshaking; + uint8_t tempReg; + tempReg = readRegister(REG_INTF, &error, &inversion); + if(enable){ + writeRegister(REG_INTF, tempReg|0x01, &error, &inversion, &wrongHandshaking); + _crcCheckEnabled = true; + } + else{ + writeRegister(REG_INTF, tempReg&0xFE, &error, &inversion, &wrongHandshaking); + _crcCheckEnabled = false; + } +} + +uint16_t MagAlphaGen7::appendCrc4(uint16_t data){ + uint8_t crc4; // 4-bit CRC (0-15) + // Compute CRC4 + crc4 = _crcInitValue; // Initial Value for CRC4 (Seed) + crc4 = (data>>8 & 0xF) ^ crc4LookupTable[crc4]; // 4 MSB first + crc4 = (data>>4 & 0xF) ^ crc4LookupTable[crc4]; // + crc4 = (data>>0 & 0xF) ^ crc4LookupTable[crc4]; // 4 LSB + // Concatenate 12-bit data with CRC4 + return (data<<4) | crc4; // 16-bit word to send <12-bit data><4-bit crc> +} + +void MagAlphaGen7::checkCrc4(uint16_t readData, uint16_t *computedCrc, bool *errorDetected, bool *inversionDetected){ + *computedCrc=appendCrc4(readData>>4); + //compare the data + CRC received VS the expected data + CRC + if (readData==*computedCrc){ + *errorDetected=false; + *inversionDetected = false; + } + else{ + *errorDetected=true; + if(((~readData) & 0xF) == (*computedCrc & 0xF)){ + *inversionDetected = true; //if the CRC is not the same, check if it was inverted + } + else{ + *inversionDetected = false; + } + } +} + +uint16_t MagAlphaGen7::getNumberOfRegisters(){ + return 128; +} + +void MagAlphaGen7::getLockedRegisters(uint8_t unlockedRegisters[]){ + uint8_t registerArray[4] = {0}; + readRegisterBurst(REG_LOCK0, registerArray, 4); + for(uint8_t i=0; i<4; i++){ + for(uint8_t j=0; j<8; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + } +} + +void MagAlphaGen7::getPartNumber(char *partNumber){ + sprintf(partNumber, "MA900"); +} + +uint8_t MagAlphaGen7::getSiliconId(){ + return readRegister(REG_PID); +} + +uint8_t MagAlphaGen7::getSiliconRevision(){ + uint8_t siliconRevision0, siliconRevision1, siliconRevision2, siliconRevision3; + siliconRevision0 = readRegister(REG_ID0); + siliconRevision1 = readRegister(REG_ID1); + siliconRevision2 = readRegister(REG_ID2); + siliconRevision3 = readRegister(REG_ID3); + return siliconRevision0; +} + +/*====================================================================================*/ +/*====================================== I2C =========================================*/ +/*====================================================================================*/ + +MagAlphaI2CGen7::MagAlphaI2CGen7(){ + _crcInitValue = 0; + _crcCheckEnabled = true; + _deviceAddress = 0x14; +} + +uint16_t MagAlphaI2CGen7::readAngleRaw(bool* error){ + uint16_t angle; + uint8_t readRegisters[2] = {0}; + readRegisterQuickRead(readRegisters, 2, error); + return (readRegisters[1]<<8) | readRegisters[0]; +} + +uint16_t MagAlphaI2CGen7::readAngleRaw16(){ + bool error; + return readAngleRaw(&error); +} + +uint8_t MagAlphaI2CGen7::readAngleRaw8(){ + return readAngleRaw16()>>8; +} + +uint8_t MagAlphaI2CGen7::readRegister(uint8_t address){ + bool error; + return readRegister(address, &error); +} + +uint8_t MagAlphaI2CGen7::writeRegister(uint8_t address, uint8_t value){ + uint8_t crc = _crcInitValue; + _i2c->beginTransmission(_deviceAddress); + crc = crc8(crc, (_deviceAddress<<1)+0); + _i2c->write(byte(address)); + crc = crc8(crc, address); + _i2c->write(byte(value)); + crc = crc8(crc, value); + if(_crcCheckEnabled){ + _i2c->write(byte(crc)); + } + _i2c->endTransmission(); + return value; +} + +void MagAlphaI2CGen7::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + bool error; + readRegisterBurst(address, valueArray, numberOfRegister, &error); +} + +void MagAlphaI2CGen7::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + uint8_t crc; + _i2c->beginTransmission(_deviceAddress); + _i2c->write(byte(address)); + for (uint8_t cnt = 0; cnt < numberOfRegister; cnt++){ + _i2c->write(byte(valueArray[cnt])); + if (_crcCheckEnabled){ + crc = _crcInitValue; + crc = crc8(crc, _deviceAddress<<1); + crc = crc8(crc, (address + cnt)); + crc = crc8(crc, valueArray[cnt]); + _i2c->write(byte(crc)); + } + } + _i2c->endTransmission(); +} + +uint16_t MagAlphaI2CGen7::detectSensorGeneration(){ + uint16_t chipId; + chipId = readRegister(REG_PID); + return (chipId>>4)&0xF; +} + +uint16_t MagAlphaI2CGen7::getZero(){ + uint8_t readRegisters[2] = {0}; + readRegisterBurst(0, readRegisters, 2); + return (readRegisters[1]<<8) | readRegisters[0]; +} + +void MagAlphaI2CGen7::setZero(uint16_t zero){ + uint8_t readRegisters[2] = {static_cast(zero & 0xFF), static_cast(zero >> 8)}; + writeRegisterBurst(0, readRegisters, 2); +} + +uint16_t MagAlphaI2CGen7::setCurrentAngleAsZero(){ + uint16_t zero; + setZero(0); + delay(10); + zero = readAngleRaw16(); + setZero(zero); + return zero; +} + +void MagAlphaI2CGen7::restoreAllRegisters(){ + uint8_t tempReg; + tempReg = readRegister(REG_MTP); + tempReg |= 0x10; + writeRegister(REG_MTP, tempReg); + //wait for MTP DONE Flag to be set to 1 (indicate MTP Store/Restore operation is finished) + tempReg=0; + while((tempReg & 0x80) == 0){ + tempReg = readRegister(REG_MTP); + } +} + +void MagAlphaI2CGen7::storeAllRegisters(){ + //Store Page 0 and Page 1 + storeRegisterBlock(3); +} + +void MagAlphaI2CGen7::storeRegisterBlock(uint8_t block){ + uint8_t tempReg = 0; + tempReg = readRegister(REG_MTP); + if(block <= 3){ + tempReg &= 0xFC; + tempReg |= 0x20 | block; + writeRegister(REG_MTP, tempReg); + } + //wait for MTP DONE Flag to be set to 1 (indicate MTP Store/Restore operation is finished) + tempReg=0; + while((tempReg & 0x80) == 0){ + tempReg = readRegister(REG_MTP); + } +} + +void MagAlphaI2CGen7::clearErrorFlags(){ + writeRegister(REG_STATUS, 0X07); +} + +double MagAlphaI2CGen7::readSpeed(){ + uint16_t speed; + uint8_t readRegisters[2] = {0}; + readRegisterBurst(REG_SPEED0, readRegisters, 2); + speed = (readRegisters[1]<<8) | readRegisters[0]; + return twosComplement(speed, 16) * 3.57; +} + +int16_t MagAlphaI2CGen7::readTurn(){ + uint16_t turn; + uint8_t readRegisters[2] = {0}; + readRegisterBurst(REG_MTV0, readRegisters, 2); + turn = (readRegisters[1]<<8) | readRegisters[0]; + return twosComplement(turn, 16); +} + +void MagAlphaI2CGen7::writeTurn(int16_t turn){ + uint16_t multiturn = twosComplementInverse(turn, 16); + uint8_t readRegisters[2] = {static_cast(multiturn & 0xFF), static_cast(multiturn >> 8)}; + writeRegisterBurst(REG_MTV0, readRegisters, 2); +} + +double MagAlphaI2CGen7::readTemperature(){ + uint16_t temperature; + uint8_t readRegisters[2] = {0}; + readRegisterBurst(REG_TEMP0, readRegisters, 2); + temperature = (readRegisters[1]<<8) | readRegisters[0]; + return twosComplement(temperature, 16) * 0.125; +} + +uint16_t MagAlphaI2CGen7::readAcquisitionCounter(){ + return readRegister(REG_READC); +} + +uint8_t MagAlphaI2CGen7::readRegister(uint8_t address, bool *error){ + uint8_t crc = _crcInitValue; + uint8_t readbackValue, crcReceived; + uint8_t requestBytes; + requestBytes=_crcCheckEnabled?2:1; //if crc is enabled, read 2 bytes from sensor + _i2c->beginTransmission(_deviceAddress); + crc = crc8(crc, (_deviceAddress<<1)+0); + _i2c->write(byte(address)); + crc = crc8(crc, address); + _i2c->endTransmission(false); + _i2c->requestFrom(_deviceAddress, requestBytes, true); + crc = crc8(crc, (_deviceAddress<<1)+1); + readbackValue = _i2c->read(); + crc = crc8(crc, readbackValue); + if(_crcCheckEnabled){ + crcReceived = _i2c->read(); + checkCrc8(crcReceived, crc, error); + } + return readbackValue; +} + +uint16_t MagAlphaI2CGen7::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister, bool *error){ + uint8_t byteCount = 0; + uint8_t crcReceived; + uint8_t crc; + *error=false; + _i2c->beginTransmission(_deviceAddress); + _i2c->write(byte(address)); + _i2c->endTransmission(false); + if(_crcCheckEnabled){ + numberOfRegister*=2; + } + _i2c->requestFrom(_deviceAddress, numberOfRegister); + while(_i2c->available()){ + valueArray[byteCount] = _i2c->read(); + if (_crcCheckEnabled){ + crc = _crcInitValue; + crc = crc8(crc, _deviceAddress<<1); + crc = crc8(crc, address + byteCount); + crc = crc8(crc, (_deviceAddress<<1)+1); + crc = crc8(crc, valueArray[byteCount]); + crcReceived = _i2c->read(); + *error = (crc != crcReceived) ? true : *error; + } + byteCount++; + } + return byteCount; +} + +uint16_t MagAlphaI2CGen7::readRegisterQuickRead(uint8_t valueArray[], uint16_t numberOfRegister, bool *error){ + uint8_t crc; + uint8_t crcReceived; + uint8_t byteCount = 0; + uint8_t firstReg = 96; + *error=false; + if(_crcCheckEnabled){ + numberOfRegister*=2; + } + _i2c->requestFrom(_deviceAddress, numberOfRegister); + while(_i2c->available()) { + valueArray[byteCount] = _i2c->read(); + if (_crcCheckEnabled){ + crc = _crcInitValue; + crc = crc8(crc, (_deviceAddress<<1)+1); + crc = crc8(crc, (firstReg + byteCount)); + crc = crc8(crc, valueArray[byteCount]); + crcReceived = _i2c->read(); + *error = (crc != crcReceived) ? true : *error; + } + byteCount++; + } + return byteCount; +} + +void MagAlphaI2CGen7::setCrcCheckSetting(bool enable){ + bool error; + uint8_t tempReg; + tempReg = readRegister(REG_INTF, &error); + if(enable){ + writeRegister(REG_INTF, tempReg|0x01); + _crcCheckEnabled = true; + } + else{ + writeRegister(REG_INTF, tempReg&0xFE); + _crcCheckEnabled = false; + } +} + +uint8_t MagAlphaI2CGen7::crc8(uint8_t crc, uint8_t data){ + return poly_table[crc^data]; +} + +void MagAlphaI2CGen7::checkCrc8(uint8_t &readData, uint8_t &computedCrc, bool *errorDetected){ + //compare the data + CRC received VS the expected data + CRC + if (readData==computedCrc){ + *errorDetected=false; + } + else{ + *errorDetected=true; + } +} + +uint16_t MagAlphaI2CGen7::getNumberOfRegisters(){ + return 128; +} + +void MagAlphaI2CGen7::getLockedRegisters(uint8_t unlockedRegisters[]){ + uint8_t registerArray[4] = {0}; + readRegisterBurst(REG_LOCK0, registerArray, 4); + for(uint8_t i=0; i<4; i++){ + for(uint8_t j=0; j<8; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + } +} + +void MagAlphaI2CGen7::getPartNumber(char *partNumber){ + sprintf(partNumber, "MA900"); +} + +uint8_t MagAlphaI2CGen7::getSiliconId(){ + return readRegister(REG_PID); +} + +uint8_t MagAlphaI2CGen7::getSiliconRevision(){ + uint8_t siliconRevision0, siliconRevision1, siliconRevision2, siliconRevision3; + siliconRevision0 = readRegister(REG_ID0); + siliconRevision1 = readRegister(REG_ID1); + siliconRevision2 = readRegister(REG_ID2); + siliconRevision3 = readRegister(REG_ID3); + return siliconRevision0; +} diff --git a/src/MagAlphaGen7.h b/src/MagAlphaGen7.h new file mode 100644 index 0000000..bf6e2b0 --- /dev/null +++ b/src/MagAlphaGen7.h @@ -0,0 +1,151 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagAlpha 7th generation Sensors. + Support Part Number includes: MA900 + MagAlpha sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef MAGALPHAGEN7_H +#define MAGALPHAGEN7_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include "MagAlphaBase.h" + +class MagAlphaGen7: public MagAlphaSPI { +public: + MagAlphaGen7(); + + uint16_t readAngleRaw(bool *error) override; + uint16_t readAngleRaw16() override; + uint8_t readAngleRaw8() override; + uint8_t readRegister(uint8_t address) override; + uint8_t writeRegister(uint8_t address, uint8_t value) override; + void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + + //Detect the sensor generation + //uint16_t detectSensorGeneration() override; + + //Set Key Parameters + uint16_t getZero() override; + void setZero(uint16_t zero) override; + uint16_t setCurrentAngleAsZero() override; + + //Memory management + void restoreAllRegisters() override; + void storeAllRegisters() override; + /** + * @brief Store register block + * @param block Register block to store. + * block=0, Do not store anything (Do not use) + * block=1, Store Page 0 + * block=2, Store Page 1 + * block=3, Store Page 0 and Page 1 + */ + void storeRegisterBlock(uint8_t block) override; + + //Advanced features + void clearErrorFlags() override; + double readSpeed() override; + int16_t readTurn() override; + void writeTurn(int16_t turn) override; + double readTemperature() override; + uint16_t readAcquisitionCounter() override; + + //Part Information + uint16_t getNumberOfRegisters() override; + void getLockedRegisters(uint8_t unlockedRegisters[]) override; + void getPartNumber(char *partNumber) override; + uint8_t getSiliconId() override; + uint8_t getSiliconRevision() override; + + uint16_t readAngleRaw16(bool *error, bool *inversion, bool isShortRead=false); + uint16_t readAngleCounter(uint16_t *angle, bool *error, bool *inversion); + uint16_t readAngleSpeed(uint16_t *angle, bool *error, bool *inversion); + uint16_t readAngleMultiturn(uint16_t *angle, bool *error, bool *inversion); + uint16_t readAngleTemperature(uint16_t *angle, bool *error, bool *inversion); + uint8_t readRegister(uint8_t address, bool *error, bool *inversion); + uint16_t readRegisterBurst(uint8_t address, uint8_t readbackValueArray[], uint16_t numberOfRegister, bool *error, bool *inversion); + uint8_t writeRegister(uint8_t address, uint8_t value, bool *error, bool *inversion, bool *wrongHandshaking); + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister, bool *error, bool *inversion, bool *wrongHandshaking); + void setCrcCheckSetting(bool enable); + uint16_t appendCrc4(uint16_t data); + void checkCrc4(uint16_t readData, uint16_t *computedCrc, bool *errorDetected, bool *inversionDetected); + +private: + bool _crcCheckEnabled; + uint8_t _crcInitValue; +}; + +class MagAlphaSSIGen7: public MagAlphaSSI {}; + +class MagAlphaI2CGen7: public MagAlphaI2C { +public: + MagAlphaI2CGen7(); + + uint16_t readAngleRaw(bool *error) override; + uint16_t readAngleRaw16() override; + uint8_t readAngleRaw8() override; + uint8_t readRegister(uint8_t address) override; + uint8_t writeRegister(uint8_t address, uint8_t value) override; + void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + + //Detect the sensor generation + uint16_t detectSensorGeneration() override; + + //Set Key Parameters + uint16_t getZero() override; + void setZero(uint16_t zero) override; + uint16_t setCurrentAngleAsZero() override; + + //Memory management + void restoreAllRegisters() override; + void storeAllRegisters() override; + /** + * @brief Store register block + * @param block Register block to store. + * block=0, Do not store anything (Do not use) + * block=1, Store Page 0 + * block=2, Store Page 1 + * block=3, Store Page 0 and Page 1 + */ + void storeRegisterBlock(uint8_t block) override; + + //Advanced features + void clearErrorFlags() override; + double readSpeed() override; + int16_t readTurn() override; + void writeTurn(int16_t turn) override; + double readTemperature() override; + uint16_t readAcquisitionCounter() override; + + uint16_t getNumberOfRegisters() override; + void getLockedRegisters(uint8_t unlockedRegisters[]) override; + void getPartNumber(char *partNumber) override; + uint8_t getSiliconId() override; + uint8_t getSiliconRevision() override; + + uint8_t readRegister(uint8_t address, bool *error); + uint16_t readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister, bool *error); + uint16_t readRegisterQuickRead(uint8_t valueArray[], uint16_t numberOfRegister, bool *error); + void setCrcCheckSetting(bool enable); + + uint8_t crc8(uint8_t crc, uint8_t data); + void checkCrc8(uint8_t &readData, uint8_t &computedCrc, bool *errorDetected); + +private: + bool _crcCheckEnabled; + uint8_t _crcInitValue; +}; + +#endif //MAGALPHAGEN7_H \ No newline at end of file diff --git a/src/MagAlphaGen8.cpp b/src/MagAlphaGen8.cpp new file mode 100644 index 0000000..2c7f8ed --- /dev/null +++ b/src/MagAlphaGen8.cpp @@ -0,0 +1,257 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagDiff 8th generation Sensors. + Support Part Number includes: MA980, MA981 + MagDiff sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#include "MagAlphaGen8.h" + +//MagAlpha Read/Write Register Command +#define READ_REG_COMMAND (0b010 << 13) +#define WRITE_REG_COMMAND (0b100 << 13) +#define STORE_SINGLE_REGISTER_COMMAND (0b111 << 13) +#define STORE_ALL_REGISTERS_COMMAND (0b110 << 13) +#define RESTORE_ALL_REGISTERS_COMMAND (0b101 << 13) +#define CLEAR_ERROR_FLAGS_COMMAND (0b001 << 13) + +#define REG_REGMAPID 23 +#define REG_SID 24 +#define REG_PID 25 +#define REG_LOCK0 28 +#define REG_LOCK1 29 +#define REG_LOCK2 30 +#define REG_LOCK3 31 + +MagAlphaGen8::MagAlphaGen8(){ +} + +uint16_t MagAlphaGen8::readAngleRaw16(){ + uint16_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); //Read 16-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint8_t MagAlphaGen8::readAngleRaw8(){ + uint8_t angle; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer(0x00); //Read 8-bit angle + digitalWrite(_spiChipSelectPin, HIGH); + return angle; +} + +uint16_t MagAlphaGen8::readAngleRaw(bool* error){ + uint16_t angle; + uint8_t parity; + uint8_t highStateCount = 0; + digitalWrite(_spiChipSelectPin, LOW); + angle = _spi->transfer16(0x0000); + parity = _spi->transfer(0x00); + digitalWrite(_spiChipSelectPin, HIGH); + parity = ((parity & 0x80) >> 7); + //Count the number of 1 in the angle binary value + for (int i=0;i<16;++i){ + if ((angle & (1 << i)) != 0){ + highStateCount++; + } + } + //check if parity bit is correct + if ((highStateCount % 2) == 0){ + if (parity == 0){ + *error = false; + } + else{ + *error = true; + } + } + else{ + if (parity == 1){ + *error = false; + } + else{ + *error = true; + } + } + return angle; +} + +uint8_t MagAlphaGen8::readRegister(uint8_t address){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | ((address & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return readbackRegisterValue; +} + +uint8_t MagAlphaGen8::writeRegister(uint8_t address, uint8_t value){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(WRITE_REG_COMMAND | ((address & 0x1F) << 8) | value); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + readbackRegisterValue = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return readbackRegisterValue; +} + +void MagAlphaGen8::readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + uint8_t readbackRegisterValue; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(READ_REG_COMMAND | (((address) & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + for (uint8_t i=0;itransfer16(READ_REG_COMMAND | (((address+i+1) & 0x1F) << 8) | 0x00) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + } + digitalWrite(_spiChipSelectPin, LOW); + valueArray[numberOfRegister-1] = (_spi->transfer16(0x0000) & 0x00FF); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen8::writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister){ + for (uint8_t i=0;itransfer16(WRITE_REG_COMMAND | (((address+i) & 0x1F) << 8) | valueArray[i]); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + } + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +/* +uint16_t MagAlphaGen8::detectSensorGeneration(){ + uint16_t chipId; + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x6000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + chipId = _spi->transfer16(0x0000) & 0x00FF; + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout + return chipId; +} +*/ + +uint16_t MagAlphaGen8::getZero() +{ + return (readRegister(1)<<8) + readRegister(0); +} + +void MagAlphaGen8::setZero(uint16_t zero){ + writeRegister(0, zero&0xFF); + writeRegister(1, zero>>8); +} + +uint16_t MagAlphaGen8::setCurrentAngleAsZero(){ + uint16_t zero; + setZero(0); + zero=readAngleRaw16(); + setZero(zero); + return zero; +} + +void MagAlphaGen8::restoreAllRegisters(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(RESTORE_ALL_REGISTERS_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(240); //Wait for 240us + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen8::storeAllRegisters(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(STORE_ALL_REGISTERS_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delay(704); //Wait for 704ms + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen8::storeRegister(uint8_t address){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(STORE_SINGLE_REGISTER_COMMAND | ((address & 0x1F) << 8) | 0x00); + digitalWrite(_spiChipSelectPin, HIGH); + delay(23); //Wait for 23ms + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +void MagAlphaGen8::clearErrorFlags(){ + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(CLEAR_ERROR_FLAGS_COMMAND); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tClearFault of 40ns before register readout + digitalWrite(_spiChipSelectPin, LOW); + _spi->transfer16(0x0000); + digitalWrite(_spiChipSelectPin, HIGH); + delayMicroseconds(1); //Wait for 1us (=1000 ns) to respect tIdleReg of 120ns after register readout +} + +uint16_t MagAlphaGen8::getNumberOfRegisters(){ + return 32; +} + +void MagAlphaGen8::getLockedRegisters(uint8_t unlockedRegisters[]){ + uint8_t registerArray[4] = {0}; + readRegisterBurst(REG_LOCK0, registerArray, 4); + for(uint8_t i=0; i<4; i++){ + for(uint8_t j=0; j<8; j++){ + unlockedRegisters[i*8+j] = ((registerArray[i]>>j)&0x01) ? 0xFF : 0x00; + } + } +} + +void MagAlphaGen8::getPartNumber(char *partNumber){ + uint8_t partId = readRegister(REG_PID); + switch(partId) { + case 1: + sprintf(partNumber, "MA980"); + break; + case 2: + sprintf(partNumber, "MA981"); + break; + default: + sprintf(partNumber, "Gen8 [%u] Unknown Part Number", partId); + } +} + +uint8_t MagAlphaGen8::getSiliconId(){ + return (readRegister(REG_SID) & 0xF0) >> 4; +} + +uint8_t MagAlphaGen8::getSiliconRevision(){ + return readRegister(REG_SID) & 0x0F; +} + +uint8_t MagAlphaGen8::getRegisterMapRevision(){ + return readRegister(REG_REGMAPID); +} diff --git a/src/MagAlphaGen8.h b/src/MagAlphaGen8.h new file mode 100644 index 0000000..fa62c77 --- /dev/null +++ b/src/MagAlphaGen8.h @@ -0,0 +1,62 @@ +/*************************************************** + Arduino library for the MPS MagAlpha magnetic angle sensor + Supports MagDiff 8th generation Sensors. + Support Part Number includes: MA980, MA981 + MagDiff sensor detects the + absolute angular position of a permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + ----> http://www.monolithicpower.com/Products/Position-Sensors/Products-Overview + Written by Mathieu Kaelin for Monolithic Power Systems. + MIT license, all text above must be included in any redistribution + ****************************************************/ + +#ifndef MAGALPHAGEN8_H +#define MAGALPHAGEN8_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include "MagAlphaBase.h" + +class MagAlphaGen8: public MagAlphaSPI { +public: + MagAlphaGen8(); + uint16_t readAngleRaw(bool* error) override; + uint16_t readAngleRaw16() override; + uint8_t readAngleRaw8() override; + uint8_t readRegister(uint8_t address) override; + uint8_t writeRegister(uint8_t address, uint8_t value) override; + void readRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + void writeRegisterBurst(uint8_t address, uint8_t valueArray[], uint16_t numberOfRegister) override; + + //Detect the sensor generation + //uint16_t detectSensorGeneration() override; + + //Set Key Parameters + uint16_t getZero() override; + void setZero(uint16_t zero) override; + uint16_t setCurrentAngleAsZero() override; + + //Memory management + void restoreAllRegisters() override; + void storeAllRegisters() override; + void storeRegister(uint8_t address) override; + + //Advanced features + void clearErrorFlags() override; + + //Part Information + uint16_t getNumberOfRegisters() override; + void getLockedRegisters(uint8_t unlockedRegisters[]) override; + void getPartNumber(char *partNumber) override; + uint8_t getSiliconId() override; + uint8_t getSiliconRevision() override; + uint8_t getRegisterMapRevision() override; + +}; + +class MagAlphaSSIGen8: public MagAlphaSSI {}; + +#endif //MAGALPHAGEN8_H diff --git a/src/MagAlphaPartProperties.h b/src/MagAlphaPartProperties.h new file mode 100644 index 0000000..8a65128 --- /dev/null +++ b/src/MagAlphaPartProperties.h @@ -0,0 +1,84 @@ + +#ifndef MAGALPHAPARTPROPERTIES_H +#define MAGALPHAPARTPROPERTIES_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include +#include + +typedef enum MagAlphaInterface{ + UNKNOWN_INTERFACE = 0, + SPI_INTERFACE = 1, + I2C_INTERFACE = 2, + SSI_INTERFACE = 3, + ABZ_INTERFACE = 4, + UVW_INTERFACE = 5, + SENT_INTERFACE = 6 +}MagAlphaInterface; + +typedef enum MagAlphaGeneration{ + UNKNOWN_GEN = 0, + MA_GEN_1 = 1, + MA_GEN_2 = 2, + MA_GEN_3 = 3, + MA_GEN_4 = 4, + MA_GEN_5 = 5, + MA_GEN_6 = 6, + MA_GEN_7 = 7, + MA_GEN_8 = 8 +}MagAlphaGeneration; + +typedef enum MagAlphaSPIMode{ + MODE_0 = SPI_MODE0, + MODE_3 = SPI_MODE3 +}MagAlphaSPIMode; + +typedef enum MagAlphaSSIMode{ + MODE_A = SPI_MODE2, + MODE_B = SPI_MODE1 +}MagAlphaSSIMode; + +typedef enum MagAlphaPartNumber{ + UNKNOWN_PART_NUMBER = 0, + MA100 = 1, //MA_GEN_1 + MA120 = 2, //MA_GEN_1 + MA300 = 3, //MA_GEN_1 + MA301 = 4, //MA_GEN_1 + MA700 = 5, //MA_GEN_1 + MA750 = 6, //MA_GEN_1 + MA700A = 7, //MA_GEN_2 + MA102 = 8, //MA_GEN_3 + MA302 = 9, //MA_GEN_3 + MA310 = 10, //MA_GEN_3 + MA330 = 11, //MA_GEN_3 + MA702 = 12, //MA_GEN_3 + MA704 = 13, //MA_GEN_3 + MA710 = 14, //MA_GEN_3 + MA730 = 15, //MA_GEN_3 + MA731 = 16, //MA_GEN_3 + MA732 = 17, //MA_GEN_3 + MA800 = 18, //MA_GEN_3 + MA820 = 19, //MA_GEN_3 + MA850 = 20, //MA_GEN_3 + MAQ430 = 21, //MA_GEN_3 + MAQ470 = 22, //MA_GEN_3 + MAQ473 = 23, //MA_GEN_3 + MAP790 = 24, //MA_GEN_3 + MAP791 = 25, //MA_GEN_3 + MA780 = 26, //MA_GEN_4 + MA781 = 27, //MA_GEN_4 + MA734 = 28, //MA_GEN_4 + MA760 = 29, //MA_GEN_5 + MA600 = 30, //MA_GEN_6 + MA900 = 31, //MA_GEN_7 + MAQ79010FS = 32,//MA_GEN_7 + MA980 = 33, //MA_GEN_8 + MA981 = 34, //MA_GEN_8 + +}MagAlphaPartNumber; + +#endif //MAGALPHAPARTPROPERTIES_H \ No newline at end of file