Microcontrollers vs PCs
- basic PC architecture: complex 32/64 bit CPU + RAM + I/O: disk, display, usb
- modern microcontrollers (MCUs)
- are full low-power computers on a single chip
- are based on simpler 8-bit CPUs (though there are more complex 16 and 32-bit MCUs)
- put the RAM on the same chip as the CPU
- and there is far less of it, typically 512 bytes to a few kB
- ATmega1284P we are using has 8kB RAM
- replace the disk with flash memory on the same chip as the CPU
- again, much less storage space
- typically a few kB to a few hundred kB
- ATmega1284P has 128kB flash
- replace the external I/O bus with on-chip peripherals
- high-resolution display interfaces are not common
- but USB is sometimes an option
- other forms of serial and parallel hardware interfaces are available
- analog-to-digital (A/D) and digital-to-analog (D/A) converters
- timers
- more below
- the low-level processor (LLP) on our robot is built around an Atmel ATmega1284P microcontroller
- it is an Orangutan SVP board
- this is similar to an Arduino but has extra hardware for robotics uses
- you will work with this processor and program it in C during the first part of the course
- prior experience in C is not necessary (but would be helpful)
- we will provide a software framework called the LLP monitor program
- you will add specific features to implement drive control
Bits and Bytes
- a bit is the smallest piece of state on any digital machine: a box that can hold 0 or 1
- a byte is 8 bits: 2^8 = 256 possible patterns
- RAM can be thought of as an array of bytes
- first byte is at address zero
- last byte is at address N-1 where N is the RAM size in bytes (e.g. 128k = 128*1024)
- modern PCs usually have Von Neuman architecture
- processor retrieves both instructions (coded as patterns of bytes) and data a single unified memory
- AVR processors have Harvard architecture
- instructions stored in flash (only)
- data stored in RAM (usually)
- also possible to put unchanging data values (e.g. string constants) in flash
- requires some inconvenience when accessing in C
- but saves precious bytes of RAM
- what happens when a computer first turns on?
- the processor tries to read its first instruction from a pre-defined memory location
- hopefully, someone has put a good instruction there!
- on a PC this is typically in the BIOS (Basic Input/Output System) memory area, which is a little bit of flash memory attached to the motherboard
- on an MCU it is usually just a well-defined address (such as address zero) in the flash
- the procesor reads that instruction and its operands
- the processor executes the instruction
- might load data into the processor for a subsequen operation
- might redirect execution so that the next instruction is read from an arbitrary memory address
- the next instruction is then fetched from the next bytes of memory (unless execution was redirected)
- rinse and repeat!
- the art of programming is to fill the memory with good instructions =)
- it is possible to literally program the flash on an MCU by specifying the bit pattern for each byte: machine code
- not so easy to write or debug code that way
- next step up is to use an assembler: reads a text file with instruction and operand mnemonics, translates those to machine code
- still very low level, can take several lines just to add two integers
- (show arch fig, instruction set from avr manual)
- (show example of dissassembly)
- next step up: C
Main Concepts of C Programming
- summary of differences vs java
- datatypes
- int, unsigned, short, long, etc - byte sizes depend on system
- char
- in C99
#include <stdint.h>
for int8_t, uint8_t, int16_t
, etc - definite sizes
- IEEE754 float (32 bits) and double (64 bits)
- no bool or boolean — use int, 0=false, not zero=true
- pointers
- address-of operator &
- content-of operator *
- pointer arithmetic
- arrays: the name of an array is a pointer to its first element
- expressions, statements, control structures
- very similar to java
- technically, only /* comments */ in C
- but many compilers also allow // comments
- literals: numbers, characters, strings
- unlike java, no + for string concatenation
- arithmetic expressions, assignment statements
- type casts
- conditionals: if/then/else, switch
- loops & branching: for, while, do/while; break/continue, return
- functions
- mostly similar to java
- no enclosing classes, of course (though c does have
struct
s)
- in C, functions are usually first declared with a prototype, then later defined
- more on this when we talk about translation units
- in C all arguments are passed by value
- Java passes primitive types by value, but objects and arrays by reference
- pointers are used to have the effect of passing by reference in C
- local and global variables
- similar to java
- local variables, including function argument values, are stored on a stack
- when a function returns, all its variables are “popped”
- control returns to the calling function, whose variables remain on the stack (and are now back at the top)
- C allows variables to be declared outside of functions
- these are essentially “global”
- they can be accessed from any function (there are some ways to control visibility)
- they exist for the duration of the program
- dynamic memory allocation
- in Java, all Objects (arrays and class instances) live on the heap
- space for each is allocated with
new
- space is reclaimed automatically by the garbage collector when an object can no longer be referenced
- C also has a heap, with some differences
- you call the function
malloc()
instead of new
- malloc really just allocates blocks of bytes
- you don’t have to put arrays on the heap, they can also go on the stack like other local variables
- you must explicitly
free()
memory when you’re done with it
- birds-eye view of the whole memory map on an AVR
- instruction space (flash), data space (RAM), and I/O space
- stack grows down from end of data space
- global vars at start of data space
- heap grows up from end of globals
- the preprocessor
- text replacement
#define, #include, #ifdef
- header files, translation units
- the compiler
- the linker
- .o object modules
- .a libraries
- you will learn more about the preprocessor, compiler, and linker in LAB0
- the C standard library
- goodies in stdlib.h, stdio.h, math.h, etc
- the Pololu AVR library
- reference documentation
- A good general book on the standard C language is Harbison and Steele C: A Reference Manual, 5th Ed. This one covers the standard library (printf(), malloc(), etc) in addition to the language itself, but is still not too thick.
- On Unix systems, usually the “manpages” for standard C library calls (again, printf() etc) are installed, so you can type “man printf” at any command prompt and get good documentation. Because the functions have mostly standard functionality both on Unix and on the AVR, the documentation mostly applies to both. (Note, in a few cases there are higher level commands on Unix with the same name. On many Linux systems, printf is one example — it can be called directly from the command line. To disambiguate and say you want the documentation for the C-level system call, type “man 3 printf”.)
- The manpages are also very important to help understand the tools, e.g. “man gcc” (there is no separate manpage for avr-gcc), “man make”, “man avrdude”, etc.
- For our use on the AVR, the AVR Libc User Manual is very important. It documents both the standard C library calls implmented by gcc-avr, as well as very useful AVR-specific extensions.
- And for our use specifically on the Pololu Orangutan SVP, the Pololu AVR Library Command Reference documents all the calls available from the Pololu AVR library.
Peripherals and Special Function Registers (SFRs)
- MCUs typically contain a variet of on chip peripherals
- in some ways these take the place of off-chip devices in standard PCs, especially for I/O, e.g. USB
- other common types of peripherals on MCUs include timers and counters, digital I/O ports, various types of synchronous serial ports, analog to digital converters and digital to analog converters, etc
- peripherals are typically accessed by reading/writing data to special function registers, SFRs
- the Atmel ATmega1284P Reference Manual describes all the on-chip peripherals of the ATmega1284P MCU on the Orangutan SVP
- the AVR Libc User Manual further describes helpful libraries that are available to deal with some of these
Interrupts
- in part because we often use them without an operating system, interrupts are more prominent in MCU programming than on PCs
- most MCUs are designed so that the regular execution path can be temporarily suspended when a variety of events occur, for example
- when the voltage level on a specified pin changes, signalling something in the physical world
- when an on-chip timer peripheral reaches a certain value
- when a data byte has been received by an on-chip serial port peripheral
- execution then jumps to an interrupt service routine (ISR), also called an interrupt vector
- you write code there that does whatever you want to handle the condition
- you then return from the interrupt; the system returns to the mainline execution where it left off
- interrupts can be convenient because they relieve you from having to constantly monitor for events to occur
- they can also add complexity, especially when data values are shared (read and written) between code running in interupt and non-interrupt context
- consider a write to a 4-byte integer
i
on AVR; this takes at least four sequential instructions
- what if an interrupt occurs right after the second of those four instructions
- the ISR will see a partially updated version of
i
where the first two bytes have the new value and the latter two the old
- the ISR could itself write to
i
…
- for these reasons, when data is shared between interrupt and non-interrupt context, any read or write to it from non-interrupt context is usually bracketed by a disable/enable of the interrupt