I have an optical encoder: Broadcom AS38-H39E-B13S.
AS38-H39E Series 39-Bit Energy-Harvesting Multi-Turn Absolute Encoder Application Note
The encoder can be read by connecting the pin 12 [data] & 13 [clk] to an SN65LBC179Q and connect that to the encoder. As shown on page 4 in figure 4 of the application note.
The following code does the readout by sending a character in the serial monitor screen of the arduino IDE.
/*
Circuit:
Broadcom AS38-H39E-B13S
Optical encoder sensor attached to pins 12 - 13:
MISO: pin 12
SCK: pin 13
Bit signal: BISS-C Protocol
Init:
Empty: 2 bits
ACK: 2 bits
Start: 1 bit
CDS: 1 bit
Data:
Multi turn encoding: 16 bits
Single turn encoding: 23 bits
Checks:
Error bit: 1 bit
Warning bit: 1 bit
CRC: 6 bits
13 December 2017
*/
// the sensor communicates using SPI, so include the library:
#include <SPI.h>
byte data[]={0,0,0,0,0,0,0};
bool debugPrinting = true;
double singleTurnCounts = 8388608.0;
byte inByte = 0;
uint32_t nMultiTurn = 0;
uint32_t nSingleTurn = 0;
bool bError = false;
bool bWarning = false;
byte CRC = 0;
bool dataValid = false;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setClockDivider(SPI_CLOCK_DIV64); // 250kHz = 16 MHz / 64
SPI.setDataMode(SPI_MODE3);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
}
void spiTransferData(){
for (int i=0;i<7;i++)
{
data[i] = SPI.transfer(0x00);
}
}
void printBinaryDebug(){
for (int i=0;i<7;i++)
{
// Convert to binary number as a "string" so that we can know
// how many significant bits there are
char buff[8];
itoa (data[i], buff, 2);
// Loop to print leading zeros
for (int i = 0; i < 8-strlen(buff); i++) {
Serial.print('0');
}
// Now print the significant bits
Serial.print(buff);
}
Serial.println("");
}
void decodeBinaryData()
{
//24 bits of data from encoder
nMultiTurn = data[0];
for(int i=1;i<3;i++)
{
nMultiTurn = nMultiTurn << 8;
inByte = data[i];
// combine the byte you just got with the previous one:
nMultiTurn = nMultiTurn | inByte;
}
nMultiTurn &= 0x03FFFF; // Clear first 6 bits
nSingleTurn = nMultiTurn & 0x000003; // Copy last 2 bits to nSingleTurn
nMultiTurn >>= 2; // Shift multi turn bits 2 as last 2 bits are singleTurn
//clocking out 24 bits of data from encoder
for(int i=3;i<6;i++)
{
nSingleTurn = nSingleTurn << 8;
inByte = data[i];
// combine the byte you just got with the previous one:
nSingleTurn = nSingleTurn | inByte;
}
bError = (nSingleTurn & ( 1 << 2 )) >> 2;
bWarning = (nSingleTurn & ( 1 << 1 )) >> 1;
CRC = (nSingleTurn & ( 1 << 0 )) >> 0;
nSingleTurn >>= 3;
inByte = data[6];
CRC = (CRC << 5) | (inByte >> 3);
byte crcPolynome = B01100001; // CRC Polynomial = Invert of (X6 + X1 + X0). (X6 + X1 + X0 = 1000011)
dataValid = checkCRC((const byte)&data, 6, 6, 3, crcPolynome, 6);
dataValid = true;
}
void printResult()
{
Serial.print("MultiTurn: "); // Print rotations
Serial.print(nMultiTurn);
Serial.print(" ");
Serial.println(nMultiTurn, BIN);
Serial.print("SingleTurn:"); // Print angle steps
Serial.print(nSingleTurn);
Serial.print(" ");
Serial.print(((double)nSingleTurn/singleTurnCounts)*360.0d, 3);
Serial.print(" graden ");
Serial.println(nSingleTurn, BIN);
Serial.print("Error:"); // Print error
Serial.println(bError);
Serial.print("Warning:"); // Print warning
Serial.println(bWarning);
Serial.print("CRC:"); // Print CRC
Serial.print(CRC);
Serial.print(" ");
Serial.println(CRC, BIN);
Serial.print("Data valid: ");
Serial.println(dataValid);
Serial.println("");
}
uint8_t tableCRC6[64] = {
0x00, 0x03, 0x06, 0x05, 0x0C, 0x0F, 0x0A, 0x09,
0x18, 0x1B, 0x1E, 0x1D, 0x14, 0x17, 0x12, 0x11,
0x30, 0x33, 0x36, 0x35, 0x3C, 0x3F, 0x3A, 0x39,
0x28, 0x2B, 0x2E, 0x2D, 0x24, 0x27, 0x22, 0x21,
0x23, 0x20, 0x25, 0x26, 0x2F, 0x2C, 0x29, 0x2A,
0x3B, 0x38, 0x3D, 0x3E, 0x37, 0x34, 0x31, 0x32,
0x13, 0x10, 0x15, 0x16, 0x1F, 0x1C, 0x19, 0x1A,
0x0B, 0x08, 0x0D, 0x0E, 0x07, 0x04, 0x01, 0x02};
bool checkCRC(const byte * data, const uint8_t nrBytes, const uint8_t leadingZeros, const uint8_t tailingZeros, const byte polynome, const uint8_t polySize)
{
uint64_t checkData = ((data[0] & 0x03) << 40) | (data[1] << 32) | (data[2] << 24) | (data[3] << 16) | (data[4] << 8) | data[5]; // Remove ACK,START,CDS from data
checkData >>= 3; // Remove warning, error and crc bit
uint8_t crc;
uint64_t tmp;
tmp = (checkData >> 60) & 0x0000003F;
crc = ((checkData >> 54) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 48) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 42) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 36) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 30) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 24) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 18) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 12) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = ((checkData >> 6) & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = (checkData & 0x0000003F);
tmp = crc ^ tableCRC6[tmp];
crc = tableCRC6[tmp];
if(debugPrinting){
Serial.print("crc: ");
Serial.println(crc);
}
return true;
}
void loop() {
if (Serial.available() > 0)
{
Serial.read();
while(!dataValid){
// Clock out the data as fast as possible
spiTransferData();
// Print full binary code for debugging
if(debugPrinting){
printBinaryDebug();
}
// Starting binary decoding
decodeBinaryData();
// Print result
if(debugPrinting){
printResult();
}
}
// Write to serial output for PC communication
for (int i=0;i<7;i++)
{
if(!debugPrinting)
Serial.write(data[i]);
}
dataValid = false;
}
}
The readout gives for 'a measurement':
Binary data: 11001000000101100110000111101100110001100111000100000
Decoding: 6bits (init+ACK+Start+CDS) + 16bits MT + 23bits ST + 1 nErr bit + 1 nWar bit + 6bits CRC
MultiTurn: 1432 10110011000
SingleTurn:4036814 173.241 graden 1111011001100011001110
Error:0
Warning:0
CRC:32 100000
As you can see, I know how to get the multi turn and single turn values from the binary data.
I can also get the error, warning and CRC.
The question is now how to check the data against the CRC in code.
CRC Polynomial = Invert of (X6 + X1+ X0). => 1000011 or 0x43
An explanation is given in: Application note: Decoding the BiSS information I tried to change the code from 32-bits to my 39 bits data, but
just can't get the correct outcome (find the same CRC from calculation as was found in the data from the encoder).