AuxPower1U: Main Controller PCB

This is a post 10 in the series (previous: Switching the High Voltage).


Well, after many posts about my AuxPower1U project, it came time to show the star - the main controller board. Its function is to pass voltage from input to output, interrupting it when necessary.

Due to cost and limited space for actual mounting, I first defined the size. Since I wanted to use Phoenix MC connectors, the width had to be 90mm in order to accommodate 5 4-pin outputs. Since I will be mounting power supplies on its right side, all 5 2-pin inputs will go there. On the bottom, I have 5 3-pin connectors for a switch and its LEDs, so the height ended up being 90mm too. And yes, that's under 100x100 mm limit that stays within PCBWay's $5 offering.

That said, mounting the board, which is 90x90 mm, would be problematic since it almost touches my power supplies. To avoid having everything too crowded, there is a 30 mm deep cutout allowing for much easier plugging and unplugging. And yes, that did make routing slightly more complicated thus requiring slightly narrower traces than I would usually prefer.

Upload to PCBWay was as easy as always and I probably had my order ready in 10 minutes. Manufacturing was a bit slower for blue PCB I decided to get, so you mgiht want to go with green soldermask if speed is of essence.

PCBs that arrived from PCBWay were as good as always. I opted for a standard HASL surface since I didn't use any troublesome components. The smallest pitch on my board was 0.5 mm and PCBWay's HASL is more than sufficient for this. There was an option to go with 2oz on the the board but I opted to use wider traces instead. Yes, a 2oz pour is better for temperature, but it does bring the price signigicantly up.

PCBWay offers FR-4 at their baseline PCB material and, during my testing, I went over 100°C for multiple hours with multiple cool-down cycles. There was no sign of delamination and thus I am fairly comfortable this PCB will handle all the power I need without any issue, especially since there will be fan cooling it down. Furthermore, since I do measure current, firmware can easily cut off power if things go crazy.

All connectors and status LEDs are on the top of the PCB, with the actual chips delegated to the bottom. I believe this gives it a better look overall and greatly reduces the chance of me accidentally knocking a component off udring installation. As you can see, this whole thing sits in a PCB case with a brace holding it down. What you don't see are the holes underneeth, alowing for air to pass.

On top, there are also UART and I2C connectors. The UART connector goes into a 2.5mm audio jack, allowing me to both connect and control the device via computer. The I2C connector goes to an OLED display, which provides a bit more feedback than just buttons on its older sibling ResetBox had. Both are really optional for the functioning of the device but they're a nice addition to have.

On the electronics side, everything is driven by a PIC18F26K83. I had a few leftover from the previous project so I decided to use it despite not having sufficient pin count for what I wanted. I wanted to measure voltage and current (5 pins each), react on buttons (5 pins), control button LEDs (5 pins), control the output (5 pins), use UART (2 pins), I2C (2 pins), and a few auxiliary functions (e.g., temperature). Add ICSP, and it's clear that the PIC doesn't have enough pins. But an IO expander does.

So, PI4IOE5V6416LEX got the duty of controlling output, buttons, and LEDs, while ADC measurement and communication were left to PIC. The only loss of functionality was LED dimming, which I used to indicate different states before. However, I can still do blinking, and having an OLED actually alleviated the need for dimming greatly.

One downside is that, if I2C communication goes down, so does my capability of turning outputs on and off. With a benefit of hindsight, I should have probably kept the outputs on the PIC - I even had exactly 5 pins extra available. But that thought only occurred to me after I both designed the board and wrote the majority of the firmware. Since testing didn't show any issues with I2C despite my best efforts to break it, I will keep that change for potential revision C.

Revision C? That implies that my current board is revision B, and thus it follows that something bad happened to revision A. Well, story of mistakes will follow in the next blog post.

Using Linux MPLAB X IDE on High-DPI Screen

These days scaling usually works even under Linux. However, there are always a few stubborn applications that evade scaling and unfortunately one of them is MPLAB X IDE I use for PIC microcontroller development.

While there are instructions on how to deal with it under Windows, it doesn't really explain how to get an equivalent behavior under Linux other than running executable directly.

But, you can use the same fontsize trick on Linux too and make your life easier by modifying the desktop file manually. Just run the following command:

sudo sed -i -E 's|Exec=(.*)mplab_ide.*|Exec=\1mplab_ide --fontsize 17|' \
    /usr/share/applications/mplab_ide-v6.20.desktop

Assuming your version is 6.20 (otherwise adjust as needed), you will get everything sized about 50% larger (default font size is 11). Now your eyes can finally relax.

.NET Plugins Without a Common Assembly

For a new project of mine, I wanted to use a plugin architecture. Since it had been a while since I did plugins in .NET the last time, I wanted to see what's new in .NET 8. Well, no news at all - plugins for .NET application are literally the same as they always were.

Don't misunderstand me, there were some steps forward. For one, there is a working example showing you exactly how it's done. And honestly, that is an example you should use. However, this is the same way we did it back in .NET 2.0 days.

And yes, I am a bit unfair since there were a lot of upgrades in the backend and .NET 8 will give you more options on how to load stuff. Let's not even get into performance improvements. However, I still have to create a common assembly that inevitably becomes a hell to maintain. And what about single-file publishing? Nope, still not supported.

While I was ok doing it the classical-style, I really hated not having a single-file, self-contained deployment. They are just so freeing when it comes to actual deployments and worth every additional byte they consume. And, since the whole framework is bundled in a single package, there is no real reason why it cannot be done. Is there?

Well, I decided to give it a try.

But before dealing with single-file deployments, what about removing the need for common assembly? Well, if you can get away with simple Get/Set interface that returns objects that can then use other standard interfaces; or, said plainly, if you can get away with forwarding standard .NET classes/interfaces, answer as always lies in good old IDesignerOptionService.

While quite a lot of interfaces you could use for plugins got trimmed with time (especially during the Windows Forms exodus), this one somehow survived. And it's almost perfect for lously-coupled plugins. It gives you two methods: get and set. Thus, you can simply use something like that:

public class MyPlugin : IDesignerOptionService {

    public object GetOptionValue(string pageName, string valueName) {
        switch (pageName) {
            // do something that returns object
        }
    }

    public void SetOptionValue(string pageName, string valueName, object value) {
        switch (pageName) {
            // do something that with object
        }
    }

}

As long as you stick to built-in objects (or you're willing to do a lot of reflection), you're golden. I agree, there is a performance impact and design is not as clean as it could be, but I would argue it's quite often worth it since we don't have to deal with common assembly versioning and all the fun that can cause.

Thus, that only leaves single-file deployment as our goal. Is it really not supported?

Indeed, if you try to make a single-file deployment of the plugin dll, it will say that you cannot do that unless OutputType is Exe. And, if you try to combine that with common PluginBase assembly, it will not be able to load anything because PluginBase as a separate assembly is not the same as PluginBase that got packed. However, if you are ok with this janky IDesignerOptionService setup, you can make your host a single-file application.

And remember, the whole .NET is essentially packed there so this application (assuming you didn't trim it), will have no issues loading our plugin DLLs.

So, to summarize, you can have your host application deployed as a single file (only the executable is needed) and then load any class from plugin dll that implements IDesignerOptionService interface. Such class will then use .NET from a host itself to run without .NET being installed separately.

To see it in action, [download the example](). Don't forget to run Make.sh in order to copy files around.

AuxPower1U: Switching the High Voltage

This is a post 9 in the series (previous: Fan Controller, next: Main Controller PCB).


Using a MOSFET as a switch is easy. Select any P-MOSFET, make sure it works at your board's logic level, supports enough sweet amps, and you're golden. I can almost guarantee that any MOSFET that satisfies those parameters will be good enough. Just pull it down to earth when you want lights to go out.

However, this doesn't work for high-voltage DC circuits. Now, people can disagree on where the "high voltage" begins. When it comes to switching DC power, for me that limit is somewhere around 20V. This is the limit where you cannot use "normal" components without care, nor can you expect your circuits that worked just fine to continue operating. It's the land of magic smoke.

For AuxPower1U, power supplies go up to 60V. And it's not hard to find a MOSFET that goes that high. However, driving that MOSFET is another story. In order for it to be fully off, you cannot just use 5V - that's not high enough to turn the MOSFET off if there's 60V passing through it.

A simple solution is just pulling the gate up to your switched voltage - 60V will definitely turn it off. The only problem is that this also brings 60V at
your microcontroller's doorstep. But, with a bit of thought, you can see it's not a catastrophic issue - an optocoupler or even a simple transistor will provide enough isolation to keep the microcontroller happy.

But more devious problem lurks underneath - often overlooked Vgs specification. Most of the time, you only get a 20V difference between gate and source to play with. In practice, to drive 60V, you can only go as low as 40V on the gate. Going all the way to ground is definitely out of question.

To resolve this, we can (ab)use the fact that a MOSFET has quite a high input impedance. Thus, a humble voltage divider will allow us to keep it at just below 20V of difference. In a 60V case, that means 10K/24K resistor values resulting in about 18V of voltage difference. If we want to be extra safe, placing a zener diode will further limit the maximum voltage. Ideally, you want the zener's voltage rating to be slightly above the expected voltage (while still under 20V) in order to minimize power usage. In this case, an 18V zener will do nicely since the voltage divider sits just under that voltage.

Making this circuit usable for many different voltages involves a decision on the minimum voltage and setting up a voltage divider to the minimum viable Vgs value. We expect the zener to "clip" higher voltages so that's the only calculation you need. Zener's power rating is not really important in this case since the currents involved are low enough.

Of course, having a working switch is just the start of the story. Depending on your needs, you might need to fiddle with the circuit a bit. For example, increasing resistance lowers power usage but it might not work properly over the whole range (moslty dependant on the MOSFET input leakage). And let's not even go into what happens if we want to do fast switching.

This is a generic, high-voltage MOSFET driving circuit intended for "slow" switching of DC voltage, and it's a good starting point.


PS: Yes, I know that I am missing a minus (-) sign in front of many voltages since we are dealing with P-MOSTFETs. I decided to remove them for clarity.