STM32 Hardware Development

Serial/UART Firmware Upload
A second firmware upload method is to use serial (UART) upload, which works in much the same way as the standard way of uploading code to an Arduino. Like in the case of the Arduino serial upload this approach relies on a pre-uploaded bootloader. My understanding is that the Nucleo boards already have this bootloader in place.

UART to Nucleo connections

  • Connect GND and 5V for power.
  • Place a jumper between BOOT0 and VDD to select the serial upload mode.
  • Connect PA9 to UART RX
  • Connect PA10 to UART TX
  • Power cycle to reset board and enter serial upload mode

Serial Uploader Tool

On Windows ST provide a tool for uploading firmware over serial called STM32-Flasher: FLASHER-STM32 - STM32 Flash loader demonstrator (UM0462) (replaced by STM32CubeProgrammer) - STMicroelectronics

For Linux there is a neat command line tool called stm32flash available in the package manager: Ubuntu Manpage: stm32flash - flashing utility for STM32 through UART or I2C

It can be installed with the following apt-get install:

sudo apt-get install stm32flash

I compiled the Arduino example Blink for the Nucleo64 STM32F303 using the Arduino IDE and then fetched the compliled .bin file from the /tmp folder that Arduino creates.

I could then upload to the STM32F303 by running:

sudo stm32flash -w blink.ino.bin /dev/ttyUSB0 -b 115200

Terminal output:

$ sudo stm32flash -w Blink.ino.bin /dev/ttyUSB0 -b 115200
stm32flash 0.5

http://stm32flash.sourceforge.net/

Using Parser : Raw BINARY
Interface serial_posix: 115200 8E1
Version      : 0x31
Option 1     : 0x00
Option 2     : 0x00
Device ID    : 0x0446 (STM32F302xD(E)/F303xD(E)/F398xx)
- RAM        : 64KiB  (6144b reserved by bootloader)
- Flash      : 512KiB (size first sector: 2x2048)
- Option RAM : 16b
- System RAM : 8KiB
Write to memory
Erasing memory
Wrote address 0x08002c5c (100.00%) Done.

If you are using the emonTxShield you can easily forgo all the link wires and use the serialusb programmer directly on the 6way header (see STM32 Development - #207 by pb66) by not populating the 5v pin and linking the 5v and 3.3v tracks on the shield. You also need to change a couple of links on the STM32 to access the uart via the Arduino headers, I can’t recall which now as it was a while back I did this, but it is documented in the nucleo user manual.

The blue user button can also be plumbed into the boot0 pin to replace the manipulation of a boot0 link wire with a button press.

A better option still is to use the GPIO of a Pi much like updating a rfm2pi (or emonpi) as then you can connect the boot0 to another GPIO pin and upload totally “handsfree”.

It is also possible to use the Pi GPIO to simulate an STlink and use the swd/jtag method without a STLink v2 but that’s more complex to set up and uses OpenOCD rather than the much simpler stm32flash.

Although ultimately I think it would be good to look at in-application programming for installing FW updates (not to be confused with communicating with the device for configuration, calibrating and debugging).

Thanks Paul, does upload work on UART2? RX and TX for the emontx shield are connected to D0, D1 on the arduino headers or PA3,PA2 on CN10 which are UART2 or did you have to do something else to configure?

My last challenge for the day was to test USB DFU upload, but I’ve been unable to get it to work so far, using the circuit in Ken Boak’s ARMiGo design.

Dmesg gives me the following:

[29399.151534] usb 3-2: new full-speed USB device number 95 using xhci_hcd
[29399.263613] usb 3-2: device descriptor read/64, error -71
[29399.479552] usb 3-2: device descriptor read/64, error -71
[29399.695559] usb 3-2: new full-speed USB device number 96 using xhci_hcd
[29399.807601] usb 3-2: device descriptor read/64, error -71
[29400.023537] usb 3-2: device descriptor read/64, error -71
[29400.239589] usb 3-2: new full-speed USB device number 97 using xhci_hcd
[29400.239772] usb 3-2: Device not responding to setup address.
[29400.443753] usb 3-2: Device not responding to setup address.
[29400.647576] usb 3-2: device not accepting address 97, error -71
[29400.759615] usb 3-2: new full-speed USB device number 98 using xhci_hcd
[29400.759803] usb 3-2: Device not responding to setup address.
[29400.963875] usb 3-2: Device not responding to setup address.
[29401.167584] usb 3-2: device not accepting address 98, error -71
[29401.167694] usb usb3-port2: unable to enumerate USB device

I note the existance of dfu-util on Ubuntu for eventually carrying out the upload but its not listing any DFU compatible devices yet and I see the errors above in dmesg… One for another day I think :slight_smile:

I’m sorry I’m a bit hazy on the detail, it was all new to me then and I’ve not looked at it since.

From what I recall I did (eventually) get it to upload via usart2 (but could be mistaken), I do know that I went through a lot of different set ups to get there.

I do not think DFU upload is possible with the existing bootloader. If you look at st doc AN2606, the default bootloader for the F303 allows upload via usart1 usart2 or I²C, I think you would at least need to replace the bootloader to use DFU (if it’s possible at all), however I believe, if the IAP method was used, the replacement FW could be “uploaded” via USB then booted via the original bootloader, if i understood the IAP implementation correctly, I didn’t get as far as trying out any of the IAP stuff at all.

[edit] Seems I’ve been looking at the wrong section in the an2606 doc, section 19 is the right one and that suggests the default bootloader WILL use DFU.

Are you using a pull-up on PA12? Also are you powering via USB or a separate PSU?
(See stm32 - Activating DFU (USB programming) on STM32F303 - Stack Overflow)

Thanks Paul, that stackoverflow thread looks like a good lead, I was testing with power from the USB, I will test later! :slight_smile:

A little more progress this morning. I find it useful to start building a schematic and board layout as I learn new hardware so I thought I would put together the basics of an STM32 design. I’ve selected the STM32F303 64pin for now as a starting point - Im aware were still discussing which model to eventually go with and whether to select the 100pin or 144pin variants.

The design so far:

  • STM32F303RET 64pin
  • 5V to 3V3 Voltage regulator MCP1825 500mA (enough for an ESP8266 I think)
  • Decoupling capacitors on supply inputs as in AN4206 best practice guidelines.
  • Oscillator
  • ST Link Header
  • UART Header
  • USB DFU (needs testing as above)
  • Battery holder footprint for RTC?
  • Jumper for BOOT0

Download schematic and board file: stm32hw01.zip (44.8 KB)

I’ve noted a number of ongoing questions I have on the schematic, they are:

  1. VREG Datasheet suggests minimum 1uF Output Capacitor, STM32 Hardware Guide suggests 4.7uF on VDD and 1uF on VDDA. Should I add all three in locations close to the respective components or is a 4.7uF capacitor near the voltage regulator sufficient.
  2. Which oscillator frequency do we choose?
  3. I’ve used a couple of solder jumpers for the RTC Battery / 3V3 supply selector, would a 3pin throughhole header be better (not likely a configuration that will change regularly in a design - solder jumper should be fine and keeps things compact).
  4. ST-Link connector pin out I copied from Ken’s ARMiGO design, the order is different from the SWD connector on the ST-LINK board, is there a standard to adhere too?
  5. Should UART reset connect to NRST somehow? BOOT0 needs to be pulled high and board reset for serial upload to work, inserting a jumper and power cycling the board worked fine in testing above, is there value in automating this step?
  6. USB DFU needs testing, Nucleo reference design has a transistor and 3 resistors connecting the 1k5 pull up to USB_RENUm, The ARMiGO design does not have this, is it needed? Same goes for the 22pF capacitors.

My next steps will be to test the USB DFU again following your suggestions @pb66 and learn more about the onboard op-amps to provide a buffered bias level for the CT and ACAC signals…

No further luck @pb66 testing the DFU upload with a secondary supply, I think I will move on for now but I did note in AN2606:

The hardware required to put the STM32F30xxx devices into System memory boot mode
consists of any circuitry, switch or jumper, capable of holding the BOOT0 pin high while
nBOOT1 bit in the option bytes (starting at address 0x1FFFF800) is set to value 1. The
setting of this bit can be done through the STLINK utility or an equivalent tool.

I wonder if this is the missing step…
(I have the 1.5k pull up on PA12 in place and 100k pull down on ID)

Trying a basic follower with Opamp1 following the reference manual RM0316 but no luck so far, any ideas @dBC @pb66?.

Configured the opamp in STM32CubeMX as follows, generated the code, ran make and uploaded the firmware.

Wired up PA1 to a 2x 470k voltage divider to give 1.6v mid rail, Measuring the output with a multimeter, VOUT is ~0V…

Edit: getting the same with opamp2 on PA6 & PA7

The general HAL model is that you configure the subsystem in the GUI and it generates all the initialisation code for you, but leaves you to determine exactly when to turn the feature on (or start the ADC running or whatever).

I’ve not played with the OPAMPs but if you have a look at the HAL manual (UM1786) you’ll see you need to call HAL_OPAMP_Start() so it follows a very similar model as all the other subsystems. The GUI never generates the HAL_xxx_Start() call, but leaves you to decide when/where to do that. HAL_OPAMP_SelfCalibrate() looks pretty useful too, for removing offsets.

I’m hoping that R choice is solely for lab experiments to compare and contrast the stability of the input and output ;-). I know you didn’t have much choice with the emonTx stuff due to the desire to run it from batteries, but I’m constantly coming unstuck on that with the emonTxShield you sent me. Every time I probe up a signal with the scope it sags from under me with just the 1M scope probe load. I’m assuming battery operation is not under consideration for this one?

I’m guessing you lost your console printfs though right? I think you also need to jumper rx and tx between the two boards to maintain that.

One slight nit-pick: that breakaway strip at the top of the Nucleo board is actually an ST-LINK/V2-1 programmer (not an ST-LINK/V2 as reported). TN1235 lists the features of all the different versions (and Virtual-COM-port interface on USB is something you can do on V2-1 but not V2).

G’morning T :sunglasses:

Looking at the eagle files, I’d go for 4.7uF MLCC type caps at the input and output of the reg to cover all bases. Theoretically, there’s no need to add cap values together, just have the highest required value (4.7uF) available.
MLCC caps have very low impedance and also function as the 100nF caps at the appropriate input/outputs. The combined electrolytic / ceramic dual cap approach can be done in a single MLCC of the higher uF value. But looking at the board, the only change I’d make is change the reg’s 1uF for a 4.7uF and that should be fine for the STM also.
The guide’s recommendation for 4.7uF and 1uF caps at both VDD and VDDA is probably to do with the possibility of a dedicated analog supply, maybe even a precision supply, which might be worth considering as part of producing a very accurate device without calibration!
The separate precision VDDA supply would be very useful if the main 3.3V supply is also going to be used for powering radio modules.
EDIT: I notice the VREF+ available for connecting the high side of a precision reference. VREF+ and VDDA can be connected together according to this.

https://octopart.com/search?q=precision%203.3v%20regulator%200.1%25&start=0

Thanks @dBC

No luck Im afraid. I’ve tried adding both:

HAL_OPAMP_Start(&hopamp1);
HAL_OPAMP_SelfCalibrate(&hopamp1);

Do I need to call

HAL_OPAMP_MspInit(OPAMP_HandleTypeDef* hopamp)

in stm32f3xx_hal_msp.c anywhere, or is this handled automatically?

After creating the basic outline in STM32CubeMX where would you look next to figure out what user code is needed? I would have assumed that since init was called that would have been enough had you not noted that start was required… and Im struggling to find reference elsewhere as to what to do. I note in application note AN4157 that there should be a whole set of examples somewhere including an opamp one but I cant find the code :slight_smile:

I choose 470k to test a high impedance input being buffered into a low impedance output in this case.

Yes, Im aware I didn’t connect those across.

Thanks @danbates!

That should get called automatically from HAL_OPAMP_Init(), which should get called from MX_OPAMPn_Init() which should get called from main()… all via the code generated by the GUI.

I always turn to the HAL manual (UM1786) as it documents the API you’re using. That’s where I learnt about the need to call HAL_OPAMP_Start(), p460 in section 33 “HAL OPAMP Generic Driver” is 33.2.2 “How to use this driver”.

The tricky bit is that manual documents the entire API as if you were writing everything from scratch. So you need to know which bits the GUI have done for you, and which bits are left for you to do. But once you’ve done a few subsystems you get the hang of it. I wasn’t at all surprised to discover there was a HAL_OPAMP_Start() function that needed calling, and that the call wasn’t generated by the GUI, because that’s how all the subsystems I’ve previously used work (ADCs, DACs, TIMs etc).

I’m signing off now, but if you haven’t got it working by morning my time, I’ll try to find time tomorrow to see if I can replicate your problem on mine.

[EDIT] - although I’ll need to use a different opamp from the one you chose, because my PA2 is plumbed through to the virtual console on the ST-LINK programmer. I’ve not snapped mine off whereas you have, which I assume is why you are able to use that pin for other purposes? Mine is hardwired and hardcoded to be USART_TX.

@TrystanLea

Did you try to download other firmware for other boards, like STM32Cube_FW_F0_V1.9.0, STM32Cube_FW_L1_V1.8.0, STM32Cube_FW_H7_V1.2.0, etc. There are about 10 such huge zips on the STM32 web site. I downloaded all of them some time ago.

Maybe you can find some examples related to OpAmp in one of them.

Walter

Thanks @daturach for the tip, I have now found and downloaded the stm32cubef3 examples. I can see a couple of Opamp examples but not for the STM32F303RE. I have now tried various combinations of positioning the HAL_OPAMP_Start() following one of the examples for other variants but still no luck :slight_smile: does the opamp depend on any other features such as the DAC or a timer setting or something like that?

Just a SWAG, but is any of this relevant?
From Reference Manual (RM0316) Pg 470.

Have you tried PA6/PA7 since introducing the calls to HAL_OPAMP_Start()?

What state are your SB62 and SB63 jumpers in? The default is open, which means D0 and D1 on the Arduino headers won’t be connected to anything.

When I’m starting a fresh project using a Nucleo board (as opposed to using a virgin chip on my own board) I always use the “Board Selector” in the GUI and then when prompted “Initialize all peripherals with their default Mode?” I always select Yes. That way any pins that are in use by the board will be flagged as in use. Even if I don’t plan using the UART, the LED or the Button, those pins are wired through to those features on this board, so having them flagged as in-use reminds me to stay away from them and use a Grey pin instead. If I absolutely have to use those pins for my feature instead of their feature, then I dust off the board schematic and work out what jumpers I need to change so as to disconnect their feature, and connect mine.

If you start with a virgin STM32F303RETx board in the GUI, you get this:

An example of that is using the second channel of the DAC. It can only be output on PA5 which is hardwired to the Green LED. That LED puts a big enough load on the signal that it can’t drive it all the way to 3.3V (even with the buffer enabled), so on the Nucleo board that I use for DAC testing I’ve had to remove SB21 and I can no longer use their LED.

Don’t underestimate the value of being able to do console printfs when the debugging gets tough. That’s saved my bacon lots of times. LEDs and GPIO toggles are great for timing stuff but there are times when you really need to see the contents of a 32-bit h/w register to find out what’s really going on.