• A New Laser and Laser Control

    Alan Green5 days ago 0 comments

    Two exciting developments today. 

    A New Laser

    In comments on a previous log, [Stefan Kruger] reminded me that common, cheap, poorly designed 532nm laser pointers also emit a surprising amount of infrared light, which is a potential danger. He  referenced this great paper from NIST, which features a laser pointer very similar to the one that donated my previous green laser.

    After a bit of research, I ended up buying a 50mW 505nm laser, which does not have the same problem. 

    Photo from the eBay listing

    The driver board I received looks a little different, and it has both "TTL" and analog inputs. 

    Laser Control

    I hooked up the "TTL" input to my PIC32 and it Pretty Much Just Worked. Here's a cross-in-a-square test pattern, which demonstrates the laser can be turned off between drawing the square and drawing the cross.

    Same pattern as before, but without the excess lines
    Look ma! No unwanted lines!

    One change I made: I moved the laser control to a 5V tolerant pin since the input is marked "TTL" and it wouldn't be unreasonable to find 5V their at some point. However, the input pin seems to float at around 1.8V, and connecting the pin to ground turns the laser off. Therefore, I set the PIC's output to use an open drain.


    I'm working on plans to mount all this hardware on the ceiling of my kitchen. I'm using Fusion 360 to model all the components so I can figure out how to place them and where all the holes need to go. It's taking a while, but I did make this blocky but dimensionally accurate laser galvo model.

    Another thing that needs doing is to rewrite the PIC32's DAC output loop. It has two problems. First, it's too slow to output 20,000 points per second to the galvos. Second, there's a bug in there because it seems to stop working from time to time. A rewrite will fix both.

  • Python Generated Shapes, Traced By Laser

    Alan Green07/12/2019 at 08:21 0 comments

    More progress: I now have a Python program, running on the RPi to send data to the PIC32 Frame Driver. It was about 500 lines of new C code, plus 100-odd lines of Python, but I can now dynamically update frames. 

    It projected this little thing onto my notebook.

    This is what success looks like

    As predicted, the communications protocol was tricky. I wrote a 4 page document to describe it. The main complication is that the PIC32+MP Harmony approach to the SPI chip select (aka CS, aka Slave Select aka SS) line doesn't conveniently allow it to be used to define the end of packet, which makes handling variable-sized packets difficult.

     As a result, the protocol I ended up with has fixed size command packets, and one of the commands says 'hey! there's data coming and it has length N'. The PIC32 then goes into a special mode where it waits for exactly that much data.

    Here's the state diagram from the PIC32's point of view:

    Abridged communications protocol state diagram
    Not shown: error handling transitions

    Also, inspired by Ben Eater's recent video about CRCs, I use 16 bit CRCs on all requests and responses. I used pycrc to both calculate CRCs in Python and to generate the C code for the PIC32. The PIC32 actually has built in facilities for CRC calculation, but I'm not clear on how to use it in conjunction with the MP Harmony SPI drivers. 

    Speaking of MP Harmony, I now have a whole rant about MP Harmony which I might polish up and publish.

    The Frame Driver is now Almost Finished Enough that I could start building the clock daemon that will run on the Raspberry Pi. However, I think my next task will be to integrate the new, 505nm 50mW laser that is due to be delivered mid-next week.

  • Mini update: power hungry lasers

    Alan Green07/06/2019 at 01:37 4 comments

    So far, my experiments have used the cat's battery powered laser pointer. Today, I disassembled a few laser pointers and powered laser modules directly from my bench power supply. 

    The green laser module was the brightest and looked the best. Also, I know it will be visible in the day time. According to the sticker that was on it, it is a "class III"  and "<5mW", which I believe makes it a class 3R laser, which I'm happy with from a safety point of view.

    However, it also draws between 250mA and 350mA, which is much more load than I want to put on the RPi's supply, especially since that load will be switched rapidly and repeatedly. 

    So, instead of using the output of the 3.3V LDO to supply the laser, I'll use a 12V wall adapter, along with an eBay buck converter module.

  • Test Pattern

    Alan Green07/01/2019 at 11:49 5 comments

      Progress! Here's a pattern generated by the PIC32, sent to the DAC, turned into twin differential signals by the op-amp and sent to the galvo:

      Pattern projected onto the window blind

      It is a cross inside a square. However, I have not yet hooked up the FET to control the laser, so the laser doesn't turn off while moving between the ends of the cross and the bottom left of the square.

      Apart from that, there are several noteworthy artifacts in this image:

      1. At three of the square corners, there is a spike where the mirror has - despite the closed loop control - overshot its destination and then walked back. It looks as though the Y galvo might have more problems than the X galvo.
      2. The end points of motion are very bright because the laser dwells on them for some time.  
      3. The path traced to and from the cross is quite curved.  I'm not entirely sure why.

      I plan to address all of these problems later in the build, after I have a basic clock showing.

      What's Happening With the Electrons

      Here's a scope screenshot showing SPI data being sent to the DAC. The DAC output we're following is channel 3, the magenta line.  The SPI command 0xBFFF causes to the output to transition from 0x000 to 0xFFF. The transition from min to max value takes about 6uS

      Channel 2 (light blue) is the signal inverted and amplified, then channel 1 (yellow) inverts the signal again.

      Over a longer period, we can see the differential output on channels 1 and 2 following the DAC output on channel 3:

      Notice that the op-amp output tends to drift toward 0V over the course of a few milliseconds. That's interesting.


      One thing I learned: the output pattern is reasonably stable despite not having a separate 3.3V supply for the analog circuitry. 

      Things to do next:

      1. Start sending patterns from the RPi to the PIC32.
      2. Solder up the laser fet to a laser so the dot can be turned on and off.

      Questions to answer some day:

      1. Measure the +/- 8 V and +/-15V rails while the galvos are operating. Is it noisy? Could the op-amps work directly with the 15V?
      2. How much of the overshoot is due to the settling of the op-amp output?
      3. Is the Y-galvo's overshoot problem specific to (a) the galvo, (b) the driver/amplifier board or (c) the output from the Frame Driver?

  • Another look at the Galvos - Closed Loops!

    Alan Green06/26/2019 at 09:28 0 comments

    It turns out that the galvos I bought are closed loop devices. When a signal is applied to them, the move to a new position, and they also give feedback about their position to their controller. This feedback "closes the loop".

    Taking the rear cover off one of the galvos shows the position sensor. It consists of an LED, two photodiodes, and a plate attached to the galvanometer shaft. As the shaft rotates, it allows more or less light to shine on each photodiode, which provides the feedback.

    I had been wondering why the galvo needed a six-wire connector. Now it seems obvious that two of the wires are for the galvanometer itself, and four of the wires are for the position sensor - V+, V- and two photodiode signals.

    This complexity also explains why each galvo control board has 4 quad op-amps: the board is an analog computer, trying to calculate how to accelerate and deaccelerate in order to bring the mirror smoothly to its new position with no over or undershoot. 

    I learned about the galvo position sensor from zenodilodon's Youtube channel, in particular the video "Inside the Closed Loop Laser Beam Stearing Galvanometer" in which Zeno shows several galvanometers that look like bigger versions of my cheapy.

    Yes, the production is a bit rough. Yes, those dead pixels are on Zeno's camera sensor, not on your screen. Yes, I too find the paint flecks on his hands distracting. Despite all that, it's a pleasure to watch a gifted professional dispensing the kind of helpful information and tips that can only come from experience. I am totally subscribed.

    Another one of Zeno's videos, "Complete Build of a 4 Watt Analog Modulated ILDA Show Laser" was also helpful. I'm building a just-good-enough for home single color, 5mW , digital version of the professional RGB, 4 Watt, four laser analog rig that Zeno puts together here. Plenty of good tips. My build will be simpler and involve less swarf.

  • Frame Driver Construction: MCU

    Alan Green06/25/2019 at 11:14 0 comments

    I spent the past few days soldering up the PIC32 MCU and getting it to work with the Raspberry Pi. 

    It's Going To Work. Hooray! There were a couple of tweaks to the schematic, one dead PIC32, and a couple of moments of utter confusion with Microchip's MPLAB Harmony, but we're now in a good place.


    I did this first since the PIC32 is an unknown for me - hence something that might go wrong. If it wasn't going to work, I needed to know early.

    As a proof of concept, I had the PIC32 use a timer to blink an LED in a pattern. It also acted an SPI slave, ready to accept data from the RPi that it would use to change the LED blinking pattern.

    Planning and Construction

    Initial Planning SheetThe picture to the right is a scan of my first planning sheet. While constructing it, I made a few changes, which you can see in the larger image, below.

    One of the nice things about working on a Blueboard#01 is that one can almost always try a new configuration if something doesn't work. It also lends itself to constructing a circuit in stages.

    The picture below is me getting excited about soldering up my first PIC32. Flux is on the footprint, and moving the chip into position.

    My First PIC32, Ready to solder
    Ready to solder

    The end result was fairly neat, with only a few solder blots. Most of the wiring is hidden on the back of the board.

    And the final planning sheet:

    Planning sheet, after further iteration
    Planning sheet, after further iteration

    Software and Testing

    The PIC32 sets up one timer peripheral and one SPI slave peripheral. It has a buffer containing a pattern.

    • When the timer times out, it turns the LED on or off according to the pattern.
    • When it receives data from the SPI peripheral, it updates the pattern.

    I used the MPLAB Harmony framework, the MPLAB IDE and the the MPLAB Snap programming tool. Microchip should send me a T-shirt.

    On the RPi side, I used Python and spidev. Spidev appears to be installed by default, which is great. It's pretty straight forward to send a bunch of bytes to an SPI slave.

    Here it is, all together. The laptop has a window open to the RPi, the RPi is wired to the PIC on the Blueboard#01, and the Blueboard#01 is being probed by the oscilloscope. 

    Everything working nicely

    There are a lot of wires. I did this because the PIC32 is highly configurable, and I wanted to make sure I had the connections right, so I used 0.1" header pins pressed into the Blueboard#01, with dupont wires to make temporary connections. I'll solder in permanent connections, behind the board now that I know it works.

    The oscilloscope is probing via a row of 0.1" header pins pushed into the Blueboard#01. With SPI running a 1 MHz clock, there were no problems at all. Channel 3 (magenta) is the clock:

    Oscilloscope trace at 1MHz
    No problems at 1MHz

    It also works at 20MHz. This is suprising to me, given all the dupont wires going everywhere. At 20MHz, the waveforms are less well defined:

    Lessons Learned

    • Power is hard, as always: I had intended to power the MCU from the RPi's 3.3V supply. Not a great idea as it turns out. The RPi's 3.3V supply seems pretty marginal, and the PIC's 30mA seemed to bring it close to failure. I watched the voltage dip 0.1V as the MCU turned an LED on and off. Instead, I chose to power it from the 3V3Ref linear regulator. I may need a second linear regulator later if it turns out the PIC makes this one too noisy.
    • Polarity is easy ... to get wrong. I blew up one PIC by connecting my bench power supply the wrong way around to GND and 3V3. They say that experience is what you get when you didn't get get what you wanted, and this was definitely an experience. The AVR chips I'm used to would have put up with that kind of abuse, but the PIC32 appears to be a different, more fragile class of device.
    • MPLAB Harmony is complex. The PIC's default programming environment uses the MPLAB Harmony framework. It took me several days to wrap my head around it. I made peace with it for now - Most Things Just Work Once You Know How.
    • Protocols require attention. The...
    Read more »

  • Frame Driver Schematics

    Alan Green06/22/2019 at 03:04 0 comments

    Following on from last posts' high level design, I drew up schematics. I like to keep each part of the schematic down to about one A4 page, so I can easily print it all.

    These schematics represent a point in time. The will change as the project goes on. When I'm finished I'll upload them in full.

    Voltage Shifter

    The voltage shifter takes the DAC_X and DAC_Y signals, and turns each into a differential pair suitable for input to the galvos.

    Voltage Shifter Schematic

    Based on my experiments with the signal generator, I don't need the full galvo deflection range, so I decided to go for an +/-8V differential range rather than the full, standard +/-10V range. 

    Generating the signal is two step process:

    1. We take the DAC's output range of 0-2V, and map it over the range 4V to -4V using one op amp. I
    2. We then find the inverse of that signal by using an op amp in standard inverting buffer configuration.

    In step 1, we map the DAC's range somewhat upside down, by mapping 0V to 4V rather than -4V. The reason for this is that the op-amp configuration is more straight forward this way. Since we are always going to need both the positive and negative signal, it doesn't matter at all which we calculate first.

    I used the site earmark.net to understand the required amp configuration and calculate resistor values. Bruce Carter has been extraordinarily generous in providing this resource. 

    [Parenthetic note: the DAC's actual range is 0.01 to 2.048V, but using 0-2V significantly simplifies the selection of values. I'm using 1% resistors, so the error from this simplification is much less than the accumulated error from other sources.]


    The PIC32 has some requirements, handily documented in section 2 of its datasheet. At least we don't need an external clock crystal. The Raspberry Pi comes with all its own support circuitry and the schematic just shows the Frame Driver's connections to the RPi's I/O header.

    MCU Schematic showing PIC32 and RPi connections

    In addition to the usual bypass caps, the PIC32 requires:

    • a small reset circuit,
    • an expensive 1uF tantalum capacitor on Vcap to stabilize the internal LDO power supply.

    There are also a couple of buttons and LEDs for debugging purposes.

    (Looking at the schematic, I can see I'll likely want to add a reset push button, too. )

    DAC and MOSFET

    These are devices the PIC32 sends commands to, in order to drive the galvos and laser.

    DAC and MOSFet schematic

    We power the DAC from a special 3V3 supply (3V3Ref) to help ensure the stability of its internal voltage reference. 3V3Ref is also shared by the voltage shifter. 

    The DMN2046U N-channel MOSFET controls power to the laser. Because the FET has ~300pF of capacitance, there's a 100Ω resistor inline on the LASER_FET output pin to reduce maximum output current to a peak of about 33mA - which is still twice the "maximum allowed" of 15mA. (Interesting discussion about gate resistors on Stack Exchange.)


    In previous projects, I've been bitten hard by noisy power supplies. This is likely overkill, but I'll start from here and then maybe experiment with removing some of it.

    Power supply schematics

    I am using an 7808 and 7908 to generate +/-8V from the galvo's +/-15V supply. The values of capacitors were taken from the datasheets, but I don't think they're particularly critical. The +/-8V is used to power the op-amps. While the op-amps can happily use +/-15V, its not clear to me that the power supply would be clean enough, especially when the galvos are under high load.

    3V3Ref is generated from the RPI's 5V supply. It's purpose is to be a clean 3V3 supply for the DAC and to be used as a reference by the op amps.

    Next steps: soldering!

  • Frame Driver High Level Design and Component Selection

    Alan Green06/15/2019 at 02:53 0 comments

    The purpose of the Frame Driver is to receive a "frame" of data from the Raspberry Pi and then output it until it receives a new frame. The Frame Driver will guide the laser beam around a path over the course of 1/30th or 1/50th of a second, turning the beam on and off as appropriate, and then do it, over and over again.

    There are several steps between receiving a frame from the Pi, and outputting voltages to the Laser Galvos.

    High level block diagram showing Frame Driver components
    Frame Driver and its components


    I've decided to use a ‎‎PIC32MX170F256B-50 microcontroller. There were several reasons:

    • The PIC32 is big enough that things are easy. It's definitely possible to do this with a smaller controller - see cfavreau's Arduino-powered Open Laser Show DAC - but I didn't want this to be hard to program, and I have no intention of large-scale production. 50MHz, multiple SPI peripherals, 64k of RAM and 256k of flash is more than enough. Cheap 32 bit arithmetic will likely help, too.
    • The PIC32 is a relatively simple, controllable processor. I will be able set timers and handle interrupts to microsecond accuracy. The problem with Raspberry Pis and BeagleBones in this application is that they multiplex so much that they are no longer able to faithfully handle strict timing requirements. Listening to Bart Dring on The Amp Hour #438 talking about the ESP32 GRBL interpreter, the ESP32 could probably handle the timing requirements, but it's not trivial. 
    • I've been wanting to learn PIC32 for a while now.


    I chose MCP4822 dual 12-bit DAC. It has an internal 2.048 voltage reference and has an SPI interface. 

    In this post on laserpointerforums.com, the consensus seems to be that an 8-bit DAC is not sufficient, but that a 12-bit DAC is plenty. 12 bits gives 4096 steps, which would be somewhere between 0.2 and 0.4mm per step on my kitchen wall, which seems sufficient, especially given that the laser beam is 1-2mm mm wide. Beyond 12 bits, things start to get quite pricey, and there's little additional advantage in having 0.05mm precision over 0.2mm precision at normal view distances.

    For the cheaper DACs, there are two common standards for loading data: I²C and SPI. Generally, SPI is a faster protocol, both in terms of physical link speed and in having a lower protocol overhead. The MCP4822 can transfer data with a 20MHz clock and I am expecting to be able to use at least 5MHz. 

    Outputting two values from the MCP4822 DAC requires two 16 bit SPI transfers and then setting the LDAC pin low. At 5MHz, this will take (16 * 0.2 * 2 + a bit)μs ~= 8μs, which is fast enough. The DAC requires a "typical" 4.5μs to change its output signal from one level to another, anyway.

    To ensure that the internal voltage reference is stable, a very stable power supply is required.

    Voltage Shifter

    The final component in the Frame Driver is the voltage shifter which takes two single-ended 0-2.048V signals and amplifies them to the +/-10V differential signals (maximum magnitude of any given line is +/- 5V) expected by the Galvo controller boards. It will be composed of 4 op amps, in a single package. I chose the TL084, because cfavreau used it successfully in his Open Laser Show DAC. It's also the same part used on the Galvo driver boards. 


    Finally here is how I plan to power each of the components:

    ComponentWhat it NeedsHow it Will Get it
    PIC323.3V, < 100mA. Pull from RPi 3.3V pins
    MPC48223.3V, a few mA, low rippleDedicated 3.3V regulator running from from RPi 5V pins
    TL084+ and - 8V supplies, <20mADedicated regulators running from Galvo +/-15V supply lines.

  • First Light

    Alan Green06/08/2019 at 11:22 0 comments

    In which I wire up the laser galvos in minimal way, validate some concepts and learn some new things.

    Turning on The Galvos

    Here's what I did. At each step I was careful to test to make sure that no smoke came out and that everything behaved as expected. 

    1. Wired up the power supply to a mains plug,
    2. Connect power to the driver boards
    3. Connect the driver boards to the galvos

    At that last step, the galvos moved! I had not been expecting them to move, but it seems that their off position is at one end of their range.

    At this point, I used Blu-Tack to hold everything down, just to make sure nothing got lost in the tangle of wires. These are the grey blobs you can see in the photos above.

    I then stole the cat's spare laser pointer, Blu-Tacked it in place and lo! there was a dot.

    Signal Generator and Pretty Patterns

    I have a dual-channel signal generator. Using a Blue Board #01 I soldered up a couple of connections. Each driver board is fed by three wires: ground, V+ and V-, with V+ and V- carrying a differential signal of up to 10V. I tied each driver board's V- signal to ground, then piped in the signal to V+.

    The resulting patterns look different on camera than they do in real life, but are interesting nonetheless. The shapes are correct even if the colors are not.

    Lissajous Pattern
    The ABC of Lissajous
    Another pattern, Lissajous like
    Space uniform logo
    3rd example Lissajous pattern
    Neon crochet pillow

    Here are some things I learned:

    • The upper frequency limit is around 1kHz. Above that, the range of movement becomes limited.
    • Above 500Hz or so, the movement of the galvos makes an audible sound. The sound becomes louder with higher base frequencies, with larger signal amplitudes and with more complex waveforms, especially those with higher frequency components.
    • The driver board heat sinks get quite warm. 
    • The power supply does not really get warm 
    • 50Hz is plenty for making a stable looking image.
    • The mirrors and galvos have momementum and it causes overshoot and undershoot.  Any drawing sequence is going to need to take these physical effects into account because it's not like drawing pixels on a screen.
    • I will need a higher power laser for day time viewing. The cat laser is going strong after several hours.

    I think this is going to work!

  • Looking at the Galvos

    Alan Green06/08/2019 at 05:43 0 comments

    What I Bought

    I bought the cheapest laser galvo mirror set that I could buy, that also had reasonable shipping. I ended up with this one.

    Picture of a laser galvanometer set
    The kind I bought

    The set comes with the twin galvanometers, mounted on a metal block, two driver boards and a power supply. It cost about 100AUD on eBay (listing). Several of the sets on sale also offer a "show card", which will run laser displays from an SD Card. I wanted to build the display logic myself, so I didn't buy a show card.

    The specs from the listing are:

    -Input voltage:15V
    -Peak current: 1A
    -Rated current:0.5A
    -Operating temperature:0~50℃
    -Rated scanning angle:± 20 °
    -Maximum scanning angle: ± 30 °
    -Drive plate size:76mm × 48mm × 26mm
    -Analog signal input impedance: 200K ± 1% Ω (differential input)
    -Analog position input range: ± 5 V.
    -Scanning speed:20Kpps
    -Lens reflectivity:> 98% @ 45 ° incidence (coverage wavelength: 380nm-700nm)

     Important to note here:

    • They are rated for 20kpps (20,000 points per second) at 20°. Here is a description of how that test is supposed to have been done. Note that, at the rated speed, the produced pattern looks different to how it does at a lower speed. The galvo mirrors aren't magical after all - they take a finite amount of time to move into position.
    • The galvanometers are rated as consume 1A 15V, peak. That's quite a bit. One can see why a driver board is required.
    • Input impedance is high, which is good.

    Given the amount of power consumed, I think it's probably a good idea to aim for smaller angles of defletion and slower scan rates.

    Power Supply

    The supply came with two 3 pin connectors pre-attached to the output screw terminals. I confirmed with the multimeter that FG is connected to the chassis, while N & L are not. The G terminal is not connected to FG or to N (or L!).

    +/- 15v supply that came with my laser galvos
    Supply and Connectors

    Label on the power supply says it supplies 1A at 15V, which nicely matches the peak current draw spec.

    Input 100-240VAC 0.5A. Output +15V 1A, -15V 0.5A.

    There's quite a difference between input power rating (0.5A@100V = 50W) and output rating(1.0A@15V + 0.5A @ 15V = 22.5W). I suppose this means that the supply gets hot.

    This is all about what I expected.

    Galvos and Mirrors

    As noted above, the galvanometers are firmly aligned in a metal block. Under the block are screw holes which are obviously useful for securing the block.

    Galvanometers with mirrors, attached to a metal block
    The interesting bit

    Hmm... looking at the photo, that mirror seems a little dusty. I'll need to clean them. The galvanometer PCBs each have the galvanometer, the connector, and nothing else:

    I'm not entirely sure why the connectors have 6 terminals each, but based on the cables, I'm guessing the galvos give some kind of feedback to the driver board.

    Driver Boards

    These boards are responsible for amplifying a high impedance, 10V differential signal into a low impedance 15V signal. 

    I've marked the connectors with their apparent function. There's signal input, two power connectors and an 8 pin output connector. The picture at the top of the page shows the cables that run between the 8 pin output connector on the driver board and the 6 pin connector on the galvo. The conductors run in two bundles. 

    Trimpots and Unknowns

    The trimpots along the bottom each have two-letter markings on the underside of the board. I've put these markings in the picture. Based on this Aliexpress listing for a similar product, I'm guessing the meanings are:

    • PS = Position Scale
    • LIN = Zero Offset
    • LFD = Low Frequency Gain
    • HFD = High Frequency Gain
    • SG = Servo Gain
    • IS = Input Scale

    All of them appear to be locked with a small amount of glue, except Input Scale. I won't touch any of them.

    There is a 2x3 header area with two jumpers on it, next to the input. No idea what that is for. 

    Similarly, there's a 2 pin connector in between the trim pots that I have no idea about.


    The 3 14-SOIC packages on the driver board appear to be TL084 Quad JFet Op Amps (datasheet), which cost about 0.20USD...

    Read more »