Documentation of the 3rd generation of my ultrasonic phased array project. Levitating stuff, directional speaker, haptic feedback and more!
When I started this project I already had some concerns that the HV583 driver might not be suitable for driving 128 ultrasonic transducers. However for some reason I kept rather optimistic that all would work out fine in the end. I did some test before, and the signals weren't too bad. Also, driving piezos is one of the recommended applications for this IC...
Well, this week I finally managed to test the performance of my array. The pcbs for the transducers arrived and I started assembling 32 of them to the pcb for testing.
All transducers received the same 40kHz square signal, because I only cared for the power consumption and temperature at this point. I supplied the HV583 from an external power supply, just to make sure...
I glued on a heatsink after I realized there is no way for this to work without one, and set the onboard fan to full speed. Unfortunately, even with only 1/4 of the load and not eve full input voltage, the heatsink quickly reached 110°C. The die temperature is probably >160°C at this point.
Here is a (quite shaky) video of this first test:
I then assembled all transducers, because, well, I don't have anything else to do with them and they were laying around. Also, a possible future attempt would probably based on the same connectors and board shape, so I can recycle the transducer array.
At least it looks quite nice...
With all transducers in place, I can only turn up the voltage to 24V before the driver passes out because of over temperature. The effective transducer voltage is 15Vpp. My 2nd array is working at 20-30Vpp...
There are multiple options now to continue this project. One might be to improve cooling, however I don't think that's worth a try.
The other option would be to use the HV582. This driver only has 96 output channels, so I would need three of them for one 16x16 array. Or two, and make it 14x14. In both cases, I would need a new mainboard, as they are unfortunately not pin compatible. On the first look the pinout seems quite identical, unfortunately Microchip decided to swap VDD and GND on these two chips...
According to the datasheet, this chip can supply 75mA peak instead of 30mA, so it might work somewhat better because the losses in the output stages are less. Also the power is spread to three instead of two packages.
I contacted Microchip to get more details about the RDSon of the HV582 compared to the HV583 to estimate if the HV582 is sufficient for my application. Unfortunately, after more than two month of rather pointless emails the were not willing to give me this information if I'm not asking as a "professional engineering firm".
I'm currently not willing to invest time and another 100$ for new pcbs for the HV582 without this information. So unfortunately, this project is on hold until Microchip decides that this project is worth it to take a quick look at the internal parameters of their design. I was not able to get anyone to do this. But maybe someone from here knows someone who can?...
UPDATE: Microchip replied! They gave me exactly the information I was looking for. Thanks to every one who helped with this shout-out.
The HV582 looks promising, the better performance might be all I need to get it properly working. However, for now I'm designing a new transducer board with a npn / pnp complementary driver stage under each transducer. This allows me to recycle the driver board with the two HV583. I'm currently designing the pcb (luckily this is only a two layer board, so it's quite cheap), so stay tuned!
Another interesting aspect about this phased array design is the power management.
While the BeagleBone is rather easy to power (it only requires 5V 2A), the main array requires a voltage of 12V – 80V. This voltage down not necessarily need to be adjustable, but it realy helps for testing to start out with a lower power. Also, for levitation applications, it is simpler to adjust the output power via the supply voltage then to change it via the phase pattern.
Designing digitally adjustable power supplies is always rather annoying. It’s not a typical application, so there are few ready-to-use chip designs available on the market. The probably most popular way is to use a standard off-the-shelf switching mode controller, and adjust the output voltage on the fly by modifying the feedback resistor network either with a digital potentiometer, or with a programmable amplifier. First off this is rather a workaround than a recommended solution, and you can get lots of problems with this design (the whole system can get unstable and start oscillating).
That’s why I decided to implement this switching mode controller all in software. I’m a big fan of the STM32 ARM processors by STMicro, and one part that is particularly interesting is the STM32F334. This microcontroller contains a high resolution timer (and by high resolution, we are talking about 217ps) and some other very useful analog peripherals. This timer allows me to generate two PWM signals, one inverted and with dead time, that have a frequency of 600kHz and a resolution of >12 bit. Every 128th period, the ADCs that measure output voltage and current are sampled and a simple PI regulator with current feedforward adjusts the duty cycle of the PWM. The signal goes straight to a half-bridge gatedriver + MOSFETs that form a synchronous boost converter. The setpoint of this regulator can be adjusted in software, and in this project the STM32 is connected to the BeagleBone via UART to set the output voltage. The serial wire debugging port is connected to the BeagleBone as well to allow flashing the STM without a designated debugger, using a port of OpenOCD.
I could write a
whole article about software-defined switching mode power supplies. This is super useful
and handy and totally underrepresented in the community. For example, this
STM cost 2.80$ and does do job of a 4$ proprietary SMPS IC. Anyway,
for now if you’re interested in how exactly this works, take a look
at the firmware on github: https://github.com/ultrasonic-phased-array/array-V3-stm32
Apart from the power management, the STM32 also serves some more purposes. The problem with the transducers I want to use is that the polarity is unknown. That is because for most applications of ultrasonic transducers, the phase of the wave doesn’t matter. You can get them with a polarity marking, but that cost like 200% extra (40ct the transducer, another 70ct for the branding…). For array V2 I did this measurement myself, by applying a sine wave with known phase and measuring the ultrasonic output with a seconds transducer at a known distance. This was a lot of work (in the order of 3-4h) and I don’t want anyone to go through the same struggle. Also, you need at least a signal generator and a scope, and I want this project to be as accessible as possible even for beginners.
That is why for this version, I wanted to implement an “auto-learn” function: The BeagleBone switches on one transducer at a time, it scans over all 256 transducers in something like 100ms.
Now you take a separate transducer that acts like a receiver that is connected to the array. You slowly move it over the surface of the array, and a GUI shows you what area you have already covered. Due to the scanning, the BeagleBone knows exactly which transducer you are currently receiving. Given a fixed distance to the array (like, for simplicity, 0mm ;) the BeagleBone...Read more »
I spent quite a few thoughts on how I want to control the HV583 shift registers.
The most obvious option would be to use a FPGA, like in V2 of my phased array: The shift registers need 8x Data, 1x Clock and 1x Latch, all shifted out in parallel with 40MHz. With a FPGA, this isn't a problem, because the driver for generating these control signals can be implemented in VHDL / Verilog. Unfortunately, if you don't have a expensive SoC like the Zynq that also has a ARM hardcore, this also means that all of the control logic has to be implemented in VHDL. I did quite some projects with FPGAs already, but when I started reading about implementing TCP/IP stacks on FPGAs I kinda felt lost. There are not many open IP cores for network available, and those that are free to use require so many resources that you would need a FPGA in the 20€ price range to make it fit.
For microcontrollers like the STM32 or Texas Instruments Tiva-C, developing network applications isn't a problem. Lightweight TCP/IP stacks like LWIP run on ARMs small as the f4 serial of STM, and there are tons of application code and tutorial available. Unfortunately, generating the required shift register waveforms is the more difficult on instruction set architectures. You need at least five assembler instructions the set the port (8 data bits) and toggle the clock pin on a typical microcontroller: LOAD, SET PORT, SET CLK, INC ADDR, CLEAR CLK. So you need at least 200MHz CPU clock to shift out the data with 40MHz. Also, during this no other tasks can be executed by the CPU, like loading new waveform patterns via ethernet.
When you search for popular projects utilizing the BeagleBone SBC, you probably sooner or later stumble upon the BeagleLogic project. The BeagleLogic is a logic analyzer capable of sampling with 100MHz in realtime without any additional logic or hardware. It does that by using the BeagleBone's PRUs (programmable realtime unit): A PRU is a fast (200-MHz, 32-bit) processor with
single-cycle I/O access to a number of the pins and full access to the internal
memory and peripherals on the AM3358 processor on BeagleBones (http://beagleboard.org/pru). This basically means that you can have a Linux running on the main ARM core, while still having two 200MHz coprocessors available to do stuff with the GPIOs of the BeagleBone. The beaglelogic does exactly this: using the PRUs to sample up the 16 GPIOs while still providing a Linux to control the sampling, analyze the data... In fact, the beaglelogic project was exactly what I needed, just the other way around: Instead of reading GPIOs and write their values to DDR memory, I want the write DDR memory to eight GPIOs.
There are quite some things to learn before you can start programming the PRUs. Luckily, there is lots of very useful documentation out there on this topic. On of the most helpful resources to understand how the beaglelogic assembler code works was the awesome blog of the beaglelogic developer himself, Kumar Abhishek. He explains in detail almost every single line of the PRU firmware, and it shouldn't be a problem to understand my modifications to his idea after you read this blogpost.
Here are few lines of the pru1.p assembler code used for shifting out the waveforms that form a 40kHz square wave at the output of the shift registers:
SHIFT: XIN 10, &r21, 32 ; r21-r28 LDI r31.b0, PRU_INT_VALID + PRU1_PRU0_INTERRUPT ; Signal PRU0 MOV r30, r21.b0 ; set data pins SET r30, r30, CLOCKPIN ; set clock pin NOP CLR r30, r30, CLOCKPIN ; clear clock pin NOP MOV r30, r21.b1 ; SET r30, r30, CLOCKPIN ; NOP CLR r30, r30, CLOCKPIN ; NOP ... NOP r30, r28.b3 ; SET r30, r30, CLOCKPIN ; NOP CLR r30, r30, CLOCKPIN ; NOP SET r30, r30, LATCHPIN ; set latch pin NOP CLR r30, r30, LATCHPIN ; clear latch pin JMP SHIFT
When you compare this to the beaglelogic code, basically all I did was swapping the XOUT to XIN to load instead of store data to...Read more »
One of the most important parts of an ultrasonic phased array are the amplifiers that drive the individual ultrasonic transmitters. It needs to drive around 2nF of capacitance per channel at 40kHz, which is about 50mW in average at 36Vpp. Unfortunately, this is also the hardest part to find when designing an array.
A good idea to start searching for are MOSFET gate drivers. These are designed for exactly that application, charging the gate capacitance of a MOSFET at high frequency, so these work perfectly fine for our application. However, these have to problems: First, they are rather expensive. I wasn't able to find one for < 20ct. This doesn't sound like much, however second, these usually come in single-channel configuration. This means you would need 256 individual ICs for a 16x16 array, or 50€ worth of gatedrivers.
That is also the reason why I used the l293 for V2. These have two full-bridge drivers per chip, so you can drive 4 transducers with a single IC. Also, they are dirt cheap when you buy them on AliExpress (4-5ct / pcs). Unfortunately, they are only available in DIP package, which is a pain to solder. Seriously, try soldering 90 DIP-16 packages.... hfgl.
The other thing is driving all these transmitters. You need at least 256 IOs, and neither a fpga nor an ARM processor has that many GPIOs (at least not in the user-friendly, low-cost range). So you will probably need some shift registers. Cheap candidates are 74HC595, and they indeed work perfectly fine. However you would also require 256 / 8 = 32 of these...
Long story short, everything sucks with standard components. This is why I was very happy when I had a look at Microchips HV driver ICs: That was when I learned about the HV583 IC. This isn't a particularly new IC, it was originally introduced by Supertex in 2003. However, back then it was only available as a bare die, so you would have to bond it to your pcb to use it. This was until Microchip bought Supertex and repackaged the HV583 design in a 169-TFBGA package. I know it's BGA and it is not the easiest to solder, but at least now it's possible to use it at all.
Here is a sneak at the datasheet which might help to understand why I'm so excited about this part:
This single IC combines the shift registers + the amplifiers for 128 transducers in a single package. It takes two of them to power the whole array. Also, they are super cheap: 12€ for single quantities at Mouser, 7€ at 500pcs via Microchip direct. In fact, you can even sample four of these from Microchip for free.
The only disadvantage about these ICs is that they are rather slow, and the shift registers are connected as 4x 32bit. This gives us a maximum phase resolution of (40MHz / 32 bit) / 40kHz = 31.25, so roughly 5 bit.
The other thing is the rather low output power of 30mA. This means that the internal RdsOn of the output driver stage is rather high, from my measurements in the range of 50-70 Ohms. This creates lots of internal losses that heat up the chip. To test if it is generally possible to use the HV583, I made a small breakout board of the IC in deadbug style:
I attached 32 transmitters to some output channels and generated a static 40kHz signal. Everything seemed to work fine, until after 30s the outputs switched off. The thermal camera showed a peak temperature of 120°C. So the chip went into over temperature disable. However this was without any cooling, neither from the pcb it was not soldered to nor from any forced airflow. So, let's hope when soldered to a proper pcb, cooling works okay.
If that should fail, I still have a backup plan: The HV582. It is basically identically to the HV583, however it has only 92 output with 75mA driving capacity. This means that I would need 3 instead of 2 chips, but that's still way better and cheaper than any of the discrete solutions mentioned earlier.
This isn't my first phased array that I built. Actually, my seconds version is working perfectly fine and has all features I wanted to have. Still, I don't feel like that's what people should read about when considering building their own arrays. And here is why.
First, some specs about V2. I won't go too much into detail, anyway feel free to ask questions if you want to know something particular.
When I started this project, I didn't know anything about phased arrays. There were some papers about the theory of operation and the maths behind it, but they all used simulations for their proposals. I tried contacting the guys who made this initial levitation youtube video, without success. I knew that I would need to control the transducers individually, and I knew that I need a lot of them. However, I didn't knew if there is a minimum amount of transducers that is necessary, and more important, with what resolution I need to control the phase. And because I wanted to be sure that it works in the end, both of these parameters turned out the be complete overkill in my design. I built a highly sophisticated, completely overengineered array with 19x19 transducers, 10 bit (1024 steps) phase resolution and 8 bit (256 steps) power resolution for each transducer, that, because if this, caused me a lot of trouble. 19x19 because that's the amount of transducers I was able to stick to my fpga, and 10 bit resolution because I was worried a lot that I would need super high resolution for everything to work smooth.
Well, turned out 5 bit (32 steps) are totally fine, and 19x19 transmitters is complete overkill. Not only did this false assumption wasted a lot of time and money, it also caused lots of troubles that are directly connected to this overkill: Thermal problems, high error rate because of the insane amount of components etc.
Especially, I wanted version 3 to be more rebuild friendly. To achieve that, I wanted to change few things:
Anyway, not everything was bad with array version 2. Things I really enjoyed about it:
If you paid attention in your physics class, the concept of how these array work shouldn't be too hard to understand. If you watched the youtube video in the description, you already know what such an array looks like. If not, here is a video of my second generation ultrasonic phased array:
As you can see, the array basically consists of 19x19 ultrasonic transmitters, mounted on the top of four stacked pcbs.
Let's imagine we only have two of these transmitters. The only reason this is ultrasound is because these frequencies (40kHz) are not hearable by humans and most mammals. You could also build a phased array from traditional speakers, however it would be loud and annoying af.
We have these two transmitters right next to each otter, and each transmitter outputs the same sinusoidal waveform with the same frequency. If we would only take one transmitter, it would have a beam shape of a cone with something like 120° opening angle. However, because we have two transmitters, they interfere with each other. Instead, what we get is a beamform that is called an interference pattern.
As we keep adding more transmitters with the same frequency, the interference gets stronger and stronger. The beamform of all transmitters combined is now rather a narrow beam than a cone. Here is the measured intensity map of my 2nd phased array with no phase shift applied (all transmitters are transmitting the exact same):
As you can see, apart from some measurement errors, the transmitted beam is rather uniform. You can still identify individual transmitters, but it's not like the typical cone you would expect from a point source.
So this is fun and all, but the applications for this static beam are very limited. You could achieve the same by simply connecting all transmitters in parallel, all powered by a single amplifier. Nevertheless, you can already have fun with this: Even tough you can't control the shape of the beam, it acts very different from what humans are used to from their experience with hearable sound. With just 8x8 transmitters you can already get a beam with an opening angle of <5°, which can have a range of >20m.
Next step is to modulate this static beam: You can control the transmitted power either by changing the overall supply voltage of the amplifier, or by supplying the transmitters not with a sinusoidal wave, but with a rectangular wave with variable duty cycle. Now you basically have an AM-modulated ultrasonic speaker:
This is exactly what the http://www.soundlazer.com/ project is all about. You can modulate the intensity with hearable audio, like music. As mentioned earlier, the human ear can't hear to actual ultrasound. This is because the eardrum is too sluggish to oscillate at 40kHz. However, there is still a change in pressure due to the changing power of the ultrasound that pushes against the eardrum: Your eardrum acts as a low-pass demodulator.
So let's get back to our phased array. And here is the trick: We can not only control the power of each transducer, but also the phase of it. By changing the phase of the transmitters, we can manipulate the 3D interference pattern above the transmitters in almost any way we want. The most simply thing to to is to apply a gradient from one end to the otter end of the array. This way, we can steer the beam of our array:
This, combined with the audio modulation, gives you a steerable, directional speaker. Cool? It gets better:
We can also focus our beam by applying a radial gradient. Here is a intensity map of the same setup as above. However, now the ultrasonic beam is focused to a single point on the virtual slide that we are scanning:
And the best thing is: All of this can be done in software! There are no moving parts, you can change the pressure of the air with the press of a button (and hours of maths and simulations, more about...Read more »