Modifying Darrel's SSPWM resolution?


Closed Thread
Results 1 to 15 of 15

Hybrid View

  1. #1


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    I tinkered around and found that with my 8mhz int clock and 2khz pwm the prescaler was being set to 1 and ticks was 1000 per cycle. 50% duty Time on/off was 500 ticks each. This suggests that resolution can be increased to 0.1% by changing DutyCycle to a word variable and using 500 instead of 50 to represent 50% duty. I have adjsted the calculation so it now ranges from 0-1000 in steps of 1 instead of steps of 10. I also removed all the calculation routines as ticks are now known as is prescaler etc. That save quite a few bytes as well

    Darrel any comments?

    Peter

  2. #2
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    Sounds like you have it under control Peter.

    The numbers look good to me.
    DT

  3. #3


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    Is it possible to keep duty cycle a constant and vary the frequency?

  4. #4
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    That wouldn't be PWM.
    It would be a variable frequency generator.

    Much easier to do, but you don't need SSPWM.
    DT

  5. #5


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    Just as a final follow up I hacked SSPWM down to a fraction of it's original size and it works great.

    I use the 8mhz internal osc and for my reqd 2000hz freq that works out at a very simple 1000 ticks per cycle


    DEFINE INTHAND INT_CODE ' Tell PBP Where the code starts on an interrupt

    wsave VAR BYTE $20 SYSTEM '$20 Save location for the W register if in bank0
    wsave1 VAR BYTE $A0 SYSTEM ' Save location for the W register if in bank1
    wsave2 VAR BYTE $120 SYSTEM ' Save location for the W register if in bank2
    wsave3 VAR BYTE $1A0 SYSTEM ' Save location for the W register if in bank3
    ssave VAR BYTE Bank0 SYSTEM ' Save location for the STATUS register
    psave VAR BYTE Bank0 SYSTEM ' Save location for the PCLATH register

    TMR1_ON_TICKS var word Bank0 ' # of Tmr ticks for On Time
    TMR1_OFF_TICKS var word Bank0 ' # of Tmr ticks for Off Time
    TMR1_ON_VAL var word Bank0 ' # to load TMR1 for On Time
    TMR1_OFF_VAL var word Bank0 ' # to load TMR1 for Off Time

    DataFlags var byte Bank0
    SPWMstate var DataFlags.2 ' Current state of SPWM output high or low

    GIE var INTCON.7
    PEIE var INTCON.6
    TMR1IE var PIE1.0
    TMR1ON var T1CON.0

    clear 'Clear All Variables

    goto Start

    ' ------------------------------------------------------------------------
    asm
    INT_CODE
    if (CODE_SIZE <= 2)
    movwf wsave ; copy W to wsave register
    swapf STATUS,W ; swap status reg to be saved into W
    clrf STATUS ; change to bank 0 regardless of current bank
    movwf ssave ; save status reg to a bank 0 register
    movf PCLATH,w ; move PCLATH reg to be saved into W reg
    movwf psave ;6 ; save PCLATH reg to a bank 0 register
    endif

    btfss PIR1, TMR1IF ; is TMR1IF set? Timer1 Interrupt Flag
    GOTO NoTimerInt ; No. Bypass timer load
    btfss _SPWMstate ; Is Output High?
    GOTO TurnON ;9/15 ; No.

    TurnOFF
    bcf _CmdPwr ; Set CmdPwr Low
    bcf _SPWMstate ;
    BCF T1CON,TMR1ON ; Turn off timer
    MOVF _TMR1_OFF_VAL,W ; 1
    ADDWF TMR1L,F ; 1 ; reload timer with correct value
    BTFSC STATUS,C ; 1/2
    INCF TMR1H,F ; 1
    MOVF _TMR1_OFF_VAL+1,W ; 1
    ADDWF TMR1H,F ; 1
    BSF T1CON,TMR1ON ; 1 ; Turn it back on
    GOTO TimerDone ;12/27

    TurnON
    bsf _CmdPwr ; Set CmdPwr High
    bsf _SPWMstate ;
    bcf T1CON,TMR1ON ; Turn off timer
    MOVF _TMR1_ON_VAL,W ; 1
    ADDWF TMR1L,F ; 1 ; reload timer with correct value
    BTFSC STATUS,C ; 1/2
    INCF TMR1H,F ; 1
    MOVF _TMR1_ON_VAL+1,W ; 1
    ADDWF TMR1H,F ; 1
    bsf T1CON,TMR1ON ; 1 ; Turn it back on

    TimerDone
    bcf PIR1, TMR1IF ; 1/28 ; Clear Timer1 Interrupt Flag

    NoTimerInt
    Movf psave,w ; Restore the PCLATH reg
    Movwf PCLATH
    swapf ssave,w ; Restore the STATUS reg
    movwf STATUS
    swapf wsave,f
    swapf wsave,w ; 6/34 ; Restore W reg

    Retfie ; Exit the interrupt routine

    endasm
    ' ------------------------------------------------------------------------

    StartSPWM: 'Set Freq and DutyCycle before calling
    'For 2khz pwm and 8mhz clock Ticks = 1000 per cycle
    GIE = 1
    PEIE = 1
    TMR1H = 255 'Load TMR1 with 65535, First tick will cause
    TMR1L = 255 'an interrupt that will load TMR1_???_VAL
    TMR1_ON_TICKS = DutyCycle '(Must be between 100 & 900 (10-90%)
    TMR1_OFF_TICKS = 1000 - TMR1_ON_TICKS
    TMR1_ON_VAL = 65535 - TMR1_ON_TICKS + 8
    TMR1_OFF_VAL = 65535 - TMR1_OFF_TICKS + 8
    TMR1IE = 1
    T1CON = 1 'Set Timer1 prescaler to 1 and turn Timer1 on
    return

    '************************************************* ************************************
    '*********************************** Main Program ************************************
    I use a word variable for DutyCycle between 0-1000 which gives me a 0.1% resolution now a tenfold increase over the original.
    I just load DutyCyle with my reqd duty and call StartSPWM:

    Thanks to Darrel for the original code which I now understand as well making some small personal inroads into Pic Assembler

  6. #6


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    A couple more questions about this Darrel as i'm trying to understand the code.

    In your variable definitions we have

    Code:
    wsave1      VAR BYTE    $A0     SYSTEM          ' Save location for the W register if in bank1
    wsave2      VAR BYTE    $120    SYSTEM          ' Save location for the W register if in bank2
    wsave3      VAR BYTE    $1A0    SYSTEM          ' Save location for the W register if in bank3
    These are not anywhere else in the code? so i don't understand how they are used?
    I tried removing them and the program compiled correctly but started giving an eroneous display?

    In your Int code you have

    Code:
    asm
    INT_CODE
          if (CODE_SIZE <= 2)
            movwf   wsave              ; copy W to wsave register
            swapf   STATUS,W           ; swap status reg to be saved into W
            clrf    STATUS             ; change to bank 0 regardless of current bank
            movwf   ssave              ; save status reg to a bank 0 register
            movf    PCLATH,w           ; move PCLATH reg to be saved into W reg
            movwf   psave       ;6     ; save PCLATH reg to a bank 0 register
           endif
    What does " if (CODE_SIZE <= 2)" do?
    Clearly it jumps over the register saving stuff but where does CODE_SIZE come from?

    2 does that mean 2k or 2 words, bytes?

    Thanks Peter

    PS I have bought PBP3 looking forward to trying it later

  7. #7
    Join Date
    Jul 2003
    Location
    Colorado Springs
    Posts
    4,959


    Did you find this post helpful? Yes | No

    Default Re: Modifying Darrel's SSPWM resolution?

    This post should cover both of those questions.
    http://www.picbasic.co.uk/forum/show...9101#post89101

    And yes, 2 means 2K.
    It is set in the .bas or .pbpinc files.
    DT

Members who have read this thread : 0

You do not have permission to view the list of names.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts