Shop OBEX P1 Docs P2 Docs Learn Events
Changing variable value over time — Parallax Forums

Changing variable value over time

JaspJasp Posts: 7
edited 2012-12-18 07:02 in Propeller 1
Hi everybody,

I'm working on a thesis in which I make an audioprocessor which is controlled by the Propeller. It's my first project ever with Propeller and I tried to teach the programming to myself, I don't have a background in programming. I only know the spin-language, assembly is still unknown to me. After three days of trying to solve the last problem in my program, I still have four days before my deadline, so I'm getting kind of nervous. What I try to do is change the value from a variable to another value in a certain time interval.

I attached the program in this message, PUB-routine 'CH1' is the routine which starts one of the following PRI-routines (Gate, Expander, Compressor or Limiter). In those PRI-routines I have to change the value of CV from 3093 to another (calculated) value. When some conditions are met, CV has to go back from the calculated value to 3093. Everything works as long as I don't introduce the timing stuff. The time in which CV has to change between values is controlled by the ATCK- en RLSE-variables (GATCK and GRLSE for Gate, EATCK and ERLSE for Expander, ...). All those times are in milliseconds.

The 'Thesis, with time problem'-object is the top-object in which the times have to be introduced. 'Scriptie' is the original top-object where I tried some stuff already.

I tried to explain myself as good as I can. I hope somebody can help... Does anybody have any hints?

Thanks!

Jasper

Comments

  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-12-17 12:53
    Jasper,

    I don't have time today to look at your code but monitoring time is pretty easy with the Propeller.

    Here's code that updates a counter every half second. The time interval could easily be changed and some other task besides displaying the counter could be done whenever the interval is reached.
    CON
      _CLKMODE = XTAL1 + PLL16X
      _CLKFREQ = 80_000_000
      _DebugBaud = 115200
      
    VAR
      long previousTime, timeInterval
      long counter
      
    OBJ
      Pst : "Parallax Serial Terminal"
      
    PUB Main
    
      waitcnt(clkfreq * 3 + cnt)    ' time to open terminal window.
      Pst.Start(_DebugBaud)
      Pst.Clear
     [COLOR=#ff0000][B] timeInterval := clkfreq / 2 ' half second
      previousTime := cnt
    [/B][/COLOR]  repeat
        [COLOR=#ff0000][B]if cnt - previousTime > timeInterval
          previousTime += timeInterval
    [/B][/COLOR]      Pst.Position(3, 5)
          Pst.Str(string("counter = "))
          Pst.dec(++counter)
     
    

    Edit: The red font messes up the formatting a bit. I think the code will still work as it is now.
  • JaspJasp Posts: 7
    edited 2012-12-17 15:05
    Thanks for the speedy reply, Duane.

    I tried implementing your code and I think there's just something strange going on elsewhere. I attached a small piece of code to this message and commented it.
    Somehow the attacktime (EATCK) doesn't work at all, the releasetime introduces some crazy audio artefacts.

    Am I overlooking something in this code?

    Thanks!

    Jasper
  • T ChapT Chap Posts: 4,223
    edited 2012-12-17 15:16
    Jasp

    Welcome to the forum. It is not clear what your problem is from your post. Assuming that your code is fine and should work as written, often when variables are not showing up as intended, it is possible the stack space is being ran over. In your case, you can do a quick test by changing StackDac to 48, also the other stacks may be increasing as well. If a stack is too small, it can run over to the next address in memory beyond the stack allocation you, causing problems there.
  • JaspJasp Posts: 7
    edited 2012-12-18 02:29
    Ok, I'll try to explain it one more time.

    CV is a variable that is calculated with some other variables, the calculated value will always be lower than 3093.
    There are two time-variables (EATCK and ERLSE), both of them are expressed in milliseconds.

    Before CV was calculated, it has a 'standard'-value of 3093, what I want to do is bring CV from 3093 to the calculated value in the ERLSE-time.
    What I tried to do is calculate the amount of clock cycles that have to pass each time CV is subtracted by one. I made a loop that subtracts 1 from 3093 and then waits the calculated amount of clock cycles each time the program goes through the loop.

    When some conditions are met however, CV has to go back from the calculated value to 3093. This has to happen in the EATCK-time.

    Somehow, the code I included in my previous message won't work. I tried increasing the stackspace for all cogs, but I still have the same problem. I don't know where to look for the problem anymore, so I tried my luck on this forum.

    Jasper
  • Mike GMike G Posts: 2,702
    edited 2012-12-18 03:49
    Sounds like you need a millisecond timer. A number is decremented every millisecond until the number reaches a calculated value or the process timesout. Is this correct?
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-18 04:03
    Intendation?

    If this is your original intendation ...
        if (ADin > ((InCon * ETRHD) + 3280)) and (ADYN == 1)                        'Condition to end routing
          if EATCK > 0 and CV < 3093                                                'If EATCK (in ms) is more than 0 and CV < 3093
            ATime := ((EATCK * 80_000)/(3093 - CV))                                 'Calculate amount of clock cycles that have to pass eacht time CV gets added by 1
            CntInit := cnt                                                          'Same thing
            Repeat
              if cnt - CntInit => ATime
              CntInit += ATime
              CV++
              if CV => 3093
                CV := 3093
                Quit    
    

    ... then it should propably be
        if (ADin > ((InCon * ETRHD) + 3280)) and (ADYN == 1)                        'Condition to end routing
          if EATCK > 0 and CV < 3093                                                'If EATCK (in ms) is more than 0 and CV < 3093
            ATime := ((EATCK * 80_000)/(3093 - CV))                                 'Calculate amount of clock cycles that have to pass eacht time CV gets added by 1
            CntInit := cnt                                                          'Same thing
            Repeat
              if cnt - CntInit => ATime
                CntInit += ATime
                CV++
                if CV => 3093
                  CV := 3093
                  Quit    
    

    But you should also give us an idea of the ranges we talk about. If your ATime and RTime is shorter than the execution time of the loop, then you might not get what you want!



    Yay .... 2000th post for me ;o)
  • JaspJasp Posts: 7
    edited 2012-12-18 04:15
    Ok, I'm a bit embarrased about the intendation. I fixed that now.

    About the timing, CV can go from 3093 to a value as low as 0 in a time as short as 1ms. So when CV has to go from 3093 to 0, I tried to split 1ms in 3093 loopcycles in which each loopcycle decrements CV with 1.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-18 04:45
    Ok ... then just have a look at your calculation:

    ATime := ((EATCK * 80_000)/(3093-CV))

    What you say is that EATCK can be 1 and CV can be 0! ATime in this case would be 25. 25 clock cycles are 6 PASM instructions (only 4 cycle instructions). So, no jump and no HUB-access.
    I'm sorry, but what you want to do is even to fast for PASM, unless I missed something.

    Where is CV used? I'd guess that the place where it is read is not faster than your Expander routine. Maybe you should calculate an increment which is bigger than 1 but therefore gives you more ATime.

    What I'd do is to measure the time that your loop needs. This should give you an idea about how big ATime needs to be minimum.
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-18 05:40
    Did you check how many values you send to the DAC per second? It does not make sense to update CV more frequently than your DAC function can send it to the MCP4922! Are you happy with the quality of your signal?

    The unrolled loop of DAC is:
      repeat
        ' function call DA.set(0 , CV)
        data := (Channel << 15) + (1 << 13) + (1 << 12) + Value
        data ><= 16
    
        outa[CS] := 0
    
        repeat 16
          outa[SDI] := data & 1
          outa[SCK] := 1
          outa[SCK] := 0
          data >>= 1
    
        outA[CS] := 1
    

    So, as is, this should give you some time for the Expander, but it could also be improved! For example you could move the MCP-code into your own code and optimize:
    PUB init ' Just a 1 to 1 copy from MCP4922.spin
    ....
    PUB DAC | ChannelMask, data
      init( PinDACS, PinDASCK, PinDASDI)
      ChannelMask := ( 0 << 15 ) + (1 << 13) + (1<<12)
      repeat
        data:= ChannelMask + CV
        data ><= 16
        outa[CS] := 0
        repeat 16
          outa[SDI] := data
          outa[SCK] :=1
          outa[SCK] :=0
          data >>= 1
        outa[CS] := 1
    
  • JaspJasp Posts: 7
    edited 2012-12-18 06:23
    I changed RTime and ATime the way you said it in your previous message. The increment is 10 now, and the smallest possible RTime is still longer than the time needed to execute the loop. The strange audio artefacts are gone now, so that's one problem solved.

    Just to make everything a bit clearer: CV is the control voltage used to control an analog VCA.

    Now, something else happened: the attack-part doesn't work at all and the release-part sounds like a hold (CV stays 3093 for the RTime and than suddenly drops to it's calculated value). I'm thinking there's something wrong with the if-conditions in the Expander-routine. This is how the code looks now:
    PRI Expander
    
      ADYN := 1                                                                     
      if EHOLD > 0                                                                 
        waitcnt ((EHOLD * (Clkfreq / 1000)) + cnt)                                  
      Repeat
        ADin := AD.in(1)                                                           
        RMSdB := ((ADin - 3280) / InCon)                                            
        REDdB := (-(3093 - CV) / OutCon)                                          
        CVc := 3093 + (OutCon * EGAIN) + (OutCon * (((RMSdB - ETRHD) * ERTIO) - (RMSdB - ETRHD)))
        if ERLSE > 0 and CVc < CV and CV == 3093                                                  
          RTime := 10 * ((ERLSE * 80_000)/(CV - CVc))                                   
          CntInit := cnt                                                          
          Repeat until CV =< CVc                                                                  
            if cnt - CntInit > RTime                                                
              CntInit += RTime
              CV -= 10                                                                     
        if (ERLSE == 0 and CVc < CV) or (CV <> 3093)                                                                   
          CV := CVc                                                                
        if (ADin > ((InCon * ETRHD) + 3280)) and (ADYN == 1)                       
          if EATCK > 0                                                             
            ATime := 10 * ((EATCK * 80_000)/(3093 - CV))                                
            CntInit := cnt                                                          
            Repeat until CV => 3093
              if cnt - CntInit => ATime
                CntInit += ATime
                CV += 10    
          ADYN := 4
          Return
        if (ADin =< ((InCon * GTRHD) + 3280)) and (ADYN == 1) and (GBP == 1)       
          Gate
          Return 
        if (EBP == 0) and (ADYN == 1)
          ADYN := 4
          Return
    

    About the DAC-stuff, I'm not sure I understand what you're saying. Looking at the datasheet, I think the DAC-value is updated every 16 clockcycles.

    In any case, thanks for your support already!
  • MagIO2MagIO2 Posts: 2,243
    edited 2012-12-18 06:50
    Yes, the DAC is updated every 16 clockcycles, but it means clock cycles generated by the propeller in the repeat 16 - loop AND NOT directly related to propeller clock cycles. So, I'd guess that you have something around 3500 samples per second on the output-channel. I thought that we talk about audio and there I'd expect to see sample rates around 44k samples for low-end and > 96k samples for high-end audio-processing.
  • JaspJasp Posts: 7
    edited 2012-12-18 07:02
    Those sample rates are when I would proces audio in de Propeller. In my project all the audio stays analog though. I'm measuring a RMS-value of the analog signal and I'm trying to control a voltage controlled amplifier with the Prop. The audio goes through the analog VCA and the prop controls the amplification. So a lower sample rate shouldn't be a problem.
Sign In or Register to comment.