Hacking a MicroPython board with custom firmware

I've had a MicroPython board sitting around my work bench for a while.  I think it's a brilliant way of interfacing hardware and using Python in a very straightforward way.  I've thinking about getting into into programming ARM chips for a little bit, and my MicroPython board came to mind.  After all, it's potentially a great development board if only we could hack the firmware that comes with it!




Software you will need...
System Workbench 
http://www.openstm32.org/Downloading%2Bthe%2BSystem%2BWorkbench%2Bfor%2BSTM32%2Binstaller

Download "System Workbench" from the above link.  You'll need to register on the site, but you'll then be able to download and install the correct version.  The installer will also install Eclipse and any necessary suitable drivers.

DfuSe
http://www.st.com/en/development-tools/stsw-stm32080.html

We'll use this to upload our code later (and to create DFU files from HEX files)

Start a new project
Once installed, follow these instructions to make a new project.  In our case however, we're not using a STM32F4 Discovery board, so click "Create a new custom board".  A quick glance at the schematic (which might be different depending on your version of the micropython board), reveals the ARM chip is "STM32F405RGT6", so select "STM32F405RTGx" from the drop-down menu.  Call the new board something like "Pyboard" and you'll be able to use it for future projects.Don't click "Finish" until the very end (click Next) - otherwise it is easy to skip past the 'Project firmware configuration' window.  This is crucial as we need to get the Standard Peripheral Libraries or the HAL for our MCU (I'm using Standard Peripheral Libraries).  Download the target firmware, select Add low level drivers in the project (as sources in the application project).  Now click Finish.

Write some code!
Let's blink an LED.  Into main.c, add this code:

#include <stm32f4xx.h>

void delay (int a);

int main(void)
{
//Enable the GPIOB Clock
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);

// GPIOB Configuration - PyBoard BLUE LED = PB4
  GPIO_InitTypeDef GPIO_InitStruct;
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_4; //
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;

  GPIO_Init(GPIOB, &GPIO_InitStruct); // Init LED pins

  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
  //Initialize pins
  GPIO_Init(GPIOB, &GPIO_InitStruct); // Init button pin - PB3

  while(1)
  {
  if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3))
  {
  GPIO_SetBits(GPIOB, GPIO_Pin_4);
  delay(500000);
  GPIO_ResetBits(GPIOB, GPIO_Pin_4);
  delay(500000);
  }
  else
  {
  GPIO_SetBits(GPIOB, GPIO_Pin_4);

  }
  }
}

void delay (int a)
{
    volatile int i,j;

    for (i=0 ; i < a ; i++)
    {
        j++;
    }
    return;
}

I've modified this code from here and here.  For reference the PyBoard LEDS and USR switch are on the following GPIOs (again according to the schematics for my board):
  • PB4 = BLU_LED
  • PA15 =YEL_LED
  • PA14 = GRN_LED
  • PA13 = RED_LED
  • PB3 = USR SWITCH
The code is fairly self-explanatory.  The blue LED GPIO (PB4) is defined as an output, and the USR switch is defined as an input (pull-UP resistor is important).  Now the button is polled.  If it is un-pressed (HIGH), the blue LED is flashed, else if it is pressed, the LED GPIO B4 is held high (ON).
This should all compile and build fine (Ctrl+B).

Flashing compiled code to MicroPython board
We need to instruct System Workbench to generate a HEX file for us (I tried and failed to put code on the MicroPython board with a BIN file).  This advice worked well. Go to Project ->Properties -> C/C++ Build -> Settings.  On Build Steps tab there's a post-build steps box.  Add the following line (preceeded with a ';' to the 'Command' line):

arm-none-eabi-objcopy -O ihex "${BuildArtifactFileBaseName}.elf" "${BuildArtifactFileBaseName}.hex"

Now Build All, and a HEX file will appear in the Debug folder. 
Create a DFU file using the "DFU file manager" that you downloaded previously and the HEX file you just created in System Workbench.  Generate and save the output DFU. 
Now launch the DfuSe demo program.  It should automatically pick up the MicroPython board when it's in DFU mode.  Instructions on how to do this are here.  Now click "Choose" in the bottom-right hand  "Upgrade or Verify Action" panel, and select the HEX file you just generated.  Click on Upgrade (click okay/yes) to any warnings and watch the file stream onto the device!  As we have such a tiny program, it will take no time at all.

Now disconnect the wire bridging the DFU pin and the 3.3V pin (keep connected to PC), and press and release the RESET button.  Voila!  The blue LED should start flashing (you no longer need an SD card present of course), and pressing the USR button will causing the blue LED to stay on.

Of course at any time we can download the latest DFU file from the MicroPython website and revert the board back to its previous settings.  In addition, we can use the DfuSe utility to make a back up of the firmware before we start adding our own!

Going forwards
This is all very tedious though, isn't it? Next I want to generate the DFU file and upload to the device through the command line... In the mean time, enjoy your new super fast ARM board!

EDIT:
I have now added a blog post detailing how to generate the DFU file and flash it with a Batch file:
http://shepherdingelectrons.blogspot.co.uk/2017/11/uploading-custom-hex-firmware-to-pyboard.html

Comments

  1. Hi Duncan! I also have a pyboard V11 lying around, and I had the same thought as yours! You can't really imagine how difficult it was for me to make anything work, I mean, to build and FLASH (that is the most difficult part!) something that would have worked!

    I managed to successfully make your code to run and I'm pretty happy since it took me too long!

    What about the totally CLI version? I'm very interested in it since I do use Ubuntu primarily, so I need a way to build things quickly using a totally (or mostly) automated workflow!

    Do you know if there is any solution/software/tool that is capable of creating .dfu files ready to be flashed with dfu-util?

    Again, thank you for this tutorial, I hope to hear something from you in order to make this flash process as straightforward and automatized as possibile!

    ReplyDelete
    Replies
    1. Hi Jack,

      Really glad it works for you!
      Check out my latest blog post on making the DFU and flashing it with a batch file:
      http://shepherdingelectrons.blogspot.co.uk/2017/11/uploading-custom-hex-firmware-to-pyboard.html

      I had another play around with the board recently and got communication over UART working, but I can't seem to get the SD card to mount and read/write files :-(. I'm been trying to use STM32F4 Discovery libraries ( https://stm32f4-discovery.net/2014/05/all-stm32f429-libraries-at-one-place/ ) because the wiring for the SD card is the same as for the pyboard, but I can't get it to work yet... :-/

      I'm wondering whether another approach might be to re-compile the micropython code, but take out the entire python thread leaving a barebones that contained the UART and SD-card access.

      Delete

Post a Comment

Popular posts from this blog

Arduino and Raspberry Pi serial communciation

Getting started with the Pro Micro Arduino Board