Need some guinea pigs for a rule-based DRC <<PROTOTYPE>>

The syntax for recognising unconnected nets has changed. Instead of:

A.NetName == 'no_connect*'

you’ll need to use:

A.PinType == '*no_connect'

This will also ensure that it only applies to pads (and not other members of the net).

For those curious, the PinType property of a pad has the following values:


Pins that have been annotated in the schematic with a “no connect” symbol will look like:


(Thus the requirement for the * at the beginning of the match if you want the rule to match on both no_connect pins and no_connect schematic annotations.)

I.e. here… :smirk: (OK, I’m willling to report bugs in gitlab, but here are some quick notes.)

That’s great, now it’s possible to create castellated pads/footprints. Here’s my final rule:

(rule 'castd'
(condition "A.insideArea('castellated') && (A.Type == 'pad' || A.Type == 'track' || A.Type == 'zone')")
(constraint edge_clearance (min -1mm))

Here’s the footprint on a board:

There are a couple of problems.

  • It doesn’t work for zones, although it doesn’t matter in this case because the zone reaches the pad anyways. And it’s questionable what it should co in case the zone would be poured beyond the edge cut.
  • The track doesn’t stop at the pad center but at the edge cut. This may be a problem because the global edge clearance constraint isn’t obeyed by the pns router, it stops all tracks in the same way. So, if there’s a more general bug in track/edge clearance, it may cover another possible problem in this local area rule.


This was routed with Shove but DRC gives an error.

Here’s the project, it should be easy to do tests with it. (14.6 KB)

It’s also not going to do what you think for zones because A.insideArea() means the whole copper zone would need to be inside the castellated rule area. So you’d need to have a separate “castellated connector” zone that you reference by name to set its edge clearance to -1.

But pads and tracks don’t need to. That’s a bit confusing.

If I change the condition to

(condition "A.insideArea('castellated')")

It seems to take also the edge.cut graphics as A and if it’s a continuous shape (rectangle) the constraint overrides the global constraint for all the edge cut, even if only a tiny bit of it is inside the rule area.

I didn’t realize earlier that rule area doesn’t mean that some rules are used inside that area, but only that some parts of items are inside the area. Doesn’t that create problems because for example track segments can continue far away from the area and then the minimum values can’t be controlled outside the area?

The typical scenario I think about with track widths and rule areas is constraining an area of tighter width/clearance so that the cost impact is lower.

So, maybe in most of the board I want 0.2mm width / 0.2mm space, but near a BGA I need to let it be 0.1mm / 0.1mm.

If I have a rule area for this, that means that a segment that crosses outside the rule area would have part of its body in the default clearance area, so it needs to meet the 0.2/0.2 rule. It would be incorrect to let that whole segment be 0.1/0.1 just because part of it was inside the rule area.

I understand that, but isn’t it contrary to what I demonstrably see in my example? I need stricter rule, i.e. larger clearance for most of the copper/edge contacts – just like larger clearance is used for most of the tracks on the board. Then I need it to be ignored in one place – just like smaller clearance is used for a BGA. But what I see is that the stricter rule is relaxed also outside the rule area if the segment continues outside it.

That’s of course what I actually want and need for the castellation, otherwise the stricter rule (keep the normal edge clearance) would be kept inside the rule area, too, when routing inside the area. That would be cumbersome.

@JeffYoung what do you think about the above? I haven’t had a chance to test to see how things actually work today in various situations, but for the case of zones, I think we should not be requiring the zone border to be entirely inside the rule area in order for the zone filler to consider clearance rules that match that zone and address a rule area.

For example, if a huge zone has a small rule area inside it, and that rule area sets a larger (or smaller) clearance from that zone to a pad that is inside the area, I’d expect the zone filler to use that clearance to that pad inside the area (but not to pads outside the area)

@eelik zone filler aside, I think you have to work within the limitations of track segments being “indivisible” – an individual track segment is all that is considered for the purposes of rules (and everything else, really). You can’t make a track segment have less edge clearance just for the portion of that segment that is inside a rule area. You will have to split that segment into two segments (make them slightly different widths if you want to keep them co-linear and don’t want to fight against our cleaning up co-linear segments)

If you are trying to route into the castellation area, then just fix the routed segments in place inside the area before you get to the actual edge. Then your last segment (starting inside the area) should have the right clearance). If that doesn’t work, it’s a bug we should fix.

A pad is knocked out from a zone, so only the pad needs to be in the rule area. But as far as I’m aware, the whole pad needs to be inside.

In the zone / edge case we do knock the edge out of the zone, so for that part only the edge segment needs to be completely inside the rule area. However, we also apply the edge clearance to the zone itself when generating its boundary (so that rounded corners will round to the clearance, not to the edge). That check runs the rules against only the zone because it’s not nearly sophisticated enough to do it with each segment separately.

So, I can only say that clearly it doesn’t work like you say it should work.

First, there’s probably a bug with routing tracks near edges. I can violate edge clearance. The violation is shown in the DRC check later. This isn’t necessarily related to this rule area or the recent “negative clearance” change.

Second, it’s enough for pads and track segments to be only partly inside the rule area to suppress the DRC errors. See this screenshot:

The hatched area is the rule area. As you can see, the pad is only partly inside it and doesn’t cause a DRC error. A pad which doesn’t touch a similar rule area causes an error. I can route the track along the edge cut, although this may be caused by the different bug mentioned above. But anyway the DRC check doesn’t complain about the track/edge clearance, even though it complains about the other segment. (The yellow arrow is just an “unconnected end” warning.)

We should fix that, in my opinion: I would expect only items fully-enclosed in the area to count (note: I don’t count zone filled areas as “items” in this sense

I reported this:

Oh no. That’s really cumbersome.

Could there be a new function check “touchesArea()”? This could be used for these tracks and pads. It doesn’t matter if the tracks can violate the edge clearance outside the footprint area because usually they aren’t routed along the edge when they start from the castellated pad. And they hardly go straight to another edge.

I checked and the code has different paths for zones and other items. Zones are “fully contained” while other items are “collide with”. I probably did it that way because our collision code is much faster than our “inside” code…

I think that’s probably OK for pads and vias. We could easily special-case tracks to check both endpoints (which still isn’t a “fully inside” check, but is probably good enough).

While I agree it’s probably not optimal for edge clearances, I really don’t want it to work differently for edge and copper clearances. And I think “both ends inside” makes more sense with copper clearances…

I like the idea of touchesArea() and changing the insideArea() code to require segments be fully inside (or at least both endpoints inside, ignoring width, as a performance optimization)

@eelik it doesn’t seem that cumbersome to me, you can also approach at an angle or just not use the co-linear cleanup functions. It seems like in your case you would just switch to touchesArea if we implement it, but in other cases where insideArea is actually what you want, you need to split up that track segment one way or another.

So I started playing around with KiCad 5.99 a few days ago (it just feels soooo much more usable than 5.0).
I’m currently on build 5.99.0-8711-gbabda304d9 and encountered a few issues with DRC rules:

The rule syntax help doesn’t have an example for a layer-specific rule, but judging by posts on this thread, it seems like this should work to enforce 5mil clearance on inner layers (for JLCPCB):

(rule "Inner layer track/space"
   (layer In*.CU)
   (constraint track_width (min 5mil))
   (constraint clearance (min 5mil))

I’m not entirely sure whether it needs to be quoted (some posts here contradict the help dialog) or whether it supports wildcards, but removing that didn’t help either, nor did removing the constraints from the rule. As soon as the layer tag appears anywhere, Pcbnew fails to parse the rules and a rule syntax check ends up in an unhandled exception dialog (without any useful info).
It seems like this should be straightforward to reproduce, but let me know if you need further debugging from my side (is there a way to capture log output or something?)

It also appears that the only way to recover from this is to remove the offending rule manually from the .kicad_dru file, as any further attempts to re-open the board setup window will crash the entire KiCad process.

And a minor nitpick: The rule syntax help tells me about the existence of a version tag, but neither that it’s required nor what the expected value is (i.e. which version of the syntax is being described there). For the above I was using version 1.

Side question: Is it possible to just update the relevant parts of KiCad to track nightlies without having to re-download and install the whole parts library every day?

For Windows there is a …x86_64-lite.exe without the libraries. When installing you get the option to install demos and/or footprint wizzards or neither.
For other OSs I do not know.

The crash is a bug when trying to tell you the layer wasn’t recognized. (I’m about to merge a fix.)

The wildcard is fine, but Cu has a lowercase ‘u’.

FWIW, there are also inner and outer keywords so you don’t have to use wildcards for this – but you can and they should work.

We don’t have any code which looks at the version yet (as there’s only one), but “1” would be the safest to use.

1 Like

Current nightly appears to crash if I have a condition containing


with B being a pad and A a track.
Not sure if this is supposed to work or how to correctly handle the different pad types (SMT vs. PTH) in layer checks.