From e398f5bb3f7a78439dfb4feec887c74a58f13703 Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sat, 12 Sep 2020 16:48:14 +0100 Subject: [PATCH 1/3] adding support for MA730, exposing clock_speed and providing additional constructors --- src/MagneticSensorI2C.cpp | 11 +++++++- src/MagneticSensorI2C.h | 11 +++++++- src/MagneticSensorSPI.cpp | 57 +++++++++++++++++++++++---------------- src/MagneticSensorSPI.h | 12 ++++++++- 4 files changed, 65 insertions(+), 26 deletions(-) diff --git a/src/MagneticSensorI2C.cpp b/src/MagneticSensorI2C.cpp index eb94a753..92137048 100644 --- a/src/MagneticSensorI2C.cpp +++ b/src/MagneticSensorI2C.cpp @@ -22,13 +22,22 @@ MagneticSensorI2C::MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, // extraction masks lsb_mask = (uint8_t)( (2 << lsb_used) - 1 ); msb_mask = (uint8_t)( (2 << _bits_used_msb) - 1 ); + clock_speed = 400000; + sda_pin = SDA; + scl_pin = SCL; + +} + +MagneticSensorI2C MagneticSensorI2C::AS5600() { + MagneticSensorI2C* sensor = new MagneticSensorI2C(0x36, 12, 0x0E, 4); + return *sensor; } void MagneticSensorI2C::init(){ //I2C communication begin - Wire.begin(); + Wire.begin(sda_pin, scl_pin, clock_speed); // velocity calculation init angle_prev = 0; diff --git a/src/MagneticSensorI2C.h b/src/MagneticSensorI2C.h index c5dc3489..200afede 100644 --- a/src/MagneticSensorI2C.h +++ b/src/MagneticSensorI2C.h @@ -17,8 +17,9 @@ class MagneticSensorI2C: public Sensor{ * @param _bits_used_msb number of used bits in msb */ MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, uint8_t _angle_register_msb, int _msb_bits_used); - + static MagneticSensorI2C AS5600(); + /** sensor initialise pins */ void init(); @@ -41,7 +42,15 @@ class MagneticSensorI2C: public Sensor{ int hasAbsoluteZero(); /** returns 0 maning it doesn't need search for absolute zero */ int needsAbsoluteZeroSearch(); + + /* the speed of the i2c clock signal */ + long clock_speed; + + /* the pin used for i2c data */ + int sda_pin; + /* the pin used for i2c clock */ + int scl_pin; private: float cpr; //!< Maximum range of the magnetic sensor diff --git a/src/MagneticSensorSPI.cpp b/src/MagneticSensorSPI.cpp index 79430b13..7d0623c3 100644 --- a/src/MagneticSensorSPI.cpp +++ b/src/MagneticSensorSPI.cpp @@ -11,23 +11,42 @@ MagneticSensorSPI::MagneticSensorSPI(int cs, float _bit_resolution, int _angle_r angle_register = _angle_register ? _angle_register : DEF_ANGLE_REGISTAR; // register maximum value (counts per revolution) cpr = pow(2,_bit_resolution); + spi_mode = SPI_MODE1; + clock_speed = 1000000; + + command_parity_bit = 15; // for backwards compatibilty + command_read_bit = 14; // for backwards compatibilty +} + +MagneticSensorSPI MagneticSensorSPI::MA730(int cs) { + MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0xFFFF); + sensor->spi_mode = SPI_MODE0; + sensor->command_parity_bit = 0; // parity bit insertion not implemented + sensor->command_read_bit = 0; // read flag bit insertion not implemented + return *sensor; +} +MagneticSensorSPI MagneticSensorSPI::AS5147(int cs) { + MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0xCFFF); + sensor->spi_mode = SPI_MODE1; + sensor->command_parity_bit = 15; + sensor->command_read_bit = 14; + return *sensor; } void MagneticSensorSPI::init(){ // 1MHz clock (AMS should be able to accept up to 10MHz) - settings = SPISettings(1000000, MSBFIRST, SPI_MODE1); + settings = SPISettings(clock_speed, MSBFIRST, spi_mode); //setup pins pinMode(chip_select_pin, OUTPUT); - //SPI has an internal SPI-device counter, it is possible to call "begin()" from different devices SPI.begin(); #ifndef ESP_H // if not ESP32 board SPI.setBitOrder(MSBFIRST); // Set the SPI_1 bit order - SPI.setDataMode(SPI_MODE1) ; + SPI.setDataMode(spi_mode) ; SPI.setClockDivider(SPI_CLOCK_DIV8); #endif @@ -77,7 +96,7 @@ float MagneticSensorSPI::getVelocity(){ float angle_c = getAngle(); // velocity calculation float vel = (angle_c - angle_prev)/Ts; - + // save variables for future pass angle_prev = angle_c; velocity_calc_timestamp = now_us; @@ -147,35 +166,28 @@ byte MagneticSensorSPI::spiCalcEvenParity(word value){ * Returns the value of the register */ word MagneticSensorSPI::read(word angle_register){ - word command = 0b0100000000000000; // PAR=0 R/W=R - command = command | angle_register; - //Add a parity bit on the the MSB - command |= ((word)spiCalcEvenParity(command)<<15); - - //Split the command into two bytes - byte right_byte = command & 0xFF; - byte left_byte = ( command >> 8 ) & 0xFF; + word command = angle_register; + if (command_read_bit > 0) { + command = angle_register | (1 << command_read_bit); + } + if (command_parity_bit > 0) { + //Add a parity bit on the the MSB + command |= ((word)spiCalcEvenParity(command) << command_parity_bit); + } #if !defined(_STM32_DEF_) // if not stm chips //SPI - begin transaction SPI.beginTransaction(settings); #endif - //SPI - begin transaction - //SPI.beginTransaction(settings); //Send the command digitalWrite(chip_select_pin, LOW); -#ifndef ESP_H // if not ESP32 board digitalWrite(chip_select_pin, LOW); -#endif - SPI.transfer(left_byte); - SPI.transfer(right_byte); + SPI.transfer16(command); digitalWrite(chip_select_pin,HIGH); -#ifndef ESP_H // if not ESP32 board digitalWrite(chip_select_pin,HIGH); -#endif #if defined( ESP_H ) // if ESP32 board delayMicroseconds(50); @@ -186,8 +198,7 @@ word MagneticSensorSPI::read(word angle_register){ //Now read the response digitalWrite(chip_select_pin, LOW); digitalWrite(chip_select_pin, LOW); - left_byte = SPI.transfer(0x00); - right_byte = SPI.transfer(0x00); + word register_value = SPI.transfer16(0x00); digitalWrite(chip_select_pin, HIGH); digitalWrite(chip_select_pin,HIGH); @@ -197,7 +208,7 @@ word MagneticSensorSPI::read(word angle_register){ #endif // Return the data, stripping the parity and error bits - return (( ( left_byte & 0xFF ) << 8 ) | ( right_byte & 0xFF )) & ~0xC000; + return register_value & ~0xC000; } /** diff --git a/src/MagneticSensorSPI.h b/src/MagneticSensorSPI.h index da70c0c4..facdae56 100644 --- a/src/MagneticSensorSPI.h +++ b/src/MagneticSensorSPI.h @@ -17,7 +17,9 @@ class MagneticSensorSPI: public Sensor{ * @param angle_register (optional) angle read register - default 0x3FFF */ MagneticSensorSPI(int cs, float bit_resolution, int angle_register = 0); - + + static MagneticSensorSPI MA730(int cs); + static MagneticSensorSPI AS5147(int cs); /** sensor initialise pins */ void init(); @@ -41,6 +43,11 @@ class MagneticSensorSPI: public Sensor{ int hasAbsoluteZero(); /** returns 0 maning it doesn't need search for absolute zero */ int needsAbsoluteZeroSearch(); + // returns the spi mode (phase/polarity of read/writes) i.e one of SPI_MODE0 | SPI_MODE1 | SPI_MODE2 | SPI_MODE3 + int spi_mode; + + /* returns the speed of the SPI clock signal */ + long clock_speed; private: @@ -72,6 +79,9 @@ class MagneticSensorSPI: public Sensor{ // velocity calculation variables float angle_prev; //!< angle in previous velocity calculation step long velocity_calc_timestamp; //!< last velocity calculation timestamp + + int command_parity_bit; //!< the bit where parity flag is stored in command + int command_read_bit; //!< the bit where read flag is stored in command }; From 7f71f015b12eac8e1a2fc6e8b64308bcd2bc01ea Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sun, 13 Sep 2020 22:10:47 +0100 Subject: [PATCH 2/3] fixing issue with MA730 not liking mask --- src/MagneticSensorSPI.cpp | 28 ++++++++++++++++++---------- src/MagneticSensorSPI.h | 4 +++- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/MagneticSensorSPI.cpp b/src/MagneticSensorSPI.cpp index 7d0623c3..f8d56999 100644 --- a/src/MagneticSensorSPI.cpp +++ b/src/MagneticSensorSPI.cpp @@ -13,16 +13,20 @@ MagneticSensorSPI::MagneticSensorSPI(int cs, float _bit_resolution, int _angle_r cpr = pow(2,_bit_resolution); spi_mode = SPI_MODE1; clock_speed = 1000000; + bit_resolution = _bit_resolution; command_parity_bit = 15; // for backwards compatibilty - command_read_bit = 14; // for backwards compatibilty + command_rw_bit = 14; // for backwards compatibilty + data_start_bit = 13; // for backwards compatibilty + } MagneticSensorSPI MagneticSensorSPI::MA730(int cs) { - MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0xFFFF); + MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0x0000); sensor->spi_mode = SPI_MODE0; - sensor->command_parity_bit = 0; // parity bit insertion not implemented - sensor->command_read_bit = 0; // read flag bit insertion not implemented + sensor->command_parity_bit = -1; // parity bit insertion not implemented + sensor->command_rw_bit = -1; // rw bit not required for angle + sensor->data_start_bit = 15; return *sensor; } @@ -30,7 +34,8 @@ MagneticSensorSPI MagneticSensorSPI::AS5147(int cs) { MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0xCFFF); sensor->spi_mode = SPI_MODE1; sensor->command_parity_bit = 15; - sensor->command_read_bit = 14; + sensor->command_rw_bit = 14; + sensor->data_start_bit = 13; return *sensor; } @@ -169,10 +174,10 @@ word MagneticSensorSPI::read(word angle_register){ word command = angle_register; - if (command_read_bit > 0) { - command = angle_register | (1 << command_read_bit); + if (command_rw_bit > -1) { + command = angle_register | (1 << command_rw_bit); } - if (command_parity_bit > 0) { + if (command_parity_bit > -1) { //Add a parity bit on the the MSB command |= ((word)spiCalcEvenParity(command) << command_parity_bit); } @@ -206,9 +211,12 @@ word MagneticSensorSPI::read(word angle_register){ //SPI - end transaction SPI.endTransaction(); #endif + + register_value = register_value >> (1 + data_start_bit - bit_resolution); //this should shift data to the rightmost bits of the word + + const static word data_mask = ~(0 >> (16 - bit_resolution)); - // Return the data, stripping the parity and error bits - return register_value & ~0xC000; + return register_value & data_mask; // Return the data, stripping the non data (e.g parity) bits } /** diff --git a/src/MagneticSensorSPI.h b/src/MagneticSensorSPI.h index e592f526..c142fc77 100644 --- a/src/MagneticSensorSPI.h +++ b/src/MagneticSensorSPI.h @@ -82,8 +82,10 @@ class MagneticSensorSPI: public Sensor{ float angle_prev; //!< angle in previous velocity calculation step long velocity_calc_timestamp; //!< last velocity calculation timestamp + int bit_resolution; //!< the number of bites of angle data int command_parity_bit; //!< the bit where parity flag is stored in command - int command_read_bit; //!< the bit where read flag is stored in command + int command_rw_bit; //!< the bit where read/write flag is stored in command + int data_start_bit; //!< the the position of first bit }; From eae25dd13969dc77e068b362d16ff4937a6d04ba Mon Sep 17 00:00:00 2001 From: Owen Williams Date: Sun, 13 Sep 2020 23:49:54 +0100 Subject: [PATCH 3/3] Alternative struct based approach --- src/Hardware.h | 47 +++++++++++++++++++++++++++++++++++++++ src/MagneticSensorI2C.cpp | 21 +++++++++++++---- src/MagneticSensorI2C.h | 13 +++++++++++ src/MagneticSensorSPI.cpp | 36 +++++++++++++----------------- src/MagneticSensorSPI.h | 19 +++++++++++++--- src/SimpleFOC.h | 1 + 6 files changed, 110 insertions(+), 27 deletions(-) create mode 100644 src/Hardware.h diff --git a/src/Hardware.h b/src/Hardware.h new file mode 100644 index 00000000..9204853c --- /dev/null +++ b/src/Hardware.h @@ -0,0 +1,47 @@ +#ifndef HARDWARE_H +#define HARDWARE_H + + +#include "MagneticSensorSPI.h" + +/** Typical configuration for the 14bit AMS AS5147 magnetic sensor over SPI interface */ +MagneticSensorSPIConfig_s AS5147_SPI = { + .spi_mode = SPI_MODE1, + .clock_speed = 1000000, + .bit_resolution = 14, + .angle_register = 0xCFFF, + .data_start_bit = 13, + .command_rw_bit = 14, + .command_parity_bit = 15 +}; + +/** Typical configuration for the 14bit MonolithicPower MA730 magnetic sensor over SPI interface */ +MagneticSensorSPIConfig_s MA730_SPI = { + .spi_mode = SPI_MODE0, + .clock_speed = 1000000, + .bit_resolution = 14, + .angle_register = 0x0000, + .data_start_bit = 15, + .command_rw_bit = 0, // not required + .command_parity_bit = 0 // parity not implemented +}; + +/** Typical configuration for the 12bit AMS AS5600 magnetic sensor over I2C interface */ +MagneticSensorI2CConfig_s AS5600_I2C = { + .chip_address = 0x36, + .clock_speed = 1000000, + .bit_resolution = 12, + .angle_register = 0x0E, + .data_start_bit = 11 +}; + +/** Typical configuration for the 12bit AMS AS5048 magnetic sensor over I2C interface */ +MagneticSensorI2CConfig_s AS5048_I2C = { + .chip_address = 0x40, // highly configurable. if A1 and A2 are held low, this is probable value + .clock_speed = 1000000, + .bit_resolution = 14, + .angle_register = 0xFE, + .data_start_bit = 15 +}; + +#endif diff --git a/src/MagneticSensorI2C.cpp b/src/MagneticSensorI2C.cpp index 92137048..38ccb0f3 100644 --- a/src/MagneticSensorI2C.cpp +++ b/src/MagneticSensorI2C.cpp @@ -28,11 +28,24 @@ MagneticSensorI2C::MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, } -MagneticSensorI2C MagneticSensorI2C::AS5600() { - MagneticSensorI2C* sensor = new MagneticSensorI2C(0x36, 12, 0x0E, 4); - return *sensor; -} +MagneticSensorI2C::MagneticSensorI2C(MagneticSensorI2CConfig_s config){ + chip_address = config.chip_address; + // angle read register of the magnetic sensor + angle_register_msb = config.angle_register; + // register maximum value (counts per revolution) + cpr = pow(2, config.bit_resolution); + + int bits_used_msb = config.data_start_bit - 7; + lsb_used = config.bit_resolution - bits_used_msb; + // extraction masks + lsb_mask = (uint8_t)( (2 << lsb_used) - 1 ); + msb_mask = (uint8_t)( (2 << bits_used_msb) - 1 ); + clock_speed = 400000; + sda_pin = SDA; + scl_pin = SCL; + +} void MagneticSensorI2C::init(){ diff --git a/src/MagneticSensorI2C.h b/src/MagneticSensorI2C.h index d4455abf..74b01cde 100644 --- a/src/MagneticSensorI2C.h +++ b/src/MagneticSensorI2C.h @@ -6,6 +6,13 @@ #include "FOCutils.h" #include "Sensor.h" +struct MagneticSensorI2CConfig_s { + int chip_address; + long clock_speed; + int bit_resolution; + int angle_register; + int data_start_bit; +}; class MagneticSensorI2C: public Sensor{ public: @@ -18,6 +25,12 @@ class MagneticSensorI2C: public Sensor{ */ MagneticSensorI2C(uint8_t _chip_address, int _bit_resolution, uint8_t _angle_register_msb, int _msb_bits_used); + /** + * MagneticSensorI2C class constructor + * @param config I2C config + */ + MagneticSensorI2C(MagneticSensorI2CConfig_s config); + static MagneticSensorI2C AS5600(); /** sensor initialise pins */ diff --git a/src/MagneticSensorSPI.cpp b/src/MagneticSensorSPI.cpp index f8d56999..df506e09 100644 --- a/src/MagneticSensorSPI.cpp +++ b/src/MagneticSensorSPI.cpp @@ -5,7 +5,7 @@ // _bit_resolution sensor resolution bit number // _angle_register - (optional) angle read register - default 0x3FFF MagneticSensorSPI::MagneticSensorSPI(int cs, float _bit_resolution, int _angle_register){ - // chip select pin + chip_select_pin = cs; // angle read register of the magnetic sensor angle_register = _angle_register ? _angle_register : DEF_ANGLE_REGISTAR; @@ -21,25 +21,21 @@ MagneticSensorSPI::MagneticSensorSPI(int cs, float _bit_resolution, int _angle_r } -MagneticSensorSPI MagneticSensorSPI::MA730(int cs) { - MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0x0000); - sensor->spi_mode = SPI_MODE0; - sensor->command_parity_bit = -1; // parity bit insertion not implemented - sensor->command_rw_bit = -1; // rw bit not required for angle - sensor->data_start_bit = 15; - return *sensor; -} - -MagneticSensorSPI MagneticSensorSPI::AS5147(int cs) { - MagneticSensorSPI* sensor = new MagneticSensorSPI(cs, 14, 0xCFFF); - sensor->spi_mode = SPI_MODE1; - sensor->command_parity_bit = 15; - sensor->command_rw_bit = 14; - sensor->data_start_bit = 13; - return *sensor; +MagneticSensorSPI::MagneticSensorSPI(MagneticSensorSPIConfig_s config, int cs){ + chip_select_pin = cs; + // angle read register of the magnetic sensor + angle_register = config.angle_register ? config.angle_register : DEF_ANGLE_REGISTAR; + // register maximum value (counts per revolution) + cpr = pow(2, config.bit_resolution); + spi_mode = config.spi_mode; + clock_speed = config.clock_speed; + bit_resolution = config.bit_resolution; + + command_parity_bit = config.command_parity_bit; // for backwards compatibilty + command_rw_bit = config.command_rw_bit; // for backwards compatibilty + data_start_bit = config.data_start_bit; // for backwards compatibilty } - void MagneticSensorSPI::init(){ // 1MHz clock (AMS should be able to accept up to 10MHz) settings = SPISettings(clock_speed, MSBFIRST, spi_mode); @@ -174,10 +170,10 @@ word MagneticSensorSPI::read(word angle_register){ word command = angle_register; - if (command_rw_bit > -1) { + if (command_rw_bit > 0) { command = angle_register | (1 << command_rw_bit); } - if (command_parity_bit > -1) { + if (command_parity_bit > 0) { //Add a parity bit on the the MSB command |= ((word)spiCalcEvenParity(command) << command_parity_bit); } diff --git a/src/MagneticSensorSPI.h b/src/MagneticSensorSPI.h index c142fc77..49db4c40 100644 --- a/src/MagneticSensorSPI.h +++ b/src/MagneticSensorSPI.h @@ -8,6 +8,16 @@ #define DEF_ANGLE_REGISTAR 0x3FFF +struct MagneticSensorSPIConfig_s { + int spi_mode; + long clock_speed; + int bit_resolution; + int angle_register; + int data_start_bit; + int command_rw_bit; + int command_parity_bit; +}; + class MagneticSensorSPI: public Sensor{ public: /** @@ -17,9 +27,12 @@ class MagneticSensorSPI: public Sensor{ * @param angle_register (optional) angle read register - default 0x3FFF */ MagneticSensorSPI(int cs, float bit_resolution, int angle_register = 0); - - static MagneticSensorSPI MA730(int cs); - static MagneticSensorSPI AS5147(int cs); + /** + * MagneticSensorSPI class constructor + * @param config SPI config + * @param cs SPI chip select pin + */ + MagneticSensorSPI(MagneticSensorSPIConfig_s config, int cs); /** sensor initialise pins */ void init(); diff --git a/src/SimpleFOC.h b/src/SimpleFOC.h index 4dc9cd8b..d8a7658f 100644 --- a/src/SimpleFOC.h +++ b/src/SimpleFOC.h @@ -94,5 +94,6 @@ void loop() { #include "MagneticSensorAnalog.h" #include "HallSensor.h" #include "BLDCMotor.h" +#include "Hardware.h" #endif