In this series, I design a programmable lab switch based on RP2040, that can turn a set of signals or supplies on or off. Over USB. SCPI compatible.
|
Task 1: extend the array of pins
Currently it's an array of 1 element (the LED), but you can define many. All GPIOs if you want.
The input validation will automatically adapt to the array size and only stack an error if you pass an index out of array range in the command
Don't forget to initialise these pins as outputs in the main() function
This is easy. I had prepared the code to deal with more than one pin. It originally only had a single definition: the on-board LED. But I had already (visionary :) ) placed it in an array:
// supported pins
uint pins[] = {PICO_DEFAULT_LED_PIN};
Let's add another pin. GP22 on pin 29 of the Pico. Why: because it's a pure GPIO pin, no other function. You can add any number of pins more if you want (homework).
uint pins[] = {PICO_DEFAULT_LED_PIN, 22};
Let's also move the definition out of the scpi sources, and place it in its own source file gpio/gpio_utils.c, where we also will put the code of task 2.
#include "hardware/gpio.h" #include "gpio_utils.h" // supported pins uint pins[] = {PICO_DEFAULT_LED_PIN, 22}; uint32_t pinCount() { return sizeof(pins)/sizeof(pins[0]); } void setPinAt(uint32_t index, bool on) { gpio_put(pins[index], on); }
You can see that I've taken the opportunity to add 2 helper functions, so that the scpi code doesn't have to know how many pins we have and how we store them. Here's the corresponding header, gpio/gpio_utils.h I created a corresponding header file:
#ifndef _GPIO_UTILS_H #define _GPIO_UTILS_H uint32_t pinCount(); void setPinAt(uint32_t index, bool on); #endif // _GPIO_UTILS_H
The code in the scpi parser now becomes very easy:
#include "gpio_utils.h" // ... // retrieve the output index SCPI_CommandNumbers(context, numbers, 1, 0); if (! ((numbers[0] > -1) && (numbers[0] < pinCount()))) { SCPI_ErrorPush(context, SCPI_ERROR_INVALID_SUFFIX); return SCPI_RES_ERR; } /* read first parameter if present */ if (!SCPI_ParamBool(context, ¶m1, TRUE)) { return SCPI_RES_ERR; } setPinAt(numbers[0], param1 ? true : false); // ...
You see the use of pinCount() and setPinAt() helpers here. Cleaner, simpler to maintain, and change the set of supported pins.
Task 2: write code that initialises the pins automatically
loop over all array items and set them as outputs.
In the original code, I configured the pin that I used in the main file. Now that we have the utility files, let's create an initialisation function that will work for 1 pin and many pins:
void initPins() { for (uint32_t i = 0; i < pinCount(); i++) { gpio_init(pins[i]); gpio_set_dir(pins[i], 1); gpio_put(pins[i], 0); } }
I've put it in the header file too, so that it can be called from main.
In the initialisation code, you get this:
// ... stdio_init_all(); initPins(); initUART(); // ...