So, i've completed an assembly project to build a software PWM program for the C2000 Launchpad.
C2000 is actually a remarkably strong platform for assembly only program with some powerful addressing modes,
many registers, and many powerful instructions. The platform to me reminisces of MSP430, which i had a wonderful
time hacking at with the FOSS tool-chain and VIM. Being forced to use CCS and controlSUITE is a minor annoyance,
(lets face it, it's the only practical way to develop for this platform) but its integration makes up for the
majority of it's shortcomings. Has anyone tried to build Cortex assembly projects with GNU tools and OpenOCD?
Thumb2 will make anyone human pull their hair out. Regardless of me being happy with the platform and environment,
without further ado, here is the code:
; main.asm ; By Daryl Metzler firstname.lastname@example.org ; ; MAIN ; .sect ".text" ; Program data .global _main _main: ; memory howto (for the Watchdog) ;memory: ; a simple demo of direct addressing ; MOVW DP, #variable ; So this is how to load data ; ;directly from memory ; MOVL XAR0, @variable ; The DP points to the page data is on, ;then MOV takes offset ; turn off watchdog timer wd_disable: ; We need to disable the WatchDog before beginning, ; or the DSP will reset after 512 cycles EALLOW ;Enable EALLOW protected register access MOVZ DP, #7029h>>6 ;Set data page for WDCR register MOV @7029h, #0068h ;Set WDDIS bit in WDCR to disable WD EDIS ;Disable protected register access ; interrupts intenable: ; Allow interrupts EALLOW CLRC VMAP ; map interrupts from boot rom to 0x0 EINT EDIS ; PLL pll_enable: ; Turn on the PLL EALLOW MOVZ DP, #7021>>6 ; PLLCR MOV @0x7029, #0xC ; Set PLLCR[DIV] = 12 MOVZ DP, #7011>>6 ; PLLSTS OR @0x7011, #0x100 ; Set PLLSYS[DIVSEL] = 2 EDIS ; CPU Timer 1 timer_enable: EALLOW OR IER, #0x1000 ; Enable INT13 in IER MOVZ DP, #0xC0C>>6 ; TIMER1TCR OR @0xC0C, #0x4000 ; Set Interrupt enable in TIMER1TCR MOVZ DP, #0xC0A>>6 ; TIMER1TCR MOV @0xC0A, #0x500 ; Set TIMER1PRD period register MOVZ DP, #0xC0B>>6 ; MOV @0xC0B, #0x0 ; TIMER1PRDH EDIS ; GPIO <blinkys> gpio_enable: EALLOW MOVZ DP, #6F86h>>6 ; GPA registers AND @6F86h, #0xFF00 ; Set GPIO1-4 for GPio MOVZ DP, #6FC2h>>6 ; GPASET OR @6FC2h, #0x000F ; Set GPIO1-4 MOVZ DP, #0x6F8A>>6 ; GPADIR MOV @6F8Ah, #0x000F ; Set direction MOVZ DP, #6FC0h>>6 ; GPADAT AND @0x6FC0, #0xFFF0; Clear GPIO1-4 (LEDS ON) OR @0x6FC0, #0xFFFA ; Set GPIO1-4 ; initialize sw_pwm MOV ACC, #0x0 MOVL XAR0, #0x0 MOVL XAR1, #0x40 MOVL XAR2, #0x80 MOVL XAR3, #0xC0 MOVL XAR6, #0x0F MOVL XAR7, #0 loop: MOVW AL, AR7 CMP AL, AR0 B onp0, LT OR AR6, #0x1 onp0: CMP AL, AR1 B onp1, LT OR AR6, #0x2 onp1: CMP AL, AR2 B onp2, LT OR AR6, #0x4 onp2: CMP AL, AR3 B onp3, LT OR AR6, #0x8 onp3: nop CMP AR7, #200h B swpwmwrap, GEQ B loop, UNC swpwmwrap: MOVL XAR7 , #0x0 MOV AR6, #0h ; Clear GPIO1-4 (LEDS ON) ; We're just incrementing the AR0-3 registers ; Which pulses their respective LED MOV AL, AR0 ADD AL, #1 CMP AL, #100h B modulus0, LT MOV AL, #0 modulus0: MOVW AR0, AL MOV AL, AR1 ADD AL, #1 CMP AL, #100h B modulus1, LT MOV AL, #0 modulus1: MOVW AR1, AL MOV AL, AR2 ADD AL, #1 CMP AL, #100h B modulus2, LT MOV AL, #0 modulus2: MOVW AR2, AL MOV AL, AR3 ADD AL, #1 CMP AL, #100h B modulus3, LT MOV AL, #0 modulus3: MOV AR3, AL B loop,UNC ; loop after fall off
We see here that main is using a lot of magic and most of the work done here is getting the hardware alive and configured.
The output is that the LEDs pulse and blink using PWM. Really, there is no sophisticated output in terms of what is done with
that PWM. The duty cycles increment modulo half the duty period. The C2000 Launchpad's LED's are wired in such a way that even
at 25% duty cycle, it is difficult for the eye to pick out the "dim" LED from one at full intensity.
.sect ".text" .global int1irq int1irq: NOP IRET .global int2irq int2irq: NOP IRET .global timer1irq timer1irq: MOV AL, AR7 ADD AL, #0x1 MOV AR7, AL PUSH DP MOVZ DP, #6fC0h>>6 MOVW @6FC0h, AR6 ; Light up the LEDs by AR6 value POP DP IRET
The interrupt routine "timer1irq" does little more than increment the PWM counter kept in AR7, and move the current LED GPIO value onto the GPADAT register.
Feel free to check out the directory to grab the code for yourself.
I hope someone finds this helpful, and that this launchpad gains a little more attention and steam with the community.