diff --git a/Examples/Arduino/A1335_allegro b/Examples/Arduino/A1335_allegro new file mode 160000 index 0000000..f781cec --- /dev/null +++ b/Examples/Arduino/A1335_allegro @@ -0,0 +1 @@ +Subproject commit f781cec322d7cd2a3677e1c273174ea00bc047e6 diff --git a/Examples/Arduino/a1335_example/.gitignore b/Examples/Arduino/a1335_example/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/Examples/Arduino/a1335_example/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/Examples/Arduino/a1335_example/.vscode/extensions.json b/Examples/Arduino/a1335_example/.vscode/extensions.json new file mode 100644 index 0000000..e80666b --- /dev/null +++ b/Examples/Arduino/a1335_example/.vscode/extensions.json @@ -0,0 +1,7 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ] +} diff --git a/Examples/Arduino/a1335_example/a1335_example.ino b/Examples/Arduino/a1335_example/a1335_example.ino new file mode 100644 index 0000000..728b9ea --- /dev/null +++ b/Examples/Arduino/a1335_example/a1335_example.ino @@ -0,0 +1,144 @@ +#include +#include +#include "A1335.h" + +#define kNOERROR 0 +#define kPRIMARYREADERROR 1 +#define kEXTENDEDREADTIMEOUTERROR 2 +#define kPRIMARYWRITEERROR 3 +#define kEXTENDEDWRITETIMEOUTERROR 4 +#define kCRCERROR 5 + +#define kUNABLETOCHANGEPROCESSORSTATE 6 + +const uint16_t ChipSelectPin = 5; +const uint16_t LEDPin = 13; + +const uint32_t WRITE = 0x40; +const uint32_t READ = 0x00; +const uint32_t COMMAND_MASK = 0xC0; +const uint32_t ADDRESS_MASK = 0x3F; + +unsigned long nextTime; +bool ledOn = false; + +bool includeCRC = false; +void setup() { + + uint16_t unused; + uint32_t flags; + uint16_t angle; + uint32_t flagsAndZeroOffset; + + SPI.begin(); + // put your setup code here, to run once: + Serial.begin(19200); + + while (!Serial); + + + pinMode(SS, OUTPUT); + digitalWrite(SS, HIGH); + + // Make sure all of the SPI pins are + // ready by doing a read + //PrimaryRead(ChipSelectPin, 0x0, unused); + + // Unlock the device + ExtendedWrite(ChipSelectPin, 0xFFFE, 0x27811F77); + + // Make sure the device is unlocked + ExtendedRead(ChipSelectPin, 0x22, flags); + if (!((flags & 0x0022) == 0x0020)) + { + Serial.println("Device is not Unlocked"); + } + + // Zero the angle + // Extended location 0x06 contains flags in the MSW and the Zero Angle values in the LSW + // so get both and zero out ZeroAngle + ExtendedRead(ChipSelectPin, 0x06, flagsAndZeroOffset); + flagsAndZeroOffset = (flagsAndZeroOffset & 0xFFFF0000); + ExtendedWrite(ChipSelectPin, 0x06, flagsAndZeroOffset); + + // Get the current angle. It is now without the ZeroAngle correction + PrimaryRead(ChipSelectPin, 0x20, angle); + + // Copy the read angle into location 0x5C preserving the flags + flagsAndZeroOffset = (flagsAndZeroOffset & 0xFFFF0000) | ((angle << 4) & 0x0000FFFF); + ExtendedWrite(ChipSelectPin, 0x06, flagsAndZeroOffset); + + /* uint16_t angle_read; + Serial.println("Init Complete"); + PrimaryRead(ChipSelectPin, 0x20, angle_read); + Serial.print("Angle= "); + Serial.println(angle_read); */ + + +} + +void loop() { + uint16_t angle; + uint16_t temperature; + uint16_t fieldStrength; + + // Every second, read the angle, temperature and field strength + if (nextTime < millis()) + { + if (PrimaryRead(ChipSelectPin, 0x20, angle) == kNOERROR) + { + if (CalculateParity(angle)) + { + Serial.print("Angle = "); + Serial.print((float)(angle & 0x0FFF) * 360.0 / 4096.0); + Serial.println(" Degrees"); + } + else + { + Serial.println("Parity error on Angle read"); + } + } + else + { + Serial.println("Unable to read Angle"); + } + + if (PrimaryRead(ChipSelectPin, 0x28, temperature) == kNOERROR) + { + Serial.print("Temperature = "); + Serial.print(((float)(temperature & 0x0FFF) / 8.0) - 273.15); + Serial.println(" C"); + } + else + { + Serial.println("Unable to read Temperature"); + } + + if (PrimaryRead(ChipSelectPin, 0x2A, fieldStrength) == kNOERROR) + { + Serial.print("Field Strength = "); + Serial.print(fieldStrength & 0x0FFF); + Serial.println(" Gauss"); + } + else + { + Serial.println("Unable to read Field Strength"); + } + + nextTime = millis() + 500L; + + // Blink the LED every half second + if (ledOn) + { + digitalWrite(LEDPin, LOW); + ledOn = false; + } + else + { + digitalWrite(LEDPin, HIGH); + ledOn = true; + } + } +} + +} diff --git a/Examples/Arduino/a1335_example/include/README b/Examples/Arduino/a1335_example/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/Examples/Arduino/a1335_example/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/Examples/Arduino/a1335_example/lib/A1335/A1335.cpp b/Examples/Arduino/a1335_example/lib/A1335/A1335.cpp new file mode 100644 index 0000000..f9c9e2d --- /dev/null +++ b/Examples/Arduino/a1335_example/lib/A1335/A1335.cpp @@ -0,0 +1,342 @@ +/*************************************************** + Arduino library for the Allegro A1335 Magnetic angle sensor + The A1335 sensor detects the absolute angular position of a + permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + + * by Florian von Bertrab + ****************************************************/ + +#include "A1335.h" + + +bytes_2::bytes_2(){ + data.integer = 0; +} + +bytes_2::bytes_2(int16_t integ){ + data.integer = integ; +} + +int16_t& bytes_2::in(){ + return data.integer; +} + +byte& bytes_2::lsBy(byte n){ + if (n > 1) { + n = 1; + } else if (n < 0) { + n = 0; + } + return data.bytes[n]; +} + +byte& bytes_2::msBy(byte n){ + if (n > 1) { + n = 1; + } else if (n < 0) { + n = 0; + } + return data.bytes[1-n]; +} + +bytes_4::bytes_4(){ + data.integer = 0; +} + +bytes_4::bytes_4(int32_t integ){ + data.integer = integ; +} + +int32_t& bytes_4::in(){ + return data.integer; +} + +byte& bytes_4::lsBy(byte n){ + if (n > 3) { + n = 3; + } else if (n < 0) { + n = 0; + } + return data.bytes[n]; +} + +byte& bytes_4::msBy(byte n){ + if (n > 3) { + n = 3; + } else if (n < 0) { + n = 0; + } + return data.bytes[3-n]; +} + +//--- Normal Write Registers ---// + +const byte EWA = 0x02; // Extended Write Address +const byte EWD = 0x04; // Extended Write Data +const byte EWCS = 0x08; // Extended Write Control and Status +const byte ERA = 0x0A; // Extended Read Address +const byte ERCS = 0x0C; // Extended Read Control and Status +const byte ERD = 0x0E; // Extended Read Data +const byte CTRL = 0x1E; // Device control +const byte ANG = 0x20; // Current angle and related data +const byte STA = 0x22; // Device status +const byte ERR = 0x24; // Device error status +const byte XERR = 0x26; // Extended error status +const byte TSEN = 0x28; // Temperature sensor data +const byte FIELD = 0x2A; // Magnetic field strength +const byte ERM = 0x34; // Device error status masking +const byte XERM = 0x36; // Extended error status masking + +//--- Extended Write Registers ---// + +const int16_t ORATE = 0xFFD0; // Output Rate + + +// Control bytes and their respective keycodes: + +// CTRL(0x1E) KEY(0x1F) +// Processor State +const byte ipm[] = { B10000000, 0x46 }; // Idle mode +const byte rpm[] = { B11000000, 0x46 }; // Run mode +// Hard Reset +const byte hre[] = { B00100000, 0xB9 }; // Hard reset +// Soft Reset +const byte sre[] = { B00010000, 0xB9 }; // Soft reset +// Clear STA +const byte csta[] = { B00000100, 0x46 }; // Clear (STA) registers +// Hard Reset +const byte cxerr[] = { B00000010, 0x46 }; // Clear (XERR) registers +// Hard Reset +const byte cerr[] = { B00000001, 0x46 }; // Clear (ERR) registers + + +// Angle Register read masks + +// ANG(0x20) ANG+1(0x21) +// Register Identifier Code +const byte ria[] = { B10000000, B00000000}; // Always 0 +// Error Flag +const byte efa[] = { B01000000, B00000000}; // At least one error in register 0x24 +// New Flag +const byte nfa[] = { B00100000, B00000000}; // A new angle is in the angle register +// Parity +const byte par[] = { B00010000, B00000000}; // Odd parity bit for the whole register +// Angle +const byte ang[] = { B00001111, B11111111}; // Encoded angle reading (n * 360/4096 = angle in deg.) + + +// Status Register read masks + +// STA(0x20) STA+1(0x21) +// Register Identifier Code +const byte ris[] = { B11110000, B00000000}; // Always 1000 +// Power-On Reset Flag +const byte por[] = { B00001000, B00000000}; // There was a power-on reset since last field reset +// Soft Reset Flag +const byte srf[] = { B00000100, B00000000}; // There was a soft reset since last field reset +// New Flag +const byte nfs[] = { B00000010, B00000000}; // A new angle is in the angle register +// Current Error Flag +const byte efs[] = { B00000001, B00000000}; // At least one error in register 0x24 +// Processor Processing Status +const byte mps[] = { B00000000, B11110000}; // 0000 Booting; 0001 Idle or Processing angles; 1110 Self-testmode +// Processor Phase Status +const byte phase[] = { B00000000, B00001111}; // 0000 Idle; 0001 Processing angles; Only in Self-test mode [0100 Built in self test; 0110 ROM checksum; 0111 CVH self test] + + +// Temperature Register read masks + +// TSEN(0x28) TSEN+1(0x29) +// Register Identifier Code +const byte rit[] = { B11110000, B00000000}; // Always 1111 +// Temperature +const byte temp[] = { B00001111, B11111111}; // Encoded temperature reading (n / 8 = temperature in K) + + +// Field Strenght Register read masks + +// FIELD(0x28) FIELD+1(0x29) +// Register Identifier Code +const byte rif[] = { B11110000, B00000000}; // Always 1110 +// Magnetic field strenght +const byte field[] = { B00001111, B11111111}; // Magnetic field strenght reading (n = field strenght in Gauss (1/10000 T)) + + +A1335::A1335(){ + +} + +int16_t A1335::getAddress(){ // returns I2C address of the sensor + return address; +} + +byte A1335::getProcessorState(){ // returns current processor state of the sensor + return processorState; +} + +byte A1335::getOutputRate(){ // returns the current sample rate of the sensor + return outputRate; +} + +byte A1335::start(int16_t address_){ // Initializes the sensor at the address given and fills the private variables + Wire.beginTransmission(address); + byte error = Wire.endTransmission(); + if (error) { + processorState = 4; + return error; + } + address = address_; + bytes_2 state(normalRead(STA)); + bytes_4 orate(extendedRead(ORATE)); + + byte processing_status = (state.msBy(1) & mps[1]) >> 4; + byte processing_phase = (state.msBy(1) & phase[1]) >> 0; + switch (processing_status) { + case B00000000: + processorState = 0; + break; + case B00000001: + if (processing_phase == 0){ + processorState = 1; + } else { + processorState = 2; + } + break; + case B00001110: + processorState = 3; + break; + } + outputRate = orate.msBy(3); + delay(1); + return error; +} + +double A1335::readAngle(){ // returns Angle in Degrees + return double(readAngleRaw()) * 360.0 / 4096.0; +} +uint16_t A1335::readAngleRaw(){ // returns raw angle data + bytes_2 angReg(normalRead(ANG)); + + int16_t parityCheck = angReg.in(); + parityCheck ^= parityCheck >> 8; + parityCheck ^= parityCheck >> 4; + parityCheck ^= parityCheck >> 2; + parityCheck ^= parityCheck >> 1; + parityCheck &= 1; // parity Check now contains the parity of all bits in angReg + if(!parityCheck) { // odd Parity in this register => a 0 means an error + return 0; + } + + angReg.msBy(0) &= ang[0]; // mutes bits, that dont contain the angle data + return angReg.in(); +} + +double A1335::readTemp(){ // returns temperature in Kelvin + return double(readTempRaw())/8.0; +} + +uint16_t A1335::readTempRaw(){ // returns raw temperature data + bytes_2 tempReg(normalRead(TSEN)); + tempReg.msBy(0) &= temp[0]; // mutes bits, that dont contain temperature data + return tempReg.in(); +} + +double A1335::readField(){ // returns field strenght in Tesla + return double(readFieldRaw())/10000.0; +} + +uint16_t A1335::readFieldRaw(){ // returns raw field strenght data + bytes_2 fieldReg(normalRead(FIELD)); + fieldReg.msBy(0) &= field[0]; // mutes bits, that dont contain temperature data + return fieldReg.in(); +} + +byte A1335::readOutputRate(){ // reads the log2() of the sample rate + bytes_4 oRate(extendedRead(ORATE)); + return oRate.msBy(3); // !!! I don't know yet, which byte holds the output rate !!! +} + +byte A1335::setOutputRate(byte rate){ // sets the log2() of the sample rate => (ORate = 2^rate) + if (rate < 0) { + rate = 0; + } else if (rate >=8) { + rate = 7; + } + bytes_2 idle_mode; + bytes_2 run_mode; + for (int i = 0; i < 2; i++){ + idle_mode.msBy(i) = ipm[i]; + run_mode.msBy(i) = rpm[i]; + } + normalWrite(CTRL, idle_mode.in()); + delayMicroseconds(150); + bytes_4 oRate; + oRate.msBy(3) = rate; + extendedWrite(ORATE, oRate.in()); // !!! I don't know yet, which byte gets the output rate !!! + delayMicroseconds(50); + normalWrite(CTRL, run_mode.in()); + delayMicroseconds(150); +} + +byte A1335::normalWrite(byte reg, int16_t data){ // writes the 2 bytes in "bytes" to the register with address reg to the sensor with I2C address adress. + bytes_2 data_bytes(data); + Wire.beginTransmission(address); + Wire.write(reg); // choose target register + for (int i = 0; i<2; i++){ + Wire.write(data_bytes.msBy(i)); // Writes data MSB first + } + return Wire.endTransmission(); +} + +byte A1335::extendedWrite(int16_t reg, int32_t data){ // writes the 4 bytes in "bytes" to the extended register with address reg to the sensor with I2C address adress. + bytes_4 data_bytes(data); + Wire.beginTransmission(address); + Wire.write(EWA); // choose write Register + Wire.write(byte(reg >> 8)); // Fill with target address + Wire.write(byte(reg)); + for (int i = 0; i<4; i++){ + Wire.write(data_bytes.msBy(i)); // Writes data MSB first + } + Wire.write(0x80); // Confirm write + Wire.endTransmission(); + delayMicroseconds(10); + Wire.requestFrom(address, 1); + return Wire.read(); // Returns 1 if it works +} + +int16_t A1335::normalRead(byte reg){ + bytes_2 data; + Wire.beginTransmission(address); + Wire.write(reg); // choose target Register + Wire.endTransmission(); + Wire.requestFrom(address, 2); + for(int i=0; i< 2; i++){ + if (Wire.available()){ + data.msBy(i) = Wire.read(); // read data bytes + } + } + return data.in(); +} + +int32_t A1335::extendedRead(int16_t reg){ + bytes_4 data; + byte rstate; + Wire.beginTransmission(address); + Wire.write(ERA); // choose write Register + Wire.write(byte(reg >> 8)); // Fill with target address + Wire.write(byte(reg)); + Wire.write(0x80); // Confirm read + Wire.endTransmission(); + delayMicroseconds(10); + Wire.requestFrom(address,5); + rstate = Wire.read(); // Reads status byte + for(int i=0; i < 4; i++){ + if (Wire.available()){ + data.msBy(i) = Wire.read(); // Reads data bytes + } + } + return data.in(); +} + + diff --git a/Examples/Arduino/a1335_example/lib/A1335/A1335.h b/Examples/Arduino/a1335_example/lib/A1335/A1335.h new file mode 100644 index 0000000..a779d15 --- /dev/null +++ b/Examples/Arduino/a1335_example/lib/A1335/A1335.h @@ -0,0 +1,99 @@ +/*************************************************** + Arduino library for the Allegro A1335 Magnetic angle sensor + The A1335 sensor detects the absolute angular position of a + permanent magnet, typically a diametrically + magnetized cylinder on the rotating shaft. + + * by Florian von Bertrab + ****************************************************/ + +#ifndef A1335_H +#define A1335_H + +#if (ARDUINO >= 100) + #include "Arduino.h" +#else + #include "WProgram.h" +#endif +#include + +class bytes_2 { // allows easy conversion from two bytes in a given order to a 16 bit int. +public: + bytes_2(); + bytes_2(int16_t integ); + + int16_t& in(); + byte& lsBy(byte n); + byte& msBy(byte n); + +private: + union { + int16_t integer; + byte bytes[2]; + }data; +}; + +class bytes_4 { // allows easy conversion from four bytes in a given order to a 32 bit int. + +public: + bytes_4(); + bytes_4(int32_t integ); + + int32_t& in(); + byte& lsBy(byte n); + byte& msBy(byte n); + +private: + union { + int32_t integer; + byte bytes[4]; + }data; +}; + +class A1335 { +public: + A1335(); + + byte start(int16_t address_); // starts the sensor at the given address + + int16_t getAddress(); // returns I2C address + byte getProcessorState(); // returns processor state: + // 0 = booting; 1 = idle; 2 = running; 3 = self-test mode; 4 = not found + + byte getOutputRate(); // returns the log2() of the samperate. E.g. 3 would mean 8 samples per data point. + + + double readAngle(); // returns the angle in degrees + + uint16_t readAngleRaw(); // returns raw angle data (4096 = 360°) + + double readTemp(); // returns temperature in Kelvin + + uint16_t readTempRaw(); // returns raw temperature data 8 = 1 K + + double readField(); // returns field strenght in Tesla + + uint16_t readFieldRaw(); // returns raw field strenght data 10 = 1mT + + + byte readOutputRate(); // reads the log2() of the sample rate. Does not really work yet! + + byte setOutputRate(byte rate);// sets the log2() of the sample rate => (ORate = 2^rate). Does not really work yet! + + byte normalWrite(byte reg, int16_t data); // writes 16 bit to a given register + + int16_t normalRead(byte reg); // reads 16 bit from a given register + + + byte extendedWrite(int16_t reg, int32_t data); // writes 32 bit to a given extended register + + int32_t extendedRead(int16_t reg); // reads 32 bit from a given extended register + + +private: + int16_t address = 0x0C; // I2C address + byte processorState = 4; // 0 = booting; 1 = idle; 2 = running; 3 = self-test mode; 4 = not found + byte outputRate = 0; // log2() of the sample rate in the EEPROM +}; + +#endif //A1335_H diff --git a/Examples/Arduino/a1335_example/lib/A1335/README.md b/Examples/Arduino/a1335_example/lib/A1335/README.md new file mode 100644 index 0000000..dd27422 --- /dev/null +++ b/Examples/Arduino/a1335_example/lib/A1335/README.md @@ -0,0 +1,8 @@ +# Allegro-A1335-Sensor-library +A C++ library for communicating with the A 1335 hall effect encoder + +Arduino library for the Allegro A1335 Magnetic angle sensor. +The A1335 sensor detects the absolute angular position of a permanent magnet, typically a diametrically magnetized cylinder on the rotating shaft. + +* by Florian von Bertrab + diff --git a/Examples/Arduino/a1335_example/lib/A1335_allegro b/Examples/Arduino/a1335_example/lib/A1335_allegro new file mode 160000 index 0000000..f781cec --- /dev/null +++ b/Examples/Arduino/a1335_example/lib/A1335_allegro @@ -0,0 +1 @@ +Subproject commit f781cec322d7cd2a3677e1c273174ea00bc047e6 diff --git a/Examples/Arduino/a1335_example/lib/README b/Examples/Arduino/a1335_example/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/Examples/Arduino/a1335_example/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/Examples/Arduino/a1335_example/platformio.ini b/Examples/Arduino/a1335_example/platformio.ini new file mode 100644 index 0000000..2be04f8 --- /dev/null +++ b/Examples/Arduino/a1335_example/platformio.ini @@ -0,0 +1,27 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:esp32doit-devkit-v1] +platform = espressif32 +board = esp32doit-devkit-v1 +framework = arduino +upload_speed = 115200 +uploade_port = COM7 +upload_protocol = esptool +monitor_speed = 19200 +lib_deps = + +[env:SAMC21] +platform = atmelsam +framework = arduino +board = samc21_xpro +upload_protocol = cmsis-dap +upload_port = COM3 +lib_deps = https://github.com/hugllc/samc21_can.git diff --git a/Examples/Arduino/a1335_example/src/main.cpp b/Examples/Arduino/a1335_example/src/main.cpp new file mode 100644 index 0000000..d8a8d27 --- /dev/null +++ b/Examples/Arduino/a1335_example/src/main.cpp @@ -0,0 +1,569 @@ +#include +#include + +#define kNOERROR 0 +#define kPRIMARYREADERROR 1 +#define kEXTENDEDREADTIMEOUTERROR 2 +#define kPRIMARYWRITEERROR 3 +#define kEXTENDEDWRITETIMEOUTERROR 4 +#define kCRCERROR 5 + +#define kUNABLETOCHANGEPROCESSORSTATE 6 + +const uint16_t ChipSelectPin = 5; +const uint16_t LEDPin = 13; + +const uint32_t WRITE = 0x40; +const uint32_t READ = 0x00; +const uint32_t COMMAND_MASK = 0xC0; +const uint32_t ADDRESS_MASK = 0x3F; + +unsigned long nextTime; +bool ledOn = false; + +bool includeCRC = false; + +/* + * CalculateParity + * + * From the 16 bit input, calculate the parity + */ +bool CalculateParity(uint16_t input) +{ + uint16_t count = 0; + + // Count up the number of 1s in the input + for (int index = 0; index < 16; ++index) + { + if ((input & 1) == 1) + { + ++count; + } + + input >>= 1; + } + + // return true if there is an odd number of 1s + return (count & 1) != 0; +} + +/* + * CalculateCRC + * + * Take the 16bit input and generate a 4bit CRC + * Polynomial = x^4 + x^1 + 1 + * LFSR preset to all 1's + */ +uint8_t CalculateCRC(uint16_t input) +{ + bool CRC0 = true; + bool CRC1 = true; + bool CRC2 = true; + bool CRC3 = true; + int i; + bool DoInvert; + uint16_t mask = 0x8000; + + for (i = 0; i < 16; ++i) + { + DoInvert = ((input & mask) != 0) ^ CRC3; // XOR required? + + CRC3 = CRC2; + CRC2 = CRC1; + CRC1 = CRC0 ^ DoInvert; + CRC0 = DoInvert; + mask >>= 1; + } + + return (CRC3 ? 8U : 0U) + (CRC2 ? 4U : 0U) + (CRC1 ? 2U : 0U) + (CRC0 ? 1U : 0U); +} + + +/* + * PrimaryRead + * + * Read from the primary serial registers + */ +uint16_t PrimaryRead(uint16_t cs, uint16_t address, uint16_t& value) +{ + if (includeCRC) + { + uint8_t crcValue; + uint8_t crcCommand; + + SPI.beginTransaction(SPISettings(500000, MSBFIRST, SPI_MODE3)); + + // On the Teensy, SPI0_CTAR0 is used to describe the SPI transaction for transfer (byte) + // while SPI0_CTAR1 is used to describe the SPI transaction for transfer16. + // To do a 20 bit transfer, change the length of the transaction to 4 bits for transfer + // and do a transfer16 followed by a transfer. + //uint32_t oldSPI0_CTAR0 = SPI0_CTAR0; + // SPI0_CTAR0 = (SPI0_CTAR0 & 0x87FFFFFF) | SPI_CTAR_FMSZ(3); // using SPI0_CTAR0 to send 4 bits + + // Combine the register address and the command into one byte + uint16_t command = ((address & ADDRESS_MASK) | READ) << 8; + + crcCommand = CalculateCRC(command); + + // take the chip select low to select the device + digitalWrite(cs, LOW); + + // send the device the register you want to read + SPI.transfer16(command); + SPI.transfer(crcCommand); + + digitalWrite(cs, HIGH); + digitalWrite(cs, LOW); + + // send the command again to read the contents + value = SPI.transfer16(command); + crcValue = SPI.transfer(crcCommand); + + // take the chip select high to de-select + digitalWrite(cs, HIGH); + + // Restore the 8 bit description + //SPI0_CTAR0 = oldSPI0_CTAR0; + + SPI.endTransaction(); + + // Check the CRC value + if (CalculateCRC(value) != crcValue) + { + return kCRCERROR; + } + } + else + { + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); + + // Combine the register address and the command into one byte + uint16_t command = ((address & ADDRESS_MASK) | READ) << 8; + + // take the chip select low to select the device + digitalWrite(cs, LOW); + + // send the device the register you want to read + SPI.transfer16(command); + + digitalWrite(cs, HIGH); + digitalWrite(cs, LOW); + + // send the command again to read the contents + value = SPI.transfer16(command); + + // take the chip select high to de-select + digitalWrite(cs, HIGH); + + SPI.endTransaction(); + } + + return kNOERROR; +} + +/* + * PrimaryWrite + * + * Write to the primary serial registers + */ +uint16_t PrimaryWrite(uint16_t cs, uint16_t address, uint16_t value) +{ + if (includeCRC) + { + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); + + // On the Teensy, SPI0_CTAR0 is used to describe the SPI transaction for transfer + // while SPI0_CTAR1 is used to describe the SPI transaction for transfer16. + // To do a 20 bit transfer, change the length of the transaction to 4 bits for transfer + // and do a transfer16 followed by a transfer. + //uint32_t oldSPI0_CTAR0 = SPI0_CTAR0; + // SPI0_CTAR0 = (SPI0_CTAR0 & 0x87FFFFFF) | SPI_CTAR_FMSZ(3); // using SPI0_CTAR0 to send 4 bits + + // Combine the register address and the command into one byte + uint16_t command = (((address & ADDRESS_MASK) | WRITE) << 8) | ((value >> 8) & 0x0FF); + uint8_t crcCommand = CalculateCRC(command); + + // take the chip select low to select the device: + digitalWrite(cs, LOW); + + SPI.transfer16(command); // Send most significant byte of register data + SPI.transfer(crcCommand); // Send the crc + + // take the chip select high to de-select: + digitalWrite(cs, HIGH); + + command = ((((address + 1) & ADDRESS_MASK) | WRITE) << 8 ) | (value & 0x0FF); + crcCommand = CalculateCRC(command); + + // take the chip select low to select the device: + digitalWrite(cs, LOW); + + SPI.transfer16(command); // Send least significant byte of register data + SPI.transfer(crcCommand); // Send the crc + + // take the chip select high to de-select: + digitalWrite(cs, HIGH); + + // Restore the 8 bit description + //SPI0_CTAR0 = oldSPI0_CTAR0; + + SPI.endTransaction(); + } + else + { + SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); + + // Combine the register address and the command into one byte + uint16_t command = ((address & ADDRESS_MASK) | WRITE) << 8; + + // take the chip select low to select the device: + digitalWrite(cs, LOW); + + SPI.transfer16(command | ((value >> 8) & 0x0FF)); // Send most significant byte of register data + + // take the chip select high to de-select: + digitalWrite(cs, HIGH); + + command = (((address + 1) & ADDRESS_MASK) | WRITE) << 8; + // take the chip select low to select the device: + digitalWrite(cs, LOW); + + SPI.transfer16(command | (value & 0x0FF)); // Send least significant byte of register data + + // take the chip select high to de-select: + digitalWrite(cs, HIGH); + + SPI.endTransaction(); + } + + return kNOERROR; +} + +/* + * ExtendedRead + * + * Read from the SRAM, EEPROM, AUX or Extended Registers + */ +uint16_t ExtendedRead(uint16_t cs, uint16_t address, uint32_t& value) +{ + uint16_t results; + uint16_t readFlags; + uint32_t timeout; + uint16_t valueMSW; + uint16_t valueLSW; + uint32_t currentTime; + + // Write the address to the Extended Read Address register + results = PrimaryWrite(cs, 0x0A, address & 0xFFFF); + + if (results != kNOERROR) + { + return results; + } + + // Initiate the extended read + results = PrimaryWrite(cs, 0x0C, 0x8000); + + if (results != kNOERROR) + { + return results; + } + + timeout = millis() + 100L; + + do // Wait for the read to be complete + { + results = PrimaryRead(cs, 0x0C, readFlags); + + if (results != kNOERROR) + { + return results; + } + + // Make sure the read is not taking too long + currentTime = millis(); + if (timeout < currentTime) + { + return kEXTENDEDREADTIMEOUTERROR; + } + } while ((readFlags & 0x0001) != 0x0001); + + // Read the most significant word from the extended read data + results = PrimaryRead(cs, 0x0E, valueMSW); + + if (results != kNOERROR) + { + return results; + } + + // Read the least significant word from the extended read data + results = PrimaryRead(cs, 0x10, valueLSW); + + // Combine them + value = ((uint32_t)valueMSW << 16) + valueLSW; + + return results; +} + +/* + * ExtendedWrite + * + * Write to the SRAM, EEPROM, AUX or Extended Access Commands + */ +uint16_t ExtendedWrite(uint16_t cs, uint16_t address, uint32_t value) +{ + uint16_t results; + uint16_t writeFlags; + uint32_t timeout; + + // Write into the extended address register + results = PrimaryWrite(cs, 0x02, address & 0xFFFF); + + if (results != kNOERROR) + { + return results; + } + + // Write the MSW (Most significant word) into the high order write data register + results = PrimaryWrite(cs, 0x04, (value >> 16) & 0xFFFF); + + if (results != kNOERROR) + { + return results; + } + + // Write the LSW (Least significant word) into the low order write data register + results = PrimaryWrite(cs, 0x06, value & 0xFFFF); + + if (results != kNOERROR) + { + return results; + } + + // Start the write process + results = PrimaryWrite(cs, 0x08, 0x8000); + + if (results != kNOERROR) + { + return results; + } + + // If writing to the EEPROM, generate the Program + // Pulses on Vcc + if ((address >= 0x300) && (address < 0x320)) + { + // Send the Program Pulses + // Need hardware which this example does not have. + } + + timeout = millis() + 100; + + // Wait for the write to complete + do + { + results = PrimaryRead(cs, 0x08, writeFlags); + + if (results != kNOERROR) + { + return results; + } + + if (timeout < millis()) + { + return kEXTENDEDWRITETIMEOUTERROR; + } + } while ((writeFlags & 0x0001) != 0x0001); + + return results; +} + +/* + * SetProcessorStateToIdle + * + * Change the processor state to idle + * This is needed to write EEPROM, change ORATE or perform certain self tests + */ +uint16_t SetProcessorStateToIdle(uint8_t cs) +{ + uint16_t results; + uint16_t value; + + // Write the enter idle state command into the control register + results = PrimaryWrite(cs, 0x1F, 0x8046); + + if (results == kNOERROR) + { + delay(1); + + // Read the status register to see if the processor is in the idle state + results = PrimaryRead(cs, 0x22, value); + + if (results == kNOERROR) + { + if ((value & 0x00FF) != 0x0010) + { + return kUNABLETOCHANGEPROCESSORSTATE; + } + } + } + + return results; +} + +/* + * SetProcessorStateToRun + * + * Change the processor state to run + * This is needed to process angles + */ +uint16_t SetProcessorStateToRun(uint8_t cs) +{ + uint16_t results; + uint16_t value; + + // Write the enter idle state command into the control register + results = PrimaryWrite(cs, 0x1F, 0xC046); + + if (results == kNOERROR) + { + delay(1); + + // Read the status register to see if the processor is in the idle state + results = PrimaryRead(cs, 0x22, value); + + if (results == kNOERROR) + { + if ((value & 0x00FF) != 0x0011) + { + return kUNABLETOCHANGEPROCESSORSTATE; + } + } + } + + return results; +} + + + +void setup() { + + uint16_t unused; + uint32_t flags; + uint16_t angle; + uint32_t flagsAndZeroOffset; + + SPI.begin(); + // put your setup code here, to run once: + Serial.begin(19200); + + while (!Serial); + + + pinMode(SS, OUTPUT); + digitalWrite(SS, HIGH); + + // Make sure all of the SPI pins are + // ready by doing a read + //PrimaryRead(ChipSelectPin, 0x0, unused); + + // Unlock the device + ExtendedWrite(ChipSelectPin, 0xFFFE, 0x27811F77); + + // Make sure the device is unlocked + ExtendedRead(ChipSelectPin, 0x22, flags); + if (!((flags & 0x0022) == 0x0020)) + { + Serial.println("Device is not Unlocked"); + } + + // Zero the angle + // Extended location 0x06 contains flags in the MSW and the Zero Angle values in the LSW + // so get both and zero out ZeroAngle + ExtendedRead(ChipSelectPin, 0x06, flagsAndZeroOffset); + flagsAndZeroOffset = (flagsAndZeroOffset & 0xFFFF0000); + ExtendedWrite(ChipSelectPin, 0x06, flagsAndZeroOffset); + + // Get the current angle. It is now without the ZeroAngle correction + PrimaryRead(ChipSelectPin, 0x20, angle); + + // Copy the read angle into location 0x5C preserving the flags + flagsAndZeroOffset = (flagsAndZeroOffset & 0xFFFF0000) | ((angle << 4) & 0x0000FFFF); + ExtendedWrite(ChipSelectPin, 0x06, flagsAndZeroOffset); + + /* uint16_t angle_read; + Serial.println("Init Complete"); + PrimaryRead(ChipSelectPin, 0x20, angle_read); + Serial.print("Angle= "); + Serial.println(angle_read); */ + + +} + +void loop() { + uint16_t angle; + uint16_t temperature; + uint16_t fieldStrength; + + // Every second, read the angle, temperature and field strength + if (nextTime < millis()) + { + if (PrimaryRead(ChipSelectPin, 0x20, angle) == kNOERROR) + { + if (CalculateParity(angle)) + { + Serial.print("Angle = "); + Serial.print((float)(angle & 0x0FFF) * 360.0 / 4096.0); + Serial.println(" Degrees"); + } + else + { + Serial.println("Parity error on Angle read"); + } + } + else + { + Serial.println("Unable to read Angle"); + } + + if (PrimaryRead(ChipSelectPin, 0x28, temperature) == kNOERROR) + { + Serial.print("Temperature = "); + Serial.print(((float)(temperature & 0x0FFF) / 8.0) - 273.15); + Serial.println(" C"); + } + else + { + Serial.println("Unable to read Temperature"); + } + + if (PrimaryRead(ChipSelectPin, 0x2A, fieldStrength) == kNOERROR) + { + Serial.print("Field Strength = "); + Serial.print(fieldStrength & 0x0FFF); + Serial.println(" Gauss"); + } + else + { + Serial.println("Unable to read Field Strength"); + } + + nextTime = millis() + 500L; + + // Blink the LED every half second + if (ledOn) + { + digitalWrite(LEDPin, LOW); + ledOn = false; + } + else + { + digitalWrite(LEDPin, HIGH); + ledOn = true; + } + } +} + + + + + diff --git a/Examples/Arduino/a1335_example/test/README b/Examples/Arduino/a1335_example/test/README new file mode 100644 index 0000000..b94d089 --- /dev/null +++ b/Examples/Arduino/a1335_example/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/Examples/Arduino/esp32_angle_sensor/esp32_angle_sensor.ino b/Examples/Arduino/esp32_angle_sensor/esp32_angle_sensor.ino new file mode 100644 index 0000000..b19d633 --- /dev/null +++ b/Examples/Arduino/esp32_angle_sensor/esp32_angle_sensor.ino @@ -0,0 +1,21 @@ +#include + +AS5048A angleSensor(SS, false); + +void setup() +{ + Serial.begin(19200); + angleSensor.begin(); +} + +void loop() +{ + delay(100); + float val = angleSensor.getRotationInDegrees(); + Serial.print("\nGot rotation of: "); + Serial.println(val); + Serial.print("State: "); + angleSensor.printState(); + Serial.print("Errors: "); + Serial.println(angleSensor.getErrors()); +} diff --git a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.c b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.c index 3551a20..c05287c 100644 --- a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.c +++ b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.c @@ -1,440 +1,500 @@ -/* - * A1335.c - * - * Created: 24/07/2021 17:54:33 - * Author: Nick-XMG - */ -#include "A1335.h" - -#define kNOERROR 0 -#define kPRIMARYREADERROR 1 -#define kEXTENDEDREADTIMEOUTERROR 2 -#define kPRIMARYWRITEERROR 3 -#define kEXTENDEDWRITETIMEOUTERROR 4 -#define kCRCERROR 5 - -#define kUNABLETOCHANGEPROCESSORSTATE 6 - -const uint16_t ChipSelectPin = 5; -const uint16_t LEDPin = 13; - -const uint32_t WRITE = 0x40; -const uint32_t READ = 0x00; -const uint32_t COMMAND_MASK = 0xC0; -const uint32_t ADDRESS_MASK = 0x3F; - -unsigned long nextTime; -bool ledOn = false; -bool includeCRC = false; - -struct SPI_S A1 = { - .SPI_angleSensor_n = &SPI_1, +/* + * A1335.c + * + * Created: 24/07/2021 17:54:33 + * Author: Nick-XMG + */ +#include "A1335.h" + + + +//--- Normal Write Registers ---// +#define EWA (0x02U) // Extended Write Address +#define EWD (0x04U) // Extended Write Data +#define EWCS (0x08U) // Extended Write Control and Status +#define ERA (0x0AU) // Extended Read Address +#define ERCS (0x0CU) // Extended Read Control and Status +#define ERD (0x0EU) // Extended Read Data +#define CTRL (0x1EU) // Device control +#define ANG (0x20U) // Current angle and related data +#define STA (0x22U) // Device status +#define ERR (0x24U) // Device error status +#define XERR (0x26U) // Extended error status +#define TSEN (0x28U) // Temperature sensor data +#define FIELD (0x2AU) // Magnetic field strength +#define ERM (0x34U) // Device error status masking +#define XERM (0x36U) // Extended error status masking + +//--- Extended Write Registers ---// +#define ORATE (0xFFD0) // Output Rate + +//--- Errors ---// + +#define kNOERROR 0 +#define kPRIMARYREADERROR 1 +#define kEXTENDEDREADTIMEOUTERROR 2 +#define kPRIMARYWRITEERROR 3 +#define kEXTENDEDWRITETIMEOUTERROR 4 +#define kCRCERROR 5 +#define kUNABLETOCHANGEPROCESSORSTATE 6 + +const uint16_t ChipSelectPin = 5; +const uint16_t LEDPin = 13; + +const uint32_t WRITE = 0x40; +const uint32_t READ = 0x00; +const uint32_t COMMAND_MASK = 0xC0; +const uint32_t ADDRESS_MASK = 0x3F; + +unsigned long nextTime; +bool ledOn = false; +bool includeCRC = false; + +bool debugPrint = false; + +struct SPI_S A1 = { + .SPI_angleSensor_n = NULL, + .io = NULL, .state = 0, .SS_pin = Angle_SS, .tx_buffer = NULL, .rx_buffer = NULL, - -}; - -void angleSensor_init(struct spi_m_sync_descriptor *spi) -{ - spi_m_sync_get_io_descriptor(spi, &io); - spi_m_sync_enable(spi); - -} - -void angleSensor_State_Machine(struct SPI_S *Sn) -{ - uint16_t value; - switch(Sn->state){ - case 0: - angleSensor_init(Sn->SPI_angleSensor_n); - gpio_set_pin_level(Sn->SS_pin, true); - Sn->state++; - break; - case 1: - PrimaryRead(Sn->SS_pin, 0x20, &value); - break; - case 2: - break; - } -} - -/* - * CalculateParity - * - * From the 16 bit input, calculate the parity - */ -bool CalculateParity(uint16_t input) -{ - uint16_t count = 0; - - // Count up the number of 1s in the input - for (int index = 0; index < 16; ++index) + +}; + +void angleSensor_init(struct spi_m_sync_descriptor *spi, struct SPI_S *Sn) +{ + Sn->SPI_angleSensor_n = spi; + spi_m_sync_get_io_descriptor(Sn->SPI_angleSensor_n, &Sn->io); + spi_m_sync_enable(Sn->SPI_angleSensor_n); + gpio_set_pin_level(Sn->SS_pin, true); + if(Sn->io == NULL || Sn->SPI_angleSensor_n == NULL) { - if ((input & 1) == 1) - { - ++count; - } - - input >>= 1; + Sn->state = 4; + } else { + Sn->state = 1; } - - // return true if there is an odd number of 1s - return (count & 1) != 0; -} +} + +void angleSensor_State_Machine(struct SPI_S *Sn) +{ + volatile uint16_t angle; + switch(Sn->state){ + case 0: // Default un-initialized State + break; + case 1: // State After angleSensor_init. Configure Sensor + Sn->state++; + break; + case 2: // Syncronouse blocking read + PrimaryRead(Sn, 0x20, &angle); + if (CalculateParity(angle)) + { + volatile float read_angle = (float)(angle & 0x0FFF) * 360.0 / 4096.0; + printf("Angle = "); + printf("%f", read_angle); + printf(" Degrees\n\r"); + } + else + { + printf("Parity error on Angle read\n\r"); + } + break; + case 3: // Continuously Read Angle (DMA) + break; + case 4: // Error State + break; + } +} + +/* + * CalculateParity + * + * From the 16 bit input, calculate the parity + */ +bool CalculateParity(uint16_t input) +{ + uint16_t count = 0; + + // Count up the number of 1s in the input + for (int index = 0; index < 16; ++index) + { + if ((input & 1) == 1) + { + ++count; + } + + input >>= 1; + } + + // return true if there is an odd number of 1s + return (count & 1) != 0; +} + +/* + * CalculateCRC + * + * Take the 16bit input and generate a 4bit CRC + * Polynomial = x^4 + x^1 + 1 + * LFSR preset to all 1's + */ +uint8_t CalculateCRC(uint16_t input) +{ + bool CRC0 = true; + bool CRC1 = true; + bool CRC2 = true; + bool CRC3 = true; + int i; + bool DoInvert; + uint16_t mask = 0x8000; + + for (i = 0; i < 16; ++i) + { + DoInvert = ((input & mask) != 0) ^ CRC3; // XOR required? + + CRC3 = CRC2; + CRC2 = CRC1; + CRC1 = CRC0 ^ DoInvert; + CRC0 = DoInvert; + mask >>= 1; + } + + return (CRC3 ? 8U : 0U) + (CRC2 ? 4U : 0U) + (CRC1 ? 2U : 0U) + (CRC0 ? 1U : 0U); +} + +/* + * PrimaryRead + * + * Read from the primary serial registers + */ +uint16_t PrimaryRead(struct SPI_S *Sn, uint16_t address, uint16_t* value) +{ + + uint8_t in_buf[2], out_buf[2]; + uint16_t returnedVal; -/* - * CalculateCRC - * - * Take the 16bit input and generate a 4bit CRC - * Polynomial = x^4 + x^1 + 1 - * LFSR preset to all 1's - */ -uint8_t CalculateCRC(uint16_t input) -{ - bool CRC0 = true; - bool CRC1 = true; - bool CRC2 = true; - bool CRC3 = true; - int i; - bool DoInvert; - uint16_t mask = 0x8000; - - for (i = 0; i < 16; ++i) - { - DoInvert = ((input & mask) != 0) ^ CRC3; // XOR required? - - CRC3 = CRC2; - CRC2 = CRC1; - CRC1 = CRC0 ^ DoInvert; - CRC0 = DoInvert; - mask >>= 1; - } - - return (CRC3 ? 8U : 0U) + (CRC2 ? 4U : 0U) + (CRC1 ? 2U : 0U) + (CRC0 ? 1U : 0U); -} - -/* - * PrimaryRead - * - * Read from the primary serial registers - */ -uint16_t PrimaryRead(uint16_t cs, uint16_t address, uint16_t* value) -{ - uint16_t command = ((address & ADDRESS_MASK) | READ) << 8; - gpio_set_pin_level(Angle_SS, false); - - struct spi_msg msg; - - - spi_m_sync_transfer(Sn->SPI_angleSensor_n, ) - - - //SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); -// - //// Combine the register address and the command into one byte - //uint16_t command = ((address & ADDRESS_MASK) | READ) << 8; -// - //// take the chip select low to select the device - //digitalWrite(cs, LOW); -// - //// send the device the register you want to read - //SPI.transfer16(command); -// - //digitalWrite(cs, HIGH); - //digitalWrite(cs, LOW); -// - //// send the command again to read the contents - //value = SPI.transfer16(command); -// - //// take the chip select high to de-select - //digitalWrite(cs, HIGH); -// - //SPI.endTransaction(); - //} -// - return kNOERROR; -} - -/* - * PrimaryWrite - * - * Write to the primary serial registers - */ -uint16_t PrimaryWrite(uint16_t cs, uint16_t address, uint16_t value) -{ - //if (includeCRC) - //{ - //SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); -// - //// On the Teensy, SPI0_CTAR0 is used to describe the SPI transaction for transfer - //// while SPI0_CTAR1 is used to describe the SPI transaction for transfer16. - //// To do a 20 bit transfer, change the length of the transaction to 4 bits for transfer - //// and do a transfer16 followed by a transfer. - ////uint32_t oldSPI0_CTAR0 = SPI0_CTAR0; - //// SPI0_CTAR0 = (SPI0_CTAR0 & 0x87FFFFFF) | SPI_CTAR_FMSZ(3); // using SPI0_CTAR0 to send 4 bits -// - //// Combine the register address and the command into one byte - //uint16_t command = (((address & ADDRESS_MASK) | WRITE) << 8) | ((value >> 8) & 0x0FF); - //uint8_t crcCommand = CalculateCRC(command); -// - //// take the chip select low to select the device: - //digitalWrite(cs, LOW); -// - //SPI.transfer16(command); // Send most significant byte of register data - //SPI.transfer(crcCommand); // Send the crc -// - //// take the chip select high to de-select: - //digitalWrite(cs, HIGH); -// - //command = ((((address + 1) & ADDRESS_MASK) | WRITE) << 8 ) | (value & 0x0FF); - //crcCommand = CalculateCRC(command); -// - //// take the chip select low to select the device: - //digitalWrite(cs, LOW); -// - //SPI.transfer16(command); // Send least significant byte of register data - //SPI.transfer(crcCommand); // Send the crc -// - //// take the chip select high to de-select: - //digitalWrite(cs, HIGH); -// - //// Restore the 8 bit description - ////SPI0_CTAR0 = oldSPI0_CTAR0; -// - //SPI.endTransaction(); - //} - //else - //{ - //SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); -// - //// Combine the register address and the command into one byte - //uint16_t command = ((address & ADDRESS_MASK) | WRITE) << 8; -// - //// take the chip select low to select the device: - //digitalWrite(cs, LOW); -// - //SPI.transfer16(command | ((value >> 8) & 0x0FF)); // Send most significant byte of register data -// - //// take the chip select high to de-select: - //digitalWrite(cs, HIGH); -// - //command = (((address + 1) & ADDRESS_MASK) | WRITE) << 8; - //// take the chip select low to select the device: - //digitalWrite(cs, LOW); -// - //SPI.transfer16(command | (value & 0x0FF)); // Send least significant byte of register data -// - //// take the chip select high to de-select: - //digitalWrite(cs, HIGH); -// - //SPI.endTransaction(); - //} - - return kNOERROR; -} - -/* - * ExtendedRead - * - * Read from the SRAM, EEPROM, AUX or Extended Registers - */ -uint16_t ExtendedRead(uint16_t cs, uint16_t address, uint32_t value) -{ - //uint16_t results; - //uint16_t readFlags; - //uint32_t timeout; - //uint16_t valueMSW; - //uint16_t valueLSW; - //uint32_t currentTime; -// - //// Write the address to the Extended Read Address register - //results = PrimaryWrite(cs, 0x0A, address & 0xFFFF); -// - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// Initiate the extended read - //results = PrimaryWrite(cs, 0x0C, 0x8000); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //timeout = millis() + 100L; -// - //do // Wait for the read to be complete - //{ - //results = PrimaryRead(cs, 0x0C, readFlags); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// Make sure the read is not taking too long - //currentTime = millis(); - //if (timeout < currentTime) - //{ - //return kEXTENDEDREADTIMEOUTERROR; - //} - //} while ((readFlags & 0x0001) != 0x0001); - // - //// Read the most significant word from the extended read data - //results = PrimaryRead(cs, 0x0E, valueMSW); -// - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// Read the least significant word from the extended read data - //results = PrimaryRead(cs, 0x10, valueLSW); -// - //// Combine them - //value = ((uint32_t)valueMSW << 16) + valueLSW; -// - //return results; -} - -/* - * ExtendedWrite - * - * Write to the SRAM, EEPROM, AUX or Extended Access Commands - */ -uint16_t ExtendedWrite(uint16_t cs, uint16_t address, uint32_t value) -{ - //uint16_t results; - //uint16_t writeFlags; - //uint32_t timeout; -// - //// Write into the extended address register - //results = PrimaryWrite(cs, 0x02, address & 0xFFFF); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// Write the MSW (Most significant word) into the high order write data register - //results = PrimaryWrite(cs, 0x04, (value >> 16) & 0xFFFF); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// Write the LSW (Least significant word) into the low order write data register - //results = PrimaryWrite(cs, 0x06, value & 0xFFFF); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// Start the write process - //results = PrimaryWrite(cs, 0x08, 0x8000); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //// If writing to the EEPROM, generate the Program - //// Pulses on Vcc - //if ((address >= 0x300) && (address < 0x320)) - //{ - //// Send the Program Pulses - //// Need hardware which this example does not have. - //} -// - //timeout = millis() + 100; -// - //// Wait for the write to complete - //do - //{ - //results = PrimaryRead(cs, 0x08, writeFlags); - // - //if (results != kNOERROR) - //{ - //return results; - //} -// - //if (timeout < millis()) - //{ - //return kEXTENDEDWRITETIMEOUTERROR; - //} - //} while ((writeFlags & 0x0001) != 0x0001); -// - //return results; -} - -/* - * SetProcessorStateToIdle - * - * Change the processor state to idle - * This is needed to write EEPROM, change ORATE or perform certain self tests - */ -uint16_t SetProcessorStateToIdle(uint8_t cs) -{ - //uint16_t results; - //uint16_t value; - // - //// Write the enter idle state command into the control register - //results = PrimaryWrite(cs, 0x1F, 0x8046); - // - //if (results == kNOERROR) - //{ - //delay(1); -// - //// Read the status register to see if the processor is in the idle state - //results = PrimaryRead(cs, 0x22, value); - // - //if (results == kNOERROR) - //{ - //if ((value & 0x00FF) != 0x0010) - //{ - //return kUNABLETOCHANGEPROCESSORSTATE; - //} - //} - //} - // - //return results; -} - -/* - * SetProcessorStateToRun - * - * Change the processor state to run - * This is needed to process angles - */ -uint16_t SetProcessorStateToRun(uint8_t cs) -{ - //uint16_t results; - //uint16_t value; - // - //// Write the enter idle state command into the control register - //results = PrimaryWrite(cs, 0x1F, 0xC046); - // - //if (results == kNOERROR) - //{ - //delay(1); -// - //// Read the status register to see if the processor is in the idle state - //results = PrimaryRead(cs, 0x22, value); - // - //if (results == kNOERROR) - //{ - //if ((value & 0x00FF) != 0x0011) - //{ - //return kUNABLETOCHANGEPROCESSORSTATE; - //} - //} - //} - // - //return results; -} + uint16_t command = ((address & ADDRESS_MASK) | READ) << 8; + //Split the command into two bytes + out_buf[1] = command & 0xFF; + out_buf[0] = ( command >> 8 ) & 0xFF; + gpio_set_pin_level(Sn->SS_pin, false); + transfer16(Sn, command); + gpio_set_pin_level(Sn->SS_pin, true); + + gpio_set_pin_level(Sn->SS_pin, false); + returnedVal = transfer16(Sn, command); + gpio_set_pin_level(Sn->SS_pin, true); + +// printf("In_buff= "); +// /* Print Received data by SPI Master from SPI Slave on Console */ +// for (int i = 0; i < 2; i++) { +// printf("%u", in_buf[i]); +// } +// printf("\n\r"); *value = returnedVal; + + + if(debugPrint) { + printf("Returned val = %u \n\r", returnedVal); + } + + + return kNOERROR; +} + +uint16_t transfer16(struct SPI_S *Sn, uint16_t value) +{ + uint8_t in_buf[2], out_buf[2]; + uint16_t wordRead; + + out_buf[1] = value & 0xFF; + out_buf[0] = ( value >> 8 ) & 0xFF; + struct spi_xfer xfer; + xfer.rxbuf = in_buf; + xfer.txbuf = (uint8_t *)out_buf; + xfer.size = 2; + spi_m_sync_transfer(Sn->SPI_angleSensor_n, &xfer); + wordRead = (uint16_t)((in_buf[0] << 8) | in_buf[1]); + return wordRead; +} + + +/* + * PrimaryWrite + * + * Write to the primary serial registers + */ +uint16_t PrimaryWrite(uint16_t cs, uint16_t address, uint16_t value) +{ + //if (includeCRC) + //{ + //SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); +// + //// On the Teensy, SPI0_CTAR0 is used to describe the SPI transaction for transfer + //// while SPI0_CTAR1 is used to describe the SPI transaction for transfer16. + //// To do a 20 bit transfer, change the length of the transaction to 4 bits for transfer + //// and do a transfer16 followed by a transfer. + ////uint32_t oldSPI0_CTAR0 = SPI0_CTAR0; + //// SPI0_CTAR0 = (SPI0_CTAR0 & 0x87FFFFFF) | SPI_CTAR_FMSZ(3); // using SPI0_CTAR0 to send 4 bits +// + //// Combine the register address and the command into one byte + //uint16_t command = (((address & ADDRESS_MASK) | WRITE) << 8) | ((value >> 8) & 0x0FF); + //uint8_t crcCommand = CalculateCRC(command); +// + //// take the chip select low to select the device: + //digitalWrite(cs, LOW); +// + //SPI.transfer16(command); // Send most significant byte of register data + //SPI.transfer(crcCommand); // Send the crc +// + //// take the chip select high to de-select: + //digitalWrite(cs, HIGH); +// + //command = ((((address + 1) & ADDRESS_MASK) | WRITE) << 8 ) | (value & 0x0FF); + //crcCommand = CalculateCRC(command); +// + //// take the chip select low to select the device: + //digitalWrite(cs, LOW); +// + //SPI.transfer16(command); // Send least significant byte of register data + //SPI.transfer(crcCommand); // Send the crc +// + //// take the chip select high to de-select: + //digitalWrite(cs, HIGH); +// + //// Restore the 8 bit description + ////SPI0_CTAR0 = oldSPI0_CTAR0; +// + //SPI.endTransaction(); + //} + //else + //{ + //SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3)); +// + //// Combine the register address and the command into one byte + //uint16_t command = ((address & ADDRESS_MASK) | WRITE) << 8; +// + //// take the chip select low to select the device: + //digitalWrite(cs, LOW); +// + //SPI.transfer16(command | ((value >> 8) & 0x0FF)); // Send most significant byte of register data +// + //// take the chip select high to de-select: + //digitalWrite(cs, HIGH); +// + //command = (((address + 1) & ADDRESS_MASK) | WRITE) << 8; + //// take the chip select low to select the device: + //digitalWrite(cs, LOW); +// + //SPI.transfer16(command | (value & 0x0FF)); // Send least significant byte of register data +// + //// take the chip select high to de-select: + //digitalWrite(cs, HIGH); +// + //SPI.endTransaction(); + //} + + return kNOERROR; +} + +/* + * ExtendedRead + * + * Read from the SRAM, EEPROM, AUX or Extended Registers + */ +uint16_t ExtendedRead(uint16_t cs, uint16_t address, uint32_t value) +{ + //uint16_t results; + //uint16_t readFlags; + //uint32_t timeout; + //uint16_t valueMSW; + //uint16_t valueLSW; + //uint32_t currentTime; +// + //// Write the address to the Extended Read Address register + //results = PrimaryWrite(cs, 0x0A, address & 0xFFFF); +// + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// Initiate the extended read + //results = PrimaryWrite(cs, 0x0C, 0x8000); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //timeout = millis() + 100L; +// + //do // Wait for the read to be complete + //{ + //results = PrimaryRead(cs, 0x0C, readFlags); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// Make sure the read is not taking too long + //currentTime = millis(); + //if (timeout < currentTime) + //{ + //return kEXTENDEDREADTIMEOUTERROR; + //} + //} while ((readFlags & 0x0001) != 0x0001); + // + //// Read the most significant word from the extended read data + //results = PrimaryRead(cs, 0x0E, valueMSW); +// + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// Read the least significant word from the extended read data + //results = PrimaryRead(cs, 0x10, valueLSW); +// + //// Combine them + //value = ((uint32_t)valueMSW << 16) + valueLSW; +// + //return results; +} + +/* + * ExtendedWrite + * + * Write to the SRAM, EEPROM, AUX or Extended Access Commands + */ +uint16_t ExtendedWrite(uint16_t cs, uint16_t address, uint32_t value) +{ + //uint16_t results; + //uint16_t writeFlags; + //uint32_t timeout; +// + //// Write into the extended address register + //results = PrimaryWrite(cs, 0x02, address & 0xFFFF); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// Write the MSW (Most significant word) into the high order write data register + //results = PrimaryWrite(cs, 0x04, (value >> 16) & 0xFFFF); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// Write the LSW (Least significant word) into the low order write data register + //results = PrimaryWrite(cs, 0x06, value & 0xFFFF); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// Start the write process + //results = PrimaryWrite(cs, 0x08, 0x8000); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //// If writing to the EEPROM, generate the Program + //// Pulses on Vcc + //if ((address >= 0x300) && (address < 0x320)) + //{ + //// Send the Program Pulses + //// Need hardware which this example does not have. + //} +// + //timeout = millis() + 100; +// + //// Wait for the write to complete + //do + //{ + //results = PrimaryRead(cs, 0x08, writeFlags); + // + //if (results != kNOERROR) + //{ + //return results; + //} +// + //if (timeout < millis()) + //{ + //return kEXTENDEDWRITETIMEOUTERROR; + //} + //} while ((writeFlags & 0x0001) != 0x0001); +// + //return results; +} + +/* + * SetProcessorStateToIdle + * + * Change the processor state to idle + * This is needed to write EEPROM, change ORATE or perform certain self tests + */ +uint16_t SetProcessorStateToIdle(uint8_t cs) +{ + //uint16_t results; + //uint16_t value; + // + //// Write the enter idle state command into the control register + //results = PrimaryWrite(cs, 0x1F, 0x8046); + // + //if (results == kNOERROR) + //{ + //delay(1); +// + //// Read the status register to see if the processor is in the idle state + //results = PrimaryRead(cs, 0x22, value); + // + //if (results == kNOERROR) + //{ + //if ((value & 0x00FF) != 0x0010) + //{ + //return kUNABLETOCHANGEPROCESSORSTATE; + //} + //} + //} + // + //return results; +} + +/* + * SetProcessorStateToRun + * + * Change the processor state to run + * This is needed to process angles + */ +uint16_t SetProcessorStateToRun(uint8_t cs) +{ + //uint16_t results; + //uint16_t value; + // + //// Write the enter idle state command into the control register + //results = PrimaryWrite(cs, 0x1F, 0xC046); + // + //if (results == kNOERROR) + //{ + //delay(1); +// + //// Read the status register to see if the processor is in the idle state + //results = PrimaryRead(cs, 0x22, value); + // + //if (results == kNOERROR) + //{ + //if ((value & 0x00FF) != 0x0011) + //{ + //return kUNABLETOCHANGEPROCESSORSTATE; + //} + //} + //} + // + //return results; +} diff --git a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.h b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.h index 76b7126..069951f 100644 --- a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.h +++ b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/A1335.h @@ -12,6 +12,7 @@ struct SPI_S { struct spi_m_sync_descriptor *SPI_angleSensor_n; + struct io_descriptor *io; uint8_t state; uint32_t SS_pin; struct spi_xfer xfer; @@ -22,18 +23,19 @@ struct SPI_S { struct SPI_S A1; struct io_descriptor *io; -void angleSensor_init(struct spi_m_sync_descriptor *spi); +void angleSensor_init(struct spi_m_sync_descriptor *spi, struct SPI_S *Sn); void angleSensor_State_Machine(struct SPI_S *Sn); bool CalculateParity(uint16_t input); uint8_t CalculateCRC(uint16_t input); -uint16_t PrimaryRead(uint16_t cs, uint16_t address, uint16_t* value); +uint16_t PrimaryRead(struct SPI_S *Sn, uint16_t address, uint16_t* value); uint16_t PrimaryWrite(uint16_t cs, uint16_t address, uint16_t value); uint16_t ExtendedRead(uint16_t cs, uint16_t address, uint32_t value); uint16_t ExtendedWrite(uint16_t cs, uint16_t address, uint32_t value); uint16_t SetProcessorStateToRun(uint8_t cs); uint16_t SetProcessorStateToIdle(uint8_t cs); uint16_t SetProcessorStateToRun(uint8_t cs); +uint16_t transfer16(struct SPI_S *Sn, uint16_t value); #endif /* A1335_H_ */ \ No newline at end of file diff --git a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/Master_Slave_IF_TestMaster.cproj b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/Master_Slave_IF_TestMaster.cproj index 6d889a0..72d2831 100644 --- a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/Master_Slave_IF_TestMaster.cproj +++ b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/Master_Slave_IF_TestMaster.cproj @@ -20,10 +20,10 @@ false true true - + 0x20000000 true - + exception_table 2 0 0 @@ -365,7 +365,6 @@ Maximum (-g3) True -std=gnu99 -mfloat-abi=softfp -mfpu=fpv4-sp-d16 - True libm @@ -377,6 +376,7 @@ True + -Tsame54p20a_flash.ld diff --git a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/main.c b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/main.c index 07548cc..3b81afa 100644 --- a/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/main.c +++ b/Examples/SPI_Data_Mirroring_Example/Master_Slave_IF_Test_Master/Master_Slave_IF_TestMaster/main.c @@ -31,7 +31,7 @@ static void task1_cb(const struct timer_task *const timer_task) void TIMER_0_init(void) { - TIMER_0_task1.interval = 10; + TIMER_0_task1.interval = 100; TIMER_0_task1.cb = task1_cb; TIMER_0_task1.mode = TIMER_TASK_REPEAT; timer_add_task(&TIMER_0, &TIMER_0_task1); @@ -88,14 +88,15 @@ int main(void) /* Initializes MCU, drivers and middleware */ atmel_start_init(); /* Initialize SPI master IO and Callback */ - spi_master_init(); + //spi_master_init(); + angleSensor_init(&SPI_1, &A1); TIMER_0_init(); - spi_m_dma_enable(&SPI_0); + //spi_m_dma_enable(&SPI_0); /* Start SPI Master data transfer using DMA */ //spi_master_rx(rx_buffer, BUFFER_LEN); - spi_master_tx(tx_buffer, BUFFER_LEN); + //spi_master_tx(tx_buffer, BUFFER_LEN); /* Start SPI Master data reception using DMA */ //spi_master_rx(tx_buffer, BUFFER_LEN); printf("Init Complete\n\r");