Close
0%
0%

Motor Shield Reprogramming

Create and flash new firmware for the WeMos D1 Mini Motor Shield.

Similar projects worth following
There is a motor shield for the WeMos D1 Mini ESP8266 board, and it uses an STM32F030 microcontroller for the communication. However, the code running on it is really sloppy, resulting in the firmware hanging and bringing the I2C bus down whenever you look at it funny. But we are hackers, we can fix it!

We have pretty good information about the motor shield:

The shield has a serial interface for programming broken out, and that chip is supposed to have a bootloader built-in, so hopefully we will be able to just use stm32flash and an USB2TTL adapter to program it.

There is a nice dev environment template for this family of microcontrollers: https://github.com/szczys/stm32f0-discovery-basic-template

  • Reprogramming Without Soldering

    Radomir Dopieralski04/21/2017 at 18:10 0 comments

    Turns out that the procedure in the previous log can be greatly simplified. You don't need an ST-Link programmer, and you don't need to solder anything. Even if your shield is locked, you can unlock and program it with a simple serial adapter. Here is how.

    First, clone the repository:

    $ git clone https://github.com/pbugalski/wemos_motor_shield
    $ cd wemos_motor_shield

    Make sure you have arm-none-eabi-gcc installed, and compile it:

    $ make
    arm-none-eabi-gcc -Wall -g -std=c99 -Os -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,-Map=motor_shield.map -Iinc src/startup_stm32.s src/main.c src/user_i2c.c src/tb6612.c -o motor_shield.elf -Tstm32f030.ld
    arm-none-eabi-objcopy -O binary motor_shield.elf motor_shield.bin
    arm-none-eabi-size motor_shield.elf
       text	   data	    bss	    dec	    hex	filename
       2032	   1084	   1056	   4172	   104c	motor_shield.elf
    

    Now, make sure you have stm32flash utility installed. Short the RTS and the 3V pins on the shield together, like this:

    And the connect the main pins of the shield to your USB2TTL as follows:

    GND ↔ GND

    3V3 ↔ 3V3 (or VCC or whatever it is called on your USB2TTL)

    D2 ↔ TX

    D1 ↔ RX

    and connect it to your computer. Now, see if you can communicate with the device:

    $ stm32flash /dev/ttyUSB0
    stm32flash 0.5
    
    http://stm32flash.sourceforge.net/
    
    Interface serial_posix: 57600 8E1
    Version      : 0x31
    Option 1     : 0x00
    Option 2     : 0x00
    Device ID    : 0x0444 (STM32F03xx4/6)
    - RAM        : 4KiB  (2048b reserved by bootloader)
    - Flash      : 32KiB (size first sector: 4x1024)
    - Option RAM : 16b
    - System RAM : 3KiB

    Now, you can unlock your shield:

    $ stm32flash /dev/ttyUSB0 -k
    stm32flash 0.5
    
    http://stm32flash.sourceforge.net/
    
    Interface serial_posix: 57600 8E1
    Version      : 0x31
    Option 1     : 0x00
    Option 2     : 0x00
    Device ID    : 0x0444 (STM32F03xx4/6)
    - RAM        : 4KiB  (2048b reserved by bootloader)
    - Flash      : 32KiB (size first sector: 4x1024)
    - Option RAM : 16b
    - System RAM : 3KiB
    Read-UnProtecting flash
    Done.
    
    $ stm32flash /dev/ttyUSB0 -u
    stm32flash 0.5
    
    http://stm32flash.sourceforge.net/
    
    Interface serial_posix: 57600 8E1
    Version      : 0x31
    Option 1     : 0x00
    Option 2     : 0x00
    Device ID    : 0x0444 (STM32F03xx4/6)
    - RAM        : 4KiB  (2048b reserved by bootloader)
    - Flash      : 32KiB (size first sector: 4x1024)
    - Option RAM : 16b
    - System RAM : 3KiB
    Write-unprotecting flash
    Done.
    
    And now you can flash it:
    $ stm32flash /dev/ttyUSB0 -v -w motor_shield.bin
    stm32flash 0.5
    
    http://stm32flash.sourceforge.net/
    
    Using Parser : Raw BINARY
    Interface serial_posix: 57600 8E1
    Version      : 0x31
    Option 1     : 0x00
    Option 2     : 0x00
    Device ID    : 0x0444 (STM32F03xx4/6)
    - RAM        : 4KiB  (2048b reserved by bootloader)
    - Flash      : 32KiB (size first sector: 4x1024)
    - Option RAM : 16b
    - System RAM : 3KiB
    Write to memory
    Erasing memory
    Wrote and verified address 0x08000c2c (100.00%) Done.
    

    Then disconnect all the wires (including the RTS pin), connect the shield to your WeMos D1 Mini, and it should work.

  • We Have a Fixed Firmware!

    Radomir Dopieralski04/21/2017 at 17:21 0 comments

    @Piotr Bugalski has recently re-written the firmware for this motor shield, and published it at https://github.com/pbugalski/wemos_motor_shield. From what I can tell, the new firmware is compatible with the old one, minus the hanging and crashing, so it should be perfect for a drop-in replacement.

    Here is how you can flash it to your shield:

    Solder two wires to the first two legs of the microcontroller, counting from the top, like this:

    Be careful to not short them with the legs next to them. This is probably the hardest part.

    Next, connect you ST-Link programmer as follows:

    SWCLK ↔ first wire

    SWDIO ↔ second wire

    GND ↔ GND

    3V3 ↔ 3V3

    T_JRST ↔ RST

    Note that, this is with the shiled *not* connected to the D1 Mini.

    Now, clone the repository:

    $ git clone https://github.com/pbugalski/wemos_motor_shield
    $ cd wemos_motor_shield

    Make sure you have installed openocd and arm-none-eabi-gcc. Compile the firmware:

    $ make
    arm-none-eabi-gcc -Wall -g -std=c99 -Os -mlittle-endian -mcpu=cortex-m0 -march=armv6-m -mthumb -ffunction-sections -fdata-sections -Wl,--gc-sections -Wl,-Map=motor_shield.map -Iinc src/startup_stm32.s src/main.c src/user_i2c.c src/tb6612.c -o motor_shield.elf -Tstm32f030.ld
    arm-none-eabi-objcopy -O binary motor_shield.elf motor_shield.bin
    arm-none-eabi-size motor_shield.elf
       text	   data	    bss	    dec	    hex	filename
       2032	   1084	   1056	   4172	   104c	motor_shield.elf
    

    And flash it onto the shield:

    $ make program
    openocd -f stm32f0motor.cfg -f stm32f0-openocd.cfg -c "stm_flash motor_shield.bin" -c shutdown
    Open On-Chip Debugger 0.9.0 (2015-09-02-10:42)
    Licensed under GNU GPL v2
    For bug reports, read
    	http://openocd.org/doc/doxygen/bugs.html
    Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
    adapter speed: 1000 kHz
    adapter_nsrst_delay: 100
    none separate
    srst_only separate srst_nogate srst_open_drain connect_deassert_srst
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : clock speed 950 kHz
    Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
    Info : using stlink api v2
    Info : Target voltage: 3.490340
    Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
    stm_erase
    target state: halted
    target halted due to debug-request, current mode: Thread 
    xPSR: 0xc1000000 pc: 0xfffffffe msp: 0xfffffffc
    auto erase enabled
    Info : device id = 0x10006444
    Info : flash size = 16kbytes
    target state: halted
    target halted due to breakpoint, current mode: Thread 
    xPSR: 0x61000000 pc: 0x2000003a msp: 0xfffffffc
    wrote 4096 bytes from file motor_shield.bin in 0.287988s (13.889 KiB/s)
    target state: halted
    target halted due to breakpoint, current mode: Thread 
    xPSR: 0x61000000 pc: 0x2000002e msp: 0xfffffffc
    verified 3116 bytes in 0.057512s (52.910 KiB/s)
    shutdown command invoked
    
    Now, disconnect everything. Your board has the new firmware on it. You can test it, and then desolder the two wires -- you won't be needing them anymore.

  • SWD Programming Continued

    Radomir Dopieralski11/22/2016 at 20:59 1 comment

    On a quest to configure OpenOCD properly. First of all, the error I'm getting was described in an issue and seems like adding "reset_config none separate" fixes that. I got a new error with this:

    openocd -f extra/fff.cfg -f extra/stm32f0-openocd.cfg -c "stm_flash `pwd`/main.bin" -c shutdown
    Open On-Chip Debugger 0.9.0 (2015-09-02-10:42)
    Licensed under GNU GPL v2
    For bug reports, read
    	http://openocd.org/doc/doxygen/bugs.html
    Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
    adapter speed: 1000 kHz
    adapter_nsrst_delay: 100
    none separate
    srst_only separate srst_nogate srst_open_drain connect_deassert_srst
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : clock speed 950 kHz
    Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
    Info : using stlink api v2
    Info : Target voltage: 3.504912
    Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
    none separate
    stm_erase
    target state: halted
    target halted due to debug-request, current mode: Handler HardFault
    xPSR: 0xc1000003 pc: 0xfffffffe msp: 0xfffffffc
    auto erase enabled
    Info : device id = 0x10006444
    Info : flash size = 16kbytes
    Error: stm32x device protected
    Error: failed erasing sectors 0 to 0
    OK, so apparently the chip is write-protected. No problem, we can unlock it with "stm32x unlock 0". After running that, and resetting the chip, I finally got:
    openocd -f extra/fff.cfg -f extra/stm32f0-openocd.cfg -c "stm_flash `pwd`/main.bin" -c shutdown
    Open On-Chip Debugger 0.9.0 (2015-09-02-10:42)
    Licensed under GNU GPL v2
    For bug reports, read
    	http://openocd.org/doc/doxygen/bugs.html
    Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
    adapter speed: 1000 kHz
    adapter_nsrst_delay: 100
    none separate
    srst_only separate srst_nogate srst_open_drain connect_deassert_srst
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : clock speed 950 kHz
    Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
    Info : using stlink api v2
    Info : Target voltage: 3.506483
    Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
    none separate
    stm_erase
    target state: halted
    target halted due to debug-request, current mode: Thread 
    xPSR: 0xc1000000 pc: 0xfffffffe msp: 0xfffffffc
    auto erase enabled
    Info : device id = 0x10006444
    Info : flash size = 16kbytes
    target state: halted
    target halted due to breakpoint, current mode: Thread 
    xPSR: 0x61000000 pc: 0x2000003a msp: 0xfffffffc
    wrote 1024 bytes from file /home/sheep/dev/3rdparty/stm32f0-discovery-basic-template/main.bin in 0.104813s (9.541 KiB/s)
    target state: halted
    target halted due to breakpoint, current mode: Thread 
    xPSR: 0x61000000 pc: 0x2000002e msp: 0xfffffffc
    verified 980 bytes in 0.030723s (31.150 KiB/s)
    shutdown command invoked
    

    Which seems to be a correct flashing.

    All this thanks to advice from @jaromir.sukuba, great thanks!

    Now let's see if I can get a blink example to work...

  • SWD Programming

    Radomir Dopieralski11/22/2016 at 20:06 0 comments

    Second approach to this is using the SWD protocol with my Chinese ST-Link V2 clone. That requires getting at the SWD pins. Fortunately, they are near the edge of the chip:

    Then I connected it according to the pinout of my programmer (the second one):

    Now just "make program" in that template, and...

    openocd -f /usr/share/openocd/scripts/board/stm32f0discovery.cfg -f extra/stm32f0-openocd.cfg -c "stm_flash `pwd`/main.bin" -c shutdown
    Open On-Chip Debugger 0.9.0 (2015-09-02-10:42)
    Licensed under GNU GPL v2
    For bug reports, read
    	http://openocd.org/doc/doxygen/bugs.html
    Info : The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD
    adapter speed: 1000 kHz
    adapter_nsrst_delay: 100
    none separate
    srst_only separate srst_nogate srst_open_drain connect_deassert_srst
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : Unable to match requested speed 1000 kHz, using 950 kHz
    Info : clock speed 950 kHz
    Info : STLINK v2 JTAG v17 API v2 SWIM v4 VID 0x0483 PID 0x3748
    Info : using stlink api v2
    Info : Target voltage: 3.497322
    Info : stm32f0x.cpu: hardware has 4 breakpoints, 2 watchpoints
    stm_erase
    Error: timed out while waiting for target halted
    TARGET: stm32f0x.cpu - Not halted
    in procedure 'stm_flash' 
    in procedure 'reset' called at file "extra/stm32f0-openocd.cfg", line 8
    in procedure 'ocd_bouncer'
    
    
    Makefile:72: recipe for target 'program' failed
    make: *** [program] Error 1
    

    Failure.

    I suspect that I shouldn't be using the configuration for the discovery board, but somehow write my own, however, I can't seem to be able to find any examples...

  • Serial Programming

    Radomir Dopieralski11/21/2016 at 10:12 1 comment

    Last evening I made the first try at programming this thing. From the datasheet and the schematic it looks straightforward: the BOOT0 pin is connected to the RTC pin of the serial, the NRST pin is connected to DTR, it should just work. So I connected the USB2TTL (also a WeMos one), and gave it a go:

    $ stm32flash /dev/ttyUSB0
    stm32flash 0.5
    
    http://stm32flash.sourceforge.net/
    
    Interface serial_posix: 57600 8E1
    Failed to init device.

    No joy. To the datasheet then! Hmm, they mention a BOOT1 there too, but it's nowhere to be seen as a pin... Let's google for it... http://stackoverflow.com/questions/22351703/stm32f030-and-boot0-pin Ah-ha! It looks like BOOT1 is a flag in something called "user flash option byte", and it has to be set to 0 for the bootloader to start. Shame I have no way to check it.

    If that flag is set to 1 in this firmware, then the only way to reprogram this board is to use an stlink programmer. Fortunately, I do have one! Unfortunately, the SWD and SWC pins are not broken out, so I guess I will need to do some precision soldering directly to the chip's legs. Oh well.

View all 5 project logs

Enjoy this project?

Share

Discussions

Piotr Bugalski wrote 04/18/2017 at 19:32 point

I have an early prototype of new firmware. Original code was never working on my board so I can't really compare the results, but I hope new code is at least not worse than the previous one. You can find my code at: https://github.com/pbugalski/wemos_motor_shield. I2C address selection is not implemented yet and the code is very messy (to fit original style), but hopefully it works as expected. If anyone wants to volunteer some testing I'd be very obligated.

  Are you sure? yes | no

Dzandaa wrote 01/25/2017 at 14:57 point

Is it possible to re-flash the Wemos MotorShield with Keil UVision and the Motor_Shield_Firmware without modifying the board.

what do I need to flash it? (I have USB to ST-LINK and also USB to TTL) how do I connect it to Motor Shield Pins?

Thank you.

  Are you sure? yes | no

Elliot Williams wrote 11/28/2016 at 22:16 point

Following on K.C. and Radomir's ideas to get extra pins: 

0) The SWD/SWCLK pins are wired to headers A0, D0.  (Why not?)

1) PA2 is jumpered across to H_STDBY (bottom left pin)

2) The I2C address select pins (AD0/PF0, AD1/PF1) are broken out to D5, D6

Et voila!  Three working GPIOs, while chip can still talk I2C or UART on TX/RX depending on firmware.

Dodgy soldering all around, though.  Wouldn't want to do this too many times.


  Are you sure? yes | no

Elliot Williams wrote 11/27/2016 at 12:51 point

This is a great idea!  The WeMos stuff is incredibly cheap and makes a great basis for experimentation.  

I picked one of these modules up, and then had a look at the schematic afterwards (which is probably the wrong order).  I expected more of the STM's GPIOs to be broken out, rather than just sitting there on the chip.  Oh well!

I green-wired the SWC/SWD pins just like you did, only I connected them to two of the unused header pins which makes programming connections solid.  I prefer stlink for programming, but as you noted the chip seems to be write protected from the manufacturer. (And stlink has no provisions for reading/setting those bits.) 

After connecting with OpenOCD, I got the chip unlocked ("stm32f1x unlock 0") but couldn't manage to flash it -- probably something wrong with my OOCD configurations somewhere.  But once the lock bit is set right, it's programmable with anything over SWD, just like usual, so I didn't bother anymore.  If/when I need serious debugging, maybe I'll revisit it.    For now, st-flash and my trusty nucleo-board programmer do the trick.

FWIW, the mecrisp-stellaris STM32F030 version flashes right in and I connect over the serial lines which are the same pins as the default I2C.  I also got an LED blinking on PA9/SCL/D1, one of the only pins that's broken out.

I had thought of using the board as the standalone brains of a small wheeled bot/toy, but with only two GPIOs broken out, and the tight clearances on the pins, I'm actually loathe to push this much further.  

I think your strategy of using it as an improved version of what it alread is (I2C smart motor driver) is the sane way to go.  I _do_ wonder if closing the control loop is worth green-wiring a couple more pins out to the header, though...

Anyway, cool stuff.  I'll be following along.  Thanks!

  Are you sure? yes | no

Radomir Dopieralski wrote 11/27/2016 at 13:00 point

I noticed you can get one more pin broken out if you short the jumper on the bottom (short both of its gaps) -- then you have the "standby" pin available. I was trying to get that pin to blink, but no luck so far -- I'm new to STM32 programming and didn't get my head around the gpio registers yet.

It's a shame that they are using the same pins for i2c as for the serial -- otherwise you would get two extra pins.

  Are you sure? yes | no

Elliot Williams wrote 11/28/2016 at 14:34 point

Getting I/O up on a bare STM32 is fun.  


Enable the clock domain for the whole GPIO port, set the data direction, ignore the slew rate stuff for now, and write to it -- I like the set/reset registers.  


Depending on the chip, that means all sorts of strange bit-shifting (some configs have 2 bits per pin).  I'm sure I'm still forgetting something, and if I remember right the M0s are different from the M4s, etc.


Frankly, having done both read-the-datasheet-and-tweak-register-bits and use-the-peripheral-library, I don't know which is more confusing.  There's a lot more internet code to crib if you use the SPL, that's for sure.  


Good call on the standby pin.  I'll give that a try and send you the code if it works.  Going from zero free GPIOs to one is a step in the right direction!

  Are you sure? yes | no

K.C. Lee wrote 11/28/2016 at 15:00 point

I have done bare metal on the STM32F030 using nothing but the RM (reference manual).  It is a lot less work as I have to read the RM figuring out their "library".  Software people in general do not document as well as the RM.

If you are just targeting a single uC, that's a much clearer way of coding.  If you are going to port the same I/O code to a different STM32 series, then the library might save you some time.  I would still prefer to write mine bare metal.

  Are you sure? yes | no

Elliot Williams wrote 11/28/2016 at 17:09 point

@K.C. Lee: Yeah, me too, but...

For instance, the STMF4 series have a silicon bug in the SPI hardware, and the workaround is well-documented in an errata white paper, but still it's a PITA to work through the three different special cases, turning on and off interrupts after this byte and before that one.  It's much easier just to use their SPI libs which hide the uglies for you.

(Not that I practice what I preach.  Nope, I wasted an entire afternoon chasing down all the edge cases.)

But I totally agree that you've got to read through the datasheet one day anyway, so you might as well do it early on.  Knowing what all the hardware does and how it does it is tremendously empowering, IMO.  Much more than looking through header files at layers of abstractions on abstractions.  And _much_ better documented.

  Are you sure? yes | no

K.C. Lee wrote 11/28/2016 at 18:37 point

BTW if you add a series resistor (e.g. 10K) to AD0/AD1 which are used as jumpers for I2C address.  Once the uC figure the I2C address, you can , you could use those pins as output pins for non-critical stuff e.g. LED that won't notice a few us of glitches.

You could abuse the I2C pins for serial during I2C "Idle" as long as you don't trigger an I2C "Start" condition.  I2C slaves ignores traffic on the bus until they see a "Start".  This would only work when the board is the only master on the bus and not a slave.

- You can the TX for output only serial communication (e.g. LCD that runs on serial).  As long as you keep RX high, then traffic on TX is okay.   

- If you keep TX low, then you can receive data on RX.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates