analogRead alternative (Part2)

Part 1, 2

Starting from the presentation of the parametric version of an alternate analogRead function, here is a lean version of the whole code. The header section of the code

/* Sampling parameters */
uint32_t _interval = 200; /* Interval between two consecutive ADC reading cycles */
uint32_t _lastTime;

Next comes the ‘setup’ routine

void setup(void)
{
	/* Initialize the ADC */
	InitADC(0);
	/* Console */
	Serial.begin(115200);
	/* Set the strating time */
	_lastTime = 0;
}

It contains the initialization parts of the ADC, console and timer. This section followed by the ‘loop’ routine

void loop(void)
{
	uint32_t _now = millis();
	/* Check elapsed time. This method handles millis overflow properly */
	if ((_now - _lastTime) >= _interval) {
		_lastTime = _now;  
		Serial.print(_now / 1000.0, 1);
		Serial.print(';');
		Serial.print(ADCRead());
		Serial.println();
	}
}

Every time the millis() is equal or more than the interval time, the loop routine prints the time (in seconds) and the raw ADC counts. And here are the two ADC related functions for acquiring analog signals in the fastest possible mode. Keep in mind that under these conditions, the output of the AnalogRead function ranges from 0 to 256 (@ 5 V)

/* Initilalize analog read in fast mode and low resolution */
uint8_t InitADC(uint8_t channel)
{
	/* Reset register contents */
	ADCSRA = 0;
	ADCSRB = 0; 
	ADMUX = 0;
	/* Set voltage reference */
	ADMUX |= (1 << REFS0); /* DEFAULT VCC, 5 V */
	/* left align ADC value to 8 bits from ADCH register */
	ADMUX |= (1 << ADLAR);
	/* Set channel */ 
	ADMUX |= channel;
	/* Set pre-scaler */
	ADCSRA |= (1 << ADPS1);
	/* Enable ADC */
	ADCSRA |= (1 << ADEN);
	/* Start first conversion */
	ADCSRA |= (1 << ADSC); 
	/* Wait for conversion */
	while (ADCSRA & (1 << ADSC));
}


/* Simple analog to digital conversion */
uint16_t ADCRead(void)
{
	/* Start conversion */
	ADCSRA |= (1 << ADSC); 
	/* Wait for conversion */
	while (ADCSRA & (1 << ADSC));
	/* Returned ADC value */
	return(ADCH);
}

Ultimately, if you really want to stick to the original analogRead format, here is the ‘advanced” ADCRead function:

/* Simple analog to digital conversion with analog channel parameter */
uint16_t ADCRead(uint8_t channel)
{
	/* Clear any lower 4 bits from the ADMUX register */
	ADMUX &= ~(0x0F)
	/* Set channel */
	ADMUX |= channel;
	/* Start conversion */
	ADCSRA |= (1 << ADSC); 
	/* Wait for conversion */
	while (ADCSRA & (1 << ADSC));
	/* Returned ADC value */
	return(ADCH);
}

 

Amazing 3D printing

As a big fan of 3D printing, I had a lot of fun watching this video

In the next future, this is what we will hear from NASA records:

  • “Hello Houston, we have a problem”
  • “How can we help ?”
  • “Could you email us a cable clip so that we can tidy up this harness”
  • “Yep, you’ll get in within the next five minutes”
  • “In white please”

analogRead alternatives (Part1)

Part 1, 2

Long story short: I never met wizards before Valerio knocked on quai-lab‘s door. And we all committed to help him to ‘augment’ the experience of his magic puppets. However, it’s long road from puppets to bytes and bits. But Valerio is not this sort of person who gives up easily and this post is a quite exhaustive answer to a question that I recently rose. Enjoy !

The analogRead is a very popular function among the basic standard functions from the Arduino programming environment. In just one command and one parameter it allows data acquisition from any from the 6 (or more) analog ports from an Arduino board. Fair enough for most applications. However, some applications may require some tweaks or fine tuning that analogRead cannot stand. This post describes what is behind the scene of analog to digital conversion on Arduino UNOs. Using the nuts and bolts from this post, you will be able to tailor your own analog readings using lower resolution and lower latency. These tunings may be very useful in applications where reading accuracy is not issue while reading time is an issue: e.g. reading a potentiometer position within a loop.

Achieving the ultimate performances has a price, and the price to pay is few lines of code. I decided to split the ADC reading operation in two distinctive parts: ADC initialization and ADC reading. Initializing the ADC is requires careful programming of 3 registers:  ADCSRA,  ADCSRB and ADMUX. Next are the few, almost self explanatory, lines of code that you may insert in your ADC initialization routine:

uint8_t InitADC(uint8_t channel, float reference, uint8_t resolution, uint8_t prescaler)
{
 /* Reset register contents */
 ADCSRA = 0; /* Consequently clears ADEN */
 ADCSRB = 0; 
 ADMUX = 0;
 /* Set voltage reference */
 if (reference == REF_VCC) {
 ADMUX |= (1 << REFS0); /* DEFAULT 5 V */
 } else if (reference == REF_INTERNAL) {
 ADMUX |= (1 << REFS1) | (1 << REFS0); /* REF_INTERNAL 1.1 V */
 }
 _reference = reference;
 _resolution = resolution;
 if (_resolution == RES_LOW) {
 /* left align ADC value to 8 bits from ADCH register */
 ADMUX |= (1 << ADLAR);
 }
 /* Set channel */ 
 ADMUX |= channel;
 /* Set pre-scaler */
 if (prescaler < 2) {
 prescaler = 2;
 } else if(prescaler > 7) {
 prescaler = 7; 
 }
 _prescaler = prescaler;
 ADCSRA |= _prescaler;
 /* Enable ADC */
 ADCSRA |= (1 << ADEN);
 /* Start first conversion */
 ADCSRA |= (1 << ADSC); 
 /* Wait for conversion */
 while (ADCSRA & (1 << ADSC));
}

Firstly, we will reset the content of the 3 registers by writing ‘0x00’s in each of them. Doing so we disable the ADC by clearing the ADEN bit. Then we will set ADMUX content, starting with the reference voltage setting. As most of you know, you may use Vcc (so as to say 5V) or a builtin reference voltage (1.1V) or read the voltage at the Vref input. As this post is intended for people with intermediate knowledge, I skipped the Vref option as it requires a good understanding of ADC in order to prevent irrecoverable mistakes. However it is easy from the table below to adapt the code to your needs:

adc_02

The reference setting is recorded in a global variable (_reference) as it will be needed in future code. In the same register, we will set the bits alignement. Let’s keep it simple. If you require a 0 to 256 range of ADC counts, use this option which I gave the constant name ‘RES_LOW’ for resolution low. Conversly, if you need a 0 to 1024 range of ADC counts, use the ‘RES_HIGH’ value in the resolution parameter. Once again, we will need this parameter for future code so it is recorded in the ‘_resolution’ global variable. Ultimately, we want to decide from which analog port we want to acquire data, that we do through the simplistic ADMUX |= channel; command.

A little bit more sophisticated is the prescaler setting within the ADCSRA register. Prescaling means applying a dividing factor to a reference clock, presently the CPU clock which runs at 16 MHz on an Arduino UNO.

adc_01

As it takes 13 ADC clock cycles per conversion in one shot mode, taking into account the 16 MHz CPU clock, it takes between 1.625 µs up to 104 µs to perform an ADC conversion depending on the prescaler value (from 1 to 7, which turns to a division factor ranging from 2 to 128 as per the above table). This highlights the fact that under the 16 MHz conditions, the choice of a division factor of 2 leads to a sampling frequency of 600+ kHz, which is far beyond the ADC potential. I experimentally determined that for a CPU clock rate of 16 MHz, the lowest permitted prescaler is 2 leading to a division factor of 4 and an ADC sampling rate of 300+ kHz.

You may wonder why we would not use the lowest prescaler as a default value. The reason is that the longer the sampling time from the ADC, the better the signal to noise ratio. In other words, the longer the time spent acquiring signal, the least the influence of noise, and ultimately the better the precision of measurements. So that if we need high precision measurements, we may want to use prescalers up to 7, to the cost of longer sampling times.

Then we want to enabled the ADC and launch a first conversion. In this way, all later conversion will all last 13 ADC clock cycles, while the first ‘blank’ conversion will require 25 ADC clock cycles.

Acquiring data is much simpler in comparison

inline uint16_t ADCRead(void)
{
	uint16_t result;
	/* Start conversion */
	ADCSRA |= (1 << ADSC); 
	/* Wait for conversion */
	while (ADCSRA & (1 << ADSC));
	/* Read digital value */
	if (_resolution == RES_LOW) {
		result = ADCH;
	} else {
		result = ADCL | (ADCH << 8);
	}
	/* Returned value */
	return(result);
}

Writing ADSC bit to one starts the one shot ADC conversion and then we wait until this bit is set back to ‘0’, meaning that the ADC conversion is fully completed. Then we read the ADCx registers according to the previously selected data format (left aligned or not). Just keep in mind that LSBs must be read priori to MSBs. Additionally, we may want to oversample data in order to improve the signal to noise ratio. Here is a complementary function which runs the ADCRead function a predetermined number of times:

uint16_t ADCRead(uint8_t samples)
{
	uint32_t result = 0;
	for (uint8_t i = 0; i < samples; i++) {
		result += ADCRead();
	}
	result /= samples;
	return(result);
}

Next post on same subject

Stepper Motors (Part 6)

Part 12, 3, 4, 5, 6

This post is about an other driver module which is very popular in the world of robots and 3D printers. These modules features the DRV8825 Stepper Motor Controller integrated circuit made by Texas Instrument (Datasheet available from >here<). Although many clones exist, it looks like Pololu was at the origin of this module.

drv8825

The DRV8825 is a micro-stepping bipolar stepper motor driver which features adjustable current limiting, over-current and over-temperature protection, and six micro-step resolutions (down to 1/32-step). It operates from 8.2 V to 45 V and can deliver up to approximately 1.5 A per phase without a heat sink or forced air flow (rated for up to 2.2 A per coil with sufficient additional cooling). The driver has a pin-out and interface that are nearly identical to those of our A4988 stepper motor driver carriers, so it can be used as a higher-performance drop-in replacement.

drv8825_1

The VELLEMANN Vertex 3D printer (aka K8400) features 4 to 5 (2 extruder configuration) of these drivers. They proved to be very reliable in spite of poor power dissipation. The amazing thing about these drivers is that most suppliers suggest the use of an heat aluminum heat dissipator mounted on top of the plastic enclosure of the driver chip itself, although most of you know that plastic has poor thermal transmission properties. The striking thing about it all is that the designers of most DRV8825 driver modules managed to create a strong thermal bounding between the bottom of the DRV8825 chip (which by the way feature a conductive metal pad) and the opposite side of the PCB thanks to through hole thermal bridges.

drv8825_2

So that the heat dissipator should be installed beneath the module meaning restricted exposure to air flows…Strange. Some argued that installing the chip upside down would restrict access to the current limiting trim pot. Quite true. But how often did you need to adjust this pot really ?

 

3D Printing (Part 10)

Part 1234567, 8, 9, 10

Almost shocking ! As I was not very satisfied with the quality of my prints, and after experiencing a strange awful printing incident (Wires every where, big melted material blob on top), I started having some sort of concern about temperature readings.

I used a very thin thermocouple connected to a pro grade thermometer (Testo 945). Then I managed to  lock the tip of the thermocouple firmly on the heated block and started performing measurements. And the readings where alarming. Although the set point for ABS was set to 245°C, the reading showed a good 280°C ! Some posts from the Vertex forum rang my bell, but none reported real data. Now it’s done. The original sensor is very badly reporting the print head temperature.

I quickly found on the Internet some vendors of thermistors (100k Ohm), some of them offering for a very cheap price assembled thermistor. So, why bother ? Here is the one I chose.

sensor_4

For less than 3€, the thermistor comes insulated and nicely wired

sensor_5

The I used a Faston connector adapter

sensor_1

that I modified in order to fit the print head profile and sensor size

Note: Watch out, the bead is fragile do not over tighten it

sensor_2

Once you are happy with the mechanical arrangement, remove the sensor, add some thermal compound around the bead and put it back. Remove the original thermistor wires from the print head PCB and place the new ones after adjusting their length.

  sensor_3

sensor_6

And now the readings are alright, no more than 5°C in difference between the thermocouple and the thermistor. The benefit from this modification is that you can retrofit it in case you find a better option.

Short discussion about the original sensor: Firstly, it is pretty risky to install it as specified, “feeling the bump” from the insulated tube. A minimal improvement would consist in removing the sleeve, marking the wire length in order to make sure that the glass bulb is properly fitted in its hole. In my opinion, what makes this big difference in readings is that the hole is too wide and the insulating tube is … insulating too much. I am afraid that using thermal compound would not help bridging the thermal gap. Am I the only one with this problem ? Didn’t it occurred during testing at VELLEMAN labs ? That’s strange ! And dangerous for the “plastic” parts all around.

And by the way, using 230°C for extruding ABS is just fine.

HTH

3D Printing (Part 9)

Part 1234567, 8, 9, 10

Open source printers are for ? … They are for mods, hacks and tweaks !

The first obvious modification (not to say immodestly improvement) deals with the cooling air blower in front of the print head. Most the air flow would splits on the Y axis rod, some would re-converge thanks to physic’s law, most would cool the peek insulator and little would reach the printed material. Gasp !

I found some nice ideas on the net, tried to design one based of the split air ducts principle but the result was poor due to the low section of the air ducts. So I decided to design one of my own which would match the following requirements:

  • Apply the least non destructive modifications to the existing design
  • Direct most of the fan production toward the printed area (1 or 2 extruders)
  • Has no effect on the size of the printed area

And here is the result:

air_ducts

The assembly is made of two symmetric parts which encapsulate the “y” rod. Tow key pins allow an easy and quick assembly. The two parts are  locked by an horizontal retaining screw (1x self-threading size 4, length 1/2′) and by vertical screws which go through the fan holes down to the cooling ducts assembly (2x self-threading size 4, length 1/2′).

The only change applicable to the existing material is a gentle bend applied to the fan holder so that the fan keeps in an horizontal position. Printing the parts is easy, take little time a little material (PLA is ok but ABS will probably last longer as the part faces a heated zone. No need for support and 0.2 mm “z” steps are far sufficient.

air_ducts_2

Here is an exemple of what you can get out of th Vertex k8400

P1170677

Installing is easy

P1170682

and results in this

P1170691

In other words, printing this part is a good exercise and results in bringing a significant improvement to the printing head design. The STL files are available for download from >here<

HTH

3D Printing (Part 8)

Part 1234567, 8, 9, 10

This post is all about the new printer that I bought for my own pleasure and private use ! It globally fullfils my own requirements which could be enumerated in this way:

  • Budget: less than 800€
  • Printed material: PLA and ABS, others if possible; 1.8 mm filaments
  • Open source: mandatory
  • Extruder: 1
  • Printed volumes: 160x160x160 mm minimum
  • Turn key/Kit: no preference

Although I keep a constant attention to the 3D printers, I spent some time on the net seeking for printers which would match my expectations. The offer is widening from day to day, however, many attractive printers are advertised yet but still under development. So that I quickly resumed my early searches and made my decision for… the Vertex K8400 from VELLEMAN. This printer looks like it is the fusion of the early k8200 and the Ultimaker 2. The Ultimaker 2 was pretty high in my list but the price is steady high and far exceeding  my budget, on the other hand the k8200 looks good but I disliked the frame arrangement. So that the mix of both was of interest for me. The Vertex is available in a surprising wide range of price, starting at 600 € and getting up to 800€ depending upon the vendors. I carefully reviewed the building instructions which looked very detailed and very nicely illustrated. From the pictures I got the feeling that the material used by VELLEMAN were high standard. No time to loose I went to the order section of CONRAD and placed an order for one.

vertex

I arrived in a nice clean package, some sort of cardboard suitcase where all parts are well packed and labelled. I found no damaged parts although fragile parts (e. g. glass plate) coexist with heavier ones (e. g. PSU). I assembled the whole printer in two consecutive half-days. So far my advises are:

  • Place all parts in a large surface in order to find them easily and avoid to mix them up.
  • Read carefully the instructions and take your time.
  • Use good quality tools.
  • If you have no experience at all in 3D printers, it might be a good idea to join a FabLab or such community in order to get help.
  • Use the forum. As usual there is “à boire et à manger”, in other words there is poor and good quality information.

And here are a few tricks from my own experience:

  • Twisting the signal wires is boring but it helps a lot routing them properly and nicely. Do the routing as the last step, including down to the main board.
  • The Spiral Wrapping Band is hard to install and useless. I prefer the plastic ties.
  • A multi-meter is useful. Although it is not mandatory, I strongly suggest that you have own in order to check voltages and possibly temperatures if your multi-meter features such option.
  • Be very, very meticulous at adjusting the printing head rods. The better the adjustment, the lesser the frictions and constraints, the lower the power sunk from the drivers, the cooler the stepper motors. And ultimately and probably the better the prints.
  • Use alcool to clean the Buildtack surface, no acetone. This Buildtack surface is awesome be must be treated with care.

And now, it’s time for testing !

zon zon zwiss zwiss rol rol rol rol zon zon zwiss zwiss rol rol rol rol zon zon zwiss zwiss rol rol rol rol … crack ! Failure ! I could not install the filament properly, although I could push it manually through the extruder (in other words, this was not a temperature nor a clogging problem). Once the filament in place, the prints were incomplete and all observations were converging towards the extruder driver. Although these drivers use high quality chips from TI, one over millions may fail, and it just happened to me.

DRV-8825

As the chip was overheating constantly, I though that it was a heat dissipation problem. But neither a small heat dissipator nor a cooling fan helped. After replacing the defective module, none from my “improvements” proved to be necessary. The module was replaced under warranty simple and easy. However, it took me a week before I got the spare part.

Please note the small adjustable resistor on the top of the DRV8825 module. You must adjust it in order to set the proper trigger level for over-current sensing, please read instructions >here<.

Next post on same subject

 

Stepper Motors (Part 5)

Part 12, 3, 4, 5, 6

The A4988 in details

pololu_3

Previous posts described the basic use of the A4988 driver. We shall get deeper in the A4988 driver in order to achieve the ultimate driving performances.

Apart from the STEP and DIR pins the A4988 driver features additional functions addressable through the following pins

  • ~RESET: the ground true RESET input sets the translator to a predefined “home state”, and turns off all of the FET outputs. All STEP inputs are ignored until reset input is set to HIGH. The RESET input is floating and should be connected to GND or VDD at any time. It is a valid option to connect the RESET input to the neighbour SLEEP input which is pulled at a HIGH level by internal resistor.
  • ~ENABLE: When the ground true ENABLE Input is set to a logic HIGH, the outputs are disabled. When set to a logic LOW , the internal control enables the outputs as required. The translator inputs STEP, DIR, and MSx, as well as the internal sequencing logic, all remain active, independent of the enable input state.
  • ~SLEEP: A logic LOW on the ground true SLEEP input turns the translator in sleep mode in order to minimize pits power consumption. A logic HIGH allows normal operation, as well as start-up. Wake up lasts at least 1ms.
  • MS1, MS2 and MS3:  The microstep resolution is set by setting the inputs MSx according to the following table.  The MS1 and MS3 pins have a 100 kΩ pull-down resistance, and the MS2 pin has a 50 kΩ pull-down resistance. When changing the step mode the change does not take effect until the next STEP rising edge.
MS1
MS2
MS3
Microstep Resolution
L
L
L
Full Step 
H
L
L
Half Step
L
H
L
Quarter Step
H
H
L
Eighth Step
H
H
H
Sixteenth Step

Next post on same subject

Tips and Tricks (Part 25)

Previous T&T

Burn Arduino bootloader… or burn your time !

Problem: When trying to burn the bootloader on any Arduino compatible board using the AVRISP mkII, Arduino IDE reports a “avrdude: usbdev_open(): did not find any USB device “usb“, “Error while burning bootloader.” smashing error message.

usb_01

Although many people faced this problem and many other tried to provide an answer, few web sites contain a simple and yet efficient answer to this problem. So that I take the risk to write this “Ultimate”, “My own way”, “Alternative” procedure.

When this situation will occur ? Mostly after installing AVR Studio or Visual Studio avr plugin, or after updating the driver from the windows environment. On completion of such operation, it is very likely that the Device Manager screen will show such list:

usb_2

The problem is that this version is not compatible with Arduino IDE and results in the above error message. Recovering from this situation is a two stages process:

  • Downgrade the driver
  • Upgrade avrdude

Downgrading the driver is pretty simple as long as you get the proper software package that you can download from >Here<. Extract the folder in a temporary folder and run the inf-wizard.exe from the bin sub-folder.

Here are the configuration forms

usb_3

Click Next >

usb_4

Select the device to install and click Next >

usb_5

Check the device configuration and click Next >

Store the installation file AVRISP_mkII.inf in the temporary folder.

usb_6

Press the Install Now.. button (unless you changed your mind)

You’ll get these splashing forms

usb_7

usb_8

And ultimately get this new list from the Device Manager

usb_9

Half the way done !

Now we need to upgrade avrdude to rev. 6.1 from >Here<

Unzip the avrdude-6.1-mingw32.zip file and store it a temporary folder.

In your [my_arduino_folder]\hardware\tools\avr\bin folder, deactivate the original avrdude.exe file, by adding an extra character or so and copy the [my_temporary_folder]\avrdude-6.1-mingw32\avrdude.exe file to [my_arduino_folder]\hardware\tools\avr\bin folder

usb_11

In your [my_arduino_folder]\hardware\tools\avr\etc folder, deactivate the original avrdude.conf file, by adding an extra character or so and copy the [my_temporary_folder]\avrdude-6.1-mingw32\avrdude.conf file to [my_arduino_folder]\hardware\tools\avr\bin folder

usb_10

Done !

usb_12

Ahhhhhhh !

Here are a couple of links which were helpful to me and contain fragmented although advanced information: https://goo.gl/8jn8I0, http://goo.gl/JCjfO1.

HTT

Cool stuff of the day

My daughters played a lot with their “Polly Pocket” in their young ages !

polypocket1

An endless perspective of gaming nicely packed in a hand palm format. Which translates into this portable lab case…

UNO Portable Lab Case

in the the Arduino’s world ! Isn’t it cute ?

More on the Arduino UNO Portable Lab Case >here<