got angle sensor reading

This commit is contained in:
Nicolas Trimborn 2021-07-26 23:20:00 +02:00
parent 312768d2cf
commit 128dbfe5c3
18 changed files with 1825 additions and 442 deletions

@ -0,0 +1 @@
Subproject commit f781cec322d7cd2a3677e1c273174ea00bc047e6

View File

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

View File

@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

View File

@ -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;
}
}
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;
}
}
}

View File

@ -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

View File

@ -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());
}

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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>

View File

@ -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");