ATTiny85 PWM sweep question

Go To Last Post
8 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

So far my code works to set a DC voltage on the ADC input, obtain a 8 bit value from the ADC result and produce a PWM output on pin 6 of the MCU by plugging the ADC value into the TOP register.

The ADC 8 bit value is used to set the TOP or slowest frequency of the PWM output.

The BOTTOM value is fixed at 1, that is the fastest frequency of the PWM output.

My next task is to have the PWM output start with the ADC 8 bit value put into OCR0A then subtract 1 from the OCR0A register and do another PWM cycle.

Continuing to do this until the TOP equals the BOTTOM then increment the OCR0A register by one until TOP is reached again.

Finally read the ADC again for another 8 bit value and repeat the cycle.

In addition I need to be able to set the amount of times the PWM output repeats the very same frequency per OCR0A subtraction or addition.

This would adjust the "laziness" of the up down sweep.

Here is my logic, please let me know if I am thinking about this correctly.

1. Read ADC and get 8 bit value.

2. Put value into OCR0A and do one timer cycle.

3. Repeat this cycle "x" amount of times (laziness).

4. Decrement OCR0A by one.

5. Repeat until TOP equals BOTTOM.

6. Then sweep back up to TOP.

7. Back to step 1.

Below is the code for the first part of the project.

Is there a way to CJNE in AVR assembly to allow me to sweep the OCR0A value down then up?

;
;
;========================================================
;  SETUP THE TIMER COUNTER FOR PHASE CORRECT PWM MODE
;========================================================
;
;
;CT0 in Phase Correct PWM Mode.
;Generating a Waveform:
;OCR0A as TOP, OCR0B as compare, OC0B as output.
;Vary OCR0A to change cycle time.
;
;
loop_bak:
	rcall READ_ADC			;read input voltage and store as a 8 bit value at ADCH
;
;Set OCR0A (TOP) and OCR0B (bottom)
	ldi TEMP, ADCH
   	out OCR0A, TEMP			;Set the TOP limit as the ADCH value
  	ldi TEMP, 1
  	out OCR0B, TEMP			;set the BOTTOM limit to ground
;
;
;Configure Timer/Counter 0
;Select Phase Correct PWM Mode, and OCR0A as TOP. Use WGM Bits.
;WGM Bits are in TCCR0A and TCCR0B. Any previous settings are cleared.
;
;
;OC0B LO when COUNT = OCR0B upcounting, HI when COUNT = OCR0B downcounting.
	ldi TEMP,0b00100001
	out TCCR0A,TEMP 		; TCCR0A = 0b10000001 clear OC0A/OC0B on compare match, WGM00 = 1, WGM01 = 0
							; select COM0B1 output mode
	ldi TEMP,0b00001101
	out TCCR0B,TEMP 		; TCCR0B = 0b00001001 set clock divide by 1024, WGM02 = 1 = mode 5
;
;
	rjmp loop_bak
;
;
;
;
;
;
;===================================
;READ THE ADC INPUT AND CONVERT TO
;A 8 BIT VALUE. 00000000 = 0V
;11111111 = 5v
;RESULTS ARE AUTOMATICALLY STORED
;IN ADCH REGISTER
;===================================
;
;
READ_ADC:
	sbi portb, NU2			;turn on "ADC running" pulse on pin 3 of MCU, WATCH WITH SCOPE
	sbi ADCSRA, ADSC  		;start conversion ADSC to 1 (zeros when done)
loopX:   
	sbic ADCSRA, ADSC  		;ADSC bit goes low when conversion complete
 	rjmp loopX         		;not complete, keep checking
	cbi portb, NU2			;turn off "ADC running" pulse on pin 3 of MCU
	ret
;
;

BADBAUD

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Is there a way to CJNE in AVR assembly
no, you will need 3 instructions to read OCR0A into a register, check it for 0 (TST) and then a BRNE or BREQ.

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks John

BADBAUD

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John,
I have one other related question.

My circuit works and I can apply a DC voltage to the ADC
input and see the PWM pulses change on my scope.

The code shows what I am doing to generate the PWM pulse.

My problem is I need to determine when the code has generated one PWM pulse and when that pulse has finished.

This way I can decrement or increment the TOP value
to obtain a sweep up and down.

The ADC input is read as a 8 bit value and is set at the initial TOP before a sweep up then down is ran.

Then the ADC is read again to obtain another TOP value.

Setting a DC voltage on the ADC input looks like the PWM generator is working perfectly.

It's when I try to vary the TOP value then start the PWM generator then vary the TOP and start the PWM generator again that the waveform looks disjointed.

Should I turn on the PWM generator and leave it running, then vary TOP while it is running or turn on the PWM generator and read some "pulse done" interrupt at which point I would vary the TOP value then re-enable the PWM generator by setting a bit?

;========================================================
;  SETUP THE TIMER COUNTER FOR PHASE CORRECT PWM MODE
;========================================================
;
;
;CT0 in Phase Correct PWM Mode.
;Generating a Waveform:
;OCR0A as TOP, OCR0B as compare, OC0B as output.
;Vary OCR0A to change cycle time.
;
;
;
PWM_GEN:
;
;Set OCR0A (TOP) and OCR0B (bottom)
;
	mov TEMP, TOPSET
   	out OCR0A, TEMP		    ;Set the TOP limit
  	ldi TEMP, 1
  	out OCR0B, TEMP			;set the BOTTOM limit to 1
;
;
;Configure Timer/Counter 0
;Select Phase Correct PWM Mode, and OCR0A as TOP. Use WGM Bits.
;WGM Bits are in TCCR0A and TCCR0B. Any previous settings are cleared.
;
;
;OC0B LO when COUNT = OCR0B upcounting, HI when COUNT = OCR0B downcounting.
	ldi TEMP,0b00110001
	out TCCR0A,TEMP 		; TCCR0A = 0b10000001 clear OC0A/OC0B on compare match, WGM00 = 1, WGM01 = 0
							; select COM0B1(bit 5 set)/B0(bit 4 set) output mode, inverse PWM output of just B1 set
	ldi TEMP,0b00001101
	out TCCR0B,TEMP 		; TCCR0B = 0b00001001 set clock divide by 1024, WGM02 = 1 = mode 5
;
;
	ret

$ Fixed code tags - JS $

BADBAUD

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Remember that you need to press the code button twice, before pasting and AFTER pasting. Otherwise simply highlight the code portion and click on the code button once.

I have only used PWM to dim LEDs, a single pulse glitch, if it does happen, would not be noticed.

So I leave PWM running and update OCR whenever, the hardware takes care of when it gets updated I think.

There MAY BE cases where this may not work well, will need to wait for more experts for further advice. :-)

John Samperi

Ampertronics Pty. Ltd.

https://www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I thought, maybe, that I needed to enable a timer interrupt so I added this at the start of the program but the result is the same. Sure hope some timer expert jumps in soon.

	ldi TEMP, (1<<TOIE1)
	out TIMSK, TEMP			;enable timer interrupt

BADBAUD

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Is there a way to CJNE in AVR assembly to allow me to sweep the OCR0A value down then up?

? I don't see what "CJNE" would do for you.

Anyway, why not just keep your "setpoint" in a register? then when you adjust it, the comparison flags are set for BNE or whatever and the value just needs an OUT/STS to be applied to the OCR register.

Sure, you can use the OCR register to hold your "variable". But as you are seeing the code may not be as streamlined and you still need a working register (or two) to do the operations.

From what is shown, it is all no matter--a few registers and flash locations used; many still available.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I think you want to generate a tone based on the pot position. I'd read the pot and stuff the value in the OCR in CTC mode using toggle mode. I used to have a buddy with a mini moog and when you adjust the pulse width the square wave tone gets fatter and thinner (the skinnier pulse has more hi freqs), but PWM doesnt affect the freq, and the freq doesnt affect the duty cycle (toggle mode is always 50%). Did I guess that you want a variable freq square wave correctly?

Imagecraft compiler user