More convenient pin initialization for ESP8266

Discussion about programs, libraries and tools that work with MicroPython. Mostly these are provided by a third party.
Target audience: All users and developers of MicroPython.
Post Reply
dehmoubedr7811
Posts: 6
Joined: Wed Apr 21, 2021 4:25 am

More convenient pin initialization for ESP8266

Post by dehmoubedr7811 » Wed Apr 21, 2021 4:36 am

Hi all,

I am trying to develop custom firmware for the ESP8266 module that can allow users to initialize Pins on an ESP8266 more conveniently.

Below is an example of how I would want to instantiate the D6 pin using the custom firmware that I aim to develop.

ESP8266 pinout:
https://imgur.com/VN06Xxl

Image of ideal firmware:
https://imgur.com/a/mN9AbB0


Essentially, I want to allow a user to initialize a Pin with a string so that they wouldn’t have to continuously look at the above diagram to know what GPIO pin each label on the microcontroller corresponds to and, instead, just input the labeled pin for convenience.

I am new to the MicroPython codebase and have limited experience with low-level programming, so I would be grateful if anyone has any suggestions on how to go about working through this task.

The current approach that I am thinking about using is to write code to map a string input into the corresponding GPIO pin to minimize the consequences of the modification to the rest of the MicroPython functionality.

Does anyone know where to implement these changes? From the research that I have done, I found that machine_pin.c (https://github.com/micropython/micropyt ... hine_pin.c) initializes possible GPIO pins, but I’m not able to pinpoint how to the function that is used to instantiate a specific pin.

Thank you so much,
Ryan Dehmoubed

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: More convenient pin initialization for ESP8266

Post by Roberthh » Wed Apr 21, 2021 8:10 am

You can set up a dictionary in your code that maps between the String labels and the Pin numbers. No need to change the firmware, especially since these mappings are vendor-specific.

dehmoubedr7811
Posts: 6
Joined: Wed Apr 21, 2021 4:25 am

Re: More convenient pin initialization for ESP8266

Post by dehmoubedr7811 » Wed Apr 21, 2021 6:45 pm

I didn't give enough context. I'm trying to teach a summer camp where we hope to teach MicroPython to beginners.

We would still want to provide a custom firmware because it makes it a lot less tedious for beginners to initialize different pins on the board. We could it a node MCU firmware to make it work specifically for that ESP8266 vendor. Any other suggestions would be greatly appreciated!

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: More convenient pin initialization for ESP8266

Post by Roberthh » Wed Apr 21, 2021 7:54 pm

It can be done by modifying machine_pin.c. At line 312 the pin number is taken from the argument. That has to extended to compare against a string of known Pin names.I made a trial build by:
a) extending the _pin_obj_t structure in modmachine.h to:

Code: Select all

typedef struct _pyb_pin_obj_t {
    mp_obj_base_t base;
    uint16_t phys_port;
    uint16_t func;
    uint32_t periph;
    char *pin_name;
} pyb_pin_obj_t;
b) adding a pin name to the list of pin definitions in machine_pin.c, lines 65 ff, using the Pin names of a WEMOS D1 mini:

Code: Select all

const pyb_pin_obj_t pyb_pin_obj[16 + 1] = {
    {{&pyb_pin_type}, 0, FUNC_GPIO0, PERIPHS_IO_MUX_GPIO0_U, "D3"},
    {{&pyb_pin_type}, 1, FUNC_GPIO1, PERIPHS_IO_MUX_U0TXD_U, "TX"},
    {{&pyb_pin_type}, 2, FUNC_GPIO2, PERIPHS_IO_MUX_GPIO2_U, "D4"},
    {{&pyb_pin_type}, 3, FUNC_GPIO3, PERIPHS_IO_MUX_U0RXD_U, "RX"},
    {{&pyb_pin_type}, 4, FUNC_GPIO4, PERIPHS_IO_MUX_GPIO4_U, "D2"},
    {{&pyb_pin_type}, 5, FUNC_GPIO5, PERIPHS_IO_MUX_GPIO5_U, "D1"},
    {{NULL}, 0, 0, 0, ""},
    {{NULL}, 0, 0, 0, ""},
    {{NULL}, 0, 0, 0, ""},
    {{&pyb_pin_type}, 9, FUNC_GPIO9, PERIPHS_IO_MUX_SD_DATA2_U, ""},
    {{&pyb_pin_type}, 10, FUNC_GPIO10, PERIPHS_IO_MUX_SD_DATA3_U, ""},
    {{NULL}, 0, 0, 0, ""},
    {{&pyb_pin_type}, 12, FUNC_GPIO12, PERIPHS_IO_MUX_MTDI_U, "D6"},
    {{&pyb_pin_type}, 13, FUNC_GPIO13, PERIPHS_IO_MUX_MTCK_U, "D7"},
    {{&pyb_pin_type}, 14, FUNC_GPIO14, PERIPHS_IO_MUX_MTMS_U, "D5"},
    {{&pyb_pin_type}, 15, FUNC_GPIO15, PERIPHS_IO_MUX_MTDO_U, "D8"},
    // GPIO16 is special, belongs to different register set, and
    // otherwise handled specially.
    {{&pyb_pin_type}, 16, -1, -1, "D0"},
};
c) replace line 312 by the following code:

Code: Select all

    size_t len;
    const char *pin_name;
    pin_name = mp_obj_str_get_data(args[0], &len);
    int wanted_pin = 99;
    for (int i = 0; i < MP_ARRAY_SIZE(pyb_pin_obj); i++) {
        if (len == strlen(pyb_pin_obj[i].pin_name) &&
            strncmp(pin_name, pyb_pin_obj[i].pin_name, len) == 0) {
                wanted_pin = i;
                break;
        }
    }
    // int wanted_pin = mp_obj_get_int(args[0]);
Then, a pin can e.g. be created by:

from machine import Pin
p=Pin("D1", Pin.OUT)

dehmoubedr7811
Posts: 6
Joined: Wed Apr 21, 2021 4:25 am

Re: More convenient pin initialization for ESP8266

Post by dehmoubedr7811 » Thu Apr 22, 2021 3:22 am

Thank you so much Robert for taking the time to write all of that. It worked! I will definitely look to extend the favor to someone else in the future!

Best,
Ryan Dehmoubed

User avatar
Roberthh
Posts: 3667
Joined: Sat May 09, 2015 4:13 pm
Location: Rhineland, Europe

Re: More convenient pin initialization for ESP8266

Post by Roberthh » Thu Apr 22, 2021 7:39 pm

That's fine. I made two minor changes to it:
a) Simplify the function mp_pin_make_new()
b) Change pyb_pin_print() such that it shows both the pin name and the GPIO number.

Code: Select all

// constructor(id, ...)
mp_obj_t mp_pin_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
    mp_arg_check_num(n_args, n_kw, 1, MP_OBJ_FUN_ARGS_MAX, true);

    // get the wanted pin object
    size_t len;
    const char *pin_name;
    pin_name = mp_obj_str_get_data(args[0], &len);
    pyb_pin_obj_t *pin = NULL;
    for (int i = 0; i < MP_ARRAY_SIZE(pyb_pin_obj); i++) {
        if (len == strlen(pyb_pin_obj[i].pin_name) &&
            strncmp(pin_name, pyb_pin_obj[i].pin_name, len) == 0) {
                pin = (pyb_pin_obj_t *)&pyb_pin_obj[i];
                break;
        }
    }

    if (pin == NULL || pin->base.type == NULL) {
        mp_raise_ValueError(MP_ERROR_TEXT("invalid pin"));
    }

    if (n_args > 1 || n_kw > 0) {
        // pin mode given, so configure this GPIO
        mp_map_t kw_args;
        mp_map_init_fixed_table(&kw_args, n_kw, args + n_args);
        pyb_pin_obj_init_helper(pin, n_args - 1, args + 1, &kw_args);
    }

    return (mp_obj_t)pin;
}

Code: Select all

STATIC void pyb_pin_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
    pyb_pin_obj_t *self = self_in;

    // pin name
    mp_printf(print, "Pin('%s'), GPIO%u", self->pin_name, self->phys_port);
}

Post Reply