Saturday, 14 March 2009

master with oled

First of all still very proud on this nice design made by my friend ! It was a good development kit to learn all things on the AVR. So the master was ment to be a target to change some slave parameters using my own one wire protocol. The purpose was to us the OLED display to give in the values. My one wire code was finished first and it coudn't test time being. But as soon as I implemented the slave state machine I finally could see the results. At first it was a bit tuning but after all that the concept worked very quickly without any major problems. On the picture you can see the master standing right next to the OLED display. At the right of the master you can see my 2 slaves. Again for any code snippets on the one wire refer to my code corner because this blog is not the place to format code in.
The second picture shows the OLED graphics. Programming it was fairly easy to do. The first step you need to do is transfer the init code out of the datasheet into your C code. Next the start of the init snippet:

// init the ports

DDRC = 0b11111111;
PORTC = 0b11111111;
DDRB = 0b00011111;
PORTB = 0b11111111;
DDRA = 0b11100000;
PORTA = 0b11111111;

PORTB = 0b11111110; // reset the oled
_delay_ms(1); // spec says wait a bit here
PORTB |=0b00000001; // unreset the oled

// general init commands out of spec
// TODO must be documented in detail

write_oled_command(0x02);
write_oled_data(0x01);
....

I wrote some helper functions for writing the command and data bytes to improve the readability of the code. When you succeed in the init the OLED will give you a screen full of noise pixels but at least you sure it's working. The purpose of the OLED screen was to give the user the ability to do some general parameter set up for the slaves. So I started to think on a possible interface for the little 160x128 pixeels display. The idea came up to use icons as a menu system. Of course the icons we all know on our computers today haven't the right format for the display. No problem for me as I can write some simple python scripts. I wrote a script that converts a extension ICO file to some raw binary data for the display. Code can be viewed at my code corner. With this script I can transfer 16x16, 32x32 or even 48x48 size icon files. The icons must be in 24 bit RGB although I have only 18 bits the last 2 bits are simply not taken into account. I only take the RGB data without the transparency information which I don't need. You can see the result of a converted 32x32 icon on the picture. This format suits very well and I can get 5 icons on one row and I have 4 rows so 20 icons in total. My intention was to draw a red rectangle over the icon to notice the user it's selected when using the 5 function mini joystick which is positioned right under the display. The only limitation I had was the amount of program flash to put in the raw icon byte arrays. I used the special gcc #pragma to locate the array into flash like this:

const uint8_t PROGMEM icon[3072] = {
0x3e,0x9a,0xde,
0x99,0x00,0x00,
0x99,0x00,0x00,
0x99,0x00,0x00,
0x99,0x00,0x00,
......

So as you can see a 32x32 icon takes already 3072 bytes in flash. But still possible to play with 15-18 icons depending on the program code size. To build a rich user interface this is definitly to less. I didn't wrote any code for the mini joystick as I was busy on the move from AVR to CORTEX. So that will be postponed to my new master based on the CORTEX core. Also here the STM32 offers a wide variety on targets that can have up to 512k on program flash. Indeed with 512k bytes you build a much nicer user interface for this oled display than with the AVR. Playing around with 80 different icons is no problem at all. That's basically it what I needed to tell you on my AVR experience.

I linked the TRIOS blog project on this target but in fact it's not quit correct anymore as I 'd changed my target now to ARM CORTEX. I decided to continue in that blog rather than here because all I will write next will be very closely linked to the CORTEX. So please for follow up on this reffer to:

http://guyvo-cortex.blogspot.com/

As the concept gets more and more to it's final stage now, it becomes time to build the PCBs. Due to the fact this has nothing todo directly with software I will open a brand new blog for it as soon as the first layouts starting to get some shape.

http://guyvo-dimmers.blogspot.com/

Enjoy !

change of processor ?

Like I told you in the previous blog I still had to find a suitable processor to implement the FIR filter. This means basically having enough performance to do a FIR calculation within the sample rate. I knew that a DSP was not reachable so I had to continue looking for a reasonable alternative with respect to speed , price and software availability. One day my eye felt on the cortex STM32. A friend of mine was already experimenting this target and he told me that the cortex was indeed a great core. I did some additional searches on software (IDE, libraries ,..) and it seemed that this was very promising. I saw that the RIDE7 environment (raisonance) was totally free of charge. It works with a gcc distribution of codesourcery and can work under windows. Meanwhile I searched also for a starter kit and found exactly what I was looking for at www.olimex.com. Cherry on the cake was that the ST people also wrote a DSP extension library for the cortex. That seemed very promising to me. I ordered the development board already.

In my previous blog I also spoke a bit on my FIR simulation. If you are interessed in the python code you can get it via my publishing corner:

http://sites.google.com/site/guyvo67/


At the picture on the left you can see the main sinus with the CAB signal on. This was the first thing I did reproducing the signal that caused the flickering as realistic as possible. The drawing was done with a simulated frequency of 40khz. Now I had my input signal it was time to integrate the FIR calculation. I experimented first with the java applet to get an idea on bandwidth and amount of taps. Than I copied the tap values into my python simulation. The calculation for FIR is rather simple. They exist out of set of MACs.(multiply/addition accumulations) So it was pretty easy in python to make the MACs. On the second picture you can see the result taken from a test with 20000 points and weak 6 order tap. In blue you can see the filtered signal which was already pretty nice for a start. I noticed that with increasing the taps you also increase the phase shift. But this shift is constant over the all signal. This can be considered as great advantage as I had to trigger the zero point most accurately. This effect can be seen on the third picture.

At that point my brand new development board was arrived. you can take a look at it on my cortex dedicated blog:

http://guyvo-cortex.blogspot.com/

My first thing I did with the cortex was as you could guess dive into the DSP function library. I did some quick tests using the RIDE simulator on performance. That moment made me very happy because it was only 7µs to calculate a 32 tapes FIR filter !!! At that particular time I was 100% sure to change my target from AVR to the CORTEX STM32 running on 72MHz. If you are curiuos on the real tests and how I did it you must switch to my cortex blog. So because the AVR story is almost ended here I will finish writing a next short blog on the master with OLED display.

Sunday, 8 March 2009

dimmer results

(click on the picture to view in full size)
I had to do a little bit of tuning at first with respect to the timings but at the end I had a very good working dimmer. The only pain in the ass was the CAB signal send by the net distributor. This signal comes when traffic lights or day/night tariff needs to switch on/off. In the case of Belgium and in my area this is 1347Hz. Although this is only 5% of the nominal 230V supply this causes heavy flickering. This was definitely something I didn't want in my final design. On the picture at the left you can see the error of the opto coupler. I noticed that this can be as far as -400µs + 400µs. Of course this phenomenon lets it
self see without a doubt. So I had to search for a solution. I first thought about simply putting an analogue filter network but this cause to many phase shifts and is difficult to get stable if you must go to 10 order and more. Yes this thing kept me going for about 3 mounts believe me. Second approach was putting a highly optimized crystal ( 0.3 ppm ) I tried to synch not on the zero cross but only on that crystal. Again this was a no go. The frequency of the net can vary between 49.8 - 50.2 in a few 10 seconds depending on area. So my crystal was far to secure to do the synchronisation. The lamp faded away and came back on again in about 10 to 20 seconds. I did a lot of try outs in software with partial synchronisation but still the flickering was there. After all that bad news, I started to read documents that told something about this topic. Lots of them. I even contacted a professor at the university of Idaho. He sent me a paper on optimizing a zero crossing. It was based on a PLL approach. I study the document but it had to many questions to even thinking on implementing it. But it gave me some new relief and hope. In between my searches I saw a lot about DSP processors. These things are very powerful especially for digital filtering. One disadvantage : those things are very expensive to buy in the form of a development kit. Meanwhile I had my focus now on trying to digitally filter the 1347Hz. Coincidently I just started to learn the python language and I saw in one of the libraries the plot.py. I started to experiment and wrote a program based on my theoretical point of view. I soon found out that indeed it could be done using a digital FIR ( Finite impulse response ). On the third picture you can see my simulation in plot python. So i artificiality generated the sin wave of 50hz + 1347HZ as the source signal. I calculated the factors using a helper program as java applet and can be found :

http://www.dsptutor.freeuk.com/FIRFilterDesign/FIRFilterDesign.html

I did a lot of testing with several number of taps and sampling rates. But at least I was very sure that this must be feasible. There was just one question to answer : which processor can handle these calculation and is also cheap enough to afford ?

Be my guest in my next blog that will be fully dedicated on this topic.

sequel 3 to slave concepts

4. handling one wire protocol with master

First of all I post my document link again where you can find the complete analyse and code:

http://sites.google.com/site/guyvo67/

(LOWBP.PDF)

I was lucky to have my analyse on paper first to implement the state diagram. It was very helpful. To fully test the protocol I had to program the master as well. But I come back on that later on. I used the ICP ( input capturing ) on the AVR to measure my timings. Below you can see how the timer needs to be setup:

/*! ********************************************
SetTimerOneWire
Preparing TIMER 0 16 bit for one wire capture
no prescale --> counting unit = 1\F_CPU

minimum unit: 12.8 MHz 78ns

maximum units: 12.8 MHz 5,1ms

@note
16 bit writing first high than low value
16 bit reading first low than high value

************************************************/
void SetTimerOneWire (void)
{
/// TIMER 0 enable ICR mode in 16 bit
TCCR0A = _BV(TCW0) | _BV(ICEN0);

/// TIMER 0 prescale value no prescale
TCCR0B = _BV(CS00);

/// TIMER 0 interrupt mask ICR
TIMSK |= _BV(TICIE0);

/// TIMER 0 starting point
TCNT0H = 0x00;
TCNT0L = 0x00;
}

So the timer is set up to handle measurements between 78ns and 5,1ms. As I put my one wire timings between 10µs-1ms this is more than precise enough to do the job. The last code snippet I want to show you is that of the interrupt itself. It works very closely together with the state machine implementation but again please refer to the document to view to full master/salve implementation. In the interrupt routine we handle the input capture measurements depending on the edges. We evaluate the measured values with our defined timing constants known by slave as well as master. Depending on the value I assign a global value to an enumeration that will be later used by the state machine to make appropriate decisions. Also here very straightforward code:

ISR(TIMER0_CAPT_vect)
{
if ( bit_is_clear(PINA, PA4) )
{
TRIGPOSEDGE;
RESTARTTIM0;
onewirepulse = INTIMING;
}
else
{
TRIGNEGEDGE;
ICRVALUE(icp);
if ( icp < onewidth )
{
onewirepulse = ONEPULSE;
}
else if (icp < zerowidth )
{
onewirepulse = ZEROPULSE;
}
else if (icp < resetwidth )
{
onewirepulse = RESETPULSE;
}
else
{
onewirepulse = ERRORPULSE;
}
capinterrupt = SIGNALED;
}
}

To be honest this was the most difficult thing to program with respect to the slave concept. But I managed to write it and test it and it worked ! I will dive a little deeper on those tests when I write something about the master. The one wire is actually optional for this design but it gives a nice added value.

My next blog will cover the overall results of this dimmer design.

sequel 2 to slave concepts

3.handling button actions:

To capture a button state change you have two option or you take a poll approach or you do it by interrupt. As I'm an interrupt lover I took the second option. On my AVR development board the EXT0 pin was used for connecting a button or switch. If you use the EXT0 you have the possibility to trigger on positive or negative edge or both. In my case I triggered the positive edge. This depends a bit on how you connect your button pulled up or not. The code of course to do that is more than simple:

ISR(INT0_vect)
{
interrupt0=SIGNALED;
}

The
interrupt0 flag I used is treated in the idle main loop. ( so a little polling anyway ) It's very important that you test the signal on any glitches or faults. The best thing you can do is bringing a delay loop in action as soon as you triggered a state change. If the signal is still stable and correct after the delay you can go ahead and treat the change as you wish. But let me copy in my code snippet here to make things clear it's sufficient self describing as you will notice reading it. Sorry for the layout , the indents are not correctly put, but it has only two levels and is not of much importance for the concept. ( HTML don't like tabs either ;-)

void TriacStep ( void )
{
if ( interrupt0 == SIGNALED )
{
// turn off INT after neg edge
DISABLEINT0;

// poll pin on remain clear
// in case of glitch abort while loop
while ( bit_is_clear(PINB, PB6) )
{
_delay_ms(PUSHDELAYPOLL);
pushtime++;
}

//***if glitch pushtime still zero here !

// check push time
if (pushtime > TRESHOLDOFF)
{
///***long hold means goto power down***
/// turn off zerocross INT
/// for NO wackup from powerdown
DISABLEPCINT;

/// no triac pulse needed
UNMASKTRIAC;

/// INT0 back on
/// for wackup from powerdown
ENABLEINT0;

/// powerdown initiated
sleep_mode();

/// zerocross back on
ENABLEPCINT;

/// triac puls back on
MASKTRIAC;

}
else if (pushtime != ZEROTIME)
{
///***normal hold for triac step***

/// increase one step
triaclevel--;

/// get pre calculated values
TC1H = tc1high[triaclevel];
OCR1A = tc1low [triaclevel];

/// when max goto min
if (triaclevel==TRIACMAX)
triaclevel= TRIACLEVELS;
}

/// toggle INT flag atomic
ATOMIC_BLOCK(ATOMIC_FORCEON)
{
interrupt0 = NOTSIGNALED;
}

/// reset pushtime
pushtime = ZEROTIME;

/// save to trigger again on edge
ENABLEINT0;
}
}

As you can see I work with some threshold value to keep track how long the button has been pressed. This is done to diversify a simple push or a long push which in my case puts the AVR to sleep and put off the lamp completely. This concept works great. Ok I bring you up to the next slave sequel then.




sequel to slave concepts

2.making the gate triac pulses:

So every 20ms there's is a new sinus wave if you have a 50hz frequency distribution. The sinus wave is 50% positive and 50% negative which means also that the positive and negative have a duration of 10ms. The purpose is to let the triac conduct somewhere in these 10ms depending on the wanted duty cycle or lamp brightness. I noticed that the range between 0 -1ms and 9-10ms is not of much use anyway. It's also a fact that light strength (candelas) are not linear at all and have to be converted using some S-curve function (eg 1/1+e^x)

What I did was very simple. On every compare match interrupt ( see previous blog ) I fire a pulse with a wide of 5µs. The time needed for the pulse depends on the triac you use. The 5µs is made by the default avr lib delay function. At the end of the interrupt I put the PCINT back on again to catch the next zero crossing. See code snippet below:

ISR(TIMER1_COMPA_vect)
{
SETTRIAC;
_delay_us(TRIACPULSEWIDTH);
CLRTRIAC;
ENABLEPCINT;
}

That's basically it. So if you let say fire your pulse at 5ms you get 50% light intensity if you take 2ms you get 90% and finally 8ms you get 10%. Beware here that the light intensity is inverse equal on the fire time. Again if you really want to have a fluent light distribution you have to implement a S-curve.

Saturday, 7 March 2009

slave concepts


The purpose of the slave AVR is :

  1. zero cross detection

  2. making the gate triac pulses

  3. handling button actions

  4. handling one wire protocol with master

I will go over each of them now in order and explain what I did and found out.

1. zero cross detection:

The input for the zero cross is an opto coupler connected to the rectified and reduced (by zener diode) mains. Every time the sinus crosses the zero the opto react upon it. This signal is given to an input pin of the slave AVR and looks like the picture below:
Basically I implemented this on the AVR using a PCINT (pin change interrupt). First thing to do is disable the ints because otherwise you get two triggers. After that restart a timer to keep track that this was the zero cross and starts counting from there. Pretty simple :

ISR(PCINT_vect)

{

DISABLEPCINT;

RESTARTTIM1;

}

The main clock of the AVR was feed by a 12.8MHZ (1 ppm ) crystal. So the timer settings were:

void SetTimerTriac (void)

{
/// TIMER 1 enable fast PWM mode on OCR1A
TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(PWM1A);

/// TIMER 1 prescale value 128
TCCR1B = _BV(CS13);

/// TIMER 1 interrupt mask compare match OCR1A
TIMSK = _BV(OCIE1A);

/// TIMER 1 TOP value OCR1C
/// 0x03E8-1 or 1000 units
TC1H = 0x03;

OCR1C = 0xE7;

/// TIMER 1 compare match value OCR1A
TC1H = tc1high[triaclevel];
OCR1A = tc1low [triaclevel];

/// TIMER 1 starting point
TC1H = 0;
TCNT1 = 0;


}

recap

It's a very long time now since I blogged here. I was to busy working on the concepts actually. But i'm back again as I never give up you know by now. Let me first recapitulate what the my intentions were:

I now have a domotic system running for three years on a couple of AVRs. The core system is quit good and very stable. But it was foreseen to have a link with my local network and even beyond. This was accomplished in using a serial2TCP converter of multitech. And this is exactly the point where things went wrong. The multitech pcb sucks with a power of 100 ! It's nothing but consequent in his interfacing and the quality of the electronics are equally bad too. After a year the power supply section was not surprisingly dead as hell. So my system continued to run, but without a possibility to change things on the fly as changing light connections or timer programs for the heater. I said to myself "this was a very bad decision made on a monday morning after having a hard weekend". This was the time that I started to think all over again with the idea that next time (third system must be the goody one) my system needs to be almost perfect. I have a period behind me now of almost 2 years of experimenting and thinking as you can read on my blogs. So it becomes time to make a final concept now don't you think ? Well I can say that I have my final concept ready !

I will slowly introduce you to my final workouts in my next blogs which I also write this weekend.