My attempts to make a rapid prototyping machine that I will use to make parts for a machine that will be able to make parts for a copy of itself.
When I used OpenSCAD to design Mendel90 I modelled complete assembly views with all the vitamins in place and a significant part of the code was actually the vitamins. Vitamins being the RepRap term for non-printed parts of a 3D printer, fasteners, motors, etc. I also automated the generation of the bill of materials, STL files, DXF files and PNG assembly views, but making the build manual was still a lot of manual work, pardon the pun.
After Mendel90 production ended I started designing other projects and found myself needing to use its vitamin library, but because it wasn't designed to be stand alone, that quickly got messy. Eventually I made a new stand alone library and a more general Python framework that would work for any project.
Over the last few years I have refactored it many times, making it much faster to preview, more general and more automated. In particular it can now catalogue all the vitamins and automatically make build manuals for any project using Markdown embedded in OpenSCAD comments. There is a simple example here. I also added reusable printed parts, such as feet, hinges and handles and some reusable enclosures.
It will never be complete because each significant project I make with it usually needs a few more types of vitamin, but it is hopefully structured so that it can grow sustainably without bringing OpenSCAD to its knees. To do that I had to fix some issues in OpenSCAD itself because it used to slow down exponentially with the number of files used. The picture above has an instance of every part in the library. The latest release of OpenSCAD can draw it in about one minute on my desktop PC. This is remarkable because at one time it took 12 minutes.
Here is an example of a typical assembly views it creates: -I have published it open source on GitHub to enable me to publish projects that use it in the future. I use it for every project I make now, so I don't have any stand alone scad files that can be put on Thingiverse, for example. Feel free to use it in your own projects.
I bought these multi-meter leads on eBay for £2.99. They are advertised as "16PCS/Set Multimeter Probe Pin Test Leads Cable Multifunction Digital Clip Kit". I was attracted to them by the large number of accessories including pin type plugs that fit old analogue multi-meters.
When they arrived I discovered that the wires are steel and have a resistance of about 1 Ohm each, which makes them about as useful as a chocolate teapot. Any resistance measurement gets 2 Ohms added . Current measurements on the amps range drop large voltages, the wires get hot and would burn if left on for more that a few seconds.
Voltage measurements would be accurate enough but where the attachments screw on there is exposed metal, so not suitable for high voltages.
I got a full refund and get a set of these instead for £2.97.
They claim to be CE cat III rated for 1000V and 20A. Their resistance is only 64 milliohms. Not bad but my UNI-T UT61E came with 600V 10A rated ones that measure 44 milliohms and my EEVblog BM235 wins with 24 milliohms for 1000V 10A probes.
I got them to replace these old ones that belong to a multi-meter I inherited from my Dad. They have numerous burns from touching a soldering iron.
I dug out this old meter when I realised all my modern digital meters only go up to 1000V at most. This one goes up to 6KV!
I think it was purchased sometime in the early 1970s. It is branded Honor Model TE-12, made in Japan. I have seen identical ones on the web branded Lafayette. I don't think you would get away with connectors like that for 6KV nowadays!
When looking at a Blog hosted by Blogger it is even more annoying because it warns for every new page of a blog visited. Looking at the cookie it uses to decide whether to warn about using cookies I noticed it stores the path of the page relative to the blog. That is why it warns for each page of someones blog. However it looks like it won't warn for sub paths of the path in the cookie. So if you visit the root of the blog and dismiss the warning there it gets rid of the warnings for every other page in the same blog. This is a lot more reasonable and probably the way it should work by default.
It is also annoying that this will expire in a year. If every website I visit repeats the warning every year it will continue to be a constant stream of warnings forever.
I came across a very useful post by Thomas Scherrer that describes how to read data from a Peacefair PZEM-021 energy meter by spying on the SPI bus with an Arduino. I decided to do the same thing with an ESP-12F WiFi module so that I could view the results remotely and plot graphs, etc. It took me a lot longer to get this working than I anticipated due to a few problems along the way.
The main hardware difference is the ESP8266 is a 3.3V device but the Arduino is 5V. The PZEM-021 is actually a mixture. The RN8208G metering chip is a 5V device. It is a SPI slave, the SPI master is an STM32 ARM processor that is 3.3V but with 5V tolerant inputs. That means the signals originating from the CPU can go straight into the ESP8266 but the data out from the RN8208G would need attenuating.
Copying Thomas, I removed the mains dropper components C1 and R1 and powered the PZEM-021 from an external supply. This allows it to measure voltages right down to zero instead of cutting out at 80V. I used this little 12V 1A supply recommended by Big Clive on YouTube.
I powered the ESP-12F from the same supply with a tiny 3.3V MP2307 buck converter module.
WARNING: when connected to PZEM-021 the 0V rail is at mains neutral potential. This has to be treated with the same precautions as live because if the mains lead happened to be be reversed or the neutral connection broke it would become live. Don't connect a USB programmer or a scope ground to the circuit unless you power it with a mains isolation transformer. Fortunately the ESP8266 can be programmed wirelessly from the Arduino IDE once a sketch with ArduinoOTA has been installed and this is much faster than USB.During the hardware development I used a mains isolation unit that I made after watching this video by Paul Carlson, another of my favourite YouTubers. I built this originally to allow me to repair a switch mode PSU that was part of a friend's home cinema unit. It allows me to connect my scope to the live part of a circuit but then of course it is no longer isolated, so great care has to be taken not to touch the high voltage bits.
It is a DiBond box with 3D printed frame, handles and rubber feet containing an isolation transformer and a small variac. It also has two 100W light bulbs in parallel with a bypass switch for optional current limiting, a different model of power meter and some 4mm jack sockets allowing me to attach my Mooshimeter to log voltage and current.
The first task was to solder wires on to the PZEM-021 PCB to bring power in and data out to my circuit.
I didn't see a need for the chip select / word latch signal and I took the data from the other end of R9 compared to Thomas. The signals are as follows:
- Red is 12V, black is ground.
- The word latch going to the display from chip U2 pin 7 on the left, used for synchronisation.
- MISO data coming from the energy chip via R9.
- The SPI clock coming from U2 pin 12.
- Strip some wire-wrap wire and trim the end to be the length of the flat part of the pin.
- Tin it. It doesn't hold much solder due to being such a small radius.
- Add plenty of liquid flux around the pin.
- Line the wire up along the top of the pin with an Andonstar ADSM201 microscope camera.
- Put a very small amount of solder on a small chisel bit.
- Press the iron on top of the wire and leave it long enough to conduct the heat through the wire to boil the flux and melt the solder on the pad below.
When I looked at the levels of the signals I got a bit of a surprise. I was expecting MISO on channel 2 to go to 5V but the other two come from the ARM and should be 3.3V signals.
They seem to have a 20kHz ripple that takes them up to 4V. I looked back at Thomas' oscilloscope pictures and see the same ripple there. It doesn't make any difference for him because he is using a 5V chip but I didn't want to stuff 4V into my ESP8266!
On further investigation I found that the whole 3.3V rail had this ripple on it. It comes from a Holtek HT7133-1 3.3V LDO regulator. The datasheet for that suggests 10uF decoupling capacitors on the input and output. The circuit has what looks like a 10uF tant on its input but the output decoupler is a tiny MLCC that looks too small to be 10uF. I added a 10uF electrolytic in parallel and that killed the oscillation. It is the blue radial cap across C1 in the photo above.
That just left the issue of the 5V signal to contend with. R9 turns out to be 1K so simply adding a 2K2 to ground drops the signal low enough.
It also changes the first eight bits from FF to 00. This is actually when the command byte is being sent to the meter chip on MOSI and MISO is tri-state, so it doesn't matter.
Hardware done, on to the firmware. Before starting the project I had seen that the ESP8266 has a spare SPI port available and I assumed it would be straightforward to just read a stream of 13 bytes, wrong! It wasn't because the SPI port it a relatively complex device with dozens of registers that doesn't just send and receive bytes. It actually works at the command level, expecting to send or receive a command and address and then send or receive status or data bytes.
When in host mode it is possible to configure it to send and receive arbitrary bytes, indeed that is what the Arduino SPI class does and it works on the ESP8266 more or less the same as it does on an AVR. In slave mode though it has to receive a command and address according to the technical manual and the command defines what happens next. The relevant sections are:
4.3.2. Communication Format Supported by Slave SPISlave ESP8266SPI communication format is almost the same as that of the master mode, i.e. command+address+read/write data, but the slave read/write operation has itshardware command and undeletable address, which is,On the face of it this looks like it will not work in this application, which is unbelievable that a SPI port can't read arbitrary data as a slave and is hard coded for emulating flash chips and the like.
- Command: a must; length: 3 ~ 16 bits; master output and slave input (MOSI).
- Address: a must; length: 1 ~ 32 bits; master output and slave input (MOSI).
- Read/write data: optional; length: 0 ~ 512 bits (64 Bytes); master output and slave input (MOSI) or master input and slave output (MISO).
- 010 (slave receiving) : Write the data sent by master into the register of slave data caching via MOSI, i.e. SPI_FLASH_C0 to SPI_FLASH_C15.
- 011 (slave sending):Send the data in the register of slave data caching (from SPI_FLASH_C0 to SPI_FLASH_C15) to master via MOSI.
- 110 (slave receiving and sending): Send slave data caching to MISO and write the master data in MOSI into data caching SPI_FLASH_C0 to SPI_FLASH_C15.
I couldn't find any proper register level documentation for the ESP8266 other than various .h files on the web. The Arduino library uses shortened names which are very cryptic but some headers use longer names. While searching for these I came across the technical manual for the ESP32 and realised it has SPI ports that are nearly the same. It also has register level documentation in it's technical manual so I was able to get a slightly better understanding. After a lot of experimentation I found a solution.
The first n bits get interpreted as a command, where n is 3 or more and defaults to 8. The start of the 13 byte sequence that I want to receive is always zero now that I added the pull down resistor. So it always receives command zero. The bottom three bits normally control what happens next and zero defaults to read status. However, it is possible to override this with user definable commands by setting SPI_SLV_CMD_DEFINE in SPI_SLAVE_REG. That makes the SPI_SLAVE3_REG define what the command values are for four different actions. By setting SPI_SLV_WRBUF_CMD_VALUE to zero and the other three values to nonzero I was able to make it interpret the command as write buffer, so the rest of the data gets written into the buffer.
Well that was the theory but I was missing two bytes at the beginning. This was because it was being interpreted as an address. The default address length is 24 bits. I changed it to 8 by setting SPI_USER1_REG and now I get the 12 bytes of data following the zero byte. Now this doesn't make sense because if the first 8 bits are being interpreted as an address where is the command coming from? The command length is set by SPI_USER2_REG and it defaults to 8. I was expecting to have to set it to say four and set the address length to four bits so that they could share the first byte but any value between 2 and 8 seems to work and makes no difference. I don't know if it is a bug in the chip or I don't understand something but I get to read my 12 bytes of data
So in conclusion you can't read a completely arbitrary SPI data stream but you can if the first few bits are a known value.
Here is my code that sets up the HSPI:
When the data is received I get an interrupt where I copy it from the HSPI's dword buffer into a byte buffer in RAM.
I set up the sync pin to generate an interrupt on the falling edge. This resets the HSPI and unmarshals the data:
I found that when I switched the load on and off I sometimes got a data packet shifted right one bit. That points to a spike on the SPI clock line into the ESP8266 but I could not find one with a 100MHz scope triggered on the mains switching edge. I added a snubber close to the switch but that didn't cure it, so I bodged it in the firmware and moved on. If a voltage sample is not more than half the previous one I ignore it once.
Another oddity is that when there is no load and the voltage is relatively high the power reading would go slightly negative. I detect that and set it to zero.
The foreground loop looks for the new_readings flag to be set and does the conversion to real units:
The conversion constants are close to what Thomas used but slightly different, so the ARM must have some per unit factory calibration constants in it.
So it took me longer than I anticipated to follow in Thomas' footsteps because of the complexity and lack of proper documentation for the ESP8266 HSPI peripheral but I got there in the end. I hope others find this as useful as I found Thomas' work.
By now you are probably wondering what this is all for. Well, while investigating a strange line regulation problem in a power supply I got annoyed that the mains voltage in our house is constantly varying, making it hard to make measurements of input versus output. This is what it looks like logged every 10 seconds over a couple of days using my Mooshimeter.
As well as the small modern variac shown above I have a old WM5 model that I got on eBay. The only data I could find on it was from 1955. It still works fine so I decided to automate it with a small stepper motor to maintain a specified voltage. I.e. make a WiFi control IOT variac.
Another DiBond and printed part creation but the front panel had to be acrylic to let the WiFi out. Fortunately the front of my bench faces towards my router. The ESP8266 controls the motor via a Pololu stepper driver.
The control interface is a simple web form that also shows the current readings using AJAX as described here.
The control algorithm is very simple. The motor is stepped at the specified speed by the error in voltage multiplied by the gain. The readings update every 200ms but they lag a lot. That causes overshoot if the gain is set high. It would probably benefit from a full PID controller but it works well enough for now. The deadband setting allows it to stay in a range without constantly moving because I don't want to wear out the variac. Servo control of a variac is a standard way of regulating mains but I have no idea how long the brushes last. Manual mode disables the motor.
The readings can be read and the settings changed from the command line or from a Python script using cURL. Here is an example that sweeps the voltage from 10 to 250 in 10 Volt steps and reads the current and power.
Here is a graph showing current, power and resistance versus voltage of a 60W light bulb
I plan to use this to plot a power supply line regulation graph. For that I will need a way of reading the output voltage in my script. I have two scopes that have network APIs as well as my Mooshimeter that has a BLE interface. I just need to work out which is the easiest to access in Python.
Here is the full ESP8266 sketch.
To put the ESP8266 into serial programming mode it needs to be reset with GPIO 2 held high, GPIO 15 low and GPIO 0 low. On the other hand to start it executing flash GPIO 0 needs to be high during reset. I have seen lots of circuits on the web, for example the NodeMCU board and Adafruit's Huzzah board that pull GPIO 0 to ground with a switch and / or with DTR from a USB to serial adapter. Reset can be driven from RTS to automate programming with the Arduino IDE.
A lesser known fact is that when the ESP8266 goes into programming mode it outputs a 26 MHz clock on GPIO 0 with considerable drive strength and fast edges. Shorting this to ground or DTR is not good at all as it causes massive contention and generates a lot of noise. This can cause programming to fail unless there is some hefty decoupling on the supply rail. The simple solution is to put a resistor between GPIO 0 and whatever is pulling it low. Here is what the signals look like with 10K between GPIO 0 and DTR from an FTD1232.
The oscillation doesn't show up at full amplitude with a slow time base but I can assure you it is full swing with plenty of overshoot due to not being terminated. You can see a bit of it coupled onto the TX line and this is when it is through 10K. Imagine how noisy things get when it is fighting with the FTD1232 DTR line and winning.
Another lesser know fact is that when the ESP8266 is in reset its GPIO lines get pulled up internally. You can see with 10K pulling it down the GPIO line only goes down to about 0.7V during reset.
Before reset my application is driving GPIO 0 low. RTS goes low a short time before DTR, so it briefly becomes an input and gets pulled to 3.3V by DTR before it pulls it low again. This explains the spike on the left.
I haven't seen any circuits published that avoid this contention.