Writing a Blinky Program: Difference between revisions

From R@M Wiki
Line 6: Line 6:


== Structure of an Embedded Program ==
== Structure of an Embedded Program ==
Embedded programs follow the same abstract structure as programming for any system: set up your resources, then enter the main execution.
Embedded programs follow the same abstract structure as programming for any system: set up your resources, then enter the main execution. For now, setting up your resources essentially means writing certain values to registers to tune the settings of the system, things like the clock, turning on or off certain pins on the board, or editing the speed of various communication protocols. Main execution for embedded devices will almost always live in an infinite loop. The idea is, "When I get power, turn on and run my code until I no longer have power, then I'll stop," so it makes sense to have the CPU constantly executing code (otherwise it would just be wasting power).


== Configs ==
== Configs ==
''Navigate to <code>config.c</code>. This is where we will store the configuration code. You will be writing the code for <code>config_led()</code>.''

One benefit of programming embedded devices is the freedom you get to configure anything you could possibly imagine on the system. The first thing you'll encounter is the clock. The official maximum clock rate of the CPU is 64 MHz (meaning 64 million CPU cycles occur every second, more on this later). So with that constraint, you are free to set the clock as you wish. For this project I have set the clock to run at the default value of 16 MHz, since right now we are not doing anything super intensive.

Now we want to blink the LED. The LED will turn on when it gets power, and off when it doesn't have power. The LED is connected to the CPU via one of the pins (on this system, it happens to be GPIO PA5). Since almost every pin starts disabled by default, we need to tell the hardware we want PA5 enabled with the ability to output an electrical signal (which will then toggle to turn the LED on and off). According to the official library documentation, we need to turn on the clock for the pin, and use <code>HAL_GPIO_Init()</code> to configure it. This function takes a GPIO port (which for now you can think of as a method the hardware uses to organize all the GPIO pins) and a configuration stored in a C struct <code>GPIO_InitTypeDef</code>. As per the documentation, we want the following configuration:<syntaxhighlight lang="c">
GPIO_InitTypeDef led_config = {
.Pin = GPIO_PIN_5,
.Mode = GPIO_MODE_OUTPUT_PP,
.Pull = GPIO_NOPULL,
.Speed = GPIO_SPEED_FREQ_LOW,
.Alternate = 0
};
</syntaxhighlight>Line by line we have:

* We want to edit pin '''5''' of '''P'''ort '''A''' (hence the pin name PA5)
* We want to '''output''' data with this pin, and we will use '''P'''ush-'''P'''ull to do so (don't worry about what that means for now, just know that it means electrical signals will be outputted on this pin)
* You can ignore the <code>.Pull</code> and <code>.Speed</code> lines as well
* <code>.Alternate</code> is a field that is used if we wanted to do something more complicated with this pin, such as digital communication with other devices. Since we are not doing anything complicated, we set this to <code>0</code>, meaning don't do any alternate function

Then turn on the clock and write the config:<syntaxhighlight lang="c">
__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_Init(GPIOA, &led_config);
</syntaxhighlight>That's it! Our LED is now enabled.


== Main Loop ==
== Main Loop ==

Revision as of 02:50, 6 October 2024

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 main program which means that the Makefile, startup code, callbacks, and interrupts do not pertain to you just yet, and hand-typing them will not be super useful/a worthwhile use of your time. So the provided initial code is here:

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 stdout, 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.

One thing to think about is why printing something like "Hello, World!" is not a good first program for an embedded device environment.

Structure of an Embedded Program

Embedded programs follow the same abstract structure as programming for any system: set up your resources, then enter the main execution. For now, setting up your resources essentially means writing certain values to registers to tune the settings of the system, things like the clock, turning on or off certain pins on the board, or editing the speed of various communication protocols. Main execution for embedded devices will almost always live in an infinite loop. The idea is, "When I get power, turn on and run my code until I no longer have power, then I'll stop," so it makes sense to have the CPU constantly executing code (otherwise it would just be wasting power).

Configs

Navigate to config.c. This is where we will store the configuration code. You will be writing the code for config_led().

One benefit of programming embedded devices is the freedom you get to configure anything you could possibly imagine on the system. The first thing you'll encounter is the clock. The official maximum clock rate of the CPU is 64 MHz (meaning 64 million CPU cycles occur every second, more on this later). So with that constraint, you are free to set the clock as you wish. For this project I have set the clock to run at the default value of 16 MHz, since right now we are not doing anything super intensive.

Now we want to blink the LED. The LED will turn on when it gets power, and off when it doesn't have power. The LED is connected to the CPU via one of the pins (on this system, it happens to be GPIO PA5). Since almost every pin starts disabled by default, we need to tell the hardware we want PA5 enabled with the ability to output an electrical signal (which will then toggle to turn the LED on and off). According to the official library documentation, we need to turn on the clock for the pin, and use HAL_GPIO_Init() to configure it. This function takes a GPIO port (which for now you can think of as a method the hardware uses to organize all the GPIO pins) and a configuration stored in a C struct GPIO_InitTypeDef. As per the documentation, we want the following configuration:

GPIO_InitTypeDef led_config = {
    .Pin = GPIO_PIN_5,
    .Mode = GPIO_MODE_OUTPUT_PP,
    .Pull = GPIO_NOPULL,
    .Speed = GPIO_SPEED_FREQ_LOW,
    .Alternate = 0
};

Line by line we have:

  • We want to edit pin 5 of Port A (hence the pin name PA5)
  • We want to output data with this pin, and we will use Push-Pull to do so (don't worry about what that means for now, just know that it means electrical signals will be outputted on this pin)
  • You can ignore the .Pull and .Speed lines as well
  • .Alternate is a field that is used if we wanted to do something more complicated with this pin, such as digital communication with other devices. Since we are not doing anything complicated, we set this to 0, meaning don't do any alternate function

Then turn on the clock and write the config:

__HAL_RCC_GPIOA_CLK_ENABLE();
HAL_GPIO_Init(GPIOA, &led_config);

That's it! Our LED is now enabled.

Main Loop