//------------------------------------------------------------------------------ // This file is part of the QMdbSim project, a Microchip Simulator framework for // QSpice C-Block components. See the GitHub repository at // https://github.com/robdunn4/QSpice/ for the complete project, current // sources, documentation, and demonstration code. //------------------------------------------------------------------------------ /* * dsPIC33FJ128MC802: RB0 pulse, 8us HIGH / 2us LOW, in cycle-exact assembly, * bypassing the XC16 C runtime startup (CRT). Companion to main_c.c. * * No special linker settings are needed. The CRT's __reset is a weak symbol, * so the __reset defined below overrides it: the CRT is still linked (about * 195 bytes) but never executes. Verified in the map file with XC16 v2.10: * __reset = 0x282 (the ASM code), CRT at 0x200. * Do NOT put -nostartfiles in the xc16-ld options; the linker misreads it * and the build fails because the .elf is never written. */ #include //------------------------------------------------------------------------------ // Configuration bits // // Clock: Boot on the internal FRC oscillator (7.37MHz), then switch to FRC // with PLL in code. PLL settings: N1 = 2, M = 43, N2 = 2. // Fosc = 7.37MHz / 2 * 43 / 2 = 79.23MHz // Fcy = Fosc / 2 = 39.61MHz (nominal 40 MIPS) // The dsPIC33F executes 1 instruction cycle per 2 oscillator clocks, so the // SIMCLK in the QSpice schematic should be Fcy (39.61MHz). //------------------------------------------------------------------------------ // FOSCSEL #pragma config FNOSC = FRC // Start on FRC; switch to FRCPLL in code #pragma config IESO = OFF // Two-speed oscillator start-up disabled // FOSC #pragma config POSCMD = NONE // Primary oscillator off (RA2/OSC1 is I/O) #pragma config OSCIOFNC = ON // OSC2 pin is digital I/O (RA3) #pragma config IOL1WAY = OFF // Allow multiple peripheral pin remaps #pragma config FCKSM = CSECMD // Clock switching on, fail-safe monitor off // FWDT #pragma config FWDTEN = OFF // Watchdog timer disabled // FPOR #pragma config FPWRT = PWR1 // Power-up timer off (default is 128ms) // FICD #pragma config JTAGEN = OFF // JTAG disabled //------------------------------------------------------------------------------ // RB0 pulse in assembly, CRT bypassed // // The linker script's reset vector does "goto __reset", and __reset is // defined here (overriding the CRT's weak __reset), so the pin code runs a // few cycles after reset. No C variables, no stack frames, no data // initialization. SFR names (LATB, TRISB, ...) resolve through the device // linker script. // // Timing at Fcy = 40MHz nominal (39.61MHz actual), 25ns per cycle: // HIGH = 320 cycles = 8us, LOW = 80 cycles = 2us, period = 10us (100kHz). //------------------------------------------------------------------------------ __asm__( " .section .text,code \n" " .global __reset \n" "__reset: \n" // RB0 low output first, so the pin is defined as early as possible " bset AD1PCFGL, #2 ; AN2/RB0 -> digital \n" " bclr LATB, #0 ; latch low before enabling output \n" " bclr TRISB, #0 ; RB0 = output \n" // stack pointer and limit (not used by this code, but cheap insurance) " mov #__SP_init, w15 \n" " mov #__SPLIM_init, w0 \n" " mov w0, SPLIM \n" // PLL: N1 = 2, M = 43, N2 = 2 -> Fosc = 79.23MHz, Fcy = 39.61MHz " mov #0x3000, w0 ; CLKDIV reset value 0x3040 with \n" " mov w0, CLKDIV ; PLLPOST = 0 (/2), PLLPRE = 0 (/2)\n" " mov #41, w0 ; M = 43 \n" " mov w0, PLLFBD \n" // clock switch to FRC with PLL (NOSC = 0b001), unlock sequences per FRM " mov #0x01, w0 ; NOSC = FRCPLL \n" " mov #OSCCONH, w1 \n" " mov #0x78, w2 \n" " mov #0x9A, w3 \n" " mov.b w2, [w1] \n" " mov.b w3, [w1] \n" " mov.b w0, [w1] \n" " mov #0x01, w0 ; OSWEN = 1 \n" " mov #OSCCONL, w1 \n" " mov #0x46, w2 \n" " mov #0x57, w3 \n" " mov.b w2, [w1] \n" " mov.b w3, [w1] \n" " mov.b w0, [w1] \n" // On real hardware, wait for the switch and PLL lock here: // 1: btsc OSCCONL, #0 / bra 1b (OSWEN clears when switch completes) // 2: btss OSCCON, #5 / bra 2b (LOCK) // Omitted since MDBCS doesn't require it. // main loop: cycle counts in brackets "loop: \n" " bset LATB, #0 ; [1] RB0 HIGH \n" " repeat #317 ; [1] \n" " nop ; [318] \n" " bclr LATB, #0 ; [1] RB0 LOW (HIGH = 320 cycles)\n" " repeat #75 ; [1] \n" " nop ; [76] \n" " bra loop ; [2] (LOW = 80 cycles) \n" );