thesis_bldc_controller/Examples/Arduino/a1335_example/src/main.cpp

570 lines
14 KiB
C++

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