oPossum 1,083 Posted June 1, 2011 Author Share Posted June 1, 2011 I think you're all nuts here. This isn't 1965's mission to moon with 70k of memory, just use 2553.Just kidding Yeah, sorry Rob. I got caught up in oPossum's "this code is optimal (can not be done with fewer instruction words or cycles)" claim, which sounded like a challenge to me (grin). Thanks for taking up the challenge. You got me to take another look at optimizing the code. I really like assembly language on PIC devices so I thought it might be fun to learn assembly language on the MSP430 value line devices. So far, the von Neumann architecture on the MSP430 is proving difficult (for me), compared to the Harvard architecture on the PIC. I have been programming PIC in assembly for about 20 years. Just learning the TMS430. I like it, but miss the btfss, btfsc, bsf, bcf, and btf instructions that the PIC has. CCS is a bit unstable and slow, I like MPLAB better. Quote Link to post Share on other sites
oPossum 1,083 Posted June 1, 2011 Author Share Posted June 1, 2011 So the basic compact serial tx is this... mov #2, R15 ; Serial output bitmask or #0x0300, R12 ; Stop bit(s) jmp bit_low ; Send start bit... bit_loop ; * Add delay here if needed* rra R12 ; 7 Get bit to tx, test for zero jc bit_high ; 8->9 If high... bit_low bic.b R15, &P1OUT ; 1->4 Send zero/start bit jmp bit_loop ; 5->6 Next bit... bit_high bis.b R15, &P1OUT ; 1->4 Send one/stop bit jnz bit_loop ; 5->6 If tx data is not zero, then there are more bits to send... ret ; Return when all bits sent The versatile DCO can be used for common bit rates... 115200 @ 1.0368 MHz 57600 @ 518.4 kHz 38400 @ 345.6 kHz 19200 @ 172.8 kHz 9600 @ 86.4 kHz 3641 @ 32.768 kHz (3600 is 115200 / 32) If you are programming in assembly, and are aware of MSP430 quirks, then something like this may work... bit_loop ; * Add delay here if needed* rra R12 ; 7 Get bit to tx, test for zero jc bit_high ; 8->9 If high... bit_low bic.b #2, &P1OUT ; 1->4 Send zero/start bit jmp bit_loop ; 5->6 Next bit... bit_high bis.b #2, &P1OUT ; 1->4 Send one/stop bit jnz bit_loop ; 5->6 If tx data is not zero, then there are more bits to send... ret ; Return when all bits sent test mov #bit_low, R11 mov #'T' | 0x0300, R12 call R11 mov #'e' | 0x0300, R12 call R11 mov #'s' | 0x0300, R12 call R11 mov #'t' | 0x0300, R12 call R11 mov #0x030D, R12 call R11 mov #0x030A, R12 call R11 jmp $ bluehash 1 Quote Link to post Share on other sites
Mac 67 Posted June 1, 2011 Share Posted June 1, 2011 In assembly language programs, how about storing const strings, two characters per word, inline with your code? There will be two (2) words overhead for each string plus a one time cost of fourteen (14) words for a PutStr subroutine. The subroutine pulls the string address from the stack, prints the string, then returns to the instruction immediately following the inline string. This method should save a bunch of memory when you have more than one const string to print. Food for thought. Kind regards, Mike call #PutStr ; print "in-line" const string .char "Test",10,13,0 ; "text" + + + 0 terminator PutStr ; { Mike McLaren } 14 words mov.w @SP, R9 ; copy return addr to R9 bump mov.b @R9+, R12 ; copy string char to R12 tst.b R12 ; end of string? jz wrap ; yes, branch, else call #Put232 ; output the character and jmp bump ; loop wrap bit.b #1, R9 ; an odd return address? jz exit ; no, branch, else inc.w R9 ; force word boundary exit mov.w R9, 0(SP) ; update the return address ret ; ret to 1st instruct after string oPossum and noexec 2 Quote Link to post Share on other sites
oPossum 1,083 Posted June 1, 2011 Author Share Posted June 1, 2011 Excellent! I think this would work to fix up the address... inc R9 ; Must be next word bic #1, R9 ; Must be word aligned The second line may not be needed - the PC may not have a lsb that is writeable. PutStr ; { Mike McLaren } 14 words mov.w @SP, R9 ; copy return addr to R9 bump mov.b @R9+, R12 ; copy string char to R12 tst.b R12 ; end of string? jz exit ; yes, branch, else call #Put232 ; output the character and jmp bump ; loop exit inc.w R9 ; next word add #2, SP ; remove return address from stack mov R9, PC ; return to instruction after string Mac 1 Quote Link to post Share on other sites
Mac 67 Posted June 1, 2011 Share Posted June 1, 2011 The second line may not be needed - the PC may not have a lsb that is writeable. Thank you. I actually observed that once when I wrote PC with an odd value but I guess I didn't think through the implications. PutStr ; { Mike McLaren } 9 words pop R9 ; pop string address into R9 bump mov.b @R9+, R12 ; copy string char to R12 tst.b R12 ; end of string? jz wrap ; yes, branch, else call #Put232 ; output the character and jmp bump ; loop wrap inc.w R9 ; next word mov.w R9, PC ; goto instruction after string Very clean, simple, and elegant! Thank you! This is exciting stuff. I really appreciate the discerning eye and tips from an assembly language person. Must head off to class (EMU). I look forward to catching up with you later. Cheerful regards, Mike McLaren, K8LH ------------------------------------ Just thought I'd post an example of how you might use the PutStr subroutine in an assembly language program; call #PutStr ; home cursor & clear screen .char 0x1b,"[2J",0 ; ANSI [2J + 0 terminator call #PutStr ; goto line 4 tab 10 .char 0x1b,"\04;10f",0 ; ANSI \YY;XXf + 0 terminator call #PutStr ; print title string .char "K8LH Iambic Keyer Demo",0 oPossum 1 Quote Link to post Share on other sites
oPossum 1,083 Posted June 2, 2011 Author Share Posted June 2, 2011 pop R9 Nice optimization. Down to 9 words! Quote Link to post Share on other sites
Rickta59 589 Posted September 16, 2011 Share Posted September 16, 2011 This is a great thread. So what changes do I need to make to get this to compile with msp430-gcc? : ) unfortunately no one seemed to pick up on my hint of getting the code to work with msp430-gcc. I gave it a try. You probably need a uniarch version of msp430-gcc to get the #include working: ; ; Copyright (C) 2011 Kevin Timmerman ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ; ; #include "msp430g2452.h" .file "serial.s" .arch msp430g2452 .cpu 430 .mpy none .comm bit_dur,2,2 .comm bit_mask,2,2 .text .p2align 1,0 .global serial_setup .type serial_setup,@function /************************************************************ * void serial_setup(unsigned bitmask, unsigned bit_dur) */ serial_setup: mov R15, &bit_mask ; Save serial output bitmask sub #16, R14 ; Adjust count for loop overhead rla R14 ; 4 cycle loop decrements by 8 to ensure even remainder mov R14, &bit_dur ; Save bit duration initial count ret ; Return .Lfe1: .size serial_setup,.Lfe1-serial_setup ;; End of function .p2align 1,0 .global putc .type putc,@function /************************************************************ * void putc(int c) */ putc: ; Char to tx in r15 ; r15, R14, r12 trashed mov &bit_mask, r12 ; Serial output bitmask mov &bit_dur, R14 ; Bit duration bis #0x0300, r15 ; Stop bit(s) jmp bit_low ; Send start bit bit_loop: mov R14, R13 ; Get bit duration bit_time: nop ; 4 cycle loop sub #8, R13 jc bit_time ; subc R13, r0 ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 rra r15 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low: bic.b r12, &0x0021 ; Send zero bit P1OUT=0x0021 jmp bit_loop ; Next bit... bit_high: bis.b r12, &0x0021 ; Send one bit jnz bit_loop ; If tx data is not zero, then there are more bits to send... ret_ins: ret ; Return when all bits sent .Lfe2: .size putc,.Lfe2-putc ;; End of function .p2align 1,0 .global puts .type puts,@function /************************************************************ * void puts(char *s) */ puts: push r9 mov r15,r9 putsloop: mov.b @r9+, r15 tst.b r15 jz puts_exit call #putc jmp putsloop puts_exit: pop r9 ret .Lfe3: .size puts,.Lfe3-puts ;; End of function Also here for the grabbing: https://gist.github.com/1220877 -rick oPossum, zborgerd and bluehash 3 Quote Link to post Share on other sites
bluehash 1,581 Posted September 16, 2011 Share Posted September 16, 2011 Thanks for sharing your code Rickta59 Quote Link to post Share on other sites
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.