Copyright K.Unsworth and Unicorn Publications International 1990-2013 All Rights Reserved. Terms and Conditions.

;Testbed-multi-channel-pwm  v1.0 (c)K.Unsworth 18-10-2012

;for Home use only. NOT FOR COMMERCIAL USE

;16 channel pwm on port b at 40hz



;clock switch works .

;

;new osciliscope shows 83.989 Mhz pic runs fast

;watchdog led flashes every 381msec instead of 400.

;80Mhz=40MIPS 2 clks per instruction



;RB = 16 pwm outputs



;3. The "__reset" label is the first label in the code section and must be    *

;   declared global. The Stack Pointer (W15) and the Stack Pointer Limit      *

;   register must be initialized to values that are past the run-time heap    *

;   space, so as to avoid corrupting user data. Initializing these registers  *

;   at the "__reset" label ensures that user data is not corrupted            *

;   accidentally. The __SP_init and __SPLIM_init literals are defined by the  *

;   linker. The linker automatically addresses above the run-time heap to     *

;   these symbols. Users can change the __SP_init and __SPLIM_init literals to*

;   suit their application.                                                   *

;                                                                             *

;4. A ".section <section_name>, <attributes>" directive declares a new section*

;   named "<section_name>" with an attribute list that specifies if the       *

;   section is located in Program Space(code), Uninitialized(bss) or          *

;   Initialized Data Space(data). Refer to the document "dsPIC 30F Assembler, *

;   Linker and Utilities User's Guide" for further details.                   *

;                                                                             *

;5. Initialize W registers: Using uninitialized W registers as Effective      *

;   Addresses(pointers) will cause an "Uninitialized W Register Trap" !       *

;                                                                             *

;6. The label "__T1Interrupt" is defined in the device linker script. The     *

;   label defines the starting location in program space of the Timer1        *

;   interrupt service routine (ISR).                                          *

;   Similarly, the linker script defines labels for all ISRs. Notice, that    *

;   the ISR label names are preceded by two underscore characters.            *

;   When users needs to write ISR code, they must use these labels after      *

;   providing them global scope. The linker will then place the ISR address in*

;   the respective interrupt vector table location in program space.          *

;   Context Save/Restore in ISRs can be performed using the double-word PUSH  *

;   instruction,PUSH.D. User can also make use of MOV.D, PUSH and PUSH.S      *

;   instructions. Refer dsPIC 30F 16-bit MCU Family Refernce Manual(DS70046)  *

;   for further details.                                                      *

;


       .equ __33fj12gp202, 1

       .include "p33fj12gp202.inc"


;*****************Configuration bits:**************************


      config __FWDT, FWDTEN_OFF              ;Turn off Watchdog Timer


;  config __CONFIG1, FNOSC_FRC & FWDTEN_OFF

;   internal rc oscilator on  and watch dog off


;  config __FOSC, FCKSM_CSECMD & IOL1WAY_OFF & OSCIOFNC_ON & POSCMD_NONE

;  clock switching on , multiple configs, i/o pins on, primary osc disabled


;  config __FOSCSEL, FNOSC_FRC & IESO_OFF

;  fast rc osc no pll ( yet), two speed osc off


;  set pll , tuning , clk div in main code then swap clocks


;from internet


 config __FOSCSEL, FNOSC_FRC

;  fast rc osc

 config __FOSC, FCKSM_CSECMD & OSCIOFNC_ON & POSCMD_NONE


; Clock Switching is enabled and Fail Safe Clock Monitor is disabled

; OSC2 Pin Function: OSC2 is Clock Output ( might need to change)

; Primary Oscillator Mode: Disabled


;Starts at 7.37 MHz with no PLL

;changes to 79.2MHz in code

;runs at 83.989 Mhz with chip i have.

;no time crytical apps so not important


;********Global Declarations: ***********************************************


       .global _wreg_init       ;Provide global scope to _wreg_init routine

                                ;In order to call this routine from a C file,

                                ;place "wreg_init" in an "extern" declaration

                                ;in the C file.


       .global __reset          ;The label for the first line of code.


        .global __T1Interrupt    ;Declar e Timer 1 ISR name global






;***************Constants stored in Program space**************************


       .section .const,psv

;       .palign 2                ;Align next word stored in Program space to an

                                ;address that is a multiple of 2



;***************** variables in Near data memory (Lower 8Kb of RAM)*************


         .section .nbss, bss, near

; var1:     .space 2               ;Example of allocating 1 word of space for

                                  ;variable "var1".

pwmcounter:  .space 2

rotatebits:  .space 2    ;storage for outputs

pwm0:   .space 2    ;channel 0

pwm1:   .space 2    ;channel 1

pwm2:   .space 2    ;channel 2

pwm3:   .space 2    ;channel 3

pwm4:   .space 2    ;channel 4

pwm5:   .space 2    ;channel 5

pwm6:   .space 2    ;channel 6

pwm7:   .space 2    ;channel 7

pwm8:   .space 2    ;channel 8

pwm9:   .space 2    ;channel 9

pwm10:   .space 2    ;channel 10

pwm11:   .space 2    ;channel 11

pwm12:   .space 2    ;channel 12

pwm13:   .space 2    ;channel 13

pwm14:   .space 2    ;channel 14

pwm15:   .space 2    ;channel 15





;********************constants for code************************




;*************Start of program**************



.text                               ;Start of Code section

__reset:

       MOV  #__SP_init, W15       ;Initalize the Stack Pointer

       MOV  #__SPLIM_init, W0      ;Initialize the Stack Pointer Limit Register

       MOV  W0, SPLIM

       NOP                       ;Add NOP to follow SPLIM initialization      

; reset all w register  this MUST be done

       CLR  W0

       MOV  W0, W14

       REPEAT  #12

       MOV  W0, [++W14]

       CLR  W14


;**************setup oscilator pll (my code)****************

;Set clock to 80Mhz = 40 MIPs

;IMPORTANT set PLL ratios before change of clock to PLL

 bclr CLKDIV,#6

 bclr CLKDIV,#7  ;PLL post =0 divide = 2

 mov  #43,w0   ;7.37/4*43=79.2275Mhz

 mov  w0,PLLFBD  ;PLL feed back divisor = 40 (38+2)


;from book

 MOV  #1,w0   ;frc with PLL, new nosc code

 

  MOV  #OSCCONH,W1  ;unlock code

 MOV  #0x78,W2

 MOV  #0x9A,W3

 MOV.B W2,[W1]   ;WRITE 0x78

 MOV.B W3,[W1]   ;WRITE 0x9A

 MOV.B W0,[W1]   ;now set type of clock

       

  MOV  #0x01,W0


 MOV  #OSCCONL,W1

 MOV  #0x46,W2

 MOV  #0x57,W3

 MOV.B W2,[W1]   ;WRITE 0x46

 MOV.B W3,[W1]   ;WRITE Ox9A


 MOV.B W0,[W1]   ;REQUEST CLOCK SWITCH

wait:

  BTSC OSCCONL,#OSWEN

;turn off bra for simulator. turn back on for real thing

  BRA  wait   ;WAIT FOR SWITCH


;****************************************************************


;set up i/o pins

 mov  #0xffff,w0  ;b1111 1111 1111 1111

  mov  w0,TRISA  ;set trisa

 mov  #0x0000,w0  ;b0000 0000 0000 0000 rb0=op

  mov  w0,TRISB  ;set trisb




;**********************************************************************


;  setup timer 1 for 0.1msec interrupts


 clr  TMR1   ;clear timer 1

 mov  #4000,w7  ;4000=100usec at 40 mips 10khz = 40hz pwm

  mov  W7,PR1   ;set timer 1 time out period when PR1=TMR1=T1 interupt

 bclr IFS0,#T1IF  ;clear t1 interupt flag IFS0,#T1IF

 bset IEC0,#T1IE  ;set interupt enable IEC0,#T1IE

 bset T1CON,#TON  ;turn on t1 16 bit timer



;************************************************************


;setup variables

  mov  #0,w0

 mov  w0,pwm0     ;set start value

 mov  w0,pwm1     ;set start value

 mov  w0,pwm2     ;set start value

 mov  w0,pwm3     ;set start value

 mov  w0,pwm4     ;set start value

 mov  w0,pwm5     ;set start value

 mov  w0,pwm6     ;set start value

 mov  w0,pwm7     ;set start value

 mov  w0,pwm8     ;set start value

 mov  w0,pwm9     ;set start value

 mov  w0,pwm10    ;set start value

 mov  w0,pwm11    ;set start value

 mov  w0,pwm12    ;set start value

 mov  w0,pwm13    ;set start value

 mov  w0,pwm14    ;set start value

 mov  w0,pwm15    ;set start value


            


;**************************************************************



;******************************************************************

;

;main loop.  

start:

;put your code here that sets the PWM mark space ratio


;ie for 25% on port 3 mov #64,pwm3


 bra  start   





;********************************************************

;

;Timer 1 Interrupt Service Routine

;Example context save/restore in the ISR performed using PUSH.D/POP.D

;instruction. The instruction pushes two words W4 and W5 on to the stack on

;entry into ISR and pops the two words back into W4 and W5 on exit from the ISR

;or push.s/pop.s for just w0-3 and SR


__T1Interrupt:

 push.s      ;save w0-3

 clr   rotatebits  ;clear storage word

 inc.b  pwmcounter  ;inc counter

 btsc  SR,#Z   ;if not zero add another

 inc.b  pwmcounter  ;dont leave at zero

  mov   pwmcounter,w0 ;put in w0

 add.b  pwm0,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm1,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm2,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm3,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm4,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm5,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm6,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm7,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm8,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm9,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm10,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm11,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm12,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm13,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm14,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word

 mov   pwmcounter,w0 ;put in w0

 add.b  pwm15,wreg  ;add the two and save result in wreg and C

 rrc   rotatebits  ;rotate carry into top of storage word


 mov   rotatebits,w0

  mov   w0,LATB   ;set/clear outputs




 bclr   IFS0, #T1IF     ;Clear the Timer1 Interrupt flag Status bit.

 pop.s      ;restore w0-3

 retfie                    ;Return from Interrupt Service routine


;***************************************************




.end                               ;End of program code in this file



16 Channel PWM for dsPIC

This is a software implementation that produces an output frequency of around 40Hz. This can be increased by shortening the timer 1 interrupt frequency. More channels can easily be added .


Download source here