DIYstompboxes.com

DIY Stompboxes => Digital & DSP => Topic started by: soggybag on March 30, 2009, 04:26:42 PM

Title: Getting started with AVR programming
Post by: soggybag on March 30, 2009, 04:26:42 PM
I want to create a project that will use an AVR. So far I have built the USBtinyISP (http://'http://www.ladyada.net/make/usbtinyisp/'). I have also built a small programming board with an 8 pin DIP socket and a 6 pin header for the USBtinyISP. I'm using the attiny13 I checked the pin out wired the header based on what was in the documentation. Hopefully I've wired these up correctly...

I have also installed the AVRMacPack-20090319. I ran a couple command lines tests on this. I made the demo project from the examples. It created the main.c file and Makefile file in the correct directory, so I assume that it is is installed correctly.

At this point I want to write a program, compile it and download it into a attiny13. So the questions I have are:
1) Where can I find some info on writing simple programs? Flashing an LED reading a value from a pot.
2) How do I compile and upload the program using AVRDUDE?

If anyone can point me to this info on the web or post a short (or long answer if you prefer) I would be most appreciative, thanks!
Title: Re: Getting started with AVR programming
Post by: zyxwyvu on March 31, 2009, 04:32:56 AM
AVR Freaks (http://www.avrfreaks.net/) is a great place to start. Check out the forum, especially the tutorial section.

Another thing that took me a while to figure out: read the datasheets! Almost everything you need to know to program each chip is in there. They're available on Atmel's site, on the product page for each chip. Each controller is unique, and certain registers may be different. The most important parts of the datasheets are the 'register description' sections. They list all the registers relevant to the section, and what each value does.

For example, to read a value from a pot, you need to use the ADC. This means you have to check the datasheet for all the relevant registers - for setting the input pin, clock speed, triggering, etc. I believe there is a tutorial on AVR freaks on the ADC, but you'll need to use the datasheet to check the registers they use.
Title: Re: Getting started with AVR programming
Post by: soggybag on March 31, 2009, 02:10:45 PM
Thanks for the reply. I'm looking at the data sheet right now. Lots of good info there. For me it's just a matter of deciphering it.

I'm trying to make an LFO with the AVR. My thoughts are that I would start by getting an LED to Flash on and off. Then try and add a pot to control the speed. From here try and create some kind of wave form like a triangle.

Here's my sample code. I was able to download this on to the AVR. But it isn't working. I'm using the attiny13v It was pointed out that the attiny13 doesn't have a PORTD! Oops.

/* Name: main.c
* Author: <insert your name here>
* Copyright: <insert your copyright message here>
* License: <insert your license reference here>
*/

#include <avr/io.h>
#include <util/delay.h>
int main(void) {
   DDRD = 1 << 4;    /* make the LED pin an output */
   for(;;) {
      char i;
       for(i = 0; i < 10; i++){
         _delay_ms(30);    /* max is 262.14 ms / F_CPU in MHz */
      }
      PORTD ^= 1 << 4; /* toggle the LED */
   } return 0; /* never reached */
}
Title: Re: Getting started with AVR programming
Post by: The Tone God on March 31, 2009, 02:11:59 PM
If you are using GCC I have a simple LED/Hello world program at my site. From there you start using the datasheet and the complier (and its documentation) to learn A/D and so forth.

I haven't used AVRDUDE but you should have the documentation on you computer if you have installed the AVR tool set.

AVRFreaks is a good place to hangout too.

Edit for new code posting:

1. Do not declare a variable inside the main loop. Put it outside the loop. Probably under the direction register assignment.
2. Tiny13 does not have PORTD, only PORTB.
3. It won't affect functionality but a "While(1)" is more traditional then "for(;;)" for the main loop.
4. It looks like your for loop is trying to create a 300ms loop. Take the loop out and try three 100ms delays in a row and see if that works at first as it is simpler.

Andrew
Title: Re: Getting started with AVR programming
Post by: soggybag on March 31, 2009, 02:32:15 PM
Thanks I'm reading your site right now. This is very informative.
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 01, 2009, 07:22:04 PM
read the documentation for avrgcc. I also found the book from smiley micros to be extremely helpful.

www.smileymicros.com

free quickstart guide:

http://smileymicros.com/Quick%20Start%20Guide%20-%20The%20Next%20Generation.pdf?&MMN_position=106:106


He also does a great series of articles for nuts & volts.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 01, 2009, 08:05:30 PM
Thanks for the reply.

Last night I got an LED flashing by downloading a program to the attiny13, so I'm making progress.

The next step is to add a pot and use it to set the speed of the blinking.
Title: Re: Getting started with AVR programming
Post by: Lurco on April 02, 2009, 09:58:23 AM
will follow thread!
Title: Re: Getting started with AVR programming
Post by: soggybag on April 02, 2009, 02:47:36 PM
Here's the program I used to flash an LED. Thanks Andrew, for pointing out that I was using the the wrong port.

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

volatile uint8_t i = 0;

int main( void ) {
   DDRB = 0b00001000;
   PORTB = 0b00000000;

   while( 1 ) {
      char i;
      for( i = 0; i < 10; i++ ) {
         _delay_ms( 30 ); /*   max is 262.14 ms / F_CPU in MHz   */
      }
      PORTB ^= 1 << 4; /*   toggle the LED   */
   }
   return 0;
}


I have  few questions at this point.

DDRB = 0b00001000;

Sets the direction of the port and pins. In this case this line seems to set PORTB pin 2 as an output. I'm not quite clear on the syntax of this. How do you set this to configure various pins as inputs or outputs?
Title: Re: Getting started with AVR programming
Post by: The Tone God on April 02, 2009, 07:00:00 PM
First thing first, lets clean up this code.

1. You declared the variable "i" twice and once in the while loop. Both are bad form.

2. There is no point in assigning a value to "i" as the for loop will do that for you.

3. The "0b00000000" format is really not well recognized and may not work in all situations. I know it looks easier as a beginner to read but really these assignments should be done in hex. For now you can get away with it but I recommend learning hex. Your computer's OS calculator should have a conversion mode for this. If not grab a free one off the net somewhere. It will make life easier.

4. Indent the blocks and try to make your brackets line up. It makes the code easier to read which when things get more complicated will help you out when you are scanning code quickly. Good coding habits start now when you are first learning. Later on it is harder to break bad habits.

5. Lots of comments! Especially if you want other people to read your code.

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

uint8_t i; // Counter varible

int main( void )
{
DDRB = 0x08; // Set PB4 (Pin 3) as output
PORTB = 0x00;

while( 1 )
{
for( i = 0; i < 10; i++ ) // Delay loop for 300ms
{
_delay_ms( 30 ); // max is 262.14 ms / F_CPU in MHz
}

PORTB ^= 1 << 4; // toggle the LED
}

   return 0;
}


Quote from: soggybag on April 02, 2009, 02:47:36 PM
DDRB = 0b00001000;

Sets the direction of the port and pins. In this case this line seems to set PORTB pin 2 as an output. I'm not quite clear on the syntax of this. How do you set this to configure various pins as inputs or outputs?

That line actually sets PB4 (physical pin 3) as an output. If you want physical pin 2 you want PB3 so that is:

0b00000100;

or better yet in hex

0x04;

You will need to change the toggle line too to:

PORTB ^= 1 << 3;

or you can make life easier and do this:

PORTB ^= 1 << PB3;

Did you read the "Digital Input and Output - Pivotal Digital" article at my site ? I cover this in that article. Also the datasheet explains alot too.

BTW if you are using a newer version of GCC the "_delay_ms" no longer has the 262 restriction. You can drop 300 in and lose the loop altogether. Check the documentation that came with your GCC version. Its on your computer as it comes as part of the GCC installation.

Andrew
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 02, 2009, 07:04:04 PM
Quote from: soggybag on April 02, 2009, 02:47:36 PM

 
I have  few questions at this point.

DDRB = 0b00001000;

Sets the direction of the port and pins. In this case this line seems to set PORTB pin 2 as an output. I'm not quite clear on the syntax of this. How do you set this to configure various pins as inputs or outputs?

the data direction register bits all have names that you can use to make your code more readable
i.e. bit 2 on DDRB is labelled 'DDB2'

so you could:


DDRB |= (1<<DDB2);


bit manipulation 101 is required reading here:

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=37871




Title: Re: Getting started with AVR programming
Post by: soggybag on April 03, 2009, 12:53:56 AM
Thanks Tone God! This is the information I was looking for. I missed that article "Digital Input and Output - Pivotal Digital", For some reason I thought is was about something else.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 03, 2009, 12:23:17 PM
With Andrew's help I simplified my program to:
#include <avr/io.h>
#include <util/delay.h>

uint8_t i; // Counter varible

int main( void ) {
DDRB = 0x08; // Set PB4 (Pin 3) as output
PORTB = 0x00;

while( 1 ) {
_delay_ms( 300 ); // delay 300ms
PORTB ^= 1 << 4; // toggle the LED
}
return 0;
}


It appears that _delay_ms() does support numbers larger than 262.

Next step reading a pot to set the delay time...
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 04, 2009, 04:19:15 AM
I'll follow this thread, I've got some tiny13's to play with.


Quote from: soggybag on April 03, 2009, 12:23:17 PM
With Andrew's help I simplified my program to:
#include <avr/io.h>
#include <util/delay.h>

uint8_t i; // Counter varible

int main( void ) {
DDRB = 0x08; // Set PB4 (Pin 3) as output
PORTB = 0x00;

while( 1 ) {
_delay_ms( 300 ); // delay 300ms
PORTB ^= 1 << 4; // toggle the LED
}
return 0;
}


It appears that _delay_ms() does support numbers larger than 262.

Next step reading a pot to set the delay time...


you still dont need that 'i' variable in there.

here's some bits to help you setup the ADC, this example is left adjusted for an 8-bit(0-255) measurement stored to ADCH



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


/*

blinky for the attiny13

     ___ ___
PB5=|   V   |=VCC
PB3=|     |=PB2
PB4=|     |=PB1
GND=|_______|=PB0


ISP---MISO-PB1
  MOSI-PB0
  SCK-PB2
  RESET-PB5


LED on PB4
ADC on PB3


use PB0 or PB1 for PWM output


will work on other attiny's

*/

int main( void )
{
/*
port setup

*/

DDRB |= (1<<DDB4); //PORTB4 output pin
PORTB = 0x00; //clear PORTB

/*
ADC setup - free running mode
    1MHz clock / 8 = 125KHz sample rate
*/

ADCSRA |= (1<<ADPS0) | (1<<ADPS1); //ADC prescaler to 8
ADMUX |= (1<<ADLAR) | (1<<MUX0) | (1<<MUX1); //left adjust for 8-bit result in ADCH, PORTB3 ADC input
ADCSRA |= (1<<ADEN) | (1<<ADSC); //enable, start converting


// do something with ADC



while(1)
{

_delay_ms(300); // delay 300ms
PORTB ^= (1<<PORTB4); // toggle the LED
}

return 1;
}
Title: Re: Getting started with AVR programming
Post by: soggybag on April 04, 2009, 11:01:35 AM
Thanks for the reply. I'll give this a try tonight. I have some similar code I was working on. But I had trouble figuring out how to set the pin number for the ADC.
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 04, 2009, 11:24:48 AM
Quote from: soggybag on April 04, 2009, 11:01:35 AM
Thanks for the reply. I'll give this a try tonight. I have some similar code I was working on. But I had trouble figuring out how to set the pin number for the ADC.

selecting the pins for ADC input is done by setting the MUX0 and MUX1 bits in the ADMUX register.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 04, 2009, 05:46:55 PM
Thanks, great reply. I'm still confused on how to read the value in the ADC correctly? Or maybe the question is really how to use the value correctly.

I want to use the value as the delay time passed to the _delay_ms() method.

Here's the code I have been using below. If I use _delay_ms( 300 ), it compiles without error and the program works, the light flashes on and off.

If I use _delay_ms( val ), the program doesn't compile correctly. I get an error:
avrdude: ERROR: address 0x0410 out of range at line 65 of main.hex
avrdude: write to file 'main.hex' failed

/*

blinky for the attiny13

     ___ ___
PB5=|   V   |=VCC
PB3=|     |=PB2
PB4=|     |=PB1
GND=|_______|=PB0


ISP---MISO-PB1
  MOSI-PB0
  SCK-PB2
  RESET-PB5

LED on PB4
ADC on PB3

use PB0 or PB1 for PWM output
will work on other attiny's

*/

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

int ReadADC(); // Function to read ADC
int val = 0; // Holds value from ADC

int main( void ) {
/* port setup */

DDRB |= ( 1 << DDB4 ); //PORTB4 output pin
PORTB = 0x00; //clear PORTB

/*
ADC setup - free running mode
1MHz clock / 8 = 125KHz sample rate
*/

ADCSRA |= ( 1 << ADPS0 ) | ( 1 << ADPS1 ); //ADC prescaler to 8
ADMUX  |= ( 1 << ADLAR ) | ( 1 << MUX0 ) | ( 1 << MUX1 ); //left adjust for 8-bit result in ADCH, PORTB3 ADC input
ADMUX  |= ( 0 << REFS0 ); // VCC as Reference 
ADCSRA |= ( 1 << ADEN  ) | ( 1 << ADSC ); //enable, start converting

// do something with ADC ( ADCH? )

while( 1 ) {
val = ReadADC();
_delay_ms( 300 ); // delay 300ms
PORTB ^= ( 1 << PORTB4 ); // toggle the LED
}
return 1;
}

int ReadADC() {
     ADMUX |= (0 << REFS0); // VCC as Reference
     ADMUX = 2;// ADC2 PB.4
     ADCSRA |= (1 << ADSC); // Start Converstion

     while( ( ADCSRA & 0x40 ) != 0 ) { }; // wait for conv complete

     return ADC;
}
Title: Re: Getting started with AVR programming
Post by: soggybag on April 04, 2009, 06:24:47 PM
Another small success! I was able to read the value of the pot with the following code. Here I have a B10K pot with the center pin connected to pin 3 on the AVR and an LED connected to pin 7.

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

#define F_CPU 9600000               // Define software reference clock for delay duration
#define LED PB2                     // Define led ext output pin on PB2

int i;                              // 8 bits integer


int main( void ) {

    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 (BP 4)

    while (1) {

    ADCSRA |= ( 1 << ADEN );          // Analog-Digital enable bit
    ADCSRA |= ( 1 << ADSC );          // Discarte 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
}

PORTB ^= ( 1 << LED );                  // Inverte led bit and show it
}
return 0;
}


Next step, random numbers...
Title: Re: Getting started with AVR programming
Post by: The Tone God on April 04, 2009, 07:48:06 PM
Little busy to look over code right now but I do recommend you put a resistor in series with the pot wiper feeding to the Tiny13's pin. Something like a 1K. At the Tiny13's pin add a cap like a 0.1uF, just like the one you are decoupling the Tiny13's power supply with right ? ;)

Andrew
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 04, 2009, 08:25:43 PM
Quote from: soggybag on April 04, 2009, 05:46:55 PM
Thanks, great reply. I'm still confused on how to read the value in the ADC correctly? Or maybe the question is really how to use the value correctly.

I want to use the value as the delay time passed to the _delay_ms() method.

Here's the code I have been using below. If I use _delay_ms( 300 ), it compiles without error and the program works, the light flashes on and off.

If I use _delay_ms( val ), the program doesn't compile correctly. I get an error:
avrdude: ERROR: address 0x0410 out of range at line 65 of main.hex
avrdude: write to file 'main.hex' failed



sorry, I should've been more specific about the ADC setup.

single conversion mode is nice when you need to switch and poll multiple channels. my previous example uses free-running mode.

for this application both do the same thing, free-running is less setup. in fact you could paste that for loop you wrote into my code and it works fine.


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


/*

blinky for the attiny13

     ___ ___
PB5=|   V   |=VCC
PB3=|     |=PB2
PB4=|     |=PB1
GND=|_______|=PB0


ISP---MISO-PB1
  MOSI-PB0
  SCK-PB2
  RESET-PB5


LED on PB4
ADC on PB3


use PB0 or PB1 for PWM output


will work on other attiny's

*/

int main( void )
{
/*
port setup

*/

DDRB |= (1<<DDB4); //PORTB4 output pin
PORTB = 0x00; //clear PORTB

/*
ADC setup - free running mode
    1MHz clock / 8 = 125KHz sample rate
*/

ADCSRA |= (1<<ADPS0) | (1<<ADPS1); //ADC prescaler to 8
ADMUX |= (1<<ADLAR) | (1<<MUX0) | (1<<MUX1); //left adjust for 8-bit result in ADCH, PORTB3 ADC input
ADCSRA |= (1<<ADEN) | (1<<ADSC); //enable, start converting




while(1)
{

uint8_t i;

for (i = 0; i < ADCH; i++); // Loop x time until i reach ADCH value
{
    _delay_ms(10); // Loop delay
}


PORTB ^= (1<<PORTB4); // Invert led bit and show it

}

return 1;
}





Title: Re: Getting started with AVR programming
Post by: soggybag on April 04, 2009, 09:01:56 PM
Thanks that helps explain what is going with the ADC.

I noticed that I was trying to use ADCH as the delay time with _delay_ms(). But I kept getting a compile error. Looking at the docs for GCC I found that _delay_ms( time ) expects time as a double. ADCH is another type, maybe uint8? How can you convert from one type to another? or is there a better method to handle this type of situation?

My next task is to attempt to generate a random number. The chip doesn't seem to have a method for this. But I suspect there might be something in the GCC library. If not there must a standard system to generate random values. 
Title: Re: Getting started with AVR programming
Post by: The Tone God on April 04, 2009, 11:34:41 PM
Quote from: soggybag on April 04, 2009, 09:01:56 PM
I noticed that I was trying to use ADCH as the delay time with _delay_ms(). But I kept getting a compile error. Looking at the docs for GCC I found that _delay_ms( time ) expects time as a double. ADCH is another type, maybe uint8? How can you convert from one type to another? or is there a better method to handle this type of situation?

The problem is that _delay_ms() wants a constant. It will not take a variable. There are several ways to create variable length delays including the loop you were doing. A better option is using the timer so the Tiny13 can be busy doing other things.

Quote from: soggybag on April 04, 2009, 09:01:56 PMMy next task is to attempt to generate a random number. The chip doesn't seem to have a method for this. But I suspect there might be something in the GCC library. If not there must a standard system to generate random values.

There is a random function but you have to "seed" the expression with a figure from somewhere. The function eats up alot of space. There are lots of other methods to generate pseudo-random and true random depending on you needs.

Andrew
Title: Re: Getting started with AVR programming
Post by: soggybag on April 05, 2009, 12:03:24 AM
That's some interesting info. I have a lot of experience programming for the internet. This Microcontroller thing puts a whole new twist on it. The idea that you can't pass a variable to function is something that I would not expect.

I'm not too worried about coming up with the most optimized code at this point. If I can just get some basic thing working I'll be happy. I'm trying to keep my goals realistic. That said I'm very curious about this counter thing. I'll have to look it up...
Title: Re: Getting started with AVR programming
Post by: The Tone God on April 05, 2009, 12:15:59 AM
Quote from: soggybag on April 05, 2009, 12:03:24 AM
That's some interesting info. I have a lot of experience programming for the internet. This Microcontroller thing puts a whole new twist on it. The idea that you can't pass a variable to function is something that I would not expect.

There was some recent talk about that issue. I believe the issue is that the delay loops are worked out at compile time so it can't take a variable. There are still basic delay loops provided by GCC or you can loop the fixed delay loop like you were before or you could use a timer.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 05, 2009, 02:22:27 AM
I found a tutorial on Timers. I tried modifying the code to work with attiny13. But it is not working. I must have missed something. This code should blink the LED without the use of the loop and delay, by instead using a timer. It seems to compile without error, but does nothing.

#include <avr/io.h>
#include <avr/interrupt.h>

volatile uint8_t count;

int main() {
   // Prescaler = FCPU / 1024
   TCCR0B |= ( 1 << CS02 ) | ( CS01 );

   //Enable Overflow Interrupt Enable
   TIMSK0 |= ( 1 << TOIE0 );

   //Initialize Counter
   TCNT0 = 0;

   //Initialize our varriable
   count = 0;

   //Port B[3,2,1,0] as out put
   DDRB |= 0x0F;

   //Enable Global Interrupts
   sei();

   //Infinite loop
   while( 1 );
}

ISR( TIMER0_OVF_vect ) {
   //This is the interrupt service routine for TIMER0 OVERFLOW Interrupt.
   //CPU automatically call this when TIMER0 overflows.

   //Increment our variable
   count++;
   if ( count == 61 ) {
      PORTB = ~PORTB; //Invert the Value of PORTB
      count = 0;
   }
}
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 05, 2009, 02:36:44 PM
haven't had much time to code this weekend.

you probably want to use CTC mode rather than an interrupt. Doing this you can set your timer compare match to ADCH where the ADC value is returned.

http://www.avrfreaks.net/index.php?name=PNphpBB2&file=viewtopic&t=50106

check out part 4, CTC mode.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 07, 2009, 01:08:21 AM
Here's what I came up with for PWM. The goal of this example is to make an LED increase and decrease in brightness. It looks correct, to me and my limited knowledge, but doesn't work for some reason. I'm missing something.

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

int main() {
unit8_t brightness = 0;

TCCR0A = 0x81; // Timer/Counter Control Register A
TCCR0B = 0x01; // Timer/Counter Control Register B
TCNT0  = 0x00; // Timer/Counter Register
OCR0A  = 0x12; // Output Compare Register A
OCR0B  = 0x00; // Output Compare Register B

DDRB   = 0x08; // Set PB4 (Pin 3) as output

while( 1 ) {
// Increase brightness from 0 to 255
for ( brightness = 0; brightness < 255; brightness++ ) {
OCR0A = brightness; // Set PWM duty based on brightness value
_delay_ms( 10 ); // Delay 10 ms
}

// Decrease brightness from 255 to 0
for ( brightness = 255; brightness > 0; brightness-- ) {
OCR0A = brightness; // Set PWM duty based on brightness value
_delay_ms( 10 ); // Delay 10 ms
}
}
return 1;
}
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 08, 2009, 03:03:19 AM
Quote from: soggybag on April 07, 2009, 01:08:21 AM
Here's what I came up with for PWM. The goal of this example is to make an LED increase and decrease in brightness. It looks correct, to me and my limited knowledge, but doesn't work for some reason. I'm missing something.


had a very quick look through.

typo in "uint8_t"

PWM tables:
(http://i4.photobucket.com/albums/y130/idiot5avant/PWMtable.jpg?t=1239172216)
(http://i4.photobucket.com/albums/y130/idiot5avant/pwm2.jpg?t=1239174052)

maybe I'm not seeing everything so double-check your COM0A0, and COM0A1 bits, and WGM bits, and prescaling bits. try mode 5 with WGM02 set. 

Title: Re: Getting started with AVR programming
Post by: soggybag on April 08, 2009, 04:35:32 PM
Thanks, I think I'm really close to getting this working. I just need to get the Timer/Counter registers setup with the correct settings.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 11, 2009, 09:44:58 PM
Thanks for the all of the help. I'm trying to set up the PWM mode 5 as per your suggestion. Here's what I have so far. I'm still missing something because this doesn't work yet. But I think I'm pretty close.

I think this sets up TCCR0A and TCCR0B correctly for Mode 5.
TCCR0A |= ( 1 << COM0B1 ) | ( 0 << COM0B0 ) | ( 1 << WGM01 ) |( 1 << WGM00 );
TCCR0B |= ( 0 << CS02 ) | ( 0 << CS01 ) | ( 1 << CS00 ) | ( 1 << WGM02 );

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

int main() {
uint8_t brightness = 0;

TCCR0A |= ( 1 << COM0B1 ) | ( 0 << COM0B0 ) | ( 1 << WGM01 ) |( 1 << WGM00 );
    TCCR0B |= ( 0 << CS02 ) | ( 0 << CS01 ) | ( 1 << CS00 ) | ( 1 << WGM02 );
TCNT0  = 0x00; // Timer/Counter Register -
OCR0A  = 0x12; // Output Compare Register A
OCR0B  = 0x00; // Output Compare Register B

// DDRB |= ( 1 << PB0 ); // Is this same as the line below?
DDRB   = 0x01; // Set PB0 (Pin 5) as output

while( 1 ) {
// Increase brightness from 0 to 255
for ( brightness = 0; brightness < 255; brightness++ ) {
OCR0A = brightness; // Set PWM duty based on brightness value
_delay_ms( 10 ); // Delay 10 ms
}

// Decrease brightness from 255 to 0
for ( brightness = 255; brightness > 0; brightness-- ) {
OCR0A = brightness; // Set PWM duty based on brightness value
_delay_ms( 10 ); // Delay 10 ms
}
}
return 1;
}
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 12, 2009, 05:24:41 PM
You are very close. think of it this way....

Timer/Counter0 has 2 compare registers, OCR0A, and OCR0B.

OCR0A corresponds to PORTB0 or pin 5 on the chip
OCR0B corresponds to PORTB1 or pin 6.

So, if we decide we want some PWM action goin on, we gotta use one of those pins...

From the table we can see that Phase-correct PWM has 2 modes.
Mode 1 or mode 5 for phase-correct PWM.
Mode 3 or mode 7 for Fast PWM.

to set mode 1, we:

TCCR0A |= (1<<WGM00));

to use mode 5, we add:

TCCR0B |= (1<<WGM02);

you have your prescaling off so you would:

TCCR0B |=(1<<CS00);


Now then... We see that the COM0A0, and COM0A1 bits in TCCR0A set the behavior of the OCR0A(the COM0B0, COM0B1 control OCR0B) 

register(our PWM pin).

look at the table, for this application we would want OCR0A cleared at the top of the count and set on the downcount...

...as we change OCR0A this varies the duty-cycleof our PWM.

then we:

TCCR0A |= (1<<COM0A1);


put it all together you have:


TCCR0A |= (1<<COM0A1) | (1<<WGM00); //0x81; // PWM Phase correct mode 1
TCCR0B |= (1<<CS00);//0x01; // --no prescale



The rest of your code is pretty much OK.

try this:



#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



uint8_t brightness = 0x00;

while( 1 )
{
// Increase brightness from 0 to 255
for ( brightness = 0; brightness < 255; brightness++ )
{
OCR0A = brightness; // Set PWM duty based on brightness value
_delay_ms( 10 ); // Delay 10 ms
}

// Decrease brightness from 255 to 0
for ( brightness = 255; brightness > 0; brightness-- )
{
OCR0A = brightness; // Set PWM duty based on brightness value
_delay_ms( 10 ); // Delay 10 ms
}
}
return 1;
}



Sorry, I sorta misguided you before. I neglected to mention, that if you use mode 5 PWM, you have to use OC0B as the output since
OC0A becomes the TOP to the Counter. My bad, as usual, I overcomplicate things. :icon_redface:

I did verify this code in hardware, so it works!!! now just get an ADC channel to set the compare value, and you have a spiffy little PWM
LFO to use in stuff!!!


-Morgan

Title: Re: Getting started with AVR programming
Post by: soggybag on April 12, 2009, 06:02:40 PM
Thanks man! That was exactly it. This worked great.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 12, 2009, 09:05:23 PM
Success at last! Here's the program to create a Sample and Hold with the AVR attiny 13. Thanks to everyone who provide me with such great help in this thread.

This probably still needs a little work. But it seems to be working pretty well so far.

/*
* Sample and Hold Demo. Flashes an LED at a random brightness at a rate set by a pot
* 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 F_CPU 9600000            // Define software reference clock for delay duration
#define F_CPU 9600000UL
#define LED PB0                     // Define led ext output pin on PB0 pin 5

int i;                              // 8 bits integer

int main( void ) {

// ******************************************************************
// *** 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

uint8_t brightness = 0x00;
// ******************************************************************

    // *******************************************************************
    // *** 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;
}
Title: Re: Getting started with AVR programming
Post by: idiot savant on April 14, 2009, 11:48:15 AM
very cool, I hacked in some additional functionality. I'll try to post it later.
Title: Re: Getting started with AVR programming
Post by: soggybag on April 14, 2009, 12:30:35 PM
Right on, I can't wait to see it, I'm sure I will learn something new.

I had tried making the Maestro FSH-1 filter sample and hold a while ago and had bad luck with clock noise. I also tried to make a 9v version that also had trouble with clock noise. Then I had the idea to do it a uC. Which I think will solve this clock problem, and cut down on the number of parts.

At the moment I'm working on making an actual pedal. I drew up a layout last night. Give me a few more days. I'll post some pictures when it's finished.