34
edits
== Initial Downloads ==
For most projects I suggest you hand-type code that is in a code block in these articles. However for files that are not super important to the lesson, I will provide downloads. So for example, in this lesson, you will be writing a <code>main</code> program which means that the Makefile, startup code
== Goal ==
A common practice whenever one wants to program with something new is to write a very simple "proof-of-concept" program. If you are learning a new language perhaps you want to write a program that prints "Hello, World!" to <code>stdout</code>, or if you are learning a new library you want to do something to that effect utilizing some basic feature of that library (such as sending a network packet over Ethernet from one computer to another saying a message like "Hello, World!"). In the case of an embedded system, the standard beginner program of choice is to write a "Blinky" program, that is, a program that turns an LED on the board on and off at a certain rate. <blockquote>
Why is printing "Hello, World!" not a good first program for an embedded device?</blockquote>
== Structure of an Embedded Program ==
</syntaxhighlight>That's it! Our LED is now enabled.
== Main
''Navigate to <code>main.c</code> for this part. This file is blank because you will be writing everything here.''
=== Headers and Main ===
This section is for people who are not yet super comfortable with C. Whenever you do anything with a '''symbol''' (a variable or function) or a struct in C, it must be '''declared''' prior. For functions, the standard in C is to place '''function prototypes''' (that is, a line just containing the '''signature''' of a function) in a '''header file''' (raw text file, usually ending with a <code>.h</code> suffix). Such files are then "copied-and-pasted" into each C source file you want by writing the line <code>#include "name_of_header.h"</code>. Since we want to use definitions provided by our board manufacturer in their library, we must include the file that has all those definitions. So start with the line <code>#include "stm32g0xx_hal.h"</code>. Now we want to use <code>config_clock()</code> and <code>config_led()</code> that were written in <code>config.c</code>, so write <code>#include "config.h"</code> on the next line. Finally the C standard says that a C program starts execution in a function called <code>main</code>, so define it as follows:<syntaxhighlight lang="c">
int main(void) {
}
</syntaxhighlight>
=== Executing our Configs ===
Inside of <code>main</code>, we must first call a function to start up the HAL, so the first line of <code>main</code> should be <code>HAL_Init();</code>. Now we are ready to start configuring our board for our application. First configure the clock, and then the LED:<syntaxhighlight lang="c">
int main(void) {
HAL_Init();
config_clock();
config_led();
}
</syntaxhighlight>
=== The Main Loop ===
Now that we're done with the configs, it's time to start writing some application code. How do we translate the logic of turning an LED on and off into code? Suppose we had a function called <code>toggle()</code> which flips the state of the LED. So if it is off and we call <code>toggle()</code>, the LED turns on, and vice versa. The CPU is really fast, so if we just wrote that line in an infinite loop, the LED would (at a rate of almost 16 million times a second!) turn on and off. I don't know about you but my eyes cannot discern that. If I were to do this with a light switch, it's as though I would want to ''wait a little bit'' in between turning the light on and off to make it more noticeable. That's exactly what we want to do in code. Flip the switch, wait a little bit, flip the switch, wait a little bit, flip the switch, and so on.
Say we want to wait a second between flipped switches. Fortunately the HAL has a function to wait a specified number of milliseconds, called <code>HAL_Delay()</code>. The <code>toggle()</code> function provided by HAL is actually called <code>HAL_GPIO_TogglePin()</code> and takes as arguments (you guessed it) the port and pin we want to flip. Thus our final <code>main.c</code> should be as follows:<syntaxhighlight lang="c">
#include "stm32g0xx_hal.h"
#include "config.h"
int main(void) {
HAL_Init();
config_clock();
config_led();
for (;;) { // this is one way to do an infinite loop in C
HAL_Delay(1000);
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_5);
}
}
</syntaxhighlight><blockquote>'''Exercise'''
How do you think <code>HAL_Delay</code> works? How is the CPU able to figure out how long one second actually is?</blockquote>
== Compiling and Flashing ==
Using the provided Makefile, run the command <code>make</code> to compile, and run the command <code>make flash</code> to flash the board. Hopefully your board should be blinking! Feel free to mess around with the constant in the <code>HAL_Delay()</code> call to make the LED blink faster or slower.
|
edits