got angle sensor reading
This commit is contained in:
parent
312768d2cf
commit
128dbfe5c3
|
@ -0,0 +1 @@
|
|||
Subproject commit f781cec322d7cd2a3677e1c273174ea00bc047e6
|
|
@ -0,0 +1,5 @@
|
|||
.pio
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
.vscode/ipch
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
// See http://go.microsoft.com/fwlink/?LinkId=827846
|
||||
// for the documentation about the extensions.json format
|
||||
"recommendations": [
|
||||
"platformio.platformio-ide"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
#include <Arduino.h>
|
||||
#include <SPI.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
@ -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 <Wire.h>
|
||||
|
||||
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
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
Subproject commit f781cec322d7cd2a3677e1c273174ea00bc047e6
|
|
@ -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 <Foo.h>
|
||||
#include <Bar.h>
|
||||
|
||||
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
|
|
@ -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
|
|
@ -0,0 +1,569 @@
|
|||
#include <Arduino.h>
|
||||
#include <SPI.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;
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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
|
|
@ -0,0 +1,21 @@
|
|||
#include <AS5048A.h>
|
||||
|
||||
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());
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_ */
|
|
@ -20,10 +20,10 @@
|
|||
<OverrideVtor>false</OverrideVtor>
|
||||
<CacheFlash>true</CacheFlash>
|
||||
<ProgFlashFromRam>true</ProgFlashFromRam>
|
||||
<RamSnippetAddress />
|
||||
<RamSnippetAddress>0x20000000</RamSnippetAddress>
|
||||
<UncachedRange />
|
||||
<preserveEEPROM>true</preserveEEPROM>
|
||||
<OverrideVtorValue />
|
||||
<OverrideVtorValue>exception_table</OverrideVtorValue>
|
||||
<BootSegment>2</BootSegment>
|
||||
<ResetRule>0</ResetRule>
|
||||
<eraseonlaunchrule>0</eraseonlaunchrule>
|
||||
|
@ -365,7 +365,6 @@
|
|||
<armgcc.compiler.optimization.DebugLevel>Maximum (-g3)</armgcc.compiler.optimization.DebugLevel>
|
||||
<armgcc.compiler.warnings.AllWarnings>True</armgcc.compiler.warnings.AllWarnings>
|
||||
<armgcc.compiler.miscellaneous.OtherFlags>-std=gnu99 -mfloat-abi=softfp -mfpu=fpv4-sp-d16</armgcc.compiler.miscellaneous.OtherFlags>
|
||||
<armgcc.linker.general.UseNewlibNano>True</armgcc.linker.general.UseNewlibNano>
|
||||
<armgcc.linker.libraries.Libraries>
|
||||
<ListValues>
|
||||
<Value>libm</Value>
|
||||
|
@ -377,6 +376,7 @@
|
|||
</ListValues>
|
||||
</armgcc.linker.libraries.LibrarySearchPaths>
|
||||
<armgcc.linker.optimization.GarbageCollectUnusedSections>True</armgcc.linker.optimization.GarbageCollectUnusedSections>
|
||||
<armgcc.linker.memorysettings.ExternalRAM />
|
||||
<armgcc.linker.miscellaneous.LinkerFlags>-Tsame54p20a_flash.ld</armgcc.linker.miscellaneous.LinkerFlags>
|
||||
<armgcc.assembler.general.IncludePaths>
|
||||
<ListValues>
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in New Issue