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