//Has to be on white for read command to work
//Low Signal is when sensor is on White when Push-Pull inverted
//Command 1 — send write command to set output type (OP and DS bits, table 1) and comparator reference level bits (table 2)
//Command 2 — send command to calibrate LED drive
//Command 3 — send write command to change comparator to new desired reference level
//Degree 30, calibration 25
//Index 2, calibration 24
//103E3 Unit 6 V4 test unit ldval=550 Index, degree ldval=650
//Benchtop test unit, index=103(ldval=550), Degree=98(ldval=650)
//Added ability to read 13ms calibration success command
//Can read output by changing read level to either high or low, seems to work well
//#define calPin 25 //all commands sent via the cal/stat pin
//#define outputPin 30
//Index
//#define calPin 24
//#define outputPin 2
byte calPin = 24 ;//25
byte outputPin = 2;//30
int led = 13;
//sensor setting arrays
//first one is benchtop test unit
uint16_t idxLD[] = {550, 550, 750, 750, 650, 750, 750};
uint16_t degLD[] = {650, 650, 750, 650, 650, 750, 750};
uint32_t idxFREQ[] = {103000, 103000, 101000, 102000, 102000, 98500, 99000};
uint32_t degFREQ[] = {98000, 103000, 98000, 102000, 100500, 98000, 97500};
uint16_t LDVAL = 550;
uint32_t freq = 103000;
int cycles;
uint32_t val = 0;
uint16_t CalTime;
uint16_t CalStart;
boolean CalStatus = false;
byte readLevel = HIGH;
byte readOffset = 0;
boolean READ_FLAG = false;
//bit reversal for 16 bit types
#define bitrev16(dat) (((unsigned short) bitrev8(dat) << 8) | ((unsigned short) bitrev8(dat >> 8)))
#define testPin1 31
volatile uint8_t buf[37];
volatile unsigned bitCnt = 0;
String wData;
word writeArray[16] = {
0b0101101010100000,
0b0101101010010000,
0b0101101001100000,
0b0101101001010000,
0b0101100110100000,
0b0101100110010000,
0b0101100101100000,
0b0101100101010000,
0b0101011010100000,
0b0101011010010000,
0b0101011001100000,
0b0101011001010000,
0b0101010110100000,
0b0101010110010000,
0b0101010101100000,
0b0101010101010000
};
IntervalTimer pit;
KINETISK_PIT_CHANNEL_t* PIT_Channel;
bool stop = true;
//00 = 1010
//01 = 1001
//10 = 0110
//11 = 0101
word ccmd = 0b0101101001010000;//only 12 bit, but need to use 16 bit, add 0000 pad
word rcmd = 0b0101101010010000;//1100-01
word wcmd = 0b0101101001100000;
void setup() {
Serial.begin(9600);
pinMode(calPin, OUTPUT);
pinMode(outputPin, INPUT);
pinMode(testPin1, OUTPUT);
pinMode(led, OUTPUT);
pinMode(17, OUTPUT);//for v4 board to keep powered up
digitalWrite(17, HIGH);
digitalWriteFast(testPin1, LOW);
digitalWrite(calPin, HIGH);
// setup interval timer
pit.priority(0); // highest
pit.begin(PIT_ISR, 1E6); // let teensyduino grab a free timer and do all the initialization work.
// Get hold of the register block for the used timer
PIT_Channel = KINETISK_PIT_CHANNELS + ((IRQ_NUMBER_t)pit - IRQ_PIT_CH0);
PIT_Channel->TCTRL = 0; // stop the timer
stop = true;
ccmd = bitrev16(ccmd);//reverse since read LSB-MSB
rcmd = bitrev16(rcmd);
wcmd = bitrev16(wcmd);
while (!Serial) {
yield();
}
Serial.println();
Serial.println("Set sensor # before reading/calibrating");
Serial.println("Index Pin initialized");
Serial.println(F("S# - Select Sensor eg:S1 = Sensor 1"));
Serial.println(F("I - Initialize Index Sensor"));
Serial.println(F("D - Initialize Degree Sensor"));
Serial.println(F("r - read settings"));
Serial.println(F("w# - Write Level eg:w0 = level 0"));
Serial.println(F("c - Calibrate"));
Serial.println(F("l - Switch Read Level High/Low"));
Serial.println(F("p - Print Options"));
}
unsigned char bitrev8(unsigned char bits) {
unsigned char tmp = 0;
//bit reversing, msb to lsb
tmp |= (bits & 0x80) ? 0x01 : 0;
tmp |= (bits & 0x40) ? 0x02 : 0;
tmp |= (bits & 0x20) ? 0x04 : 0;
tmp |= (bits & 0x10) ? 0x08 : 0;
tmp |= (bits & 0x08) ? 0x10 : 0;
tmp |= (bits & 0x04) ? 0x20 : 0;
tmp |= (bits & 0x02) ? 0x40 : 0;
tmp |= (bits & 0x01) ? 0x80 : 0;
return tmp;
}
void loop() {
if ( Serial.available()) {
char ch = Serial.read();
switch (ch) {
case 'S': {//Set value of sensor to read/calibrate
while (Serial.available() == 0); {
val = Serial.parseInt();
Serial.print("Sensor set to ");
Serial.println(val);
}
break;
}
case 'p': { //print options again
Serial.println();
Serial.println(F("S# - Select Sensor eg:S1 = Sensor 1"));
Serial.println(F("I - Initialize Index Sensor"));
Serial.println(F("D - Initialize Degree Sensor"));
Serial.println(F("r - read settings"));
Serial.println(F("w# - Write Level eg:w0 = level 0"));
Serial.println(F("c - Calibrate"));
Serial.println(F("L - Switch Read Level High/Low"));
Serial.println(F("p - Print Options"));
break;
}
case'c': {
//how to read pin and signal via LED, so we know we are on white
//use while we wait for serial input
// while (!Serial.available()) {
// digitalWriteFast(led, digitalReadFast(outputPin));
// if (Serial.available()) {
// break;
// }
// }
pinMode(calPin, OUTPUT);
for (byte i = 0; i < 12; i++) {
if (bitRead(ccmd, i) == 0) {
digitalWriteFast(calPin, 0);
} else {
digitalWriteFast(calPin, 1);
}
delayMicroseconds(10);
}
digitalWriteFast(calPin, 0);
Serial.println("Calibration Sent");
pinMode(calPin, INPUT);//after calibrate it responds, so need to be input
delay(2);
digitalWriteFast(testPin1, HIGH);
attachInterrupt(calPin, calStatus, CHANGE);
delay(100);
Serial.println(CalTime);
if (CalTime > 10) Serial.println("Calibration Successful");
detachInterrupt(calPin);
break;
}
case 'L': {//change LDVAL value
while (Serial.available() == 0); {
LDVAL = Serial.parseInt();
Serial.print("LDVAL set to ");
Serial.println(LDVAL);
}
break;
}
case 'F': {//change Freq value
while (Serial.available() == 0); {
freq = Serial.parseInt();
Serial.print("freq set to ");
Serial.println(freq);
}
break;
}
case 'f': {
Serial.print("freq: ");
Serial.println(freq);
Serial.print("LDVAL: ");
Serial.println(LDVAL);
break;
}
case 'I': {
calPin = 24 ;
outputPin = 2;
LDVAL = idxLD[val];
freq = idxFREQ[val];
Serial.println("Index Sensor Initilized");
Serial.print("LDVAL set to ");
Serial.println(LDVAL);
Serial.print("Read frequency set to ");
Serial.println(freq);
break;
}
case 'D': {
calPin = 25 ;
outputPin = 30;
LDVAL = degLD[val];
freq = degFREQ[val];
Serial.println("Degree Sensor Initilized");
Serial.print("LDVAL set to ");
Serial.println(LDVAL);
Serial.print("Read frequency set to ");
Serial.println(freq);
break;
}
case 'r': {
pinMode(calPin, OUTPUT);
attachInterrupt(outputPin, PIN_ISR, FALLING);//to read back response
retrigger();
for (byte i = 0; i < 12; i++) {
if (bitRead(rcmd, i) == 0) {
digitalWriteFast(calPin, 0);
} else {
digitalWriteFast(calPin, 1);
}
delayMicroseconds(10);//try different values to trigger response
}
pinMode(calPin, INPUT);
delay(50);//delay to allow time to read response
if (bitCnt == sizeof(buf)) //fill array at each tooth
{
detachInterrupt(outputPin);
for (byte i = 0; i < sizeof(buf); i++) {
Serial.print(buf[i]);
}
Serial.println();
byte refValue = 0;
for (int i = 3, j = 27 + readOffset; i > -1; i--) {
refValue += buf[j--] << i;//since MSB when read back
}
Serial.print("Reference level: ");
Serial.println(refValue);
byte ledCount = 0;
for (int i = 9, j = 23 + readOffset; i > -1; i--) {
ledCount += buf[j--] << i;
}
Serial.print("LED Count: ");
Serial.println(ledCount);
byte AGC = 0;
for (int i = 1, j = 13 + readOffset; i > -1; i--) {
AGC += buf[j--] << i;
}
Serial.print("Gain Level: ");
Serial.println(AGC);
byte reservedCount = 0;//should always be 0
for (int i = 6, j = 36 + readOffset; i > -1; i--) {
reservedCount += buf[j--] << i;
}
Serial.print("Reserved Bits: ");
Serial.println(reservedCount);
byte bank3 = 0;//9 bits at beginning, always the same
for (int i = 8, j = 10 + readOffset; i > -1; i--) {
bank3 += buf[j--] << i;
}
Serial.print("Bank3 Bits: ");
Serial.println(bank3);
if (buf[28 + readOffset] == 0) {
Serial.println("Open Drain");
}
else {
Serial.println("Push-Pull");
}
if (buf[29 + readOffset] == 0) {
Serial.println("Buffered");
}
else {
Serial.println("Inverted");
}
if (buf[11 + readOffset] == 0) {
Serial.println("Calibration Failed");
}
else {
Serial.println("Calibration Successful");
}
if (buf[1 + readOffset] == 0) {
Serial.println("No Errors");
}
else {
Serial.println("Error");
}
//use below to make sure read values are correct since bank3 and last bank are always the same
if (reservedCount == 0 && bank3 == 168) { //have to dbl check bank3 value
Serial.println("No Read Errors");
}
else {
Serial.println("Read Errors, check LDVAL or read Hz settings");
}
}
break;
}
case 'w': {//Ref Level 0 0000 = 10101010
while (Serial.available() == 0); {
val = Serial.parseInt();
Serial.print("Writing Reference Level ");
Serial.println(val);
}
writeCmd(writeArray[val]);
break;
}
case 'l': { //switch readlevel
readLevel = !readLevel;
readOffset = !readOffset;
Serial.println(readLevel);
Serial.println(readOffset);
}
}
}
}
void writeCmd(word wData) {
//Write Bank 2 Bits 1100-10-bbbbbb
//010110100110
pinMode(calPin, OUTPUT);
wData = bitrev16(wData);
//Send write command first
for (byte i = 0; i < 12; i++) {
if (bitRead(wcmd, i) == 0) {
digitalWriteFast(calPin, 0);
} else {
digitalWriteFast(calPin, 1);
}
delayMicroseconds(10);
}
//Writting Output type and comparator reference levels
for (byte i = 0; i < 12; i++) {
if (bitRead(wData, i) == 0) {
digitalWriteFast(calPin, 0);
} else {
digitalWriteFast(calPin, 1);
}
delayMicroseconds(10);
}
Serial.println("Write Done");
}
void PIT_ISR() {
if (bitCnt < sizeof(buf))
{
digitalWriteFast(testPin1, HIGH);
buf[bitCnt] = digitalReadFast(outputPin);
bitCnt++;
digitalWriteFast(testPin1, LOW); // debugging
}
else // stop timer
{
PIT_Channel->TCTRL = 0; //stop PIT
}
}
// pin interrupt
void PIN_ISR()
{
if (stop) return; // just a quick hack to avoid looking up the correct register settings :-)
stop = true;
// To align the timer with the clock we need to manually adjust the first timer period.
PIT_Channel->TCTRL = 0; // to immediately change LDVAL the timer need to be stopped first. Otherwise LDVAL gets buffered and will be loaded at the next zero transition
PIT_Channel->LDVAL = LDVAL; // adjust, so that the first PIT_ISR() is called at the correct time.
PIT_Channel->TCTRL = 3; // start the PID
// Set the timer reload values for the follwing periods according to the frequency of the Manchester signal
//OPB9000 sends read at 100 kb/s ± 5 kb/s.
//think only way is to either know data we will see and compare, or use scope to dial in each encoder
//use scope to measure Hz of output, then enter that value in as freq
//103 Unit 6 V4 test unit
//Benchtop test unit, index=103(ldval=550), Degree=98(ldval=650)
//constexpr float freq = 98E3;
//constexpr unsigned cycles = F_BUS / freq;
cycles = F_BUS / freq;
PIT_Channel->LDVAL = cycles; // This value will be buffered and is loaded after at the first timer zero transition
//The PIT will miss the first clock cycle (can not choose the first LDVAL small enough, maybe a T3.6 would be quick enough)
//To avoid handling a 7bit byte we simply call the first PIT_ISR manually (after a short delay)
volatile int dummy; for (int i = 0; i < 5; i++) {
dummy *= dummy;
}
PIT_ISR();
}
// this simply waits until it detects 15µs bus inactivity.
void sync()
{
int i = 0;
while (i < 15)
{
//maybe read pin, soon as it goes low, start, first value always 0
i = (digitalReadFast(outputPin) == readLevel) ? 0 : (i + 1); //if low =0, if high increment
delayMicroseconds(1);
}
}
void retrigger()
{
sync();
stop = false;
bitCnt = 0;
}
void calStatus() { //time any Calibration signal time
CalTime = millis() - CalStart;
CalStart = millis();
}
// else if (c == 'b') {//Ref Level 1
// writeCmd(0b0101101010010000);// 0001 = 10101001
// }
// else if (c == 'd') {//Ref Level //2 = 0010 = 10100110
// writeCmd(0b0101101001100000);
// }
// else if (c == 'e') {//Ref Level //3 = 0011 = 10100101
// writeCmd(0b0101101001010000);
// }
// else if (c == 'f') {//Ref Level //4 = 0100 = 10011010
// writeCmd(0b0101100110100000);
// }
// else if (c == 'g') {//Ref Level //5 = 0101 = 10011001
// writeCmd(0b0101100110010000);
// }
// else if (c == 'h') {//Ref Level //6 = 0110 = 10010110
// writeCmd(0b0101100101100000);
// }
// else if (c == 'i') {//Ref Level //7 = 0111 = 10010101
// writeCmd(0b0101100101010000);
// }
// else if (c == 'j') {//Ref Level //8 = 1000 = 01101010
// writeCmd(0b0101011010100000);
// }
// else if (c == 'k') {//Ref Level //9 = 1001 = 01101001
// writeCmd(0b0101011010010000);
// }
// else if (c == 'l') {//Ref Level //10 = 1010 = 01100110
// writeCmd(0b0101011001100000);
// }
// //00 = 1010
// //01 = 1001
// //10 = 0110
// //11 = 0101
// else if (c == 'm') {//Ref Level //11 = 1011 =01100101
// writeCmd(0b0101011001010000);
// }
// else if (c == 'n') {//Ref Level //12 = 1100 = 01011010
// writeCmd(0b0101010110100000);
// }
// else if (c == 'o') {//Ref Level //13 = 1101 = 01011001
// writeCmd(0b0101010110010000);
// }
// else if (c == 'p') {//Ref Level //14 = 1110 = 01010110
// writeCmd(0b0101010101100000);
// }
// else if (c == 'q') {//Ref Level //15 = 1111 = 01010101
// writeCmd(0b0101010101010000);
// }