Monday, 11 July 2016

Multiplexing A3144 hall sensors with an Arduino/AVR

After deciding to go down the "open source" route for producing an electronic board game, we've spent quite a bit of time focussing on almost the opposite end of the market for hobbyists and gamers - originally we focussed very much on mass production, cheap components, robustness and simplicity for gaining the necessary CE marks and other standards required for selling a manufactured product.

With a self-assembled kit of parts, from an open source list of components, we're focussing much more on ease of use, familiarity and "hackability".

Which inevitably means shoe-horning an Arduino in there somewhere.
Our original electronics for the board game were based around a super-cheap PIC 16F1829 (with plenty of internal pull-up resistors, an internal clock running at up to 32mhz) and an A2892 source driver IC (to provide power to each row of hall sensors).

But that was back when we were making a 12x12 grid of sensors. Or when we were looking at an 8x6 grid. Or even 6x6 shaped PCBs for a dungeon crawler type of game. But now we're looking at a 7x7 square grid per board section, possibly running off an Arduino/AVR...

And so, in the name of simplifying things for the Arduino hobbyists, we checked out the datasheets for the A3144 hall sensors and the AVR atmega328P.

(typical values for an A3144 hall sensor)


The A3144 typically uses 4.4mA as the supply current.
We've got 7 of them in a row. That's 7 x 4.4  = 30.8mA if all the sensors in a single row are powered at the same time (we're multiplexing, so only one row is active at any one time anyway).

Modern PICs can generally sink about 40mA but many still only source up to 20mA. Looking at the datasheets for our 16F1829 it says it's a symmetrical i/o port, sinking and sourcing up to 25mA. Just not quite enough.

However, atmega chips can sink and source up to 40mA per i/o pin.
What if....?

If we could source the power for an entire row of seven hall sensors from a single output pin on an  (atmega328 powered) Arduino then we could simplify the design even further and lose the need for a current driver too - simply hook up the sensors directly to the Arduino i/o pins: something that a lot of electronics hobbyist users would be more used to doing.

All we needed to do was try the idea out and see how it fared....

Here's some simple firmware for the Arduino. It uses digital pins 2-8 for the "outputs" (driving each row of hall sensors at a time) and pins 9-12 for the inputs (we only hooked up four of the seven inputs, for ease of use while testing).



int row=0;
int col=0;
int inputValue=0;
int lastValue[]={0,0,0,0,0,0,0,0};
int k;
int j;
bool led;

void setup() {
     // put your setup code here, to run once:
     for(int i=2; i<=8; i++){
          pinMode(i,OUTPUT);
     }

     pinMode(9,INPUT_PULLUP);
     pinMode(10,INPUT_PULLUP);
     pinMode(11,INPUT_PULLUP);
     pinMode(12,INPUT_PULLUP);

     pinMode(13,OUTPUT);

     delay(500);
     Serial.begin(9600);
     Serial.println(F("Let's go"));
     led=false;
        
}

void clearAllPins(){
     for(int i=2; i<=8; i++){
          digitalWrite(i, LOW);
     }
}

void getInputValue(){
     inputValue=0;
     int bitValue=1;
   
     for(int i=0; i<=3; i++){
          k = digitalRead(i+9);
          if(k==LOW){ inputValue+= bitValue;}
          bitValue = bitValue << 1;
     }

}

void loop() {
     // put your main code here, to run repeatedly:

     clearAllPins();
     digitalWrite((row+2), HIGH);
     delay(5);
     getInputValue();

     j=lastValue[row];
   
     if(inputValue!=j){
          Serial.print("row: ");
          Serial.print(row);
          Serial.print(" old value: ");
          Serial.print(j);
          Serial.print(" new value: ");
          Serial.println(inputValue);
          lastValue[row] = inputValue;   
     }

     row++;
     if(row>=7){ row=0;}
   
}


And the end result was...


Success. Sort of.
As we moved the magnet over the sensors, each one triggered and released as expected. Almost perfect operation! Almost. Because this time, we had to use a much larger magnet than with our PIC-based design.


The magnet at the top of the image is 10mm across and 2mm deep. This triggered the sensors when driven directly from the Arduino i/o ports. The smaller magnets are the ones we used for testing our PIC-based board (with dedicated current driver). They are just 8mm across and only 0.5mm deep.

The smaller magnets still work with the Arduino-based test rig, but they need to be placed exactly over the top of each sensor. The larger magnet allowed for a bit of imprecision when placing it (which is what we need, when using it to trigger the sensors from inside a playing piece on a board game). The larger magnet also worked on the reverse side of the board, through 6mm thick mdf. The smaller magnets could not be detected from the underside of the 6mm mdf.

So there we have it - if we compromise on the size of the magnets used in the playing pieces (i.e. go bigger, whereas we've tried to keep them as small as possible) we'll be able to simplify the electronics to just a PCB with an atmega on it (and the usual supply caps of course!) and a diode on the ground pin (swap the polarity of your power supply on an atmega and it goes pop very quickly).

And of course, for the open source brigade (some people are really quite militant about it) we can also now include an Arduino instead of one of those tricky-to-use, industrial-strength PIC microcontrollers - AVRs and Arduino are already the de-facto for hacking and doing your own thing with.

If we were looking at manufacturing, I'd absolutely insist on PIC, even if it meant adding the source driver. But for simplified open source kits that anyone can make themselves... well, Arduino seems to have that corner of the market well and truly sewn up. We'd be crazy not to take advantage!