Shop OBEX P1 Docs P2 Docs Learn Events
Smart pin modes 001001 (pulse/cycle output) or 001011 (transition output) for small frequencies. — Parallax Forums

Smart pin modes 001001 (pulse/cycle output) or 001011 (transition output) for small frequencies.

Hello all,

I understand that the minimum frequency for smart pin modes of pulse/cycle or transition output is clkfreq/2^16. If clock frequency is 160MHz it results in 2441Hz. Is it possible to go lower frequencies? It seems like a simple task of toggling output for a given number of times with 100Hz should be possible using smart pin modes, no?

Any input here would be greatly appreciated,

Alex

Comments

  • evanhevanh Posts: 15,913
    edited 2023-03-24 11:21

    Are you wanting a specific pulse count? If not then there is a plain frequency mode too. Frequency mode has much wider range of frequencies.

    As for using those two pulse modes you've listed, one option is lower the sysclock frequency to suit your needs.

    Given the low rate desired, another option is use timed bit-bashing. Maybe even use the interrupt system.

  • evanhevanh Posts: 15,913
    edited 2023-03-24 12:03

    This worked:

    CON
        _xtlfreq = 20_000_000
        _clkfreq = 6_553_500
    
    PUB  tester()
        debug( udec(clkfreq), uhex(clkmode) )
        pinstart( 56, P_PULSE | P_OE, 65535 | (32768<<16), 0 )
        repeat
            wypin( 56, 5 )
            waitms( 500 )
    

    EDIT: Or maybe a cleaner sysclock would be:

    CON
        _xtlfreq = 20_000_000
        _clkfreq = 6_000_000
    
    PUB  tester()
        debug( udec(clkfreq), uhex(clkmode) )
        pinstart( 56, P_PULSE | P_OE, 60000 | (30000<<16), 0 )
        repeat
            wypin( 56, 5 )
            waitms( 500 )
    

    EDIT2: Ah, and transition mode allows sysclock to be doubled:

    CON
        _xtlfreq = 20_000_000
        _clkfreq = 12_000_000
    
    PUB  tester()
        debug( udec(clkfreq), uhex(clkmode) )
        pinstart( 16, P_TRANSITION | P_OE, 60000, 0 )
        repeat
            wypin( 56, 10 )
            waitms( 500 )
    
  • The problem is that the silicon docs are very sparse and Chip uses his own terminology instead of what is cvommonly used for other processors.

    Mode "Pulse/Cycle Output (%00100)" is actually a PWM mode. X15..0 sets the frequency and X31..0 sets the duty cycle.

    Mode "Transition Output (%00101)" generates a fixed number of pulses. X15..0 is the clock prescaler and Y31..0 sets the number of transitions = double the number of pulses. It's useful for generating clock pulses for serial communication such as SPI. But it doesn't offer much resolution and it doesn't work for frequencies <clkfreq/2^16.

    If you need PWM for motor control or similar applications I'd rather use the PWM modes (%01000 to %01011). If you need a continous frequency I'd use "NCO frequency (%00110). There you have 16 bits for the prescaler and 32 bits resolution for the frequency. You can go well below 1Hz.

  • JonnyMacJonnyMac Posts: 9,102
    edited 2023-03-24 14:50

    I needed a slow LED blinker and managed to do it like this.

    pub slow_blink(pin, duty) | x
    
    '' Blink LED slowly (0.5Hz) at duty cycle (0% to 100%)
    
      x.word[0] := 1 #> (clkfreq << 1) / 10_000 <# $FFFF
      x.word[1] := 10_000
    
      duty := (0 #> duty <# 100) * 100
    
      pinstart(pin, P_OE | P_PWM_SAWTOOTH, x, duty)
    

    This is in free-running PWM mode, though.

  • Thank you for responses everyone. I can see that using continuous modes will give me desired frequencies, however it will not provide option of exact pulse count output. 100 Hz was only an example, it could also be 1Hz, so lowering clock frequency is not desirable. I am thinking maybe of combining two or even three smart pins somehow, but nothing comes to mind. The goal is not to have repeat cycle, only one set up and smart pins should do the rest.

  • evanhevanh Posts: 15,913
    edited 2023-03-24 21:48

    Smartpins can't chain each other without using an output pin. Inputs only come from the physical pins. There is one exception to this, a smartpin input can come from a cog's OUT bit, which in turn can be from a streamer.

    But even using a second external pin, or OUT bit, won't help for those pulse modes, since the clock source divider is not via an input.

    The streamer could do it without using the smartpins. Its NCO is 32-bit (does get relatively coarse at low frequencies). But there is only one streamer per cog.

    Ah, how about use the smartpin frequency mode and count its pulses? Then disable the smartpin when completed. Could even use a second smartpin to internally do the counting. No extra physical pins toggling at least.

  • "Ah, how about use the smartpin frequency mode and count its pulses? Then disable the smartpin when completed. Could even use a second smartpin to internally do the counting. No extra physical pins toggling at least."

    This is exactly what I am thinking about, but how stop smart pin without checking the counter in the repeat cycle?

  • evanhevanh Posts: 15,913
    edited 2023-03-25 00:52

    It needs the cog to participate once the counting is done but the pulse counting itself can be done with a smartpin in a counter mode. Typically the next smartpin over would be chosen to count the pulses from the frequency smartpin.

    Okay, typed up an example:

  • @evanh said:
    It needs the cog to participate once the counting is done but the pulse counting itself can be done with a smartpin in a counter mode. Typically the next smartpin over would be chosen to count the pulses from the frequency smartpin.

    Okay, typed up an example:


    quantity := 5
    frequency := 100.0
    newpulses( TRUE )

    >

    repeat
    checkcount()

    >

    ' do other stuff


    This will definitely work, thank you for this example, but looks like 'do other stuff' either has to wait until all pulses are completed or it has to be called constantly while 'doing other stuff'. I wish there was a solution where once we issued newpulses( TRUE ) we could start 'doing other stuff' immediately and not worry about checkcount(). If frequency > clkfreq/2^16 we can use smart pin set to transition output (mode 001011) for achieving such task. It seems that there is no simple way (or maybe no way at all) to do so for lower frequencies.

  • Edit: 'do other stuff' either has to wait until all pulses are completed or checkcount() has to be called constantly while 'doing other stuff'

  • evanhevanh Posts: 15,913

    It's free to perform other tasks immediately the pulses start. No delays required, the delay I have is only for making a gap in the demo to observe on a scope.

    It does have to check up on progress checkcount() at least twice per pulse so as to stop the frequency smartpin before it can produce more than desired. Twice being the Nyquest limit for asynchronous sampling like this.

    However, this interval of starting to stopping of pulses can be estimated too. So the first check for stopping might be a lot later because you know there is enough pulses occurring in the mean time.

  • evanhevanh Posts: 15,913

    Oh, that do other stuff comment should have been placed within the prior repeat loop. I was a little untidy there.

  • JonnyMacJonnyMac Posts: 9,102
    edited 2023-03-25 16:44

    I don't know if this is helpful, but I was working on a servo driver yesterday that used the pulse mode with simple period math. This runs inline as a test, but this kind of code running in its own cog should allow several channels with decent accuracy; especially at low frequencies.

    pub pulses_out(pin, pwidth, period, count)
    
      pinstart(pin, P_PULSE | P_OE, clkfreq/1_000_000, 0)
    
      org
                            getct     pr0
    .p                      add       pr0, period
                            wypin     pwidth, pin
    
    .w                      getct     pr1
                            cmp       pr1, pr0                      wcz
            if_b            jmp       #.w
                            djnz      count, #.p
      end
    

    The pwidth parameter is pulse width in microseconds; the period is in system ticks.

  • evanhevanh Posts: 15,913

    Yeah, if you've got a bunch of these operating at once then throwing a whole cog at managing them might be a good idea.

  • This is all very helpful, thank you.

Sign In or Register to comment.