Shop OBEX P1 Docs P2 Docs Learn Events
Troubles with POSEDGE mode in SPIN counter — Parallax Forums

Troubles with POSEDGE mode in SPIN counter

Hey all,
Having issues with my latest project. I'm driving a computer fan with a PWM output from the Propeller then trying to sense the frequency through the onboard sensor on the fan (yellow wire of a 3-wire fan). I'm seeing where as the PWM duty cycle (and such the speed of the fan) increases, the counter is reading back decreasing values, which tells me something is definitely off.
End goal is to be able to query the user for a PWM value, run the fan at that set duty cycle, sense the number of pulses that come from the fan (2 per revolution is what I've heard everywhere) and convert this to RPM before sending the value back over the serial connection. I know that the PHSA conversion for RPM isn't accurate at the moment, just trying to find something that might work with no luck. Any tips would be greatly appreciated.
{Propeller Attempt 1
The debug terminal will request a PWM duty cycle percentage. The user will enter this into the terminal and hit enter.
One cog of the Propeller will drive a 5kHz signal at the set percentage for a span of 5 seconds.
Simultaneously, a second core will measure the number of pulses in a 1 second period and multiply this by 30 to get the fan's RPM.
The fan speed will be output to the user in the debug terminal, and then the program will wait for another duty cycle to test.}

CON
        _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
        _xinfreq = 5_000_000
        PWMFreq = 10000
        Fan=0
        Sense=1

VAR
  long duty
  long OnTime
  long OffTime
  long RPM
  long Period
  long FreqCounterStack[100]
   
OBJ
  PST :"Parallax Serial Terminal"
  
PUB Main
  Period:=clkfreq/PWMFreq
  PST.Start(115200)
  dira[Fan]~~
  outa[Fan]~
  repeat
    PST.Str(String("Please input a duty cycle in percent for the fan to be run at: "))
    duty:=PST.DecIn
    OnTime:=(Period/100)*duty
    OffTime:=Period-OnTime
    cognew(FreqCounter,@FreqCounterStack)
    repeat (PWMFreq*5)
      outa[Fan]~~
      waitcnt(OnTime+cnt)
      outa[Fan]~
      waitcnt(OffTime+cnt)
    PST.NewLine
    PST.Str(String("The fan is running at "))
    PST.Dec(RPM)
    PST.Str(string(" RPM."))
    waitcnt(5*clkfreq+cnt)
    PST.Clear

PUB FreqCounter
  waitcnt(clkfreq+cnt)
  ctra[30..26]:=%01010
  ctra[5..0]:=%01010
  frqa:=1
  phsa:=0
  waitcnt(clkfreq+cnt)
  RPM:=phsa*30
  cogstop(cogid)

Comments

  • Why do you run FreqCounter in its own cog and constantly restart it? What if you run it in the same cog (and get rid of the "cogstop(cogid)" and add a "ctra~" instead to turn off the counter)? Or, what if you only start FreqCounter once and have it loop? The way you're doing it could be made to work, but it seems rather convoluted to me. There are probably simpler ways.
  • Did you check the output of the sensor with your scope and hz counter? If it is a simple square wave 3.3v a freq counter should work.
  • Is the fan by any chance a brushless type? If so it might not respond well to PWM, and the tach might expect constant power same as the fan motor.
  • DirA[Pin] := In
    CTRA :=0
    CTRA := (%01010<<26) | (%001 <<23) | (0 <<9) | (Pin)

    FRQA := 1000
    PHSA := 0
    WaitCnt( 80_000_000 + CNT)
    Frequency := PHSA/1000
  • Then do the math for the blade count.
  • Took a similar approach to my previous attempt, but switched from directly attempting to read the frequency to reading the time between each falling edge of the integrated sensor and trying to calculate RPM from there. Fan is a 5 blade count fan and is running from a 9V supply. Sense line is pulled up with a 10k resistor to VDD, then running through a 220 ohm current limiting resistor to pin 1 of the propeller.

    Here's the updated program. I've removed the second cog program and am just watching the sense pin for now to try to clock how many counts go by between falling edges of the sense pulses. Current issues I'm running into are that the timeDifferential reading always seems to be the exact same regardless of the fan speed, and that the PeriodTime and RPM calculations do not appear to be running. Does anybody have any ideas for me or stupid mistakes to point out?
    {Propeller Attempt 2
    The debug terminal will request a PWM duty cycle percentage. The user will enter this into the terminal and hit enter.
    One cog of the Propeller will drive a 5kHz signal at the set percentage for a span of 5 seconds.
    Simultaneously, a second core will measure the number of pulses in a 1 second period and multiply this by 30 to get the fan's RPM.
    The fan speed will be output to the user in the debug terminal, and then the program will wait for another duty cycle to test.}
    
    CON
            _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
            PWMFreq = 10000
            Fan=0
            Sense=1
    
    VAR
      long duty
      long OnTime
      long OffTime
      long RPM
      long Period
      long FreqCounterStack[100]
      long initialClock
      long FinalClock
      long periodTime
      long timeDifferential
       
    OBJ
      PST :"Parallax Serial Terminal"
      
    PUB Main
      Period:=clkfreq/PWMFreq
      PST.Start(115200)
      dira[Fan]~~
      outa[Fan]~
      ctra[30..26]:=%01100
      ctra[5..0]:=%000001
      repeat
        PST.Str(String("Please input a duty cycle in percent for the fan to be run at: "))
        duty:=PST.DecIn
        OnTime:=(Period/100)*duty
        OffTime:=Period-OnTime
        repeat (PWMFreq*3)
          outa[Fan]~~
          waitcnt(OnTime+cnt)
          outa[Fan]~
          waitcnt(OffTime+cnt)
        PST.STR(string("Now checking pulse width."))
        repeat while ina[Sense]~
          waitcnt(2+cnt)
        repeat while ina[Sense]~~
          waitcnt(2+cnt)
        initialClock:=cnt
        repeat while ina[Sense]~
          waitcnt(2+cnt)
        repeat while ina[Sense]~~
          waitcnt(2+cnt)
        PST.NewLine
        PST.Str(string("Now computing period time."))
        finalClock:=cnt
        timeDifferential:=cnt-initialClock
        PSt.NewLine
        PST.Str(string("timeDifferential="))
        PST.Dec(timeDifferential)
        periodTime:=(timeDifferential)/(clkfreq/100)
        PST.NewLine
        PST.Str(string("periodTime= "))
        PST.Dec(periodTime)
        PSt.NewLine
        PST.Str(string("Now restarting PWM."))
        repeat (PWMFreq*2)
          outa[Fan]~~
          waitcnt(OnTime+cnt)
          outa[Fan]~
          waitcnt(OffTime+cnt)
        RPM:=600000/(periodTime*5)
        PST.NewLine
        PST.Str(String("The fan is running at "))
        PST.Dec(RPM)
        PST.Str(string(" RPM."))
        PST.NewLine
        PST.NewLine
    
  • Tracy AllenTracy Allen Posts: 6,656
    edited 2016-12-09 17:21
    I'd suggest you simplify and try one thing at a time. Work on reading the tach and leave the PWM for later. Run the fan on DC, and vary its speed by changing the DC voltage from 9V down to as low as it still turns.

    Your program sets the NEGDET mode on pin 1 for ctra, but it does not make use of that. Instead you have a sequence using waitcnt. If you want to shy away from using the cog counters, you'll be better off using waitpeq and waitpne. Maybe something like this...
    PUB ticker | ticks
      repeat
        waitpne(0,|<SENSE,0)   ' wait for sense high
        waitpeq(0,|<SENSE,0)   ' then low
        ticks := -cnt          ' start measurement
        waitpne(0,|<SENSE,0)   ' one complete tach cycle
        waitpeq(0,|<SENSE,0)
        ticks += cnt   ' clock ticks for one tach cycle
        PST.Str(string("periodTime= "))
        PST.Dec(periodTime)
        waitcnt(clkfreq+cnt)    ' pace the measurements
    

    By the way, waitcnt(2+cnt) is bound to give you problems, because spin takes 381 ticks to execute the command. The minimum value is, I think, waticnt(381+cnt). That is about 5 microseconds at 80MHz clkfreq.
Sign In or Register to comment.