9. Embedded programming¶
Week 09¶
Assignment:
Group assignment
Compare the performance and development workflows for different microcontroller families
Document your work (in a group or individually)
Individual assignment
Read the datasheet for the microcontroller you are programming
Program the board you have made to do something, with as many different programming languages and programming environments as possible.
Identify relevant information in a microcontroller datasheet.
Implement programming protocols.
I really have no idea where to start off this week so I checked out the pages of fablab students who went before me. I found this helpful presentation by Will Rudolph on the basics of C. I also flipped through a ton of the Fab Academy presentations and projects that were linked, those were super helpful (as always).
Datasheet¶
I will be programming my Hello World Board from week07 which uses the ATTiny412 microcontroller. The first part of the assignment was to read the datasheet. I read this Sparkfun Tutorial which advised on how to approach reading a datasheet, because this is 500 pages and I’d rather understand as much as possible on the first go then have to go back.
(There also is a datasheet summary available) How a chip as tiny as this can have 500 pages worth of information written about it was beyond me. But I do believe I learned a lot from what I read. It was very confusing, but I think through trying to understand it I gained a lot of knowledge not only about how microcontrollers worked but also just generally about how these types of electronics are designed(not just the attiny412).
I first had to learn to distinguish microcontrollers from microprocessors. Niel mentioned it in his lecture but I also found this source explaining things in more detail. They both have the same purpose and a CPU unit but the biggest difference is the microprocessor has many more peripherals and therefore more built in functions. The additional peripherals and functions can be added onto a microprocessor externally. Microprocessors aren’t always necessarily better because they have more functions, microcontrollers are very useful and can perform specific tasks very well for a reduction in size and cost.
It outlines many of the features on the first couple of pages. It also outlines the interior workings of the chips functions on the Block Diagram, seeing the layout was very helpful in helping me gain a bit more insight into how the hardware worked.
It also then explained how this affected the pinout of the diagram. I usually just google what pin I need to be using for different functions. I understand a little bit about what each pin “does” but this showed me what each pin was connected to in the block diagram, and gives me more information about the different uses of each pin.
I had heard of most of these acronyms before but I didn’t really understand the pins’ different uses. Just the first few pages helped me a lot with understanding the general electronics behind not just an Attiny412 but microprocessors in general.
It also gives a brief definition of many of the different types of memory and what I will use them for, which is helpful because now I understand why certain types of instructions have to go to different memories and how they work. I found this reading interesting on how memory is stored electronically. It also helped define a lot of terms I really didn’t understand yet.
This describes a bit about how the logic works (scroll down to question 2 for specifics about logic in microcontrollers) in this specific architecture, with this chip (Harvard Architecture). It implements an Arithmetic Logic unit.
The flow of the hardware interacting with the software. There are also diagrams of this for every individual peripheral.
Honestly all of this section was very important in explaining how to configure pins.
This part explains how to make sure you doesn’t break it by overloading it with too much electricity(volts, current, amps…) or heat, and also what the power consumption of the device and all of its peripherals are (volts, current, amps again…) each part needs. This should be very helpful in designing boards. It gave a very detailed definition and description of all the peripherals.
Programming the Board¶
Setup¶
I will be using a board similar to the ArduinoUno (the Elegoo Uno R3) as a programmer board. The original plan was to use a programmer board I designed, but I don’t have access to the lab anymore (The county I live in is under a stay-at-home order) and I thought using this would be more efficient until I can get back into the lab and make my own programmer. I experimented with using an arduino in week07, electronics design week, but I eventually ended up using a programmer I borrowed from Dr. Harris. I had planned on making my own programmer this week, however we are not in the lab anymore and I have an arduino handy, so I decided to use that because it was the most readily available.
Here was my setup from week07:
This is the setup I used this week:
Technically, the board in the image is the arduino nano, but the same setup still works. I referenced this site for the setup. I later referenced that site for programming with the Arduino IDE. For now I am still waiting to get access to a few parts, but while I am I will document the software and all the setup for programming, and then report on my results when I gain access to the parts I need.
TinkerCircuits¶
I started this week by making a very simple circuit in tinkercad and generating a blink code in C.
I made this block code for this setup:
This is my code in a type of C/C ++ Code, which Arduino uses. I used this mainly to get a better look at C code so I could try to understand it better and write it myself later.
void setup()
{
pinMode(6, OUTPUT);
}
void loop()
{
digitalWrite(6, HIGH);
delay(1000); // Wait for 1000 millisecond(s)
digitalWrite(6, LOW);
delay(1000); // Wait for 1000 millisecond(s)
}
Arduino IDE¶
I started by uploading the Jtag2UPDI code to Arduino IDE. This code was necessary because it tells the arduino it should be acting as a programmer. That way, when I upload the code I want to be loaded onto the attiny, the code will simply be sent through the arduino and to the attiny. If I skipped this step, the arduino would not know that I was trying to upload a blink code to an attiny, and would instead load the blink code onto the arduino’s own microcontroller.
I then installed the board manager package by going to File -> Preferences and uploading this URL: http://drazzy.com/package_drazzy.com_index.json
to “Additional Boards Manager URL.” The board manager was necessary because Arduino IDE needs to know what board it is uploading to. Attiny412 is not one of the boards that the Arduino Ide recognizes and can interact with, but the drazzy package contains the information Arduino IDE needs to interact with the attiny412.
I navigated through Tools -> Boards -> Board Manager downloaded the first Spence Konde “megaTinyCore” option.
Under Tools, I made sure my my board was selected as the “attiny412,” a com port was selected, and my programmer was set as “jtag2updi”. I then tried to upload my C code from tinkercad to the circuit. The only change I made was changing the pin number to “6,” so that it matched the GPIO pin the LED was attached to on the attiny412.
However, It did not work. The IDE said my code had successfully been uploaded, but the LED did nothing. I tried the other two name options on the data sheet, “PA6” and “0”, to no avail. However, when I tried PA6, I did get an error message. It said that “PA6 was not declared in this scope”
I googled the error message, and I realized I probably had the name of the pin wrong. However, I could not seem to figure out the naming convention for an attiny412 pin using megatinycore. I eventually just asked my peers, and one of their recommendations was to use “PIN_PA6” to define my pin. Using that name, I was able to upload the sketch successfully
Arduino Code:
void setup()
{
pinMode(6, OUTPUT);
}
void loop()
{
digitalWrite(6, HIGH);
delay(1000); // Wait for 1000 millisecond(s)
digitalWrite(6, LOW);
delay(1000); // Wait for 1000 millisecond(s)
}
Atmel¶
Atmel was a bit more difficult to figure out. I started by downloading the software here. I had used arduino IDE before, just to upload code to an arduino. I had never used atmel studio 7 before. Fortunately, I found this tutorial which walked me through setting up atmel and then uploading my code.
First, I opened the program, navigated through “File -> New -> Project,” and opened a “GCC Executable Project,”
It prompted me to select the microcontroller I was uploading to, which is the attiny412.
I was then brought to this screen:
It seems that the format is a bit different than arduino.The program only has “int main(void)” and a “while(1)’ statement. I googled while(1), and in english it essential means “while ___, execute the following:” The 1 is a boolean condition being passed into the while statement. The boolean condition can either equal true or false. Entering any non-zero integer makes the statement read “while true” and run forever. It seems that this loop is the equivalent of the “void loop()” function in arduino IDE, which is meant to run infinitely, so I put my main code under the while loop and my setup code under the “int main(void)” function.
In the top menu, I then navigate to “Build -> Build Solutions.” Unfortunately, I got the error message that my build had failed, along with a list of errors. I assumed this was more issues with the non-clemature of my code. I was able to find this page in the datasheet, which directed me on how to set pins as inputs/outputs, and how to toggle them high and low.
To set pin 6 of port a to output (or turn the output function “on”), I had to write a bit 1 (“on”) to PORTA.DIRSET for pin 6 .
To toggle pin6 as on or off, I had to write a byte of 1(on) or a byte of 0 (off) tothe register which controls PA6 with the PORTA.OUT command.
I was still a bit confused as to how to write the bit and include the 6, so I watched this video for programming an attiny45 with atmel. Attiny412’s have very different syntax, but this provided me with a basic structure for the syntax I was able to reference. To set PA6 as an output:
PORTA.DIRSET |= (1 << 6);
To toggle the pin:
PORTA.OUT |= (1 << 6); //write a bit 1 to the register which controls PA6 (turning it on),
PORTA.OUT &= ~(1 << 6); //clear that register (turning it off).
When watching the video, I also realized I had been missing the following pieces of information: The attiny412 runs on a clock (as do all microcontrollers), and the clock/it’s speed needs to be defined in atmel when using the microcontroller.
At the beginning of the code, you must include
#define F_CPU 20000000UL
Secondly, the delay function is a library that needs to be imported on Atmel. It was already imported on Arduino, so I did not realize I needed to import it here. The function also has a slightly different syntax then in arduino. In arduino, the function is
delay(1000); //waits 1000 microseconds
In atmel 7, the function is
delay_ms(1000); //waits 1000 microseconds
And at the beginning of the sketch, you must import the delay library by including the lines
#include <util/delay.h>
I put it all together and came up with this:
#include <avr/io.h>
#define F_CPU 20000000 //20mhz
#include <avr/delay.h>
int main(void)
{
PORTA.DIRSET |= (1 << 6);
/* Replace with your application code */
while (1)
{
PORTA.OUT |= (1<<PA6) //set PA6 high
delay_ms(1000); //wait 1000 ms
PORTA.OUT &= ~ (1<<PA6) //set PA6 low
delay_ms(1000); //wait 1000 ms
}
}
I ran “Build-> Rebuild Solution” (you MUST use rebuild solution for compiling if you have already used “Build solution”)
It did not work, I ran into this error message.
I was not sure exactly what had to change, so I looked at an example code our Fab Lab instructor Mr. Rudolph had provided us with last week.
define F_CPU 20000000
include <avr/delay.h>
include <avr/io.h>
uint8_t counter;
void setup() {
PORTA.DIRCLR |= PIN7_bm; //Set PA7 to input
PORTA.PIN7CTRL |= PORT_PULLUPEN_bm; //Set pullup resistor on PA7
PORTA.DIRSET |= PIN6_bm; //Set PA6 as output
}
void loop() {
if(~PORTA.IN & PIN7_bm){ //check to see if PA7 is pulled low
while(~PORTA.IN & PIN7_bm){ //wait until PA7 returns high
_delay_ms(5);
counter++;
if(counter >= 5){
PORTA.OUT |= PIN6_bm; //set PA6 LOW
_delay_ms(1000);
PORTA.OUT &= ~PIN6_bm; //set PA6 HIGH
}
}
}
I noticed that while I had used
delay_ms(1000);
He had used
_delay_ms(1000);
I added the underscore and the function instantly turned another color. In hindsight, the fact that the function was not another color should have been a warning flag in my head, typically functions turn other colors when they are fully written out. I rebuilt it again, and this time my build was successful!
Actual final code:
/*
* hello.world.2.c
*
* Created: 6/20/2020 2:55:57 PM
* Author : sv2852
*/
#include <avr/io.h>
#define F_CPU 20000000 //20mhz
#include <avr/delay.h>
int main(void)
{
PORTA.DIRSET |= (1 << 6);
/* Replace with your application code */
while (1)
{
PORTA.OUT |= (1<<6); //set PA6 high
_delay_ms(1000); //wait 1000 ms
PORTA.OUT &= ~ (1<<6); //set PA6 low
_delay_ms(1000); //wait 1000 ms
}
}
I then went back to the video tutorial on uploading code and configured Atmel to work with AVRdude, the “program for downloading and uploading the on-chip memories of Atmel’s AVR microcontrollers,” according to the linked site.
I navigated to “Tools -> Device Programming” The video tutorial I had been following up until this point was using AVRISP mkII as a programmer, which is similar to the typical programmer I use when programming an arduino. However, I am using the Jtag2updi wiring/setup for programming, so I found another tutorial which showed me how to load the jtag2updi protocol.
I first went to “Tools -> Device Pack Manager.” It asked me if I wanted the Device Pack manager to be allowed to make changes to my device, I said yes.
I went to install the Attiny412 device package manager (DPM) as the tutorial instructed. Somehow, it was already installed.
I then closed the Device Package Manager and went to “Tools -> External Tools” I then created a new tooland for jtag2updi as a hardware programmer that uses avrdude with the following settings:
Title:
jtag2updi ATtiny412
Command:
C:\Program Files\avrdude\avrdude.exe
(Where my avrdude.exe file was stored)
Arguments:
avrdude -P com4 -c jtag2updi -p t402w -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i```
I changed the com to “com 4” because that is the one that opens when I use arduino IDE with the arduino uno board I am using. I then hit ok and went back to “Tools -> Device Programming.” However, nothing showed up, and it would not let me select anything as the tool, device, interface, etc. In fact, when I hovered over the “Tool” dropdown, a little box with the word “Simulator” would pop up. The video noted that the device must be plugged in, which it was, the arduino’s light was on and the attiny’s LED was still flashing from the arduino code that was uploaded earlier.
I tried closing and reopening the program. When I reopened my file, the code did not show up, and it said “no device selected.” Thankfully, I had already copied my code, but I was pretty sure this was not supposed to happen.
I was pretty sure I had missed a step when creating the GCC executable file/done something wrong, so I created a new file and tried building the solution again. I then opened the device programming menu, but there was still nothing. I started clicking around, and actually clicked on something that said “jtag2updi Attiny412” under tools. It said this tool was not a valid programmer.
I went back into “Tools -> External Tools” to edit the jtag2updi programmer. I was not entirely sure why it was invalid, so I started changing the arguments. I found this separate tutorial using jtag2updi on atmel, and I realized I may have multiple instances of the avrdude.exe and avrdude.conf files. I had downloaded avrdude outside of arduino, but megaTinyCore and Arduino had their own versions of these files. I believe Atmel needs to use the same ones arduino uses.
I changed the location of the avrdudue.exe file to match the file that arduino used and changed the arguments so they would call the avrdude.conf file from the megatinycore files:
-P COM4 -C C:\Users\sv285\AppData\Local\Arduino15\packages\megaTinyCore\hardware\megaavr\2.0.2\avrdude.conf -c jtag2updi -p t412 -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i
Finally, it worked! I changed the code so that it would wait 2 seconds before blinking, so that when it overrode the arduino code I could tell it had actually worked.