## Blinky The classic, helloWorld of embedded programming. This program turns the LED on and off periodically. ### Initial steps: - Create new project with project generator. - Open the project folder in VSCode. - Build the project by pressing the `build` button at the bottom and select the option with `arm-none-eabi`. - Make sure the build exits with code 0. ### Basic Code: ``` C int main() { stdio_init_all(); const uint OnBoardLED = PICO_DEFAULT_LED_PIN; gpio_init(OnBoardLED); gpio_set_dir(OnBoardLED, GPIO_OUT); while (true){ gpio_put(OnBoardLED, true); sleep_ms(500); gpio_put(OnBoardLED, false); sleep_ms(500); } } ``` #### Explanation: `stdio_init_all()`: initialize stuff `OnBoardLED = PICO_DEFAULT_LED_PIN`: Get the GPIO number of onboard LED. Remember: this is GPIO Number, NOT PIN NUMBER. `gpio_init(OnBoardLED)`: Initialize that GPIO pin. `gpio_set_dir(OnBoardLED, GPIO_OUT)`: Set GPIO direction (`GPIO_OUT` for writing and `GPIO_IN` for reading). `while (true){}`: Super loop of the program `gpio_put(OnBoardLED, true)`: Set `OnBoardLED` pin to `on` (`true` to turn on/set to high/voltage to VDD, `false` to turn off/set to low/voltage to GND) Pico logic HIGH voltage is 3.3v and LOW voltage is 0v. `sleep_ms(500)`: sleep for 500ms. --- ## Different Blinky This makes the pico blink like a beacon, 2 short blinks followed by long delay. A `for` loop is used for repeating the short blink twice. ```c for (int i = 0; i < 2; i++) { gpio_put(OnBoardLED, true); sleep_ms(50); gpio_put(OnBoardLED, false); sleep_ms(100); } sleep_ms(500); ``` --- ## External Blinky This program blinks an LED connected to one of the GPIO(General Purpose Input/Output) ports. For this example, I used Pin 20 == GP15. I connected a resistor to this pin and connected an LED in series with the resistor to the ground, as shown in the image below. This resistor limits the amount of current drawn by the LED. There are other ways to limit the current, which are discussed in this document later. ```c const uint LEDPin = 15; gpio_init(LEDPin); gpio_set_dir(LEDPin, GPIO_OUT); while (true) { for (int i = 0; i < 2; i++) { gpio_put(LEDPin, true); sleep_ms(50); gpio_put(LEDPin, false); sleep_ms(100); } sleep_ms(500); } ``` The only change here is in line 1, `PICO_DEFAULT_LED_PIN` is changed to `15`, to represent GP15. Remember: in the program, a GPIO pin is represented by the GP number and NOT by the pin number, as shown in the [Pico's Pinout](https://pico.pinout.xyz/). --- ## Multiple Blinky This program controls multiple LED connected to various GPIO ports. Here, the program is written such that it looks like a loading bar. For this setup, internal current limits are used. They are toggled programatically as shown in the code below. ```c int LED1 = 11; int LED2 = 12; int LED3 = 13; int LED4 = 14; int LED5 = 15; int LEDS[5] = {LED1, LED2, LED3, LED4, LED5}; for (int i = 0; i < 5; i++) { gpio_init(LEDS[i]); gpio_set_dir(LEDS[i], GPIO_OUT); gpio_set_drive_strength(LEDS[i], GPIO_DRIVE_STRENGTH_2MA); } while (true) { for (int i = 0; i < 5; i++) { gpio_put(LEDS[i], true); sleep_ms(100); } for (int i = 0; i < 5; i++) { gpio_put(LEDS[i], false); sleep_ms(100); } } sleep_ms(500); ``` ### Explanation: - `int LEDS[5] = {...};` declares a list of integers of length 5. GPIO numbers of the 5 connected LEDS are stored here. - `gpio_set_drive_strength(LED[i], GPIO_DRIVE_STRENGTH_2MA)` sets the **Drive Strength**/Current Limit of GPIO port. The RP2040 C SDK provides 4 drive strengths, 2mA, 4mA, 8mA and 12mA. The rest of the code is similar to the prior examples, which toggles the LEDS one by one, in series and turns them off, creating a loading effect. Visual output can be seen below. ## ToggleBlinky This example uses `gpio_get_out_level` to to get the output level for gicen given gpio port. The above example can be simplified by using this function call, as below. ```c int LED1 = 11; int LED2 = 12; int LED3 = 13; int LED4 = 14; int LED5 = 15; int LEDS[5] = {LED1, LED2, LED3, LED4, LED5}; for (int i = 0; i < 5; i++) { gpio_init(LEDS[i]); gpio_set_dir(LEDS[i], GPIO_OUT); gpio_set_drive_strength(LEDS[i], GPIO_DRIVE_STRENGTH_2MA); } while (true) { for (int i = 0; i < 5; i++) { gpio_put(LEDS[i], !gpio_get_out_level(LEDS[i])); sleep_ms(100); } } sleep_ms(500); ``` --- ## ParallelBlinky In this example, the init and set dir operations are performed simultaneously using `gpio_init_mask` and `gpio_set_dir_masked` calls. These take a integer value called mask, where each bit represents one GPIO pin. The above example can be simplified and replicated with the code below. ```c int LED1 = 11; int LED2 = 12; int LED3 = 13; int LED4 = 14; int LED5 = 15; int LEDS[5] = {LED1, LED2, LED3, LED4, LED5}; int pinMask = 0b1111100000000000; int dirMask = 0b1111100000000000; gpio_init_mask(pinMask); gpio_set_dir_masked(pinMask, dirMask); while (true) { for (int i = 0; i < 5; i++) { gpio_put(LEDS[i], !gpio_get_out_level(LEDS[i])); sleep_ms(100); } } sleep_ms(500); ``` Here, the `pinMask` variable represents the gpio pins. The position from the right represents the the gpio pin with that number and putting a `1` in that position means it is highlighted. So the 0th bit maps to GP0, 1st bit maps to GP1 and so on. We need GP11 to GP15, so the bits in 11th to 15th positions are set to `1`, denoting they are highlighted. `gpio_init_mask` will initialize only the pins highlighted in the function's input, which is its first argument `pinMask`. `gpio_set_dir_masked` will set the IO direction of only the highlighted pins in its first argument `pinMask` to the direction specified in its second argument `dirMask`. In dirMask, `1` denoted output and `0` denotes input. For this example, the init mask functions will initialize GP11 to GP15, because they are highlighted by `pinMask`. The set dir mask function will focus on GP11 to GP15, because they are highlighted by `pinMask`, take the bits in highlighted locations from `dirMask` and set the direction if they are 1 or 0. --- ## Line Control This experiment showcases how digital output pin can control a DC appliance, a fan in this case, using a particular IC. The code stays the same as `Blinky`, only the hardware changes. This example showcases real world use case for digital output. For this example, a `IRLZ44N` MOSFET is used for controlling a 12v DC fan. This MOSFET acts as a switch, which can be digitally controlled using the digital out pin on the pico. A 12v voltage module is used as power source for the fan. Positive of the module is connected to the fan's positive pin. The `Gate` pin of the mosfet is connected to a GPIO pin, `Source` is connected to ground and `Drain` is connected to -ve pin of the fan. It is important to note that ALL THE GROUND MUST BE CONNECTED, forming whats knows as **Common Ground**. [Explanaion provided in Arduino Forum](https://forum.arduino.cc/t/common-ground-and-why-you-need-one/626215). The ground of the 12v module is connected to ground of the pico. This should result in connections like below. Code to turn the fan on and off with a 2 second delay: ```c { stdio_init_all(); const uint FANPIN = 22; gpio_init(FANPIN); gpio_set_dir(FANPIN, GPIO_OUT); while (true){ gpio_put(FANPIN, true); sleep_ms(2000); gpio_put(FANPIN, false); sleep_ms(2000); } } ```