Pendant Development

Just realized I probably didn’t actually answer your question.

In terms of how hard is it to get CAN working? At a basic level I’d say not ‘that’ much harder, but it’s much more open so it depends on what you’re trying to do with it.

I2C, chances are you’re hooking up signals from to the microcontroller to a device and using a library on the microcontroller that handles the hardware setup and control, which is normally just pin definitions and clock rate. From there, it’s looking at the documentation on the device, figuring out the address and then calling functions that will read/write the appropriate data to that address. Pretty easy, not a whole lot to go wrong.

Fundamentally, CAN won’t be that different. You’re hooking up signals from the microcontroller to a CAN transceiver and likely out onto a wire, then connecting that wire to other CAN devices. You’ll still use a library that sets up the CAN hardware for you. From there it gets a little trickier, in my experience. The hardware operates much more ‘in the background’, so instead of requesting data, you’re waiting for new messages to arrive or firing an interrupt when they do. There are also a lot more configuration options in terms of bit timing, potentially needing to define which address masks are being listened for, potentially setting up multiple different mailboxes to listen for specific messages. Some of this may be specific to the hardware I’ve used and may not be the ‘common’ generic implementation, I’m not sure. You also may need to define things like which messages will get acked etc.

If you’re using a pre-existing CAN device then it probably spits out frames at a specific rate and with pre-defined addresses. Reading data from those should be pretty straight forward. You’d define a CAN message that would be sent out (address, data loadout to match what was documented, send via a function) or define a message ID to listen for and then an interrupt handler (or wait loop) to act on that incoming frame, unpack it and do something with the received info.

If you’re using it in a situation where you’re talking between 2 devices, it’s much the same as above but you need to go through and define the message structure itself. At the simplest level this is easy, but it can get complex. Ideally you’d pay attention to which addresses you’re using, because lower numbered addresses have higher priority and will ‘win’ arbitration processes more often. You’d define frame repetition rates so that low update rate data might be 1 or 10Hz while fast update rate data might be up to 100Hz or beyond. You’d be checking that to make sure that you’re not overloading the bus and blocking the lower priority frames from transmitting, as well as having defined timeouts after which you flag an error due to a loss of communications to the other device. You’d need to make sure that both ends are using the same endianness and byte order, otherwise things can get real weird.

One nice thing about CAN is that due to it being a somewhat ‘higher level’ interface than I2C, there are a lot of options for mucking about with it. It’s relatively straightforward to use a PC with a USB-CAN interface to pretend to be a sensor or controller, for instance. We will often set up a project in PCAN Developer which pretends to be a device that we’re connecting to. That way instead of needing to test on an actual vehicle where we might not be able to make the battery management system do everything we want, instead we can end up with a slightly janky interface full of buttons and sliders that lets us set any values to anything we want. That way it’s a lot easier to test the firmware interfaces and that things like protection modes work, response times are good enough, error handling makes sense, etc.

So yeah, I’m still not sure I actually answered that question. I guess I’d say definitely more complex, but also some of that is just because you have a LOT more freedom with CAN, which brings with it its own complexity.

2 Likes

CAN sends 8 bytes in each message. That makes it tricky for gcode. Some commands, like G1 X100 are less than 8. But G1 X12.1234 Y1.234 F376.458 are not

I think that also makes the I2C overly complicated. Whatever you make would be more generally useful if the grbl/marlin side was just 5V(3.3V tolerant, ideally) uart at 112500 or 250000 baud. Any higher voltages or different protocol means you either have to have a special kind of grbl or you need a translator chip in between.

Having a translator that collected multiple CAN messages into a stream of gcode would work. But it is more conplicated and adds more parts. The big benefit is noise rejection. But I would wait to see a problem before I tried to fix it.

Appreciate all the CAN info, learning lots, cheers!

Sounds like CAN is better suited for sending sensor on/off/position/orientation/other information easy to represent in small payloads. Maybe GCODE generation happens within an MCU on the IO port Expander, or the JackPot ESP32 even (providing additional Pendant specific interrupts/compute won’t impact/destabilize JackPot ESP32’s core CNC/whatever processing)?

Stepping back from CAN, and up above protocols for a bit… Sounded like Jamie’s going with UART/Serial for MVP? Curious what required features and functions the Pendant must/should have? Just multi-axis-joysticks, knobs, dials and button sensors, or will there be a read/touch display, any other ways for the User and/or Software to interact with the main Controller?

Where will mapping of sensor state to gcode generation happen? Within FluidNC similar to Marlin’s Joystick implementation, or will Pendant’s MCU, and/or MCU on the IO expander… generate gcode from the sensor state?

Guessing User won’t be explicitly entering GCode for a v1 MVP, they’d probably be better off using a wifi tablet+keyboard setup with FluidNC’s existing webui in that case.

CAN is specifically designed around frequently updated individual values. So in this case it would be typically be used for things like the joystick positions, not direct machine control. You wouldn’t send gcode over it because that’s something that has been entirely devised around a serial stream. Instead, you’d do something like define a frame that was a movement command and then do something like X position, Y position, Z position, all as 16 bit values and then a command value. Or if you needed more precision, have multiple frames to set the next position/feed rate and then another frame that updated a flag to ‘execute’ the move. That’s what I mean with CAN requiring a different kinda thought process that makes it a bit tricky.

On the other hand, if you just want to communicate a bunch of info about a system in a straightforward manner, it’s great for that. A frame could have a 100Hz update rate with current position, temperatures, IO status, all sorts and you’d just watch those frames come in and update local variables as required, no issues. With some more complex hardware blocks on fancier microcontrollers, you can basically just treat it almost like a long-distance DMA setup.

@azab2c I think the existence of web UIs is probably a good way to keep a lid on some of the complexity and feature creep. At some point, there will be functions that are probably more suited to a menu or touchscreen setup than dedicated buttons on a hardware controller, I’d say.

2 Likes

2 Likes

The current plan is to move all of the sensor detection into an external MCU, and the host, whether FluidNC or Marlin will get information via serial. A custom non-gcode serial connection could be done but I think sending gcode commands (and adding gcode commands where necessary) can accomplish almost everything that can be done with a custom serial, provided there is a facility for queue-jumping immediate processing.

My analog joystick for Marlin could be implemented through g-code if there were a way to:

  • Perform relative move without switching between G91 (relative) and G90 (absolute) state and switching back. (Grbl has this with jog commands)
  • Query queue depth to control latency by adjusting the rate of issuing commands

That’s basically it for the joystick but for the pendant I’m wanting a lot more functionality.

Buttons and handwheel are pretty self-explanatory as far as what they should do.

I also want instant feedrate adjustment. The use-case for going slow and for going fast are somewhat different, so I was thinking two knobs. One for going slow (0 to 100%) and the other for going fast (1x to maybe 5x). The slow knob would double as pause function, and by turning the knob within maybe 0.5 seconds you can stop and start without losing steps from excessive acceleration. Or if things are going poorly you can reduce the feed rate. The go-fast knob is if you turn out to have chosen a conservative feed rate and you want to see how fast you can go before the router starts making unhappy sounds. You can turn it up and then back off a bit. The slow (0 to 100%) and fast (1x to 5x) knobs are multiplied together so you can still pause and resume if you are going in overdrive.

These are straightforward enough to turn into (new) gcode commands, but the receiving end might be a challenge.

3 Likes

Okay, I think this is getting pretty close to done:

I/O Expander uses two one-bit translator instead of bidirectional.

I put only one 100nf cap per supply for both translators instead of one each. I’m thinking that’s okay this time.

The pendant now has two port expanders on the I2C bus, configured with different addresses where the ADDR pin allows two devices on one bus.

I addition, I mapped the remaining three Arduino pins to three more I/O headers, so they can be used as extra buttons/switches/LEDs, or they would also be available for a future SPI device. So there are 19 pins in total available for buttons or LEDs.

I also dropped the 5V connection from FTDI for simplicity, and I added a NC jumper on the Arduino supply that you can cut if desired. This allows plugging two pendant boards into two computers via USB and connecting them to each other with an ethernet crossover cable, and one computer can generate keyboard/mouse inputs for the other. That’s a separate project someday (maybe never).

I trimmed the I/O Expander board to be a bit shorter but still long enough to be supported by the standoff
image

The pendant board is pretty dense but the auto-router found paths on only two layers, so I guess it’s fine. I didn’t forget the mounting holes and I also rounded corners. The overall dimensions are only 67 mm x 40.6 mm.

If there are no major errors, I’m ready to order these!

3 Likes

I would definitely use one decoupling cap per translator IC. The goal is to have one capacitor as physically close to the power/ground terminals as possible (ideally within a mm or 2, 5mm total ‘path’ length) so that the higher frequency components of a fast edge rate will be supplied from that capacitor, rather than from one further away down a higher inductance path that will cause the supply voltage to drop briefly (or the ground node to rise briefly) on transition. It’s a geometric consideration more than it is an electrical/schematic based consideration. If you end up with 2 decoupling caps that are basically right next to each other than you could remove one, but I wouldn’t bother. 100nF capacitors are probably the cheapest and most commonly made part on the board, so they’re likely less than a cent each.

I would also use decoupling caps every place that there’s a VCC signal going out on a header, typically. Partly for decoupling, partly to filter any noise from coming back down the cables and into your supply lines, which isn’t that different of a purpose to decoupling, really. For the banks of headers like H1, H16, H5 then I’d just put a single one there.

Just a weird thought with the layout of those headers, in future I’d probably do them as 8 instances of 1x3 headers to closer match the ‘intention’ of their use. That way you’re guaranteed that each header will be the correct dimensions because they’re a single part, you’ll have flexibility to move them around a little if needed and it will make the schematic much more readable, which is key to avoiding mistakes. I wouldn’t change it now. It’s baking my brain a little, though.

With header H6, where was that heading to? I’ve lost the plot a little bit with this design, sorry. I ask because it doesn’t currently have a ground net routed to it.

Was this just a test to see how it turned out? Auto-routers typically turn out designs that are ‘maybe’ DC correct but almost never good enough to actually attempt to use, in my experience.

I would always strongly, strongly encourage things to be hand routed. On simple boards it may not matter, but the only way you can tell whether it matters or not is by getting the boards back and testing them. Signal integrity failures are the worst to debug and will just be ‘the board works fine most of the time, then it doesn’t’. These are the failures that can soak a lot of time to find.

The other thing is that on simple boards, you might as well use those to develop the skills needed to do more complicated boards. I would have said that the pendant board already has enough routing on it to be quite complex to do well in a 2 layer board, just due to the number of traces.

This will also give you a feel for what the tradeoff is when adding extra stuff to soak up unused pins and how to do it effectively. Adding block headers like that is great for functionality, but it adds a lot of routing complexity. If I’m not sure I’ll use it, I’ll typically add them as single through-hole test points. That lets me wire something up manually if I need to use them and then I can add the proper hardware in a future revision if needed, without making the planned-for design significantly worse.

In terms of the issues with the above board, it comes back to the same stuff I was writing about in the 6-pack thread. For every single signal, you should be able to go through and draw a loop for where the current will flow. Even digital IO signals will have current flowing because input pins have capacitance, so every time a signal changes state, a small high-frequency burst of current will flow between the input and output pins on a net. That current will also have a closed loop path back to where it came from. The goal is to make that path as low inductance as possible, which we do by making the loop area as small as possible. Looking at some of those ground traces, the loop area is huge, which means that any current in the loop will radiate off the board and cause noise in the adjacent loops, as well as any noise externally (like a brushed router that’s basically a broadband noise generator, for instance) will be picked up by those loops like they’re an antenna.

My approach to routing a board like that would be to forget about the ground connections for the moment, try to route all the signal connections cleanly first, then get all the power connections routed, then go through and pour a ground polygon on the top and bottom layers to provide the power/signal return path. Try to keep connections to the top layer wherever possible. If you need to use the bottom layer, try to do it for brief hops then come back up to the top so you’re not cutting ‘slots’ in it. Try to group signals together so that you can get big unbroken chunks of ground plane. Then add vias everywhere that you can.

Other than that, is looks pretty good. I would also try to move all the designators on the silk layer so that they’re not touching any other silk and so that they’re not over the top of pads. I also try to keep them all the same orientation as the component (where it makes sense), as well as all in one of 2 orientations, so that they’re all either 0 degrees or 90 degrees for instance.

3 Likes

It is really awesome to see the terrific spread of talent in here! Bravo to you 2!

5 Likes

If the commands were “interruptible”, then you wouldn’t need this.

If you can say, “Go X+10mm” and then after it travels 5mm say, “No, Go X-5mm” or “stop”. That would also work. You need to make aure the user can change directions quickly. Your solution is to not send commands far enough in the future for the user to notice. My solution is to abort commands mid-execution.

I think grbl does the latter. But I may be mistaken.

Getting position feedback would also be nice, in case you also wanted something like a DRO. It is frustrating to me that gcode is so “standard” and the feedback messages make no effort to be standard at all. Marlin has some trouble computing real time position updates. But still, the format is 100% different than grbl. And neither standard is generic enough.

1 Like

Ok. I can easily add two more caps for the one-per-IC (per supply) rule but I’d like to learn if this is a valid exception.

This part of the circuit is the two single-signal voltage translators:

Which is this part of the layout:
image

They are already pretty close to the ICs and I could double the value just as easily, instead of making two adjacent capacitors. My other thought was that each level shifter should mostly only draw from one of the supplies (I guess that’s an assumption about how they work internally), so they are not doubling the load.

To be clear, I’m not arguing for one capacitor per IC (per supply) per se, I’m just wondering if my thinking is wrong.

I had hand-routed boards in the past in Eagle CAD entirely for fun, like a game of Tetris, but the problem is that the criterion for success was whether I can cram in all the stuff and obey the DRC. I don’t know if the signal quality is any good. I don’t know if I can effectively develop skills if there is not a “signal quality score” feedback that I can optimize. That would make it like a game again and I would have a chance.

My other thought is that everything is pretty low speed and low current, so I’m hoping a “DC” layout is going to be pretty decent. I want to be mindful of not getting “stuck” on optimizing too much, and I feel like this is entering diminishing returns, so I think I will proceed as-is, though I did clean up the silkscreen a bit and filled with ground planes top and bottom:

The 3D render showed silkscreen over top of the solder pads which seems strange to me. I don’t know if this is real or if the manufacturer will maintain solder pads clear from silkscreen, but anyway I moved them so all the pads are clear now.

H6 is a rotary switch to select between “off” and “Wheel X”, “Wheel Y”, “Wheel Z”, and “Joystick”.
H2 is OLED, H7 is encoder wheel, H3 is analog XYZ and two knobs, and H12 is for the FTDI. I don’t have a dedicated port for selecting between low/medium/high jogging speed, but I can use some of the 19 available generic pins for that.

There is definitely merit to this and I think in my skimming I had read something about Grbl maybe doing this. Marlin has no way to modify the queue except for blowing everything catastrophically, so for Marlin the choice was made for me.

I think there may also be a difference between an analog joystick and an on/off fixed rate jog button. Releasing the jog button should stop quickly with the lowest latency and aborting queued commands is definitely on the table. Changing speed from +50% to +52% on the analog joystick, it is less obvious whether aborting some of the queue is advantageous. I will have to think about that.

There is also room for improvement more broadly. I don’t normally notice, but if I’m moving in +X and then move the joystick to move diagonally +X+Y, the machine will ‘stutter’ a bit and slow down before moving diagonally. I suspect this is due to a “sharp” corner that has a reduced top speed, whereas an arc could perhaps maintain speed. This is some work to calculate though, so it will probably come last.

2 Likes

Good catch, I should have clarified that this is a ‘per IC’ thing. I think there probably is a difference for the level shifters where the output side is more critical because it will be supplying current into the line to charge any downstream capacitance, but there are definite internal state changes on the input side that will need brief current pulses supplied. The capacitors also work to provide what is basically a high-frequency short circuit between the voltage rail and the ground connection. In a 2 layer board with only a ground plane then this isn’t as important, but it can make a big difference for a 4 layer board where both the +V plane and GND plane can be equally valid return paths.

It’s not so much a capacity limitation as it is a series inductance limitation. The goal is to have the lowest inductance possible for a few reasons. One is so that the capacitor works at the broadest range of frequencies that way, because the inductance between the chip and the capacitor forms an LC filter. For the same capacitance, higher L will make the corner frequency of that LC filter lower, meaning that the supply voltage doesn’t really exist for that frequency. Adding more C can help with that, but larger values of C typically have worse frequency performance so that’s a losing battle. Another reason is also avoiding shared inductance between multiple ICs where one IC drawing a pulse of current will reflect as a voltage shift on the supply pin of the adjacent IC.

The ‘one cap per IC’ is certainly a very rough rule of thumb. If I were placing the cap in the same location for 2 ICs, I would definitely consider consolidating them into one. In the case you’ve shown there, I’d already be moving those caps so they were closer to the power pins and then routing signals under them. Sometimes I just keep them in place if it won’t cause an issue, because they’re not really a driver of board size or board cost, it’s just layout time really and sometimes making that change and justifying it costs more than keeping them there. The other thing is that having both there means that you can adjust the layout without needing to then go back and add them back in.

So yeah, that could be an exception for the caps connected to pin 1. For the cap connected to pin 6 on U2, I’d say that was poor placement for the decoupling cap and try to move it closer.

I don’t think your thinking is wrong at all, I think you’re on the right path, it’s just normally something that’s such a base level requirement that I don’t bother trying to optimize for it. This is more a personal thing, but I tend to take the approach that there’s a limited number of details that I can keep in my head about a design at once, so I like to expend effort on things that might be impactful overall. If someone has to take the time to explain to me in a design review why something is missing a decoupling capacitor then chances are we’ve already spent more money than omitting the decoupling capacitor will save, unless we’re making 10M+ per year.

Well, that’s kinda why I’m here, and why it might be worth hopping on Discord at some point. The fundamentals are actually remarkably straightforward, they can just be a little difficult to explain in text. Basically, it’s just minimizing loop area of signals, fundamentally. Learning to figure out what the high frequency return path of a signal is and being able to draw it on a printout from the board will give you a good start to know what’s good and what isn’t. I’d say that the Jackpot board went from some super questionable signal integrity in specific parts of the board to actually pretty good in only a few short revisions.

The thing is, you don’t need to aim for perfect, you just need to aim for ‘plausibly good enough’ to start with. A lot of it is just being able to identify what’s bad (large loops in the current path) and then doing whatever to improve them. Once you’ve improved them beyond your ability to see any better way forward, that’s probably good enough to get reviewed by someone else who may have other suggestions or insights, etc. The goal isn’t to go from amateur to passing a hardcore EMI/EMC testing suite first try, the goal is to build a solid enough base that you’re not definitely causing problems. The auto-routed layout above DEFINITELY will have problems. Whether those problems are bad enough to cause the design to work or not is unknown until you try it.

Oh for sure, there’s nothing super critical here, but they key thing is that if everything were DC then nothing would change state. It’s also not just about the signals themselves, it’s about the signal integrity and noise immunity. If a circuit is super low frequency with slow edge rates and in an electrically quiet environment then no worries. If it’s super low frequency with slow edge rates and in an electrically noisy environment then you can still have issues despite the design itself being simple.

Fair enough. I don’t think of this as ‘optimizing’ so much as ‘avoiding mistakes that can waste money and hours of time tracking down’. You can definitely always just give it a shot and see how it turns out. Hopefully it works out well enough. I’d also say that if you don’t try on the simple stuff, you don’t develop skills to move to harder stuff. All down to what your goals are here, of course :slight_smile:

Typically, I would place silkscreen so that they don’t touch and lines don’t run over the top of designators. They don’t need to be exactly beside the component, they just need to be somewhere that it’s obvious which component they’re referring to.

For H6, you’re relying on internal pull-downs, then? Typically, switches would be active-low, passively pulled high. For that, you need a GND to link to.

2 Likes

Great, thank you for taking the time. The capacitor thing looks like it’s also a reason for manual routing because even though the capacitors are “close” to the level shifters, the auto-route took the long way that defeated the purpose of keeping them close.

As for the H6 header for the rotary switch, I’m depending on the Arduino’s ability to assign pull-downs (or pull-ups) on all the inputs, so external ones aren’t needed.

I’ll give it a go with manual routing and see how it goes.

2 Likes

Yeah, that’s kinda the thing. Auto-routers get used a decent amount in industry, but usually when there are other constraints controlling them like length matching, controlled impedances, that kinda thing. They’re very much a garbage-in, garbage-out kinda scenario and I think.

Right, most of the ones I’ve worked with are older Atmel chips with only configurable pull-ups.

Very happy to hear that. If you run into issues, don’t worry. It’s a very iterative process and often it’s a case of routing the easiest stuff first, then going back and moving/ripping until the harder stuff fits. Don’t sweat it if the +V rails are kinda crazy paths, they don’t need to be ‘good’, just connected. It’s also worth keeping in mind what the ‘extra’ bits are that can be moved or split into individual test points if routing gets overly complex. I also often end up moving the traces to different GPIO once I start routing as usually it’s a lot easier to reconfigure pin definitions than it is to have a bunch of wires that need to flip around each other a bunch.

Just remember the goals of keeping as much stuff on the top as possible and, where possible, keeping traces running side by side.

1 Like

Ok, so this was not nearly as bad as I thought it would be. The auto-router had to think for a while, so I thought I was going to have a hard time finding a route, but it was really pretty easy and it went quickly.

Here’s the top with lots of straight, side-by-side traces:

And the bottom doesn’t need a lot, just a few short hops except for VCC on H8 and H10 and the pullup resistors:

I see what you mean about reassigning pins is sometimes easier than an awkward routing. I might have gotten a better layout with some exchanges but it seemed ok so I left it.

I double checked the pull-down for the Arduino and I’m glad I checked. Only pull-up is supported, so I also changed H6 to provide GND instead of VCC. Nice catch!

I’m pretty confident in the IO Expander module but here it is since I don’t know what I might not be seeing:

And the bottom just has two jumps:

2 Likes

I was thinking about that earlier. I’ve used more complex micros that support pull up/pull down, variable drive strength pins, all sorts. I was going to ask which Arduino you’re using and double check that. When in doubt, active low, passively pulled high is kinda the defacto standard.

The next thing I would do with that layout is to try move some traces to shorten those ‘dogbones’ (the small lengths on the bottom that ‘hop’ the top side traces) and move them around to get a little bit of copper in between some of them. This works to avoid the bottom side traces cutting big slots in the ground plane forces return signals to go way out of their way around the outside of them.

I’d try get some bottom copper where I’ve drawn in green here:

So the next thing is to put vias everywhere. I usually put one as close as possible to the gnd pins of the ICs. Then think of the vias as using the other side plane to connect the plane ‘across’ the slots cut by traces, so there should be ones at every junction, plus periodically along a track.

image
That’s something like what I’d end up doing.

Then just do something similar for the pendant board.

That’s starting to look pretty good.

2 Likes

Oh, and definitely try to break up that big power distribution trace along the bottom if possible, even if it needs to run a slightly weirder route.

As an example, I picked one of the signals and traced it in green.

Whenever that signal changes state, a pulse of high frequency current will follow the lowest inductance path back to the gnd on the micro. In this case, it’s following the yellow path, which is pretty meandering. The goal is to try to allow the return path current to flow as close to the forward path current as possible, because that’s the lowest inductance path.


Changing the power trace for those connections to something like this will free up that path entirely.

Leading to something like this:


Where the return current will run directly under the trace for the most part, leading to lower inductance which means cleaner rising/falling edges, more noise immunity, lower EMC, less interference with other traces etc.

5 Likes

For me changing the plane/copper area settings from “spoke” to “direct” makes this type of thing go away and seemed to help me with routing and spotting odd mistakes.

Screenshot 2023-07-10 065150

Don’t forget to add some flair to your silkscreen, do you have a name yet?

I can’t wait to see how this goes. Next up is pendant hardware design…

6 Likes

The spokes are there to provide ‘thermal relief’ for soldering. The idea is that if the plane is directly connected to the pads, it’s much harder to heat the entire barrel of the through-hole and get solder to flow through. Having solder flowing all the way through the entire barrel is quite important for robustness of the joint long term.

Personally, I just tend to direct-connect everything and use a better iron for soldering or pre-heat the board if I need to, but I’m often dealing with high current applications. It’s definitely a good idea to have the thermal reliefs though, especially on multi-layer boards.

Typically, if I was using thermal reliefs (sometimes called spokes, as you say, or wagon wheels) then I’ll use the same size for the plane pullback and the width of the trace, so 0.3mm traces and 0.3mm pullback, 0.5mm traces and 0.5mm pullback, etc. It looks to me like the traces of those thermal reliefs are probably too wide.

5 Likes

Now the VCC net looks like this, much more tree-like for shorter, straighter paths:

And the back side has no big slices, only smaller openings, except for that string of 7 consecutive pins which I couldn’t figure out how to break up.

I also changed out the socket for two female headers since the BOM was showing parts unavailable.

Also I changed out the jumper for a ghetto do-it-yourself cut trace because it was complaining about DRC and also complaining in the BOM so I just drew it by hand.

Also turns out I made a mistake on the TX/RX filtering capacitors so now I’ve corrected it with your earlier suggestion of 1nF and 100R.

I am also realizing the analog signals from potentiometers could be perhaps be noisy when they move, and I’m tempted to add a capacitor on each line such that a 10k pot would filter to maybe 1 kHz or something. But at the same time I don’t want to be tweaking and adding things forever. I know that forever never ends, but how do I know when forever begins?

2 Likes