Search This Blog

Friday, December 21, 2018

STM8 Timer - Irrigation

Projects / Misc 8-bit uC projects

Water level sensor

The TPP223 (.pdf) touch sensor I bought finally arrived.  As usual, the LED is just too bright.  I change the series resistor (bottom in black) to a 2K (0603).  A small value capacitor (0-50pF) can be added to the empty footprint at the top right corner to reduce the sensitivity of the sensor.

The default output is push-pull, active high, non-toggled.
There are two solder bridge jumpers: A, B to set the following options.
A: (AHLB) pin 4 - Active low
B: (TOG) pin 6 - Toggle


For testing, I used a small piece of double side tape to stick it to the side of a plastic container and slowly filling it with water.  The LED lights up for a minute or so.


I think this could be useful for determining if water level reaches the high water mark.

I cut up a plastic bottle into two halves and fitted the top end with a short PVC jacket from a stranded CAT5 patch cord.  I used lots of hot glue to seal the joint. The top end works like a funnel. I drill a hole on the bottom half for the exit.


I tried to make a gentle L bend without crushing the PVC jacket.


I am trying to avoid using regular tapes as they tends to dry up and crack under sun light. I cut up 3 strip of paper about 2" wide x 11" long.  I applied a generous amount of white glue and use it to wrap it around the plastic bottle to hold it together.  This forms a paper mache shell to hold the two halves together.


I soldered in a 22pF capacitor to the empty pads on the touch sensor board.  This lowers the sensitivity a bit. I soldered a short piece of wire (~1cm) to the corner pad of the touch sensor to a small copper foil.  The bottom part of the copper foil is used to set the high water mark.


The output of the board drives a 2N7002 MOSFET which converts it to an Open Drain output.  This will be wired in parallel to the light sensor.  The on resistance of the MOSFET is about 10 ohms.

I have to make my trip much sooner. I have given away two of the plants as I can always grow more.  Only been running it for a few days on the remaining one and it seems to be okay.

Things I have learnt so far:
  • The pump I used is a centrifugal pump which requires that the pump to filled with water.
  • The pump produces a lot of electrical noise generated by the DC motor during commutation to reset the microcontroller.  I have included ceramic cap near the output connector on my PCB, but that wasn't good enough.  I had to add a 0.047uF cap at the pump side end of the long cable. I added another one to the other end of the cable for good measure.
  • The water drains out of the container very quickly making it hard to measured..  There are ways to stop the drainage.  Right now I set the timer for a fixed time instead of relying on water level detection
  • There was water leaking out of the seams in the pump, so I touched it up with super glue. That fixed the issue.
  • Water from the container relies on gravity.  Some water droplet ends up sticking to the small diameter silicon tubing.  It amounts to less than a couple of cc.  Try to keep he slope of the tubing uniform to minimize the water retained. I might try using a slightly larger diameter tubing. It probably not going matter too much as they'll get pushed out next time.


Friday, October 19, 2018

STM8 Timer

Projects / Misc 8-bit uC projects 
This is one of those weekend project.  It is a timer built using STM8 microcontroller for controlling LED light strip and a water pump. It can be used for other things.

There are two switched outputs: 12V 2A for LED strip switched by a MOSFET and a MC34063 switch mode power supply is used to generate the 2.5V for a small pump.  The output voltage can be altered by changing the feedback divider.  The buck converter can be disabled by sending a logic '1' via diode D3 to its feedback pin. There is a leakage path  (~0.4mA) to the output from GPIO via D3 and R7.  The whole block (except C2 and C4) can be removed when not needed.

I am using a 5.1V Zener diode as a shunt regulator for the 5V rail while I was waiting for my 78L05 order.  I notice that there are some artifacts on the LCD with the 78L05. I'll guess I can stick with the Zener diode or  add a bulk electrolytic or tantalum 10uF capacitor across the 5V rail.

There is a sensor input and two unused solder pads for I2C.



The LCD is connected to the main PCB with two sets of 6 conductors ribbon cables.  I am using 4-bit mode on the LCD. I have wired the R/W pin for polling the busy flag in the LCD controller.


There is a 3-pin connector for the SWIM hardware debugger.

LCD delay vs polling

The datasheet for the character LCD lists the timing for each of the instructions.  These are the worse case timing that include timing variations due to component variations, voltage and temperatures. Most of the projects implements a delay loop to meet these timings.


The LCD timing can be tighten up by polling the internal Busy Flag to determine when the LCD is ready for the next command.  This requires an additional GPIO to control the R/W signal.


The instruction time can be less than the values in the datasheet which have some margins for component variations.

TIM1 is used as a trigger for ADC and timer interrupt every 5ms for a software RTC implementation.
I used a prescaler of 1 and a reload value of 60000 in TIM1_RELOAD.
12MHz/60000 = 200Hz
With calibration, the reload value can be used to trim the accuracy to be within +/- 0.72 sec per day. 
(24 Hr/day * 3600 sec/Hr )/60000 = 1.44 sec/day
I have implemented a menu for trimming.


The timer reload value could be changed in the IRQ service routine from a  software phase accumulator to further increase the resolution to fractional values. The difficult part is to automate the calibration against an external time reference (e.g. GPS).

The ADC alternates between the buttons and sensor inputs.  They are managed inside the ADC IRQ and their results stored in global variables.  The key input routines are run inside the IRQ.

The ADC value is matched to a look up table for decoding the buttons.

const uint16_t Key_Value[]=
{
  510+ButtonTolerance, 194, 340, 140, 510, 163, 255, 123
};
  • count is used to keep track of the amount of time that the button(s) are pressed.
  • code is used to store the code for button. KEY_FLAG bit signalnifies a key make event
  • A button is recognized if it reaches KEY_THRESHOLD (passed debouncing)
  • If the count reaches KEY_CNT_MAX, then a key make event occurred with a  KEY_LONG attribute.  The counter is then loaded with the KEY_RELOAD value.  The difference of these values controls the key repeat rate.
typedef struct
{
  volatile uint8_t code;
  volatile uint8_t count;
} key_t;

enum keys { KEY_MENU=0x04, KEY_DEC=0x02, KEY_INC=0x01, KEY_MASK=0x07, 
            KEY_LONG=0x20, KEY_REPORTED=0x40, KEY_FLAG=0x80 };

#define KEY_REPEAT_RATE  4
#define KEY_THRESHOLD  5
#define KEY_RELOAD  50
#define KEY_CNT_MAX  (KEY_RELOAD+TICKS_PER_SEC/2/KEY_REPEAT_RATE)

These data structures are used to control a simple user interface using 3 buttons.
  • Value is a pointer to the item which can be an 8/16-bit integer or the text label for a UI_Menu_t structure or a function.
  • Modified is a pointer to a flag variable that get set when an item is modified.  It is also used as the pointer to a function.
typedef struct
{ 
  void    *Value;
  uint8_t  *Modified;
  uint8_t  X;
  uint8_t  Y;
  uint8_t  Width;
  uint16_t Min;
  uint16_t Max;
  uint8_t  Flags;
} UI_Item_t;

typedef struct
{ 
  uint8_t   *Text;
  UI_Item_t *Items;
  uint8_t   Size;
} UI_Menu_t;

enum DataFlags { D_12H, D_U8, D_U8Z, D_U16, D_Menu, D_Function };



This is inside the "Alarm" sub-menu. (See further down for an updated version)
A long press of the Edit/Exit key is used to enter/exit the setting menu.  The settings are stored in the STM8's internal EEPROM.

I have selected the items can be selected by using the buttons.  An up/down arrow appears on the right hand side of the item.  The Prev/Next key can be used to decrease/increase the value by one.  When the key is held down, the values auto decrease/increase by 10.  The Edit/exit key is used to exit the editing.


The firmware so far consumes a fraction of the available memory - about 2.8kB. (8kB FLASH, 1kB RAM).

I made a make shift light sensor by filing the top off a 2N2222 (.pdf) TO-18 metal can package to expose the die inside.


I use a bit of hot glue to seal the package.  It is a bit of dust and dirt magnet.  I hope it doesn't turn yellow like epoxy after exposing to sunlight.  I covered the sensor with a bit of plastic from an antistatic bag to reduce the sensitivity.

I paired it up with a 2N3904 to to improve on the gain as the 2N2222 die is not sensitive to light. They are wired as a Darlington pair.



I guess this has to do until I get my CdS photoresistors in the mail.  It will be connected directly across the sense input.


The following is the Alarm menu.  The alarm time is set to 7:00am and the pump goes on for 3 minute.  The LED is set to supplement the ambient light.  It turns on whenever the ADC value is above 650 within a 12 hours period.  A bit of hysteresis is added in the code to minimize the lights toggling.


This replaces the plug in mechanical timer that runs warm (2W).  When running in idle, power consumption at 12V is around 14mA. The wallwart is cool to the touch and below the resolution of the cheap wattmeter I have.


I hooked it up to the LED strip for my urban window garden. The sensor is place above the LED strip and pointing outside the window.   The LED strip will be switched off to save power when the ambient light has cross the set threshold.  It was still dark outside.


The timer is hanging from the mounting holes on the LCD.  I am still waiting for the pump and drip irrigation parts to come in.

Part 2: https://hw-by-design.blogspot.com/2018/12/stm8-timer-irrigation.html
Files are in github: https://github.com/FPGA-Computer/Timer

Monday, September 24, 2018

Candle stove

Projects / Preparness

Two tornados showed up.  The second hit a major power distribution transformer and knocked out the power grid in my area for 48 hours. At one point there were 200,000 or so out of power.

Like most cooking shows, I made one previously. This is my emergency bootle with matches, candle, and a dry pack.


The lid is a candle stove.  I let it burnt a bit to melt the wax to soak the cardboard  and tried to shape the wax a bit so that it would fit the bottle.


The cross is made out of thin corrugated cardboard that had slots cut in them.


It light up very easily.  It turns out the cardboard and pieces of wax would just light up easily.


There is a lot of carbon soot in the flame and it is very messy.


That amount of wax is sufficient to make a pot of instant noodles.

or reheat a pot of homemade soup.


Advantage: Simple to build, high energy density, not having to deal with storing liquid fuel.
Disadvantage: very dirty flame, lots of carbon soot coating the cookware, low temperature.

Next time I'll see if I can improve the fame by having the wax vapor premixed air before combustion like my kerosene burner.

Links:

Backout:

Here is a picture of my city in the backout.  It kinds of looks like some rural area or North Korea.


As of this morning, they have restored the power for all but one city block by using the redundancy in the grid.  They are going to rebuild the substation in the next coming months.

Friday, September 14, 2018

Portable F103 - Power source detection

Projects / F103 Pod

I did some power measurements.  They agree with the published values on the datasheet.  The LED backlight can add another 2 - 5mA depending on brightness setting.


To converse battery life, the firmware can optionally drops the clock speed to 12MHz. This should allows for a battery life of 10+ hours with the larger LiPo and 5+ hours for the smaller one (vs 2+ and 1+ hours at full speed.)  The actual current consumption may vary depending on the amount of time the CPU is active vs sleep.

The firmware has to be able to detect if a charger or USB is present.  If so, it can run at the full clock speed of 72MHz

The STM32F103 is quite old and does not have a charger detection hardware built-in.  The USB data pin on the STM32F103 can be used as GPIO and is able to detect USB connection. and some of the more common chargers.

Silicon Labs EFM8UB1 on the other hand can detect the complex charging protocol in USB spec. Apple chargers can also be detected as it USB pins can also function as ADC inputs.

Charger Detection

For the STM32F103 FT (5V tolerant) at VDD = 3.3V, the VIH threshold is
0.42*(3.3V - 2V) + 1V = 1.546V (min)
STM32F103 I/O Static characteristics
A simple USB chargers that have data pins D+ and D- shorted together can be detected by configuring the   D- line as a GPIO input pin with an internal pull-down resistor.  The 1.5K pull up from D+ is looped back by the connection to the D-.
The voltage at the D- is 3.3V * 50K/(50K+1.5K) = 3.2V which is a logic '1'.
Apple chargers uses a resistor network to encode the current capacity.  For the 1A chargers, they use a 43K/ 51K voltage divider on the D- pin.

Apple 1A charger resistor networks
The parallel resistance of 51K//50K is around 25K. The voltage at the D- is
5V * 25K/(25K+43K) = 1.84V which is a logic '1'.   This is also treated as a charger.
For Apple 0.5A charger,  the voltage is at 1.25V which is within undefined area and cannot be read reliably.


USB detection

There are 15K pull down resistors on the USB port.  The firmware detect that by configuring the input pin with an internal pull-up resistor.
The voltage at the D- is 3.3V * 15K/(50K+15K) = 0.76V which is a logic '0'.
If the pin is a '1', then it could mean that the input is floating or that it is connected to an Apple 0.5A or 2.1A charger.  I came up with a way to detect whether a pin is floating a while back, but I won't bother here.

The detection code is listed below. I added in Delay(0x80000) for the connector contact debouncing.  The smaller Delay(0x200) is there to give a bit for parasitic capacitor to charge up and stabilize.



Status is set to Pwr_Unknown as further detection is needed by secondary mean.  If the Battery voltage is above 4.3V that means that the Power Switch is in the On position and external power source is present.

Note: Blogger messes up my code each time I go into the editor.  It is too much work to fix their problem.  I am giving and switching to using screen captures.

Thursday, August 30, 2018

Portable F103 - ADC

Projects / F103 Pod

The battery voltage is sampled by a voltage divider and fed into the ADC at PA0.  C12 is used to lower the AC impedance of the divider and provides charge to the ADC sampling circuits during a conversion.  The 3.3V rail from my LDO is as a voltage reference for the ADC and I probably used some Chinese 5% resistors.


I did some calibration by hooking up an external linear power supply and my 5 digits multimeter.  I ran a regression analysis on the data.


The first two columns are the collected data and the rest are the analysis results. Vin can be calculated using
Vin = ADC * 0.001375334 -0.043132682
The "Predicted Vin" column are the results using the formula and the "Residuals" are the difference from my input voltage.  The error is around - 0.0017V to 0.0014V which isn't too bad.

Using Fast Decimal to Fraction Approximations, I converted the coefficient into a fraction.


I can scale the voltage in mV and use 32-bit integer math for the calculations. The equation becomes
Vin = (ADC * 447000)/325012 - 43  [mV]
ADC max = 4095.  4095 *  447000 = 1830465000 which is within 32-bit integer bound.

Formatting the voltage stored in mV to a fixed point is easy.  I use the small code size xprintf.c from ChaN's FatFS.  It does not support float. either.

  Batt = Batt_Read();
  xprintf("%01d.%03dV",Batt/1000,Batt%1000);



Voltage reference for ADC

The internal reference source is better than the cheap XC6206P332MR LDO that I am using at 100ppm/C (typ).


The internal reference for the STM32F103 is specified as 100ppm/C max. The ADC reading of the internal reference at operating temperature vs calibration temperature can be used as a scaling factor to correct the results.


For critical applications, the MCP1700T-3302E/TT LDO can be used. It has better tempco comparable to decent a reference source and is footprint compatible.


Temperature measurement

The datasheet shows the following table.  The only useful point is the linearity. The rest of the numbers aren't too useful as is without some calibration.


I did a rough experiment of measuring the internal temperature sensor and internal reference over temperature.  Today is an unusual day as it was very warm in the day time and cool at night.  With the help of my freezer, I got 3 temperature points for a linear regression.  I do not have enough data point for a proper analysis or did I bother to tape the thermal couple onto the microcontroller to get a more accurate temperature reading. There are quite a bit of improvements that can be made.


Temp column is the measured temperature with a thermal couple.
Ref column is the ADC reading of the internal reference
T Column is the ADC reading of the temperature sensor
T ratio is the temperature reference vs internal reference

The most surprising result is that the "T" column has better correlation than the "T ratio".


The formula for the temperature sensor on my STM32F103 chip  is
Temperature = T * -0.151911851511773 + 286.686137163595 [C]
I did yet another liner regression using the "Ref" column.  For my particular board, the ADC value of the internal reference is a slightly better temperature sensor.



Wednesday, August 22, 2018

Portable F103 - Misc items

Projects / F103 Pod

32kHz oscillator start up issue

I ran into a bit of oscillator start up issue with the 32kHz crystal.  I don't know if it is because of the corner cases of the cheap STM32F103 chips combined with the 32kHz crystal I pulled from a PC motherboard that doesn't satisfy ST's recommendation of load capacitance and bad luck.  Looks like it could be VBAT is out of specs and that might have damaged the internal circuits in the process. 

Anyways the symptoms seems to be that from time to time the crystal would take a long time to start up and occasionally fails.  My code was waiting for RCC_BDCR_LSERDY.


So I looked at the signal levels at the oscillator pins and found that PC15 (OSC32_OUT) was at 3.2V where as PC14 (OSC32_IN) was near 0V.  There was something funny about this as there was supposed to be an internal feedback resistor that should make the inverter linear at about mid-rail.




I measured a DC resistance of about 2.8M to ground on both input and output pins.  Not sure why it was grounded at the middle.  Could that be a fault due to handling?  Or that it was damaged by me violating the VBAT specs.

I read the following from an article (.pdf)  They recommended 10-15M feedback resistor for 32kHz. Higher resistor values means higher gains.


I looked at a few of the PC motherboards and they all have a 1M resistor, so I have decided to take one from the motherboard and solder in parallel to the oscillator pins.  It doesn't hurt if the oscillator passives are close to the values where I got the crystal from.  I do however recommend to follow ST guideline whenever possible.

Both the pins are now at 1.6V and the start up issues seems to be cured for now.  I have made the changes to the PCB layout for an optional resistor.

It seems like the VBAT circuit might be the cause of this issue. I used two silicon diodes to reduce the voltages from battery.  In LTSpice, the voltage drop works out to be 0.6V at 1uA and in theory that should satisfy the maximum voltage.

I operate the board without the battery attached for development as I might need to solder or probe things.  The LiPo charger is in float charge mode, so UB+ is always around 4.2V.  With the battery attached, the charing would have been stopped and would not see voltages this high that often.


The problem is that the Power Switch circuit bypasses VBAT when VDD is present.  There might not be sufficient current drawn to maintain a high enough voltage drop. I have decided to add an additional load at output of the diode with a 2.7M resistor.

LiPo capacity estimation

I have decided to estimate the MP3 player battery capacity by weight.  I gathered a few LiPo batteries of the same pouch style from my collection.  Unfortunately I don't have enough for a reliable estimate, but I think they are better than not having one.


The "400mAH" was a aftermarket replacement for the ipod mini. Apple had a recall of the ipod because of battery issues, so I swapped the my replacement back out.  The "180mAH" one was from a picture frame and the two smaller ones are from 2 different models of the MP3 players. I trusted the "180mAH" battery capacity a bit more as it was a part in a product not directly sold from China.

It works out to be about 41.86mAH per gram. The battery weights which is mostly composed of the chemical ingredients are used as a ratio for the estimate. I think the numbers are close as the capacity are close to rounded numbers. The larger MP3 player battery is close to my initial 100mAH estimate.


The power consumption of the STM32F103 could be reduced by running at or below 12MHz while on battery.