08/ embedded programming



In this week we start to program the board we made two weeks ago. We have to:


1. compare the performance and development workflows for architectures

2. read a microcontroller data sheet

3. program my board to do something



← previous

→ next

⋯ assignment list

🏁/ final project



Group assignment

To understand the difference between computer architectures, I found this chart below from this site.

If you have time it will be helpful to read through this Chapter 1. An Introduction to Computer Architecture from "Designing Embedded Hardware, 2nd Edition" by John Catsoulis.

The ATtiny 44 we use for the class is an AVR microcontroller with RISC(reduced instruction set computer) Architecture. To compare its performance and development workflows with other architectures, I take a look at the Raspberry Pi 3 Model B+ board in the lab.

Raspberry Pi is a single-board computer. The whole board is like a spread-out and enlarged view of the inside universe of an ATtiny44 chip. The Raspberry Pi works similar to an ATtiny44 but is more powerful.

Raspberry Pi has a chip as well but the chip works as a microprocessor (ATtiny44 is a microcontroller), and thus it needs to work with other components from the board to process or communicate.

It uses an physical SD card for its operating system and data storage, and is able to load multiple programs at one time (ATtiny44 loads one at a time).

It has got more pin heads and connectors which allow the board to be connected to a screen or Internet or camera or other peripherals. These connectors are like a more advanced version of the leads of an ATtiny44 chip.

All Raspberry Pi models feature a Broadcom system on a chip (SoC) with an integrated ARM-compatible central processing unit (CPU) and on-chip graphics processing unit (GPU) (according to Wikipedia).

Here are specifications of Pi 3 Model B+ copied from its official site:

  • – Broadcom BCM2837B0, Cortex-A53 (ARMv8) 64-bit SoC @ 1.4GHz
  • – 1GB LPDDR2 SDRAM
  • – 2.4GHz and 5GHz IEEE 802.11.b/g/n/ac wireless LAN, Bluetooth 4.2, BLE
  • – Gigabit Ethernet over USB 2.0 (maximum throughput 300 Mbps)
  • – Extended 40-pin GPIO header
  • – Full-size HDMI
  • – 4 USB 2.0 ports
  • – CSI camera port for connecting a Raspberry Pi camera
  • – DSI display port for connecting a Raspberry Pi touchscreen display
  • – 4-pole stereo output and composite video port
  • – Micro SD port for loading your operating system and storing data
  • – 5V/2.5A DC power input
  • – Power-over-Ethernet (PoE) support (requires separate PoE HAT)

There are a wide range of operating systems you can run on Raspberry Pi, such as Raspbian provided by Raspberry Pi Foundation, third-party Ubuntu, Windows 10 IoT Core, RISC OS, and etc.. For programming languages you can write Python, C, C++, Java, Scratch, Ruby and so on.

This is a diagram showing how the ARM Cortex-A53 Processor works. For more detailed info you can read this reference manual.

Below are some useful links if you want to explore deeper:

Raspberry Pi I Architecture PDF by David Lor and Kaiwen Zheng

For comparison of different Raspberry Pi models

To learn how to set up rasbian


Read a microcontroller data sheet

To better understand how microcontroller works we need to read the ATtiny44 data sheet. The ATTiny44 is high Performance, low Power 8-bit Microcontroller with advanced RISC architecture.

It will be overwhelming if you start to read from the beginning. Go to page 281 to view the table of content and have a general understanding of what this microcontroller is consisted of and what each parts can do. Then go to contents that interest you.

Here are some of an ATTiny44 chip's main features:

  • – 256 Bytes of Programmable EEPROM
  • – 4K Bytes of Flash Program Memory
  • – 256 bytes SRAM
  • – 12 programmable I/O Lines
  • – 32 general purpose working registers and 8-channel 10-bit ADC
  • – One 8-bit and one 16-bit Timer/Counter with Two PWM Channels
  • – Internal calibrated oscillator
  • – Operating voltage supply between 1.8 ~ 5.5V

Here are the pin configurations:

There are two kinds of ports:

  • Port A pins (PA0 to PA7) are 8-bit bi-directional I/O port with internal pull-up resistors
  • Port B pins (PB0 to PB3) are 4-bit bi-directional I/O port with internal pull-up resistors

"The AVR uses a Harvard architecture – with separate memories and buses for program and data. Instructions in the Program memory are executed with a single level pipelining. While one instruction is being executed, the next instruction is pre-fetched from the Program memory. This concept enables instructions to be executed in every clock cycle. The Program memory is In-System Reprogrammable Flash memory."

The chip contains four different clocks: the ADC Clock, the I/O Clock, the CPU Clock and the flash Clock. The default clock is the internal oscillator which runs at 8mHz.



Thanks to the TOC I find this Fuse Bytes chart including the three fuse bytes ATtiny44 uses. The fuses are read as logical zero, “0”, if they are programmed. This chart may be useful if I need to set fuses for my board.

Link to calculate fuse

To understand fuses check out this AVR Fuse Programming tutorial page and the whole AVR® Insights youtube playlist by Microchip Technology to have someone explain AVR to you.

Other things seem interesting:




Program my board to do something

I was able to make the board echo in Arduino serial monitor two weeks ago. This week I learned some basic arduino commands to control the button and light up the LED on my board.

I use Arduino IDE to write the program. It is a simple coding environment especially designed for AVR microchips. The programming language used for IDE is a simplified version of the C. IDE comes with many libraries of functions ready to use, and thousands of pages of documentation on www.arduino.cc website and online community.

Here are some useful command examples:

buttonState = digitalRead(buttonPin);
digitalWrite(LedPin, HIGH);
sensorValue = analogRead(sensorPin);
analogWrite(LedPin, luminosity);

The analogRead function reads analog input value ranging from 0 to 1023, and the analogWrite function outputs a limited range from 0 to 255.

To change the brightness of a LED or to control the direction of a servo motor there is a technique called PWM(Pulse Width Modulation). It allows us to vary the proportion of time when the signal is set to high or low over a consistent time interval in an analog fashion. Not all the pins are able to work with PWM. For ATtiny44 only pin5, 6, 7, 8 (ones connected with purple bubbles below) are PWM enabled.

This pinout diagram is helpful to match the ATtiny pin number with the IDE pin number when programming. For my board, the buttonPin = 7, LEDPin = 3.

The way I connect my FabISP and new board to my computer is slightly changed from previous. I soldered the bridge on the solder jumper back on my FabISP so the 2x3 ISP header is now connected to the VCC traces. Thus the new board gets 5V power supply from FabISP and no longer needs to connect to external power source with an FTDI cable.

I may later remove the bridge again when I need to program boards that work with 3.3V instead of 5V for some sensors can only work at 3.3V.

I sometimes get error messages showing problems upload to board, or board is not connected, or the serial port does not show up under the Port menu, although all the time my computer detects the existance of a USBtiny :( I later find out the reason is that one of the 2x3 ISP pinheaders went loose after many times I connect and disconnect them.

After the board is connected, I am able to load several test programs to it using Aduino IDE. Since I am using a pull-up resistor, when the button is pushed its status should be LOW instead of HIGH.

Serial communication is not necessary for the simple commands I have right now. It is mostly used to print command line out and debug. Since serial communication does not come with ATtiny44, if you have serial related codes, at the beginning of the program you need to include a SoftwareSerial library which allows serial communication on digital pins and uses software to replicate the functionality.

#include <SoftwareSerial.h>
#define RX    0   // pin12
#define TX    1   // pin13

SoftwareSerial Serial(RX, TX);

One thing we find during our class is that the LED blink runs about 8x slower than the delay time we set. This is probably because we are using the fuse file written in C by Niel, which may not contain the "divide by 8" fuse setting which is more commonly set for microcontrollers. Arduino expects the "divide by 8" setting on microcontroller and tries to make up for that. In our case, it slows down because our board works in normal speed. After burning the bootloader, the microcontroller's setting matchs with Arduino's, and the 8x slower issue gets solved.



After I tried modifying existing codes, I started to write one from scratch. It is a simple combination of the blink and press light up examples.

int buttonPin = 7;
int ledPin = 3;
int buttonState = 0;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop() {
  buttonState = digitalRead(buttonPin);

  if (buttonState == LOW){
    digitalWrite(ledPin, HIGH); 
  }
  
  else{
    digitalWrite(ledPin, HIGH);
    delay(100);

    digitalWrite(ledPin, LOW);
    delay(100);
  }
}

Later I find an interesting Arduino hold button example which enables the LED to have different performance when you hold the button down for different time length.

After I understand its structure, I modify it by adding different LED actions (blink or on) for different time the button gets hold. The original code writes a LEDblink function and calls it in the loop. It helps clean the codes up a bit and will be helpful when there are more LEDs.

Topic on Arduino forum on Single, double and hold button for myself to check later.

↓ download file: button_hold_test.ino or copy the code below.

/* code modified base on example from:
 *  https://playground.arduino.cc/Code/HoldButton
 */

int buttonPin = 7;
int ledPin = 3;
int buttonState = 0;

unsigned long firstTime;
byte previous = HIGH;

long millis_held; 
long secs_held;
long prev_secs_held;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(buttonPin, INPUT);
}

void loop() {
  
  buttonState = digitalRead(buttonPin);

  /* if button gets pushed, update start time */
  if (buttonState == LOW && previous == HIGH && (millis() - firstTime) > 10) {
    firstTime = millis();
  }

  millis_held = (millis() - firstTime);
  secs_held = millis_held / 1000;

  /* if button pressed more than 10ms debounce */
  if (millis_held > 10) {             

      /* when button is pressed down */
      if (buttonState == LOW && secs_held > prev_secs_held) {
          digitalWrite(ledPin, HIGH); 
          }

      /* when button is released */
      if (buttonState == HIGH && previous == LOW) {
          
          /* if hold button for more than 3 sec 
          LED on */
          if (secs_held >= 3) {
              digitalWrite(ledPin, HIGH); 
              }

          /* if hold button from 1-3 sec 
          quickly blink 10 times */
          if (secs_held >= 1 && secs_held < 3) {
              ledblink(10,80);
              }
              
          /* if hold button less than 1 sec 
          blink once */
          if (secs_held < 1) {
              ledblink(1, 100);
              }
        }
    }

   /* update */
   previous = buttonState;
   prev_secs_held = secs_held;
}

/* blink function */
void ledblink(int times, int lengthms){
  for (int x=0; x < times;x++) {
    digitalWrite(ledPin, HIGH);
    delay(lengthms);
    digitalWrite(ledPin, LOW);
    delay(lengthms);
  }
}

It's working :D

I also tried modify a C code file found on previous student's website and load it to my board.

First download the c file and make file into the same folder. Rename the .make file to Makefile with no extension. Open the C file with any text editor and modify the name of output pin, PORTA or PORTB to match with the pin, and delay time to set the blink speed. Save the file.

↓ download files: led-blink.c, Makefile

In terminal on Mac, cd to the folder with Makefile and c file, enter:

make
make program-usbtiny

It should work as below and you can see the LED starts blinking.

Later if I have time I'll learn how to write C from scratch. I may also explore CrossPack. Here are some links suggested by another students I may follow through later:

Writing the First Program to Turn On an LED and Transferring the Program into the Microcontroller

Programming AVR Microcontrollers in C - O'Reilly Webcast

(Updated 03.20.2019)