Shop OBEX P1 Docs P2 Docs Learn Events
Problems getting Sinewave Generator to output full bandwidth — Parallax Forums

Problems getting Sinewave Generator to output full bandwidth

sstandfastsstandfast Posts: 39
edited 2008-08-24 00:38 in Propeller 1
Hello,

In a previous post where I was asking about the availabilty of a simulator, I alluded to the fact that I would also post my "mostly working" problem program to a different thread.· Before I do that, let me provide a little background into what this code is expected to do.· As a first venture into programming the Prop in assembly, I wanted to do something relatively simple.· I took the PWM demo code and modified it to operate as a sinewave generator.· I stored·360 8-bit values for one cycle of a DC offset sinewave into a look-up table in the COG.· This gives me 1 degree resolution per entry.· The theory is that the fixed frequency PWM signal is used to reproduce the sine wave by dynamically updating how often the duty cycle changes.· Pretty straighforward stuff I would think.· By altering how many PWM pulses, or "samples" as I call them in my code, pass between retrieving the next value or "step" from the look-up table I am able to adjust the frequency of the sine wave.· So far the code works mostly as expected.· I can generate low tones from 1 Hz "pops" up to 1KHz tones.· However, attempting to go beyond 1KHz gives problems·in the form of if a tone is generated at all it sounds the exact same pitch as the 1KHz tone.· The theoretical maximum output frequency of this setup should be the PWM frequency / #steps per cycle of Sinewave or PWM Freq / 360 in this case.· Since I am using a PWM frequency of 1MHz I should have no problem completely covering the audio band but as I said, I peak at 1KHz.

There are a few other quirks about my program that I feel I should mention.· First, increasing the PWM frequency above 1MHz results in no tone being generated.· With the Prop running at 80MHz, it should have no problem generating a 1MHz PWM signal right?· Second, when doing the bounds checking for the look-up table, I am XORing the index variable with 361 and if the result is zero, then clearing the index.· In theory, the result of the bounds checking (index XOR 361) should require the "nr" switch so that the value in "index" is unchanged.· However, for some reason, my code will not work with the "nr" switch present.confused.gif· So, this tells me that index is counting as 0, 361, 1, 360, 2, 359, etc...but from the sound of the tones produced, this is not the case.· This is why a simulator would be handy, I could watch how the look-up table was being indexed and I might be able to figure this out easier.

Anyway, now that I have talked everyone's ear off, let me post my code and see if anyone can make heads or tails of it.
CON _clkmode = xtal1 + pll16x
    _xinfreq = 5_000_000
    pwm_freq = 1_000_000
obj
  serial : "fullduplexserial"
var
  long paramater
  long cog
pub main | ticks, temp
 serial.start(31,30,0,115200)    'start the serial terminal
 waitcnt(cnt + clkfreq)          'pause 1 second
 serial.str(string("Please Enter Frequency : "))  'prompt for output frequency
 repeat      'forever loop
   ticks := serial.rxcheck  'get response
   case ticks   'parse response
     "S","s" : stop    'stop the tone
               serial.str(string("Cog Stopped"))
               serial.tx($0D)
               serial.str(string("Press 'G' to restart or enter a new frequency."))
               serial.tx($0D)
     "G","g" : if start   'start the tone
                 serial.str(string("Cog Started Successfully"))
                 serial.tx($0D)
                 serial.str(string("Press 'S' to stop or enter a new frequency."))
                 serial.tx($0D)
     $0D     : paramater := pwm_freq / (temp * 360) 'X Hz Tone * 360 Steps / Cycle = X Steps/Sec
               temp := 0                 'PWM Freq samples/Sec * 1Sec / X Steps = Y Samples/Step
               serial.str(string("Frequency accepted."))  'update new tone frequency
               serial.tx($0D)
               serial.str(string("Press 'G' to start or 'S' to stop or enter a new frequency."))
               serial.tx($0D)
     $30..$39 : temp := (temp * 10) + (ticks - $30) 'build numeric representation of entered
pub start : success
  stop
  success := cog := cognew(@entry,@paramater) + 1
pub stop
  cogstop(cog~ - 1)  
dat
entry   mov dira, diraval              'set APIN to output
        mov ctra, ctraval              'establish counter A mode and APIN
        mov frqa, #1                   'set counter to increment 1 each cycle
        mov time, cnt                  'record current time
        add time, period               'establish next period
        and index, #$00000000          'clear look-up table index
        add index, sine - 4            'initialize look-up table index
        
:loop    
        mov value, index               'get next pulse width
        rdlong freq, par               'get up to date sample count
        cmpsub count, freq wz          'test for # samples.  if #samples = samples/step count then
        if_z add index, #1             'incriment step count
        xor index, #$00000169 wz       'check for 360 steps  ***DOES NOT WORK WITH NR FLAG EVEN THOUGH IT NEEDS TO BE SET
        if_nz xor index, #$00000169    'if 360 steps, wrap back to zero
        waitcnt time, period           'wait until next period
        add count, #1                  'incriment sample counter
        neg phsa, value                'back up phsa so that it
        jmp #:loop                     'loop for next cycle
diraval long |< 10                     'APIN=10
ctraval long %00100 << 26 + 10         'NCO/PWM APIN=10
period  long 80_000_000 / pwm_freq     'PWM Period = (_clkfreq / PWM Freq)                      
time    res 1                          
value   res 1                          
count   res 1
index   res 1                          'index into Sine Look-Up Table
freq    res 1                          'Sets frequency of output'd sine wave
sine
     long 127, 129, 131, 134, 136, 138, 140, 143, 145, 147, 149, 151, 154, 156, 158, 160, 162, 164, 167
     long 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199, 200, 202, 204
     long 206, 208, 209, 211, 213, 214, 216, 218, 219, 221, 222, 224, 225, 226, 228, 229, 231, 232, 233
     long 234, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 246, 247, 248, 249, 249, 250, 251
     long 251, 252, 252, 253, 253, 253, 254, 254, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
     long 255, 254, 254, 254, 253, 253, 253, 252, 252, 251, 251, 250, 249, 249, 248, 247, 246, 246, 245
     long 244, 243, 242, 241, 240, 239, 238, 237, 236, 234, 233, 232, 231, 229, 228, 226, 225, 224, 222
     long 221, 219, 218, 216, 214, 213, 211, 209, 208, 206, 204, 202, 200, 199, 197, 195, 193, 191, 189
     long 187, 185, 183, 181, 179, 177, 175, 173, 171, 169, 167, 164, 162, 160, 158, 156, 154, 151, 149
     long 147, 145, 143, 140, 138, 136, 134, 131, 129, 127, 125, 123, 120, 118, 116, 114, 111, 109, 107
     long 105, 103, 100, 098, 096, 094, 092, 090, 087, 085, 083, 081, 079, 077, 075, 073, 071, 069, 067
     long 065, 063, 061, 059, 057, 055, 054, 052, 050, 048, 046, 045, 043, 041, 040, 038, 036, 035, 033
     long 032, 030, 029, 028, 026, 025, 023, 022, 021, 020, 018, 017, 016, 015, 014, 013, 012, 011, 010
     long 009, 008, 008, 007, 006, 005, 005, 004, 003, 003, 002, 002, 001, 001, 001, 000, 000, 000, 000
     long 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 000, 001, 001, 001, 002, 002, 003
     long 003, 004, 005, 005, 006, 007, 008, 008, 009, 010, 011, 012, 013, 014, 015, 016, 017, 018, 020
     long 021, 022, 023, 025, 026, 028, 029, 030, 032, 033, 035, 036, 038, 040, 041, 043, 045, 046, 048
     long 050, 052, 054, 055, 057, 059, 061, 063, 065, 067, 069, 071, 073, 075, 077, 079, 081, 083, 085
     long 087, 090, 092, 094, 096, 098, 100, 103, 105, 107, 109, 111, 114, 116, 118, 120, 123, 125, 127

I will also attach the source file so that you can download and load it straight into Propeller Tool.· The only dependancy it has is the "FullDuplexSerial" object.

Please let me know if you see anything or can help me get debugging information from the generator to the serial port.

Thanks in advance,

Shawn

p.s.· I am using the Propeller Demo Board.

Comments

  • AleAle Posts: 2,363
    edited 2008-08-23 09:52
    If those longs are after the res directive... that will not work.

    The RES directive does not reserve any real space it will only declare a named symbol at that address. Use LONG instead or put your RES directives at the end of your table.

    BTW: Why you did not use the internal SINE table ?
  • sstandfastsstandfast Posts: 39
    edited 2008-08-24 00:38
    Ale said...
    If those longs are after the res directive... that will not work.

    The RES directive does not reserve any real space it will only declare a named symbol at that address. Use LONG instead or put your RES directives at the end of your table.
    Ok, when I get home this evening I will try your suggestion and see what that does.· Thanks for that!
    Ale said...
    BTW: Why you did not use the internal SINE table ?
    Since this was·supposed to be more of a learning experiment and not a "useful" project , I wanted to break it down one small step at a time.· My initial read through the Prop. manual gave me the impression that there were some complex manipulations required to retrieve the values from the internal table.··It·seemed much more·straightforward·to just include·my own table.· Plus, it gave me an opportunity to play with different addressing schemes in Prop. assembly.· Really, doing it this way offered no·benefit other than it simplified the coding, this was after all my first attempt at writing assembly for the Prop.

    I'll come back later with my findings after I get an oppertunity to try your suggestions.

    Shawn
Sign In or Register to comment.