0% found this document useful (0 votes)
55 views

Embedded Linux - Lab Exercise 2: Revision History Rev Date Author Notes

This document provides instructions for a lab exercise involving creating a C program for the Raspberry Pi that uses POSIX timers, basic I/O through the wiringPi library, and handles external interrupts. The summary creates files for the main function, I/O configuration, and timer initialization. It compiles and debugs the program, adding a real-time library and disabling a debug signal. Finally, it sets up an external interrupt pin and tests the interrupt handler.

Uploaded by

skypededa33
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
55 views

Embedded Linux - Lab Exercise 2: Revision History Rev Date Author Notes

This document provides instructions for a lab exercise involving creating a C program for the Raspberry Pi that uses POSIX timers, basic I/O through the wiringPi library, and handles external interrupts. The summary creates files for the main function, I/O configuration, and timer initialization. It compiles and debugs the program, adding a real-time library and disabling a debug signal. Finally, it sets up an external interrupt pin and tests the interrupt handler.

Uploaded by

skypededa33
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 11

Embedded Linux - Lab exercise 2

Revision history
Rev Date Author Notes
0.1 17.9.2019 Jarno Tuominen Initial revision

0.2 20.9.2019 Jarno Tuominen Added 2nd part (ext int)

1
1 Introduction
In this exercise we will create a simple C-program for RasPi, which
- uses POSIX timers / interrupts
- utilizes basic I/O-access through wiringPi-library
- has a handler for external interrupts

2
2 Creating some new files and playing with timers
Right click the “src”-directory in the project navigator, and create a new source file. Name it main.c.

Every C-program must have one – and only one - main()-function. That is an built-in entry point to
your application. So, now we have one (it came with a template).
At this point, your main function does not need to take any arguments and it will return int. (0
indicates success.)
Include errno.h – this is part of C standard library
(https://en.wikipedia.org/wiki/C_standard_library), which contains error codes used by library
functions. They will be used later on.
Create another source file, “ioconfig.c”
- This will contain your I/O-initialization routines
Create a header file for ioconfig.c: ioconfig.h
- Like creating a .c-file, but use “New Header File” instead
- This will include the function prototypes of functions defined in ioconfig.c
Observe how the template contains lines:
#ifndef IOCONFIG_H_
#define IOCONFIG_H_

#endif /* IOCONFIG_H_ */

This is called an “include guard”. As the number of files in project increase, it is possible that C
preprocessor will “see” same header-file multiple times, leading to errors (redefinition of variables
etc). The include guard makes sure that the contents of the whole file is included only once, on the
first entry to that particular .h-file.
Create another source file, “timers_init.c”
- This will contain your timer routines
Create a header file for timers_init.c: timers_init.h

3
- Header files typically contain macros, possibly some global variables and the function
prototypes of functions defined in corresponding .c-file, in this case in timers_init.c
- The prototypes (function declarations) are required only for those functions, which are goint
to called from other files (=modules, for example from main.c).
- So, add the following line to timers_init.h (inside the include guard)
int timers_init(void);

This is a prototype of the timers_init-function, which, like said, needs to be visible to anyone using it.
In this case main() will call this function and the compiler needs to know the arguments and return
type of the function when main.c is being compiled.
Include both newly created .h-files in main. As these headers do not come from default include-file
search path, use “filename” instead of <filename>
We leave ioconfig.h empty for now.
In your main-function, add a call to timers_init(), followed by an endless loop ( while(1) { } )
Get the contents of the timer_init.c and ioconfig.c from Redmine. (Yes, you could have downloaded
the files directly from Redmine in the first place- but now you know how to create new files from
Eclipse UI so that they are in the project, in correct place)

4
3 Compiling and debugging
Try to compile – you should get an error at linking phase:
'Building target: test1'
'Invoking: Cross GCC Linker'
arm-linux-gnueabihf-gcc -o "test1" ./src/ioconfig.o ./src/main.o ./src/test1.o
./src/timers_init.o
c:/dev_tools/sysgcc/raspberry/bin/../lib/gcc/arm-linux-
gnueabihf/8/../../../../arm-linux-gnueabihf/bin/ld.exe: ./src/timers_init.o: in
function `makeTimer':
E:\Eclipse_WS\test1\Debug/../src/timers_init.c:69: undefined reference to
`timer_create'
c:/dev_tools/sysgcc/raspberry/bin/../lib/gcc/arm-linux-
gnueabihf/8/../../../../arm-linux-gnueabihf/bin/ld.exe:
E:\Eclipse_WS\test1\Debug/../src/timers_init.c:76: undefined reference to
`timer_settime'
collect2.exe: error: ld returned 1 exit status
make: *** [test1] Error 1
"make all" terminated with exit code 2. Build might be incomplete.

The reason is: You are missing the real-time (rt) library. That can be included by providing linker
additional instruction to include it: “-lrt”, where “-l” is prefix for “library”, and “rt” is name of the
required library.
In Eclipse: File -> Properties -> C/C++-build -> Settings -> Cross GCC Linker -> Libraries

Now the build should be succesful (assuming you don’t have other errors in your source code)
Start debugging it. Observe the output on the screen, the timer “hellos” should be visible.
Observe how the program stops in the main loop – even if there is no breakpoint. This is a bit
annoying. Open debugger console in Eclipse and see the reason:

5
Program received signal SIG34, Real-time event 34.
main () at ../src/main.c:21
21 while(1) {

We need to disable this.


Edit .gdbinit (should be in your project root), add the following line:
handle SIG34 nostop noprint pass

Terminate the debug session and start it again. In debug view (debug tab): Terminate and relaunch.

Now your application is running smoothly and the timers are talking to you.

6
Open timers_init.c, look at function: timerHandler. Set breakpoint on the line, where timer3 in
handled, by double-clicking the line right left to line numbers. As timer3 is pretty slow, it may take a
while, but evidently your program execution stops when timer 3 fires. You can remove the
breakpoint by double-clicking it again.
Open terminal to rasPi (local or over SSH) and type “top”. This will show you the CPU utilization. How
many % of CPU resources does your application use?
Insert a call to sleep-function in the infinite while-loop.
while(1) {
sleep(1);
}

Recompile, restart and observer the CPU utilization now.


Can you still see it with top?
Type: ps-aux |grep <your_app_name> to see that it’s still there, up and running

The memory and CPU usage is now 0%. (Well, not quite but close to zero)

7
4 Handling external interrupts
Warning: Before connecting any wires to RasPi, read the warnings below (in red)
WiringPi-library provides functions to read and write GPIOs, including setting up the external
interrupts. Our target is to:
- set up one pin as an output (will be used later on)
- set up one pin as an edge-sensitive interrupt input and associate it with the interrupt service
routine (ISR)
Tip: focus on word “library” - you need to do the same trick for WiringPi-library as you did for rt-
library earlier.
Tip: WiringPi needs to be set-up before using any of it’s function. Look at ioconfig.c – call
appropriate function from the main() –function. Once WiringPi is set up, you can call the routine
which initializes the I/O-interrupt.
Tip: the I/O and interrupt set-up routines use macros as pin names (EXT_INT_PIN_1, DEBUG_PIN_1)
– which are not defined. Define them in ioconfig.h. Also add the function prototypes.
In order to test the functionality of your interrupt handler, you need to cause a rising edge on the
respective I/O-pin. Note that RasPi I/Os, when configured as interrupts, have an internal pull-up
resistor by default – this means that when the pin is floating (not connected to anything), it’s logic
level is high. In order to create a rising edge, you need to pull the pin down (to ground) and then
release it. This can be done simply with a wire connected to a pin header. To avoid accidental short-
circuit, get 2 female-male-wires – connect the other one to the ground pin, and the other one to
your external interrupt input. Generate the pulse by touching the open (male) ends of the wire
together.
How to select the correct input pin?
The RasPi expansion connector is shown in the figure below:

8
IMPORTANT:
The physical pins of the connector (1 to 40) do NOT match directly with GPIO-pins seen by WiringPi.
Take for example physical pin 3:
It’s alternate function is I2C data line – this is just an “agreement” that physical pin numbers 3 and 5
are “typically” used as an I2C-bus. This enables 3rd party manufacturers to build expansion boards
(like piFace digital board), which have I2C routed to those pins, enabling possibility to stack multiple
of them. In case each manufacturer would pick the pins freely, there would be compatibility issues.
The physical connector pin 3 is routed GPIO pin 2 of Broadcom’s processor (BCM numbering).
However, wiringPi has yet another numbering convention: it’s pin number 8. These are the numbers
we need to use, as we are using WiringPi library.

Pick 2 pins freely from the ones which have “WiringPI-number”.


Warning: never connect power pins (3.3V, 5V) to ground (0V) – or 3.3V to 5V – you will kill the RasPi
with 100% certainty. Permanently.

9
Warning: Never connect 5V pin to any of the I/O-pins – they are only 3.3V tolerant, meaning that
connecting 5V to any I/O will burn your RasPi.

Once you have connected the wires (and checked it at least 3 times), run the program and connect
the wires together and release them.
What are your observations?
Can you find and explanation to this behaviour?
How would you correct this?

10
5 Eclipse tips
To perform string search on all files of the project: ctrl-H

11

You might also like