Quadrature encoder decoder IC - HCTL family (2016)

Hello all,

I'm having a tough time with the HCTL2016 IC... I found some topic about it here on the forum, but none of them could solve my problem. The datasheet is so simple, but it's just not working for me. Please, if you had similar issues help me out.

So the short story. I would like to use this chip (HCT2016), to read quadrature encoder signals.[datasheet: https://inst.eecs.berkeley.edu/~ee128/fa04/labs/hctl2016.pdf]

Yes I would like to use a chip instead of the arduino doing the whole stuff with decoding. I need to work with 4 encoder, I would like to use its noisy filter and so on.

So according to the datasheet I only need he OE and SEL pins (as outputs) and one clock pin. I attach my test program, that is not working.

const byte CLOCKOUT = 11;  // Mega 2560
int selPin = 40;
int OEPin = 41;
int RSTPin = 53;

int D0 = 30;
int D1 = 31;
int D2 = 32;
int D3 = 33;
int D4 = 34;
int D5 = 35;
int D6 = 36;
int D7 = 37;

volatile uint8_t lowValue,highValue=0;
volatile uint16_t countValue = 0;

#define FLAG100ms 4
volatile uint8_t bTimer5_overflowsFlagShared=0;
volatile static uint8_t overflows=0;

void setupTIMER5(); 

void setup() {  
    // set up 8 MHz timer on CLOCKOUT (OC1A)
    pinMode (CLOCKOUT, OUTPUT); 
    // set up Timer 1
    TCCR1A = bit (COM1A0);  // toggle OC1A on Compare Match
    TCCR1B = bit (WGM12) | bit (CS10);   // CTC, no prescaling
    OCR1A =  0;       // output every cycle
  
    pinMode(clockPin, OUTPUT);   // sets the pin as output
    pinMode(selPin, OUTPUT);
    pinMode(OEPin, OUTPUT);
    pinMode(RSTPin, OUTPUT);
    digitalWrite(selPin,HIGH);
    digitalWrite(OEPin,HIGH);
    digitalWrite(RSTPin,HIGH);
    
    Serial.begin(9600);
    DDRC = 0b00000000;  //C port all pins are inputs
    digitalWrite(D0, HIGH); //pullup resistors on
    digitalWrite(D1, HIGH);
    digitalWrite(D2, HIGH);
    digitalWrite(D3, HIGH);
    digitalWrite(D4, HIGH);
    digitalWrite(D5, HIGH);
    digitalWrite(D6, HIGH);
    digitalWrite(D7, HIGH);
  
    setupTIMER5();
    digitalWrite(RSTPin,LOW);  //reset the internal counter
    digitalWrite(RSTPin,HIGH);
}


void loop() {
  static uint8_t bTimer5_overflowsFlags;
  
  if(bTimer5_overflowsFlagShared)
  {
    cli(); // clear the global interrupt enable flag 
    byte sregRestore = SREG;     
    
    bTimer5_overflowsFlags = bTimer5_overflowsFlagShared;
    bTimer5_overflowsFlagShared = 0;
    
    SREG = sregRestore; // restore the status register to its previous value
    sei();
  }

  if(bTimer5_overflowsFlags & FLAG100ms)  //its mean ca. 100 ms cyclic
  {
    countValue = readOUT();
    digitalWrite(selPin,HIGH);  //just to be sure, that the lines are in high states
    digitalWrite(OEPin,HIGH);
    Serial.println(countValue);
  }

  bTimer5_overflowsFlags = 0;  
}

uint16_t readOUT()
{
  
  digitalWrite(OEPin,LOW);    //When OE goes low, the outputs of the multiplexer are enabled onto the data lines.
  digitalWrite(selPin,LOW);   //If SEL is low, then the high order data bytes are enabled onto the data lines  
     
  highValue = PINC;   //C port read (digital pins: 30-37)

  //Serial.println(highValue,BIN); //at first the high order

  digitalWrite(selPin,HIGH);   //If SEL is high, then the low order data bytes are enabled onto the data lines.

  lowValue = PINC;            //secondly the low order
  //Serial.println(lowValue,BIN); //
  digitalWrite(OEPin,HIGH);   //When OE goes high, the data lines change to a high impedance state.

  //digitalWrite(RSTPin,LOW);    //reset the counter again
  //digitalWrite(RSTPin,HIGH);
  //Serial.println(lowValue);
  return word(highValue,lowValue);
}

void setupTIMER5(){     
  cli();  // disable global interrupts  
  TCNT5 = 0;              // clear the timer count
     // Initilialise Timer5
     TCCR5A = 0;             // normal counting mode 
     TCCR5B = 2;             // set prescaler of 8 = 1 tick = 500ns (1/(16MHz/8)*65535) [(1/2000000)*65535) = overflow in every 32,7675 ms
     TIMSK5  = 1;            //Timer5 overflow interrupt enabled //32,7675 ms
     TCNT5 = 15535;         //(50000 tick = 0,025 sec = 25ms)       
   sei();  // enable global interrupts
}

ISR(TIMER5_OVF_vect)    //Timer5 overflow interrupt
{
  overflows++;
  TCNT5 = 15535;
  if(overflows>=4)
  {
    bTimer5_overflowsFlagShared |= FLAG100ms;
    overflows=0;
  }
}

And with this sketch I got nothing on the outputs just 0-s.

I have a scope so the quadrature encoder just working fine, the SEL and OE pins are OK. But I cannot read anything just 0 from the data lines.....

Please, if someone have a nice idea feel free to share it. Really appreciate

pin 11: set the pinMode before tinkering with the timer - just in case pinMode changes any PWM settings (cannot recall if it does, digitalWrite definitely does).

use pinMode (D1, INPUT_PULLUP); for clarity with the data pins - that's much more self-explanatory.

The datasheet says the #OE and SEL inputs are sampled on a falling clock edge. Your code doesn't take that into account. The chip is designed to be driven from an early microprocessor bus where the clock happens once per memory access I think.

Thanks for your advices.

pin11: I set this pinMode, before tinkering with the timer.

Yes the datasheet says it, but around here in the forum I found some examples that just worked fine (according to the author).
Besides - I think - the datasheet means that the evaluation happens on falling clock edge. So when the clock signal goes down and the OE pin is low, than it enables the inhibit logic.

Anyway I also tried this line with no success:

PORTG = (0 << PG0) | (0 << PG1); //SEL, OE manipulation at the same time

At pin 11 I measured a 8 MHz square waveform singal (was not a perfect one, but it was OK).
My Arduino works at 16 MHz. But it should not be the problem.

The sketch is just still not working.