Voting resources, early voting, and poll worker information - VOTE. ... Adafruit is open and shipping.
0

Give me some tips to improve my program
Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.

Give me some tips to improve my program

by soggybag on Tue Aug 24, 2010 1:11 am

I have a small program that generates a random PWM output, that changes at a rate determined by a pot. The program I have works, but not as well as it could.

I used a loop, looping a number of times determined by value read from the ADCH from the pot. Within the loop I call _delay_ms(10). I see that this is a crude system, and I could live with it. But, it has a few problems.

First, the main thing is the timing as set by the rotation of the pot feels non-linear. Most of the change is bunched up at one end of the pot rotation.

Second, at the slow end I notice a lag in response, as the loop needs to finish before the pot is read again.

Last, I know there must be a better way. I need a few suggestions to point me in the right direction. Your input is greatly appreciated!

I'm using an attiny13, avr-gcc and avrdude.

Here's a sample of the code I'm using at the moment.

Code: Select all | TOGGLE FULL SIZE
while ( 1 ) { // Main program
 
          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
      //----------Set rate of blinking based on ADCH byte---------
       for ( i = 0 ; i < ADCH ; i++ ) { // Loop x time until i reach ADCH value
             _delay_ms( 10 );                   // Loop delay
      }
      brightness = (uint8_t) rand();   // Need a random number from 0 - 255
      OCR0A = brightness;
   }




Here's the entire application in case it's relevant:
Code: Select all | TOGGLE FULL SIZE
/*
* Sample and Hold Demo. Flashes an LED at a random brightness at a rate set by a pot
* LED anode connected to pin 5, cathode to ground through a 470 ohm resistor
* B10K Pot center lug to pin 3, outer lugs to +5v and ground
* LED PB0 connected to pin 5
* Pot AD2 (PB4) connected to pin 3
*
*/

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

#define LED PB0       // Define led ext output pin on PB0 pin 5
 
int main( void ) {
   int i;              // 8 bits integer - should be set in main?
   uint8_t brightness = 0x00;   // Holds the random value applied to OCR0A

   // ******************************************************************
   //    *** Set up PWM ***
   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
   // ******************************************************************
 
       // *******************************************************************
      //    *** Set up ADC ***
       DDRB   |= ( 1 << LED );           // Set output direction on LED
       ADCSRA |= ( 1 << ADEN  ) |        // Analog-Digital enable bit
      ( 1 << ADPS1 ) |          // set prescaler to 8 ( clock / 8 )
      ( 1 << ADPS0 );           // set prescaler to 8 ( clock / 8 )
 
       ADMUX |=  ( 1 << ADLAR ) |        // AD result store in ( more significant bit in ADCH )
      ( 1 << MUX1  );           // Choose AD input AD2 ( PB4 ) pin 3
       // *******************************************************************

       while ( 1 ) { // Main program
 
          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
      //----------Set rate of blinking based on ADCH byte---------
       for ( i = 0 ; i < ADCH ; i++ ) { // Loop x time until i reach ADCH value
             _delay_ms( 10 );                   // Loop delay
      }
      brightness = (uint8_t) rand();   // Need a random number from 0 - 255
      OCR0A = brightness;
   }
   return 0;
}

soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

by adafruit_support_bill on Tue Aug 24, 2010 7:01 am

First, the main thing is the timing as set by the rotation of the pot feels non-linear. Most of the change is bunched up at one end of the pot rotation.


What kind of pot are you using: Linear or Audio ( logrithmic)?

Second, at the slow end I notice a lag in response, as the loop needs to finish before the pot is read again.


Put the analog read code inside the loop. If the value goes down, the loop will end earlier.

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

by soggybag on Wed Aug 25, 2010 12:34 am

Thanks for the reply. I'm using a linear taper pot, B10K. Now that you point it out. Seems that a log taper pot might give a linear feel since the time is based on 10ms * x.

I'm curious about the value for ADCH. I'm guessing this is defined in one of the includes. How can I look up the documentation for this?

The code I'm using to read the analog input I took from another example. I wonder about the reasons for reading the value then discarding the first read and then reading the value a second time. Is this the standard way to do this? Do need to read this twice every time you want to read an analog input, or do you need to discard only the very first time you read it?

For example could I read the analog input once, just above the while loop, then just read once inside the while loop?

soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

by adafruit_support_bill on Wed Aug 25, 2010 5:52 am

The A/D is multiplexed between all the analog pins and it takes some time for things to settle when switching between inputs. So, when reading from multiple inputs it is a good idea to throw away the first one. In your case, (1) you are only reading one input and (2) the accuracy of the reading is not very critical. So I don't think you need that extra read.

No need to change out your pot to change the response. There is a 'log()' function in the Arduino library.

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

by soggybag on Wed Aug 25, 2010 10:51 am

Thanks for the reply arduwino, I'll give log() a try. I'm consulting the documentation here: http://www.nongnu.org/avr-libc/user-man ... 647c152126

log() accepts a double and returns a double, I think I also need an int for OCR0A. How would I convert an int to a double?

I'll guess that the attiny13 will shut down the un-used pins, and that I don't need to ground them, as you might with other logic type IC's?
Last edited by soggybag on Wed Aug 25, 2010 11:07 am, edited 1 time in total.

soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

by adafruit_support_bill on Wed Aug 25, 2010 10:58 am

No need to ground the unused analog pins.

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

by soggybag on Wed Aug 25, 2010 11:16 am

Thanks again, do I need to convert the double returned rand() and log() to an int for OCR0A?

soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

by adafruit_support_bill on Wed Aug 25, 2010 12:22 pm

Yes, OCR0A won't take a double. You can convert by casting as in:
(unit8_t)log(x)

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

by soggybag on Wed Aug 25, 2010 12:40 pm

Thanks again for the help. I have been programming internet stuff (Actionscript and Javascript) for some years. The ideas make sense. But, it's taking me a while to wrap my head around this lower level stuff.

I'm guessing I can do this:
Code: Select all | TOGGLE FULL SIZE
brightness = (unit8_t)log( rand() );
OCR0A = brightness;

soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

by adafruit_support_bill on Wed Aug 25, 2010 12:48 pm

Should work. Don't be afraid to experiment!

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

by soggybag on Wed Aug 25, 2010 3:20 pm

Hmmm... I seem to be getting an error when I use log().

Code: Select all | TOGGLE FULL SIZE
wait = (uint8_t) log( ADCH );


Code: Select all | TOGGLE FULL SIZE
avr-gcc -Wall -Os -DF_CPU=9600000   -mmcu=attiny13 -c main.c -o main.o
main.c: In function 'main':
main.c:51: warning: implicit declaration of function 'log'
main.c:51: warning: incompatible implicit declaration of built-in function 'log'
avr-gcc -Wall -Os -DF_CPU=9600000   -mmcu=attiny13 -o main.elf main.o
/usr/local/AVRMacPack-20090319/lib/gcc/avr/4.3.2/../../../../avr/lib/avr25/libc.a(floatsisf.o): In function `__floatunsisf':
(.text.fplib+0x0): multiple definition of `__floatunsisf'
/usr/local/AVRMacPack-20090319/lib/gcc/avr/4.3.2/avr25/libgcc.a(_usi_to_sf.o):/Users/cs/Developer/Hardware/AVR-USB/AVRMacPack/buildtmp.nobackup/gcc-4.3.2/build-objects/avr/avr25/libgcc/../../.././gcc/fp-bit.c:1391: first defined here
make: *** [main.elf] Error 1

soggybag
 
Posts: 35
Joined: Sat Mar 01, 2008 3:28 am

Re: Give me some tips to improve my program

by adafruit_support_bill on Wed Aug 25, 2010 3:37 pm

Might be a limitation of the attiny. That line compiles fine with an Arduino target.

adafruit_support_bill
 
Posts: 78748
Joined: Sat Feb 07, 2009 10:11 am

Re: Give me some tips to improve my program

by uhe on Tue Aug 31, 2010 2:17 pm

Did you include math.h?
"I have not failed. I've just found 10,000 ways that won't work." - Thomas Edison
uhe
 
Posts: 178
Joined: Mon Sep 03, 2007 4:50 pm
Location: metric world

Please be positive and constructive with your questions and comments.