Stephen Smith's Blog

Musings on Machine Learning…

Posts Tagged ‘gpio

Flashing LEDs in Assembler

leave a comment »

Introduction

Previously I wrote an article on an introduction to Assembler programming on the Raspberry Pi. This was quite a long article without much of a coding example, so I wanted to produce an Assembler  language version of the little program I did in Python, Scratch, Fortran and C to flash three LEDs attached to the Raspberry Pi’s GPIO port on a breadboard. So in this article I’ll introduce that program.

This program is fairly minimal. It doesn’t do any error checking, but it does work. I don’t use any external libraries, and only make calls to Linux (Raspbian) via software interrupts (SVC 0). I implemented a minimal GPIO library using Assembler Macros along with the necessary file I/O and sleep Linux system calls. There probably aren’t enough comments in the code, but at this point it is fairly small and the macros help to modularize and explain things.

Main Program

Here is the main program, that probably doesn’t look structurally that different than the C code, since the macro names roughly match up to those in the GPIO library the C function called. The main bit of Assembler code here is to do the loop through flashing the lights 10 times. This is pretty straight forward, just load 10 into register r6 and then decrement it until it hits zero.

 

@
@ Assembler program to flash three LEDs connected to the
@ Raspberry Pi GPIO port.
@
@ r6 - loop variable to flash lights 10 times
@

.include "gpiomacros.s"

.global _start             @ Provide program starting address to linker

_start: GPIOExport  pin17
        GPIOExport  pin27
        GPIOExport  pin22

        nanoSleep

        GPIODirectionOut pin17
        GPIODirectionOut pin27
        GPIODirectionOut pin22

        @ setup a loop counter for 10 iterations
        mov         r6, #10

loop:   GPIOWrite   pin17, high
        nanoSleep
        GPIOWrite   pin17, low
        GPIOWrite   pin27, high
        nanoSleep
        GPIOWrite   pin27, low
        GPIOWrite   pin22, high
        nanoSleep
        GPIOWrite   pin22, low

        @decrement loop counter and see if we loop
        subs    r6, #1      @ Subtract 1 from loop register setting status register
        bne     loop        @ If we haven't counted down to 0 then loop

_end:   mov     R0, #0      @ Use 0 return code
        lsl     R0, #2      @ Shift R0 left by 2 bits (ie multiply by 4)
        mov     R7, #1      @ Service command code 1 terminates this program
        svc     0           @ Linus command to terminate program

pin17:      .asciz  "17"
pin27:      .asciz  "27"
pin22:      .asciz  "22"
low:        .asciz  "0"
high:       .asciz  "1"

 

GPIO and Linux Macros

Now the real guts of the program are in the Assembler macros. Again it isn’t too bad. We use the Linux service calls to open, write, flush and close the GPIO device files in /sys/class/gpio. Similarly nanosleep is also a Linux service call for a high resolution timer. Note that ARM doesn’t have memory to memory or operations on memory type instructions, so to do anything we need to load it into a register, process it and write it back out. Hence to copy the pin number to the file name we load the two pin characters and store them to the file name memory area. Hard coding the offset for this as 20 isn’t great, we could have used a .equ directive, or better yet implemented a string scan, but for quick and dirty this is fine. Similarly we only implemented the parameters we really needed and ignored anything else. We’ll leave it as an exercise to the reader to flush these out more. Note that when we copy the first byte of the pin number, we include a #1 on the end of the ldrb and strb instructions, this will do a post increment by one on the index register that holds the memory location. This means the ARM is really very efficient in accessing arrays (even without using Neon) we combine the array read/write with the index increment all in one instruction.

If you are wondering how you find the Linux service calls, you look in /usr/include/arm-linux-gnueabihf/asm/unistd.h. This C include file has all the function numbers for the Linux system calls. Then you Google the call for its parameters and they go in order in registers r0, r1, …, r6, with the return code coming back in r0.

 

@ Various macros to access the GPIO pins
@ on the Raspberry Pi.

@ R5 is used for the file descriptor

.macro  openFile    fileName
        ldr         r0, =\fileName
        mov         r1, #01     @ O_WRONLY
        mov r7,     #5          @ 5 is system call number for open
        svc         0
.endm

.macro  writeFile   buffer, length
        mov         r0, r5      @ file descriptor
        ldr         r1, =\buffer
        mov         r2, #\length
        mov         r7, #4 @ 4 is write
        svc         0
.endm

.macro  flushClose
@fsync syscall
        mov         r0, r5
        mov         r7, #118    @ 118 is flush
        svc         0

@close syscall
        mov         r0, r5
        mov         r7, #6      @ 6 is close
        svc         0
.endm

@ Macro nanoSleep to sleep .1 second
@ Calls Linux nanosleep entry point which is function 162.
@ Pass a reference to a timespec in both r0 and r1
@ First is input time to sleep in seconds and nanoseconds.
@ Second is time left to sleep if interrupted (which we ignore)

.macro  nanoSleep
        ldr         r0, =timespecsec
        ldr         r1, =timespecsec
        mov         r7, #162    @ 162 is nanosleep
        svc         0
.endm

.macro  GPIOExport  pin
        openFile    gpioexp
        mov         r5, r0      @ save the file descriptor
        writeFile   \pin, 2
        flushClose
.endm

.macro  GPIODirectionOut   pin
        @ copy pin into filename pattern
        ldr         r1, =\pin
        ldr         r2, =gpiopinfile
        add         r2, #20
        ldrb        r3, [r1], #1 @ load pin and post increment
        strb        r3, [r2], #1 @ store to filename and post increment
        ldrb        r3, [r1]
        strb        r3, [r2]
        openFile    gpiopinfile
        writeFile   outstr, 3
        flushClose
.endm

.macro  GPIOWrite   pin, value
        @ copy pin into filename pattern
        ldr         r1, =\pin
        ldr         r2, =gpiovaluefile
        add         r2, #20
        ldrb        r3, [r1], #1    @ load pin and post increment
        strb        r3, [r2], #1    @ store to filename and post increment
        ldrb        r3, [r1]
        strb        r3, [r2]
        openFile    gpiovaluefile
        writeFile   \value, 1
        flushClose
.endm

.data
timespecsec:   .word   0
timespecnano:  .word   100000000
gpioexp:    .asciz  "/sys/class/gpio/export"
gpiopinfile: .asciz "/sys/class/gpio/gpioxx/direction"
gpiovaluefile: .asciz "/sys/class/gpio/gpioxx/value"
outstr:     .asciz  "out"
            .align  2          @ save users of this file having to do this.
.text

Makefile

Here is a simple makefile for the project if you name the files as indicated. Again note that WordPress and Google Docs may mess up white space and quote characters so these might need to be fixed if you copy/paste.

model: model.o
    ld -o model model.o

model.o: model.s gpiomacros.s
    as -ggdb3 -o model.o model.s

clean:
    rm model model.o

 

IDE or Not to IDE

People often do Assembler language development in an IDE like Code::Blocks. Code::Blocks doesn’t support Assembler language projects, but you can add Assembler language files to C projects. This is a pretty common way to do development since you want to do more programming in a higher level language like C. This way you also get full use of the C runtime. I didn’t do this, I just used a text editor, make and gdb (command line). This way the above program has no extra overhead the executable is quite small since there is no C runtime or any other library linked to it. The debug version of the executable is only 2904 bytes long and non debug is 2376 bytes. Of course if I really wanted to reduce executable size, I could have used function calls rather than Assembler macros as the macros duplicate the code everywhere they are used.

Summary

Assembler language programming is kind of fun. But I don’t think I would want to do too large a project this way. Hats off to the early personal computer programmers who wrote spreadsheet programs, word processors and games entirely in Assembler. Certainly writing a few Assembler programs gives you a really good understanding of how the underlying computer hardware works and what sort of things your computer can do really efficiently. You could even consider adding compiler optimizations for your processor to GCC, after all compiler code generation has a huge effect on your computer’s performance.

Advertisements

Written by smist08

January 7, 2018 at 7:08 pm

Fortran Lives

with 3 comments

Introduction

I was looking at a programming IDE called Code::Blocks that seems popular on the Raspberry Pi. Much lighter weight than Eclipse or Visual Studio, but it has a great deal of the same functionality including debugging, project templates, code highlighting and auto-complete. One thing that caught my interest was that Code::Blocks has direct support for Fortran programming. Back when I took first year Computer Science at UVic, all the programming labs were done in WATFIV (Waterloo Fortran IV) and then one of my Co-op work terms was at the the Institute of Ocean Sciences analysing experimental data from the Arctic, writing in Fortran using the extensive Fortran scientific and visualization libraries that were state of the art for the time (on a Univac mainframe).

One thing I noticed when playing with Machine Learning and Python programming was that if I installed something that didn’t have a binary for the particular flavour of Linux I was using then it would download the source code and compile that. What surprised me was the number of Fortran source files it would compile. Part of the reason for this is the giant library of efficient and well tested numerical libraries written in Fortran that have either been donated to the public domain or originated that way from various University research projects. It turns out that many of the popular array, numerical and algorithm libraries for Python are all written in Fortran and a large part of the popularity of Python is the easy access to all these libraries (like LAPACK).

GCC

Many people think of GCC just as the Gnu C compiler for Linux. However officially GCC stands for the Gnu Compiler Collection and supports C, C++, Objective-C, Objective-C++, Fortran, Java, Ada, Go and OpenMP. This then provides a great free cross platform compiler for Fortran that supports most of the things in the latest standard. As a result you can do Fortran programming easily anywhere including the Raspberry Pi. GCC is the compiler that the Code::Blocks IDE runs to compile your Fortran programs.

Fortran isn’t pre-installed on the Raspberry Pi, so to compile a Fortran program you need to add Fortran support to GCC which you do from a terminal window by:

sudo apt-get install gfortran

GPIO

I thought as an experiment I would port my simple flashing light program that I showed in Python and Scratch in my previous blog posting on breadboarding over to Fortran. So Python and Scratch come with GPIO libraries pre-installed and was really easy. For Fortran I didn’t see any such library, but fortunately for Unix/Linux you can usually access any hardware devices via the file metaphor. Basically you control the hardware by opening a file (usually in /dev) and then cause things to happen by writing various things to these special files. Similarly you read these files to get input or status. A good description of how to control the GPIO lines via files is given here. For instance if we want to turn on our LED we wired to pin 17, we would send 17 to the file /sys/class/gpio/export. We can do this from a terminal command line via:

echo 17 > /sys/class/gpio/export

This causes a number of files under /sys/class/gpio/glio17 to be created that we can now access. First we setup pin 17 for output via:

echo out > /sys/class/gpio/gpio17/direction

Then we turn pin 17 on via

echo 1 > /sys/class/gpio/gpio17/value

And turn it off via:

echo 0 > /sys/class/gpio/gpio17/value

Since most programming languages have file I/O libraries, under Linux this then makes most devices accessible.

Fortran Code

Creating the program was quite easy. I found a library on the Web that provides the GPIO access via the files which I’ll list later. The only problem was that the Fortran sleep function takes its parameters only in seconds so you can’t do a sub-second sleep which means the LEDs flash very slowly. Fortunately it turns out that you can call C runtime routines from Fortran fairly easily, so I include the interface to the C usleep (sleep in microseconds) function so we can use the same 0.2 second time between flashes that we used before. Below is the Fortran source code:

 

! Flash the GPIO lights
program main
  use gpio
  implicit none
  interface
     subroutine usleep(useconds) bind(C)
      use iso_c_binding
      implicit none
      integer(c_int32_t), value :: useconds
     end subroutine
  end interface
  integer i, sleepTime

  call gpioSetOut(17)
  call gpioSetOut(27)
  call gpioSetOut(22)

  sleepTime = 200000

  do i = 1, 10
    call gpioOutput(17, 1)
    call usleep(sleepTime)
    call gpioOutput(17, 0)
    call gpioOutput(27, 1)
    call usleep(sleepTime)
    call gpioOutput(27, 0)
    call gpioOutput(22, 1)
    call usleep(sleepTime)
    call gpioOutput(22, 0)
  end do
end


Fortran has evolved a bit since my University days. There are full structured programming constructs, so you don’t need to use labels. Notice the DO loop has a DO END rather than specifying a label on a CONTINUE statement as we used to do. Fortran has added good support for modules and even object oriented programming while maintaining compatibility for all those scientific libraries everyone loves so much.

Now the GPIO module which I found here. This shows how to create a nice Fortran module. It also shows some Fortran string processing. The module didn’t work for me directly, I had to add a sleep statement after allocating the GPIO pin to allow time for the files to be created or I got file access errors. Here is the code:

 

module gpio
    implicit none
    contains
    subroutine gpioSetOut(pin)
        integer, intent(in) :: pin
        character (len=35) :: unexportChar
        character (len=33) :: exportChar
        character (len=45) :: directionChar
        write (unexportChar, '("echo ", I0, " > /sys/class/gpio/unexport")') pin
        write (exportChar, '("echo ", I0, " > /sys/class/gpio/export")') pin
        call execute_command_line(unexportChar)
        call execute_command_line(exportChar)
        call sleep(1)

        write (directionChar, '("echo out > /sys/class/gpio/gpio", I0, "/direction")') pin
        call execute_command_line(directionChar)
    end subroutine gpioSetOut

    subroutine gpioSetIn(pin)
        integer, intent(in) :: pin
        character (len=35) :: unexportChar
        character (len=33) :: exportChar
        character (len=45) :: directionChar
        write (unexportChar, '("echo ", I0, " > /sys/class/gpio/unexport")') pin
        write (exportChar, '("echo ", I0, " > /sys/class/gpio/export")') pin
        call execute_command_line(unexportChar)
        call execute_command_line(exportChar)
        call sleep(1)

        write (directionChar, '("echo in > /sys/class/gpio/gpio", I0, "/direction")') pin
        call execute_command_line(directionChar)
    end subroutine gpioSetIn

    subroutine gpioOutput(pin, value)
        integer, intent(in) :: pin, value
        character (len=45) :: valueChar

        write (valueChar, '("echo ", I1, " > /sys/class/gpio/gpio", I0, "/value")') value, pin
        call execute_command_line(valueChar)
    end subroutine gpioOutput

    subroutine gpioRead(pin, value)
        integer, intent(in) :: pin
        integer, intent(out) :: value
        character (len=28) :: valueChar

        write (valueChar, '("/sys/class/gpio/gpio", I0, "/value")') pin

        open (unit=1, file=valueChar)
        read (1,*) value
        close (1)
    end subroutine gpioRead

end module gpio


One other thing, I needed to add -lgfortran as a linker option in Code::Blocks, since for some reason a freshly created Fortran application project didn’t include the link for the Fortran runtime.

Fortran Evolution

The latest standard for Fortran came was Fortran 2008 which came out in 2010. The next version will be Fortran 2018 and we’ll see if it shows up next year. GCC supports most things in Fortran 08 plus a few other enhancements. The next 2018 release is includes quite a few things including more advanced parallel processing capabilities and easier interoperability with C. Certainly Fortran has made great strides since my University days with structured, modular and object oriented programming support along with variable length string processing. Fortran really excels at parallel processing support since it is still the goto language on most supercomputers and used for all those advanced climate, astronomical and other scientific models.

Summary

I think I’ll stick to Python as my current goto language. But playing with Fortran was fun and it’s amazing to see how much usage it still gets. If you are doing serious high performance numerical processing then you are probably going to have to get your hands dirty with Fortran. Certainly the Raspberry Pi is a good place to learn Fortran with high quality free tools like Code::Blocks and GCC Fortran.

 

Written by smist08

December 2, 2017 at 4:39 pm

Breadboarding with my Raspberry Pi

with 4 comments

Introduction

One of the cool things about the Raspberry Pi is that it has a set of general purpose input/output (GPIO) pins. Many Raspberry Pi starter kits (including my Canakit) come with a breadboard and few simple electronic components you can play with. In this article I’ll talk about connecting up some LED lights and controlling them from both Python and Scratch. Below is a bit of a hazy picture of my Raspberry Pi hooked up to the breadboard and a Scratch program running.

Here is a closer look at the breadboard with a few LEDs and resistors connected.

You don’t need to do this for many standard tasks, after all the Pi has four USB ports, Wifi, Bluetooth, HDMI, sound/composite video and ethernet ports. But the GPIO port is great for electronic enthusiasts, hobbyists and educators to get their hands dirty playing with electronic components.

Hooking up an LED

Each GPIO pin can be individually controlled and will provide 3.3V when activated. It is then specified to keep the current under 16mA or you can damage the circuits. My kit came with a number of 220 Ohm resistors and by Ohm’s law these would case the current to be 3.3V/220Ω = 15mA, so just right. You need to have a resistor in series with the LED since the LED’s resistance is quite low (typically around 13 Ohms and variable). I connected 3 LEDs and for each LED you connect a wire from a GPIO pin (in this case I used 17, 27 and 22) to the positive lead of the LED then you connect the negative side to a resistor and the other side of the resistor to the -3.3V line on the breadboard. Really quite simple.

Python

It’s quite simple to control the GPIO pins via a Python package. You just need to import RPi.GPIO and you can get going. This package came pre-installed so all I had to do was write some lines of code and away it went. Basically I just need to set the mode for since the package supports a few different boards and chipsets, then configure the pins I’m using for output. Then I just need to turn the LEDs on and off. You need to add some sleep statements or the whole thing executes faster than you can see.

Scratch

Scratch is a very simple and visual programming language/environment developed by the MIT Education Department. It is used to teach programming to students as young as in kindergarten. It is really amazing the animations and games that kids can produce with this system. It comes pre-installed on the Raspberry Pi and you can also control the GPIO pins with it, just like you can in Python. You have to run the GPIO server from the edit menu and then you use the broadcast statement to control the GPIO functions. Here is the Scratch version of the simple Python program displayed above.

More on the GPIO

The GPIO has 26 pins, two are +3.3V, two are +5V, 5 are ground and then that leaves 17 as general GPIO pins.

In the same way we configured the pins for output to control LEDs you can configure them for input and then for instance read the setting of a switch.

However this isn’t all there is to GPIO, besides the functions we’ve talked about so far, which are rather limited, a number of the pins have “alternate” functions that you can select programatically. For instance pins 3 and 5 can support the I2C standard that allows two microchips to talk to eachother. There are pins that can support two serial ports which are handy for connecting to radios or printers. There are pins that can support PWM and PPM which are handy for controlling electical motors.

Summary

The Raspberry Pi 3 is a very versatile device. It runs a most Linux software and has a very flexible architecture allowing it to interface to a great many devices. It has four USB ports, Wifi, Internet and Bluetooth. Plus there is the general purpose GPIO bus that allows a great deal of flexibility to interface the Pi to almost anything. That is why you see Raspberry Pi’s built as the brains of drones, robots, home security systems, information kiosks and so much more.

 

Written by smist08

November 15, 2017 at 9:14 pm

Posted in raspberry pi

Tagged with , ,