The Bus Pirate & my High-2-Sea Adventure.. Arrrrrrr !

This past week I’ve been busy hacking on an Arduino project that uses the I2C bus. It’s been ages since I’d used the Wire library so I was more than a little rusty. Thankfully when it came time to test the code I’d written I could reach into my test equipment box and yank out my Bus Pirate. I’ve been saving up that post title for a while now.

Looking in the test equipment box I noticed at some point in the past I’d purchased one of the SeeedStudio v4 bus pirates which I’d forgotten about. Until now I’d typically used the Sparkfun v3.6 design. Hmm don’t remember when I purchased the new unit, must be old age.. Anyway seemed like a good time to take the plunge with the updated unit.

This new Arduino project monitors the voltage and current in a few external supply rails. Which can then be read by another device over the I2C. I’m sure at some point you’ll find the project code sitting in a public repository along with some hardware files as I complete and test a bit more of the project.

The bus pirates are great if you need to drive and interact with I2C devices. It implements a very simple macro style interface which means you can also edge case test and send out of order I2C signals to make sure your code is working.

So the first surprise with the new v4 unit was when I plugged it into my Windows 7 Dev machine, it needed a driver. I found it here here in the bus pirate archive (click), it actually wasn’t that easy to find. Once I’d updated the “driver” Win 7 it then did its usual thing and turned into a Serial Port.

Connecting to the Bus Pirate with PuTTY is relatively straight forward once you’ve found the serial port number, serial speed is 115200. It was then time to connect the wires. Dangerous Prototypes have a great page on how to do this, you can find it here (click). In a nutshell on my v4 board MOSI connected to SDA, CLK to SCK and GND to GND. Now back to the console. Firstly we need to get the Bus Pirate into I2C mode, so I used the following commands;

HiZ>m
1. HiZ
2. 1-WIRE
3. I2C
4. SPI
5. 2WIRE
6. 3WIRE
7. LCD
8. DIO
x. exit(without change)
(1)>3

I2C mode:
 1. Software
 2. Hardware
(1)>1

Set speed:
 1. ~5KHz
 2. ~50KHz
 3. ~100KHz
 4. ~400KHz
(1)>2
Ready
I2C>

As you will see I decided to select I2C software mode and a speed of 50kHz to start with. So now we need to turn on the power supplies and turn on the pull-up resistors to talk to the Arduino.

I2C>W
Power supplies ON
I2C>P
Pull-up resistors ON
Warning: no voltage on Vpullup pin
I2C>

Umm… hold the boat ! What’s happened to the pull-ups? That one threw me for a bit, I don’t remember the Sparkfun v3.6 units doing this.

Well if you’ve only skim read the Dangerous Prototypes v4 page like I had you would have missed you need to connect the Vpu pin to one of the internal supplies, so in my case I used another wire to short Vpu to the 3V3 pin, conveniently they were adjacent to each other.

If you look closely you can see a yellow wire in the top right of the image above, that joins Vpu to 3V3 and is the secret sauce to making this work. Ok so now that’s solved I could then try to get the power supplies and pull-ups working again;

I2C>W
Power supplies ON
I2C>P
Pull-up resistors ON
I2C>

From here it was straight forward to the rest of the testing. Another good tid bit is the following macro is great for checking things work as expected, essentially it scans the bus and will report all of the devices it can talk to;

I2C>(1)
Searching I2C address space. Found devices at:
0x40(0x20 W) 0x41(0x20 R)
I2C>

Sweet. The Bus Pirate found my device and tells me I can read and write to it. More importantly I know what address to use, sometimes things get a little screwy due to the 7-bit I2C address and the read-write bit. Dangerous Prototypes have a good guide that allow you to work out what macros you need to use to build your I2C commands (click).

Here’s an example of me reading a single register from a specific address from within my Arduino I2C firmware;

I2C>[0x40 0x50[0x41 r]
I2C START BIT
WRITE: 0x40 ACK
WRITE: 0x50 ACK
I2C START BIT
WRITE: 0x41 ACK
READ: 0x08
NACK
I2C STOP BIT
I2C>

So the macro above can be read from left to right and in words;

  • send a start condition
  • the write address (0x40)
  • a data byte (0x50)
  • a second start condition
  • the read address (0x41)
  • read byte
  • stop condition

.The bus pirate then prints that it READ a value of 0x08 from that register. Actually that value tells me there are 8 bytes in that register strucutre, so I can modify my macro and read the entire contents;

I2C>[0x40 0x50[0x41 r:8]
I2C START BIT
WRITE: 0x40 ACK
WRITE: 0x50 ACK
I2C START BIT
WRITE: 0x41 ACK
READ: 0x08 ACK 0x20 ACK 0x1C ACK 0x00 ACK 0x00 ACK 0x98 ACK 0x3A ACK 0x00                       NACK
I2C STOP BIT
I2C>

You’ll see that the last part of the above macro is now set to read 8 bytes and you can see the response from the unit appears to have data in it. The nice thing with an Arduino is you can have it print out messages on it’s serial port and then check the responses match, so I’m gong to call that working !

Now all I need to do is write a script that can then test all of the I2C edge cases to ensure my code really works and I’ll be able to move on to a more interesting part of the project.

Maple Mini’s & a STM32F103CBT6

I recently found myself at the very limits of what you can ask an Arduino Uno to do, both in terms of flash and speed. I’ve used Atmel AVR processors for nearly 20 years so I know them and their foibles very well.

At work a while back we started using various STM32 processors and that has been somewhat enjoyable, I now like throwing floats around instead of having to resort to fixed point maths and excel for algorithm development. I’d heard that you could run up the Arduino framework on the STM32 platforms so was keen to try it.

So I initially went looking for a well supported board and simply struggled to find one. It seemed that this space had come and gone rather rapidly. Further research showed why, the Chinese clones has effectively decimated this market due to price. I was still keen to give it ago so placed an order for two Maple Mini boards with the STM32F103CBT6 processors on them off eBay for the princely sum of A$20 with free freight. Little wonder everyone abandoned ship in mid 2016.

A big thanks has to go to Leaflabs since they have left all of the circuits, boot-loaders & design files in a GitHub repository here (click).

So what did we have to do to get these working ? It wasn’t as trivial as the Arduino Uno that is for certain.

The first step was to get Windows 7 drivers (yes I know it runs out next year) for the Maple Mini, I found some here (click). I basically hit the green button marked “Clone or Download”, saved the file on my local machine. Extracted the files from the archive to a temp directory, then via the System Manager clicked on the “Maple 003” device that appears, told it I wanted to update the drivers from a specific location then pointed it at the temp directory I’d stored the files in previously. It figured it out and installed the ones I needed. What I found amusing is it then appeared under a category called “Atmel Devices” since I’d installed tools based on libdfu for these devices once upon a time ago. YMMV.

Once I had drivers installed I could then fire up PlatformIO in the VSCode editor and attempt to create a new project. I selected the board type “Maple Mini Original” and “Arduino” for the platform and let it do its business. Unfortunately the processor I have and the one on the original maple mini are different, so I had to change a few things in the platformio.ini file; my config is below. This config is based on a PlatformIO blog post written by Vortex314, can’t thank them enough for sharing this information (click).

[env:maple_mini_origin]
platform = ststm32
board = maple_mini_origin
framework = arduino
board_build.mcu = stm32f103cbt6
board_build.f_cpu = 72000000L
build_flags = 
    -D USBD_USE_CDC
    -D PIO_FRAMEWORK_ARDUINO_ENABLE_CDC
    -D PIO_FRAMEWORK_ARDUINO_USB_FULLMODE
    -D USBCON
    -D USBD_VID=0x0483
    -D USB_MANUFACTURER="Unknown"
    -D USB_PRODUCT="\"BLUEPILL_F103C8\""
    -D HAL_PCD_MODULE_ENABLED

So what is so special? Firstly there are separate board_build definitions to set the processor and speed for the board. Thankfully the cores between the original board and my Chinese clone are similar enough for this to work. Secondly there’s a heap of additional build flags that will build in a USB serial port. So if you’re used to the USB serial to debug your code this will still work. You can find out a little more about why this is necessary on Roger Clark’s website here (click).

It is interesting that the boot-loader contains only DFU code and that the application needs to have the USB serial built in separately. In the above configuration you may notice that the VID is 0x0483 which is by design, this means the Communications Device Class (CDC) will trigger the ST Serial drivers on a Windows installation if you have them installed. If you don’t you can find them here (click).

So from within the PlatformIO environment we can write our code and build for our target. Here’s my very simple test program that flashes the onboard LED (pin 33) and will send some test data to the USB serial port.

#include <Arduino.h>

void setup() 
{
  // put your setup code here, to run once:
  pinMode( 33, OUTPUT );
  Serial.begin(115200);
  
}

void loop() 
{
  static int i = 0;
  
  // put your main code here, to run repeatedly:
  digitalWrite( 33, HIGH );
  delay(500);
  digitalWrite( 33, LOW );
  delay(500);

  Serial.print("Test #");
  Serial.println(i++,DEC);
}

So the last comment I need to make is in the programming of the device. When you hit the upload button from within PlatformIO you’ll see OpenOCD start and then pause with the comment “Searching for DFU device [LEAF:0003]” and if you wait long enough a subsequent message flashes by reading “Couldn’t find the DFU device: [LEAD:0003]” and nothing appears to happen.

Initially I thought my board was dead when it dawned on me… The Arduino uses a separate ATmega8U2 that is capable of resetting the target ATMega328 under software control, the STM32F103Cx is using the internal USB port and does not have this reset function (*face palm*). So when we start the program cycle we need to wait for the “Searching for DFU device” to appear and then manually reset our target to force the boot-loader into DFU mode momentarily where it is then caught and updated. Once done the process carries on as expected and you find you haven’t bricked your device.

Happy programming !