Klipper Firmware Fails to Start on Custom STM32F070 Board

Hello Klipper Community,

I’ve been working on a custom board based on the STM32F070F6P6 microcontroller. I developed my own firmware for it, and everything works as expected: the crystal oscillator starts, pins initialize correctly, all GPIO-s is functional.

However, when I flash the Klipper firmware onto the board, it fails to start entirely. Here are the symptoms:

The crystal oscillator does not start.

Pins that would typically initialize to default states remain unresponsive.

UART communication is completely absent.

It seems like the microcontroller doesn’t even reach the initialization phase. I’ve verified my hardware design and ruled out any issues there since the board works perfectly with my custom firmware.

I’m looking for insights or suggestions on:

Potential configuration issues in the Klipper firmware that could cause this behavior.

Any known compatibility concerns with the STM32F070 series.

Debugging steps to pinpoint what might be going wrong during startup.


Sorry, but you haven’t provided anything to go on - without you providing schematics or your “custom firmware” there’s not much we can say at all.

When you provide your schematics, please make sure to include part numbers; especially for the crystal.

EDIT:

Just thinking more about this.

To maximize the chance that we can figure out what’s wrong, could you provide:

  1. Schematics. In .pdf format would be preferable.
  2. Your custom firmware source. I would be most interested in your initialization code including clocking.
  3. What are the parameters that you are using in make menuconfig
  4. How you Flash the MCU? Are you using DFU or are you loading in a bootloader and, if so, please provide where you got the bootloader.
  5. As part of the previous request, could you tell us whether or not you have STM Link (with STM32 Cube Programmer) or another tool to load your firmware or the Klipper firmware?
    ^ If you can write to your STM32F070’s Flash, what happens if you clear the Flash - you should be in DFU mode. If don’t have a USB connection, then you can program the STM32F070 USART1 TX (PA9) should be in output mode and high.
    ^ I’m asking this because this requires a running clock - and you should be a good way of getting things running.

Thank you for your response! Here are additional details about my setup:

  1. Schematic.pdf
  2. main.txt (main.c)
  3. config.txt (.config)
  4. I am using ST-Link to flash both my firmware and Klipper firmware. I do not use a bootloader.
  5. Of course! I have an ST-Link and use STM32 Cube Programmer for loading both my firmware and Klipper firmware. I have access to the flash and scan erase and write to it without issues.

Currently, it is more important to understand why the firmware does not start.

I have a Blue Pill board where I tested an equivalent Klipper firmware for the STM32F103. Here is what I observe:

UART communication works, and I can see data on the oscilloscope (trigger set for monitoring) and in screen.

The crystal oscillator starts, and its frequency is visible on the oscilloscope.

The LED on PC13 lights up as expected. :slight_smile:

However, on my custom board, the crystal oscillator does not start, and the LEDs do not turn on either. This is currently the primary issue. UART functionality can be addressed later, but for now, simply turning on the LEDs would be a good starting point.

I have tried selecting the internal oscillator for the custom board, but that does not work either.

To provide confidence that the hardware design is correct, I would like to mention that my own firmware works flawlessly. All modes function as expected without any issues.

Let me know if you need further adjustments or clarifications!

config.txt (2.8 KB)
main.txt (11.6 KB)
Schematic.pdf (141.2 KB)

Probably it was right to write this as a response to your message :man_shrugging:

A few comments then I want to dive into what you’re observing in more detail.

Overall, I don’t see any reason why Klipper shouldn’t run although what you’re using is a pretty marginal part. I’m guessing you designed it as a Serial/USB connected controller board for controlling a chamber.

Secondly, you haven’t provided the complete schematics. I would like to see how the heater/fan drivers are wired specifically. I’d also like to know what “MODE” (PA4) is wired to. I also asked for the crystal part number.

Third, you have a somewhat weird circuit connected to PA9/PA10 (USB and USART1 - apparently set up as both). I’m not sure what the pull up on PA10 USART1 RX pin will do here.

Now, when I look at your Klipper configuration, I believe that it is what I see on the make menuconfig - the conventional way of showing what you are doing is to show the screen like:

Are these the parameters that you used?


The most likely cause for your board not starting is that you haven’t flashed the firmware correctly. How are you verifying the start of code in the firmware.bin file? How are you verifying that the firmware has gone in correctly?

It sounds like you have a good idea how to check if the firmware is running, so I would have to question how the code goes in.

To this end, I’ve designed three boards and have only used ST Link to verify that the firmware has gone in correctly, erase the device and set the operational bits. To program the board, I’ve always use DFU Mode - it’s fast, reliable and easy to use.

What I would be interested in hearing is what happens if you erase the device, remove R172 (the pull up on PA10) and plug the board, using the USB C connector into a Linux system and do a lsusb command.

You should get back something like:

Bus 001 Device 005: ID 0483:df11 STMicroelectronics STM Device in DFU Mode

If you do, then you can do a DFU-UTIL load of the Klipper firmware and start working with it once you reset. I would recommend changing your config to use USB rather than serial as that will give you an immediate link to your host.

Let’s see what happens here.

You are quite right, this is the control board for the active thermal camera.

The MODE button in a cycle switches the operating modes when this is used as a standalone device.

PA9/PA10 - this is also correct here! In one case a 1.5Kohm pull-up resistor is needed, in the other case it is not needed, but this is a feature and inconvenience that I decided on consciously. That is, if necessary, I can put a jumper and thus control Pullup DP.

You recreated my settings exactly from the file. I also tried Internal clock and that also did not lead to anything.

Regarding the supposed cause and the start of the firmware.

In order to exclude such errors, I generated two firmware for stm32f103 and stm32f070.

And flashed them from address 0x0800000000 via ST-link and STM32CubeProgrammer.

For verification I erased the chip, checking that all memory is filled correctly

But only stm32f103 starts and the LED on PC13 confirms it. And yes, I also check for a signal from the crystal and only the stm32f103 has one.

I will not argue about the quality of st-link and DFU, but st-link, being an official tool, shows its reliability in other projects and even on the example of stm32f103 everything works perfectly. I should check the DFU too though.

I have removed R172 and put it back in place. This does not lead to anything. And of course I connected my board to Linux, because I just recently got a Windows computer and I can’t be sure that I will do everything right in Windows.

If you do, then you can do a DFU-UTIL load of the Klipper firmware and start working with it once you reset. I would recommend changing your config to use USB rather than serial as that will give you an immediate link to your host.

I would like to understand what I am doing wrong with stm32f070, because I am doing the same actions for both MCUs but only in one case I get the desired result.

If you have any suggestions, what could be wrong with the stm32f070, I will be glad to fulfill your recommendations.

I would be satisfied with one of the three LEDs glowing or the presence of a signal from the crystal, the rest will not cause problems :blush:

I emphasize.
The operation of the hardware has been checked.
All actions for stm32f070 and stm32f103 are similar
The result have is only for stm32f103

Okay, I don’t think you got what I was saying.

Just to be clear:

  1. I don’t see any reason why Klipper won’t run on your board. The device you’ve chosen is marginal for the application (in terms of Flash and pin resources) but I think it should work.
    ^ Having said that you do have a bit of a wonky USB/Serial interface that should work for both. As will be discussed below, I think the USB C connector (with R172 removed) should provide you with a DFU interface.
  2. I meant no disparagement of STM Link/STMCubeProgrammer - I use them all the time.
  3. I have never Flashed an STM32 device using STM Link with Klipper. I’m not confident that loading in the klipper.bin image as is into STM Link and Flashing it into the MCU will work.
    ^ I do not know what tool you used for building your custom firmware nor do I know the parameters and whether or not the generated file is in the same format as klipper.bin.
  4. Where I do have experience is with DFU-UTIL. It’s reliable, fast and easy to use.

In summary, things look good but there’s the unknown as to whether or not using ST Link/STMCubeProgrammer can successfully Flash klipper.bin into an MCU.

I’m going to suggest that you try to attach your board to your Linux system using the USB C connector on the board. I just verified it on one of my Linux systems (Ubuntu 24.04LTS) and will pass along the screenshots of what I got on one of my custom boards.

  1. Create your klipper.bin file. I’m going to recommend that you set it up to run on USB after the build, so that you have another way of checking that it took place correctly. The parameters that you should use are:
  2. Remove R172 from your board.
  3. Apply power to your board, attach STM Link and erase the MCU’s Flash. I did it with one of my boards here:
  4. Remove power, disconnect STM Link.
  5. Connect your board to your Linux system. Based on the schematics, it looks like the board will be powered through the USB C connector.
  6. Do an lsusb on your system and you should see a device with the ID 0483:DF11 - this is the STM DFU USB VID/PID.
  7. Run sudo dfu-util -a 0 -D <location>/klipper.bin --dfuse-address 0x08000000:force:mass-erase:leave -d 0483:df11 where “<location>” is where you have your klipper.bin file.
    You should get something like (you can ignore the last line regarding error on get_status:
    d
  8. Now, when you do an lsusb command, you’ll see that the MCU is now available as an “OpenMoko” device:

That’s it. I should point out that this is the first time I’ve done this - it was theoretical for me up to now but it’s nice to see that you can Flash an MCU using a basic Linux system without any issues.

I would expect that you would be able to do this with your board, from the photographs in the original posting it looks like your USB C connector is quite close to the MCU, so if you haven’t designed it with line impedance in mind, you should be okay.

Just remember to remove R172 before doing this.

I look forward to hearing how this works for you.

@Rula

I agree with Myke. Without a complete schematics there will be just guessing.

1 Like

A new datapoint that I don’t think you’re going to love.

I wanted to see if STM Link/STMCubeProgrammer could be used for loading the Klipper firmware.

So, I took the firmware image that I built in my previous posting and Flashed it into another of my custom MCU boards using STM Link/STMCubeProgrammer. I then connected the board (via USB) to a Raspberry Pi 4B with Klipper installed and…

The Raspberry Pi 4B used a new 64bit OS using Raspberry Pi Imager with Klipper/Moonraker/mainsail installed using KIAUH which also creates a simple printer.cfg. I used KIAUH to do any available system updates.

With Klipper installed, I plugged in my board and checked to see if it was recognized as an “OpenMoko” USB device and then did a ls /dev/serial/by-id to get the Klipper UUID:

I copied this UUID into printer.cfg, did “SAVE & RESTART” and got the result that you see at the top; the board (and MCU) connect to the Klipper host without issues.

So, my trepidation regarding using ST Link/STMCubeProgrammer for loading the Klipper Firmware into an MCU seems to be unwarranted. In STMCubeProgrammer I simply loaded in klipper.bin and uploaded it into the (cleared) MCU.

So, where does this leave you? Honestly, I don’t know.

What I would suggest is:

  1. Share your full schematics with us as well as a photograph of the full board. Maybe there’s something that will jump out at us as being problematic.
  2. Detail the full process you are using to Flash your MCU, including how you built the Klipper image and where you got your copy of Klipper and how you installed it.
  3. Share how you’re checking the MCU to see if it’s working. You mentioned 'scoping the clock (which generally is not recommended) what else have you done? Have you checked the 3V3 power rail? What about devices that are backdriving the MCU?
  4. Try to follow the process I outlined above precisely. I think you should be able to use DFU-UTIL to load your MCU - I highly recommend that you follow my example and use USB communications rather than serial (remember to remove R172). The advantage of the process I outlined previously is that you get indications along with way whether or not things are working as expected.
  5. Look for a development board that uses the EXACT same MCU as you are using. I did a quick look and STM doesn’t have one (theirs uses the STM32F070RBT6 which has more Flash and IO pins) but some other company may.

How many boards do you have? Do they all work the same way?

When you’re reporting your results or providing information, remember that more is better.

I’m looking to hear how things work for you.

This is redundant information, as is the attempt to replace one flashing tool with another. It clearly yields no results and only generates false hypotheses.

The search for truth is the elimination of all false assumptions. I reconsidered my approach and simply tried flashing with Katapult. This allowed me to exclude all peripherals except PA11 and PA12. Of course, I conducted this in parallel on two boards: my own and a BluePill. The result turned out to be identical. On the BluePill, I observe a functioning firmware, while on my board, I don’t even see the oscillator starting up.

So far, based on the results, I can conclude that the issue lies with the linking specifically for the STM32F070, causing some currently unknown error. I draw this conclusion from the fact that my custom firmware, configured in 5 minutes using CubeMX, works perfectly fine. According to Katapult’s documentation, it is based on Klipper files, so this could be a systemic issue. If I can muster the strength and patience, I might go down the path of building with make V=1, but I fear that path could be long.

Of course, it would be easiest to get feedback from someone who has an STM32F070 in operation to definitively confirm that the problem is with my board. However, since no one has responded so far, I suspect this MCU is not commonly used.

Perhaps someone familiar with Klipper’s development, its source code, and the build system could quickly verify this. However, I don’t know who among the developers to invite to this topic who is specifically working in this area.

Mike, I am very grateful for your attempt to help. My tests have so far been unsuccessful, and I’ve ordered a development board based on the STM32F070F6P6 to rule out possible design errors - though I can hardly imagine where one could make a mistake, given that it’s hard to get confused with just three resistors. Nevertheless, I’ll receive the order in two days and will continue my investigation.

Once again, thank you so much for your effort to assist! I will get back in touch and definitely share what the issue was, or we’ll resume the discussion in a few days.

1 Like

Where did you find a development board with the STM32F070F6P6? the only one I found was:

But the designer won’t share his schematic or PCB layout.

The “STM32F070” is not uncommonly used but all the boards that I’ve found that incorporate it have the “STM32F070CBT6” which has 128k Flash and 48 IO pins - I should point out that these run Klipper without any issue. I have never seen a Klipper board running the STM32F070F6P6 and I can’t find one online.


Now, I would like to make a hypothesis that you can test out while you’re waiting for your development board.

My hypothesis is that Klipper builds for the “STM32F070CBT6” under the assumption that all “STM32F070” boards are the same and have the same basic register functions and addresses but the “STM32F070F6P6” actually has different ones.

If I were to make a guess, I’d say that to make your test code you got your firmware development tool here:

https://www.st.com/en/embedded-software/stm32cubef0.html

When I go through the documentation, I see something interesting in terms of the supported products:

Note that there is a different .h file for the “STM32F070x6” and the “STM32F070xB”. I would expect that you created your firmware including STM32F070x6.h (but in the “main.txt” you provided there’s no include statement for the device used or a complete set of source files to confirm).

You can validate this hypothesis by:

  1. Rebuilding your test firmware including “STM32F070xB.h” and Flashing it into your board and seeing if it works. If it doesn’t, which is expected by the hypothesis, then go on to the next step:
  2. Go through the Klipper source, find the file “STM32F070xB.h” or it’s equivalent and replace it with “STM32F070x6.h” or an equivalent, build the new Klipper firmware, load it into your board and see if it works (make sure the resulting file isn’t greater than 32k or it won’t load properly into your device).

If this is the problem then report to the developers (on this site under the “Developers” category), explaining the issue, providing all code and ask that they update Klipper to differentiate between the STM32F070xB and STM32F070x6. Don’t expect an immediate fix, there will probably be questions along with how to present it as a “make” option to users.

Hello, hardware engineer here :slight_smile:

As I am repeatedly reading the “Quarz is not starting up” I wonder if you have looked into if your chosen Quarz actually is suited for your processor?

In detail, there is a thing called “critical transconductance” (gm_crit) which must be met, otherwise the combination of MCU oscillator-circuitry + quarz would not start up.

Quarz conductance calculation not only take the load caps into account but also things like the parasitic quarz capacitance and the Quarz resistance.

It’s a thing I also experienced which STM processors.

The problem is: the common STM32F103 takes as literally the shittiest quarz out there and will quite happily start up.
Other STM32 processors require higher grade quarzes.
But as the F103 is literally the most used STM Processor in the DIY community nobody seems to bother with it when the are start using more powerful processors for their projects.

For all the other wiring you can cross-reference my own USB-Toolhead board which utilizes a STM32F072 Controller:

  • cad435

Ok, here is another reply for a 30sek review about the schematic you posted

  1. your LDO which makes 3.3V does most likely not be fed by 5V, but by 5V minus the voltage-drop over the diode.
    Did you account for that? Did you leave enough voltage margin, so that the drop-out of your LDO don’t cause any problems when the MCU goes “full power” (likely only a few 10/100 milliamps)

If your voltage drop over the diode and the LDO is to high and the MCU gets “to low” voltage only for a very short period of time, very funny and very random things can happen.
Idk if and how brown-out detection is handled by Klipper or even your custom firmware.

  1. I would recommend starting with 0R resistors and unpopulated capacitors for the USB-Lines. Those are for matching your trace impedance. Either you simulate, measure (both ways definably challenging at least) or you just start with “something” and change it if it’s not working.

I don’t see the caps rarely used. If communication is not working, I’d recommend unpopulate the caps and varying the resistance.

Populating caps can (not “will”!) generate overshooting and potentially shortening the life-span of your electronics.

Otherwise that part of the schematic is definately good.

  • cad435

I’m not sure you understand exactly what @Rula is saying here.

To net things out:

  1. He feels his board runs fine using (what I believe is) the ST C Toolset (found here: https://www.st.com/en/embedded-software/stm32cubef0.html) for the STM32F070F6P6". Apparently this code also works when built for the STM32F103.
    Going by his “test.txt” file, it looks like he’s doing some simple exercising of the ADCs and IO pins. I would not consider this a comprehensive test of his board, but it should demonstrate basic start up, clocks, code operation, digital IO and analog input.
  2. When he builds the Klipper firmware for the “STM32F070” and “STM32F103”, he gets nothing. He can’t see the clock starting nor can he see any specified LEDs turning on. It sounds like he tried to connect serially but did not get a response.
  3. From what I can see, he has not tried to program his board using DFU or used USB in any way. I’m not exactly sure why - from the photographs, it looks like his USB connection should be okay, so long as he removes R172. More on this below.

In reply to your post:

  • Regarding the oscillator, I’d have to see the part but the loading is correct and he says that things run fine with his code.
  • Regarding the LDO (ME6211C44M5G-N), if you read it’s datasheet, you’ll see that it has a dropout of 200mV when 600mA are being drawn. The BAT54C has a maximum forward voltage of 1V (when 1A is drawn through it) - it’s not a great choice.
    So, in the worst possible case, he will have 4V at the LDO input, which needs 3.5V to operate properly. There shouldn’t be any issues here.
  • I don’t know where you’re coming from suggesting that he adds caps to the USB lines. You should never consider adding capacitors to bus lines with set impedance.
    Anyway, when I look at the photograph in the original post, I would estimate that his USB lines (from the STM32F070F6P6) are between 15 and 20mm long. I don’t see any evidence that he’s using any kind of impedance control or matching, but at that length, he should be able to connect at USB Full Speed (12Mbps) without any issues - of course he needs to remove the R172 pull up resistor.

I just don’t see any hardware issues here - the problem is most likely software related. This is why I’m recommending that @Rula go through the Klipper initialization code for the “STM32F070” and compare it to the STM initialization code for the “STM32F070x6” as well as the “STM32F070xB”.

The STM32F070F6P6 is an interesting part and I can see it being useful as a small peripheral/IO controller for Klipper (connected to the host via USB), which is why I’m following this thread so closely.

1 Like

Hello,

I guess there are some misunderstandings, yes.

About the Caps: If you see the schematic he provided there are 2 Line-Caps on DM/DP.

About in the middle of the sheet.

I had also recommended to NOT use them.

Also about the Quartz: I didn’t read that it was successfully working with ST-Code.

Note: idk if on both code-bases HSE-CLK is used, or for example HSI on the ST-Code.

Just some thoughts :slight_smile:

  • cad435
1 Like

@Rula definitely didn’t provide enough information to really understand his problems or what’s really happening.

When I read your post, it sounded like you were suggesting adding caps to the schematic. As for the other hardware concerns you pointed out, I don’t think they’re potential issues - I don’t know the crystal he’s using but it looks correct (and matches what I’ve done on the custom Klipper boards I’ve designed).

But, @Rula is pretty adamant that his test code works stating that the crystal is running and he can turn on/off LEDs.

As I said above, I think there’s a register difference between the STM32F0706x and the STM32F070xB with the STM32F070xB (and STM32F103) being the more commonly used part and the one that’s used when he tries to run Klipper.

I want to take a look for the differences and that’s number 3 on my list of todos.

The Klipper stm32f070 support was designed around the stm32f070cb and rb variants - not the f6 variant.

At a minimum, you’ll need to adjust src/stm32/Kconfig to adjust the FLASH_SIZE and RAM_SIZE (to 32KB and 6KB respectively). You may also need to enable HAVE_LIMITED_CODE_SIZE to get the code to fit in that chip’s flash size.

Other changes may also be needed to fit the smaller memory and flash size.

Cheers,
-Kevin

EDIT: Also, FYI, if you adjust any Kconfig file you’ll also need to run a full make menuconfig, save the changes, rebuild, and flash.

Hey Kevin,

Thanx for the post - I’ve gone through the make menuconfig process and thought that it would require modification of ~/klipper/src/stm32/Kconfig and thank you for confirming it.

Thank you for also confirming my hypothesis that the issue was regarding the STM32F070x6 vs STM32F070xB, which is the default build for Klipper under “STM32F070”.

My question to you is, what’s the best way to package things up in Kconfig file so that the user can see there’s a difference between the STM32F070xB and the STM32F070x6 so that when I submit a PR for the update it will most likely be accepted - I would like to give the user the option of “STM32F070x6” and “STM32F070xB” rather than just “STM32F070”.

Some background for the reason why I’m asking the question; while there seem to have been a number of main controller boards based on the STM32F070xB, built with the STM32F070xB prior to 2021, they are now assembled with the STM32F103 (which makes sense as they’re cheaper, more powerful and footprint compatible). So, while the number of new users for the STM32F070xB is effectively zero, that doesn’t mean the number of possible users with the STM32F070xB is zero.

It also means that my changes to Kconfig will not be verified on the STM32F070xB until some user tries it out, either on an printer they’re converting to Klipper or one they’re updaing.

What is the risk mitigation process here? Do a Klipper Firmware Build with the basic Kconfig file, then one with my changes and do a KDiff on the two of them to see if there are any differences?

Well, the mainline Klipper code targets hardware that has at least around 100 users (this is mentioned briefly at Contributing to Klipper - Klipper documentation ). So, if this is for a one off machine, then I’m not sure it would make sense to submit a PR for it.

If this is for a run of motherboards such that it is felt there is a significant number of potential users, then I’d probably take a look at how MACH_STM32F103x6 is implemented in src/stm32/Kconfig.

Alternatively, if it was felt this was needed for a very large audience of printers, then we might consider changing the default for stm32f070 to include the f6 variant. (This seems unlikely though.)

Finally, it is worth pointing out that more extensive changes may be needed than what I mentioned. I don’t know what work is needed - I just suspect some minimum changes would be needed.

Cheers,
-Kevin