Κυριακή 31 Μαΐου 2015

Clocking the MSP430F5529 Launchpad, Part II: The Assembly Way

We have already discussed a nice way to clock your launchpad using the mspware library of functions provided by TI. How about trying the same thing in assembly language?

Assembly allows you precise control over the MCU although it is arguably more involved than plain C (or mspware assisted) programming. Let's revisit our previous clocking examples and try to implement them in MSP430 assembly.

Before we Start

To do any serious assembly work, you will need to study at least three documents:


The Family User's Guide shows all the appropriate registers and operations needed for tasks like setting the clocks, raising Vcore, working with timers, GPIOs and so on.  It also describes the internals of  the MSP430 and the assembly language instructions. The Assembly Language Tools User's Guide will get you started on the assembler provided with CCS. The F5529 datasheet provides info specific to the chip we are programming. There are also some nice tutorials available on the Internet to get you started with assembly programming on the MSP430.  And don't miss out on the examples installed on your development system either:
Have a look in C:\ti\msp430\MSPWare_2_00_00_XX\examples\devices\5xx_6xx (or wherever you installed mspware). Check for  folders named Assembly_CCS.  You may not find one for the F5529, but there are plenty of examples for other similar devices.

Default Clocks

As we already know, the default MSP430 clock is about 1MHz. Here is some code to prove it:

bis.b #BIT2,&P2DIR ; Set P2.2 as output
bis.b #BIT2,&P2SEL ; Set P2.2 as peripheral output
; P2.2 is multiplexed with SMCLK
; This will output SMCLK to P2.2
  bis.b #BIT7,&P7DIR ; Set P7.7 as output
bis.b #BIT7,&P7SEL ; Set P7.7 as peripheral output
; P7.7 is multiplexed with MCLK
; This will output MCLK to P7.7
                          ; P7.7 is not present in the headers
; of the launchpad. It is output pin 60
; on F5529. Top right corner ;)

bis.b #BIT7,&P4DIR ; Set P4.7 as output (Green LED)
bis.b #BIT0,&P1DIR ; Set P1.0 as output (Red LED)
mov.w #3787, R15 ; Delay parameters
  mov.w #22, R14
blink xor.b #BIT0,&P1OUT
call #delay
jmp blink

Download the complete project files here. 'Delay' is a subroutine that mimics the behavior of the __delay_cycles() intrinsic of the C compiler. With the values specified here (in R14 and R15 registers), delay will  waste about 250000 cycles (check out comments in the source code and you will figure it out) allowing us to watch the red LED blinking!

If you have a scope, you may connect it to P2.2 where SMCLK is output. Here is what you will see:


If you feel lucky, you may also probe (carefully!) port 7.7. This is MCLK (same frequency as SMCLK here). It is pin no 60 of the F5529, but it is not output on any header pin.

Direct clocking with Crystals

Clocking with crystals is mostly straightforward. Download the complete project files here. We connect the 32.768KHz crystal to ACLK and the 4MHz crystal to MCLK/SMCLK:

       bis.b #BIT4+BIT5,&P5SEL   ; Connect XT1 to P5.5, P5.4
                                ; by configuring the ports 
                                ; peripheral function
       bis.b #BIT2+BIT3,&P5SEL   ; Connect XT2 to P5.3, P5.2
                            ; by configuring the ports for
                            ; peripheral function

The crystal pins are multiplexed with GPIOs in F5529. We have to first select them as peripheral pins using the P5SEL register.

bic.w #XT1OFF, &UCSCTL6  ; Turn on XT1
bic.w #XT2OFF, &UCSCTL6  ; Turn on XT2

We then turn on the crystals, by clearing their OFF bits in the UCSCTL6 register. UCSCTLx registers define the behavior of many aspects of the Unified Clock System (UCS).

bis.w #XCAP_3, &UCSCTL6  ; Internal load capacitor for XT1

 We connect an appropriate capacitor to the low frequency XT1.

waitclear   bic.w   #XT2OFFG | XT1LFOFFG | DCOFFG, &UCSCTL7
; Clear XT2,XT1,DCO fault flags  (XT1 and XT2 only here)
            bic.w   #OFIFG,&SFRIFG1         ; Clear fault flags
            bit.w   #OFIFG,&SFRIFG1         ; Test oscillator fault flag
            jc      waitclear

We have to wait for the crystals to start and stabilize. We continuously clear and test the oscillator fault flag until it is no longer set.

     bic.w #XT1DRIVE_3,&UCSCTL6  ; XT1 is now stable, reduce drive
                                 ; strength. Low frequency crystals 
                                 ; take some time
                                 ; to start and stabilize
     bic.w #XT2DRIVE_0,&UCSCTL6  ; XT2 Drive strength reduced to
                                 ; level 0    
; for 4-8MHz operation

 Finally, we set the right drive strengths for both crystals. The low frequency crystal takes some time to start-up and stabilize. After this time, the drive strength is reduced. This prolongs the life of the crystal and also reduces power consumption.

We are now ready to assign the crystals to our clocks:

      mov.w #SELA_0|SELS_5|SELM_5,&UCSCTL4

UCSCTL4 is the register that sets the source for each clock (ACLK, SMCLK, MCLK). SELA_0 selects XT1 for ACLK, while SELS_5 and SELM_5 select XT2 for MCLK and SMCLK. You can easily see the difference by using your scope as before:



Also note the LED blinks a lot more rapidly now, as the MCLK frequency is 4MHz :)

Using the DCO and FLL

Going beyond the crystals we need to configure DCO and provide it with an FLL reference. Going above 8MHz also requires setting  Vcore to a higher level. Fortunately, there is an assembly language example in the samples provided by TI. We have implemented this as a subroutine and call it three times to set Vcore to the maximum level (download the complete project files here):

  mov.w #PMMCOREV_1,R12
call #setvcore
mov.w #PMMCOREV_2,R12
call #setvcore
mov.w #PMMCOREV_3,R12
call #setvcore

Here is a diagram showing the required Vcore by frequency, as shown in the F5529 datasheet. Launchpad supplies 3.3V to the F5529, so we can clock it up to its maximum operating frequency, as long as we raise PMMCOREV to 3:

 TI states that Vcore should only be raised one level at a time, hence the three separate calls here.

Having  connected and started the crystals in our previous example, we are halfway to our target already! 

; Default settings in UCSCTL3: SELREF = 000b -> FLLREF = XT1CLK
;                              FLLREFDIV = 000b -> FLLREFCLK / 1

bis.w   #SCG0,SR       ; Disable the FLL control loop
        clr.w   &UCSCTL0       ; Set lowest possible DCOx, MODx
        mov.w   #DCORSEL_7,&UCSCTL1   ; Select range for 20MHz
        mov.w   #FLLD_2 + 639,&UCSCTL2 ; Set DCO multiplier
                                       ; for DCOCLKDIV
        ; (FLLN + 1) * (FLLRef/n) * FLLD = DCOCLK
        ; FLLD_2 = 4
        ; FLLRef=32768 and n=1
        ; (n=FLLREFDIV)
        ; DCOCLKDIV = DCOCLK/FLLD = (FLLN+1)*(FLLRef/n)
        ; Default settings are DCOCLKDIV for MCLK/SMCLK

        bic.w   #SCG0,SR ; Enable the FLL control loop

UCSCTL3 contains important settings: The clock source to use for the FLLREF (default is the low frequency crystal, XT1CLK) and FLLREFDIV which allows FLLREFCLK to be further divided by 1, 2, 4, 8, 12 or 16. We just use the defaults here.

Before changing the DCO setting, we first disable the FLL control loop and clear the UCSCTL0 register. This register will be set automatically after we adjust the FLL parameters.  We need to look at the documentation of F5529 to choose the appropriate DCO range. The F5529 datasheet will help us find this one:



For 80MHz operation, we need to go up to the last range, DCORSEL_7 and store it in register UCSCTL1. We set the multiplier and frequency bits in UCSCTL2.

Multiplier is FLLD_2 which is 4
FLLN is 639.
Thus, DCOCLK =  (639+1) * (32768/1) * 4 = 83886080 Hz (84MHz)

DCOCLK is not used directly on MCLK/SMCLK (that would be one hell of an overclocking!). DCOCLKDIV is used instead:

DCOCLKDIV = DCOCLK / FLLD  = 83886080 / 4 =  20971520 Hz or about 21 MHz.


Although DCO is now set, the actual frequency will take sometime to stabilize.  Our delay subroutine comes handy again:

; Worst-case settling time for the DCO when the DCO range bits 
have been changed is n x 32 x 32 x F_fLLREFCLK cycles.
; n = FLLREFDIV
; 1 x 32 x 32 x 20.97152 MHz / 32.768 KHz = 655360  
; MCLK cycles for DCO to settle

mov.w #9930,R15
mov.w #22,R14
call #delay

; Total cycles: setup 6+6+2=14
; Internal Loop: 9930*3*22=655380
; Outer loop: 22*5 = 110
; Total: 110+655380+14 = 655504

And we also clear the oscillator fault flag and loop until it no longer sets itself:

; Loop until DCO fault flag is cleared

delay_DCO   bic.w   #DCOFFG,&UCSCTL7    ; Clear DCO fault flags
            bic.w   #OFIFG,&SFRIFG1     ; Clear fault flags
            bit.w   #OFIFG,&SFRIFG1     ; Test oscillator fault flag
            jc      delay_DCO

Finally, we assign the clock sources to their respective clocks (these are in fact the default settings for UCSCTL4):

mov.w #SELA_0|SELS_4|SELM_4,&UCSCTL4

Checking SMCLK with the oscilloscope:



For this last example, we have adjusted the  LED delay loop to 1 million cycles, so we can still watch it blinking!

Guess what - assembly is great for lots of happy afternoons :)

Σάββατο 23 Μαΐου 2015

Programming Target and Breakout Boards using a Launchpad

Using the launchpad as a spy bi-wire programmer is not new: People have been doing it with the value line launchpads for ages. But how about using a launchpad to program a chip in LQFP-64, LQFP-80 or LQFP-100 package (or in other SMT style packages). These chips cannot be directly breadboarded but compared to the THT MSPs, they are a lot more powerful, hence a lot more desirable :)

As I found out, there is more than one way to use your trusty launchpad to program these.

The Target Board

Texas Instruments sells boards equipped with ZIF (Zero Insertion Force) sockets for just about every package type they produce an MSP in. The boards alone sell for about 80-100 USD officially, but you can get much better prices on ebay. The target board will allow you to insert your MSP, connect it to a JTAG programmer (sold separately), program it and then remove it and use it in your PCB or prototype board.
Guess what: you don't really need to buy the JTAG programmer (FET interface), since you already have the launchpad!
I recently acquired an LQFP-100 target board (MSP-TS430PZ100B) and a couple of MSP430F6736 and set out to find how to program them using the F5529 launchpad.  It turned out to be pretty easy:


Launchpad to Target board

The connections are straightforward:

Launchpad to target board schematic
Your launchpad will program and also power the chip in the target board. Don't forget to set your target board configuration to Spy bi-wire. There is usually a set of jumpers that you have to move to the SBW position:


While a target board is handy, it will only allow you to program specific types of chips (unless you start collecting target boards, which might become a rather expensive hobby). But there is another way to program MSPs and use them for prototyping too: the breakout boards.

Programming a Breakout Board

Fortunately, eBay is full of sellers for breakout boards of any type. I ordered ten LQFP-100 boards from a seller in China. These were promptly delivered and I soldered a couple of F6736 chips on them:


After soldering some headers on it, I set out to find the minimum circuit that would allow this little board to work and get programmed by my launchpad. It basically comes down to this:


You will have to look at the datasheet for your specific MSP to find out which pins to connect and where. There will be more than a couple of pins that need to be tied to Vcc and GND and also a few that will require capacitors to GND. The spy bi-wire interface needs a few additional components (you can probably ommit the 330 Ohms resistor though). And this is how it looks like:

Launchpad to breakout board

Yes, it's a big mess of wires. But it works!
And of course if you are designing your own PCB, you can just provide a port for the spy bi-wire pins and program your MSP directly in circuit. Either way, MSP programming is a lot of fun!