Wednesday, November 17, 2010

Hello Word ( LED blinker ) on LPC1768 explained. GPIO tutorial

Traditionally, blinking an LED has been the first program written for almost any embedded system and LPC1768 is no exception. Here's a detailed description of all the software tools needed to get started. The LPC1768H schematic is available in the NGX website. The schematics show that TEST_LED is connected to P1.29. Now, for the register description, we'll need the LPC1768 manual.

For using any of the LPC1768 peripherals, the general steps to be followed are

1. Power Up the peripheral to be used.
2. Set the Clock Rate for the peripheral
3. Connect necessary pins using Pin Connect Block.
4. Initialize the registers of the peripheral.

Before proceeding, you'll need to know about bit manipulation in C. Here is a quick tutorial if you need it.

Now lets say "Hello World".

Open the LPC1768 manual, goto chapter 4: Clocking and Power Control, look for register Power Control for Peripherals register (PCONP) . Its in page 63. From the table, bit 15 is PGPIO. Setting the bit to 1 will power up the GPIO ports. Note that the default value is 1, which means GPIO is powered up by default on reset. But the start up code may have modified this and its best not to assume anything.So,

LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO

Now, to give the right clock to the peripheral. In the same chapter, look for Peripheral Clock Selection register ( PCLKSEL1 ). Its in page 57. Bits 3:2 set the clock divider for GPIO. Since we're not using interrupts, we wont change the default value. Even if it isn't default, it wont matter to our program. So we wont write to this register. But careful attention to these bits is needed for peripherals like timers and SSP.
Just in case someone is confused, PCLK refers to Peripheral Clock and CCLK refers to CPU Clock. PCLK is obtained by dividing CCLK by 1,2,4 etc. (For more details, look at table 42 in page 57).


By default, GPIO pins are connected to the external pins. So there is need to change settings in the pin connect block.

To initialize the port, goto chapter 9 GPIO (page 122). First, P1.29 has to be made an output pin

LPC_GPIO1->FIODIR |= 1 << 29; // puts P1.29 into output mode.

Caveat : Unlike the AVR pins which are in hi-Z after reset, LPC1768 pins are in internal pull-up mode after reset.

To turn ON the LED (assuming the other end is connected to GND via a resistor),

LPC_GPIO1->FIOPIN |= 1 << 29; // make P1.29 high

To turn it OFF

LPC_GPIO1->FIOPIN &= ~( 1 << 29 ); // make P1.29 low

This can more easily be accomplished using FIOSET and FIOCLR. Most of these registers are also byte addressable.

So, lets have the complete code

Assuming you have CodeSourcery g++ Lite, Eclipse installed, to create a project in Eclipse
1. Open Eclipse
2. File->New->C Project
3. In the project type pane, select Makefile Project -> Empty Project. Select Other ToolChain as the toochain. Give a project name, say "LEDBlinky". Click Finish
4. Get the Startup code and extract it somewhere.
5. In eclipse, in the project window, right click the newly created "LEDBlinky" project and import files.
6. Select File System in the Import window. Select the folder to which you extracted the startup code ("starter_code_21Oct2010"). Select all files for import. Click Finish.
7. Now open main.c

#include "LPC17xx.h"

volatile uint32_t temp;

void _delay(uint32_t del);

int main (void) 
{
    LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO
    LPC_GPIO1->FIODIR |= 1 << 29; // puts P1.29 into output mode.
    while(1)
    {
        LPC_GPIO1->FIOPIN |= 1 << 29; // make P1.29 high
        _delay( 1 << 24 );
        LPC_GPIO1->FIOPIN &= ~( 1 << 29 ); // make P1.29 low
        _delay( 1 << 24 );
    }
    return 0;
  
}
void _delay(uint32_t del)
{
    uint32_t i;
    for(i=0;i < del; i++)
        temp = i;
}

_delay() has been used as a crude software delay producing function. It should produce about a second or so of delay depending on CCLK.
A volatile variable 'temp' has been updated everytime in the loop so that the compiler will not optimize away the loop. Now hit Ctrl+B for build ( Project -> Build All ). You should see this in the console window

**** Build of configuration Default for project LEDBlinky ****

make all
arm-none-eabi-gcc -c -W -Wall -Os --std=gnu99 -fgnu89-inline -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections main.c -o main.o
arm-none-eabi-gcc -c -W -Wall -Os --std=gnu99 -fgnu89-inline -mcpu=cortex-m3 -mthumb -ffunction-sections -fdata-sections system_LPC17xx.c -o system_LPC17xx.o
arm-none-eabi-ld -Map main.map --gc-sections -T LPC17xx.ld startup_LPC17xx.o core_cm3.o main.o system_LPC17xx.o -o main.elf
arm-none-eabi-objdump -x --syms main.elf > main.dump
   text       data        bss        dec        hex    filename
    648          0       2056       2704        a90    main.elf
arm-none-eabi-objcopy  -O binary main.elf main.bin
arm-none-eabi-objcopy  -O ihex main.elf main.hex

Now you can burn the hex file using whatever method you prefer.

The Compiled Eclipse project is here. To download the hex code,use jtag or load serially using flash magic. The flash start has been put as 0x00000000 in the linker file.

If you are using NXP secondary bootloader, then the flash start will have to be changed to 0x00002000 in the linker file ( LPC17xx.ld ). Here is the compiled project with that change.

UPDATE: The latest code base is available here.

38 comments:

  1. Great! I hope this tutorial is not the end.

    ReplyDelete
  2. Glad you liked it. Many more to come.

    ReplyDelete
  3. Thank you very much. This example helped me a lot!!!

    ReplyDelete
  4. Helped me too, thank you!
    I'm looking forward to reading more of your tutorials!

    ReplyDelete
  5. Very useful for getting started! Is there something like a cheat sheet for which bit in which register to write to for different peripherals (e.g. LPC_GPIO1->FIODIR bit 29)?

    ReplyDelete
  6. Not sure I understand what you're looking for. Perhaps the register description in LPC17xx manual ?

    http://www.nxp.com/documents/user_manual/UM10360.pdf

    ReplyDelete
  7. For example, how do you know it's under LPC_GPIO1 and not LPC_GPIO0 or another struct? Thanks!

    ReplyDelete
  8. if its the NGX Blue Board you are talking about, then the schematic will give you that info.

    http://blueboard-lpc1768.googlecode.com/files/Blueboard_lpc1768_H_schematics.pdf

    The LED is connected to P1.29

    The manual however says FIO1PIN. If you want to know how i got that LPC_GPIO struct, then look at LPC17xx.h. This should be unnecessary since the names are quite intuitive. If you're using eclipse, then code complete will come in handy ( press CTRL + Space after typing the first few characters ).

    ReplyDelete
  9. Thanks! That's exactly what I was looking for. Never thought of looking at the schematics.

    ReplyDelete
  10. Hi! I set up the enviroment using yagarto, but when debugging with eclipse it almost set the breakpoint but says:

    target remote localhost:3333
    0xfff7ed7e in ?? ()

    and put a "unresolved breakpoint" warning.

    any idea? is it the same if i use the 0x00002000 or the 0x00000000 ld. Anyway, how to know which to use? I use a lpc1768 and openOCD.

    Thanks!

    ReplyDelete
  11. 0x00002000 is meant to be used with a bootloader ( USB ) and the bootloader occupies the flash from 0x0000 to 0x00001FFF and the application starts from 0x00002000. If you're using JTAG for debugging, you should use 0x00000000 as the start address.

    ReplyDelete
  12. I am making a project using LPC1768 and wanted your advice on few things. Can you give me your mail id ? My id is itsgaram@hotmail.com

    ReplyDelete
  13. It's great finding tutorial like this!
    I have a question if you fancy taking a look at it. Check out the line

    LPC_SC->PCLKSEL0 |= 1 << 3;
    // Clock for timer = CCLK/2

    Here is the page it comes from (likely also appears on LPC source code)
    http://msys-mv.blogspot.com/2010/11/configuring-and-playing-with-timer-of.html

    If the clock for timer0 is controlled by bits 3:2 in peripheral clock register, and we are putting a 1 in bit position 2 (1 shifted 3 places), it means we are setting bits 3:2 to 01 which, according to table 42 means clock for timer0 is now set at CCLK, right? I am wondering if I am reasoning properly because the explanation says the clock is now CCLK/2. What do you think?

    ReplyDelete
  14. Never mind the above comment, we are actually setting 3:2 to 10, which makes the explanation CCLK/2 correct.

    ReplyDelete
  15. I got confused a fair few times over the same issue !

    This was one of my attempts at programming LPC1768 and I've learnt that code, particularly code that assigns register values, is a LOT more readable if bits are assigned to groups rather than individually.

    For instance, like you said, assigning ( 0x2 << 2 ) leaves less room for confusion than ( 1 << 3 ).

    Thanks for pointing this out !

    ReplyDelete
  16. Thanks for the response! I agree with you.

    Another question? In the same page, what frequency does the LED end up blinking at if we assume CCLK = 100 MHz? I get ~47 Hz but want to check if I have erred somewhere.

    ReplyDelete
  17. With a software delay routine, its very hard to calculate. The delay will strongly depend on compiler version, optimization level etc. Maybe a rough estimate can be made if you assembly for cortex m3. But I dont.

    At 100Mhz, I had gotten about 2Hz. 47Hz seems very high. If you were looking at the LED, most certainly, you cant see it blinking. It'll just appear dull if its blinking at 47Hz.

    As you might have guessed, a timer will have to be used even if coarse control over timing is needed.

    ReplyDelete
  18. Okay thanks again for the answer. I certainly don't see any blinking. I'm trying to program it such that the flicker can be eliminated and I can have the display appear as if the digits are on simultaneously. Yes, the software delay is indeed significant and incalculable as I found out while debugging.

    ReplyDelete
  19. Hi,
    I tried the same code with BlueBaord Combo , but test LED on stamp module didn't blink, instead it was just in ON status.
    Please help me.

    ReplyDelete
  20. 1. Are you certain you got the code running ?

    2. Try modifying the code to keep the LED OFF at start and check out if the LED remains OFF

    3. Its possible that the CPU isnt running at the right frequency and the delay is too much ( maybe over a minute ) and so you're not seeing it blink. Try smaller delays / check the frequency. If I remember correctly, the code assumes you're running at 100MHz.

    ReplyDelete
  21. Hello Sagar,
    Now my code is running. Actually I did nothing ,just downloaded the previous code and I found it was working:).
    Anyways thanks for prompt reply.

    I am also staying in Mysore.
    Is it possible for share your contacts?:)

    ReplyDelete
  22. Hi Sagar,

    Thanks for this awesome page. I wouldnt have known how to deal with this stuff without.

    I however am having a problem with the environment. I downloaded eclips and code sourcery as instructed. I wrote the code as written above, but when it comes to building it, eclips says:

    **** Build of configuration Default for project LEDBlinky ****


    (Cannot run program "make": Launching failed)

    Did you ever come across something like this?

    Any help would be greatly appreciated.

    Thanks

    ReplyDelete
  23. 1. Your PATH enviroment variable doesnt point to make.
    2. There is something wrong with the g++ installation.

    Try going to the command line and see if you can run make from there.
    Try uninstalling and re-installing sourcery g++.

    ReplyDelete
  24. Wow Thanks for the prompt reply! :D

    Ok, So I uninstalled it, and reinstalled it with the destination directory C:\eclips.

    I figured, this is the most likely place eclips would want its stuff to be in.. and IT WORKED!!! =D

    Well I think.. Cuz, I kept getting errors on the delay function in your code. So, as a test, I commented out all the delay stuff. and just had it turn off the pin on Port1.29

    but when I test it, the pin is still high. :/

    Any clues to that?

    I'm using the bootloader method. and I also made sure that the start location is 0x00002000.

    Hope to hear soon

    ReplyDelete
  25. I just did the whole setup in programmers notepad. it works, as in compiles and everything.. But the same issue, after copying the bin file over, it doesnt run the code. No LED flashing or pin toggeling either...

    Also, it was the bin file or the hex file.. regardless, I copied both, for a test each time.. didnt work.. any hints?

    ReplyDelete
    Replies
    1. Sorry for this very late reply.

      Perhaps your bootloader is larger and the start point for the main application is different.

      Delete
  26. hello, thank you for a nice guide.
    But, I have a problem. I did all the mentioned steps and when it comes to build step I get this message:

    **** Build of configuration Default for project LEDBlinky ****
    (Cannot run program "make": Launching failed)

    I tried to reinstall codesourcery several times, and checked Path, everything is fine. please help me to figure out the problem!!

    ReplyDelete
  27. Try running make from the command line.

    ReplyDelete
  28. output that I get when I run in cmd:

    C:User\Khassan\make
    'make' is not recognized as internal or external command,
    operable program or batch file.

    ReplyDelete
  29. sorry, I run it again by using following command:
    arm-none-eabi-g++ -v

    The last line of output is :
    gcc version 4.4.1

    ReplyDelete
  30. Probably "make" is not in PATH. The other remote possibility is that somehow "make" was not installed. Try locating make.exe in the installation directory and include that in PATH.

    Another crude option is to install WinAVR or some other GCC compiler which will also install "make"

    ReplyDelete
  31. I dont have make.exe, but I have cs-make.exe file.

    ReplyDelete
  32. ok, I renamed cs-make.exe file to make.exe and now it compiles. thank you for ur help.

    ReplyDelete
  33. Hi,
    I am in my final year engineering. I am fairly new to LPC1768.
    I have tried the blinky program. Can you please help me with HELLO WORLD program?

    Deepthi

    ReplyDelete
  34. Hi again,
    i wanted to clarify that i want my program to print "hello world" on the serial window.

    Deepthi

    ReplyDelete
  35. I thank you alot for this tutorial. Helped alot!

    ReplyDelete
  36. it was very very useful and i thank you, but when i connect a led to pin0.0 it seems on , i connected to other pins but its the same, its like there is some voltage on all pins.
    i defined pin0.0 as output and set and reset it but there is no change in led status.here is my complete code:
    #include
    int main (void){

    LPC_SC->PCONP |= ( 1 << 15 ); // power up GPIO
    LPC_GPIO0->FIODIR |= 1 << 0;
    LPC_GPIO0->FIOPIN |= 1 << 0;

    }
    i will be thankful if you tell me what file should i add to project or what settings i should i do for cclk andpclk,
    thanks a lot for your attention.

    ReplyDelete