Skip to content

Week04

Embedded programming

Assignment

Group assignment:

  • Demonstrate and compare the toolchains and development workflows for available embedded architectures
  • Document your work to the group work page and reflect on your individual page what you learned

Individual assignments

  • Browse through the datasheet for a microcontroller
  • Write and test a program for an embedded system using a microcontroller to interact (with local input &/or output devices) and communicate (with remote wired or wireless connections)

Group Assignment

Our document for group assignment.

LPC1114FN28

Datasheet: https://www.nxp.jp/docs/en/data-sheet/LPC111X.pdf

User manual: https://www.nxp.jp/webapp/Download?colCode=UM10398&location=null

NXP’s LPC1114FN28 is one of my favorite MCU, it have my favorite processor core Arm Cortex-M and easy to play DIP28 package. In addition, it was cheaper than 8 bit ATmega328P. Faults of this MCU are 1) Too wide package 2) small amount RAM. I ported this processor to Mbed OS 10+ years ago, so I read datasheet of this MCU deeply. When I saw this assignment, I remember this MCU at first. So that I dug this MCU from my inventory.

https://os.mbed.com/users/ytsuboi/notebook/getting-started-with-mbed-lpc1114-ja/

Bare metal

The toolchain I’m using for bare metal programming for Arm Cortex-M this time is GCC. I used brew to install GCC.

% brew install --cask gcc-arm-embedded

So that, brew will download package from developer.arm.com and install it.

Arm Cortex-M is memory-mapped I/O. Memory-mapped I/O uses the same address space to access both main memory and I/O devices. The memory and registers of the I/O devices are mapped to address values, so a memory address may refer to either a portion of physical RAM or to memory and registers of the I/O device.

I’m going to blink a LED connected to LPC1114FN28’s pin 14.

LPC1114FN28 pinout

From this figure page 18 of “LPC1110/11/12/13/14/15 Product data sheet Rev. 9.2 — 26 March 2014”, pin 14 is PIO1_5 this mean we need to toggle the register value of 5th bit of port 1 register.

LPC1114’s GPIO (General Purpose Input/Output) register address and stracture can be found on User Manual. Pictures below are from page 192-193 of “UM10398 LPC111x/LPC11Cxx User manual Rev. 12.5 — 13 August 2024”.

Register description

GPIO direction

GPIO pins can be configured as input or output by software, and reset value of GPIO data direction register are 0x00. It means when LPC1114FN28 start, all of GPIO pins are configured as input. So, if I want to blink LED connected to P1_5, I need to configure 5th bit of port 1 as output, it means set 1 on 5th bit of of port 1 GPIO data direction register. And the GPIO data direction register address for port 1 is 0x50018000.

GPIO data

After configuring GPIO pin as output, we can control GPIO output state by changing value of GPIO data register. If I want to output HIGH on P1_5, I just need to set 1 on 5th bit port 1 GPIO data register. To output LOW, set 0. The GPIO data register address for port 1 is 0x50013FFC.

main.c
#include "LPC11xx.h"

int main(void) {

LPC_GPIO1->DIR |= (1 << 5);

    while(1)
    {
        LPC_GPIO1->DATA ^= (1 << 5); // Toggle P1_5 by using XOR
        for (int i=0; i<1000000;i++); // loop for delay
    }
}

We can use register address directly but I used LPC11xx-LPCXpresso-CMSIS. It was provided by NXP long time ago. Normally, semiconductors are providing this kind of example code for customers convenience.

I included LPC11xx.h because it defines all structures and symbols for LPC11xx.

main.c
#include "LPC11xx.h"

int main(void) {

#define P1DIR   (*((volatile uint32_t *) 0x50018000 ))
#define P1DATA  (*((volatile uint32_t *) 0x50013FFC ))

P1DIR |= (1 << 5);

  while(1)
  {
    P1DATA ^= (1 << 5); // Toggle P1_5 by using XOR
    for (int i=0; i<1000000;i++); // loop for delay
  }
}

If I directly designate register address, the code should be like this and it also works.

There are timer on LPC1114FN28, but I choose easy way to put some delay between toggling GPIO output state. Since I connected anode of LED to P1_5, LED will be turned on when P1_5 state is HIGH. ( Cathode of LED was connected to GND through 1k ohm register.)

When we drive something with microcontroller’s GPIO directly, we’d better to check if the microcontroller can drive.

This figure is from page 86 of “LPC1110/11/12/13/14/15 Product data sheet Rev. 9.2 — 26 March 2014”. From this figure, it looks ok to drive LED directly. If the chip’s cuurent drive capability isn’t enough, we need to consider to drive it through MOSFET and other way,

On the other hand, Vf of the LED I used is 2.1 V. Supply voltage is 3.3 V and current limit register is 1k ohm. So, the current LED consume would be around 1.2 mA.

ISP (In-System Programming)

I needed install USB-UART bridge driver on my new Apple silicon Mac mini. The chip I used was FTDI FT232RNL. Device driver for this chip can be downloaded from VCP Drivers page. After downloading, I needed to copy the installer onto Applications folder. Launched the installer so I could install the driver. After installing, I enabled the driver.

After connecting USB-UART bridge, I could confirm now the bridge is working.

% ls /dev/tty.usbserial-*

LPC1114 has ISP (In-System Programming) that can flash a program through UART (Universal Asynchronous Receiver/Transmitter). To flash, there are a tool named lpc21isp to transfer a program through UART from host computer. I used Homebrew to install lpc21isp.

% brew install lpc21isp

LPC1114FN28’s RXD is on pin 15, TXD is on pin 16. So connect TXD of USB-UART bridge to pin 15 and RXD to pin 16. Also we need to connect GND of both LPC1114FN28 and USB-UART bridge.

To put LPC1114 into ISP mode, put PIO0_1 (24th pin) LOW when LPC1114 powered on or return from reset. I connected 24th pin to GND by jumper wire and pressed reset button, and disconnected jumper wire after releasing reset button. Then, I flashed finished binary to microcontroller like this.

% lpc21isp -control -bin main.bin /dev/tty.usbserial-XXXXXXXX 115200 48000
lpc21isp version 1.97
File main.bin:
    loaded...
    image size : 8024
Image size : 8024
Synchronizing (ESC to abort). OK
Read bootcode version: 1
7
Read part ID: LPC1114.../102, 32 kiB FLASH / 4 kiB SRAM (0x1A40902B)
Will start programming at Sector 1 if possible, and conclude with Sector 0 to ensure that checksum is written last.
Erasing sector 0 first, to invalidate checksum. OK 
Sector 1: ...........................|.........................|.........................|.....................
Sector 0: ..........................|.........................|.........................|.........................
Download Finished... taking 5 seconds
Now launching the brand new code

So, a LED connected to pin 14 of LPC1114FN28 blink!!

If you want to reproduce this, you can do by following step.

% git clone https://github.com/ytsuboi/LPC1114-BareMetal-Blinky.git
% git clone https://github.com/ytsuboi/LPC11xx-LPCXpresso-CMSIS.git
% cd LPC1114-BareMetal-Blinky
% make

Mbed

Arm Announced End of Life Timeline for Mbed, but I’m going to use Mbed OS maybe as the last. Anyway, I tried to control I²C 8 char x 2 line text lcd AQM0802A-RN-GBW from LPC1114FN28.

I²C (Inter-Integrated Circuit, pronounced as “eye-squared-see”) is a synchronous, multi-master/multi-slave, serial communication bus invented by Philips Semiconductors (now NXP). I²C uses two signal lines, SDA (Serial data) and SCL (Serial clock). We are going to let LPC1114FN28 communicate with AQM0802A-RN-GBW through I²C and display something on it.

I used Keil Studio Cloud at this time.

New project

Open Keil Studio Cloud and created new project.

New project

Because LPC1114FN28 only has 4kB memory, we’d better to use mbed2, the classic one doesn’t include RTOS. So, I choose “mbed2-example-blinky”, and named this project as “mbed2-AQM0802A”.

Library page

There is a AQM0802A-RN-GBW library for mbed. I wanted to use this library to reduce time and trouble. I’ve got URL to import this library from this button.

Add Mbed lib

Next, I added library by right clicking project name and choose “Add Mbed Library…”.

Adding lib

I pasted library URL, so that library name will be appeared.

choosing branch

Choosed “default” branch.

Coding

So, the library will be imported to your project. The code I wrote was:

main.cpp
#include "mbed.h"
#include <AQM0802A.h>

AQM0802A lcd(dp5, dp27);

int main() {
  lcd.cls();
  lcd.printf(" FabLab\n Nagoya");
}

Built

Build your project with hummer icon “Build your project” button. If there are no error on build process, compiled binary will be start downloading automatically. If you are using Mbed board, you can flash that binary bu drag and drop the file. If you aren’t you can use ISP or other way to flash it.

pin out

SCL on LPC1114 is pin 27, SDA is pin 5. So I connected power (VDD and GND) and I2C lines between LPC1114FN28 and AQM0802A.

It works!!

Arduino Uno (ATmega328P)

The microcontroller on Arduino Uno is ATmega328P, a AVR series from Microchip Technology.

Datasheet: https://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

Bare metal

To install toolchain for AVR, I used Homebrew.

% brew tap osx-cross/avr
% brew install avr-gcc avr-binutils avrdude

and wrote a code.

main.c
#include <avr/io.h>
#include <util/delay.h>

int main(void) {

    DDRB |= (1 << DDB5); // set PB5 as output

    while(1) 
    {
    PORTB ^= (1 << PORTB5); // Toggle PB5
     _delay_ms(1000); // wait 1 sec
    }
}
We are using AVR-LibC. “avr/io.h” switches header file by MCU type and it is “iom328p.h” for ATmega328P.

ATmega328P is also memory-mapped I/O. Let’s look into Port B register, it’s on page 72 of 7810D–AVR–01/15 ATmega328P.

13.4.2 PORTB – The Port B Data Register

And we can find same address on iom328p.h.

#define PORTB _SFR_IO8(0x05)
#define PORTB0 0
#define PORTB1 1
#define PORTB2 2
#define PORTB3 3
#define PORTB4 4
#define PORTB5 5
#define PORTB6 6
#define PORTB7 7

and Makefile

Makefile
default:
    avr-gcc -Os -DF_CPU=16000000UL -mmcu=atmega328p -c -o main.o main.c
    avr-gcc -o main.bin main.o
    avr-objcopy -j .text -j .data -R .eeprom -O ihex main.bin main.hex

clean:
    rm -f main.o main.bin main.hex
finally, compile the sourcecode.
% make
so that we can get HEX file. Microcontroller on Arduino Uno has bootloader named optiboot. Optiboot flash a program when it receive commands and data to flash through UART like ISP of LPC1114FN28. LPC1114FN28 itself has ISP function but ATmega328P doesn’t.

We can send a commands and data to flash with avrdude. Avrdude communicate with Arduino Uno through USB serial, so we need to know the name of serial device at first. And then run avrdude with that serial port.

% ls /dev/tty.usbmodem*
/dev/tty.usbmodemXXXXX
% avrdude -F -V -c arduino -p ATMEGA328P -P /dev/tty.usbmodemXXXXX -b 115200 -U flash:w:main.hex

The repository for this code: https://github.com/ytsuboi/ATmega328P-BareMetal

Arduino IDE

Arduino IDE has gcc and avrdude inside, so you just need to install Arduino IDE from Arduino Software page. I’m using Legacy IDE, so I used Arduino IDE 1.8.19 at this time.

Arduino IDE

Let me skip explaining how to use Arduino IDE, there are tons of documents how to use. You can see avrdude works internally from the message from Arduino IDE.

I found a potentiometer Grove module in my drawer, so I connected this module’s output to A0 of Arduino Uno. And wrote short sketch to make something interactive.

int val = 0;

void setup() {
  pinMode(LED_BUILTIN, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  val = analogRead(A0);
  Serial.println(val);
  if (val <= 500) {
    digitalWrite(LED_BUILTIN, LOW);
  } else {
    digitalWrite(LED_BUILTIN, HIGH);    
  }
  delay(1000);
}

The sketch control the state of LED on Arduino Uno board by reading value of A0 pin. By rotating the knob of potentiometer, reading value should be change between 0 and 1023. On this sketch, LED will be turned off when the value is lower than 500 otherwise LED will be turned on. Also there are Serial.println() in this sketch, so we can see the read value through Serial Monitor of Arduino IDE.

Serial Monitor

And it works!!

Checklist

  • Linked to the group assignment page
  • Browsed and documented some information from a microcontroller’s datasheet
  • Programmed a board to interact and communicate - interact communicate
  • Described the programming process(es) you used
  • Included your source code
  • Included ‘hero shot(s)’