Difference between revisions of "Documents/LED Blink"

From Nutwiki
Jump to: navigation, search
(Building the Application Code)
Line 181: Line 181:
If everything worked well, your LED should start blinking.
If everything worked well, your LED should start blinking.
[[led-hardware.html|Previous]] [[led.html|Contents]] 
[[Documents/LED Hardware|Previous]] [[Documents/LED Tutorial|Contents]] 

Revision as of 18:55, 13 July 2017

Nut/OS LED Tutorial

We will now start with our first application. It will initialize the port bit and then switch on and off the LED in an endless loop.

ATmega Ports

Almost all digital ports of the ATmega128 can be individually configured for input or output. Three registers are used to control or monitor each port.

  • Port register

When the port is configured for output, we can clear each bit to drive the corresponding output low or set the bit to drive it high.

  • Pin register

When the port is configured for input, then each bit reflects the status at the corresponding input pin. The bit is zero, when the input is low or set if the input is driven high.

  • Data direction register

This register is used to configure the mode of each port pin. When the bit is set, then the port pin works in output mode.

All registers are 8 bits wide and three of them are available at the [[../hardware/expansion.html|Ethernut expansion port]] , named B, D and E.


Standard C does not provide functions to access port registers. But the AVR library, that comes with your compiler, offers such capabilities. Almost all AVR compilers allow to handle ports like predefined variables. To set bit 2 of data direction register of Port E, we can write

DDRE |= 0x04;

In addition a bit value macro is supported as well, which often makes the code easier to read.

DDRE |= _BV(2);

However, using predefined variables to access port registers makes the code less portable. With Nut/OS we prefer to use macros instead. To set bit 2 of the data direction register, we use

sbi(DDRE, 2);


cbi(DDRE, 2);

could be used to clear it again.

Blinking LED

Setting and clearing the output pin can be done in a similar way:

for {
    cbi(PORTE, 2);
    sbi(PORTE, 2);

This loop will rapidly drive the output pin 41 of the expansion port to low and back to high. Driving the output low will lit the LED, driving it high will switch the LED off. However, the switching occurs so fast, that we would not be able to notice anything but a glowing LED. At this point Nut/OS jumps in. It offers a function named NutSleep(), which suspends the current thread for a specified number of milliseconds. You may now ask yourself: "What thread?". Take it easy, we will explain this in detail later. Until then it is sufficient to understand, that our application will stop running for a given amount of time.

Building the Application Code

You should have created a sample application directory by following the Ethernut Software Manual. Within this directory create a new subdirectory named led01. Within this directory create a new C source file name led01.c and put in the following contents.

 * This header contains the Nut/OS timer function
 * prototypes. We need it for calling NutSleep.
#include <sys/timer.h>

 * Ethernut LED example #1.
int main(void)
     * Configure port E bit 2 as an output.
    sbi(DDRE, 2);

     * An endless loop.
    for (;;) {
         * Set port E bit 2 to low. This will lit the LED.
        cbi(PORTE, 2);

         * Sleep 1000 milliseconds.

         * Setting port E bit 2 to high switches off the LED.
        sbi(PORTE, 2);

         * Sleep for another 1000 milliseconds.

If you're using the ImageCraft IDE, then you will probably create a project. Again, check the Ethernut Software Manual for specific project settings.

For the GCC compiler we need to create a file name Makefile in the same directory, which contains:

PROJ = led01

include ../Makedefs

SRCS =  $(PROJ).c
OBJS =  $(SRCS:.c=.o)
LIBS =  $(LIBDIR)/nutinit.o -lnutos -lnutdev $(ADDLIBS)
TARG =  $(PROJ).hex

all: $(OBJS) $(TARG)

include ../Makerules

Next open a command line shell (DOS box), change to our new directory. On Linux the PATH is usually correctly configured. On Windows you may have to execute

SET PATH=C:\ethernut\nut\tools\win32;C:\WinAVR\bin;C:\WinAVR\utils\bin;%PATH%

Replace the given directories with the paths used when you installed Nut/OS and WinAVR on your machine. Now simply enter


on the command line. The resulting output on your environment may vary, but in general should look like

avr-gcc -c -mmcu=atmega128 -Os -fno-delete-null-pointer-checks
        -Wall -Wstrict-prototypes -Wa,-ahlms=led01.lst -D__HARVARD_ARCH__
        -DETHERNUT2 -IC:/ethernut-3.9.8/nutbld-21b/include
        -IC:/ethernut-3.9.8/nut/include  led01.c -o led01.o
avr-gcc led01.o -mmcu=atmega128 -Wl,--defsym=main=0,-Map=led01.map,--cref
        C:/ethernut-3.9.8/nutbld-21b/lib/nutinit.o -lnutos -lnutdev
        -o led01.elf
avr-objcopy -R .eeprom -O ihex led01.elf led01.hex
rm led01.elf

Once again, the Ethernut Software Manual will be helpful with creating Nut/OS applications. As a result you'll find several new files in your application directory. The most important one is led01.hex, which contains the code to be transfered to the Ethernut Board in Intel Hex Format.

Running the Application Code

It's time to attach the programmer and power up your Ethernut.

The ImageCraft compiler offers an integrated programming tool. With GCC you can use

make burn

Your output may vary again, but should look similar to

uisp -dprog=stk500 -dserial=/dev/ttyS0 -dspeed=115200 -dpart=atmega128
     --erase --upload if=led01.hex
Firmware Version: 49.48
Atmel AVR ATmega128 is found.
Uploading: flash

If everything worked well, your LED should start blinking.

Previous Contents