Wednesday, March 4, 2015

How to Create an Assembly-Only Project for TIVA Launchpad in Code Composer


Baremetal ARM? Time to don the geek glasses!

Aargh!

You have no idea how long I spent googling keywords contained in the title of this post.  Especially now that you found this post, you lucky duck.  I wasted literal DAYS trying to get a stupid assembly program to run on my TIVA Connected Launchpad.  I've done a handful of programs for the TIVA in the past, but they have been all in C and all the examples TI gave were also in C.

All I needed was an example on the syntax that Code Composer uses for assembly and some of the directives I would need to get it going.  Sadly, I could not find this anywhere.  My friend Andrew Mendez who is also working on the Launchpad, pointed me to this webpage of UT professor Jonathan Valvano where he has starter files for several simple projects in his textbook, which I highly recommend and you can purchase from Amazon here.

The page has files for both TIVA Launchpads in C as well as assembly.  However, all of them are formatted to run in Keil uVision assembly, which uses a totally different syntax than what Code Composer or the GNU compiler use.  I found this out the hard way.  And yes, the examples did run flawlessly in Keil uVision v4, but I did not want to use yet another IDE and then have to worry about porting my existing CCS C projects.  Not to mention the free MDK-Lite version of the software is limited to only 32 Kilobytes, which granted would probably be enough for most microcontroller programs, but chaining down the beast that is the 120 MHz Launchpad with over 1 MB of flash memory to a measly 32 K seemed like a sin to me.  Plus, the Keil syntax for assembly just looks odd to me as I'm much more used to the dot (.) syntax.

It wasn't until I took a closer look at that webpage where Prof. Valvano is kind enough to provide a guide for converting the weird Keil syntax into something CCS can understand.

Even with that, the journey wasn't as easy as I thought it would be for a multitude of reasons that I won't get into, but eventually I was actually able to get an LED to blink.  Now that I've vented some of my frustrations, I can get on with the guide.

Step 1: Create a New Project in Code Composer Studio

Open up CCS.  Click File -> New -> CCS Project.


You will be met by a familiar window.  Select you target board (for the Connected Launchpad, it's "Tiva TM4C1294NCPDT").  Select your method of programming the board (for the Connected Launchpad, it's "Stellaris In-Circuit Debug Interface").  Type in a name of varying degrees of creativity for your project.  Now here's the trap.  Do not select "Empty Assembly-Only Project" as your project type.  I did so and even with code that I knew worked, it would not run properly on the board.  I spent over an hour fiddling with the project settings to no avail so let's not waste any more time on something so mundane and let's just do it the easy way that works!  Select "Empty Project (with main.c)" Hit Finish and let's move on.


Step 2: Set up project files

Go into the project tree and delete the main.c file.  We won't need it.


Now select the project folder, right-click it and add New -> File.


When the dialog pops up, name it "main.asm" this will hold the code for the main assembly program.


Step 3: Program assembly

Now for the fun part!  Open up main.asm, type in your program and voila!  Here's a basic assembly structure:

    .global  main                                   ; makes main accessible from outside this file.
    .thumb                                          ; use thumb, duh
    .data                                           ; set memory location to sram
    ; put your variables here
    .text                                           ; set memory location to flash
main:
    ; code goes here
OK it's not as easy as that since the real challenge of this came from finding a working example of a full assembly program specifically for the TIVA Connected Launchpad written in a syntax that Code Composer would understand.  None existed (or my google-fu is rusty), so I had to make my own.  Fortunately for you, here it is in all its baremetal glory!

;=========================================================================================================
; Blink in Assembly
; By Ricardo Angeli (03/04/15)
; Designed for Tiva Connected Launchpad (TM4C1294NCPDT)
;=========================================================================================================
; Description:
; Blinks an onboard LED at an approximate rate of once
; per second.  Designed as a test for an assembly-only
; program on the Launchpad.
;=========================================================================================================

    .global  main                                   ; makes main accessible from outside this file.
    .thumb                                          ; use thumb, duh

    .text                                           ; set memory location to flash
    .align 4                                        ; align on 32-bit boundary

;=========================================================================================================
; Hardware Constants
;=========================================================================================================
GPIO_PORTJ_DATA_R             .field 0x400603FC,32
GPIO_PORTJ_DIR_R              .field 0x40060400,32
GPIO_PORTJ_AFSEL_R            .field 0x40060420,32
GPIO_PORTJ_PUR_R              .field 0x40060510,32
GPIO_PORTJ_DEN_R              .field 0x4006051C,32
GPIO_PORTJ_AMSEL_R            .field 0x40060528,32
GPIO_PORTJ_PCTL_R             .field 0x4006052C,32
PJ0                           .field 0x40060004,32
PJ1                           .field 0x40060008,32
SWITCHES                      .field 0x4006000C,32
SW1_PRESSED                   .equ 0x02              ; value read from location SWITCHES when just SW1 is
                                                     ; pressed.
SW2_PRESSED                   .equ 0x01              ; value read from location SWITCHES when just SW2 is
                                                     ; pressed.
BOTH_PRESSED                  .equ 0x00              ; value read from location SWITCHES when both
                                                     ; switches are pressed
NO_PRESSED                    .equ 0x03              ; value read from location SWITCHES when neither
                                                     ; switch is pressed.
GPIO_PORTN_DATA_R             .field 0x400643FC,32
GPIO_PORTN_DIR_R              .field 0x40064400,32
GPIO_PORTN_AFSEL_R            .field 0x40064420,32
GPIO_PORTN_DEN_R              .field 0x4006451C,32
GPIO_PORTN_AMSEL_R            .field 0x40064528,32
GPIO_PORTN_PCTL_R             .field 0x4006452C,32
PN0                           .field 0x40064004,32
PN1                           .field 0x40064008,32
LEDS                          .field 0x4006400C,32
LED1_ON                       .equ 0x02               ; value written to location PN1 or LEDS to turn on
                                                      ; LED1.
LED2_ON                       .equ 0x01               ; value written to location PN0 or LEDS to turn on
                                                      ; LED2.
SYSCTL_RCGCGPIO_R             .field 0x400FE608,32
SYSCTL_RCGCGPIO_R12           .equ 0x00001000         ; GPIO Port N Run Mode Clock Gating Control
SYSCTL_RCGCGPIO_R8            .equ 0x00000100         ; GPIO Port J Run Mode Clock Gating Control
SYSCTL_PRGPIO_R               .field 0x400FEA08,32
SYSCTL_PRGPIO_R12             .equ 0x00001000         ; GPIO Port N Peripheral Ready
SYSCTL_PRGPIO_R8              .equ 0x00000100         ; GPIO Port J Peripheral Ready

;=========================================================================================================
; Custom Constants
;=========================================================================================================
CPU_FREQ                      .field 8000000,32       ; Current CPU clockspeed stored in Hertz

;=========================================================================================================
; Program Code
;=========================================================================================================
        .align 2                                      ; align on 16-bit boundary

main:                                                 ; must be called main to execute on its own

        push {r0-r2, lr}                              ; push registers we will use into the stack,
                                                      ; useful for integrating within C code.

        ; Enable GPIO port
        ldr r0, SYSCTL_RCGCGPIO_R
        mov r1, #SYSCTL_RCGCGPIO_R12
        str r1, [r0]

        ; Wait a few cycles for the peripheral to be enabled
        nop
        nop
        nop
        nop
        nop

        ldr r0, GPIO_PORTN_DIR_R
        mov r1, #0x01
        str r1, [r0]

        ldr r0, GPIO_PORTN_DEN_R
        mov r1, #0x01
        str r1, [r0]

        ldr r0, GPIO_PORTN_DATA_R

blink:
        ; Turn on the LED
        orr r1, r1, #LED2_ON
        str r1, [r0]

        ; Initiate wait drive!
        ldr r2, CPU_FREQ                              ; load number of cycles we want to wait
wait1:
        sub r2, r2, #10                               ; subtract 10 every 10 cycles
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        cmp r2, #0
        bgt wait1

        ; Turn off the LED
        bic r1, r1, #LED2_ON
        str r1, [r0]

        ; Initiate wait drive!
        ldr r2, CPU_FREQ                              ; load number of cycles we want to wait
wait2:
        sub r2, r2, #10                               ; subtract 10 every 10 cycles
        nop
        nop
        nop
        nop
        nop
        nop
        nop
        cmp r2, #0
        bgt wait2                                     ; loop back unless r2 <= 0

        ; loop to the beginning of the blink routine all over again
        b blink

        ; if calling this assembly program from C, this would pop back used registers and return back to C
        pop {r0-r2, lr}
        mov pc,lr
I know this is not the cleanest or most efficient code for this sort of thing.  But I wanted a simple program to get up and go and this features many common instructions.  I'm not even going to deal with interrupts until I can get an LED to blink.  Note that the .field is required to specify a 32-bit word.  The maximum number of bits for .equ is 16, I think.  That was another stumbling point through this.

Notice how to call an immediate value stored in memory, you use the # symbol followed by the name of the label such as in orr r1, r1, #LED2_ON.  Yet if you are using an instruction to call a memory location, then you simply type the name of the label like in ldr r0, SYSCTL_RCGCGPIO_R.

Well I hope you found this post useful.  If you did, please let me know via the comments section.  If you managed to find a good source that explains all of this let me know as well.

Downloads

If you want to download the Code Composer Project file, you may do so below. All you need is to unzip it and import it into your workspace.  It's the same code shown in the example.

Download BlinkyASM.zip

Tuesday, March 3, 2015

Back from the Dead!

Me after long coding session
So way back in my freshman year of college, I felt inspired and decided to create my own electronics blog!

Then I just kinda forgot about it.

A lot has happened since and I've worked on many projects.  I'm still in college, but I can finally see the light at the end of the tunnel!

Anyway, I'm going to be making a few posts here about some stuff I've been working on.  Some stuff may include, ARM, C, assembly, Launchpad, AVR, Linux, Raspberry Pi, Android, hardware hacking, retrocomputers and more!  My goal is to present information that I've found that is either not accessible anywhere on the Al Gore web or pick-and-placed from a multitude of sources and condensed into an easy to swallow tablet.

Oh and by the way, I've updated the look of the site and the name is now Ricky's Awesome Electronics at rawelec.blogspot.com!

I've got content coming in the following weeks so stay tuned!

Thursday, September 22, 2011

Turn off TV's with an Arduino


Behold, my artistic talents!!

'Bout it:
This little build will go through several manufacturer's TV codes for turning off (or on) nearly any kind of television.  It does take a while to go through the program so depending on how weird your TV is, it might take up to a minute to find the right code--though it does my Samsung in about 2 seconds.

Yeah, I know.  It's like that "TV Be-Gone" thing.  Well go ahead, spend twenty bucks on it and buy it then... Or you can make it yourself!

Parts:

You just need:
(1) Arduino (I have an UNO, but it will work on anything)
(2) IR LEDs
(1)10k Ohm Resistor
(2)470 Ohm Resistors
(1)Push Button

I used TWO LEDs to improve the range, but it will work with just one of course. Ditto with the 470 Ohm resistors.

The Making Of:
So to wire it,

Step 1:
Wire the pushbutton with one pin to +5 volts on the Arduino and the other pin on the same side to a 10k Resistor that goes to Ground.  Wire the pin on the opposite side of ground to port 3 on the Arduino.

Button
Step 2:
Next, we're wiring up the LEDs.  Connect the positive side (longer pin on the LED) of each to its own 470 Ohm resistor, the negative sides to ground.  Then connect both resistors to port 2.
LEDs

Programming:
OK, here is where we need to have a little chat.  As it turns out, it's not as easy as it seems making the IR LEDs spit out all of these TV Remote sequences.  One needs to find all of the codes ONLY for the power on/off and make sure it appears only once in the list or else the TV may turn off and then turn back on again.

Fortunately thanks to Ken Shirriff (who posted this code on the internets), he actually ported over the firmware for the official TV Be-Gone to the Arduino platform.  It was a little dated so I changed the ports it used.  Be forewarned that trying to understand this code as a beginner will be very challenging.

P.S: The download is at the bottom of the post, this is where ALL downloads will be in this blog.  If it's broken, let me know.

P.P.S: To use the Arduino sketch, simply copy the "TVB" folder into your My Documents>Arduino folder and then open the Arduino IDE, go down "Sketches" and "TVB" should be there.


The Final Result:

Here it is.  Again, it does take a little bit to find the right code, but it should get it eventually.  I have NO IDEA what the pushbutton does, if you do please tell me.  It's there because it won't run without it but you don't ever need to push it at any point.  Also, the range is not too great, probably no more than like 6 inches away.

Finished Product

As I mentioned, you can have it work with one LED or make it work with 64 if you wanted to.  I just had 2 so I used them.  What else are can you do with IR LEDs??

Anyway in this pic, you can SEE the infrared!!! ZOMG!!

See the little purplish light in the LEDs?  That, sir, is INFRA-RED.

So, did you build it?  Questions? Comments? Rants?

As always thanks for reading :-)


Downloads:
 TVB.zip

Hello World!

My name is Ricardo Angeli and I'm a freshman studying Computer Engineering at the University of Central Florida.  I created this blog to track down some of the electronic crap I've made and what I'm currently working on as well as stuff that's happening in my life.

Now as you may have noticed, this blog is called "Ricky's Amateur Electronics".  There is a reason: I'm just starting out playing around with microcontrollers, servos, resistors, etc.

So unfortunately, you won't be seeing any flying cars, LED rave-suits, or 3D printers--at least anytime soon.  However, I will promise to document my builds thoroughly (unless I don't feel like it ;)   ).  And who knows?  Maybe when I get better at this stuff I could start making flying cars, LED suits, and 3D printers...  But for now, thanks for reading and ENJOY!