1. Introduction to Bits and Atoms
3. General AVR Programming Workflow in Windows 10
We can think about bits and atoms as an abstraction of software and hardware, respectively. This analogy blows my mind. Understanding that physical and digital world should not be treated separately will open you to you a whole new world where bits and atoms go hand by hand shaping our everyday reality. I know I'm starting to becoming a bit philosophical but this duality is present everywhere. It is present across different scales in biology, in musical instruments, embedded systems that we use to satisfy our everyday needs and many more... More importantly as a researcher, I feel ashamed that I never spent the time to learn the way things in the world of embedded computing work. In fact, I spent time learning superficially an abstraction wrapped around the way things work, designed to protect me from the way things work as Elliot Williams mentions in his wonderful book about AVR microcontrollers. And yes. These manifesto lines are about Arduino, shields etc. Although the Arduino environment is good for getting people hooked on microcontrollers, it’s a cheap high.
These microcomputers stand directly in the middle ground between the hardware world of buttons, motors, and lights and the software world of algorithms, connectivity, and infinite possibility. Combining the electronics design and production skills with embedded programming will allow me to bring ideas to life faster, better and cheaper! Lets dive in.
If the goal of this week is to get me building projects with microcontrollers (MCUs) and writing my own firmware (or using libraries from other people) in C, I need to understand what and how these MCUs we use in HTMAA do. I’ve chosen the Atmel AVR series MCUs to focus on because they have a fantastic free and open toolchain, easily available programming hardware, and off course because I have already interacted with them in the form of Arduinos.
At their core, microcontrollers have a processor that is similar to the CPU on your computer. The processor reads
instructions from a memory space (in flash memory rather than on a hard drive), sends math off to an arithmetic
logic unit (instead of a math coprocessor), and stores variables in RAM while your program is running. Many of
the chips have dedicated serial hardware that enables them to communicate to the outside world. Like any computer
they can be programmed with a variety of programming languages following the classical design-code compile-run
-debug cycle. We use the C programming language, which is the gold standard for the programming of embedded
Thus, MCUs are just tiny computers on-a-chip.
computers. One thing to notice is that the chips in the AVR product line, from ATtiny15 to ATmega328, include the flash program memory space in kilobytes in the chip’s name. So, we’re talking about 1 KB to 32 KB of room for my code. MCUs have limited RAM as well. The ATTTINY 44 that we’ll be focusing on here have 256 bytes of DATA RAM size. Although it’s entirely possible to interface with external RAM to get around this limitation, most of the time, the limited working memory is just something you’ll have to live with. On the other hand, 256 bytes isn't that limiting for blinking a couple of LEDs.The typical microcontroller application takes an input data stream, processes it relatively quickly, and shuttles it along as soon as possible with comparatively little buffering.
Continuing on specs, the CPU core clocks of the AVR MCUs run from 1 to 20 megahertz (when used with an external crystal like in Neil's board), rather than the handful of gigahertz I am probably used to. Even with the AVR’s RISC design, which gets close to one instruction per cycle, the raw processing speed of a microcontroller doesn’t hold a candle to a modern PC. Finally, the AVR family of microcontrollers have 8-bit CPUs without a floating-point math coprocessor inside. This means that most of the math and computation you do will involve 8-bit or 16-bit numbers.
Because the computer that’s inside the microcontrollers is truly micro, some more of the niceties that I'm used to in my PC aren’t present. There’s no operating system, which means that there’s no built-in provision for multitasking. Built-in hardware interrupt, clock, and timer peripherals will help me get around this limitation. On the other hand, the built-in hardware serial interface means that I don’t have to write serial drivers, but merely put mty byte in the right place and wait for it to get transmitted. Built-in pulse-width modulation hardware allows you to just write a byte in memory and then the AVR will toggle a voltage putput accordingly with fractional microsecond precision.
The first task is to learn how to write and compile code for the AVR, and then get that code written into the chip’s flash program memory. By the end of Chapter 2, you’ll have an LED blinking back at you from your breadboard.
The short answer to this question is by reading voltages applied to its various pins or by setting up output voltages to these very same pins. Blinking an LED is a good example according to which the output voltage is high, the LED lights up and when the voltage is low, it doesn't. More complicated examples include the serial ports that communicate numbers by encoding them in binary, with high voltage standing in for a 1 and low voltage standing in for a 0, and changing the voltage on the pins over time to convey arbitrary messages.
Each pin on the AVR has a name that you can use to refer to them in code. Most of the pins on the AVR also have secondary functions, and these are listed as mnemonics in parentheses. Internally, and somewhat according to function, the pins are arranged into banks of eight pins. Because each bank, has a maximum of eight pins in it, you can refer to them by an eight-bit binary number to turn on or off their voltage source and onward. Rounding out the miles-high overview here, I can access all of these pins and their various functions from within my code by reading from and writing to special I/O registers in the chip, which your code will be able to access as if they were any other variable.
The Core: Processor, Memory and I/O
2. Memory: Flash, RAM, EEPROM
3. Clocks: When you’re using any of the peripheral subsystems, remember the clock prescalers—you’ll often have to set their values.
1. Serial communications (serial hardware peripherals): USART, SPI, I2C
2. Analog to digital converter: A number of the useful sensors that I'd like to connect to my projects don’t speak the microcontroller’s native digital language; rather, they speak in terms of continuous analog voltages. To read in these values and manipulate them like you’ll manipulate any other digital data, you’ll need to run them through an analog to digital converter (ADC).
4. Timers/counters: they keep a running count of how many times a pin or internal source has changed its voltage level. Counters really come into their own when paired up with clocks, and this is why they’re often referred to as timer/counters. With a clock and a timer, you can measure either how long some event takes, or the event’s frequency. I’ll even be able to output to certain AVR pins (OCRxn in the pinout diagram) and fire off special subroutines periodically. The timer/counter peripherals are tremendously configurable and turn out to provide more functionality than I would have thought.
The take out message here is that the code I write has physical side effects on the chip: directly controlling or reading the voltage levels on the pins.
STEP 1: Write your source code in an editor.
STEP 2: Turn the source code into machine code with a compiler (ans associated software tools)
STEP 3: Using uploader software on my PC and a hardware flash programmer, send the machine code to target AVR chip, which stores the instruction sin its nonvolatile flash memory.
STEP 4: As soon as the flash programmer is done, the AVR chip resets and starts running the code.
Below I list all the necessary steps I followed to get all the necessary software tools in first place.
1. GNU AVR toolchain installation on Windows 10
Brian's tutorial is excellent! I followed that and everything worked like a breeze.
If you’re using a programmer that ends in a standard 6-pin or 10-pin two-row IDC connector, getting the pinout correct can be a little bit tricky. For orientation, set the connector on the table so that you’re looking down into the holes, and notice the location of the plastic tab. The cable should also have a red stripe on the same side that has the VCC pin, which is a very helpful mnemonic. Hook up the power pins so that they look like Figure 2-6.
3. AVRDUDE After you’ve gotten the circuit breadboarded and the AVR connected up to the programmer, you’re ready to start talking to the AVR to test the connection. And, believe it or not, the easiest way to do this is to type a little bit.
4. Configuring your Makefile