I am working on a project which flashes and sequences 16 different sets of LEDs. I'm using an Arduino Nano so I'm using D2-D13 plus A0-A3 to get 16 different digital outputs. I am using A4 and A5 for I2C to drive an LCD character display with a backpack. And finally, I have 2 buttons to control the speed and pattern. The only pins left was A6 and A7, so that's where I connected the buttons.
It all basically works, and reasonably well! But I am doing software PWM on all 16 outputs and I am trying to optimize and gain some speed to get rid of the noticeable flicker. I have already changed all the output code to do direct port manipulation rather than digitalWrite() and that has helped quite a bit.
I've been doing some research, and it seems that pins A6 and A7 on the Nano and Mini can only be used with analogRead() as they don't directly connect to any of the port pins. I've also been reading up on how analogRead actually works behind the scenes and the hardware and process involved. The most detailed discussion I've found is here: http://www.instructables.com/id/Girino-Fast-Arduino-Oscilloscope/?ALLSTEPS I've gotten a lot of theory, but I'm missing some specifics. I'm trying to write a fast digitalRead function for just these 2 pins. I don't care about resolution because I am using A6 and A7 as digital inputs with pushbuttons attached, not analog.
So it seems to write my own routine I need to do several things:
1: Set the prescaler to a low value to get speed at the expense of resolution.
2: Set the ADC Control Register ADCMUX to select which channel I want to read. In my case, A6 and A7.
3: Start the ADC process.
4: Check Status / Wait for it to finish / Go do something else for up to 108us.
5: Read the value from the ADCL and ADCH registers. Bit placement depends on ADLAR being 0 or 1.
So, now how do I do each of these things? Best as I can determine, to select the input channel, I just need:
// Set Analog Input Multiplexer for Channel 6, using lowest 4 bits of ADMUX register
// Set ADLR low on bit 5, and bits 6 and 7 should be low to select AREF as the voltage reference source
ADMUX = 6;
(or = 7 for pin A7)
To start the conversion process:
ADCSRA |= 0x40; // Turn on bit 6 (ADSC) of the ADCSRA register.
Then wait or go do something else (I know how to do that!)
Then if the button is pressed, bits 0 and 1 of the ADHC register will correspond to the highest 2 bits (8 and 9) of the 10-bit conversion value. I can check that with:
if (ADHC) {
// Button is pressed...
(Assuming that ADLAR = 0, as it was set above)
Life is never simple of course, and obviously I am missing something(s) as my test sketch doesn't work. Here's the full test sketch:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address and pin numbers
bool speedButton = false;
bool patButton = false;
void setup() {
lcd.begin(16,2);
lcd.backlight();
// Clear lowest 3 bits to set the prescaler to "2" and get the fastest sampling rate at the expense of resolution
//ADCSRA |= 0xf8;
} // End void setup{}
void loop() {
// Set Analog Input Multiplexer for Channel 6, using lowest 4 bits of ADMUX register
// Set ADLR low on bit 5, and bits 6 and 7 should be low to select AREF as the voltage reference source
//ADMUX = 6;
// Start Conversion
ADCSRA |= 0x40; // Turn on bit 6 (ADSC) of the ADCSRA register
//go do something else here... waste some time while waiting for A-D conversion.
//might as well update the display while waiting!
lcd.setCursor(0,0);
if (patButton) {
lcd.print ("PATTERN!!");
} else {
lcd.print ("nopattern");
}
speedButton = (ADCH);
// Set Analog Input Multiplexer for Channel 7, using lowest 4 bits of ADMUX register
// Set ADLR low on bit 5, and bits 6 and 7 should be low to select AREF as the voltage reference source
ADMUX = 7;
// Start Conversion
ADCSRA |= 0x40; // Turn on bit 6 (ADSC) of the ADCSRA register
//go do something else here... waste some time while waiting for A-D conversion.
//might as well update the display while waiting!
lcd.setCursor(0,1);
if (patButton) {
lcd.print ("SPEED!!");
} else {
lcd.print ("nospeed");
}
patButton = (ADCH);
} // End void loop()
Can anyone tell me what I'm missing?