makersguide_ch3.2.png

In this lesson, you will learn how to develop code to blink an LED and the process of creating an embedded executable and transferring that executable to the Wonder Gecko Starter Kit.  

 

Enable the GPIO Clock

The first thing that we must do in our code before we can try to put voltage on any pin is to turn on the GPIO clock source.  By default, all clocks are disabled except for the HFCLK, which is the only one that is necessary to enable programs to run on the MCU, but doesn’t allow for many, if any,
of the peripherals to function. 

 

WARNING: If you try to use a peripheral whose clock source is not configured, nothing will happen.  Nothing BAD will happen, it just won’t do what you expect and the compiler will not complain at all.  You will sit there stumped for a while.   Personally, I forget to enable clock sources for the peripherals that I use all the time.  After a while, it becomes the automatic first thing that I check when things don’t work as expected.

 

To enable the GPIO clock, we need to add the statement #include “em_cmu.h” file to our compiler directives section.  This will bring in the necessary Clock Management Unit (CMU) EFM32 library that makes our job easier.  We could get the job done by just using the definitions that are available in “em_system.h,” but there could be a sequence of events that must be completed.  The library team at Silicon Labs has already worked out the sequence of events in these support libraries, so I like to use them until I have a good reason to go a different route. 

 

Note that whenever we add a .h file to our code, we have to add the rest of the library driver to our build environment.  The .h file is a header file, which pulls in function declarations and some definitions.  But some of the definitions only are found in the .c file, which is the implementation file.  The way to get the .c file for an emlib driver into your 3_Hello_World project is a bit complicated.  You will get used to it in time.

 

The files that you will need are in C:\SiliconLabs\SimplicityStudio\v2\developer\sdks\efm32\v2\emlib\src if you are on a Windows computer.  For all other computers, the path of the files will be relative to the SiliconLabs install directory.  Just copy that whole thing into your explorer or finder window and bookmark it.  Then, whenever you need a library file, open this bookmark, find the file from within that directory and copy it into your emlib directory in Simplicity Studio.   In this case, we need the em_gpio.c file and the em_cmu.c file.  Select both of those and copy them into your emlib directory for the 3_Hello_World project.

 

When you paste the files into emlib, Simplicity Studio will ask if you want to copy the files or link the files.  If you copy the files, you will freeze the files in time and they won’t ever change unless you change them.  If you link the files, your library files could be updated when you update the Simplicity Studio software.  I like to make a copy and then control when I get the update for an existing project.

 

Here is the function call from the CMU that we need to add to our code to enable the GPIO clock.  Just drop it in right after the CHIP_Init() function call without a return assignment.  

 

CMU_ClockEnable(cmuClock_GPIO, true);

 

But how did I know that?  Well, this one is pretty simple because it shows up in all of the examples.  But if I didn’t already know that, here is how I could have found out...   Once again, the information is right there in the Simplicity Studio software.  Navigate back to the Simplicity Studio home screen by selecting the Simplicity perspective button at the top right hand corner of the IDE.  Then, select the “Software Documentation” tile.  I am omitting pictures since you should be familiar with what a tile looks like by now.   In the window that appears, you will scroll down to the Wonder Gecko section and click on the link “emlib Peripheral API for the Wonder Gecko family” and that takes you to an Internet page that details all of the available emlib functions:

ch3.2_api.png

 

When you then click on the CMU_ClockEnable branch, you see all the gory details about what this function does:

 

ch3.2_clockenable.png 

 

This tool is very useful to figure out what library functions already exist and their uses.  But now you look at that parameter list and you might think, what is a CMU_Clock_Typedef and how do I pass that into the function?  Easy.  Just click on the CMU_Clock_Typedef which is linked to a list of enumerations for the type.  You will see that cmuClock_GPIO is already in that list.  Since you have already included em_cmu.h at the top of your file, the enumeration is detected by Simplicity Studio and it gives it an italic blue style to indicate that it recognizes it as a known enumeration.

 

Set a GPIO Pin High

Now that we have enabled the clock, we are ready to turn on the LED.  You could once again look through the emlib API guide to find the “em_gpio.h” library (don’t forget to add the #include “em_gpio.h” to the top of your code in the compiler directives section) and find following function:

 

GPIO_PinModeSet(gpioPortE, 2, gpioModePushPull, 1);

 

Once again, the enumerations for gpioPortE and gpioModePushPull can be found in the em_gpio.h library header file or on the emlib API guide.  Don’t worry about what gpioModePushPull means.  We will cover that in the next lesson.  With this statement, we are instructing the GPIO peripheral to set the output mode of pin E2 to a push-pull driver, and to put that pin in a high state.  If you will recall, we read that one of the test LEDs was on pin E2 and was of type “active high” which means that we have to drive pin E2 high to turn on the LED.  So that is what we have just done.

 

That’s it!  We are now ready to run our first program on the Starter Kit.

 

Attach to the Starter Kit

Plug in your Starter Kit via the USB cable and let your system detect it.  Since you have already installed Simplicity Studio in the first lesson, the drivers should be ready to recognize it and attach to it.  Next, open Simplicity Studio and create a “New Silicon Labs MCU Project” from the File menu.  Name the project “3_Hello_World” and Simplicity will open the emptyProject.c file for you.

 

Your Wonder Gecko MCU on the Starter Kit can be powered by the USB cable or by a little coin battery to the bottom left.  You don’t need to use a coin battery for now, so make sure that the little switch is slid over to the right side.  If this switch is set wrong, the Starter Kit will be detected by your computer over USB, but you will not be able to program the MCU from Simplicity Studio.

 

ch3.2_wondergecko.png

 

 

Build and Run the Executable

Now, press the build button, which if you recall looks like a little hammer in the tool bar at the top of the screen.  The IDE will automatically save and build the emptyProject.c file with your new changes.  If all goes well, you should see things streaming by in the lower console “Build Console” until you see if it failed or succeeded.  Make sure to look back in the log every time and look for warnings as well as errors, because warnings are often just as bad as errors.  Always start with the first warning or error that happens in the Build Console by scrolling back to find it.  Read what it says and try to solve the problem.  Then rebuild until you get no errors or warnings.

 

Now that we have built the executable, you are ready to transfer it to the Wonder Gecko and run it on the MCU.  To do this, press the Debug icon on the toolbar.  It is the one that looks like a little bug: 

 

 ch3.2_icon.png
The Debug tool will first save your files, then build (again) and then transfer the executable to Wonder Gecko and leave your current execution line icon at the first line in the main() function. 

 

 NOTE: You do not have to first Build and then Debug your code, since the Debug tool will do both as part of its sequence, but I find that it is easier to find problems by building before debugging.  If there are build errors, the Debug tool will complain that it can’t transfer a file because it hasn’t be built yet.  In addition, the IDE will swap our Build Console with the Program Output Console, and so your will have to hunt around the icons to find the Build Console again.

 

ALSO NOTE: Sometimes the build leaves files behind and needs to be cleaned.  If you find that things are inexplicably failing with odd errors, try the Clean option from the build menu and try building again.

 

Let’s set a break point at line 30, that contains the CMU_ClockEnable() function.  To do that, right click on the space to the left of line 30 and pick “Toggle Breakpoint.”  Your screen should now look like this:

 ch3.2_debugger.png

 

You will see the Run, Pause, Detach, Reset, Step In, and Step Over icons at the top appear when Simplicity Studio automatically switches over to “Debug perspective.”  You can use them now.  First click the Run button.  Simplicity Studio will execute all of the lines up to line 30, leaving the current line icon on line 30, ready to execute that line.  From there, click on the “Step Over” button and you will see the current execution arrow move to line 31.  When you pressed the Step Over button, it executed the code on line 30, and only that line.  Inside the MCU, the GPIO clocks should now be alive and ready to execute line 31.  So press Step Over again, and voila! You should see LED0 light up on the Starter Kit!

 

ch3.2_led.png

Providing LED Illumination on LED0

 

If you have trouble, take a look at the source code available on the Maker's Guide web page.  The full source is available.

 

Make it Blink

But wait!  We can turn it on but the “Hello World” program requires that we make it blink.  So let’s do that.

We need to turn the LED off and on, but if we do it too quickly, no human would be able to see the blinking.  You have to remember that the MCU can do things very fast, so fast that you can’t even see it.  You now live in a world of nanoseconds, microseconds and milliseconds.  So we will add some delay and then turn the LED off, then more delay and turn it back on, forever.  There are many ways to add delays and delays are one of the important topics of the upcoming lessons, so for now we will use a simple execution delay.  

 

Make your main function look like the following:

 

int main(void)
{
  /* Chip errata */
  CHIP_Init();
 
  CMU_ClockEnable(cmuClock_GPIO, true);
 
  /* Infinite loop */
  while (1)
  {
        // Turn on the LED
        GPIO_PinModeSet(gpioPortE, 2, gpioModePushPull, 1);
              
        // Add some delay
        for(volatile long i=0; i<100000; i++)
            ;
       
        // Turn off the LED
        GPIO_PinModeSet(gpioPortE, 2, gpioModePushPull, 0);
       
        // Add some more delay
        for(volatile long i=0; i<100000; i++)
            ;
  }
}  

When you execute the above code, your LED should be blinking nicely.  Here is what happens.  We add a delay by keeping the MCU core busy doing meaningless work with the for loop.  It is definitely the WORST kind of delay to use because it is not consistent across different processor speeds AND it wastes energy.  I am only using this for now because it is quick and dirty.  It is perfectly acceptable to do stuff like this during the prototyping stage.  The keyword volatile tells the compiler that the variable i might change outside the compilers control.  For instance, another MCU might be running on the same memory space and that the variable could change at any moment.  Depending on the build settings, the compiler might “optimize away” the repeated (useless) setting of i.  The whole line of instruction might not even show up in our executable.  By declaring it volatile, we tell the compiler not to mess with it and force the machine to execute the useless loop 100,000 times, which adds up to enough of a delay that the LED settles down and you see it as off for a split second.  That should give you a good idea of how many things this MCU can do in a single second.  If the compiler were to optimize away the setting of i, the for loop would not be in your executable and there would be no delay at all.  The LED would blink so fast that you wouldn’t be able to see it. 

 

So this wraps up your first real embedded program.  Congratulations!  Consider yourself welcomed among the elite group of people who have ever written an embedded program.   Now go find someone right now and drag them over to your creation to show them your little blinky light.  But please try to use some big words like “compiled” and “volatile variable execution delay” etc., that you just learned so that you don’t describe it as just a blinky light.

 

If you want to take this lesson further, figure out how you might speed up or slow down the rate of blink.  Can you make it blink three times and then pause for a few beats?  Can you blink it so quickly that the LED appears to be dimmed?  Can you make the LED glow brighter and brighter over time, like a sunrise?  You’ve got the tools now, using only the simple statements that we have studied so far.  Post your solution in the comments section.

 

In the next lesson, we will continue the study of the all-important GPIO and other ways we can drive it, including an introduction to basic electronics and breadboarding.

 

PREVIOUS NEXT

  • Blog Posts
  • Makers