Memory: The ESP32 has much more RAM and program space to allow more features, levels and audio files.

Physical Size: A Mega is very big. This creates a large enclosure that takes a while to print. The smaller enclosure is also more portable.

DAC Pins: The audio capabilities on the Mega are very crude and basically limited to square wave tones. A DAC can output digital audio. Currently I am just using a similar square wave tone to the Mega, but it works much better for adjusting the volume.

Wireless: The ESP32 has Wifi and Bluetooth. This will allow easier (smartphone) interfacing for options (brightness, volume) and level pack uploads. I also want to consider dual player battle type games with linked controllers.

The Audio

The original TWANG bit banged audio directly from I/O to a speaker. This was super simple, but the volume at max was not loud enough for noisy environments. The ESP32 I/O is a lower voltage (3.3v) and less current, so something needed to be done. I prototyped with a PAM8403 based amplifier (~$4 on Amazon). This worked great, so I added that I.C. to my shield. The volume is controlled by the amplitude of the DAC.

The Shield

I made a shield to simply the wiring and provide a stable way to mount the ESP32. I used a NodeMCU 32S development board for the ESP32. Under the ESP32 is a the audio circuitry. I should have some extra boards to sell on Tindie soon. I will publish the source files soon.

The Firmware

The code is on Github. The port was relatively easy, but I had to rewrite a few libraries. They were designed so the main “setup” and “loop” parts did not change much. Currently the serial port based setup from the Mega version was not ported. This probably won’t be used. A wireless version is in the works.

Enclosure

The new enclosure is smaller. It prints quicker and is easier to fit in my backpack. The size is still big enough to hold comfortably while playing. The files will be uploaded to Thingiverse within the week.

Next Steps

Wireless control: I want a simple way to read the game statistics (average score, levels played, boos kills, etc) and tweak simple settings like audio volume and brightness. I think the easiest way is to make it a wifi access point with a simple web server. This eliminates having to write any client side apps and any smartphone or computer can hope on easily.

Levels: Make some way to edit or upload levels via wifi.

Multiplayer: I should be able to link multiple controllers. If I can think of a good dual player game idea, I might try to add that.

Python: It might be a fun challenge to write the game in Micro Python. This might open up the development to more people.

I have been working on some games for the ESP32 and needed some decent quality audio with a minimum number of additional components. I was bouncing between using the DAC and using the I2S bus. The DAC requires less external parts, so I went that way. I ended up creating a very simple library for use in he Arduino IDE. (Note: This only works with ESP32)

DACs

The ESP32 has (2) internal 8 bit DACs. DACs are Digital to Analog Converters. You give them an 8 bit value and they output an analog voltage. The voltage range of the 0-255 8-bit value is roughly Gnd to 3.3V on the ESP32. If you digitize an audio file, you can then play it back through the DAC. The DAC can’t directly drive a basic speaker, but you can connect it to an amplifier or amplified external speakers. The 8-bit quality is not great, but more than good enough for simple games.

The sound data comes from wave (.wav) files. This uses the 8 bit, unsigned, uncompressed format. Wave files can be saved with any sampling rate you want. To get a decent sound you need to sample the analog files at thousands of times per second. I have found that 4000 Hz is about the minimum for anything musical or spoken. 8000 sounds pretty good for most stuff. For reference, CDs are sampled a 44100 Hz (also 16-bit not 8-bit). This means there is a lot of data even for short duration audio. The typical ESP32 board has 2 to 4MB. At an 8000Hz sampling rate that gives you 125 seconds per MB. That is plenty for what I am working on, so I decided to store the data on the ESP32. If that is not good enough, you could use an SD card.

Here is a reference of the wave format. Only a few of the values are used.

Byte

Length

Description

0

4

Always "RIFF"

4

4

File size in Bytes

8

4

Always "WAVE"

12

4

Always "fmt " with a null

16

4

Length of format

20

2

Audio format (1=PCM)

22

2

Number of channels

24

4

Sample rate

28

4

Byte Rate

32

2

Block Align

34

2

Bits per sample (8,16)

36

4

Alaways "data"

40

4

File size

44

...

Start of data

References

I found some good references to help me with this library.

IoT Sharing: This was a great reference for understanding the basics, but it uses an SD card to save the data.

I started with the Xtronical XT_DAC_Audio library, but found it got be very unstable when I added it to my game. It often crashed when seemingly unrelated code was added. I think the problem was due to trying to use floating point math in the interrupt. As soon as I took that out, it got very stable. They make reference to the issue in the code and suggest it could get fixed via compiler updates.

How it works

The wave data is stored in large char arrays. An interrupt reads the data and feeds that to the DAC. Using an interrupt allows the audio to play “in the background” while the game is running. The Xtronical library uses a fixed interrupt rate of 50kHz. It does some floating math in the interrupt to adjust to the actual sample rate of the wav file. I decided to change the interrupt rate to the actual sample rate of the wav data.

The sample rate is stored in the header of the wav data. When you play the file, it sets the interrupt rate to match the sample rate, so no math is required. You can use a mix of sample rates in the waves you use. It will adjust as needed before it is played back. It allows 2000Hz to 50000Hz sample rates. If you try to go outside that range it will use 2000 Hz. You will easily know there is a problem if you hear that.

Game Related Features

I added some features that might be needed when using with a game.

Check to see if the audio player is currently playing anything.

Interrupt The Current Wave – If something happens like an explosion you need to immediately switch to that sound. This is an option when you send a command to play a wave.

Change the Frequency – I had some sounds that needed to change based on game speed. There is an option speed up r slow down the play back speed by a multiplier to give.

Create a Game_Audio_Class object. The first parameter is the DAC pin number you want to use. It should be 25, 26. The second parameter is the timer number to use. Example: Game_Audio_Class GameAudio(25,0);

Create a Game_Audio_Wav_Class object. The only parameter is name of the char array of you wave data. Example: Game_Audio_Wav_Class pmDeath(pacmanDeath);

I have been playing with the ESP32 microcontroller to see how well it would perform as a small scale CNC controller. The low cost and high performance as well as the built in Wifi and Bluetooth make it very attractive.

One of the challenges is step pulse timing. Most stepper drivers work with a direction signal and step signal. The step signals are a short pulse for each step. If they are too short, the driver will not detect them. If they are too long, it limits the rate at which you can send them.

You first set the direction signal high or low depending on the direction you want the motors to spin. You then send the step pulse. The direction signal has to be stable for a short period of time before the step signal is sent. The process is…

Set direction

Wait a bit (if it changed)

Turn on the step pulse signal.

Wait a bit

Turn off the step pulse signal.

The timing is critical and varies by motor driver. Here is a typical spec.

Here are the specs for a few of the stepper drivers I regularly use.

Allegro A4988

TI DRV8825

Toshiba TB6600

Direction Delay

200ns

650ns

?

Step Pulse Delay

1us

1.9us

2.2us

Test Firmware

Typically the firmware motion planner determines when to take a step, then sets an interrupt to occur at that time in the future. This allows the firmware to do other things like interacting with the user and planning future moves while it is waiting for the interrupt.

To simulate a stream of pulses, I created a timer interrupt that would case steps to occur at a constant 5kHz rate. That is onStepperDriverTimer() in the code.

In that interrupt service routine I first set the direction pin. Normally you only need to set it when the direction changes, but it will be easier to see this on a logic analyzer if I change it every time for this test. I then need to wait a little time before setting the step pulse pin. I could use another interrupt to do this, but the time is so short at about 750ns, that it is better to just waste a few cycles. In the CNC software I will only need to do this when the direction changes. That will be at the few beginning of the acceleration when the step rate is the slowest. I do this delay with a few NOP()s. The are “no operations”.

I then setup the the interrupt to end the pulse. That is onStepPulseOffTimer() in the code. I set the step pin after this because those instructions take clock cycles too. I can use those as part of my delay.

When that interrupt occurs, I turn off the step pulse signal. I also turn off the direction in this example. I am only doing it here so I can see that change on the logic analyzer. Normal CNC frmware would just leave it alone because there are typically thousands of steps before the direction is likely to change.

I wrote a program to simulate some CNC firmware so I could play with step pulse timing.

Results

Here is a picture of my setup.

This is screen shot of what the logic analyzer captured. The upper line is the step signal and the lower line is the direction signal. The direction signal comes on first and then the step pulse signal comes on 0.75us later. The step pulse then lasts for about 2.5us before turning off.

Next Steps

I’ll go forward this method to see how well it works in actual CNC firmware.

I have been programming in the Arduino-ESP32 environment. This is an easy way to learn about the peripherals and do some quick tests. I may switch to the ESP-IDF in the future.

I would like to investigate the RMT features of the ESP32. It is designed for Remote Controls, but I have heard it is quite flexible and might help with pulse generation.

In a previous post I showed how to use the HC-06 Bluetooth module. In this post we will be using the HC-05. They are very similar, but the HC-05 has more features. The ability to be a master is the main feature. A master can create a connection with other Bluetooth devices. In this post we will only being using it as a slave.

The basic module looks like this.

It is typically purchased soldered to carrier PCB with some additional electronics. The HC-05 typically has a 6 pin header, rather than the 4 pin HC-06 header. The two extra pins are state and enable (en). State gives the state of the Bluetooth connection and enable can power down the module by turning off the power regulator. I will not be using the enable. I will use the state to allow programming of the Arduino via Bluetooth.

Here is a schematic of the carrier board. Not all carrier boards are the same, though.

The parts on the carrier PCB are pretty basic

3.3V Low Dropout Regulator, which allows you to power it from 3.6V to 6V.

An LED to show the mode.

Fast Blink = Waiting for Bluetooth connection3.6

Slow Blink = In AT command mode

Double Blink = Connected via Bluetooth

A button to enter AT Command Mode

A diode, probably for reverse voltage protection.

Various Pull Up/Down resistors and bypass capacitors.

Configuring the HC-05

Like the HC-06, the HC-05 has a AT command mode, but the commands are a little different. The HC-05 is put in the AT command mode by holding in the switch while applying power. It will do a slow blink when in AT mode. AT Mode accepts commands at 38400 baud , N,8,1 using the Rx and Tx pins. You should level shift the Tx out of your Arduino to 3.3V using a resistor divider. Commands are sent with line feed and carriage return appended to the end. Most serial monitors can do this for you including the Arduino Serial Monitor.

Any command that sets a parameter can also get it.

Set commands are in this format “AT+CMD=PARAM” like … AT+NAME=FRED to set the name to FRED. Some commands have multiple parameters that are separated by commas.

Get commands are in this format AT+CMD?” like AT+PSWD? to get the password. Weirdly, they all seem to work except AT+NAME?.

Here are the commands you needs for slave mode. Remember, each is followed by a line feed and carriage return.

AT+POLAR=a,b (a=PIO8 (LED), b=PIO9 for both 0=low turn on, 1 = high turn on. (see below for how we use this)

AT+ORGL (reset all parameters to defaults)

AT+RESET (restarts the HC-05. Will not be in AT mode afterward unless button held”)

Using an Arduino to program the HC-05

We need some hardware to talk to the HC-05. An Arduino will easily do that. Here is a diagram and sketch to do this using an Arduino UNO.

This is the hardware diagram. I show an UNO, but virtually any hardware (Nano, Mega, etc) will work. The HC-05 is a 3.3V device so we need to level shift the Arduino 5V Tx signal down to 3.3V. The diagram uses a resistor divider to do this. The Arduino should have no trouble reading the 3.3V Tx signal from the HC-05, so we don’t need to shift that.

The State connection through the capacitor is optional. This will force a reboot of the Arduino when a Bluetooth connection is made. More on that later.

BTW: A lot of people don’t bother to level shift and it appears to work fine, at least in the short term 🙂

The Arduino Sketch

Here is the sketch I use. We will be setting up 2 serial links. One link will be from the PC to the Arduino to send the commands from the keyboard over USB. We also need a serial connection from the Arduino the HC-05. We will use a software serial port for this and can use any remaining pins to do this. HC-05 uses 38400 baud for AT commands, regardless of the what you set it to for Bluetooth operation. I used 115200 for the PC to Arduino connection. Set the Serial monitor like this.

Arduinos are programmed over serial via a bootloader. A bootloader is program that runs for a few seconds whenever the Arduino is started. It looks for someone trying to program it. It runs in one part of the Arduino’s memory. If it does not detect an attempt to program the Arduino it switches to the part of memory where the last program (sketch) resides. If it does detect an attempt to program the Arduino, it reads the incoming program instructions over the serial port and writes them to that other part of memory where normal programs (sketches) reside. Once the upload is complete it switches to that program and runs it.

Therefore, in order to program the Arduino over a serial connection, you need to trigger a reboot. The Arduino USB creates a full RS232 connection. In addition to Rx and Tx is has other control lines like DTR (Data Terminal Ready). The Arduino uses the DTR signal to force a reset. To reset an Arduino you pull the reset line to ground. The DTR signal out of the USB chip is high when there is no connection and low (ground) when there is a connection.

If we directly connect DTR to the reset pin, the Arduino will be stuck in permanent reset mode whenever a serial connection is open. To correct that, a capacitor is inserted in the circuit. Capacitors block a continuous signal, but pass a quick transition. Therefore the the change from high to low will look like a quick pulse to ground at the reset pin. That pulse is exactly what is needed to reboot run the bootloader.

Here is what that circuit looks likes on an Arduino Nano schematic. The length of the pulse depend on the value of the capacitor and characteristics of the high to low transition.

The HC-05 state pin will work for this. In its normal mode it is high during a connection. We need that to be low (ground). Fortunately the HC-05 has the Polar command. That allows you to flip that logic. AT+POLAR=1,0 will do the trick. The first parameter is for the LED. We leave that at 1. The second parameter is the state and we switch that from the default of 1 to 0.

I found that the typical 0.1uF capacitor would not generate an adequate pulse to ground, so I bumped it up to 1.0uF. It occasionally does not work when uploading. I think a little less capacitance might be better. The Arduino uses the hardware serial connections for programming, so you use those pins. When programming the Arduino use the virtual serial port you got when pairing the Bluetooth. Do not use Bluetooth and the USB serial port at the same time. Both would be connected to the hardware Rx and Tx and conflict with each other and possibly cause damage.

Other Reset Features

You may not care about uploading code over Bluetooth, but some of your applications may expect that reboot on connect behavior. I have found this with some GCode senders. They open the serial port and expect to see the text Grbl spits out at startup. Without seeing this text, the program wrongly assumes there is a problem and closes the connection.

When you have a round work piece like a drink coaster, it makes sense to have a round work area. A round work area works best with a polar coordinate system. A polar coordinate system uses an angle and a distance from a center point to define a point in 2D.

The problem is that most drawing and CAM programs work in Cartesian (X,Y,Z) coordinate systems. My machine controller firmware, Grbl, also works in normal linear X,Y, and Z. The process of converting one system to another uses Kinematics.

The Firmware

The firmware is side is actually quite easy. I defined the X axis as the distance in mm from the center (the radius). The Y axis will control the angle. The Y axis is setup so that millimeters will equal degrees. If I tell the Y to move 360mm, it will actually rotate the work area by 360°. I could have used radians, but my brain works a lot slower in radians.

The machine will only need to home on the X axis. It needs to know where the exact center of the work area is. The starting angle does not matter because the coaster is a circle.

The conversion from X, Y to polar is probably won’t fit in into the firmware, so the X, Y conversion is done in a preprocessor software program. The X,Y gcode is output from normal CAM programs, then run through a conversion program.

The Conversion Program

The program reads the X,Y gcode, converts any X or Y coordinates into polar coordinates and outputs a new gcode file. The sender simply sends the new files. The math is actually quite simple.

Typical Gcode sends line data by giving the end points of lines. You simply draw from one point to the next, unfortunately this creates a few problems with a non linear machine.

The basic non-linearity problem

If we were trying to draw the green square centered on the work area, the generated gcode would basically send the corner points. Each corner point has an equal radius to the center. Therefore, the pen will never change radius when going to the next point. This will result in a circle. We want the green square, but we get the red circle.

We need to calculate each point along the way to stay on the desired path. The preprocessor divides the line into tiny segments. Each segment has the same problem, but at a scale you won’t be able to see.

The Spiral Problem

If we are drawing a shape that crosses the 0° angle we don’t want the angle to spin the wrong way. If a point is at 350° and the next point is 10° (crosses over 0) we don’t want it to spin backwards from 350° to 10°. We want it to go to 370°. It happens anywhere the angle difference between 2 points is greater than 180°. The program will choose the shortest direction even if that means going above 360° or below 0° degrees.

The Feed Rate Problem

Feed rate, in CNC terms, is the speed of the tool across the material. The CAM software is setting the feed rate as if this were a Cartesian machine. On this machine, if you were drawing a circle, you would simply move 360 units in Y. Without compensating feed rate, the pen would move across the work piece faster for larger diameter circles. I want to do some sort of compensation to help with this. The coasters are very absorbent, so the lines look thicker if the speed is slower. A consistent speed will help the quality of the work.

Since the lines are all very short, the easiest way to compensate for feed rate is to use the current radius. With a simple circle, Grbl thinks the machine moved 360mm. The real distance is easy to to calculate from the perimeter of that circle.

We can compare it to the 360mm (full circle) and apply the ratio to the desired feed rate from the CAM program.

polarFeedrate = cartesianFeedrate * 360 / (2 * pi * radius)

Video

Here is a video of it. The machine is rerunning a file to see the repeatability.

Next Steps.

I would like to automate the preprocessor. I think a Raspberry pi, might be an easy way to do this. It would sit between the sender and the controller.

The TB6600 stepper drivers I have in the X-Controller have a “Torque” feature. You set the motor current with a reference voltage and the torque feature allows you to easily switch between that current and 1/3 third of it. This is typically used for an idle current reduction feature at the system level.

Why Idle Reduction?

Stepper motors have a lot of hold torque, but that torque quickly falls off with speed. Therefore you typically size a stepper motor and set the current for your maximum cut or rapid speed. This means your motors will have excess torque when idle and will tend to run hottest at idle. You basically the the current as high as possible until the motors get too hot. If you could reduce the current at idle, you would reduce the temperature and could set the current higher than normal when spinning.

This is great, but the machine will never be in idle during a long job. At least one of the motors should always be running. If you could figure out when each individual motor was idle, you handle each motor independently. That is not easy in firmware, but there are tricks to do it in hardware. You could tie the feature to the step pulse. Whenever the step pulse is active, the full torque could be active. That has two problems. The step pulse is extremely short, in the range of a few microseconds. The other is you might want the current high for a a short bit after the motor goes idle just to make sure the machine is stable in the new position.

The trick is to use the step pulse, but extend it to the desired duration. It should stay on through all the step pulses and extend the last pulse.

Discrete Hardware Solution

The X-Controller uses a discrete logic chip to do this. It uses a retriggerable monostable vibrator (74HC123D). The R/C circuit on the right of the schematic snippet sets the duration. It works great, but this adds a lot of parts and things are locked down and not easily adjustable. If you needed to override this function, you have to break out the soldering iron.

PSoC Solution

With PSoC, when you hear “discrete logic” you should know there is probably a good way to do it on the chip. In this case I designed a custom component using verilog.

The verilog code is quite simple. The best part is none of this is done on the CPU, so there is no impact on the motion control performance. What the video to see the details.

I am very happy with the X-Controller. It packs everything you need to run Grbl into a clean little package. It is super easy to hook up and move between machines. With that said, I had a quite a bit different idea in mind when I began the design.

The X-Controller was designed to be the motion controller for the X-Carve. The “X” in X-Carve was meant to signify that it was sold through a configurator and there were a lot of options. The X-controller was going to follow the same concept. It would support Grbl,Beaglebone Machinekit, Smoothy, and others. Additionally, alternate stepper driver PCBs might be developed.

To enable the configurability, the stepper driver section would be separated from the controller section. Every feature the stepper drivers supported would be available to the controller. The plug in controller PCB would control the features via firmware or jumpers and pots, depending on the power of the controller. The current X-controller has 4 stepper drivers, but (2) are wired together. In the split concept the controller card would decide how that was done.

At the time Easel was starting to get some real traction and Easel only supports the Grbl protocol. We decided that it was best to pick the easiest solution for our customers and make the X-Controller Grbl only.

My experiments in Beaglebone and PSoC have been such tangled messes of wires. I always wished I had that disconnected stepper PCB. I finally decided to make one.

The XCC Stepper Driver PCB uses the same Toshiba TB6600 drivers as the X-Controller. It fits in the X-controller just like a stock PCB, but it is quite a bit shorter. The interface side of the PCB has (1) 2×5 right angle header connector for each axis. Brought out the the connector are…

Step

Direction

Torque (high=full current, low=1/3 current)

Enable

Micro-stepping selection

VRef (sets the motor current)

Ground and VMot

For this version, I put a current selection pot and micro step selection jumpers for each axis to simply testing. These function should be on the controller board, so most of these will be built without those installed. The PCB also needs 12VDC to 40VDC power for the motors. Each driver has a small 5VDC supply built in, so an external source is not needed.

Here is a snapshot of the schematic. This is just 1 of the 4 identical sections.

Here is snapshot of the layout. I was able to get everything on 2 layers.

It fits into the X-Controller great. I used a small piece of black acrylic to fit the gap due to the shorter length. It is working perfectly. I have been testing it with my PSoC port manually wired in. A PSoC5 controller will probably be the first controller card I will have made.

Paul Kaplan, originator of the Easel project, came up with another way to do the kinematics for the Line-us Clone. My method used intersecting circles. His method uses the Law of Cosines.

The Law of Cosines relates the lengths of the sides of a triangle to the cosine of one of its angles.

This can be used to find the angles of the servo arms.

(Click on the images if you want a larger view)

The Goal

The goal is to find the two angles, A1 and A2, of the servo arms

Known Values

Px is the desired X location of the pen

Py is the desired Y location of the pen

L1 is the length of the upper servo arm (50mm)

L2 is the length of the end of the Pen Arm (50mm)

Step 1

Find the distance “D” of the pen to hub using the Pythagorean Theroem and the angle T1 using arctangent.

Px2 + Py2 = D2

rewritten … D = Sqrt(Px2 + Py2)

T1 can be found using the arctangent or inverse tangent formula. Note: When programming use the atan2(x,y) function to preserve the quadtrant.

T1 = atan2(Py,Px)

Step 2

Find T2 using the Law of Cosines

L12 + D2 – L22 = 2 * L1 * D *cos(T2)

rewritten … T2 = acos( (L12 + D2 – L22) / (2 * L1 * D))

Step 3

Find T3 using the Law of Cosines. We want the left one of the two T3 angles, but since the linkages form a parallelogram that same angle shows occurs in several places. We will use the right one and the dimensions associated with it.

L12 + L22 – D2 = 2 * L1 * L3 * cos(T3)

rewritten … T3 = acos( (L12 + L22 – D2) / (2 * L1 * L2))

Step 4

Determine A1 and A2 from the angles we figured out.

A1 = T1 + T2

A2 = A1 + T3

Conclusion

I think I will switch the code to use this method. I think I can optimize it better in C code. The speed of the code is important. The faster it runs, the most times per second we can run it. The more often we run it, the smoother it will run.

The PSoC family is my go to line of processors for prototyping. It is like having a breadboard full of digital and analog circuits that you can wire up on the fly. I have been doing some stuff with hobby servos lately so I needed to figure out how to do it on the PSoC.

Hobby Servos

From Wikipedia

Image from Adafruit

Hobby servos set their rotation based on the length or a repeating pulse. The pulse should be 1ms to 2ms long and repeat every 20ms. One end of the rotation is at 1ms and the other is at 2ms.

The PSoC PWM Component

The PWM component is perfect for this job. The PWM component can be setup to have a period and an on time. The period should be 20ms and the on time would be between 1ms and 2ms. The component uses a clock and two counter values. The component will count on every clock pulse. It resets the counters after the period count has been reached and the CMP value determines how long the pulse is logic high.

The PWM output goes to the servo control line. Here is the configuration dialog box for the PWM component. The graph at the top is a good reference for what the output will look like.

The goal is to have a pretty decent resolution to set the 1ms to 2ms pulse. I chose a 2MHz clock. I picked the fastest clock that would still fit within the 16bit (65535) limit of the control. PSoC clocks are derived from system clocks, so you need to pick values easily divided down from them. The IDE helps with creation of these clocks. At 2Mhz the period (repeat rate) should be set to 40,000. The equation is the clock * period(in second) = period counts (2,000,000 counts/sec * 0.02 secs = 40,000 counts).

The CMP Value is how many counts the high pulse should last. The equation is the same. For 1ms the count would be (2,000,000 cnts/sec * 0.001secs = 2,000 counts) and for 2ms the counts would be 4,000. The range is 2,000 to 4,000 (2,000 count resolution). This is better than most hobby servos can do.

The Code

The IDE will generate a bunch of functions, a custom API, for each component used when the application is built. There are two PWM Component functions we need to use for this application .

PWM_Servo_Start() This will initialize the component and get it running. This is called once at the beginning of the program.

PWM_Servo_WriteCompare(val) This sets the CMP Value that will be used to set the pulse length.

The Results

Here is a screen shot of my logic analyzer. The output was set for 1/2 rotation. The pulse is 1.51ms and the period is 20.14ms. That is close enough for me. It is likely the clock speed is different between the PSoC and and the analyzer.

Typically you will have to tune the to the actual servos used. Just tweak the endpoint values until you get the rotation you want.

Grbl

Grbl is a high performance CNC controller. It is used on a lot of small scale CNC machines and is the motion control code behind a lot of 3D printers. It was originally targeted at the Arduino 328p hardware (UNO). It is developed by Sungeun “Sonny” Jeon. He is a good friend. He is always very helpful and this port would not have been possible without the quality of his code and his advice.

PSoC Mixed Signal Controller

I love working with the PSoC (Programmable System on Chip) family of micro controllers. You can configure them on the fly with many analog and digital components. The analog components are not basic ADCs and DACs, you have OpAmps, PGAs, filters, MUXs and more. The digital blocks includes basic logic gates, all the way up to FPGA like components you program yourself in Verilog.. There are over 200 ready to use components you can wire together on the chip.

I have always used them for small prototype projects, but wanted to test my skills by porting a major project like Grbl. At the same time I wanted to take advantage of the features of the PSoC. The dev board I used was the CY8CKIT-059. This has ARM Cortex M3 processor a lot of I/O and costs less than $10! It has a built in programmer and debugger.

PSoC Advantages

Here is a comparison between the the ATMega 328p (Arduino UNO) and the PSOC5

PSoc 5

ATMega328p (UNO)

CPU

32 bit

(ARM Cortex M3)

8 bit

Speed

Up to 80MHz

16MHz Typ.

Flash (program size)

256k

32k

RAM

64k

2k

EEPROM

2k

1k

I/O

up to 62

14

Flexibility

Grbl’s flexibility allows you to tailor it to your hardware. With a few limitations, you can move the pins around and change things like whether switches are active low or high. This is all done using #define values in configuration files. That is great, but the code gets a little messy every time you access hardware. It has to do a little logic gymnastics each time.

With PSoC you can do all of that in a visual schematic and pin wiring feature. Here is a PDF of my schematic. Have you ever swapped transmit and receive on a UART? In PSoC you can just swap the pins on the schematic.

Special Hardware Usage

I used some special features to move functions out of code and onto the hardware. One of them was the step pulse. Stepper drivers typically require a pulse of a minimum length to take a step. In normal hardware you have to raise the pin, then figure out a way to turn it off after a given period of time. This is typically done via an interrupt. It works fine, but the code is messy and interrupts can cause timing issues. PSoC control registers have a pulse feature that automates this. You attach a clock and the clock determines the length of the pulse. The code sets it and the hardware clears it. It looks like this on the schematic.

Another feature I used was hardware switch debouncing. This can be done completely in hardware. See the image below. The clock sets the debounce time. The debouncers are all fed into a status register where they are read as a single value. There are digital “nots” after the debouncers because my switches close to ground. The firmware could invert the logic, but it is so much easier to read on the schematic. It then feeds an interrupt.

If you would rather do this with an analog filter, you can design custom filters in the hardware. You could fine tune the filter right from your keyboard.

LCD

PSoC has a built in character LCD Component that makes using and LCD very easy. The code for the LCD is in the main loop and not an interrupt. This allows the time critical stuff to have higher priority. I used an interrupt to just set a flag so the LCD does not update every time through the main loop. I found the LCD to be an awesome debugging tool. I could display stuff while the code is running.

I also used a hardware Quadrature Decoder for the LCD rotary knob. This works great to monitor the encoder in hardware. I just need to read the value in the LCD update routine. The clock feature on the QuadDec is a debouncer, which helped debounce my mechanical encoder.

Next Steps

I have been testing for a while and so far it is working great. I also have some plans to use the extra power on some cool projects.