Monday, November 9, 2020

Constant current LED driver using ATtiny13 - Headlamp flashlight

Here is a simple constant current source for driving 7 white 5mm LEDs and also 2 red LEDs. I have made the circuit for a headlamp flashlight that had a soft button which required a microcontroller. To save the battery life the microcontroller is powering down when the lights are off with a current draw of only 0.3uA.

Constant current LED driver using ATtiny13 - Headlamp flashlight

Schematic of a constant current LED driver using ATtiny13A microcontroller

Constant current LED driver using microcontroller schematic

Using a resistor for current limiting in a LED driver is inefficient because when the battery voltage drops the resistance remains the same leading to a low light brightness even though there is still potential for a higher current in the batteries. For this reason it is preferable to replace the fixed resistor with a variable one. For that a transistor mosfet is used here (Q3 and Q2).

The circuit is very simple and the working principle can be applied to other LED projects. In this case I had to fix a headlamp torch that had the main IC burned out so I made another PCB to drive the LEDs. The flashlight has 7 white LEDs that are driven with 210mA (30mA for each LED) and 2 red LEDs (40mA - 20mA per LED).

Q3 is an SMD mosfet acting as a variable resistor. A mosfet is better than a transistor here because when the batteries are almost depleted the voltage will be too low to waste on the voltage drop that a transistor has even when is fully turn on. The collector voltage drop increases with the current and since the red LEDs only need 40mA, a cheap SMD transistor Q2 is used there. When the battery is almost empty the voltage is around 0.8V - 1V. If the flashlight uses 3 batteries, the lowest voltage will be around 3 volts therefore a mosfet with a low Vgs must be selected.

A 0805 SMD current sense resistor of 1 ohm is used (R5 and R3) and the ATtiny13A microcontroller monitors the current through the LEDs by measuring the voltage drop on the shunt resistor using an ADC. Then PWM is used to generate a voltage to control the mosfet. The PWM frequency is fixed only the duty cycle varies. If the current is lower than the desired one, the duty cycle is increased. If the current is too high the duty cycle is decreased.

An RC low-pass filter composed by R4 and C3 is used to convert the PWM to a steady voltage. 

Q1 mosfet is for reverse voltage protection in case the batteries are connected in reverse. The mosfet must have a low RDSon to drop as little voltage as possible at the maximum current that the circuit uses. Both Q1 and Q3 are both CPH3448-TL-W SMD mosfets with 0.038 ohm RDSon. To learn more about reverse voltage protection see this article from Texas Instruments Reverse Current/Battery Protection Circuits

J2 has 6 SMD pads for soldering the custom connector for the ISP programmer that I made from 6 pins header with the pins bend at 90 degrees. After programming the connector can be easily desoldered compared to a through hole one.

Headlamp repair constant current microcontroller

Headlamp repair constant current microcontroller

Software code for headlamp using ATtiny13A microcontroller and a soft push button

The code can be seen or downloaded bellow and has comments that explains it. The PCINT2 pin is set as an input with the pull-up resistor enabled and when the button is pressed the pin is pulled to ground triggering an interrupt and then the ISR sets a flag that the button was pressed. The debouncing is made in software. On every button press the flashlight toggles between on and off. When OFF the microcontroller enters in power down power saving mode and the current consumption is around 0.3uA. This is important to preserve the battery life while the flashlight is not used.

When the flashlight is ON the voltage at the current sense resistor is measured continuously by the ADC2 pin for main light and by the ADC3 for the auxiliary light (red LEDs). The transistors are controlled by Timer0 set in fast PWM mode with OCR0A controlling PB0 and main lights and OCR0B controls PB1 and the auxiliary light.

To switch between main and auxiliary light the button must be held down for approximately 2 seconds. Other modes can be implemented such as flashing and other brightness levels but are not implemented in the current software.

The current is set by the defines ADC_MAX_BRIGHTNESS and ADC_AUX_BRIGHTNESS which represents ADC units. To convert from current to ADC units use the formula: 

ADC = (Vrsense * ADCres) / Vref

Vrsense - is the voltage at the current sense resistor = Desired Current * Rsense = 0.210A * 1ohm = 0.210V
ADCres - is the ADC resolution. For a 10bit ADC used here this is 2^10 = 1024
Vref - the ADC refference voltage which is 1.1V in this case

So for 210mA the ADC value is (0.210V * 1024) / 1.1 = 195

By default ATtiny13A comes with the 9.6MHz CPU clock divided by 8 so I removed this clock prescaler by changing the fuse bits to get the full speed. Here are the fuse bits programmed with avrdude command line:

-U lfuse:w:0x7A:m     -U hfuse:w:0xFF:m 

Be aware that is a difference between ATiny13 and ATiny13A regarding the fuse bits so look at the microcontroller label to check the type. Here is the site used for calculating the fuse bits.

Download

main.c - v1.0

adc.h - v1.3 

Thursday, October 15, 2020

Capacitive transformerless power supply schematic for PIR motion sensor NV-1111.35

In the previous article I have explained how a PIR motion sensor works. There you can also find the schematic for the NV-1111.35 PIR sensor which is based on a popular three stage op-amp topology. Understanding this can help you understand other pyroelectric sensors as well.

This sensor is powered by a capacitive transformerless power supply with an output of 8V and 7mA of current.

Capacitive power supply for pyroelectric (PIR) sensors

The board includes a power 24V relay that can switch a load up to 1200W. The relay is controlled by the sensor's main board.

Capacitive power supply for pyroelectric (PIR) sensors
A rectifier diode and the output 8V Zener were burned which evaporated the copper traces. The board was repaired and components replaced

Schematic of a capacitive transformerless power supply for NV-1111.35 PIR outdoor sensor switch

Schematic of a PIR sensor capacitive power supply

WARNING: this type of power supply is meant only for use cases where no humans or animals can touch the board. This is because it doesn't have a galvanic isolation. If the Zener diode fails or the wrong part is touched will lead to electrocution with mains voltage.

The schematic is self explanatory. To understand how a capacitive transformerless power supply works read this very interesting PDF which also talks about resistive power supply, half and full bridge types and which one can be used to drive SCRs and TRIACs:

Transformerless Power Supply Design

https://www.designercircuits.com/DesignNote1c.pdf

Sunday, October 11, 2020

How an outdoor motion PIR sensor switch works with schematic

In this article I will be explaining how a pyroelectric (PIR) sensor works and show the reverse engineered schematic simulated in LTspice. The schematic is for NV-1111.35 outdoor PIR sensor used to switch a mains light and has 3 potentiometers for setting SENSITIVITY, LUX and TIMEOUT.

This sensor is based on a popular three stage op-amp topology. Understanding this can help you understand other pyroelectric sensors as well and also something about active filters using LM324 and removing and setting a DC voltage bias.

Outdoor PIR sensor board repair

Outdoor PIR sensor board repair

 

How a PIR sensor work

This particular sensor board is using the D203S PIR sensor. Pyroelectric passive infrared (PIR) sensors detect infrared (IR) radiation. A warm object emits infrared energy that is not visible with a human eye. Since the purpose of the sensor is to detect motion not only heat, there are two parts sensitive to IR that look like two little windows or slots. 

D203S PIR sensor
The sensor window is actually split into two parts

This two elements are used in series with opposite polarity so the average radiation is cancelled out. When the sensor is idle both slots detect the same amount of IR so the ambient temperature won't trigger the sensor. If a warm body like a human or animal passes by the infrared energy it is first detected by an element then by the second one and so generating an AC signal. A mosfet is also included to buffer the weak signal produced by the PIR sensor.

PIR sensor elements polarity diagram
PIR sensor diagram

 
Principle of the PIR sensor movement detection
Image from AN4368 - Signal conditioning for pyroelectric passive infrared (PIR) sensors

The signal produced by the PIR sensor is around 1mVpp and it has a DC offset voltage that can vary from 0.3V to 1.2V. 

Fresnel lenses

In order for the sensor to cover a wide angle, Fresnel lenses are mounted in front of it. They are cleverly designed with many areas of Fresnel lenses arranged in a way so they can split the detection area into multiple sections. This for the sensor looks like it has not only two detection elements but many pairs of them. So even a small movement can trigger both elements.

PIR Fresnel lens diagram
Image from D203S datasheet

PIR sensor circuit explanation and schematic using the LM324N op-amp

Outdoor PIR sensor board repair

The board can be powered from 5V to 12V however the value of the components are designed for 8V to 12V. It can work on 5V but the voltage division created by R17 and R18 must be changed.

Power consumption is very low: 1.5-2mA.

Outdoor PIR sensor board repair
Parts of solder mask were burned due to the power board short-circuit but only the op-amp was damaged on the main board

Outdoor PIR sensor board schematic
Outdoor PIR sensor board schematic (click to enlarge)

This op-amp architecture consists of three stages.

Stage 1

The first architectural stage amplifies the signal. It cancels the DC part of the signal and filters the high frequency noise that could lead to false detections.

PIR sensor schematic - stage 1
 
The high frequencies are filtered by C4 and R4 and the cut-off frequency is 2.2 Hz (fhigh1 = 1 / (2 x pi x R4 x C4)).
The second filter is used to reject the DC part of the signal. C1 and R3 perform a high pass filter that has a cut-off frequency of 0.34 Hz (flow1 = 1 / (2 x pi x R3 x C1)).
The stage gain is 221 (Gain = 1 + (R4 / R3)). The gain must be high enough to amplify the sensor signal above the noise level but not too high to drive the op-amp into saturation. The amplification is made around a common mode voltage set by the sensor and is not VCC / 2. 
 

Stage 2 - Setting PIR sensor sensitivity

 
Stage 2 is very similar to stage 1. It is used to filter and amplify the AC signal except that this time the signal is inverted.
PIR sensor schematic - stage 2

The signal Vout1 from stage 1 enters stage 2 through a 10k potentiometer that is used to set the sensitivity of the PIR sensor so it does not trigger every time a dog passes by.
Regarding the filtering function, the low and high cut-off frequencies respectively are 0.72 Hz (flow2 = 1 / (2 x π x R6 x C5)) and 4.8 Hz (fhigh2 = 1 / (2 x π x R10 x C6)). The flow2 also depends on the potentiometer position.
The gain of this stage is -100 (minus represents the inverted signal) (Gain2 = -R10/R6). This gain means that after stage 2 the signal between 0.7 Hz and 4.8 Hz will have been amplified 22100 times (87 dB).
In this stage the op-amp common mode voltage is set by the resistors R12, R9 and R8 to 37% of the power supply (Ratio = R8 / (R12 + R9 + R8)). The gain is intentionally set high so the signal is clipping looking more like a square wave now.

Stage 3 - Setting PIR sensor timeout and light threshold


PIR sensor schematic - stage 3

In this last stage 3 the signal from stage 2 is again inverted and filtered by the R11 and C7 with a 3.38 Hz cut-off frequency but this time the last two op-amp are used mostly as comparators. The non-inverting input is set by R12, R9 and R8 at 44% of VCC, one diode voltage drop above the ratio in stage 2.
The R16 potentiometer together with the LDR controls at what light intensity the sensor will trigger. The more light the lower the resistance of the LDR will be and if the pot is lower the base of Q1 will be pulled low turning off the transistor and R13 will let the diode D1 conducting the sensor signal to ground. If the potentiometer is on the other side even if the LDR would have 0 resistance the 150k of the pot would make the Q1 turn on then R13 will develop a voltage drop of VCC / 2 which is higher than the output voltage from stage 2 and the sensor will trigger. 
 
The last op-amp has the non-inverting input set at 83% of VCC. When no movement is detected Vout3 is always high and so the inverting pin of U1.4 is higher than (+) pin making the output to relay low. When Vout3 is low the negative plate of C8 is pulled to ground and so (-) pin is lower than (+) pin making the output high turning on the transistor that controls the power relay. Now even if Vout3 will be a very short pulse or the sensor will detect movement multiple times, the output will still remain high. If Vout 3 will keep going low to to motion detection the timeout will be reset but the relay will remain on. So when Vout3 remains high the capacitor C8 will be charged through R20 and the pot R19 that sets the timeout.
This method of using a capacitor was new to me and it took me a while to understand it. after the C8 charges to almost VCC the (-) pin will be higher than (+) and the output will go low turning off the relay. 
 
PIR sensor signal conditioning
PIR sensor signal conditioning ploted in LTspice

The schematic was simulated in LTspice. In the first plot there is Vpir that represents the 1mV signal from the sensor around 500mV offset voltage.
In the second plot Vout1 is the amplified signal after stage 1.
Vout2 is the output from stage 2. Here the signal is inverted, amplified to the maximum op-amp output and the offset voltage is set to 2.96 V at 8V power supply.
Vout3 is the output from stage 3 and is normally high. When motion is detected and signal Vout2 is higher than 3.55V then Vout3 will go low. Notice that it only uses the second half of the PIR signal pulse.
Finally Vrelay goes high when Vout3 is low. It will remain high even if Vout3 will change states again. If Vout3 remains stable at a high level then Vrelay will remain high depending on the RC constant set by C8, R20 and potentiometer R19. 
 
PIR sensor LTspice simulation
PIR sensor simulated in LTspice

In the next tutorial I will be presenting the capacitive power supply.

Download


Monday, September 28, 2020

Using USBTinyISP programmer with Atmel Studio 7 | AVR programming

In the last article I talked about Programming any AVR microcontrollers using WinAVR and USBTinyISP but recently I found that USBTinyISP can be easily used together with Microchip Studio.

For microcontrollers that are using UPDI interface for programming, I have another tutorial here.

Using USBTinyISP programmer with Atmel Studio

Using an external programmer in Microchip Studio 7

To add USBTiny to Microchip Studio go to Tools -> External Tools

Using an external programmer in Atmel Studio 7


Add USBTiny to Atmel Studio

Here pick a name for the programming tool, for example USBTinyISP_Debug or USBTinyISP_Release.

In the command field write avrdude.exe. For this to work you need to download avrdude and unzip it in a folder at an arbitrary location. Then add avrdude to the Windows system path otherwise instead of avrdude.exe you need to provide the full path to the executable. Here is how to add an application to the Windows path.

To check if avrdude is installed and added to Path, open a command prompt window, type avrdude and press enter. You should now see something like this:

avrdude cmd

In the arguments field specify what arguments will be sent to avrdude.exe

-c usbtiny -p m328p -U flash:w:$(ProjectDir)Debug\$(TargetName).hex:i

-c : specify programmer type. For USBTinyISP use usbtiny. To see a list of all supported programmers use avrdude -c abcd

-p : the avr device. For example ATmega328P is m328p. To see a full list of microcontrollers use avrdude -c usbtiny -p abcd

-U : indicates that we want to :w: write to flash memory the .hex file. :i is Intel hex file format. $(ProjectDir) and $(TargetName) is specific to Microchip Studio 7. In Atmel Studio 6 this can differ. Replace Debug with Release when working in Release mode.

Lastly, check the Use Output Window.

Now in the Tools menu you should see the tool above the External Tools.... You can add as many as you want. For example one for Debug and one for Release.

Atmel Studio external tools

When having more than one project in one solution (more than one microcontroller type), select the main.c file before uploading the code to ensure the proper hex file will be used.

That's it! Now after building the code (F7), you can upload it to the microcontroller using Tools -> and the newly created programming tool.

Friday, September 4, 2020

Program any AVR microcontroller using WinAVR and USBTinyISP - Getting started with AVR tutorial for beginners

Nowadays Arduino is the platform of choice for programming AVR microcontrollers and for good reasons. But there are times when you want to have full control over what is added to your code. 

For example Arduino is enabling by default Timer0 for use in millis function and other functions and includes some interrupt routines that perhaps your project is not using and so adding to the code size or perhaps those interrupts can interfere with your code.Two main alternatives are WinAVR and Atmel Studio. This tutorial covers WinAVR because it's simpler to use for a beginner.

What you will need:

  • ATmega328P (used in this tutorial as an example)
  • USBTinyISP programmer 
  • WinAVR software (more on this later)

What you can learn:

  • how to program an AVR microcontroller using an In-System Programmer such as USBTinyISP and WinAVR
  • some bitwise operations for handling the registers

There are two main ways to program a microcontroller:

- ISP (In System Programming) using SPI protocol and a ISP programmer
- With a bootloader using UART protocol and a USB to Serial programmer. Some microcontrollers come with a bootloader already pre-programmed on them.
 
This tutorial will cover the ISP programming way.

Programming software

There are many tools for programming an AVR microcontroller such as Atmel Studio, PlatformIO, Eclipse with an AVR plugin, etc but the simplest and light weight solution that I found is using WinAVR.

Programming hardware

Apart from development software there is also the need of a hardware programmer that the software uses to communicate with the microcontroller and upload the code to it. Searching online for 'avr programmer' reveals lots of options. The most popular I believe is the USBTinyISP and is very cheap. There is also Atmel-ICE from Atmel. A bit more expensive but it has the benefit of being able to debug and see in real time what happens inside the microcontroller.


WinAVR and USBTinyISP - Getting started with AVR


Getting started with WinAVR

WinAVR is a free suite of executable open source software development tools for the Atmel AVR series for Windows. WinAVR contains all the tools for developing on the AVR such as avr-gcc compiler, avrdude for uploading the code and avr-gdb for debugging.

To download WinAVR visit the project homepage at http://winavr.sourceforge.net and in the download section you will find the link https://sourceforge.net/projects/winavr/files and on that page click on download the latest version. Some users reported that the installation affected their system PATH. All I can say is that I have installed WinAVR on Windows 10 many times and didn't encounter any problem with it.

Updating WinAVR to the latest AVR-GCC and AVRDude

Unfortunately WinAVR hasn't been updated for a few years now and the avr-gcc compiler and avrdude is outdated but there is a way to update them. First download the AVR toolchain from Atmel visiting this link https://www.microchip.com/en-us/development-tools-tools-and-software/gcc-compilers-avr-and-arm.

Scrolling down you should find a link called 'AVR 8-bit Toolchain v3.62 – Windows' which is a zip file. Now in that zip file there should be a folder containing other folders such as 'avr, bin, doc, lib, etc...' Select all these folders and drag them where WinAVR is installed and replace the existing ones. By default WinAVR is installed on C:\WinAVR-20100110.

Now for AVRDude follow this link http://download.savannah.gnu.org/releases/avrdude and download 'avrdude-6.3-mingw32.zip' or newer version then extract the two files from the AVRDude zip file to C:\WinAVR-20100110\bin.

That's it.


After installation search on windows start for WinAVR and you should see Programmer's Notepad app.

Programmers Notepad

Programmer's Notepad does everything for you. Is calling the make utility, which executes your makefile, which in turn calls the compiler, linker, and other utilities used to build your software. You just need to write the code and click Make then Program. 
 

Starting first WinAVR project

Inside Programmer's Notepad click File -> New -> Project. Choose a name for the project then navigate to a folder where you want to put the project files. I named mine Blink LED.

Programmer's Notepad make project folder

Now you should see the project in the left side panel. Here you can also make/rename a project group.
 
Programmers Notepad adding project files
 
Now to add a file first add some code and save the file as main.c in the folder where you saved the project file. The name must be main and the extension can be .c for C or .cpp for C++ languages. Bellow is a code template that I made for my future projects.



/*************************************************************
	INCLUDES
**************************************************************/
#include <avr io.h>
#include <util delay.h>
#include <avr interrupt.h>


/*************************************************************
	DEFINES
**************************************************************/



/*************************************************************
	GLOBAL VARIABLES
**************************************************************/



/*************************************************************
	FUNCTION PROTOTYPES
**************************************************************/
 
 
 
/*************************************************************
	MAIN FUNCTION
**************************************************************/
int main(void){
	
	
	while(1){
	

		}
	}
}

/*************************************************************
	FUNCTIONS
**************************************************************/



/*************************************************************
	ISR Handlers
**************************************************************/

By right clicking on the project name use Add Files to add the main.c file to the project.
To display the line numbers go to View -> Line Numbers.

Make file 

Now it is time to setup the make file. This file tells WinAVR what microcontroller do we use, what CPU frequency, what programmer, on what port, etc. For this, search like before for WinAVR but this time open MFile [WinAVR]. Then select Makefile -> MCU type -> ATmega -> atmega328p

make file select mcu type

From Port select usb. Then on the bottom click Enable Editing of Makefile. Now from Programmer choose your programmer. If you use USBTinyISP and it doesn't appear in the list simply pick a random one and then change it with usbtiny.
The last setting is the CPU frequency. Scroll up in the file until you see F_CPU and put your CPU frequency. For ATmega328 use 8000000 which means 8MHz - 8 with 6 zeros or 16000000 if you have a 16MHz crystal.
 
 
Makefile F_CPU frequency

 
Finally save the file as Makefile (without any extension) inside the project folder. Later it can be open and edited using Programmers Notepad.
The following section talks about configuring a port, bitwise and binary operations. If you are already familiar with this, skip to this section uploading the code to the microcontroller.

Learning AVR programming by blinking a LED using ATmega328P


On page 12 you can find the pinout. Say you want to connect the LED to pin 28 of the 28 PDIP package. Near the pin number 28, PC5 indicates that this pin belongs to port C and has the port pin number 5. By looking at the other pins we notice that there are 3 ports: B, C and D each one having 8 pins (0 to 7) except port C that has only from 0 to 6. Inside the parenthesis are shown what other functions the pin can have, like ADC for example (Analog to Digital Converter).

To setup the pins we use the defines

#define LED_DDR			DDRC
#define LED_PORT		PORTC
#define LED_PIN			PC5
After #define any name can be used. Then press TAB a few times to make the lines look nice and readable and then write the values.

DDRx stands for Data Direction Register and selects the direction of the pin - input or output. You want it to be an output when driving an LED or transistor and an input when reading a button press. The x after DDR is the port and in our case is C.

*A register in an 8 bit microcontroller like this one is just a set of 8 bits that holds a number and the microcontroller uses the bit values to configures itself.
 

Configuring ATmega328 port pins - this can replace Arduino digitalWrite to increase the speed

Configuring a pin as a digital output

DDRC |= 1 << PC5

Let's analyze the above line. Somewhere in the avr_io.h included file, PC5 is associated with the value 5 and so PC5 will be replaced with 5. So is the case with the defines. When we write 
 
LED_DDR |= 1 << LED_PIN 
 
the pre-processor will replace LED_DDR with DDRC and LED_PIN with PC5.
<< is called the left shift and makes part of the bitwise operations. 1 << 5 is saying move the binary representation of 1, 5 times to the left.
 
In binary 1 is 0b00000001 and after it has been shifted 5 times to the left is 0b00100000
We can also write it like this:

DDRC |= 0b00100000

The 8 bits represents our DDRC register and each bit is the pin. 
Pin 0 is 0b00000001
Pin 1 is 0b00000010
Pin 2 is 0b00000100
Pin 3 is 0b00001000
Pin 4 is 0b00010000
Pin 5 is 0b00100000
Pin 6 is 0b01000000
Pin 7 is 0b10000000
By putting 1 on that bit position we set the DDR (direction) of the pin to be an output. Leaving it or setting it to 0 will make it as an input.
So what is with the | symbol? It is called a bitwise or operator.

0b00100000 | 0b00000010 = 0b00100010

because as the name suggests 
0 or 1 = 1
1 or 1 = 1
0 or 0 = 0
In a bitwise operation two bytes are compared against each other bit by bit. Notice the colors: red (bit 0) is compared to the other red, blue (bit 1), green (bit 2) and so on.
The purpose of the or | operator is to change our desired pin but leave the others the same as before.
If we have some other pin controlling a motor for example PC1 and we change pin 5 (PC5)

DDRC before is 0b00000010 - PC1 is 1 (output)

DDRC |= 1 << PC5

DDRC after is 0b00100010
Notice that the use of the or operator, left the PC1 bit unchanged.

To practice or to solve bitwise operations there is this nice website http://bitwisecmd.com/
The browser's search bar can also be used without pressing enter.
 

Setting a digital output pin HIGH

After setting the pin as an output, let's make it HIGH to drive the LED.
PORTC |= 1 << PC5
This leaves the other pins unchanged. To make only this pin high and the rest low (0) we could write:
PORTC = 1 << PC5

Setting a digital output pin LOW

PORTC &= ~(1 << PC5)
Now the pin is connected to ground.

Configuring a pin as a digital input

As before but instead of 1 we write 0 to the specific pin
 
DDRC &=  ~(1 << PC5)
 
~ is the not operator so 0b00100000 becomes 0b11011111

DDRC before is 0b00100000

DDRC &= 0b11011111 (after not operation)

DDRC after is 0b00000000

because with & bitwise operator both values must be 1
1 and 1 is 1
1 and 0 is 0
0 and 1 is 0

When a pin is set as an input and we write this

PORTC |= 1 << PC5

then the internal pull-up resistor is activated. Now we could add a push button between the pin and ground and when the button is pressed the pin will be pulled to ground and when the button is not pressed the pin will be high due to the pull-up resistor. This is how we can read if a button is pressed.

if(PINC & (1 << PIN5))

PINC represents all the pins of port C and by some bitwise operations we check only if pin 5 in 1 or 0.

Toggling a pin

DDRC ^= 1 << PC5
 
If the pin is low (0) will be made high (1) and vice versa.
 
In summary to set a bit in a register to 1 use

DDRC |= 1 << PC5

and to set a bit to 0 use

DDRC &= ~(1 << PC5)

Another way is to use the _BV() macro function that means bit value. So the lines above can be replaced by

DDRC |= _BV(PC5)
DDRC &= ~_BV(PC5)
Now finally let's blink that LED with the following code:
 
int main(void){
	// Set the pin as output
	LED_DDR |= 1<<LED_PIN;
	
	// Set the pin HIGH
	LED_PORT |= 1<<LED_PIN;
	
	while(1){
		// Toggle the pin
		LED_PORT ^= 1 << LED_PIN;
		
		// Wait 500 milliseconds
		_delay_ms(500);
	}
}

To compile the code click Tools -> Make All. 
 
If the WinAVR wasn't updated using the toolchain from Atmel then the following error message should appear:
'fatal error: opening dependency file .dep/main.o.d: no such file or directory'

To fix it visit this forum https://www.avrfreaks.net/forum/windows-81-compilation-error?page=all and you can find a link to a .dll file. Copy this file in the WinAVR installation folder -> utils -> bin and replace the existing file. Now it should compile without errors.

To upload the code to the microcontroller click Tools -> Program. But first lets see how to connect the microcontroller to the programmer.

Connecting USBTinyISP to ATmega328P AVR

USBTinyISP header pinout

USBTinyISP has 2 headers and each one can be used but I prefer the small one. In my case the pin headers are mirrored so you should check with a multimeter first with the power of. 

The corresponding pins on the microcontroller can be found in the datasheet.

MOSI - master out, slave in
MISO - master in, slave out
SCK - system clock
RST - reset

This protocol of communication is called SPI (Serial Peripheral Interface) .

A 10k resistor is needed from VCC to the reset pin of the microcontroller to keep it high. If the reset pin is pulled to ground then the microcontroller will be kept in reset  mode.

On the USBTinyISP there is a yellow jumper. If removed the programmer will not provide 5V power to the microcontroller (MCU) and you need to provide power from other source but be sure to have a common ground. This is useful when you want to power the micro with 3.3V for example.

Installing drivers for USBTinyISP

The drivers for USBTinyISP can be found on Adafruit website here https://learn.adafruit.com/usbtinyisp/drivers. The install includes drivers for some other programmers. Check the box that has USBtinyISP at the end.

USBTinyISP driver instal

Now if everything is connected properly you should be able to program the micro using Tools - > Program.

Having a LED blink using the delay function is useful for checking if the F_CPU is set correctly. If not the LED will blink either to slow or too fast. ATmega328 comes from the factory with their cpu clock  divided by 8. In the datasheet you will see the term prescaler. The CPU clock can be divided with a prescaler of 1 (no prescaler), divided by 8, 16... The micro has an internal RC oscillator at 8MHz and has a fuse set to divide this by 8 so the actual speed is 1MHz. You could either change the speed in the makefile to 1000000 or change the fuse and set the CPU divider to 1 and keep the 8MHz specified in the makefile.

There is also the option of connecting a 16MHz crystal oscillator to the microcontroller and get a more precise clock. For most applications the internal RC oscillator is just fine but don't build a clock with that.

AVR Fuses

There are 3 bytes stored in a special area of flash memory called fuse bits. These are Low, High and Extended fuse bytes. Setting some of this bits wrong can make the micro unusable and will be needed a special high voltage programmer to make it work again. For this reason there are fuse calculators and as long as you are careful what options you select it will be fine.

Here is a good online tool for fuse calculation https://www.engbedded.com/fusecalc Be sure to select the exact part. Default fuse values for ATmega328P look like this
 
ATmega328P default fuse values fuse calculator

Clock Selection

 
With the first selection menu the source and type for the CPU clock can be selected. The Clock Startup can be either of the following: 14CK + 0 ms, 14CK + 4 ms, 14CK + 65 ms. 
The Startup Time is just how long it take for the clock source to stabilize from when power is first applied. Always go with the longest setting 14CK + 65ms unless you know for a fact your clock source needs less time and 65ms is too long to wait. 
 

Clock Output

 
Checking Clock output on PORTB0 will output a square wave with the clock frequency at pin PB0 and is useful when you want to debug the clock rate or to drive other chips. 
 

Clock Divide

 
This divides the clock by 8 and it's the default factory value. You may want to uncheck this to get the full speed. Although on battery powered devices the slower the clock the less power is consumed. 
 

Reset Disable 

 
Warning. This fuse turns the reset pin into a normal pin and after doing this the chip cannot be programmed anymore. 
 

Brown-out Detect (BOD)

 
When the voltage will drop beneath the specified BOD voltage the micro will turn off until the voltage returns to normal. This must be tuned on if the EEPROM memory is used to prevent write errors. The chip has a lower voltage limit at which it can work reliably and beneath that voltage the chip can behave erratically, erasing or overwriting the RAM and EEPROM. 
 

Preserve EEPROM

 
If this is checked the EEPROM will not be erased during programming. Here usually settings are kept so is a good idea to check this to preserve the settings

To calculate the fuses click Apply feature settings. I don't recommend using the Manual fuse bits configuration unless you know what you are doing. 
 

Burning the fuses 

To program the fuses open a command prompt window and paste
avrdude -c usbtiny -p atmega328p -U lfuse:w:<0xHH>:m
avrdude -c usbtiny -p atmega328p -U hfuse:w:<0xHH>:m
avrdude -c usbtiny -p atmega328p -U efuse:w:<0xHH>:m

Replace 0xHH with the values from the fuse calculator.

 

Further reading

Thursday, June 25, 2020

How a POV propeller display works

In part 1 on How to make a POV display we talked about the hardware and schematic. In this part 2 we will dive in how the code works and why the POV (Persistence Of Vision) display is so cool and fun to play with.

How a POV display works

Looking at the example in the above figure we want to display the letter "H" starting from column 5.

First we need to measure the time it takes for the PC fan to make a full rotation. For this we will use a Hall effect sensor and a magnet.When the Hall effect sensor on the board passes above the magnet an interrupt will be triggered that will start Timer 0. Next time the display makes a full rotation, the magnet will trigger the interrupt again and Timer 0 holds now the time it takes to make a full rotation (44ms in this example).

Say a PC fan has 1360 RPM divided by 60 = 22.66 rotations per second.

1 / 22.66 = 0.044 seconds or 44 milliseconds for one rotation.

To find out after how much time the next column can be displayed, the time it takes for a full rotation is divided by the number of columns (60 in this example).

time_per_column = one_rotation_time / number_of_columns

time_per_column = 44ms / 240 = 183 microseconds per column for 240 columns

time_per_column = 44ms / 120 = 366 microseconds per column for 120 columns

time_per_column = 44ms / 60 = 733 microseconds per column for 60 columns

Notice how increasing the number of columns decreases the time available for one column. More columns gives a better resolution but the microcontroller must be fast enough to finish the code in that time. Number of columns can be changed in software.

Timer 2 is set to trigger interrupts every 733 microseconds. On each interrupt the 16 leds are updated based on what is to be displayed on the active column. The array povDisplayData[] is used for this. Looking at the above figure again, if the active column is 4, all leds would be off because povDisplayData[4] would be all 0's. On the next column 5 all the leds are on to display the first part of the "H" character. On columns 6 and 7 only two leds are on. What leds are on depends on how you want to draw the characters.

Turning the leds on and off with as less code as possible is not as easy as it should be. If all leds would be on a single port this would be achieved simply like this:

PORT0 = povDisplayData[active_column];

But when the leds are located on multiple ports the code becomes a bit tricky. I have used some bitwise operations and bitmasks for this. Switch case takes 10 times longer and if/else conditions even longer.

Connecting the app to POV display device

On first use the device will create an wireless access point with SSID: POV Display and KEY: ESP826608. With a wireless device connect to this access point then using the Android app access Router Credentials page under the menu. Here you need to pass the credentials of your router for the ESP8266 to connect to the router. This step is only necessary once and after this the credentials are saved inside ESP8266 flash memory.

* a flashing blue light indicates the device is waiting for router credentials

Download

This zip file contains main code and dependency libraries:

  • POV Display - EFM8BB31F32_main.c
  • uart.h
  • ESP8266.h
  • Flash.h
  • globals.h
  • delay.h

If you want to know how to program an EFM8 microcontroller visit this link https://www.programming-electronics-diy.xyz/2018/03/cheap-and-powerful-50-cents-microcontroller.html

However you don't need Simplicity Studio for that. For uploading the code I have also included:

  • POV Display - EFM8BB31F32.efm8

This is the compiled file that needs to be uploaded on the microcontroller using an executable provided by the Silicon Labs

  • efm8load.exe

And a bat file for uploading on COM3. This can be edited.

  • 2 - Bootload Record Downloader.bat

The bat file contains:

@echo Downloading bootload record using COM3
@efm8load.exe -p COM3 -t "POV Display - EFM8BB31F32.efm8"
@pause


Tuesday, June 23, 2020

Build a wireless energy POV display propeller clock with Android app

A POV display aka propeller display/clock is a display that uses the Persistence Of Vision (POV). By turning just a few LEDs on and off at a specific position around a circle, a full display that would normally require hundreds of LEDs can be created. This illusion of a still image is due to the eye's slow refresh rate. Without this perk we would see moving pictures instead of videos and obnoxious LED lights caused by PWM in daily life.

If you think about it is is an interesting and fun project to experiment with. This will be more obvious in part 2 where we will discuss the code and the basic principles. It can be used as a clock or display text from internet in real-time or for image display.

Here is a video with the POV display controlled by an Android app. Needless to say it looks better in person. The display can be styled by different LED colors.


POV display construction overview

POV display construction 01

Part list

Power Transmitter board
  • 1 x 92mm PC fan
  • 4 x 4mm screws with nuts for fixing the board on the fan
  • 1 x ATtiny13A microcontroller for controlling the main TX coil
  • 1 x female (receptacle) header 1 row 6 pins (2.54 mm spacing) for programming the microcontroller
  • 1 x DC jack. A panel mount one connected with wires is better than the one I use
  • 1 x 12V to 5V linear voltage regulator
  • 1 x 0,1uF ceramic capacitor 2,54mm (C4)
  • 1 x 0,33uF ceramic 5mm (C5)
  • 1 x 470uF/16V electrolytic capacitor 5mm (C1)
  • 1 x 33nF film capacitor (important) (C2)
  • 1 x IRFZ44N N-Mosfet or equivalent (Q4)
  • 2 x BC337 NPN transistors (Q1 and Q3)
  • 1 x BC327 PNP transistor (Q2)
  • 1 x 10k resistor (R5)
  • 2 x 47k (R2 and R4)
  • 2 x 2.2k (R1 and R3)
  • 1 x 100mm x 110mm double sided copper clad board
All resistors are normal size low power through hole with ~8 mm distance between pins.

Main (top) board
  • 1 x EFM8BB31F32I-B-QFP32 microcontroller
  • 1 x USB to Serial converter (UART) for programming the MCU
  • 1 x ESP8266-01 module
  • 1 x female header for ESP module 2 rows 4 pins 2.54mm. It can be made from 2 headers with 4 pins.
  • 1 x female header 1 row 6 pins 2.54mm for programming the main microcontroller
  • 16 x 0805 SMD LEDs with a desired color (yellow or white works better for text)
  • 1 x red, 1 x green, 1 x blue 0805 SMD LEDs
  • 1 x AH372-P-B Hall sensor (from Farnell) or equivalent
  • 1 x AMS1117-3.3V voltage regulator
  • 1 x 12V low power zener diode
  • 1 x 33nF film capacitor (important)
  • 1 x SK24A Schottky diode or equivalent
  • 2 x 3mm x 24mm screws with 3 nuts for each screw
  • 1 x 160mm x 50mm double sided copper clad board
  • 1 x 80mm x 80 mm single or double copper clad board for making the circular receiver coil board. This can be integrated in the main board since a manufacturer can easily cut any board shape.
  • other generic resistors and capacitors (see the schematic). Most are 0805 surface mount which is preferred for a spinning board.
The PCBs are not made for factory manufacturing because they are home made using the UV method. If you plan to order them from a manufacturer then carefully examine the gerber files that you will generate if the traces and holes are correct.


The brain of the display is EFM8BB31F32I-B-QFP32 microcontroller set to run at 49MHz and it uses ESP8266-01 module to connect to internet and to local LAN to communicate with an Android app. Under the ESP module is a piezo diaphragm for producing alarm sounds.
On the left side there are two screws with nuts acting as a counterweight. This must be tweaked until the vibration is reduced to the minimum. Is not very elegant but I don't know of any other solution for now.
Between the two screws there are 3 LEDs red, green, blue used for the rim color and then two sets of 16 LEDs. One yellow with 16 resistors and one set blue with no resistors. After I tested the board I've noticed it was not a good idea since the LEDs need to be perpendicular to the center otherwise the display image will look skewed. In the schematic this is corrected.

The board is powered through the two screws in the middle. The two nuts on top are used to press the board on other two nuts beneath the board that are used to conduct power to the board. Under these second pair of nuts is a circular board that captures the magnetic fields and it sits on two other nuts for electrical connection and also for height adjustment.

POV display construction 02

POV display construction 03

POV display construction 04

POV display construction 05

POV display construction 06
Inductive wireless power receiver

Inductive wireless power transmitter
Inductive wireless power transmitter

POV display construction 08

The whole assemble is supported on two screws used also for powering the top board. Pulling out the fan is achieved by removing a small ring connected to the shaft on the other side where you normally put the oil. Removing the ring is a bit tricky. Try using some curved tweezers.

POV display construction 09

POV display construction 10

POV display construction 11

Warning: be sure nothing is loose on the board. If something breaks from the board at full speed it could hit someone with 40 Km/h speed. For safety wear glasses during testing and keep the device in an enclosure after it is ready.


Inductive wireless power transmitter

Inductive wireless power transmitter

The 92mm PC fan used here has three main roles: to support the display inside a case, to spin the top board and for cooling.

The board is powered with 12V through a DC jack (panel mounted ideally) and an external power switch connected using wires. The fan wires are connected to the board through another switch so the board doesn't spin during programming of the top board microcontroller. U2 can be a generic 5V voltage regulator for powering the U1 IC which is an ATtiny13A microcontroller that is used to produce a 267 KHz square wave. A more elegant solution would be the use of a ring oscillator using 3 Schmitt-triggered inverter gates, resistors and capacitors.
Q1, Q2, and Q3 transistors form a gate driver for the power mosfet Q4. L1 is a printed circuit board  inductor with 7 turns, 2.5 mm trace width, 1.3 mm clearance and together with C2 capacitor forms an LC tank oscillator. C2 must be of a plastic film type.

Inductive wireless transmitter bottom view

I did measure the efficiency and output power but I forgot to take notes and I can't redo it now in circuit. All I can remember is that the input power is 12V / 0.5A and that the efficiency is not very good. The mosfet and the capacitor gets a bit hot without the board spinning. Maybe with a better circuit that would measures the mosfet drain voltage and adjust the oscillating frequency depending on the load the efficiency would be better.

Inductive wireless power receiver


The receiver coil is the same as the transmitter one and it could be integrated in the main board.

POV display main board

POV display main board

Starting from the left power is coming through the two screws that are connected to the printed inductor board beneath and together with C6 film capacitor forms an LC tank oscillator. D1 is a Schottky diode to rectify the AC voltage. C7 is a bulk capacitor and perhaps could be lower in value.
D5 is a 12V Zener diode to cap the input voltage. Unloaded voltage from the LC oscillator is around 90V but will drop quickly under even a small load so the Zener diode will not see much current.
Then a 3.3V voltage regulator provides voltage to the LEDs and microcontroller which is a 3.3V type.

C1 is a decoupling cap for the micro, R2 is a pull-up for the reset pin and C3 is used by the DTR for programming.

There is also a piezo diaphragm connected directly to the high voltage side but could be removed together with it's circuitry if not needed.

Red, green and blue LEDs are for the display's contour and could be used in any combination.
16 yellow LEDs are connected directly to the microcontroller each one having a 75 ohm resistor. The color of the leds could be any color you like but since the voltage drop is dependent of the led color the resistor value will vary.
For this 0805 type of leds  I have measured the following voltage drops:
  • Red: 2V (120 ohm, 10mA)
  • Green: 2.1V  (120 ohm, 10mA)
  • Blue: 3.3V (with no resistor 10.4mA)
Keep in mind that the maximum current the microcontroller can sink is 200mA. It would be preferable to drive the leds with 20mA for maximum brightness especially considering they are not on all the time, but the current for one led multiplied by (16 leds + 1 led for rim color) must not exceed 200mA.

IC1 is an AH372 bipolar latch hall effect sensor and it triggers an interrupt each time the sensor passes on top of a magnet. To align the magnet with the right polarity you could toggle a led inside the ISR then move the board by hand counter-clockwise until the led toggles on each rotation. The sensor is bent with the front side facing the board and can sense the magnetic field through the PCB. A big and strong magnet works better than a small one.
If you notice any jitter in the image put the magnet closer or use a stronger magnet. I've noticed that when the magnet is farther away at full speed many times doesn't trigger the interrupt thus causing jitter.

J1 is used for programming the micro. JP1 has two jumpers. When they are placed towards the center of the board the microcontroller's UART is connected to the ESP. When is on the other side the micro is connected to the USB to serial converter for programming. C2D pin of the micro must be connected to GND with a jumper wire to enter into programming mode then the software can be uploaded. In case the programming fails pull out the ESP first.

Possible Improvements

  • Maybe mounting the leds vertically to remove the vertical gaps without reducing the screen height
  • Placing the leds very close to each other vertically for higher pixel density but that would decrease the screen height. Doubling the number of leds to 32 will fix that but then extra circuitry is required such as shift registers since there are not enough pins on the micro
  • Using RGB leds. Maybe in version 2
  • Better circuitry for the inductive wireless power to increase it's efficiency

In the next part I will be talking about the code and basic principles of a POV display.


If you have comments or suggestions leave them in the comments below.

Download:

This zip file contains:
  • schematic and PCB layout made in DipTrace (free version) for all 3 boards
  • 92mm fan footprint for drilling holes in the enclosure
  • html and javascript file character generator. Although all A-Z, a-z and 0-9 characters are already in the code file, you could use this to modify them.

Android app .apk format version 1.0


Install from unknown sources must be enabled since is not installed from Google Store. Uploading apps on Google Store cost a few dollars and for now it will only be available for download here.