Showing posts with label usb. Show all posts
Showing posts with label usb. Show all posts

2018-12-09

Connecting a USB serial console to WRT1900ACS


Goal

A while ago I purchased a Linksys WRT1900ACS-v2 router to replace my aging 15-years firewall (still running kernel 2.4 on an old VIA Eden board!). This device is pretty nice, it's fully supported by Linux mainline, it offers multi-gigabit connectivity with a real CPU (Marvell Armada 385), has lots of RAM (512 MB) and storage (256 MB NAND), and dual-band WiFi. Yes I know, having NAND flash nowadays instead of eMMC is still annoying to deal with, but I won't need to write often, so I certainly can ignore wear leveling since I'll only be loading the rootfs into RAM. This will be plenty of room to run Formilux with nftables.

I don't have much time to devote to its conversion and I figured that if it's still not in production, it's because I don't want to switch to it before I'm 100% confident about the config and it doesn't have an accessible serial console to allow me to recover from my mistakes. Thus I decided to work on exposing a serial console before finishing its configuration.

Serial Connector

Linksys engineers were really cool with this device, you don't need a soldering iron as they already placed the connector inside. You have remove the screws under the rubber pads and strongly pull apart the blue from the black parts to access it.



There are still a few caveats though :
  • the connector is a 2.0mm pitch connector (JST-PH-2.0 to be precise)
  • the on-board marking is reversed compared to the connector's specification, which creates a lot of confusion and can easily fry an adapter since the power pins are at both ends
  • there is something strange with the Tx output, the device refuses to boot if it detects too strong a pull-up (4.7kohm is too strong). I suspect the device tries to pull the line low during boot to detect such a condition in order to stop in debugging mode or something like this.
Thus it is not as trivial as it seems to simply place the connector outside.

After measuring the voltage on the pins and doing a few attempts, I finally came up with this pin-out :


That's fine, I don't need the +3.3V since I intend to connect this to a USB serial adapter which is alimented by the USB bus. So I can use a 4-pin connector which will cover the connector's pins 1 to 4 (motherboard pins 3 to 6). Such 4-pin connectors are easily found with many motherboards which provide a sound connector for the CD/DVD drive. It's the same! Yes it only has 3 wires but that's what we need : GND, Rx, Tx.


Serial adapter

I picked a CH340G-based micro-USB to TTL adapter like this one, which supports working on 3V or 5V (I've set it to 3V) :



Connecting this adapter to the connector revealed the issue with the too strong pull-UP. So I decided to try to attack it various ways. First, I cannot replace the pull-up on the adapter because it's inside the chip itself. In the end, the easiest and most reliable solutions I found were to use either a 2N4403 PNP transistor or a low voltage AO3407 P-channel MOSFET with a much weaker pull-up. These ones would amplify the WRT's Tx pin negative signal to act  stronger on the adapter's Tx input pin. I tried the two following diagrams and finally decided on the MOSFET one since it features an even weaker pull-up :



Since I had to add components to the board, I wouldn't be able to use the existing 6-pin connector, so I desoldered it to make the PCB thinner. Be careful, on mine the Tx PCB pad went off. Fortunately it's didn't serve as a via and is not used, it just made my task a bit more complicated to figure what pin the signal was going to :



Then I noted the soldered the MOSFET and the resistor on the PCB close to the IC :



And connected the extremity of the wires there. Note if you reproduce this design, I left far too long wires, you could shorten them to 15 cm I think.



Drilling a hole

Every device needs to have at least one hole for a console connector :-)

It wasn't easy to find an accessible place for this connector. I tried to place it in front, but this required disassembling the front panel which I failed to. There are screws below the label underneath but despite these the front panel doesn't come off. It looks like there are molten plastic joints at various places holding it firmly in place. In the end I found an empty place above the front right rubber pad. I drilled a large enough hole to let a micro-USB male connector enter, and placed the adapter there on top of dual-sided thick tape against the internal plastic wall. It looks as if it was made for this, there's very little margin there.


I don't want dust nor random metal stuff inadvertently entering the hole, so I wanted to fill it with hot glue. The difficulty with hot glue and USB connectors is that it tends to fill them up so that it's not possible to insert anything anymore there. So I had the idea to insert the USB connector before filling the hole with glue. But I didn't want my USB connector to be glued. Thus I reused the dual-sided tape protection. By definition it's non-adhesive, so I adapted it to the hole's form and placed it around the micro-USB connector. This way I could plug the hole while filling with the glue. The result is perfect and the adapter cannot move anymore.



Reassembly

Reassembling the device is almost as easy as opening it except when you have an excess of cable as I had. You have to find tiny places to push a few centimeters of cable in order for everything to fit. But once reassembled, it looks very clean, and the connector is very easy to access from the front.


And of course it works fine, I can now attach minicom to it at any moment to watch the boot process (yes I know there's no password now, I'll set one at the end of the installation) :



Now I can finish to install it and play with nftables without fear of being locking myself out ;-)

2018-02-25

USB-based watchdog for ATX power supply

Introduction

Sometimes when developing on low-level stuff like a kernel, you face situations which completely freeze your system. While it's not that much of a problem on a development board, it's more annoying when it happens on a regular PC and you have to move off your chair to power cycle the beast, or worse, wait till you're home when developing remotely.

Usually this doesn't happen because your hardware is supposed to come with a hardware watchdog timer that will reboot the board if hung. But some boards don't have one, or sometimes it doesn't work well or you simply don't have the driver on your experimental kernel.

This article explains how it is possible to implement a watchdog for an ATX power supply, that is controlled over USB. It supports both being controlled by the target device itself (like any regular watchdog timer), or by another machine which will be able to power cycle the tested one.

Background

First, it seems useful to remind how a watchdog timer works. It is a hardware counter that counts down from a configured value, and which triggers the system's reset once the counter reaches zero. The main system periodically refreshes this counter so that as long as the system runs, the counter cannot reach zero (e.g. it sets it to 10 seconds every second). If the system hangs, it stops refreshing the timer and once the period is over, the reset line is triggered and the system reboots.

Second, it happens that some embedded boards do not easily expose certain connectors like the reset pin. At this point it becomes a bit harder to implement a hardware watchdog timer. But there is a solution : ATX power supplies are expected to drive the PWR_OK signal up once the voltage is correct, and drive it down when it's out of specs. More precisely, they connect it to a pull-up resistor, and actively drive it down when the voltage is not within specs. The motherboard is supposed to watch this signal and hold its reset line until this signal is up. This is very convenient because it means we can connect to this signal without even cutting any wire, and drive it low to force the board to reset itself.

So we have our reset input :-)

Locating the PWR_OK signal

This signal is on the grey wire connected to ping 8 of the ATX connector (either 20 or 24 pin) as shown below. In case of doubt, please use your favorite search engine to look for ATX pinout. But be careful, the pinout is often shown from the pin side (front view) and not from the wire side (rear view) :

Controlling the signal

We will need a timer and one solution to communicate with the host and/or with another host. Initially I thought about using a serial port but they are not always available nowadays. Then I thought about using the PS/2 connector and periodically sending commands via the keyboard controller, but some boards do not have such connector. Nowadays almost all boards do have plenty of USB ports however. So it looks like implementing a USB slave device is a good idea, which will make it easy to unplug and connect to another machine if desired.

The difficulty with USB is to find a suitable chip. But not only this is no longer a problem thanks to the V-USB stack but it ends up possibly be the cheapest solution one can think of. This stack is available for very affordable micro-controllers like Atmel (now Microchip)'s ATTiny85. which can be purchased already soldered on a board with all required external components for around $1.50 to $2.00 depending on the board and form factor. Models sold as "Digistump Digispark", "Adafruit Trinket" as well as various so called "ATTINY85 development/programmer board" equipped with a micro-USB connector are all suitable. Two such devices have been successfully used to date :


One point to keep in mind is that the PWR_OK pin can be very sensitive on the motherboard. The ATX specification says that a power supply is required to drain at least 200 µA (i.e. 5V through a 25k resistor), and a motherboard must consider any voltage lower than 2.4V as low. This means that simply connecting a 10k resistor between this signal and the ground may be enough to drive it low with some power supplies. As long as the module is always connected, it's not a problem. But if the module is to be left disconnected, hanging out of the machine, then it will drain the signal through the power lines and will drive it low, preventing the machine from powering up. One pin on the ATTiny85 doesn't cause this : PB5. It's shared with the RESET signal and supports a high voltage, so it doesn't contain any pull-up nor clamp diode. The tests confirmed that indeed, when the module is not connected, only this pin doesn't prevent the board from powering up.

There are 3 solutions to this problem :
  1. use the PB5 pin as the output to control PWR_OK. I'm not happy with doing this as it won't be possible to reprogram the device anymore without providing a high voltage to the chip.
  2. permanently connect the +5V to the device by connecting it to the power supply's +5V line. I'm not fond of this method either, as taking the +5V outside of a machine isn't always safe if there aren't efficient protections (e.g. wires getting accidently pulled off could easily burn if shorted). On some boards this may also require disconnecting the +5V from the micro-USB connector to avoid leaking the current into the USB host.
  3. adding a transistor to only let the current flow when the board is powered. This sounds like the best solution, an only requires one external component.
The boards above all include a LED connected to PB1. We'll use it to indicate when the PWR_OK signal is asserted by the module and to help debugging. It's always convenient to be able to test a driver without having to power down the machine to confirm it works! On such boards, PB3 and PB4 are used for the USB connection. PB5 is shared with the RESET, which only leaves PB0 and PB2 available. Thus we'll use PB0 here to control the PWR_OK signal.

Additionally, in order to protect the device against cheap power supplies which would directly connect PWR_OK to the +5V output, we'll put a series resistor to protect the transistor and the micro-controller against a short-circuit. The micro-controller is supposed to be able to drain and sink 40 mA per output pin. By using 180 ohm, we'll limit the output current to 27 mA in the worst case (just enough to lit a LED), which allows to safely control a wide range of power supplies.

Circuit design

The circuit is pretty simple. A BS170 MOSFET is connected between +5V and PB0, so that the output is only connected when PB0 is low. This MOSFET contains a reverse diode, which allows us to also monitor the output and report it to the USB host. The MOSFET may be replaced with an NPN transistor like a 2N3904 or a BC547, a resistor, and a diode if the voltage monitoring function is desired. Both solutions have been built, tested, and confirmed to work :



The code takes care of disabling the output and the pull-up when the output is not asserted, so that no current even flows through the diode. The finalized boards look like this (before putting them into transparent heat shrink tube) :




Communicating with the chip

The V-USB mentionned above provides USB connectivity. This is fine for HID devices, but these devices require a driver on the host (well, it's not totally exact as they can send keyboard keystrokes but there's no trivial way to send data without a driver or an application). Another solution consists in emulating a modem using the CDC ACM mode. This is exactly what the AVR-CDC code does. It's important however to keep in mind that CDC ACM over a low-speed device is out of spec but general operating systems tend to support it, which is what we're exploiting here.

The AVR-CDC code comes with an example application consisting in a USB-to-RS232 interface realized entirely in software. It's a good starting point for what we need, so the RS232 code was removed and the USB code was modified to instead simply manage a watchdog. The modified code is available here with the pre-compiled firmware in hex format.

The protocol is very simple : the device presents itself as a serial port on the host, and receives some short commands. The following commands are supported :
  • '0'       : disables the watchdog
  • '1'..'8'  : schedules a reset after 2^N-1 seconds (1..255)
  • 'OFF'     : power off
  • 'ON'      : power on
  • 'RST'     : triggers a reset immediately
  • 'L0'/'L1' : turns the LED off/on (to test communication without resetting)
  • '?'       : retrieves current state on 2 bytes. First byte indicates the level of the pin, which is set as an input when not off, allowing to check a power supply's status. '0' indicates it's off (or forced off), '1' indicates it's on (or disconnected). The second byte indicates the remaining amount of seconds before reset.
All unknown characters reset the parser, so CR, LF, spaces etc will not cause any trouble.

All commands which manipulate the timer or the output ('0'..'8', 'ON', 'OFF', 'RST') automatically disable any pending timer. The device takes a great care not to influence the output during boot, and doesn't automatically start. This way it's possible to leave it connected inside a machine and to turn it on by software. It may also be used as a self-reset function by writing 'RST' to the device.

Testing the module

The tests were conducted on an ATX motherboard with an ATX power supply. The module was connected to a netbook PC. The module was forced off and on, then it was verified that the device didn't reset as long as the timer kept being refreshed, and then that stopping the loop (Ctrl-C) was enough to cause the board to restart. The status and the timer were also read before, during and after a reset :


The whole test setup :


The motherboard tested here (Asus P5E3 WS Pro) seems to only sample the PWR_OK signal on the falling edge for a short time, and decides to start anyway after a few seconds. It will prevent from controlling the power from outside. It's not dramatic, it still allows to remotely reset the board, which is the most important.

It is likely that some users may want to enable the timer at boot time. It's easy to do in the code anyway. A change could consist in checking pin PB2 to decide whether or not to automatically start the timer at boot. A variation could consist in replacing the output resistor with a relay connected to +5V or +12V, inserted between the mains and the power supply, or between an external power block's output and the board to control. The system is simple and versatile enough for many variations, possibly not even requiring any code update.

For motherboards featuring an internal USB connector, the Digispark board may be the best, as it includes the USB male connector, so it can directly be plugged into the internal connector without any cable. For internal connections, only the PWR_OK wire is needed.

For remote control, it's preferable to place the module outside of the machine with only the two long wires connected to the ATX power connector. These ones do not represent any particular risk. In case of shortage or connection to the ground, the board will simply be forced off.

Some tests should be conducted to determine whether or not it would make more sense to drive the PS_ON# signal instead. This one is driven low by the board to turn the power supply on. The problem is that some boards wire it to the ground to keep it constantly low. However it would be possible to implement the inverted signal on pin PB2 and decide depending on the motherboard whether to use PWR_OK or PS_ON#.

Downloads and links

2017-12-09

Tiny USB batteries v3

A bit of background

Since my last experiment at shrinking down USB batteries to fit in my pocket, I made a few observations resulting in new improvements :
  • it's becoming hard to find mini-USB cables these days, while there are micro-usb cables everywhere
  • the previous battery was still a bit thick due to the use of two boards, one for the charge and the other one for DC-DC conversion
  • sometimes I used the battery with a small USB-based LED to walk downstairs at the office, and I'd rather have this LED incorporated.

Migrating to micro-USB

I initially thought about just replacing the charging board by a new one. Most TP4056-equipped boards nowadays come with a micro-USB connector. But while looking at this, I started to think about the other aspects and considered some charging+DC/DC boards as well.

Reducing the thickness

I found a number of new DC/DC boards but as some readers may remember from my previous experiments, most of these are unable to deliver even 1A, let alone the 1.6-2A that I need for my bicycle's light. But recently a few very capable chips appeared : TP5400 and TP5410, equipping a few boards such as these ones.

I bought 5 of these boards and ran a few tests. They are able to deliver 5V at up to 2.8A max from 3.8V in. So there's some hope to run everything with a single board. I bought the version without the USB connector to try to optimize component placement.

 
The board is mostly flat on one side and mostly flat on the other one. Thus I decided to cut the board in two to split the charging part from the discharge part to stack all the components (the charge only needs the micro-USB connector and a few leds).



Default USB connectors are very high. Instead I picked a recessed USB connector, which perfectly fits aligned with the PCB. That makes a very thin board+connector. The coil became the tallest component so I tried a few other smaller ones I had, and ended up using a small 10 µH one.

I reinstalled the output decoupling capacitors against the USB connector and close to the output diode, which I doubled to reduce losses (there was enough room).


The charging LEDs and their 1.2k resistor were installed directly on the charging chip's leads. I don't need direct visibility, the hot glue I'll use to finish the assembly is translucent enough to make the green/red colors pretty visible.


I also noticed during a few experiments with such a board in a previous design (v2n never documented), that the TP5400/5410 stop charging at 1/4 of the programmed charging rate. While it's possible to charge small batteries in 15-30mn, it's problematic to cut off at 1/4 of the rate because they're far from being charged, in part due to the losses in the battery's protection circuit. So I had to replace the programming resistor (1.2k by default) with 4.7k and finally 10k to lower the charge current to around 200 mA (the TP5400 and 5410 have slightly different currents for the same resistor).

I kept the small part of PCB attached to the micro-USB connector as a more convenient support for this connector.


After completing this assembly, I just had to reconnect the battery to the circuit and verify that it could still deliver power and charge. The battery still needs to be a high rate one. I'm using 20C at 240mAh, that's 4.8A max output. When the battery is about to be discharged near 3V, that's still 14.4W, or 2.88A under 5V assuming 100% efficiency (which never happens), so that doesn't leave much margin in the end! Given that TP5410's internal MOSFET supports up to 4A, it's important that the battery is at least that strong. That's 25C for 160mAh, 20C for 200mAh, 16C for 250mAh, 12.5C for 320 mAh.


The resulting assembly with a 240mAh battey is very thin as can be seen below, 12mm thick, 20mm wide and 34mm long. There's very little wasted space now, which is noticeable when filling it with hot glue because very little glue is needed to keep the parts together.


Adding an integrated LED-based torch

I found that some unused space was left next to the USB connector. Just enough to place a powerful LED, a button and a resistor. So I cut two pins from a small button, soldered a 39 ohm resistor to it with the other end connected to the +5V output. The other end of the button was connected to the LED's anode, whose cathode was directly soldered to the USB connector providing the ground. This way pressing the button delivers 60mA into the LED and makes quite a bright torch.


As for v2, I simply placed two crossed layers of heat shrink tube, one in each direction, completely covering the connectors and the button, thus completely closing any hole. Then I just cut the tube around the USB connectors and the assembly is finished. The tube is soft enough to let the LED button be pressed through it.


Final thoughts

I spent a lot of time trying to figure the best way to assemble the parts together. I even hesitated to make a PCB. That may be for v4. What I figured, which will be useful for future designs (and for anyone willing to make a commercial version of this) :
  • the coil is approximately the same height as the USB connector. It must be placed behind it.
  • the IC, diode(s) and capacitors are approximately the same height. It's not really possible to stack them in a production version, but they should probably be placed in the same area.
  • the micro-USB charging plug doesn't need to be exactly on the opposite of the USB connector. I found that it could be placed on one side, possibly over the IC, diodes and capacitors if one is found with long legs or wires. It could even be glued on top of the IC.
  • all resistors and LEDs are very flat and should be placed below because they will not inflate the board's thickness by any measurable size.
  • the recessed USB connector is critical here to keep the device thin
  • the PCB could possibly be rotated 90° and be as large as the battery is long. The USB connector would then be placed on a small area, and all the components including the micro-USB, the press button and the white LED could be installed on the remaining part of the PCB
  • in any case, the battery should be placed on top of the USB connector and components. This also makes the top mostly flat and reduces the length of wires between the battery and the PCB.
An example of more efficient component placement is this one :


Feel free to copy this design and improve it. I'll be happy the day I can simply buy such a small pocket battery without having to spend a week-end building it myself :-) Do not hesitate to share suggestions and comments of course!





EDIT: 2.5 years later the new design above was finally realized: battery v4