[PIC] Using a PIC to generate square wave sweep tones (audio)

Status
Not open for further replies.
I never mentioned Pickit3, I don't have one myself but I can still debug programs. In MPLAB, if you check through the menus you will find an option to select which debugger to use, if you select the simulator instead of PM3, it will let you run the program in a simulated environment, you don't need any hardware attached at all.

I don't have MPLAB installed, I use MPLABX under Linux but if you find the 16F1508 is too recent for the MPLAB simulator, try downloading MPLABX and even if you don't want to use it, copy the assembler and simulator .exe files to your MPLAB folder, I can't try it myself (no Windows!) but I think it will work. MPLAB and MPLABX are just front ends for stand-alone assemblers and simulators so they are probably compatible.

There is nothing wrong with using the CWG but it isn't really intended for your purpose. It is optimised for driving H-bridge circuits that need dead time during the switch over so much of it's initialization isn't necessary. You are only using it as an inverter which is why I suggested hardware may be easier.

As I see it, you can configure the NCO to generate the lowest frequency in the same way as I suggested PWM should be set. Use FDC mode and put the step in frequecy in the increment registers. Still use another timer to generate say 1mS interrupts and use them as I suggested to set the step rate to the next frequency until your target is reached.

To use CWG, simply use the NCO output as the CWG source and select opposite polarities to the output pins.

Brian.
 

Thank you for your reply, Brian.

I have an old WinXP PC that runs MPLAB 8.92 and MPASM 5.51 wonderfully, but it's too old to even upgrade to Win7. I installed MPLAB X 3.05 quite a long time ago, but I never liked its UI versus 8.x (and prior to 8.x, I had used 5.x for quite a long time). I tried installing the latest version of MPLAB X on it, but the installer failed because it seems to require Win7 or higher. The PC serves its purpose well for what I use it for though, which is why I never upgraded it. I am primarily a Macintosh guy, with a late 2015 5k Retina iMac atop my desk. And while Microchip claims to have a Mac version, I have tried multiple times and failed. Failed in that once installed and the app launches and the UI displays, I get a spinning beachball forever. I have an open ticket with Microchip at this, but thus far they've not replied back. All said, I cannot run the latest version of MPLAB X for now, which is why I have been sticking with version 8.92.

I must admit that I've never used the software debugger in MPLAB 8.92 since I always just write to the chip, test, rewrite, etc. That has always worked for me, albeit, I've been using the same old chips for a long time so I know when my ASM code is good. But since I am trying out a new chip, the 16F1508, for the first time, along with its new features, I was trying to find a splattering of ASM code to confirm my own code is on the right track. Sometimes Microchip will put a little of that ASM code in its data sheets, at least, it did the in the past. But these days there's about as much C code as ASM, which is not what I am looking for.

Anyway, in MPLAB 8.92, there is a "Debugger" menu (which again, I've never used before), and within that menu is a "Select Tool" submenu, which inside that we find "4 MPLAB SIM." Choosing that causes "Run, Animate, Step Into" icons to appear, and an MPLAB SIM tab appears. Running it with my chip chosen and code loaded does nothing but produce the green dots at the bottom left of the window showing "Running." I would intuitively expect a graphic of the chip showing how the I/O responds, but nothing like that appears. I guess I will need to read up on the SIM to figure it out. But honestly, the one in MPLAB X is probably much better, so it would be good if I got to know that instead. But like I said before, I cannot run MPLAB X on my Mac or my PC for reasons already mentioned.

Thanks.
 

I wrote the ASM code below and tested it in-circuit with H-BRIDGE and 8-ohm speaker. The code doesn't include a tonal sweep. This code is simply to test a simple duo-tone sequence of 625Hz for 600ms followed by 825Hz for 600ms, repeating. I created it to verify my NCO and CWG init routine works. I verified the CWG output pins on a scope and confirmed it by listening to the speaker. The frequencies quite accurate, and my 1.5us of dead band is also correct as well. So I will proceed with the rest of my code assuming there are no problems with my CWG init routine.

Thanks.


Code ASM - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
; --------------------------------------
 
       list     p=16f1508               ; Define processor 
        
#include        p16f1508.inc            ; Variable definitions
 
; --------------------------------------
 
;               +---u---+
;          Vdd <|1    20|> Vss
;          RA5 <|2    19|> RA0/ICSPDAT
; **CLKOUT/RA4 <|3    18|> RA1/ICSPCLK
; MCLR/Vpp/RA3 <|4    17|> RA2
;    CWG1A/RC5 <|5    16|> RC0
;   *CWG1B/RC4 <|6    15|> RC1/NCO1***
;          RC3 <|7    14|> RC2
;          RC6 <|8    13|> RB4
;          RC7 <|9    12|> RB5
;          RB7 <|10   11|> RB6
;               +-------+
;   * CWG1B is inverted with respect to CWG1A.
;  ** CLKOUT = Fosc/4 (4MHz w/ HFINTOSC) when CONFIG1 = CLKOUTEN_ON.
; *** NCO output on RC1 only when NCO1CON bit6 is Set.
 
; --------------------------------------
; Configuration Bits & Error Level
; --------------------------------------
; The "& 0x3FFF" was added to fix an error in the *.inc file that causes a 303 Warning in MPASM 5.51.
;  See forum post: [url]https://www.microchip.com/forums/FindPost/714197[/url]
; Config Bits Info: \Program Files\Microchip\MPASM Suite\p16f1508.inc
 
 __CONFIG _CONFIG1, _FOSC_INTOSC & _WDTE_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF & 0x3FFF
 __CONFIG _CONFIG2, _WRT_OFF & _STVREN_OFF & _BORV_LO & _LPBOR_OFF & _LVP_OFF & 0x3FFF
 
 errorlevel -302                        ; Suppresses assembler Messages pertaining to banks, so be careful!
 
; --------------------------------------
; Custom Variable Definitions (Equates)
; --------------------------------------
CountA  EQU     0x070                   ; Memories for delay routines
CountB  EQU     0x071                   ;  (RAM Addresses 70h - 7Fh are common to all banks)
CountC  EQU     0x072              
 
; --------------------------------------
; Core Registers (present in all Banks)
; --------------------------------------
; INDF0 & INDF1
; PCL
; STATUS
; FSR0L & FSR0H & FSR1L & FSR1H
; BSR
; WREG
; PCLATH
; INTCON 
; --------------------------------------
 
        ORG     0x000                   ; Reset vector.
        goto    Main                    ; Go to main program.
        ORG     0x004                   ; Interrupt vector location 
                                        ; NOTE: W, STATUS, BSR, FSTs & PCLATH are saved 
                                        ; automatically in Shadow regs (Bank 31)
        retfie                          ; Return from interrupt.
        
Main
; ---------[ Interrupts ]-------------------------------------------
        movlw   b'01000000'             ; Interrupts disabled, PEIE bit6 enabled
        clrf    INTCON                  ; INTCON is a Core Register (in all banks)
        banksel PIE2                    ; [Bank 1]
        movlw   b'00000100'             ; NCO1IE = 1 (enabled) for NCO Interrupts
        movwf   PIE2
        banksel PIR2                    ; [Bank 0]
        clrf    PIR2                    ; Peripheral Inter. Flags (NCO1IF bit2 = 1 on Accum.Overflow)
; ---------[ Oscillator Setup ]--------------------------------------
        banksel OSCCON                  ; [Bank 1]
        movlw   b'01111000'             ; Internal OSC = 16 MHz
        movwf   OSCCON
        btfss   OSCSTAT, HFIOFR         ; Internal OSC running?
        goto    $-1                     ; No, loop until running.
        btfss   OSCSTAT, HFIOFS         ; OSC stable?
        goto    $-1                     ; No, loop until stable.
; ---------[ Ports & I/O Setup ]------------------------------------
        banksel PORTA                   ; [Bank 0] Initialize Ports.
        clrf    PORTA
        clrf    PORTB
        clrf    PORTC
        banksel LATA                    ; [Bank 2] Clear data Latches.
        clrf    LATA
        clrf    LATB
        clrf    LATC
        banksel ANSELA                  ; [Bank 3] Setup I/O.
        clrf    ANSELA                  ; PORTA = Digital I/O.
        clrf    ANSELB                  ; PORTB = Digital I/O. (NOTE: missing on 16F1503)
        clrf    ANSELC                  ; PORTC = Digital I/O.
        banksel OPTION_REG              ; [Bank 1]
        movlw   b'11000010'             ; Pull-ups Off, TMR0 Prescaler = 1:8
        movwf   OPTION_REG
        movlw   b'11111111'             ; Make CWG1A & CWG1B Inputs for now. (See CWG Setup below.)
        movwf   TRISC                   ;  PORTC 
        movlw   b'00000000'             ; All outputs
        movwf   TRISB                   ;  PORTB 
        movlw   b'11101111'             ; RA4 the only Output (pin 3)
        movwf   TRISA                   ;  PORTA 
; ---------[ CWG Setup ]------------------------------------------
; The sequence below follows "26.11 Configuring the CWG" in the PIC16(L)F1508/9 datasheet:
; [url]https://ww1.microchip.com/downloads/en/DeviceDoc/40001609E.pdf[/url]
; CWG1A (RC1) & CWG1B (RC0) are configured as Inputs for now.
        banksel CWG1CON0                ; [Bank 13]
        bcf     CWG1CON0, 7             ; Clear GxEN (bit 7) to Disable CWG.
        movlw   .20                     ; Put 20d into "CWG Rising DEAD-BAND Count Register"
        movwf   CWG1DBR                 ;  (20 clock cycles = 1.25us @ HFINTOSC=16MHz)
        movlw   .20                     ; Put 20d into "CWG Falling DEAD-BAND Count Register"
        movwf   CWG1DBF
        movlw   b'10000000'             ; GxASE(b7)=1, GxARSEN(b6)=0
        movwf   CWG1CON2                ;  (CWG in Shutdown State, Auto-Restart Disabled)
        movlw   b'10100110'             ; CWG1B(b7&6) & CWG1A(b5&4) will be LO on Shutdown, Source = NCO1
        movwf   CWG1CON1
        movlw   b'01100001'             ; Leave GxEN=0, CWG1A/B to Output pins, Normal Polarity, HFINTOSC
        movwf   CWG1CON0                ;  (CWG1A clones the NCO output, CWG1B is inverted.)
        bsf     CWG1CON0, 7             ; Set GxEN (bit 7) to Enable CWG.
        banksel TRISC                   ; [Bank 1]
        movlw   b'11001111'             ; RC4=CWG1B, RC5=CWG1A (set to Outputs)
        movwf   TRISC                   ;  PORT C
        banksel CWG1CON2                ; [Bank 13]
        bcf     CWG1CON2, 7             ; Clear GxASE to start the CWG.
; ---------[ NCO Setup ]------------------------------------------
        banksel APFCON                  ; [Bank 2]
        clrf    APFCON                  ; NCO1 function is on RC1 (NCO not using pin. See NC01CON below.)
        banksel NCO1CLK                 ; [Bank 9]
        clrf    NCO1CLK                 ; NxPWS n/a due to fixed DC, clock source HFINTOSC (16 MHz).
        clrf    NCO1ACCU                ; Clear the Accumulator (UPPER->HI->LO).
        clrf    NCO1ACCH
        clrf    NCO1ACCL
        clrf    NCO1INCH                ; HI Incr.Value = 0  (NCO1INCH must execute before NCOINCL)
        movlw   .82                     ; LO Incr.Value = 82d
        movwf   NCO1INCL                ;  Foverflow = (NCO Clock x Incr.Value)/(2^21)=626Hz square-wave
        movlw   b'10000000'             ; Enable NCO, Disable Out-pin b6, Polarity=HI(non-inverted), Fixed D.C.
        movwf   NCO1CON                 ;  Bit5 (NxOUT) is 1 when NCO output is HI, 0 when LO.
SET847
        call    DEL600m                 ; Wait 600ms.
        movlw   .111                    ; LO Incr.Value = 111d
        movwf   NCO1INCL                ;  Foverflow = (NCO Clock x Incr.Value)/(2^21)=847Hz square-wave
        call    DEL600m                 ; Wait 600ms.
        movlw   .82                     ; LO Incr.Value = 82d
        movwf   NCO1INCL                ;  Foverflow = (NCO Clock x Incr.Value)/(2^21)=626Hz square-wave
        goto    SET847
 
; NCO square wave continues to be output until NCO1CON bit7 is cleared.         
; NCO1CON bit5 (NxOUT) can be polled to determine when Accumulator Overflows (half-cycle) occur.
; Alternatively, Peripheral Interrupt PIR2 bit2 (NCOxIF) = 1 on Accumulator Overflows:
;  * NCOxIF = 1 on Accumulator Overflows, even if Interrupts are Disabled, and can be polled. 
;  * NCOxIF must be cleared before exiting the ISR, if Interrupts are Enabled.
; ------------------------------------------------------------------
DEL600m                                 ; 600ms delay routine(@Fosc=16MHz)
                movlw   .13
                movwf   CountC
                movlw   .45
                movwf   CountB
                movlw   .215
                movwf   CountA
loop            decfsz  CountA,1
                goto    loop
                decfsz  CountB,1
                goto    loop
                decfsz  CountC,1
                goto    loop
                retlw   0
        end

 
Last edited by a moderator:

Well done!

The debugger did as expected, the running dots are there to tell you the program is running. You can configure the trace function to show waveforms although it is rather counter-intuitive to configure. You can also click on lines of code to set breakpoints and very useful is the stopwatch, you can reset it at breakpoints and confirm the delay routines are working properly. You can also display memory areas, watch variable or watch registers and the simulator will highlight any that change so it's easy to follow what the program is doing. It is an excellent simulator and cycle accurate, I always use it to check my code before reaching for the hardware.

Be careful with the interrupt routines, they should be outside of 'main' and end with a retfie instruction, they should run independantly of the main code rather than being 'in line' with it. I would also suggest using labels instead of "$-1" types of targets. It works fine but the code isn't portable across all devices. It tells the compiler to generate a jump/branch to the previous memory address but on some PICs the instructions are wider and it would have to be changed to "$-2" to work the same. If you label the previous line and jump/branch to it the code becomes re-usable on other devices.

With that fixed, your next step would be to generate periodic interrupts, I would suggest every 1mS. TMR0 or TMR1 should be able to do it easily. The interrupts would set the speed of frequency sweep and it would be constant regardless of the program flow.

I appreciate the problem with older OS. I normally use Linux so MPLABX is no problem but I can dual-boot into Windows XP if I have to. I do not have or want any later versions of Windows, MS have taken a lot of my money already, they are not getting any more!

Brian.
 
Reactions: JDW_

    JDW_

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…