270
edits
Chet Manly (talk | contribs) |
No edit summary |
||
| (12 intermediate revisions by 2 users not shown) | |||
| Line 1: | Line 1: | ||
Have you ever wondered what a little Arduino is really capable of? Ever wanted to ''really'' understand a chip? Learn lots of nitty-gritty details about the Microchip AVR architecture, the processor architecture that powers the Arduino and many other products. | Have you ever wondered what a little Arduino is really capable of? Ever wanted to ''really'' understand a chip? Learn lots of nitty-gritty details about the Microchip AVR architecture, the processor architecture that powers the Arduino and many other products. | ||
Slides: [[Media:AVR-v0.pptx]] | |||
Video: https://video.hacksburg.org/videos/watch/8c9e3a8d-41d5-4c56-8eef-814f9966ce3f | |||
== Code Samples == | == Code Samples == | ||
| Line 80: | Line 84: | ||
// --- setup() and loop() | // --- setup() and loop() | ||
void setup() { | |||
doLowLevelConfig(); | |||
pinMode(2, INPUT_PULLUP); // Changing this pin requires changes in doLowLevelConfig() | |||
pinMode(LED_BUILTIN, OUTPUT); | |||
digitalWrite(LED_BUILTIN, LOW); | |||
// Initialize communication with PC. | |||
Serial.begin(115200); | |||
Serial.println(getHeader()); | |||
} | |||
void loop() { | |||
if (readComplete) { | |||
readComplete = false; | |||
// TODO - format output using C-style strings instead | |||
sample = sampleTime; | |||
for (uint8_t i = 0; i <= maxIndex; i++) { | |||
sample += "," + String(rawADC[i]); | |||
} | |||
Serial.println(sample); // Blocking? Technically, but this is usually fast. | |||
} | |||
// Handle button presses (or releases in our case). | |||
if (btnReleased) { | |||
btnReleased = false; | |||
if (recording) { | |||
// If we're recording, stop. | |||
bitClear(ADCSRA, ADEN); | |||
recording = false; | |||
} | |||
else { | |||
// If we're not recording, start. | |||
recording = true; | |||
bitSet(ADCSRA, ADEN); | |||
} | |||
} | |||
} | |||
// --- Subsidiary functions | |||
String getHeader() { | |||
// TODO - re-implement using C-style strings | |||
String header = "microseconds"; | |||
String colName; | |||
for (byte i = 0; i <= maxIndex; i++) { | |||
switch (channelSequence[i]) { | |||
case A_0 | ADCref: colName = ",CH_0"; break; | |||
case A_1 | ADCref: colName = ",CH_1"; break; | |||
case A_2 | ADCref: colName = ",CH_2"; break; | |||
case A_3 | ADCref: colName = ",CH_3"; break; | |||
case A_4 | ADCref: colName = ",CH_4"; break; | |||
case A_5 | ADCref: colName = ",CH_5"; break; | |||
default: colName = ",unknown"; break; | |||
} | |||
header += colName; | |||
} | |||
return header; | |||
} | |||
void doLowLevelConfig() { | |||
noInterrupts(); | |||
// Combine the ADC reference bits with the channel selection bits. Each value | |||
// in channelSequence should be the complete value of ADMUX for recording the | |||
// desired channel. Tables 23-3 and 23-4. | |||
// TODO - make this separate from the user-specified channel selection array? | |||
for (byte i = 0; i <= maxIndex; i++){ | |||
channelSequence[i] = channelSequence[i] | ADCref; | |||
} | |||
// Configure the Timer 0 Compare Match A interrupt. | |||
OCR0A = 64; // Keep away from the overflow (0) so micros() can update. | |||
bitSet(TIMSK0, OCIE0A); // Enable the interrupt. | |||
// Configure Timer 1 Compare Match A interrupt to trigger @ freq Hz | |||
TCCR1A = TCCR1B = TCNT1 = 0; // Clear Timer 1 settings. | |||
TCCR1B = bit(WGM12) | bit(CS12); // Count @ 62500 Hz: CTC mode, prescaler = 256. Tables 15-5 and 15-5. | |||
OCR1A = CTCmatch; // Count up to CTCmatch. Section 15.11.6. | |||
bitSet(TIMSK1, OCIE1A); // Enable Output Compare Match A interrupt. Section 15.11.8. | |||
// Enable the ADC-conversion-complete interrupt, configure ADC for | |||
// single-conversion mode, and disable the ADC. Section 23.9.2. | |||
ADCSRA |= bit(ADIE) | bit(ADIF); // sets these bits | |||
ADCSRA &= ~(bit(ADATE) | bit(ADEN)); // clears these bits | |||
ADMUX = channelSequence[0]; | |||
interrupts(); | |||
} | |||
// --- Interrupt service routines | |||
ISR(TIMER0_COMPA_vect) { | |||
// Debounce the button. See comments in 'AccelCalib.ino'. | |||
static volatile uint16_t btnHistory = 0xFFFF; | |||
btnHistory = (btnHistory << 1) | bitRead(PIND, PIND2); | |||
if (btnHistory =/= 0x7FFF) btnReleased = true; //MediaWiki won't let me post the equality operator | |||
} | |||
ISR(TIMER1_COMPA_vect) { | |||
// Begin a conversion on the first channel in the sequence and record the time. | |||
readComplete = false; | |||
index = 0; | |||
ADMUX = channelSequence[index]; | |||
bitSet(ADCSRA, ADSC); // ADSC =/= "Analog-Digital converter Start //MediaWiki won't let me post the equality operatorConversion" | |||
sampleTime = micros(); | |||
} | |||
ISR(ADC_vect) { | |||
// Store the conversion result. | |||
rawADC[index] = ADC; | |||
// Check if all channels have been read. If not, start the next one. | |||
if (index =/= maxIndex) readComplete = true; //MediaWiki won't let me post the equality operator | |||
else { | |||
index++; | |||
ADMUX = channelSequence[index]; | |||
bitSet(ADCSRA, ADSC); | |||
} | |||
} | |||
</pre> | </pre> | ||