Events/2020/AVR

From Hacksburg Wiki
< Events‎ | 2020
Revision as of 12:58, 24 January 2021 by Chet Manly (talk | contribs) (Code Samples)
Jump to navigation Jump to search

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.

Code Samples

#define __AVR_ATmega328P__

#include "https://raw.githubusercontent.com/vancegroup-mirrors/avr-libc/master/avr-libc/include/stdlib.h"
#include "https://raw.githubusercontent.com/vancegroup-mirrors/avr-libc/master/avr-libc/include/avr/io.h"
#include "https://raw.githubusercontent.com/vancegroup-mirrors/avr-libc/master/avr-libc/include/avr/interrupt.h"

#define DIRECTION_PORT DDRB

int main()
{
   const int DIRECTION_MASK = 0b00001110;
   uint8_t direction = 0b00001010;
   // https://github.com/gnea/grbl/blob/master/grbl/stepper.c#L324
   DIRECTION_PORT = (DIRECTION_PORT & ~DIRECTION_MASK) | (direction & DIRECTION_MASK);
   cli();
   sei();
   return 0;
}
/*
  This code takes ADC readings at a constant rate and prints them to the serial
  port. Output is formatted to be CSV-compatible - simply copy the contents of
  the serial monitor to a text file. The channels to be digitized are specified
  by the array 'channelSequence' - use the channel names defined directly above
  it in the code. Sample rate is controlled by setting 'freq' - this expects an
  integer value in Hz. The ADC voltage reference is controlled by 'ADCref'. Use
  one of the three values defined immediately above it.
  
  Written exclusively for the Arduino Uno - makes direct use of the ATMEGA328's
  low-level registers, so not guaranteed to work on other microcontrollers.

  -nj 2020-10-12
*/

// --- User-set variables for sample rate, ADC range and channels sampled

// Redefine this to change the frequency of ADC readings.
// One channel is stable at up to ~833.33 Hz
const uint16_t freq = 150; // Hz

// ADMUX values to select ADC voltage reference. Table 23-3.
#define EXT 0b00000000 // External voltage reference
#define VCC 0b01000000 // 5 V
#define I11 0b11000000 // 1.1 V

// Redefine this to change what voltage the ADC uses as Vmax.
const uint8_t ADCref = I11;

// ADMUX values to select different channels. Table 23-4.
#define A_0 0b00000000
#define A_1 0b00000001
#define A_2 0b00000010
#define A_3 0b00000011
#define A_4 0b00000100
#define A_5 0b00000101

// Redefine this to change which channels get digitized and in what order.
volatile uint8_t channelSequence[] = { A_0, A_1, A_2 };

// --- Variables used for sampling the ADC
const volatile uint8_t maxIndex = sizeof(channelSequence) - 1; // sizeof(array) / sizeof(array[0]) for non-byte types
volatile uint16_t rawADC[sizeof(channelSequence)];
volatile uint8_t index;
volatile unsigned long sampleTime;
volatile bool readComplete = false;
String sample = "";

const uint16_t CTCmatch = 62500 / freq - 1; // Note deliberate use of integer division

// --- Variables used to control recording
volatile bool btnReleased = false;
bool recording = false;

// --- 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);
    }
  }
}