Compiling ARM assembler for Raspberry Pi

When compiling assembly source code on the raspberry pi we need to do the following: take your source file e.g. source.s and run the as (assembler) command to create an object file:

as -o source.o source.s

This will create an object file named source.o
We now need to link the object files together into one executable file (it’s possible that you will have multiple object files, see below for how to link multiple source files) to do this we run the ld (linker) command:

ld -o source source.o

This will have created an executable file called source. The previous steps will work fine for assembly source files assuming that you have a function called _start within your source.s file which is the entry point for our code.

Another method is to use the gcc compiler which has a built in linker. In this case we generate the object files as above. Once we have the object files we run GCC with the following command.

gcc -o source source.o

This will have the same effect as running the linker. However as we are using the C compiler our source code file needs to acknowlege this by using the entry point named main rather than _start.

If we have functions in seperate source files then we need to create multiple object files. Before we link them. This is acheived by first creating all of our object files. e.g.

as -o source.o source.s
as -o source1.o source1.s
as -o source2.o source2.s
as -o source3.o source3.s

When we have all our object files created we link them all together like:

ld -o source source.o source1.o source2.o source3.o

or using GCC:

gcc -o source source.o source1.o source2.o source3.o

Creating .img files for Bare Metal

If you are coding for bare metal then you will need to convert your file to an image file do be dropped into the OS. I usually call these files kernel.img.

The first thing that we need to do is create a .ELF file. this is done using GCC with a command similar to the following:

gcc -o kernel.elf mykernel.c

We then need to convert the .ELF file to our .IMG file. (a .ELF file is essentially already a binary file it just contains some extra pieces of information.) To convert to a .IMG we use the following or similar:

objcopy kernel.elf -O binary kernel.img

This should provide a kernel.img file that can replace a kernel file on raspbian for example and is essentially a new operating system.

A Note on file formats

.s is our source code in assembly language.
.c is our source code file written in C which is a higher level language than assembly.
.o is an object file, which is a conversion of our source files into machine code, they are a little like libraries in a way as they contain non directly executable code, and need to be compiled into an executable before they can run.
.elf is an executable and linkable format file, and is similar to an object file, but they contain the full program. Whereas a .o file could contain references to external symbols from libraries or other object files.
.img is a binary file of our executable stored as a disc image.

A Note on compiler commands

as starts our assembly compiler. Feed it with .s files.
gcc start our c compiler. Feed it with .c files.
ld starts our linker. This links our object files together that we created with as or gcc into a single binary file. Feed it with .o files.
objcopy converts between binary file formats.

Date and Time in Python

Example Code

1
2
3
4
5
6
7
8
9
10
11
12
13
import time
import datetime

print "Time in seconds since the epoch: %s" %time.time()
print "Current date and time: " , datetime.datetime.now()
print "Or like this: " ,datetime.datetime.now().strftime("%y-%m-%d-%H-%M")
print "Current year: ", datetime.date.today().strftime("%Y")
print "Month of year: ", datetime.date.today().strftime("%B")
print "Week number of the year: ", datetime.date.today().strftime("%W")
print "Weekday of the week: ", datetime.date.today().strftime("%w")
print "Day of year: ", datetime.date.today().strftime("%j")
print "Day of the month : ", datetime.date.today().strftime("%d")
print "Day of week: ", datetime.date.today().strftime("%A")

Output

1
2
3
4
5
6
7
8
9
10
Time in seconds since the epoch: 	1349271346.46
Current date and time: 2012-10-03 15:35:46.461491
Or like this: 12-10-03-15-35
Current year: 2012
Month of year: October
Week number of the year: 40
Weekday of the week: 3
Day of year: 277
Day of the month : 03
Day of week: Wednesday

Roll Your Own Raspberry Pi Kernel

Getting Started.

There are many distirbutions of operating systems avaialble for the Raspberry Pi. But what if you wanted to write your own? Where would you start if you wanted a realtime system without all the overheads of a bulky operating system. This is my work through on getting started with writing my own kernel from scratch for the Raspberry Pi. I will endeavour to write this in C, mainly because it’s a language that I am familiar with, but also as it has a track record of being the language used to write most of the operating systems today, and also because it is the goto language for interfacing directly with hardware which is ultimately what we are trying to do.

There are probably many tutorials out there already that show you how to do something similar. This is not meant to compete with them, and there are certainly no guarantees that it will match them. This blog isn’t really for you. It’s for me. Though you may find it useful.

Of the other tutorials that I have found two really stand out.

Baking Pi - A Tutorial for writing an OS for the Raspberry Pi, mainly in Assembly.
Valvers.com - A tutorial for compiling a system for the Raspberry Pi, written mainly in C.

Cross Compiling

I will be doing the majority of the work on my mac. The thing with doing that is that my mac has an Intel processor, where the Raspberry Pi has a Broadcom ARM chipset. Therefore what is known as a cross compiler is needed.

The GCC ARM Embedded Project on Launchpad provides a GCC toolchain to use on mac. Addtionally you could head to https://developer.arm.com/open-source/gnu-toolchain/gnu-rm which now holds the most recent and up to date compilers. However the easiest way to install the cross compiler on a mac is to use homebrew. To install the gcc cross compiler, first of all install homebrew and then install the compiler with the command brew install gcc-arm-none-eabi-49 You should also install at this time the gnu debugger. brew install gdb-arm-none-eabi
You can now type on the command line arm-none-eabi-gcc and if all is functioning you should see a response similar to the below.

1
2
3
>arm-none-eabi-gcc
arm-none-eabi-gcc: fatal error: no input files
compilation terminated.

Again you can test the debugger by typing arm-none-eabi-gdb If all is well this should open up the debugger on the command line. You can exit by typing quit and return.

The GCC settings for compiling code for the orginal Raspberry Pi can be found on the elinux page.

1
-Ofast -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s

As mentioned on that page, -Ofast may cause issues so it is recommended to use -O2 instead. Also -mcpu=arm1176jzf-s can be used in place of -march=armv6zk -mtune=arm1176jzf-s

For the Raspberry Pi 2 as it has a different architecture. The porcessor has been replaced by a quad core Cortex A7. To compile effectively for this processor the compiler options are:

1
-O2 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7

The Compiler and Linker

A compiler converts our C program into optimised assembly. No more no less.

The C compiler then asks the assembler to assemble that file into an object file. This will have relocateable machine code within along with symbol information that the linker will use.

The linker’s job is to link all the files together, hence the name linker, into a file that can be executed. The linker requires a linker script which tells the linker how to organise the object files. The linker will then resolve symbols to addresses when it has arranged all the objects according to the rules in the linker script.

Basically there are some things that need to happen before our c file can run. Variables need to be initialised. This is taken care of by an object file which is linked by the linker because the linker script will include a reference to it. The object file is called crt0.o

This code uses symbols that the linker can resolve to clear the start of the area where initialised variables start and end and will zero this memory section. It sets up a stack pointer, and always includes a call to _main. Symbols present in C code get prefixed with an underscore in the assembler version of code. So where the start of a C program is the main symbol, in assembler we refer to it as it’s assembler version which is _main.

The simplest c program

1
2
3
4
5
int main(void) {
while(1) {
}
return 0;
}

This basically does nothing, just implements an infinte loop which will hold all the code that we need to implement our kernel.

We compile with the following for the Broadcom BCM2835 (ARM1176)

1
arm-none-eabi-gcc -O2 -mfpu=vfp -mfloat-abi=hard -march=armv6zk -mtune=arm1176jzf-s mykernel.c

And we compile with the following for the Broadcom BCM2836 (ARM Cortex A7)

1
arm-none-eabi-gcc -O2 -mfpu=vfp -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 mykernel.c

GCC will compile the source code successfully but will fail with something similar to the following:

1
2
3
/usr/local/Cellar/gcc-arm-none-eabi-49/20150306/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/lib/fpu/libc.a(lib_a-exit.o): In function `exit':
exit.c:(.text.exit+0x2c): undefined reference to `_exit'
collect2: error: ld returned 1 exit status

Connect to MySQL server in C

Connecting to a mysql database from C is a fairly straightforward process. The following instructions should work on any Linux distro or UNIX computer.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <mysql.h>
#include <stdio.h>

main() {
MYSQL *conn;
MYSQL_RES *res;
MYSQL_ROW row;

char *server = "localhost";
char *user = "USER"; /* Enter your mysql username */
char *password = "PASSWORD"; /* Enter your mysql password */
char *database = "mysql";

conn = mysql_init(NULL);

/* Connect to the mysql database */
if (!mysql_real_connect(conn, server,
user, password, database, 0, NULL, 0)) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}

/* send SQL query */
if (mysql_query(conn, "show tables")) {
fprintf(stderr, "%s\n", mysql_error(conn));
exit(1);
}

res = mysql_use_result(conn);

/* output all table names */
printf("MySQL Tables in mysql database:\n");
while ((row = mysql_fetch_row(res)) != NULL)
printf("%s \n", row[0]);

/* close our connection */
mysql_free_result(res);
mysql_close(conn);
}

MySQL comes with a script called mysql_config. It provides useful information for compiling your MySQL client and connecting it to a MySQL database server. You need to use following two options.

Pass the libs option i.e. ‘Libraries’ to show required Libraries to link with the MySQL client library.

1
$ mysql_config --libs

Output:

1
-L/usr/local/Cellar/mysql/8.0.13/lib -lmysqlclient -lssl -lcrypto

Pass cflags option ‘Compiler flags’ to find include files and critical compiler flags and defines used when compiling the libmysqlclient library.

1
$ mysql_config --cflags

Output:

1
-I/usr/local/Cellar/mysql/8.0.13/include/mysql

You need to pass above two options to your compiler. So to compile above program, enter:

1
$ gcc $(mysql_config --cflags) mysql.c $(mysql_config --libs)

Now execute program:

1
$ ./a.out

Output:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
MySQL Tables in mysql database:
columns_priv
component
db
default_roles
engine_cost
func
general_log
global_grants
gtid_executed
help_category
help_keyword
help_relation
help_topic
innodb_index_stats
innodb_table_stats
password_history
plugin
procs_priv
proxies_priv
role_edges
server_cost
servers
slave_master_info
slave_relay_log_info
slave_worker_info
slow_log
tables_priv
time_zone
time_zone_leap_second
time_zone_name
time_zone_transition
time_zone_transition_type
user

You have successfully connected to and retrieved information from your MySQL database from within a C environment.

Connecting and using the DS18B20 temperature sensor with a microcontroller

Introduction

The DS18B20 is a 1-Wire digital temperature sensor from Maxim IC. It reports the temperature in degrees Celsius with 9 to 12-bit precision, with a range from -55 to 125 (+/-0.5). Each temperature sensor has a unique 64-Bit serial number etched into the silicon which allows for a huge number of sensors to be used on one data bus with the probability of 9,223,372,036,854,775,807 to 1 that any two will clash!

The DS18B20 Temperature sensor

Features

  • Unique 1-Wire interface that requires only one port pin for communication.
  • Each device has a unique 64-bit serial code stored in an onboard ROM, as mentioned above.
  • Requires no external components.
  • Can be powered from it’s data line.
  • Power supply range is from 3.0V to 5.5V.
  • Measures temperatures from –55°C to +125°C (–67°F to +257°F) with ±0.5°C accuracy from –10°C to +85°C.
  • Thermometer resolution is user-selectable from 9 to 12 bits.
  • Converts temperature to 12-bit digital word in a maximum time of 750ms.
  • Alarm search command which allows it to identify and addresses devices whose temperature is outside of programmed limits (temperature alarm condition).
  • Applications include thermostatic controls, industrial systems, consumer products, thermometers, or any thermally sensitive system.

What you need to make a working thermometer

To construct an electronic thermometer you will need the following:

  • A microcontroller. (In this instance an Arduino or Atmega328p)
  • A DS18B20 sensor and a 4.7k resistor.
  • Breadboard.
  • Jumper leads.

Libraries

You will need to download and install 2 libraries for this exercise. If you are using the arduino then this should be fairly straight forward and can be acheived by following the menus within the IDE. The two libraries that you will need are:

  • 1-wire bus
  • Dallas Temperature

Build the simple circuit

The DS18B20 circuit diagram

To read the data from DS18B20 in the serial monitor of the Arduino IDE, build the circuit in the above schematic.

Connect the sensor pins to the Arduino in the following order: pin 1 to GND; pin 2 to any digital pin (pin 2 in this case); pin 3 to +5V or +3.3V. Connect the pull-up resistor between the Vcc supply and the data wire.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// First we include the libraries
#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into pin 2 on the Arduino
#define ONE_WIRE_BUS 2

// Setup a oneWire instance to communicate with any OneWire devices
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

void setup(void)
{
// start serial port
Serial.begin(9600);
Serial.println("Dallas Temperature IC Control Library Demo");

// Start up the library
sensors.begin();
}

void loop(void)
{
// call sensors.requestTemperatures() to issue a global temperature
// request to all devices on the bus
Serial.print(" Requesting temperatures...");
sensors.requestTemperatures(); // Send the command to get temperature readings
Serial.println("DONE");
Serial.print("Temperature is: ");
Serial.print(sensors.getTempCByIndex(0)); // Why "byIndex"?
// You can have more than one DS18B20 on the same bus.
// 0 refers to the first IC on the wire
delay(1000);
}

Place the above code into the IDE and upload via the arduino uploader. If everything is okay you should see the temperature being measured and showed in the serial monitor of the IDE.

The difference between TCP and UDP

What is the difference between TCP and UDP?

Both TCP and UDP are protocols used for sending bits of data — known as packets — over the Internet. They both build on top of the Internet protocol. In other words, whether you are sending a packet via TCP or UDP, that packet is sent to an IP address. These packets are treated similarly, as they are forwarded from your computer to intermediary routers and on to the destination.

TCP and UDP are not the only protocols that work on top of IP. However, they are the most widely used. The widely used term “TCP/IP” refers to TCP over IP. UDP over IP could just as well be referred to as “UDP/IP”, although this is not a common term.

TCP

TCP stands for Transmission Control Protocol. It is the most commonly used protocol on the Internet.

When you load a web page, your computer sends TCP packets to the web server’s address, asking it to send the web page to you. The web server responds by sending a stream of TCP packets, which your web browser stitches together to form the web page and display it to you. When you click a link, sign in, post a comment, or do anything else, your web browser sends TCP packets to the server and the server sends TCP packets back. TCP is not just one way communication — the remote system sends packets back to acknowledge it is received your packets.

TCP guarantees the recipient will receive the packets in order by numbering them. The recipient sends messages back to the sender saying it received the messages. If the sender does not get a correct response, it will resend the packets to ensure the recipient received them. Packets are also checked for errors. TCP is all about this reliability — packets sent with TCP are tracked so no data is lost or corrupted in transit. This is why file downloads do not become corrupted even if there are network hiccups. Of course, if the recipient is completely offline, your computer will give up and you will see an error message saying it can not communicate with the remote host.

UDP

UDP stands for User Datagram Protocol — a datagram is the same thing as a packet of information. The UDP protocol works similarly to TCP, but it throws all the error-checking stuff out. All the back-and-forth communication and deliverability guarantees slow things down.

When using UDP, packets are just sent to the recipient. The sender will not wait to make sure the recipient received the packet — it will just continue sending the next packets. If you are the recipient and you miss some UDP packets, too bad — you can not ask for those packets again. There is no guarantee you are getting all the packets and there is no way to ask for a packet again if you miss it, but losing all this overhead means the computers can communicate more quickly.

UDP is used when speed is desirable and error correction is not necessary. For example, UDP is frequently used for live broadcasts and online games.

avrdude

Avrdude is a library that allows you to perform functions and upload files to the AVR series of microcontrollers. It is open source software and is freely available to download. With an interface it makes it easy to upload files and interrogate microcontrollers from the command line. It is the software that the Arduino IDE uses in the background.

Example of erasing a chip completely: (Warning this will erase the bootloader too!)

avrdude -p m328p - c usbtiny -e

Will result in output similar to the below, confirming that your chip indeed has been erased.

1
2
3
4
5
6
7
8
9
10
avrdude: AVR device initialized and ready to accept instructions

Reading | ################################################## | 100% 0.01s

avrdude: Device signature = 0x1e950f (probably m328p)
avrdude: erasing chip

avrdude: safemode: Fuses OK (E:FD, H:DE, L:FF)

avrdude done. Thank you.

Programming fuses with avrdude and USBTiny

Fuse programming on the ATMega328 is very straightforward with the USBTiny. Connect the USBTiny to the AVR with the ICSP (In Circuit Serial Programming) connections. You need to ensure that you have avrdude installed on your computer. Once connected the following commands apply.

avrdude -c usbtiny -p ATmega328p

the above line reads the fuse settings on an ATmega328p

avrdude -p m328p -c usbtiny -U efuse:w:0xff:m -U hfuse:w:0xd9:m -U lfuse:w:0xe2:m

the above line writes the fuse bits on an ATmega328p

The fuse settings for standard 16MHz ext clock are E:FD H:DE L:FF

The fuse settings for standard 8MHz int clock are E:FF H:D9 L:E2

The fuse settings for standard 1MHz int clock are E:FF H:D9 L:62

^