Skip navigation

DIY Test Equipment

July 2017 Previous month Next month

Peter, Jon and I are designing a programmable electronic load, here on element14: Programmable Electronic Load

We'll never make it in time for the DIY Test Equipment initiative (we may have a first prototype In the Year 2525). But it can help you if you want to build a device that can be automated with LABView or similar*.



What's in the current version:

- working firmware with a SCPI integration. Complies to SCPI standard out of box.

- tested PCB with several ADC and DAC channels, programmable and readable via SCPI - isolated and with a voltage reference

- LCD interface


Our goal is to extend Peter Oakes' popular DC Load into a programmable one. The modular design of the control logic is a start point for other designs too.

You can adapt the ADC/DAC design and control your own instrument with it. In it's current state, it can be turned into a programmable meter, signal generator, sampler.

With firmware adaption you can link the SCPI commands with your microcontroller's timers and use it as a PWM generator or a frequency counter.

With additional hardware you can buffer in-and outputs, create a programmable power supply, ...



Both PCB and firmware - although based on TI-RTOS for MSP432 and BoosterPack pinout, can be adapted. We've taken care that no license stops you from doing whatever you want and sources are attached.

Hope to see it reused in an element14 DIY Test Instrument.



* or other programs that support serial comms - even a plain terminal program like PuTTY.

I was planning to make a super simple logic probe but Jon beat me to it with his comparator based logic probe. So I've prototyped a microcontroller based one.


Microcontroller based logic probe with display

My project has just two modules, an Arduino clone and an Adafruit I2C LED backpack. The probe is connected to an analogue pin although the current software uses it as a digital pin only. The pin is sampled once every half second and 8 samples are shown across the screen on the first 2 lines.


I tested the LCD with the Adafruit demo followed by writing my own hardcoded bitmap.



The setup sets the pins, then clears the display and sets the brightness. In the loop it takes a sample, mirrors it to the pin 13 LED and then updates the display.


#include <Adafruit_LEDBackpack.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
Adafruit_8x8matrix matrix = Adafruit_8x8matrix();
int sampleNo;
bool samples[8];

void setup() {
  Serial.println("Logic Probe");
  pinMode(A1, INPUT);
  pinMode(13, OUTPUT);
  matrix.begin(0x70);  // pass in the address

void loop() {
  samples[sampleNo] = digitalRead(A1);   // read the input pin
  digitalWrite(13, samples[sampleNo]);   // sets the LED to the input value
  sampleNo = ++sampleNo % 7;

void writeDisplay() {
  for (int i=0; i <= 7; i++){
      matrix.drawPixel(i, samples[i], LED_ON);





There seems to be a power issue where the Arduino resets when the display refreshes. That was the case with the demo as well as my test code. Potentially a big capacitor across the power rails might fix that or perhaps an independent supply for the display.


It should be possible to update writeDisplay so that the signal scroll across the screen, it would also be good if it used more than just the first two rows on the display.


The other obvious thing to try would be to write the data from the input back to the serial port then have a graphing tool on a host PC to display or capture the waveform.



I am one of the road testers for the Infineon DC Motor Shield w/ TLE94112EL for Arduino and this project shows the testing platform I developed to test the features of the board shield, but it is also useful to test the DC motors performance, as well as other motor controller boards for Arduino.

According to me, carrying out a testing on the road of this platform based on the Infineon TLE94112TLE94112 IC requires a versatile and flexible platform to make possible all the tests without building a lot of unreliable breadboarded stuff with loose wires. Moreover, in order to widen the range of possible tests making the platform reusable in the future you need to add only few extra components.


A full test of the TLE94112LE shield for Arduino based on this platform will be published in the Road Test section.



The Project

Planning the Design

The idea of making an interactive testing platform evolved as I progressed analyzing in depth the shield features on several Arduino compatible platforms: Arduino UNO R3Arduino UNO R3, Chipkit PIChipkit PI and the Infineon XMC1100 BootInfineon XMC1100 Boot. All these platforms were reliable with no t special issues by the TLE94112 shield; for the final development I opted for the Infineon board due the better ARM MCU, which is faster and with more available flash and RAM memory (ARM Cortex M0 32 bit, 16Kb high-speed RAM, 64Kb Flash memory) I should admit that the better performance of this board compared to the Arduino UNO kept as reference.

IMG_20170519_095746.jpg IMG_20170519_095806.jpg

Testing motors

To create a reference for the test platform I chosen 6 brushed geared micro-motors with electrical characteristics included in the acceptable ranges of the TLE94112LE IC assembled together on an Aluminium square bar.

IMG_20170628_232738.jpg IMG_20170628_233349.jpg IMG_20170629_000615.jpg

To that aim, I used cheap motors from Pimoroni with the following characteristics:


Free-run current @ 6V: 60mA (max 120mA) - in some conditions can generate an overcurrent that is useful to test the error registers of the TLE94112

Stall torque @6V: 2.5Kg/cm

Stall current @6V: 900mA (TLE94112LE max current per half-bridge is just 0.9A)

Gear ratio: 298:1


A small 3D printed object has been designed to make visible the rotation of the motors.


Control I/O

Using a terminal to control the shield seemed immediately the right choice as the available control options open a wide scenario of many motion possibilities. The problem arose when I saw that some status information and configuration updates need continuous and immediate feedback. To solve this problem, an LCD display has been added to the testing board.



DC/DC Regulator

To provide the right power supply to the TL94112 a separate power line has been set through a DC/DC power regulator.


Design in practice

The working version of the design evolved around the features of the board I have experienced during the first phase of the hardware testing growing its complexity. The images below show the most meaningful steps.


{gallery} Platform design evolution






The Testing Platform

The last element added to the testing platform is a 50K potentiometer connected to the analog port 0. That will be used by the software when you need to read dynamic values (e.g. the manual duty cycle). The diagram below shows the components connection.

Screen Shot 2017-07-26 at 17.02.13.png

The Software

The hard part was developing the software, that required a lot of revisions, 37 pushes on the GitHub repository, but nowat last it is available as Open Source under the LGPL 3.0 license:



Software Design

The software is divided into functional blocks as listed below

  • Main Sketch: initialize and setup the system. The main loop controls the TLE94112 through the Arduino library (via SPI protocol on PINs 8 and 10), the analog input and the parser, the messaging via the serial terminal and the LCD display.
  • Commands: definition of all the serial commands response messages and all related to the parsing.
  • MotorControl: the class interfacing the (thanks to) Infineon TLE94112 Arduino library with the high-level methods used by the serial commands

We'll see them in detail in the next chapters.


1. Main Sketch

I tried to reduce as much as possible the definition of global variables and constants in the main sketch. The only pre-processor definitions in the TLE94112LE.ino are limited to the global flags driving thebehaviorr of the program in the mainLoop() and the symbolic constants definitions strictly related to the application logic to avoid confusion and better readability and making the MotorControl class fully reusable in other projects.


//! Max analog reading range with a 50K potentiometer
#define MAX_ANALOG_RANGE 1024
//! Min analog reading range with a 50K potentiometer

//! Duty cycle analog read should be ignore (bypass the analog reading)
//! Duty cycle analog read should be assgined to DC min
#define ANALOG_DCMIN 1
//! Duty cycle analog read should be assgined to DC mAX
#define ANALOG_DCMAX 2
//! Duty cycle analog read should be assgined to DC manual reading
#define ANALOG_DCMAN 3


A special note about the preprocessor directive _SERIAL_ECHO:


#define _SERIAL_ECHO - all commands are echoed to the serial terminal as shown in the example below

Serial output

setting  all

Direction  ccw

setting  none

setting  m1+

PWM:  80

setting  dc80

set  accel

setting  dc100

#undef _SERIAL_ECHO - only wrong commands are notified on the serial terminal

Serial output

wrong command  'mindc'

Main loop() structure

The main loop control the logic of the application. It is organised in three functional blocks checked sequentially every cycle depending on the status of the top flags and the data availability on the serial port (Tx/Rx, Pin 0 and 1)


Motors running status block

This block is checked only if the system status is running (start command). Every loop cycle when the motors are running it is checked for the presence of some error on the TLE94112LE registers and eventually errors are notified on the serial terminal

  // Check if at least one motor is running to test the error status
  // Note: It is possible to isolate the error status, if any,
  // for any motor. Here we make a simplification and check over
  // the motor without filtering
  isRunStatus = false;
  for(j = 0; j < MAX_MOTORS; j++) {
    if(motor.internalStatus[j].isRunning) {
      isRunStatus = true;
      j = MAX_MOTORS; // Force exit from loop
    } // check for running motors
  } // motors loop
  // If at least one motor is running check for diagnostic
  if(isRunStatus) {
    if(motor.tleCheckDiagnostic()) {
      //! Show the error star


Serial parsing block

If there are data available on the serial, the parser function parseCommand(String) is launched to check the command (or return a command error).

Serial commands are received as String terminated by CR=LF characters to be supported by any terminal or common serial connection. The last two terminating characters are removed before the string parsing.

All the commands and parser related strings are defined in the header file commads.h


Analog reading block

There are three conditions that enable the reading of analog values:

  • ANALOG_DCMIN User is setting manually via the potentiometer the minimum duty cycle value for one of the three PWM channels
  • ANALOG_DCMAX User is setting manually via the potentiometer the maximum duty cycle value for one of the three PWM channels
  • ANALOG_DCMAN User can change manually via the potentiometer the current duty cycle value for the PWM channel(s) enabled for manual duty cycle


Other functions in the main sketch

The main sketch also includes the functions to control the optional LED (on pin 12) and the LCD layout control functions.


LCD layout

For obvious size reasons the LCD shows several layouts depending on the conditions using a layout with abbreviations; whenever possible, more readable strings have been used. The shortened symbols used by the LCD are listed below:

  • M1, M2, M3, ... M6 Set the corresponding motor
  • M* Set all the motors with the same parameter
  • PWM[1] 80Hz, PWM[2]100Hz, PWM[3] 200Hz Set one of the three PWM channels (assigned to a fixed frequency)
  • CW/CCW Clockwise/Counterclockwise direction of the selected motor(s)
  • FreeWh+/FreeWh- FreeWheeling active enabled/disabled for the selected motor(s)
  • DCMin Minimum duty cycle value for the selected PWM channel(s)
  • DCMax Maximum duty cycle value for the selected PWM channel(s)
  • ena/dis Selected motor(s) set as enabled or disabled
  • Ramp Set acceleration and deceleration for the selected PWM channel(s)
  • Inst. Set instant starting for the selected PWM channel(s)


The gallery below shows and example of several LCD layouts


{gallery} LCD Layout examples











2. MotorControl Class

The MotorControl C++ class is pat of the software, uses the TLE94112 Arduino Library by Infineon and is built around the files motorcontrol.cpp, motorcontrol.h and motor.h (extra preprocessor definitions). The class itself is structured through two level methods.

For the complete methods of the class and full documentation refer to the software available on the GitHub repository


MotorControl - Hardware control methods

The hardware control method interfaces directly the features of the hardware shield exposed by the TLE94112 Arduino library.


MotorControl:: tleCheckDiagnostic(void)

MotorControl::tleDiagnostic(int motor)


Check the diagnostic status and send the corresponding error message to the serial terminal (if any)


MotorControl::motorConfigHBCCW(int motor)

MotorControl::motorConfigHBCW(int motor)

and others similar to configure half bridges direction and the other parameters, the PWM channel, duty cycle etc.


MotorControl - High level methods

The hight level methods interfaces the commands calling recursively after filtering potential errors, This avoid internal problems or unexpected behaviours or hardware damages.

Every parser command call one of the high level commands of this class.


3. Commands Description and Syntax

Excluding the potentiometer on the board all the controls are sent via terminal through a USB-to-serial connection. When the system is in running mode it can accept configuration commands that will be effective after a stop and start call.

If errors occur while the system is running these are shown in detail on the serial terminal and are notified on the LCD screen

The available commands are listed below:

Direction control

  • cw : clockwise rotation
  • ccw : counterclockwise rotation
  • accel : enable the acceleration when motor start
  • noaccel : disable the acceleration when motor start

Action commands

  • start : start all motors
  • stop : stop all motors
  • reset : reset the system to the default

Duty cycle settings to PWM channels

  • dcmanual : Set the duty cycle value depending on the pot
  • dcauto : Set the duty cycle current limits
  • dcmin : Set the min duty cycle value via pot
  • dcmax : Set the max duty cycle value via pot
  • dcinfo : Shows the duty cycle range for the selected PWM channel

PWM channel selection for duty cycle settings

  • dc80 : Set the duty cycle to the PWM channel 80Hz
  • dc100 : Set the duty cycle to the PWM channel 100Hz
  • dc200 : Set the duty cycle to the PWM channel 200Hz
  • dcPWM : Set the duty cycle to all the PWM channels

Motor select for settings

  • all : Select and enable all motors
  • none : Disble all motors
  • m1 : select motor 1
  • m2 : select motor 2
  • m3 : select motor 3
  • m4 : select motor 4
  • m5 : select motor 5
  • m6 : select motor 6

Motor enable

  • m1+ : enable motor 1
  • m2+ : enable motor 2
  • m3+ : enable motor 3
  • m4+ : enable motor 4
  • m5+ : enable motor 5
  • m6+ : enable motor 6

PWM Frequency selector

  • 80 : PWM 80 Hz
  • 100 : PWM 100 Hz
  • 200 : PWM 200 Hz

Freewheeling mode motor(s) setting

  • fwactive : Fereewheeling active
  • fwpassive : Freewheeling passive

Show all motors configuration

  • conf : Dump the current settings


For the last updates and revisions please follow the TLE94112LE on GitHub

(special thanks to antoricagno for text review)


I am one of the road testers for the Infineon DC Motor Shield w/ TLE94112EL for Arduino and this project is the second part of the road test blogging. This is the motorised evolution of the 3d printer filament roll holder and monitor for Arduino and it is also the second Arduino project I publish in this area.

In the first part I presented the building of the 3D printed structure to manage the load sensor while printing and the motor control of the filament spool with a geared brushed motor. Now we see the electronic part based on ArduinoArduino or the Infineon XMC1100 BootInfineon XMC1100 Boot compatible with Arduino and the TLE94122LE Arduino shield .


Hardware setup


The video above shows the system at work. Thanks to the completeness of the TLE94112LE Arduino shield the electronic assembly is extremely easy; this is one of the aspects I most appreciated of this Infineon board as well as the possibility to manage many motors together. The setting can be done just in three steps:


  1. Insert the shield on top of the Arduino or the Infineon XMC110 Arduino compatible board
  2. Connect the motor wires to the Out1 and Out2 screwed connectors of the shield
  3. Connect the power and signals from the HX711 AD weight sensor amplifier to the Arduino pins. In this case I have used pins 2 and 3 but all the free pins can be used


Note: pins 8 and 10 are reserved by the TLE94113LE shield for the SPI connection

That's all.


Controlling the system through the serial port

There is a precise reason - imposed by the number of available pins on the Arduino UNO family boards - I chose to control the system via the USB to serial connection and a serial terminal: The TLE94112LE shield can manage up to 6 brushed motors (or more in cascade configuration) and every motor in this setup can control a different filament roll independently. As every motorised unit is based on a weight sensor to control six different filament dispensers we should be able to read data from six weight sensors. Every load cell "consumes" two pins, pin 0 and 1 are reserved (Tx/Rx) for the serial and pins 8 and 10 are reserved for the SPI channel connecting the TLE94112LE shield.


System status

The control software works through four different states, defined in filament.h:


#define SYS_READY "Ready"       // System ready
#define SYS_RUN "Running"       // Filament in use
#define SYS_LOAD "Load"         // Roll loaded
#define SYS_STARTED "Started"   // Application started

// Status codes
#define STAT_NONE 0
#define STAT_READY 1
#define STAT_LOAD 2
#define STAT_RUN 3


Status : Started

This status occurs after a hardware reset or when the system is powered on. The power-on (and setup() call when the sketch starts) initialises the internal default values and should be started with no extra weight on the platform as part of the initialisation sequence is the acquisition of the absolute tare to reach the physical zero weight.


Status : Ready

The ready state occurs after a soft reset (sent from the serial terminal). It is similar to the physical resect but no tare is calculated; the reset command can be launched also when the system is running.


Status : Load

The load status occurs when the load command is sent by the terminal. This means that the filament roll has been loaded and the dynamic tare has been calculated. The exact filament weight is obtained by the kind of roll setup subtracting the weight of the motor unit and the empty roll.


Status : Running

This status enable the automatic weight calculation and the automatic filament dispenser.


Terminal messages

The current version of the software returns human readable messages to the terminal depending on the commands. The string messages are defined in two header files: commands.h (command related messages and responses) and filament.h (strings used by the parser to create compound messages).


In commands.h

// Execution notification
#define CMD_EXEC "executing "
#define CMD_NOCMD "unknown "
#define CMD_SET "setting "
#define CMD_MODE "set mode to "
#define CMD_UNITS "set units to "
#define CMD_STATUS "set status to "
#define CMD_WEIGHT "Weight "
#define CMD_WRONGCMD "wrong value "


In filament.h

#define MSG_USED "used: "
#define MSG_REMAINING "remain: "

#define SYS_READY "Ready"       // System ready
#define SYS_RUN "Running"       // Filament in use
#define SYS_LOAD "Load"         // Roll loaded
#define SYS_STARTED "Started"   // Application started

#define DIAMETER175 "1.75 mm"
#define DIAMETER300 "3.00 mm"

// Units
#define UNITS_GR "gr"
#define UNITS_CM "cm"
#define UNITS_MT "m"
#define UNITS_KG "Kg"
#define FILAMENT_ROLL "Roll"

#define PLA_MAT "PLA"
#define ABS_MAT "ABS"



Two different files are involved in the command management: commands.h including all the commands and related parameters and filament.h including all the constants and definitions used by the weighting system and by the parser. While the internal calculations are done automatically by software I have implemented a series of commands to set the behaviour of the system and manually control some parameters.

Command keywords are case sensitive and should just be send from the terminal. If a command is not appropriate for the current status of it is not recognised a wrong command message is returned else the command is executed.


Status commands

Change the current status of the system and the behaviour is adapted as well

// Status change
#define S_RESET "reset"        // Reset the system with the current filament setup
#define S_LOAD "load"          // Filament roll has been loaded
#define S_RUN "run"            // Print job is running
#define S_DEFAULT "default"    // Reset the system with the default settings


Filament commands

Using separate commands it is possible to setup the filament and roll characteristics based on the most common weight and sizes today available on the market

// Filament setup
#define SET_PLA "PLA"
#define SET_ABS "ABS"
#define SET_175 "1.75"
#define SET_300 "3.00"
#define SET_1KG "1kg"
#define SET_2KG "2kg"


Units commands

These are a couple of commands to set the visualisation of the measure units in grams or centimetres. As a matter of fact it is possible to eliminate this commands and always represent data in both units.

// Units setting
#define SET_WEIGHT "gr"
#define SET_CENTIMETERS "cm"


Information commands

Shows group of information depending on the system status

// Information commands
#define SHOW_INFO "info"          // Shows roll current info (weight, material, diameter, remaining percentage)
#define SHOW_STATUS "stat"        // Shows weight status values (used material)
#define SHOW_DUMP "conf"          // Dump the current settings
#define SHOW_WEIGHT "weight"      // Show the current read weight (last absolute weight value read from the sensor)


Motor commands

Control the motor for filament feed or pull.

If the preprocessor _USE_MOTOR_ is undefined in filament.h header all the motor functions and commands are ignored. This is to grant the compatibility of the program with the non-motorised version of the system without maintaining separate sources.

// Motor control
#ifdef _USE_MOTOR
#define MOTOR_FEED "feed"       // Feed a length unit
#define MOTOR_PULL "pull"       // Pull back a lenght unit
#define MOTOR_STOP "stop"       // Pull back a lenght unit
#define MOTOR_FEED_CONT "feedc"    // Feed continuopusly
#define MOTOR_PULL_CONT "pullc"    // Pull back continuously


All motor commands follow an acceleration/deceleration path. The two commands feed and pull executes a short sequence as defined in motor.h by the constant FEED_EXTRUDER_DELAY while feedc and pullc commands runs indefinitely until a stop command is not received.


Running mode commands

The running status accept two modes; mode man just read periodically the weight and the motor moves until a motor control command is not sent. Mode auto instead executes two feed commands when the extruder needs more filament.

The principle is based on the weight readings, contextualised to this particular environment. We expect that the filament consumption is relatively slow, 3D printers are almost slow and the normal weight oscillations depends on the environment vibration (better if you don't put the entire stuff on the 3D printer ) When the extruder pulls the filament instead the weight difference dramatically increase (50 gr or more) in very few time, typically between two o three readings. This information is filtered by the software that "deduct" that new filament is needed.

To avoid wrong readings weight variations while the motor is running are ignored at all.

// Running mode
#define MODE_AUTO "auto"        // Run in automatic mode
#define MODE_MANUAL "man"    // Run in manual mode


Application logic

The application logic is distributed in the .ino main (the Arduino sketch) along three functions: setup(), loop() and parseCommand(commandString) The sketch uses two separate classes: FilamentWeight class to manage all the filament calculations and sensor reading via the HX711 IC and MotorControl class interfacing the low level methods of the TLE94112LE Arduino shield.



Launched once when at power-on or after a hardware reset initalises the instances of the classes, setup the hardware and the terminal communication.

// ==============================================
// Initialisation
// ==============================================
void setup() {
  // Serial is initialised at high speed. If your Arduino boards
  // loose characters or show unwanted/unexpected behavior
  // try with a lower communication speed

  // Print the initialisation message

  // Initialize the weight class
#ifdef _USE_MOTOR
  // initialize the motor class
  modeAuto = false;



The main loop function just manage three different conditions. While there are two classes for weight sensor and motors relatively complex, there is the advantage that the resulting sketch is really easy to understand and manage.

  1. Check (in mode auto) if the extruder needs more filament
  2. If the motor is running check for hardware errors (returned by the TLE94112LE)
  3. If there are serial data available parse the command
// ==============================================
// Main loop
// ==============================================
 * The main loop role is executing the service functions; display update, 
 * calculations, button checking
 * The scale reading is done at a specific frequence and is interrupt-driven
void loop() {
#ifdef _USE_MOTOR
  // Check for the extruder request
  if( (scale.statID == STAT_RUN) && (scale.currentStatus.filamentNeededFromExtruder == true) ) {
    if(modeAuto) {

  // Check if the motor is running to test the errors status
  if(motor.internalStatus.isRunning) {
    if(motor.tleCheckDiagnostic()) {

  if(Serial.available() > 0){
  } // serial available

//! Send a single line message to the serial
void serialMessage(String title, String description) {
    Serial.print(" ");



The parsing function check for the strings coming from the serial and when a command is recognised it is immediately processed. Every command act as a state machine impacting on some parameter of the system; following this logic all the commands are reduced to three sequential actions:


  1. Send a command to the FilamentWeight class (weight commands) or to the MotorControl class (motor commands)
  2. Executes a calculation to update weight values or update one of the internal parameters
  3. Show on the terminal and information output when the execution complete


Below the full parsing listing; commands have been grouped by type as shown in the Commands section above.

 // =========================================================
  // Parameters settings
  // =========================================================

  // Set PLA material and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  if(commandString.equals(SET_PLA)) {
    scale.materialID = PLA;
  // Set ABS material and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_ABS)) {
    scale.materialID = ABS;
  // Set 1.75 mm filament diameter and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_175)) {
    scale.diameterID = DIAM_175;
  // Set 3.00 mm filament diameter and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_300)) {
    scale.diameterID = DIAM_300;
  // Set 1kg filament spool and recalculate the material characteristics
  // Flag is set to display an update next loop cycle
  else if(commandString.equals(SET_1KG)) {
    scale.wID = ROLL1KG;
  // Set 2kg filament spool and recalculate the material characteristics
  // Flag is set to display an update nesxt loop cycle
  else if(commandString.equals(SET_2KG)) {
    scale.wID = ROLL2KG;
  // Set units in grams
  else if(commandString.equals(SET_WEIGHT)) {
    serialMessage(CMD_UNITS, commandString);
    scale.filamentUnits = _GR;
  // Set units in cm
  else if(commandString.equals(SET_CENTIMETERS)) {
    serialMessage(CMD_UNITS, commandString);
    scale.filamentUnits = _CM;

  // =========================================================
  // Change current functional status
  // =========================================================
  // Send a reset command and restore the parameters to the defaults
  // The tare is not recalculated to avoid wrong measure (if the spool
  // is already on the scale platform
  // This command had mandatory executi9on and ignore the previous state
  // The flag is set to show an update nextg loop cycle
  else if(commandString.equals(S_RESET)) {
    scale.stat = SYS_READY;
    scale.statID = STAT_READY;
//    scale.flashLED();
  // Send a load command status setting
  // Should be executed after the filament roll has been set 
  // and placed on the scale base or after a reset command
  // The flag is set to show an update nextg loop cycle
  else if(commandString.equals(S_LOAD)) {
    scale.stat = SYS_LOAD;
    scale.statID = STAT_LOAD;
    scale.initialWeight = 0;
  // Send a run command status setting
  // Should be sent when a print job is started
  else if(commandString.equals(S_RUN)) {
    scale.stat = SYS_RUN;
    scale.statID = STAT_RUN;
    scale.initialWeight = scale.lastRead - scale.rollTare;
    scale.prevRead = scale.lastRead;
    scale.lastConsumedGrams = 0;
  // Send a default command status setting
  // Should be used to reset the system to the default values 
  // of the material without changing any setting in the weight
  // tare and calculations but the current status is not changed.
  // Use this commmand to reset the material to the internal conditions
  else if(commandString.equals(S_DEFAULT)) {

  // =========================================================
  // Informative commands
  // =========================================================
  else if(commandString.equals(SHOW_INFO)) {
  else if(commandString.equals(SHOW_STATUS)) {
  else if(commandString.equals(SHOW_DUMP)) {
  else if(commandString.equals(SHOW_WEIGHT)) {

  // =========================================================
  // Motor control
  // =========================================================
#ifdef _USE_MOTOR
  else if(commandString.equals(MOTOR_FEED)) {
    serialMessage(CMD_EXEC, commandString);
  else if(commandString.equals(MOTOR_PULL)) {
    serialMessage(CMD_EXEC, commandString);
  else if(commandString.equals(MOTOR_STOP)) {
    serialMessage(CMD_EXEC, commandString);
  else if(commandString.equals(MOTOR_FEED_CONT)) {
    serialMessage(CMD_EXEC, commandString);
  else if(commandString.equals(MOTOR_PULL_CONT)) {
    serialMessage(CMD_EXEC, commandString);

  // =========================================================
  // Change behaviour mode
  // =========================================================
  else if(commandString.equals(MODE_AUTO)) {
    serialMessage(CMD_MODE, commandString);
    modeAuto = true;
  else if(commandString.equals(MODE_MANUAL)) {
    serialMessage(CMD_MODE, commandString);
    modeAuto = false;
    serialMessage(CMD_WRONGCMD, commandString);


The last updated version of the software is available under the LGPL 3.0 open source license on GitHub:


Read also the first part: 3D Printer Filament Automatic Dispenser for Arduino - #1 Design and Hardware


I am one of the road testers for the Infineon DC Motor Shield w/ TLE94112EL for Arduino and this project is the first part of the road test blogging. This is the motorised evolution of the 3d printer filament roll holder and monitor for Arduino and it is also the second Arduino project I publish in this area.

I have made and used for months the filament roll support based on the mechanics illustrated in the mentioned project but some filament issues have not yet been solved by this tool.

When it is used by 3D printers filament - usually almost robust - is pulled by the extruder while the roll is placed nearby free to rotate. I have observed meaningful differences in the material behaviour depending on the usage level, based on 1Kg filament rolls. A new filament spool flows almost well but the force applied by the extruder should be relatively relevant. The extruder motor (a Nema17 stepper motor) is not damaged but the two gears of the extruder collect particles of the plastic material due the applied force; this requires extruder maintenance after a while to avoid clogging of the filament in the hot end. These particles tends to detach and mix with the clean filament while it is feeding the hot end nozzle increasing clogging problems and a general more frequent nozzle wear; this occurs more frequently with 0.3 mm diameter nozzles.

When the filament roll is half used and more its spirals become smaller and in some environmental conditions the filament tend to break too frequently.

Long print jobs become less reliable; for example I can't leave the printer working alone for an entire night without controlling it. Thus the idea to make a controlled filament feeder figured a precise series of issues to solve.


  • Make the automated engine almost simple and easy to reproduce
  • Reduce as much as possible the number of non-3D printable components to make it
  • Reduce as much as possible the stress applied to the extruder while printing
  • Use a low cost and easy to program micro controller board
  • Use the weight load sensor to keep under control che filament consumption and filament feeding
  • Manage the environmental noise interfering with the filament weight measures


Also using a single 3D printer we frequently manage more filament rolls (different colors) not all at the same level depending on the print job we are doing. Using an Arduino and the TLE94112EL shield motor controller may result the most reliable and cheaper solution: the board can control up to 6 different brushed motors with simple commands. This Infineon board has its own half bridge motor controller including three different frequencies PWM channels: 80, 100 and 200 Hz. In practice this means running motors sending commands from Arduino keeping the MCU free to other tasks while motors are running.



Choosing the design approach

Respect to the mechanical components the design approach should comply some essential requisites. The most important is the possibility to make corrections and upgrades to the mechanical prototype if testings does not reach the expected results. We should also consider the applied forces to every part: it is not a good practice designing the entire complex component (but possible) to avoid issues some frequent issues:


  • Different parts of the same structure requires different levels of robustness
  • Too long single-printing time
  • Difficulty positioning the 3D printed object requiring as less as possible support material
  • Difficulty refining the entire object
  • If something goes wrong in a part the entire object should be reprinted and a lot of material will be trashed with a single-object approach
  • Difficult adapting the same design to different versions of the model


Making the right choice in the 3D design means saving a lot of prototyping and production time, a considerable quantity of filament and creating an adaptable structure. To say this in one word: 3D parametric model

An adaptable design means also a model reusable building; the same structure can be reused with a different kind of motor, different bearings etc. Thanks to a modular design it was possible approaching a solution for this project after a first prototype with a different and not reliable motion transmission solution..


Introducing the TLE94112LE Arduino shield


One of the limits I have experienced with other motor control shields for Arduino (but not only) is that they uses the features of the same micro controller (i.e. PWM and other GPIO pins); this means that your board becomes dedicated to these tasks while only few other resources (MPU and GPIO) are available for other uses. To stay on the same topic of this project many 3D printer controllers based on Arduino clones experience this kind of limits. Having the possibility to put my hands on the TLE94122LE Arduino shield for road testing, the most evident advantage of the IC the board is based on is just its completeness. Arduino board communicates with the board via the SPI protocol using just only two pins (or three if you stack two different TLE94112 shields on the same Arduino). Every command you send to the shield is processed autonomously by the IC without consuming MPU resources. Another remarkable feature of the Infineon board is the possibility to control up to six brushed motors with three programmable PWM channels. This means that Arduino can setup one or more motors, start then continue working on other tasks. This shield revealed perfect to support up to six different filament rolls at the same time that is just one of the main goals of this project.

Considering the possibility to manage six different filament spools with a single Arduino + shield the micro controller cost impact of every single filament controller less than 5 Euro.


3D Printer Filament Dispenser.png

Functional design and components

As shown in the image above this project is not extremely complex to assemble starting from the kit; HX711 do his job very well (a well working Arduino library is available on GitHub) sending to Arduino the load cell readings. By the other side the TLE94112LE shield (with its own library too, thanks to the Infineon developers) manages all the motor part.



Arduino UNO R3.jpg XMC1100_Boot-Kit.jpg

This project has been developed in several steps making (and discarding) early prototypes using Arduino UNO R3 and Infineon XMC1100 Boot KitXMC1100 Boot Kit Arduino compatibile. By a hardware point of view there was no difference at all but I should say that the higher processor speed and more available memory of the XMC1100 made the difference in the general performances: the systems - that works perfectly with Arduino - show better responsiveness and performances when running on the Infineon board. One of the advantages using the XMC1100 board is the availability of more internal resources (memory and MCU speed).


Weight sensor

After doing some experiments in several directions I saw it was possible to control the entire system - monitoring and automatic feeding - with a single sensor; with some experience managing data in the right way a load cell able to dynamically measure the filament spool weight variations can provide all the information we need.

IMG_20170612_144450.jpg IMG_20170613_143006.jpg

I  used an inexpensive load cell in the range 0-5 Kg (less than 4 Euro) sold together with a small breakout board of the HX711 AD Amplifier, an IC adapt to manage the load cells sensors. There was not interfacing problems as the Arduino library is available on GitHub (HX711).


Motion hardware

Spool rotation is obtained by a couple of 2:1 demultiplied gears moved by a 280 rpm brushed motor. The motor is a McLennan instrument DC geared motor McLennan instrument DC geared motor 90:1 with a rated current of 50 mA and a max no-load current of 20 mA (see the attached datasheet). This brushed geared motor fits the specifications of the TLE94112LE DC motor controller shield.


Obviously also similar characteristics geared motors can be used as well.


Filament spool driver

The spool driver is the base where the filament spool rotates free. The weight sensor is the mid support of the two-layers base so the system is able to detect the weight variations in the various conditions.

IMG_20170701_140929.jpg IMG_20170613_143006.jpg

To avoid as much as possible the friction during rotation I have used four bearings while on the bottom part of the base the HX711 breakout board is fixed with a couple of screws.

Only six wires should be connected to the Arduino shield:


  • 5V and GND (from Arduino) power line for the HX711 IC
  • Two signal lines from the HX711 IC (to Arduino I/O pins 4 and 5)
  • Two power lines from the brushed motor connected to out 1 & 2 of the shield (TLE94112LE power lines)


Mechanics and motion design

Mechanic design needed two different prototypes. Before seeing in depth the steps I followed there is a short foreword we should say about 3D printing and mechanic design.

When we need 3D printing to build - no matter how complex - moving parts and in general mechanical elements we should always consider that there will be some forces, static of dynamics, that will be applied to the prototype while it is working. Knowing before what are the kind of forces applied to our 3D printed structure it is essential to decide important parameters:


  • 3D printing orientation: always reduce as much as possible the extra-material used to create supports while printing, large surfaces grant better adhesion so it is good to place them to the bottom on the printing bed
  • Layer thickness: a too thick layer (i.e. 4 mm) makes printing fast but we loose definition. I always use 2 mm layers that are a good compromise between final quality and printing speed
  • Solid fill density: excluding the first experiments I have done with my first 3D printer, it is very rare I fill objects more than 75% and I strongly suggest never to fill objects less than 15-20% to avoid very crap results.


But the first step that can dramatically change the quality and robustness of the resulting 3D printed piece is the CAD design. Designing single objects like cases, puppets, gadgets CAD choices is not influencing too much the final result but when we have many moving parts I consider a must designing compound objects for at least two reasons:


  1. Depending on the role of every part it is possible to decide separately the better fill density
  2. The compound object - just like in this case - can be easily modified and upgraded without impacting the entire structure and reducing the number of elements to reprint

3D Parts.jpg 3D Top.jpg

The two images above shows all the parts to be printed from the first prototype design. You can see the two green pulley used to manage the movement; the first idea was using a tooth belt for the transmission but when the prototype was built the solution revealed almost bad. The gallery below illustrated several rendering of the mechanics design before I started 3D printing the parts.


{gallery} Model rendering

Assembled 02.jpg

Asssembled 01.jpg

Exploeded 01.jpg

Exploeded 02.jpg


Exploeded 03.jpg

Exploeded 04.jpg

Exploded 07.jpg

Exploded 06.jpg

Exploded  05.jpg

Assembled 06.jpg

Assembled 04.jpg

Final 01.jpg

Final 02.jpg


After 3D printing then assembling the first prototype the tooth belt transmission was not working well. The tension of the belt required a more robust support than the structure I designed. The rest of the parts instead was working perfectly. As the complete structure was built with different parts it was sufficient to replace the two tooth pulleys with a couple of gears; I had to reprint only these two replacements and the issue was solved.

The video below shows the final solution and the making of refining and assembling the first prototype


In the second part we see the commands and software logic: 3D Printer Filament Automatic Dispenser for Arduino - #2 Connection and Software

I work with small thermocouples and Hot-Wire/Hot-Film devices in my lab.  To test and calibrate these devices requires some crazy equipment sometimes.

Try to imagine blowing air on a thermocouple that's in a chain of thermocouples 1mm apart without disturbing the ones on either side.

Hot-films are very sensitive to the air flow direction, and it's difficult to move a big fan around keeping the air flow at accurate angles.

So, after trying straws taped to little fans and other sometimes successful ideas, I designed a small hand-held air jet for this purpose.

The case was designed using AutoCAD, and printed on a SeeMeCNC H2 Delta 3D printer.


I designed it to use a small 30mm fan , and power it with a 9V battery.

Here's the finished unit:


Here's a video of the jet in operation with a hot-film.

Just understood what the prize is haha. In that case, this could benefit me with the documentation of the different max speeds of all electric motors in my inventory. I could then select the most appropriate motor for a certain application.  

I have recently begun the construction of an 8-bit computer based around an Intel 8088 CPU. I believe that I have all necessary components for the build, but I am still not too sure. A handful of ICs (including what appears to be the clock IC) have lost their labels after years in storage. It would be very handy to have a component tester to know which pins are which; therefore, knowing what the IC is. I also have many unlabed MOSFETs with no branding or information printed in them as well. So again, it would be helpful to know which pins are G, S, and D. It would also eliminate the hassle of Googling part schematics in some cases.

DIY Test Equipment

Monthly project competitions, chances to earn prizes, you decide project themes, your ideas, your projects, turn ideas into projects.

Back to The Project14 homepage

Project14 Home
Monthly Themes
Monthly Theme Poll



This project is to build a handheld test tool, to measure how fast things are turning. It could have uses in vehicle diagnostics, or for checking how fast a drill is spinning. It could also be used in math/physics experiments to see how fast wheels or other parts are revolving. Basically if any machine is spinning you can measure its rotational speed in revolutions per minute (RPM) or revolutions per second (Hz).

The short (60 second) video here shows it in action:


It is low-cost (<$25) and easy-to-build, so it could be ideal as a beginner 'learning electronics/learning to solder' project. All parts and details are published in this blog post.



How does it work?

The principle is really simple; an infrared LED shines light on the target object. Reflections get sensed by a single photodiode 'eye'. Provided there is a reflective portion of the target object and a non-reflective portion (as an example, a piece of white tape could be stuck on a dark colored object, or a piece of black tape on a light colored object) then the reflected light occurs in pulses directly related to the number of revolutions per minute. The pulses are counted by a microcontroller every second and shown on a LCD display.



Working with the Microcontroller

This project uses a Texas Instruments MSP430 series microcontrollerMSP430 series microcontroller. A microcontroller in a nutshell is a computer-on-a-chip. it contains a microprocessor, memory, storage (often in the form of Flash memory) and lots of input/output (I/O) pins. Software is written and compiled/built into an executable file on a PC, and then programmed into the Flash memory.

In order to program the microcontroller integrated circuit (IC), a cheap development board development board is used. It has a 20-pin DIP socket so it is perfect for plugging in a microcontroller, programming it, removing it and then fitting it into your own projects.



To get started, plug in the development board into the PC using the supplied USB cable. Next, google ‘CCS Cloud’ and register at the TI website and the web browser will show a development environment. All coding and compiling can be done in the web browser, and there is no need to download and install any development software.

Go to File->New CCS Project and give the project any name (e.g. tachometer) and for the Device field select MSP430Gxxx Family and MSP430G2553.



You’ll see that the CCS Cloud environment has created a file for you called main.c and it has a basic main function already inside in the editor pane. It will look like this:



As a test, click File->Save and then click on the Hammer icon which is used to build the code into an executable file. The text in the Output pane will indicate Finished building: tachometer.This proves that the compiler is functioning. In order to download the code into the microcontroller plugged on the development board, all you need to do is click on the Run icon. The first time you do this it may download and install a little helper program to perform the transfer, and subsequently you don’t need to install anything to the PC.



The program doesn’t do anything, so you may wish to experiment and blink the LED on the development board. To do this, type the following code into the Editor pane:

#include <msp430.h>

#define LED1_ON P1OUT |= BIT0
#define LED1_OFF P1OUT &= ~BIT0

* main.c
int main(void) {
    WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
  P1DIR |= BIT0;


  return 0;


It should look like this:



Select File->Save then click the Hammer icon, confirm the Output pane successfully says Finished building: tachometer.hex, and then click the Run icon.


After a short pause the code gets transferred into the development board microcontroller, and the red LED should flash rapidly as the code was written to do. The executable file is written into non-volatile Flash memory, so if you unplug the USB cable and then re-insert it, the LED will start flashing again.


Now that hopefully you are comfortable with writing code and building it and installing it onto the microcontroller, the tachometer code can be installed. Go to github and copy the code there and paste it into the CCS Cloud browser editor pane so that it replaces the original code. Same as before, click on File->Save and then the Hammer icon, and again confirm that the output says Finished Building: tachometer.hex. Note that if there are any errors, there will be red error messages in the Output pane and they will need to be corrected. There should be no issue with the current code however.


Click on Run and the code will be installed into the microcontroller. Unplug the USB cable and then using a flat blade screwdriver carefully lever out the programmed microcontroller from the development board. It will be installed in the Cyclops-1000 circuit board!


Building the Circuit

There are different ways to build the circuit; for example using isolated pad proto board, or using a printed circuit board (PCB). To build it on a PCB, the computer aided design (CAD) files are sent to a PCB manufacturer; the typical cost is $20 for 10 boards. One PCB manufacturer is iTead, but others offer similar prices and results too. To use iTead, search for their PCB prototyping service, and purchase their 2-layer 10x10cm board option. Then go into your iTead account order and click on 'View Order' and there will be a button to upload the CAD files. The PCB CAD zip file for this project can be downloaded from github and uploaded to iTead as a zip file. That’s it! The PCBs should arrive within a week or two.



I initially built mine on isolated pad proto board. To start off, the power supply circuit is built. It can be verified by plugging in a battery and using a multimeter to confirm 5V and 3.3V outputs are functioning.



Next, the optical portion of the circuit is constructed. It consists of an infrared LED, and a photodiode circuit that amplifies the received signal and then provides a high/low logic output. The output is inverted and converted to a 3.3V logic signal using the Q1 transistor.


To test this circuit with a multimeter, placing white card to cause a reflection should result in the signal output from Q1 to change from high (3.3V) to low (0V). Careful adjustment of the angle of the LED should allow for a reliable distance of about 10cm from the target using a white card target.



The output from Q1 is connected to the microcontroller. The microcontroller circuit consists of a 20-pin DIP socket for the MSP430 series microcontroller, a reset circuit (R6 and C6), a 32.768kHz crystal, a supply decoupling capacitor (C7) and two pull-up resistors (R4 and R5) which together establish an I2C serial bus.



The microcontroller that was programmed earlier can be plugged into the 20-pin socket once the entire circuit has been soldered.



The final part of the circuit is to attach the LCD display.



And that’s it! The circuit is very simple. Plug the microcontroller in, connect a 9V battery and everything should work. The LCD display will prompt you to point it at a rotating object and the display will automatically indicate the RPM value and the number of rotations per second too (in Hz).


Any questions, please feel free to discuss in the comments section below. Also, if you do improve the hardware or software it would be great to hear about it.


PCB Version

The PCB has a couple of optional features, in particular there is space for a push-button. It could be useful to implement new functions for example min/max display of speed where the speed is varying over time, or a ‘high-res’ mode where very high granularity is needed for the RPM measurement, or a 'counter' mode which just counts number of rotations forever until it is reset.


The PCB version is quicker to build and there is less chance of error during assembly.


Final Test and Assembly

The project functions to speeds beyond practical limits for rotating objects. To prove this, I pulsed an LED at known frequencies and pointed it at the sensor. It worked to beyond 15,000 pulses per second which is close to 1 million RPM. The entire project fits in a handheld casehandheld case; a window will need to be cut for the display, the optical parts and the power switch. Alternatively a 3D printer could be used to create something suitable.



The window was cut to be larger than the text display area, so that the text would be visible from an angle too.


The window was fitted with a neutral density filter. This was glued on the inside of the case. For the push-button, I deliberately drilled a bigger hole so that a plastic cap that I had lying around (it wasn't designed for the specific push-button that I used) could fit. Other cylinder shaped plastic pieces could be used.


It turned out that I didn't need to glue the cap to the push-button; it just sits on top loosely, and is fitted with a lip (I used a grommet) around it so that it won't drop out of the case. Since there is a lot of light bleed from the sides of the LCD, I cut a black piece of card to act as a surround and lightly glued it down (I used 'glue dots' so that it can be easily removed if necessary).


Here are some final photos of the assembled device:




How does the Software work?

The software is straightforward. It is examined in detail here.



To examine it, look at the function called main(). The software sets up the crystal oscillator, and then sets a hardware timer inside the MSP430 chip to repeat every second. When the timer reaches one second the hardware will automatically call an interrupt routine. The main function also sets up another different interrupt to occur each time a falling edge signal occurs on the microcontroller. The edge interrupt pin is connected to the optical circuit.


The rest of the main function just loops forever, waiting for a fresh edge sum to be available, and printing it to the LCD.


Whenever the edge interrupt occurs, a counter is incremented. Whenever the 1-second event occurs the counter value is published in a global variable called edge_sum and then the counter value is reset.


Therefore the global variable edge_sum contains the total number of transitions that occurred every second. This value is multiplied by 60 to get an RPM value.



This project has shown how to build an RPM measurement device (tachometer) at low cost, and how to program the microcontroller and make modifications to the code. With the PCB this is a really easy beginners project and provides a tool for measuring the rotational speed of all sorts of machines.


Parts List

Note: A quantity of two parts is needed for some line items! Refer to the first column to see how many references there are to that part, to determine the quantity.


C1, C7100n100n100nF ceramic capacitor
C2, C31u1u1uF ceramic capacitor
C4, C510u10u10uF electrolytic capacitor
C61n1n1nF ceramic capacitor
D1SD5620-001SD5620-001Honeywell SD5620 optoschmitt detector
D2IR LEDIR LED850nm infrared LED Vishay  VSLY5850VSLY5850
J2DIL headerDIL headeroptional - SMD 10WAY DIL header 1.27mm pitch
Q1BC547BC547BC547 transistor NPN
R11k1k1k resistor
R222k22k22k resistor
R347R47R47 ohm resistor
R4, R52.2k2.2k2.2k resistor
R647k47k47k resistor
R7180R180R180 ohm resistor
R8330R330Roptional - 330 ohm resistor
SW1Slide SwitchSlide Switchslide switch  OS102011MA1QN1OS102011MA1QN1
SW2Push SwitchPush Switchtactile switch 6.5mm x 4.5mm pin spacing Omron  B3F-1070B3F-1070
U1R-78E5.0-0.5R-78E5.0-0.5Recom R-78E series 5V 500mA DC-DC converter
U2MCP1702-3302EMCP1702-3302E3.3V LDO voltage regulator
U3MSP430G2553MSP430G2553MSP430 series microcontroller  MSP430G2553IN20MSP430G2553IN20
X132.768kHz32.768kHz32.768kHz crystal wire ended, 12.5 pF
MSP-EXP430G2MSP-EXP430G2MSP430 development board
DIP socketDIP socketDIP socket 20-way
EnclosureEnclosure117x79x24mm case with battery holder
PP3 battery clipPP3 battery clip9V battery clip
Proto boardProto boardoptional - 160x100mm perf pad board