Micropython on a cheap NRF51822 module

IMG_20200202_153744
It is possible to buy small NRF51822 modules like the black “daughter-board” in the picture above for about €2. The motherboard it connects to breaks all the pins out to various headers, provides an JTAG/SWD port and a USB/Serial interface. These motherboards cost around $6 on Aliexpress.
I was curious about micropython on this platform so I took the following steps:

First, I downloaded the Nordic Semiconductors command line tools from here
They were then installed as follows:

sudo dpkg -i nRF-Command-Line-Tools_10_6_0_Linux-amd64.deb

(I had to fiddle with my PATH environment variable to make the programs available to the script used later).

Next, the motherboard and JTAG interfaces were plugged in to a USB port.

Micropython was compiled and downloaded as follows (Note, I had an arm cross compiler already on my system.):

git clone https://github.com/micropython/micropython.git micropython
cd micropython
make -C mpy-cross
cd ports/nrf
./drivers/bluetooth/download_ble_stack.sh
make submodules
make BOARD=wt51822_s4at SD=s110 sd

The last line targets a particular board that is compatible with the little cheap Aliexpress one, it also includes the Bluetooth soft-device and flashes the board.

All that seemed to work ok and I tried to connect to the board over a serial terminal: No success. After a bit of searching I discovered file called mpconfigboard.h in the micropython/ports/nrf/boards/wt51822_s4at directory. This needs to be edited as follows so that TX and RX for the micropython shell are routed properly.

/*
 * This file is part of the MicroPython project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2017 Ayke van Laethem
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

// Datasheet for board:
// https://4tronix.co.uk/picobot2/WT51822-S4AT.pdf
#define MICROPY_HW_BOARD_NAME       "WT51822-S4AT"
#define MICROPY_HW_MCU_NAME         "NRF51822"
#define MICROPY_PY_SYS_PLATFORM     "nrf51"

#define MICROPY_PY_MACHINE_UART     (1)
#define MICROPY_PY_MACHINE_HW_SPI   (1)
#define MICROPY_PY_MACHINE_TIMER    (1)
#define MICROPY_PY_MACHINE_RTCOUNTER (1)
#define MICROPY_PY_MACHINE_I2C      (1)
#define MICROPY_PY_MACHINE_ADC      (1)
#define MICROPY_PY_MACHINE_TEMP     (1)
#define MICROPY_PY_RANDOM_HW_RNG    (1)

#define MICROPY_HW_HAS_LED          (0)

// UART config
#define MICROPY_HW_UART1_RX         (11)
#define MICROPY_HW_UART1_TX         (9)
#define MICROPY_HW_UART1_HWFC       (0)

// SPI0 config
#define MICROPY_HW_SPI0_NAME        "SPI0"
#define MICROPY_HW_SPI0_SCK         (1)
#define MICROPY_HW_SPI0_MOSI        (2)
#define MICROPY_HW_SPI0_MISO        (3)

Note the changes to MICROPY_HW_UART1_RX and MICROPY_HW_UART1_TX.

I repeated the last “make” command and hey presto : I was able to type python into a serial terminal!

nrf51822_python

There are a couple of little problems:
1) You can’t paste large amounts of python into the terminal as it overflows the serial buffer in the device
2) The range of pins available is restricted as this board is not quite the same as the wt51822_s4at

Anyway, it’s a start

17 thoughts on “Micropython on a cheap NRF51822 module

    • fduignan November 8, 2020 / 11:08 pm

      Thanks for that. Very nice

      Like

  1. Amir ghezelbash May 21, 2021 / 11:59 am

    hi, can you send link from your bin or hex file?

    Like

    • fduignan May 21, 2021 / 2:27 pm

      I put the firmware hex file up on pastebin. I believe this is the correct version but I am not sure. Just copy the pastebin text and paset it into a file

      Like

      • Amir ghezelbash May 22, 2021 / 2:47 pm

        Thank you for your fast response.

        I save it as .hex and upload code into nrf51822 nothing shows up in terminal.
        as i build from micropython without S110 everything is ok but then add S110 and nothing works.
        link to my build without s110: https://pastebin.com/6JVuLaSc
        link to my build with s110: https://pastebin.com/fCDSutrZ

        can you test my hex files?

        Like

      • fduignan May 22, 2021 / 3:34 pm

        Hi Amir, I no longer have that board so I can not debug your hex files. I do have a BBC microbit (V1) which includes an NRF51822. I may be able to experiment in a meaningful way with that however the serial TX/RX pins will likely be different.

        Like

      • fduignan May 23, 2021 / 11:37 am

        Hi Amir, I think I have a solution for you. This worked for me on the BBC Microbit. When you copy the s110 version of the hexfile to the device this does not seem to include the softdevice. I experienced the same problems as you did when I tried the s110 version. What I did next was to flash the softdevice hex file to the nrf51822. I then flashed the micropython hex file and the system worked again. This is related to interrupt vector tables I’m supposing. In my case, the softdevice hex file was found at micropython/ports/nrf/drivers/bluetooth/s110_nrf51_8.0.0/s110_nrf51_8.0.0_softdevice.hex
        When you program the second hex file be sure NOT to erase the entire device as you will be back where you started then. I hope this helps

        Like

  2. Amir ghezelbash May 28, 2021 / 4:53 pm

    Thanks a lot.
    It’s working.
    🙂

    Like

    • fduignan May 28, 2021 / 5:25 pm

      Cool!

      Like

  3. Amir ghezelbash June 8, 2021 / 4:54 pm

    Hi FDUIGNAN, the way you mention above working precisely, but in micropython as I try to use BLE . this error happend:
    “OSError: can’t apply GAP parameters”

    but when I use arduino, BLE works
    do you have any idea how I can fix this?
    Thanks.

    Like

    • fduignan June 8, 2021 / 5:01 pm

      Hi Amir, do you have any code that I can see?

      Like

      • Amir ghezelbash June 11, 2021 / 5:35 am

        The code is so simple I’ve just try to enable BLE

        import ble
        ble.enable()

        Like

  4. fduignan June 11, 2021 / 11:19 am

    Hi Amir, I have been able to replicate your fault. The behavior is the same on the Microbit as your board. I tried a modified version of one of the examples as follows:
    from ubluepy import Service, Characteristic, UUID, Peripheral, constants
    def event_handler(id, handle, data):
    global rtc
    global periph
    global serv_env_sense
    global notif_enabled

    if id == constants.EVT_GAP_CONNECTED:
    print(“Connected”)
    elif id == constants.EVT_GAP_DISCONNECTED:
    print(“Disconnected”)
    elif id == constants.EVT_GATTS_WRITE:
    print(“Gatt Write”)

    service_id=UUID(“0x1234”)
    characteristic_id=UUID(“0x5678″)
    myservice=Service(service_id)
    characteristic_properties=Characteristic.PROP_WRITE | Characteristic.PROP_READ
    periph = Peripheral()
    periph.addService(my_service)
    mycharacteristic = Characteristic(characteristic_id, props=characteristic_properties)
    myservice.addCharacteristic(mycharacteristic)
    periph = Peripheral()
    periph.addService(myservice)
    periph.setConnectionHandler(event_handler)
    periph.advertise(device_name=”ioprog”, services=[myservice])

    But this fails on the line “myservice=Service(service_id)”
    with the error:
    OSError: can’t apply GAP parameters
    The error is produced in ble_drv.c (I saw your post on the micropython forum)

    // set up security mode
    ble_gap_conn_params_t gap_conn_params;
    ble_gap_conn_sec_mode_t sec_mode;
    BLE_GAP_CONN_SEC_MODE_SET_OPEN(&sec_mode);
    const char device_name[] = “micr”;
    if ((err_code = sd_ble_gap_device_name_set(&sec_mode,
    (const uint8_t *)device_name,
    strlen(device_name))) != 0) {
    mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT(“can’t apply GAP parameters”));
    }
    I modified the code as follows:
    char message_number[20];
    int index=9;
    message_number[10]=0;
    while(index >=0)
    {
    message_number[index]=(err_code % 10)+’0′;
    err_code = err_code / 10;
    index –;
    }

    mp_raise_msg(&mp_type_OSError, MP_ERROR_TEXT(message_number));
    This printed the error code in the python terminal as follows:
    OSError: 0000000002
    Looking through the header files I see this:
    s110_nrf51_8.0.0_API/include/nrf_error.h:#define NRF_ERROR_SOFTDEVICE_NOT_ENABLED (NRF_ERROR_BASE_NUM + 2) ///< SoftDevice has not been enabled

    So it would seem that the softdevice has not been enabled is the cause of the error.
    I will continue to investigate for a bit

    Like

  5. fduignan June 11, 2021 / 3:10 pm

    One more thing:
    If I modify the code in ble_drv.c as shown below it tells me that the error is:
    NRF_ERROR_SDM_INCORRECT_INTERRUPT_CONFIGURATION
    This suggests that the module is already enabled. Something is going wrong down at the driver level or at least with its interface with Micropython

    #if (BLUETOOTH_SD == 110)
    #if BLUETOOTH_LFCLK_RC
    uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_RC_250_PPM_250MS_CALIBRATION,
    softdevice_assert_handler);
    printf(“LFCLK_RC \r\n”);
    #else
    uint32_t err_code = sd_softdevice_enable(NRF_CLOCK_LFCLKSRC_XTAL_20_PPM,
    softdevice_assert_handler);
    #endif // BLUETOOTH_LFCLK_RC
    #endif // (BLUETOOTH_SD == 110)
    if (err_code)
    {
    printf(“sd_softdevice_enable %u\r\n”,(unsigned int)err_code);
    }

    Like

  6. Amir August 29, 2021 / 2:36 pm

    Hi FDUIGNAN,
    Finally it works, just build again from last version of Micropython.

    Like

    • fduignan August 29, 2021 / 4:13 pm

      Thanks for letting me know Amir!

      Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s