Full Version : OSSI Sine Wave Generator (AVR ASM)
avr >>ASSMBLER ROUTINES >>OSSI Sine Wave Generator (AVR ASM)


AVR_Admin- 05-07-2006
Sine Wave Generator.

Use a TINY2313 and clock it with 16MHz crystal.

If we dont want to use an external DAC we only have digital outputs
that must be filtered. In order to do this job with very simple filters
use a "sample rate" as high as possible. Thats what oversampled DACs in audio
do in a very clever way.

So connect a simple RC-lowpass ( 10kOhm and 220 nF ) to Pins PORTB.0, PORTB.1 and PORTB.2 for the 3 phases.

Since we need 3 outputs and have only a single limited PWM on the chip use another approach:

Call it the DPM (Dirty Pulse Modulation) approach. It tries to achieve something similar as a PWM but
simpler and in some respects even better. (Search the web for "Simple Digital Control of Converters
using Building Blocks" to obtain a reference.)

Suppose you have a 8 bit accumulator. In each "sample-period" you add a constant value x
to this accu (as in the DDS phase-accumulator). If this addition yields a CARRY, you output
a 1 (5 Volts) during the next "sample-period". Else you output a 0 (0 Volts).
Than the mean voltage at the output is simply x/256 * 5Volt. So the mean output voltage
can be controlled by x. The resolution is given by the size of the accumulator.
If we add 128 we get a simple 1:1 square-wave with a 2.5Volt mean value.
Its period is two times the "sample-period". So a quite high frequency (compared
with a PWM of same resolution) is used in the mid-range.

So we expect, that the energy of the "noise" is more in a higher frquency region
as compared with a constant-frequency PWM. It is also more "random". So perhaps we
can filter it out better. (This is indeed the case !)

A DPM is (I think) compuationally simpler. so where do we arrive if we actually implement it ?

My implemenation works as follows:

Sine-table as 256 values each 8-bit in flash.
24 bit DDS accumulator for sampling this table.
Sample this table for the 3 phases with different offsets added.
Convert the 3 sampled waveforms to analog by DPM technique.

Interrupt routine needs approx. 2 mikroseconds (TINY2313 at 16MHz clock).
Use 250kHz interrupt rate. ( So processor load is approximately 50 percent)

Measure Signals after low-pass filters:

Amplitude is 4.2 Volts peak-peak. This is less than 5Volts due to lowpass !
Spectral purity (measured with spectrum analyzer):
harmonics and other spurs are down at least 60dB.

But never watch the pin PINB.0 directly, its incredible that this digital "noise" contains our signal in such a pure form and can be filterd that simple.


CODE

; OSSI 7.th may 2006
; generate three phase-shifted 50 Hz sine-signals
; outputs on PIN PORTB.0 PORTB.1 PORTB.2
; filter each sgnal with RC lowpass  10k , 220nF
; output amplitude (measured) 4.2V peak-peak
; spectral purity: SPURs are down at least 60dB (measured)
;
;
; 16.0 MHz Clock
; Interrupt Rate = DDS rate = 250 kHz = 16MHz/64  
; DDS accumulator size 24 bit = 3 bytes
; DDS frequency setting to generate 50Hz
; Deltadds = 50Hz/250kHz*(2^24)=3355.4432.. = approx 3355
      .nolist
     .include "tn2313def.inc"
     .list


.def    SREGsav = r2  // save status there
.def PHASEshiftB =r3  // 120 degrees phase shift
.def PHASEshiftC =r4  // 240 degrees phaseshift

.def delta0 =r5   // hold 24 bit phase increment of DDS
.def delta1 =r6
.def delta2 =r7

.def    temp =r16  // used as temporary at many places

.def DDS0 =r17  // 3 byte DDS accumulator
.def DDS1 =r18
.def DDS2 =r19

.def pattern =r20  // hold bit pattern there

.def DPMa =r21  // dirty pulse modulation registers
.def DPMb =r22
.def DPMc =r23

 rjmp RESET    // Reset Handler
 rjmp RESET
 rjmp RESET
 rjmp RESET
 rjmp RESET
 rjmp RESET
 rjmp TIM0_OVF   // Timer0 Overflow Handler
;
;---------------------------------------------------------------------------
;
.equ page1 = $0100 // store sine-table on 256 word boundary !!
.org page1
.include "sinus1.inc"
;
;---------------------------------------------------------------------------
;

RESET:  ldi  temp, low(RAMEND) // Main program start
       out  SPL,temp

       ldi  temp,$0ff     // set port D 0 as output
       out  DDRD,temp

       ldi  temp,0b00000111    // set port B bit 0..2 as

output
       out  DDRB,temp

 ldi  temp,$03     // fast pwm
 out  TCCR0A,temp
 ldi  temp,$009    // fast pwm

OCRA=TOP CLK src=interal CLK
 out  TCCR0B,temp
 ldi  temp,63    // interrupt

every 64 clocks
 out  OCR0A,temp
 
 ldi  temp,$02
 out  TIMSK,temp    // timer0

overflow int enable
 
 ldi  temp,low(3355)  // setup phase

increment for 50Hz
 mov  delta0,temp
 ldi  temp,high(3355)
 mov  delta1,temp
 ldi  temp,0
 mov  delta2,temp


 clr  DPMa    // initialize

DPMs
 clr  DPMb
 clr  DPMc

 ldi  temp,85    // set phase

shifts
 mov  PHASEshiftB,temp
 ldi  temp,171
 mov  PHASEshiftC,temp

 sei       //

start the show
 
LP:  rjmp LP      // and loop

around
 
;---------------------------------------------------------------------------
;
; this routine needs approximately 4 mikroseconds (measured) to execute
;
TIM0_OVF:        //

interrupt
 in  SREGsav,SREG   // save

status
  sbi  PORTD,0     //

signal start of interrupt handler

 out  PORTB,pattern   // we output

pattern generated by interrupt before
         

// this gives small jitter
 clr  pattern     //

reset pattern for new generation by OR in bits

 add  DDS0,delta0    //

execute 24 bit DDS
 adc  DDS1,delta1
 adc  DDS2,delta2

 ldi  ZH,high(2*page1)  // prepare ZH

for sinus-table accesses

         

// generate phase A signal
 mov  ZL,DDS2     //

get phase from DDS
 lpm  r0,Z     //

get sinus table value
 add  DPMa,r0     //

use it for DPM control of output A
 brcc noCYa     // and

generate OUTPUT A bit
 ori  pattern,0b00000001  // set

appropriate bit on CY
noCYa:
         

// generate phase B signal
 mov  ZL,DDS2     //

get phase from DDS
 add  ZL,PHASEshiftB   // add phase

shift
 lpm  r0,Z
 add  DPMb,r0
 brcc noCYb
 ori  pattern,0b00000010  
noCYb:
         

// generate phase C signal
 mov  ZL,DDS2
 add  ZL,PHASEshiftC
 lpm  r0,Z
 add  DPMc,r0
 brcc noCYc
 ori  pattern,0b00000100  
noCYc:

 cbi  PORTD,0     //

sign

//
 .db 128,131
 .db 134,137
 .db 140,144
 .db 147,150
 .db 153,156
 .db 159,162
 .db 165,168
 .db 171,174
 .db 177,179
 .db 182,185
 .db 188,191
 .db 193,196
 .db 199,201
 .db 204,206
 .db 209,211
 .db 213,216
 .db 218,220
 .db 222,224
 .db 226,228
 .db 230,232
 .db 234,235
 .db 237,239
 .db 240,241
 .db 243,244
 .db 245,246
 .db 248,249
 .db 250,250
 .db 251,252
 .db 253,253
 .db 254,254
 .db 254,255
 .db 255,255
 .db 255,255
 .db 255,255
 .db 254,254
 .db 254,253
 .db 253,252
 .db 251,250
 .db 250,249
 .db 248,246
 .db 245,244
 .db 243,241
 .db 240,239
 .db 237,235
 .db 234,232
 .db 230,228
 .db 226,224
 .db 222,220
 .db 218,216
 .db 213,211
 .db 209,206
 .db 204,201
 .db 199,196
 .db 193,191
 .db 188,185
 .db 182,179
 .db 177,174
 .db 171,168
 .db 165,162
 .db 159,156
 .db 153,150
 .db 147,144
 .db 140,137
 .db 134,131
 .db 128,125
 .db 122,119
 .db 116,112
 .db 109,106
 .db 103,100
 .db 97,94
 .db 91,88
 .db 85,82
 .db 79,77
 .db 74,71
 .db 68,65
 .db 63,60
 .db 57,55
 .db 52,50
 .db 47,45
 .db 43,40
 .db 38,36
 .db 34,32
 .db 30,28
 .db 26,24
 .db 22,21
 .db 19,17
 .db 16,15
 .db 13,12
 .db 11,10
 .db 8,7
 .db 6,6
 .db 5,4
 .db 3,3
 .db 2,2
 .db 2,1
 .db 1,1
 .db 1,1
 .db 1,1
 .db 2,2
 .db 2,3
 .db 3,4
 .db 5,6
 .db 6,7
 .db 8,10
 .db 11,12
 .db 13,15
 .db 16,17
 .db 19,21
 .db 22,24
 .db 26,28
 .db 30,32
 .db 34,36
 .db 38,40
 .db 43,45
 .db 47,50
 .db 52,55
 .db 57,60
 .db 63,65
 .db 68,71
 .db 74,77
 .db 79,82
 .db 85,88
 .db 91,94
 .db 97,100
 .db 103,106
 .db 109,112
 .db 116,119
 .db 122,125




Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.