| RSGC ACES' AVR Optimization: Drilling Down |
With a high-level understanding of microcontroller-based interfacing sufficiently entrenched in your skill set, it's time to examine performance optimization options. Using the 8-bit AVR family of microprocessors as our platform, investigations will include an overview of the native language of the (any) processor (called Assembly), the on-board memories, the ports, the registers, and the peripherals of the devices within ATMEL's 8-bit family. A solid understanding of these concepts will make for an easy transition to ARM and Intel devices on your own.
To better prepare for the depths we will descend to in our remaining terms, we'll begin with a review of some of the basic C language elements. Develop code to confirm the result where requested.
// Purpose: To confirm fundamental AVR-gcc data type elements and integer storage sizes
// Reference: https://en.wikipedia.org/wiki/C_data_types
// Author: C. D'Arcy
// Date: 2017 03 17
// Status: Working
#include <limits.h>
char buff[50];
char data = 0x80;
void setup() {
// Open the serial port at 9600 bps:
Serial.begin(9600);
while (!Serial);
Serial.println("AVR-libc's (implementation of Standard C) Fixed Point Data Types (memory size in bytes):");
Serial.println(sizeof(char) + String(" :char"));
Serial.println(sizeof(signed char) + String(" :signed char"));
Serial.println(sizeof(unsigned char) + String(" :unsigned char"));
Serial.println(sizeof(short) + String(" :short"));
Serial.println(sizeof(short int) + String(" :short int"));
Serial.println(sizeof(signed short) + String(" :signed short"));
Serial.println(sizeof(signed short int) + String(" :signed short int"));
Serial.println(sizeof(unsigned short) + String(" :unsigned short"));
Serial.println(sizeof(unsigned short int) + String(" :unsigned short int"));
Serial.println(sizeof(int) + String(" :int"));
Serial.println(sizeof(signed) + String(" :signed"));
Serial.println(sizeof(signed int) + String(" :signed int"));
Serial.println(sizeof(unsigned) + String(" :unsigned"));
Serial.println(sizeof(unsigned int) + String(" :unsigned int"));
Serial.println(sizeof(long) + String(" :long"));
Serial.println(sizeof(long int) + String(" :long int"));
Serial.println(sizeof(signed long) + String(" :signed long"));
Serial.println(sizeof(signed long int) + String(" :signed long int"));
Serial.println(sizeof(unsigned long) + String(" :unsigned long"));
Serial.println(sizeof(unsigned long int) + String(" :unsigned long int"));
Serial.println(sizeof(long long) + String(" :long long"));
Serial.println(sizeof(long long int) + String(" :long long int"));
Serial.println(sizeof(signed long long) + String(" :signed long long"));
Serial.println(sizeof(signed long long int) + String(" :signed long long int"));
Serial.println(sizeof(unsigned long long) + String(" :unsigned long long"));
Serial.println(sizeof(unsigned long long int) + String(" :unsigned long long int"));
// Floating point...
Serial.println("Standard C Floating Point Data Types (memory size in bytes):");
Serial.println(sizeof(float) + String(" :float"));
Serial.println(sizeof(double) + String(" :double"));
Serial.println(sizeof(long double) + String(" :long double"));
// limits...
sprintf(buff, "Signed char:\t[%hi,%hi]", SCHAR_MIN, SCHAR_MAX);
Serial.println(buff);
sprintf(buff, "Unsigned char:\t[0,%hu]",UCHAR_MAX);
Serial.println(buff);
sprintf(buff, "Signed short:\t(%d,%d)", SHRT_MIN, SHRT_MAX);
Serial.println(buff);
sprintf(buff, "Unsigned short:\t[0,%u]", USHRT_MAX);
Serial.println(buff);
sprintf(buff, "Signed int:\t[%i,%i]", INT_MIN, INT_MAX);
Serial.println(buff);
sprintf(buff, "Unsigned int:\t[0,%u]", UINT_MAX);
Serial.println(buff);
sprintf(buff, "Signed long:\t[%li,%li]", LONG_MIN, LONG_MAX);
Serial.println(buff);
sprintf(buff, "Unsigned long:\t[0,%lu]", ULONG_LONG_MAX);
Serial.println(buff);
}
void loop() {}
void loop(){
while (Serial.available() == 0);
uint8_t data = Serial.read();
Serial.println(data);
// Serial.write(data);
}
Predict the result of disabling the println statement and enabling the write function. Try it. 
uint8_t value = 200; Serial.println(value<<1); value <<= 1; Serial.println(value);
int8_t number = -1; Serial.println(number,BIN); Serial.println((uint8_t)number,BIN);
Bit Manipulation
Although a byte (8 bits) is the smallest memory size that can be reserved for a variable, the individual bits within a byte can be assigned different roles in the world of microcontrollers. The ability to set (1), clear (0) or toggle an individual bit, or group of bits, while leaving the others unaffected, is an essential assembly skill. You're familiarity with digital logic gates (ie AND, OR, NOT, etc.) is about to prove handy.
Serial.println(11&5); Serial.println(11|5); Serial.println(~5);
Serial.println(15&7<<1); Serial.println(0xAA&036); Serial.println(254|1); Serial.println(~10^1<<2); Serial.println(value&1);
The digital I/O pins are grouped into sets of 8, called Ports, named A, B, C, and so on. A quick review of the Arduino Pin Mapping diagram reveals there is no PortA, but there is a PortB, PortC and PortD. PortD can be found on chip pins 2-6,11-13. Bits 6 and 7 of PortC appear to be inaccessible and the bits of PortB can be found on both sides of this DIL-28 package. Adding to the confusion is the somewhat random mapping from the chip pins to the header pins. A review of the Port resources for the ATtiny85 reveals only 6 available pins of a PortB (PB0-PB5).
External Interrupts (Great Reference: Nick Gammon's Notes)
| Simple As Possible Processor | ATmega328 Interrupt Vector Table |
|---|---|
![]() |
![]() |
