News:

SMF for DIYStompboxes.com!

Main Menu

AVR PWM Question

Started by soggybag, August 21, 2010, 07:24:13 PM

Previous topic - Next topic

soggybag

I've written a small program (below), which controls the brightness of an LED with a pot. The program below works. I have a few questions about how it works.

I'm using the attiny13. I have my LED connected to PIN 5 with a 150ohm resistor to GND. I have a 10K pot connected to +5V and GND with the wiper connected to pin 3.

For some reason the at the lowest value the LED isn't completely off. I'm wondering about ADCH. Where is this value coming from and what is the range of it?

OCR0A sets the PWM value. I remember using this with another program and it accepted a value of 0 - 255, uint8_t.

Any illumination, clarification, suggestions and comments welcome.

/*
* changing the brightness with PWM
* control PWM value with a 10K pot
* Confirmed working 082110
* LED PIN 5
* POT PIN 3
*/

#include <avr/io.h>
#include <util/delay.h>

#define F_CPU 9600000UL

int main(void) {
   
   TCCR0A |= (1<<COM0A1) | (1<<WGM00);    // PWM Phase correct mode 1
   TCCR0B |= (1<<CS00);         // --no prescale
   TCNT0  = 0x00;            // Timer/Counter Register
   OCR0A  = 0x12;            // Output Compare Register A

   DDRB   |= (1<<PORTB0);   // Set PB0 (Pin 5) as output

   ADMUX |=  ( 1 << ADLAR ) |          // AD result store in (more significant bit in ADCH)
              ( 1 << MUX1  );              // Choose AD input AD2 (BP 4, Pin 3)

   while( 1 ) {
      // Start A to D conversion
      /**/
      ADCSRA |= ( 1 << ADEN );          // Analog-Digital enable bit
          ADCSRA |= ( 1 << ADSC );          // Discard first conversion
            while ( ADCSRA & ( 1 << ADSC ) ); // wait until conversion is done
          ADCSRA |= ( 1 << ADSC );          // start single conversion
             while ( ADCSRA & ( 1 << ADSC ) )  // wait until conversion is done
          ADCSRA &= ~( 1 << ADEN );         // shut down the ADC
     
      OCR0A = ADCH;         // Set PWM at pin 5 to the ADCH read from pin 3
   }
   return 1;
}

soggybag

I tried experimenting with setting the value of OCR0A to set the PWM output. I connected PWM output to an LED/LDR and measured the resistance. Here's the results:

// VTL5C9 150ohm
// OCR0A = 255;   // 74ohm
// OCR0A = 192;   // 86ohm
// OCR0A = 128; // 109ohm
// OCR0A = 64;   // 165ohm
// OCR0A = 32;   // 250ohm
// OCR0A = 16;   // 414ohm
// OCR0A = 8;   // 695ohm
// OCR0A = 4;    // 1K2
// OCR0A = 2;   // 2k1
// OCR0A = 1;    // 3K6
// OCR0A = 0;   // 3M1

You can see I get huge range between 1 and 0. I'm guessing that I can't set the value to a number (1,2,3 etc.). I probably need to set OCR0A as a hex value like 0x00.

Is there a way I could write the program in C where I could use a numeric value here?

slotbot

Hello, to me it seems your setup is working fine, maybe its just not what you expected to have happen.

are you using avr studio?

i dont have it in front of me but from what i remember the default radix IS decimal. so if you say

OCR0A = 1;

it is teh same as

OCR0A = 0x01;

0x or $ specify hex and 0b specifies binary IIRC.




Also ADCH is the high byte result of the a/d conversion. It should range in this case from 0-255 which fits in nicely to OCR0A.



finally this is just speculation but did you measure the resistance of the vactrol when the led is disconnected? that value might be helpful in helping you toubleshoot. The reason you see the huge jump may be that at 0 there is no positive cycle to the PWM wave at all so the led is in fact always  off. ON the VTL5C9 data sheet it looks like 3k6 corresponds to about .2mA current. Given that the average current delivered from the pwm at 1 (1/256 )is around .1mA and the fact that the turn off time is quite slow, i would say that 3.6 k is totally normal with your 150 ohm resistor.


soggybag

Thanks slotbot that's very helpful.

I need to get the LDR resistance into a range of 100K. I like the VTL5C since the response time is fast. I'll have to test out a few more. I drawer of them.

I have been thinking I might be able to use a transistor in place of the LDR.

How did you figure the PWM value of 1/256 as .1ma?

I was having a hard time wrapping my head around the data sheet for the VTL5C9. Now I'm seeing that you were looking at the chart labeled: Output Resistance vs. Input Current. Which makes sense to me at this point.

slotbot

Hey, this might not be the best vactrol if you are aiming for ~100k. you can see from that same graph on teh data sheet that the resistance shifts from 20k to 3k over just 1mA, it might be hard to be that precise with the atmega.

the 5c3/2 looks maybe  more suitable?

as for the calculation.. the current through the resistor (in your case 150 ohm) is proportional to the voltage across it. in this case the voltage accross the resistor will be ~ 5V - the forward drop of the LED when the PWM signal is HIGH and 0 V when it is off.

to find the average value of the pwm take the value odf OCR0A/256 *Voltage/Resistance

so for 1/256 its ~ (1/256) * (5V - 2.2V) / 150 Ohms = 73 uA which is just shy of .1 mA.

Another consequence of this number is that the average current can only be incremented by steps of 73uA since you cannot put a number like 1.1 into OCRA0 ;) Lets jsut round that to .1ma for simplicity, you can see now from looking at that graph taht between teh first few low values possible of OCRa0, we have already covered most of the resistance range of the vactrol.  you can see this trend in your test data as well. ie 1 = .1mA ~ 11k, 2 = .2mA ~ 3k, 3 ~ .3 mA ~1k etc.. and then say between 100 and 200 (10 to 20mA) the change in resistance is merely a few ohms.

anyways hopefully that helps. i would recommend using a differnet LDR or vactrol if you are still going to go with this hardware setup and you need values in teh 100k range.

scott

soggybag

Thanks that's a great explanation.

I started to think it might be possible to use a transistor in place of the LDR. I'm imagining the transistor turning on and off at the rate  of the PWM. The MXR Envelope Filter works on a similar principle.

slotbot

whats your end goal? ie: what are you trying to use this for? what circuit etc...

soggybag

I want to create something like the Maestro FSH-1 (just the sample and hold mode). The concept is to use an AVR chip to generate the random voltage, to control a simple wah.

So far I have the Colorsound wah on the bread board, with an LDR in place the 100K wah pot. With my current program in the AVR it all works. Just not as well as it could. I'm just not getting a good range of change in the LDR. From your calculations above, it looks like I'm getting a range of 3K. Which makes sense to what I'm hearing.

So far the project looks pretty promising. Obviously the FSH-1 running off two 9v batteries and more sophisticated filter is going to have overall better sound quality. But the FSH-1 is also pretty complex and has it's own problems. My project is 1 8 pin DIP, two transistors and a handful of other parts running on a single 9v battery.

Experimenting with a pot in place of the LDR I found that the most useful range was about 470ohms to 18k. Below 470ohms I started to hear high frequency noise, and above 18k the wah was in the low range which wasn't so pronounced on guitar. Between 470 and 18k the wah effect was very useful on guitar.

So the goal in a nutshell, would be to get the PWM out of the AVR to create a random resistance in the range of about 0 to 18K.


slotbot

hmmok i would suggest 2 things........

1) adjsut the resistor value that is in series with th LED side of the vactrol (150 ohms). i would try putting it to around 2.2k. If you only want a range up to ~ 20k on the resisotr side of the vactrol you might be successful with the hardwareyou already have.

You cna use the graph and the same formula mentioned above to see why. Lets jsut say we want a range from 20k to 500 ohms. 20k happnes at around .1 - .2 mA. SO thats our minumum desired current. Now 500 ohms is around  1 mA so this is our maximum desired current.

wed like to get the 0-255 range drive the LED in that current range  so youcan first figure out what resistance value will give you ~ 1mA when OCRA0 = 220. ( close to the maximum)

(220/255)*(5V-2.2V)/R = 1mA

OR... R ~ 2.2k

now go backwards and see what OCRA0 should be to get .1mA with this R

(OCRA0/255)*(5V-2.2V)/2200ohms = .1mA

OR

OCRA0 =  20.03 or lets say 20 because it has to be an integer.

So this value seems ok even though we dont use the whole range of OCRA0 , we are using 200 out of 255 which is much better than 3 or 4 out of 255 as before.  Also by calculting it this way you have abit of hadroom in both directions (the max was at 220 and min at 20, which are not teh max and min of the PWM. Its still not going to be perfectly linear but it is at least improved. Some experimenting maybe required but thats the general idea.

option 2)

the filter used is a "twin t notch" filter. You could simply recalculte the C values to accomodate the range of R your setup is already giving you. if you google "twin t notch filter" you will find many many pages with the formula and schmeatic for this type of filter.

good luck

soggybag

Thanks again, that was really helpful.

I gave the 2.2K resistor a try. This helped, but from the sound I feel like I'm only getting half of the possible range.

I'm looking into the Twin-T filter and seeing about adjusting the caps. Hopefully this will get the filter to work better with the range of control resistance I have.

slotbot

ok also you could try a 5K or 10K pot instead and jsut sweep throught to see if you can find a usable range. (put a 150 ohm r in series with the pot so that you dont end up with 0 ohms resistance at one extreme).

i guess you are tryingto keep iot as simple as possible? idid somethign similar but with a delay but made teh S/H wave using a noise genrator a 555, opamp and LF398. Th LF398  says it needs 10 volts supply on teh data sheet but i think that is jsut to meet the charging time specifications. I found wiht 9 or less it still works quite well for LFO purposes. Its alot more parts but its about as random as you can get, analog and also you can use the opamp to get the signal exactly where you want it to drive the LED/fet whatever you want.


soggybag

The LF398 sounds pretty interesting. I had seen that I might have order one from Futurlec, but I never got around to trying it.

I'm stuck on the AVR for now. I'm interested in learning how to program.

I used a 470ohm resister and a 5K pot from the LED to ground. Adjusting this seemed to give a little more range. At which point I was realizing it's hard to tell what the full range is when the Control Voltage is random!

I think my next goal is to modify my program a bit to produce a ramp or triangle. This way I can test and hear the entire range that is possible.