Chips which supports multiple 2bit gray code encoders w/ i2c interface (& LED PWM?)

Status
Not open for further replies.

Pensive

Well-known member
Chips which supports multiple 2bit gray code encoders w/ i2c interface (& LED PWM?)

Hi All

I've been searching for a while and come up fairly empty so far;

I'm looking for a chip which would support (at least) 2 rotary encoder inputs with 6 PWM LED outputs, preferably double that on one chip, or even 4 times that in a perfect world.

I can find the MAX7360 from maxim which has the LED outputs but only 1 rotary encoder input.

OR

A chip that is dedicated for encoders, supporting 4 or 8 of them, hang the leds, I can use any one of 10 different LED driver chips over i2c fairly easily.

At the moment, I'm looking at running an atmega328p over wire library and using pin change interrupts, to support up to 4 encoders with an RGB LED output for each:
http://thewanderingengineer.com/2014/08/11/arduino-pin-change-interrupts/

but this seems a little kludgy, not to mention adds another step to a manufacturing process of having to burn chips before they are mounted onto a PCB, plus then the obvious challenges of firmware bugs once soldered.
Plus there's hardware PWM for 6 outputs but not twelve so I'd have to roll my own PWM solution for 2 of the encoders. Reality is i'd be looking at 2 encoders per Atmega328p. (They're only around 90p each so this might be the cheapest solution.)

I could use one max7360 per encoder but what a waste! and a very expensive solution, at £2.30 a pop even in bulk.

Anyone got any ideas? Is there a good place to look for this sort of thing - I'm a bit new to low level IC things - is there a chip that does this anywhere?

Thanks

Jon
 
Just came across this link, which leads to an HTCL-2032, which supports 4 encoders and speaks via a bus connection of some kind. Downside of course, is the need to develop the software implementation within the arduino-verse
http://pi.bbcrobotics.org/news/index.php?controller=post&action=view&id_post=38

http://www.avagotech.com/products/m...s/integrated-circuits/decoder-ic/hctl-2032-sc

But it looks like the most cost effective option for offloading lots of quadrature pins onto hardware decoders.
 
The teensy 3.2 already has 2 hardware quadrature decoders built in. The encoder library supports more. Is there some reason you want to use another chip?
 
The teensy 3.2 already has 2 hardware quadrature decoders built in. The encoder library supports more. Is there some reason you want to use another chip?

Yes, there is - this is not just a one off project for me, otherwise i'd just buy Teensy-LC's and use those. I'm thinking commercial manufacture of hundreds of pieces etc. etc.

A Teensy 3.2 costs 20 dollars, and I have 8 encoders in 3 separate locations (i.e. 3 PCBs). thats 24 total encoders, each with a switch, and rgb backlighting.

I dont see the point of using hardware encoders for _some_ of them - for me its all or nothing otherwise i have two engineering approaches and 2 sets of failure modes to manage, plus messy code.

BUT

Teensy LC I did consider though as it has precisely the correct number of pins to exist on an i2C bus, and run 4 encoders (With switch) with 4 sets of RGB LED outputs ((4x3 = 12) + (4x3 = 12) = 24, with 2 spare for i2c = 26 total pins).

But I'd still need to use 6 of them to handle 24 encoders, plus a Teensy 3.2 to run the whole show on the rest of the project = nearly $100 worth of boards, which is fine for a one-off DIY if it saves my previous geek time, but totally outrageous for a manufactured product.

Plus all 6 would need to be programmed separately, and soldered up etc, it really doesn't bear thinking about. I've thought about creating a 4 encoder PCB with a Teensy LC loader and chip on it etc. But it all seems a bit over the top, frankly, when I could probably just use these off the shelf chips for a fraction of the price and an i2c 16 channel PWM LED driver chip.

It's just coding the bus comms that is the blocker. It's not beyond me but I'm such a cottage industry with a full time job and an etail company I run in the evenings as well - I need to work out the best route for my dev time.
 
I looked at the sheet for the HC 2032s.... I thought it said 2 encoders (four channels total, leaving aside the incremental channel). why can't you just use a multiplexer? I have code for n-objects encoders (like the encoder library itself). The mechanical encoders are just switches, are they not.

I use polling to read a set of eight pins, process and store the sate of four encoders... why can't that be done through a multiplexer? you could have 12 per teensy plus your LED's too ?
 
Hmm I use polling of about 400 microseconds for 2 encoders, and then smooth that over 3 reads. ... that's 1.2 milliseconds to debounce 2 encoders. You must be able to up that rate using a mux and easily get 8 if not 12 encoders
 
I looked at the sheet for the HC 2032s.... I thought it said 2 encoders (four channels total, leaving aside the incremental channel). why can't you just use a multiplexer? I have code for n-objects encoders (like the encoder library itself). The mechanical encoders are just switches, are they not.

I use polling to read a set of eight pins, process and store the sate of four encoders... why can't that be done through a multiplexer? you could have 12 per teensy plus your LED's too ?

By jove you're right. All those pins and it only supports channels A and B.

I am working on the assumption that I need interrupt pins so I don't miss any movements, and of course multiplexing opens up the way for movements to be lost.
However if I drop the need to use interrupts and use polling instead and do it fast enough it might well be fine.

Since I have 3 banks of 8, this could be achieved with 3 Teensy-LCs, or even better I could use atMega328p chips (CHEAP! and I already have a chipburning rig) at risk of going slower.

I'll need to think about this!!!
 
Am I on a hiding to nothing using interrupts on mechanical encoders anyway (debounce issues) ? Perhaps polling is a better way.

Interrupts seem to be universally implemented for optical encoders which is a very different ball game.
 
Am I on a hiding to nothing using interrupts on mechanical encoders anyway (debounce issues) ? Perhaps polling is a better way.

Interrupts seem to be universally implemented for optical encoders which is a very different ball game.

I guess its a speed thing in the end ... with mechanical encoders, there is a heck of a lot of bounce, I have found. I know nothing about optical encoders.

I use the following strategy for rotaries (I think I have just recently perfected it:cool:)

fast read on a polling basis, lets say 200 micro seconds .... take three of these... if they are the same, then you have a stable read. if you also have on the other channel a stable 3 times read, then apply the 'quadrature table'. Use a callback. In the callback count a couple and then 'do action CCW' etc.

Here is the ino ...

Code:
#include <myController.h>

Rotary encoder1 (2, 6); // 2 and 6 are Teensy pin numbers, left and right
Rotary encoder2 (3, 7);


//counters//
int a_clockwise_event;
int an_anticlockwise_event;
int rcount;
int lcount;

void setup() {
  encoder1.SetHandleLeft (Left1);
  encoder1.SetHandleRight (Right1);
// encoder2.SetHandleLeft (Left2); // later ...
// encoder2.SetHandleRight (Right2);
  }

void loop() {
  Rotary::ReadWrite(); // starts things for all encoders
}

//callbacks (for encoder1 only)//

void Right1 (void) {
  rcount++;
  if (rcount > 3) {
    rcount=0;
    a_clockwise_event ++;
    }
  }

void Left1 (void) {
  lcount++;
  if (lcount > 3) {
    lcount=0;
    an_anticlockwise_event ++;
    }
  }
Here is my library code minus the header (set up for max of 4 encoders ...) :
Code:
#include <myController.h>

uint8_t Rotary::objectIndex = 0;
Rotary * RobjArray[4] {NULL, NULL, NULL, NULL};
const int8_t encState [16] {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
elapsedMicros RotaryTimer;


void Rotary::SetHandleLeft(void (*Left) (void)) {
  pLeft = Left;
}

void Rotary::SetHandleRight (void (*Right) (void)) {
  pRight = Right;
}

void Rotary::ReadWrite() {
	if ((RotaryTimer - 200) >= 0) {
		RotaryTimer = 0;
		RotaryRead();
		for (int i = 0; i < 4; i++) {
			if (RobjArray[i]) {
				RobjArray[i]->rotaryA <<= 1;
				RobjArray[i]->rotaryB <<= 1;
				RobjArray[i]->rotaryA |= RobjArray[i]->rotaryAraw;
				RobjArray[i]->rotaryB |= RobjArray[i]->rotaryBraw;
				RobjArray[i]->RDDB = 0;
				RobjArray[i]->rotaryA &= 0x0F;
				RobjArray[i]->rotaryB &= 0x0F;
				if (RobjArray[i]->rotaryA == 15) {
					RobjArray[i]->RDDB = 1;
				}
				else if (RobjArray[i]->rotaryA == 0) {}
				else {
					return;
				}
				if (RobjArray[i]->rotaryB == 15) {
					RobjArray[i]->RDDB |= (1 << 1);
				}
				else if (RobjArray[i]->rotaryB == 0) {}
				else {
					return;
				}
				RobjArray[i]->rotaryData <<= 2;
				RobjArray[i]->rotaryData |= RobjArray[i]->RDDB;
				RobjArray[i]->rotaryState = (encState[(RobjArray[i]->rotaryData & 0x0F)]);
				if (RobjArray[i]->rotaryState > 0) {
					if (RobjArray[i]->pLeft) {
						RobjArray[i]->pLeft();
					}
				}
				if (RobjArray[i]->rotaryState < 0) {
					if (RobjArray[i]->pRight) {
						RobjArray[i]->pRight();
					}
				}
			}
		}
	}
}

void Rotary::RotaryRead () {
	for (int i = 0; i < 4; i++) {
    if (RobjArray[i]) {
      RobjArray[i]->rotaryAraw = digitalReadFast (RobjArray[i]->leftPin);
      RobjArray[i]->rotaryBraw = digitalReadFast (RobjArray[i]->rightPin);
    }
  }
}
 
Am I on a hiding to nothing using interrupts on mechanical encoders anyway (debounce issues) ? Perhaps polling is a better way.
You definitely don't need interrupts or hardware decoders to read quite a few hand-turned mechanical decoders. That stuff isn't necessarily helpful if you have bounce issues.

Also keep in mind that mechanical encoders are rated for pretty low rotation speeds (if you go above, the signals turn to crap), so you don't need a terribly high polling frequency.

You have written a lot, but not what your encoders actually are. ;)
Interrupts seem to be universally implemented for optical encoders which is a very different ball game.
For high speed, that's what you would want. But there is also this kind:
https://www.digikey.com/product-detail/en/cts-electrocomponents/291V1022F624AB/CT3042-ND/3045550
for hand/low speed operation. These optical encoders works 100x better than the mechanical versions, but are unfortunately rather expensive.

Multi-channel LED drivers with serial interface (I2C, SPI or some shift register) can be had extremely cheap, I don't see the point in using a PWM input version. From what I have seen, they are cheaper than I2C/SPI -> PWM converters.

If you go with a slightly bigger Atmega (those 40/44 pin guys), you could get away with 1 per board (8 encoders). If you can easily bring all the wires to a single location, the Teensy with a multiplexer is an option as well (switch/poll something like 12 inputs in parallel).
 
Thanks Adrian! That's awesome!

Sorry its been mad - just a quick response;

I intend to use these: https://www.sparkfun.com/products/10982

I think i'll go for a bigger atmega chip, but are they available in a pluggable socket arrangement? Such that I could burn them on the bench and plug them into the pcb?
 
Status
Not open for further replies.
Back
Top