Schematic symbol from STM32 configuration

Hi all,

when working with STM32CubeIDE you get pin assignments like this:

In order to use this in the schematics, you have to manually adapt the STM32 symbol

and enter labels for all components. This is a tedious and error-prone process - notice how the CubeIDE graphic does not show pin numbers (you have to count or mouse-over), also the KiCad symbol has the pins in a different order. The alternate pin functions are brillant though!

Has anyone attempted to generate a symbol from a STM32Cube assignment? It seems possible to export those

https://community.st.com/t5/stm32cubeide-mcus/how-to-produce-list-of-pin-assignments/td-p/756937

Maybe I should let Claude Haiku try…

1 Like

OK just tried Claude Haiku 4.5 (in VSCode Github Copilot Agent mode). I gave Claude Haiku a go as it costs 1/3 of Claude Sonnet (and is said to be much faster too).

I told it to extract the symbol from the STM32F1 library and delete all alternate functions.

Then I told it to copy the pin modes and labels from the CSV file. Interestingly Haiku did not do this by itself (as Sonnet probably would have done), but created a Python script to import the changes. It took some discussion, but finally did what I wanted.

The result is pretty decent already. I had to widen the symbol manually to make the names fit.

Now you could discuss whether PB3-SYS_JTDO-TRACESWO should be PB3-TRACESWO or TRACESWO (as I don’t use JTAG but SWD). The nice thing with Claude is that you can simply tell it what to do and it will fix the code - instead of digging through cryptic regexes. I have not looked more than a few seconds on the python script - it seems to work fine, so why bother.

Pretty amazing AI stuff. Best of all: I could have coded all that by myself. But it would have been gruelling, tedious and boring work. Just like we used to code for the past decades. Now it’s a few copilot prompts.

import csv
import re

# Read the CSV file
pin_mapping = {}
with open('pinout.csv', 'r') as f:
    reader = csv.DictReader(f)
    for row in reader:
        position = row['Position'].strip('"')
        name = row['Name'].strip('"')
        signal = row['Signal'].strip('"')
        label = row['Label'].strip('"')
        
        # Keep only the first part of the name before the hyphen
        if '-' in name:
            name = name.split('-')[0]
        
        # Create concatenated name
        parts = [name]
        if signal:
            parts.append(signal)
        if label:
            parts.append(label)
        new_name = '-'.join(parts)
        
        pin_mapping[position] = new_name

# Read the symbol file
with open('STM32F103C8Tx.kicad_sym', 'r') as f:
    lines = f.readlines()

# Process lines to replace pin names
i = 0
while i < len(lines):
    line = lines[i]
    
    # Look for (number "X" pattern
    if '(number "' in line:
        # Extract the pin number
        match = re.search(r'\(number "([0-9]+)"', line)
        if match:
            pin_number = match.group(1)
            # Look back to find the corresponding (name line
            j = i - 1
            while j >= max(0, i - 20):  # Look back up to 20 lines
                prev_line = lines[j]
                if '(name "' in prev_line:
                    # Found the name line, replace it if needed
                    if pin_number in pin_mapping:
                        new_name = pin_mapping[pin_number]
                        # Replace the name on this line
                        lines[j] = re.sub(r'\(name "[^"]*"', f'(name "{new_name}"', prev_line)
                    break
                j -= 1
    
    i += 1

# Write the modified content back
with open('STM32F103C8Tx.kicad_sym', 'w') as f:
    f.writelines(lines)

print("Pin names updated successfully!")
print("Sample mappings:")
for pos in sorted(pin_mapping.keys(), key=lambda x: int(x))[:15]:
    print(f"  Pin {pos}: {pin_mapping[pos]}")

3 Likes

Why that complicate?

Rightclick on the pin and choose the alternate functions: PA9 for example, see the pictures below.

Works in most newer Symbols.

Cheers

1 Like

It’s not about alternate functions. I know how this works.

It’s about copying all pin configurations, functions, port names and custom labels from CubeMX to KiCad. It’s a lot of work and very error-prone. Imagine an 256-ball device where you can’t just bend up a pin (that’s why I prefer QFP) and rewire it.

Hence the question for an automated approach.

But with the alternate functions you would have the correct electrical type (Input/Output/etc.) and that would be important for the DRC.

In your python script I didn’t see that the “Electrical Type” is modified.

Maybe you have to ask the KI again !

1 Like

IMO the “input/output” classification is far too limited to be of any practial use. I always use the DRC in PCB, but never with schematics (nor do I know anyone who does).

Can you explain how you use the ERC? What types of designs do you do?

You can have much more than input/output, see screen-shoot. (thats why i wrote (Input/Output/etc.) in my post.
With correct defines in the symbols and correct ERC matrix you can avoid errors in your design.

Documentation Schematic Editor | 9.0 | English | Documentation | KiCad is good and should help you.

1 Like

The electrical pin type is available in the CSV file exported from STM32 Cube already. I presume it would be very little extra work to add the necessary code in your (?Claude’s) script to add this to the symbol and thereby satisfy the ERC design requirements for the symbol. This could make a neat little plugin.

1 Like

Cool trick. I find myself doing this (ie. CubeMX → KiCad symbol assignment) a fair bit lately. The csv output and KiCad’s text file format is a match made in heaven. But losing the alt functions (and their electrical types) makes it a net loss for me - above all I seek to minimise resistance to change so like to avoid one way doors.

Honestly I kind of like having a human in the loop of pin assignment - helps me catch mistakes or at least double check the choices I’ve made. It’s only a once off per MCU, and you get pretty quick at it after a couple of goes. Automating once-offs sometimes causes more strife than it saves.

At the very least a checker than confirms the CubeMX settings match the symbol assignments would be nice. Invariably I make a couple of changes as I go, so a sanity check that everything is still in sync would be handy.

Funny, that’s just the kind of thing I use ERC for :wink: it’s a life-saver for catching mistakes in things like mismatched hierarchical labels or clashes in netnames or out of date symbols. I’ve never worked with anyone that doesn’t use it, so goes to show how experiences can differ!

But this sort of “programmable EDA” stuff gets really exciting when you have vendor tools that lean in. There’s lots of opportunities. The CSV export from CubeMX is a great example, thanks for sharing.

Well, to some degree:

“10”,“PA0-WKUP”,“I/O”,“TIM2_CH1”,“”
“11”,“PA1”,“I/O”,“TIM2_CH2”,“”
“12”,“PA2”,“I/O”,“USART2_TX”,“”
“13”,“PA3”,“I/O”,“USART2_RX”,“”
“14”,“PA4”,“I/O”,“SPI1_NSS”,“”
“15”,“PA5”,“I/O”,“SPI1_SCK”,“”
“16”,“PA6”,“I/O”,“”,“”
“17”,“PA7”,“I/O”,“SPI1_MOSI”,“”
“18”,“PB0”,“Output”,“GPIO_Output”,“nSRCLR”
“19”,“PB1”,“Output”,“GPIO_Output”,“RCLK”
“20”,“PB2”,“Output”,“GPIO_Output”,“nOE”
“21”,“PB10”,“I/O”,“USART3_TX”,“”
“22”,“PB11”,“I/O”,“USART3_RX”,“”
“23”,“VSS”,“Power”,“”,“”
“24”,“VDD”,“Power”,“”,“”
“25”,“PB12”,“Input”,“GPIO_Input”,“Btn4”
“26”,“PB13”,“Input”,“GPIO_Input”,“Btn5”
“27”,“PB14”,“Input”,“GPIO_Input”,“Btn6”

It only works for GPIO. The two timer channels are inputs in encoder mode, but marked as I/O.

The SPI signals are master transmit only so would be outputs, but also I/O. Same with UART RX/TX.

Yes, Claude could modify the script, but I doubt it would be of much help.

Well, modifying the pinout after it was imported would kind of defeat the purpose… The whole point of the excercise was keeping designs in CubeMX and KiCad in sync.

But I’m sure one could keep those alternates. Of course the converter script then would have to select the correct alternative (like the SPI4_SCK of all possible alternatives). I wonder if the wording used in CubeMX and the KiCad library is consistent.

Also, when using the predefined alternates, what about the user labels?

I added the original port number (which is somewhat informative even if you configured it to an alternate function) and the user label. As always those things are a matter of taste, balancing between cluttering the schematic and losing information.

Actually the labels would be useful in your schematic. How do you make sure that MCU_5V_EN is an PD6 and not PD7? If you have assigned it in CubeMX, it generates the definitions in main.h - wouldn’t it be nice to have those visible in the schematic? That was my thought here, for example PA8 has the user label EBtn1 assigned and is connected to net ENCBTN1.

I quickly thought about using the pin helper function “generate net labels” for automatically generating the correct net associations, but as you mentioned having a human in the loop makes sense here. Particularly for deciding if USART3_RX now goes to STLINK_RX or TX? BTW on some UARTS they added a swap functions, obviously because many people messed it up.

I will look into the ERC. I doubt that the input/output classification is useful in practise, but catching single pin nets alone would be a big benefit!

Ah yes, I see your point. I still like to be able to click on the pin to see the alternatives. And I prefer to allow them to diverge - they could well have different design lifecycles and I don’t necessarily consider the CubeMX view of the world as correct. But I see your point - if you treat the ioc file as the single source of the truth, that eliminates a manual step and one source of error.

Now you need to do it for all the other MCU’s as well :wink: I created a RPi5 symbol with alternate function pins (including electrical type) using a sed script similar to your Python script. So I guess I’m biased to think of those alternative functions as standalone useful.

That’s got me thinking. I happen to use those heavily in the firmware, so they’re not just informative. But again, I develop a slightly different design philosophy between schematic and firmware - most significantly, the schematic labels are scoped to make sense at the schematic level. So for example in this case they often have a “MCU_” prefix, which is not relevant in the firmware. But you mention that too, so to your point “how do you make sure that MCU_5V_EN is an PD6 not PD7?” - the same way you’d make sure “EBtn1 is ENCBTN1 and not ENCBTN2”: manual verification.

So in my case I like to have the “STM” name on the symbol (eg. PE7 or UART8_RX) and the “electrical” name on the net (eg. 24V_PGOOD and MCU_RX_GNSS1), so I can see the mapping at glance. Having to adjust the size of the symbol because I want to use a different label would be a disaster for me. The labels are much more prone to change than the functions.

But I definitely find the auto-gen appealing. As you say, you could include or hide information according to your preference, and having it appear on the schematic would make it checking easier.

Tell me about it. Can you believe one of these is correct and one isn’t? Every year I swear is my last making TX/RX swap mistakes. Every year I’m mistaken.

I do an export from CubeMX, run a custom script, and then paste into the pins table. Works like a charm. If I am going to make pin changes, I drive it from CubeMX and repeat the flow.

It would be nice to get ST to export the preformatted csv data so we didn’t need to externally run a script :slight_smile:

You’ll love this:

(STM32G4)

Actually, I presented this script not so much as a working solution, but to show what current agentic LLM coding together with the text based KiCad files can do. If you have never used a modern LLM for coding like Claude Sonnet, you are missing the biggest revolution in computer programming for the past decades. By all means, get yourself for example a Github Copilot pro subscription ($10/mo, nothing worth your time is free) and start playing with Claude Sonnet 4.5. It’s truly amazing.

Good catch! I had the table in the back of my mind but thought it would be Altium. They had that for a long time and KiCad only recently caught up. I work with both which causes me to forget which features are where (sure enough, first, second and third top places on the list what to copy from Altium would be “find similar objects”).

Sure, using the pin table would be less invasive (and potential cause for errors) than modifying the source file. Would you share your script? Of course I can ask Claude to do that as well, but if you have a working version that might be easier.

Oh I make sure to only ever make that mistake on USARTs that do not support SWAP.

1 Like

And RTS / CTS? Those are swapped too in the second screenshot.

Nope, that’s the correct one! Netnames are from the perspective of the UART on the other end. That’s what my “Pi_” naming convention was supposed to remind me of, and it did. Alas, I changed my mind half way through for the “EXP” UART…

Ha! Murphy lives. I’ve taken to using arrows next to a signal name to help keep me straight. The default KiCad font set supports extended Alt-XX characters like arrows.

Wait…? Did not a few post above someone advertise the input/output tagging of pins together with ERC as the holy grail of finding connection bugs?

How come something stone age as a left-right arrow is necessary when we have the glory of ERC?

Symbol from Device perspective

In your first picture you show a chip image from CubeMx. Which is nice. KiCad should copy that with names. An other option is? logical groups like KiCad symbols. Those two should be options in SCH symbol.

Those arrows are good.in TX/RX, by the way