Go to Post I don't even care if it doesn't work as well as they would like. YOU MADE IT. You may never use it, but you made it. AWESOME. Every year there has been 1 team (sometimes 2) that has done something that really stood out. This year 1 team has done 2 things that stand out. Thanks guys. - rees2001 [more]
Home
Go Back   Chief Delphi > Technical > Programming
CD-Media   CD-Spy  
portal register members calendar search Today's Posts Mark Forums Read FAQ rules

 
Closed Thread
Thread Tools Rate Thread Display Modes
  #1   Spotlight this post!  
Unread 06-04-2006, 14:18
John Gutmann John Gutmann is offline
I'm right here
AKA: sparksandtabs
FRC #0340 (GRR)
Team Role: Mechanical
 
Join Date: Feb 2005
Rookie Year: 2004
Location: rochester
Posts: 804
John Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant future
Send a message via AIM to John Gutmann Send a message via MSN to John Gutmann Send a message via Yahoo to John Gutmann
ATMEGA16 PWM

Ok so here is my problem,

I have a AVR ATMEGA16 uC made by atmel. I have normal timers working but I cannot figure out from the data sheet how to get a PWM output. I have posted on avrfreaks.net but none will post an example code for me. All they do is redirect me to ode that is not for my uC. So i decided since I know a few people on here use them if they could post some very basic example code for me which just includes basic PWM timer operation and to have to code commented so I can look at it and learn from it.

The datasheet can be found at:
http://www.atmel.com/dyn/resources/p...ts/doc2466.pdf

thank you in advanced,
John
  #2   Spotlight this post!  
Unread 06-04-2006, 22:03
Don Reid Don Reid is offline
Registered User
#0997
Team Role: Mentor
 
Join Date: Jan 2003
Rookie Year: 2002
Location: Corvallis, Oregon
Posts: 45
Don Reid will become famous soon enough
Re: ATMEGA16 PWM

Here is a pwm module I wrote. It is currently set up for an ATMega8, so the register names may need to be changed slightly, but I have used a version of this code on an ATMega16.

This does direct motor control PWM, 0 - 100%, not RC servo PWM. If that is what you want, you need to adjust the period and limit the range.
Attached Files
File Type: h pwm.h (787 Bytes, 2240 views)
File Type: c pwm.c (2.2 KB, 3703 views)
__________________
Don Reid
  #3   Spotlight this post!  
Unread 06-04-2006, 22:56
John Gutmann John Gutmann is offline
I'm right here
AKA: sparksandtabs
FRC #0340 (GRR)
Team Role: Mechanical
 
Join Date: Feb 2005
Rookie Year: 2004
Location: rochester
Posts: 804
John Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant future
Send a message via AIM to John Gutmann Send a message via MSN to John Gutmann Send a message via Yahoo to John Gutmann
Re: ATMEGA16 PWM

Usually from what I have seen for the atmegax series you can use any code from a lower processor on a higher level processor with out changing register names. I don't know if it is true but I guess I can try your code and find out.

What compiler do you use?
I am currently running AVR studio-GCC

I am going to look at some things but do you think it will be safe to hook the servo up to the STK500.

wow....that is above my reading level. If possible seeing as how I am a begginer would you mind commenting some, I mean most of that code. I have never seen the #endif and all those # commands before other than #include and #define Could you possible offer an explanation?

Also I need "main.h" and "stdint.h"

Last edited by John Gutmann : 06-04-2006 at 23:22.
  #4   Spotlight this post!  
Unread 06-04-2006, 23:28
Tristan Lall's Avatar
Tristan Lall Tristan Lall is offline
Registered User
FRC #0188 (Woburn Robotics)
 
Join Date: Aug 2001
Rookie Year: 1999
Location: Toronto, ON
Posts: 2,484
Tristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond reputeTristan Lall has a reputation beyond repute
Re: ATMEGA16 PWM

Quote:
Originally Posted by sparksandtabs
wow....that is above my reading level. If possible seeing as how I am a begginer would you mind commenting some, I mean most of that code. I have never seen the #endif and all those # commands before other than #include and #define Could you possible offer an explanation?
Compiler directives. (That link is for C++, but it's the same idea in C.)
  #5   Spotlight this post!  
Unread 07-04-2006, 12:00
Don Reid Don Reid is offline
Registered User
#0997
Team Role: Mentor
 
Join Date: Jan 2003
Rookie Year: 2002
Location: Corvallis, Oregon
Posts: 45
Don Reid will become famous soon enough
Re: ATMEGA16 PWM

Quote:
Originally Posted by sparksandtabs
Usually from what I have seen for the atmegax series you can use any code from a lower processor on a higher level processor with out changing register names. I don't know if it is true but I guess I can try your code and find out.
When a newer processor add resources the register names may change, for example with one UART there is UBRRL, but with 2 UARTS there is UBRR0L and UBRR1L.

Quote:
What compiler do you use?
I use avr-gcc on Linux

Quote:
I am going to look at some things but do you think it will be safe to hook the servo up to the STK500.
I don't think a 5V logic signal can hurt a servo even if it doesn't like the timing. The power to the servo needs to come from a source that can supply enough current.

Quote:
wow....that is above my reading level. If possible seeing as how I am a begginer would you mind commenting some, I mean most of that code. I have never seen the #endif and all those # commands before other than #include and #define Could you possible offer an explanation?

Also I need "main.h" and "stdint.h"
The #ifdefs include or don't include parts of the code for different purposes. the SIM set creates a version that runs on a workstation and simulates the behavior. The pwm simulation isn't very interesting, it just returns the setting multiplied by a constant. The PWM_INT set causes an interrupt every cycle.

You should look at the register settings this code does, and look at the manual sections for those registers to understand how it uses the timer to do PWM. Then you can write you own code or modify this to do what you want.

main.h isn't very much:

Code:
#define F_CPU 14745600UL

extern int direction;	// 1 = right side, -1 = left side (reverse)
stdint.h is part of the standard C library. It came with avr-gcc. You can do without it by changing "uint8_t" to "unsigned char" etc.
__________________
Don Reid
  #6   Spotlight this post!  
Unread 12-04-2006, 11:52
intellec7's Avatar
intellec7 intellec7 is offline
108 programmer
AKA: Gustavo
FRC #0108 (SigmaC@ts)
Team Role: Programmer
 
Join Date: Sep 2005
Rookie Year: 2006
Location: Hollywood, Florida
Posts: 65
intellec7 is on a distinguished road
Send a message via AIM to intellec7 Send a message via MSN to intellec7
Re: ATMEGA16 PWM

If you want to generate a pulswidth of 0 - period (0-100%) I generally used Timer 1 because it has to Output Compare Units (A and B).
The code that I use to set up is in asm, because I'm an assembler junkie.

Code:
 ;Init Timers
;Timer 1 16 bit 2 output compare to drive motors


	ldi		temp,0b10110001 ;Clear OC1A/OC1B on compare match, set at top
	out		TCCR1A,temp		;PWM Phase Correct 8bit

	ldi		temp,0b00000001	;prescaler is 1
	out		TCCR1B,temp
The way I have it, it does not generate interupts, the Atmega hardware has two pins, OC1A and OC1B, this allows you to do 16 bit pwm on two channels.
If you want to control RC servos, which are a PWM wave with the PWM from anywhere from .5 ms to 2.5 ms every ~50 hz (20 ms) then I have a pretty inefficient code, but it gets the job done. BTW this is all using a 16mHz crystal.
Code:
;Timer 0 (to call servo routine every 10 ms
	
	ldi		temp,0b00001101
	out		TCCR0,temp	;set prescaler to 1024 and clear timer on compare match

	ldi		temp,0b00000010
	out		TIMSK, temp	;generate an interupt on compare match 16mhz/1024/156=100 hz
	
	ldi		temp,156
	out 	OCR0, temp
	;we want to execute the actual servo subroutine 50 hz, but the timer
	;doesnt go that slow, so we call the servo every 100 hz, and only execute 
	;the code every other call
I first have a timer that calls an adress every 10 ms, but in the actual subroutine it only executes the code every even call.
Code:
Servo: ;update servo positions, should call every 20ish ms called by interupt
	push	temp
	push    temp2
	in		temp, SREG
	push	temp
	
	dec		ServoSt		;this is to activatre the routine only every other interupt 
	tst		ServoSt		;since it is called every 10ms
	brne	Servexit
		
	ldi		ServoSt, 2
	clr		ServCoun
	sbi		Servport,Serv1	; Servport is the port and Serv1 is the pin
	sbi		Servport,Serv2
	sbi		Servport,Serv3
	sbi		Servport,Serv4
;	rcall	Delay200	;this is to optomize the range of the servo
	rcall	Delay200	;to 255, because no servo signal should ever be
	rcall	Delay200    ;less than ~400-600 us
	ser		temp		;this is to execute the below code for 2 ms then leave

Serloop:
	dec		ServCoun 	;servo counter, is decremented ~ every 7.5 us
Ser1:
	cp		ServCoun,Servo1	;sees if the servo counter is more or = to the
	brsh	Ser2			;desired servo value
	cbi		Servport,Serv1
	nop						;an attempt to make it equal if servo is met or not
Ser2:
	cp		ServCoun,Servo2
	brsh	Ser3
	cbi		Servport,Serv2
	nop
Ser3:
	cp		ServCoun,Servo3
	brsh	Ser4
	cbi		Servport,Serv3
	nop
Ser4:
	cp		ServCoun,Servo4
	brsh	Ser5
	cbi		Servport,Serv4
	nop
Ser5:
 	;continue if more servos
	
	rcall	Delay7
	dec		temp
	brne	Serloop

ServExit:
	pop		temp
	out		SREG,temp
	pop		temp2
	pop		temp
	reti
I swear it looks prettier in the text editor.
all of the names temp, temp2, Serloop, ServSt, Servo1- 4 are all registers. To change the servo position change the value of Servo1-4.

AND one more thing, Delay200, Delay7 are two delay loops. Their code:
Code:
Delay7:
; each cycle =  62.5 ns (16 MHz)
; number of processor cycle = 112 = 40 uS
; total delay ~7 useconds 
	;clr DelayCounter1	;1 (A)
	ldi DelayCounter1, 35	;
DelayLoop2:					;
	dec DelayCounter1	;60 x 1 (B)
	brne DelayLoop2		;1 x 1 if no branch (C), 255 x 2 if branch (D)
						;        (A)  (B)   (D)  (C)   
						; so far: 1 + 60 + 118 + 1 = 180 cycles * 62.5ns
						;                             
						; 1 + N + (N-1)*2 + 1 = 1 + 3N -2 + 1 = 3N 
						; N=213 --> 40 uS	
	ret

Delay200:
	ldi	DelayCounterMS, 5 ;40*5=200 useconds
Delay200msloop:
	call Delay40
	dec DelayCounterMS
	brne Delay200msloop
	ret
(note Delay200 depends on Delay40!!)
Code:
Delay40:
; each cycle =  62.5 ns (16 MHz)
; number of cycle = 213 = 40 uS (not processor cycles)
; total delay 40 useconds (slightly less)
	;clr DelayCounter1	;1 (A)
	ldi DelayCounter1, 210	;1 (was 213, 210 tuned with Locic Analy)
DelayLoop1:					;
	dec DelayCounter1	;256 x 1 (B)
	brne DelayLoop1		;1 x 1 if no branch (C), 255 x 2 if branch (D)
						;        (A)  (B)   (D)  (C)   
						; so far: 1 + 256 + 510 + 1 = 768 cycles * 270 ns --> 207 useconds
						;                             768        * 62.5   -->  48 useconds
						; 1 + N + (N-1)*2 + 1 = 1 + 3N -2 + 1 = 3N 
						; N=213 --> 40 uS
	ret
:sigh: it's ugly, and inificient, but it did the job for me. If anything IM me or PM me.
[Edit for code tags, thanks Matt Krass]

Last edited by intellec7 : 12-04-2006 at 13:54.
  #7   Spotlight this post!  
Unread 12-04-2006, 12:56
Matt Krass's Avatar
Matt Krass Matt Krass is offline
"Old" and Cranky. Get off my lawn!
AKA: Dark Ages
FRC #0263 (Sachem Aftershock)
Team Role: Mentor
 
Join Date: Oct 2002
Rookie Year: 2002
Location: Long Island, NY
Posts: 1,187
Matt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond reputeMatt Krass has a reputation beyond repute
Send a message via AIM to Matt Krass
Re: ATMEGA16 PWM

Quote:
Originally Posted by intellec7
If you want to generate a pulswidth of 0 - period (0-100%) I generally used Timer 1 because it has to Output Compare Units (A and B).
The code that I use to set up is in asm, because I'm an assembler junkie.
<SNIP!>

:sigh: it's ugly, and inificient, but it did the job for me. If anything IM me or PM me.

Might I recommend the use of [ code] and [ /code] tags?

Code:
;Init Timers
;Timer 1 16 bit 2 output compare to drive motors


	ldi		temp,0b10110001 ;Clear OC1A/OC1B on compare match, set at top
	out		TCCR1A,temp		;PWM Phase Correct 8bit

	ldi		temp,0b00000001	;prescaler is 1
	out		TCCR1B,temp

The way I have it, it does not generate interupts, the Atmega hardware has two pins, OC1A and OC1B, this allows you to do 16 bit pwm on two channels.
If you want to control RC servos, which are a PWM wave with the PWM from anywhere from .5 ms to 2.5 ms every ~50 hz (20 ms) then I have a pretty inefficient code, but it gets the job done. BTW this is all using a 16mHz crystal.

;Timer 0 (to call servo routine every 10 ms
	
	ldi		temp,0b00001101
	out		TCCR0,temp	;set prescaler to 1024 and clear timer on compare match

	ldi		temp,0b00000010
	out		TIMSK, temp	;generate an interupt on compare match 16mhz/1024/156=100 hz
	
	ldi		temp,156
	out 	OCR0, temp
	;we want to execute the actual servo subroutine 50 hz, but the timer
	;doesnt go that slow, so we call the servo every 100 hz, and only execute 
	;the code every other call

I first have a timer that calls an adress every 10 ms, but in the actual subroutine it only executes the code every even call.

Servo: ;update servo positions, should call every 20ish ms called by interupt
	push	temp
	push    temp2
	in		temp, SREG
	push	temp
	
	dec		ServoSt		;this is to activatre the routine only every other interupt 
	tst		ServoSt		;since it is called every 10ms
	brne	Servexit
		
	ldi		ServoSt, 2
	clr		ServCoun
	sbi		Servport,Serv1	; Servport is the port and Serv1 is the pin
	sbi		Servport,Serv2
	sbi		Servport,Serv3
	sbi		Servport,Serv4
;	rcall	Delay200	;this is to optomize the range of the servo
	rcall	Delay200	;to 255, because no servo signal should ever be
	rcall	Delay200    ;less than ~400-600 us
	ser		temp		;this is to execute the below code for 2 ms then leave

Serloop:
	dec		ServCoun 	;servo counter, is decremented ~ every 7.5 us
Ser1:
	cp		ServCoun,Servo1	;sees if the servo counter is more or = to the
	brsh	Ser2			;desired servo value
	cbi		Servport,Serv1
	nop						;an attempt to make it equal if servo is met or not
Ser2:
	cp		ServCoun,Servo2
	brsh	Ser3
	cbi		Servport,Serv2
	nop
Ser3:
	cp		ServCoun,Servo3
	brsh	Ser4
	cbi		Servport,Serv3
	nop
Ser4:
	cp		ServCoun,Servo4
	brsh	Ser5
	cbi		Servport,Serv4
	nop
Ser5:
 	;continue if more servos
	
	rcall	Delay7
	dec		temp
	brne	Serloop

ServExit:
	pop		temp
	out		SREG,temp
	pop		temp2
	pop		temp
	reti

Code:
Delay7:
; each cycle =  62.5 ns (16 MHz)
; number of processor cycle = 112 = 40 uS
; total delay ~7 useconds 
	;clr DelayCounter1	;1 (A)
	ldi DelayCounter1, 35	;
DelayLoop2:					;
	dec DelayCounter1	;60 x 1 (B)
	brne DelayLoop2		;1 x 1 if no branch (C), 255 x 2 if branch (D)
						;        (A)  (B)   (D)  (C)   
						; so far: 1 + 60 + 118 + 1 = 180 cycles * 62.5ns
						;                             
						; 1 + N + (N-1)*2 + 1 = 1 + 3N -2 + 1 = 3N 
						; N=213 --> 40 uS	
	ret

Delay200:
	ldi	DelayCounterMS, 5 ;40*5=200 useconds
Delay200msloop:
	call Delay40
	dec DelayCounterMS
	brne Delay200msloop
	ret
 (note Delay200 depends on Delay40!!)

Delay40:
; each cycle =  62.5 ns (16 MHz)
; number of cycle = 213 = 40 uS (not processor cycles)
; total delay 40 useconds (slightly less)
	;clr DelayCounter1	;1 (A)
	ldi DelayCounter1, 210	;1 (was 213, 210 tuned with Locic Analy)
DelayLoop1:					;
	dec DelayCounter1	;256 x 1 (B)
	brne DelayLoop1		;1 x 1 if no branch (C), 255 x 2 if branch (D)
						;        (A)  (B)   (D)  (C)   
						; so far: 1 + 256 + 510 + 1 = 768 cycles * 270 ns --> 207 useconds
						;                             768        * 62.5   -->  48 useconds
						; 1 + N + (N-1)*2 + 1 = 1 + 3N -2 + 1 = 3N 
						; N=213 --> 40 uS
	ret
__________________
Matt Krass
If I suggest something to try and fix a problem, and you don't understand what I mean, please PM me!

I'm a FIRST relic of sorts, I remember when we used PBASIC and we got CH Flightsticks in the KoP. In my day we didn't have motorized carts, we pushed our robots uphill, both ways! (Houston 2003!)
  #8   Spotlight this post!  
Unread 14-04-2006, 19:46
John Gutmann John Gutmann is offline
I'm right here
AKA: sparksandtabs
FRC #0340 (GRR)
Team Role: Mechanical
 
Join Date: Feb 2005
Rookie Year: 2004
Location: rochester
Posts: 804
John Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant futureJohn Gutmann has a brilliant future
Send a message via AIM to John Gutmann Send a message via MSN to John Gutmann Send a message via Yahoo to John Gutmann
Re: ATMEGA16 PWM

Do you happen to have anything in C? Just a quick and easy code that will show me how to do it.

What should my timer be set at? 8mhz I am guess to get the most efficient use of your processor.

What Timer should I use?

What is the easiest way to run 2 servos at once?
Closed Thread


Thread Tools
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
reading hobby PWM sciguy125 Programming 2 17-10-2005 20:47
FYI about using PWM 13-16 with interrupts cabbagekid2 Programming 6 22-01-2005 00:54
Using an Operator Interface with the 2004 EDU RC wirelessly Dave Flowerday Robotics Education and Curriculum 34 19-04-2004 19:06
pwm 13-15 wayne 05 Programming 2 04-10-2003 12:08
PWM and burning out motors patrickrd Technical Discussion 7 19-06-2003 15:30


All times are GMT -5. The time now is 23:00.

The Chief Delphi Forums are sponsored by Innovation First International, Inc.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi