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 eb94a753..38ccb0f3 100644 --- a/src/MagneticSensorI2C.cpp +++ b/src/MagneticSensorI2C.cpp @@ -22,13 +22,35 @@ 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(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(){ //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 16b9fa51..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: @@ -17,8 +24,15 @@ 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); - + /** + * MagneticSensorI2C class constructor + * @param config I2C config + */ + MagneticSensorI2C(MagneticSensorI2CConfig_s config); + + static MagneticSensorI2C AS5600(); + /** sensor initialise pins */ void init(); @@ -40,8 +54,17 @@ class MagneticSensorI2C: public Sensor{ /** returns 1 because it is the absolute sensor */ int hasAbsoluteZero() override; /** returns 0 maning it doesn't need search for absolute zero */ + int needsAbsoluteZeroSearch() override; + + /* 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..df506e09 100644 --- a/src/MagneticSensorSPI.cpp +++ b/src/MagneticSensorSPI.cpp @@ -5,29 +5,49 @@ // _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; // register maximum value (counts per revolution) cpr = pow(2,_bit_resolution); - + spi_mode = SPI_MODE1; + clock_speed = 1000000; + bit_resolution = _bit_resolution; + + command_parity_bit = 15; // for backwards compatibilty + command_rw_bit = 14; // for backwards compatibilty + data_start_bit = 13; // for backwards compatibilty + } +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(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 +97,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 +167,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_rw_bit > 0) { + command = angle_register | (1 << command_rw_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 +199,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); @@ -195,9 +207,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 (( ( left_byte & 0xFF ) << 8 ) | ( right_byte & 0xFF )) & ~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 f40ea91c..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,7 +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); - + /** + * MagneticSensorSPI class constructor + * @param config SPI config + * @param cs SPI chip select pin + */ + MagneticSensorSPI(MagneticSensorSPIConfig_s config, int cs); /** sensor initialise pins */ void init(); @@ -40,7 +55,14 @@ class MagneticSensorSPI: public Sensor{ /** returns 1 because it is the absolute sensor */ int hasAbsoluteZero() override; /** returns 0 maning it doesn't need search for absolute zero */ + int needsAbsoluteZeroSearch() override; + + // 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 +94,11 @@ 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 bit_resolution; //!< the number of bites of angle data + int command_parity_bit; //!< the bit where parity 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 }; 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