oPossum 1,083 Posted October 16, 2011 Share Posted October 16, 2011 Had some requests for this in IRC so here it is. This is an improved version of the serial tx previously posted and new serial rx code. Both tx and rx are blocking and interrupts should be disabled before calling. C code to show how to use the serial_setup(), putc(), puts(), and getc() functions. This will receive a character, increment it and echo it back. So if you type 'A', then 'B' will be echoed. // test.c #include "msp430g2211.h" // Functions in serial.asm (this really should be in a header file) void serial_setup(unsigned out_mask, unsigned in_mask, unsigned duration); void putc(unsigned); void puts(char *); unsigned getc(void); void main(void) { char c; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) serial_setup(BIT1, BIT2, 1000000 / 9600); // Send a string puts("\r\nRunning...\r\n"); for(; { // Do forever c = getc(); // Get a char ++c; // Increment it putc(c); // Echo it back } } The serial tx/rx code. Just add this as a new source file in your CCS project and it will be callable from your C code. ; serial.asm .cdecls C, LIST, "msp430g2231.h" .bss in_bit_mask, 2 ; Serial in pin .bss out_bit_mask, 2 ; Serial out pin .bss bit_dur, 2 ; Bit duration in cycles .bss half_dur, 2 ; Half bit duration in cycles ; .text ; .def serial_setup ; void serial_setup(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .def putc ; void putc(unsigned c); .def puts ; void puts(char *s); .def getc ; unsigned getc(void); ; ; serial_setup ; - Setup serial I/O bitmasks and bit duration (32 minimum) mov R12, &out_bit_mask ; Save serial output bitmask mov R13, &in_bit_mask ; Save serial input bitmask bis.b R12, &P1DIR ; Setup output pin bis.b R12, &P1OUT ; bic.b R13, &P1DIR ; Setup input pin or R13, R12 ; bic.b R12, &P1SEL ; Setup peripheral select mov R14, R12 ; sub #16, R14 ; Adjust count for loop overhead rla R14 ; Multiply by 2 because NOP is two bytes mov R14, &bit_dur ; Save bit duration sub #32, R12 ; Adjust count for loop overhead mov R12, &half_dur ; Save half bit duration ret ; Return ; ; - Send a single char putc ; Char to tx in R12 ; R12, R13, R14, R15 trashed mov &out_bit_mask, R15 ; Serial output bitmask mov &bit_dur, R14 ; Bit duration or #0x0300, R12 ; Stop bit(s) jmp bit_low ; Send start bit... ; tx_bit mov R14, R13 ; Get bit duration tx_delay nop ; 4 cycle loop sub #8, R13 ; jc tx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; rra R12 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low bic.b R15, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high bis.b R15, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; ret ; Return when all bits sent ; ; ; - Send a NULL terminated string puts ; Tx string using putc push R11 ; mov R12, R11 ; String pointer in R12, copy to R11 putsloop ; mov.b @R11+, R12 ; Get a byte, inc pointer tst.b R12 ; Test if end of string jz putsx ; Yes, exit... call #putc ; Call putc jmp putsloop ; putsx pop R11 ; ret ; ; getc ; - Get a char mov &bit_dur, R14 ; Bit duration mov &in_bit_mask, R13 ; Input bitmask mov #0x01FF, R12 ; 9 bits - 8 data + stop ; rx_start ; Wait for start bit mov.b &P1IN, R15 ; Get serial input and R13, R15 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, R13 ; Wait for 1/2 bit time ; rx_delay nop ; Bit delay sub #8, R13 ; jc rx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov.b &P1IN, R15 ; Get serial input and &in_bit_mask, R15 ; rrc R12 ; Shift in a bit ; mov R14, R13 ; Setup bit timer jc rx_delay ; Next bit... ; rla R12 ; Move stop bit to carry swpb R12 ; Move rx byte to lower byte, start bit in msb ret ; Return with rx char and start bit in R12, stop bit in carry ; .end ; DrMag, RobG, SirZusa and 14 others 17 Quote Link to post Share on other sites
Rickta59 589 Posted October 23, 2011 Share Posted October 23, 2011 Here is an msp430-gcc port of serial.S. Only some minor changes required: renamed from serial.asm to serial.S changed header inclusion, .cdecls to #include added ':' to all labels changed .bss directives to .lcomm changed .def directives to .global fixed argument registers CCS using R12-R15 for arg1-arg4, GCC uses R15-R12 for arg1-arg4 reworked temp registers because of argument register reorder changed OR asm statements to BIS statements ; serial.S - gcc port of serial.asm #include ;------------------------------------------------------------------------------- ; --- define PC,SP,SR gcc only knows about registers --- #define PC r0 #define SP r1 #define SR r2 #define ARG1 R15 #define ARG2 R14 #define ARG3 R13 #define ARG4 R12 .lcomm in_bit_mask, 2 ; Serial in pin .lcomm out_bit_mask, 2 ; Serial out pin .lcomm bit_dur, 2 ; Bit duration in cycles .lcomm half_dur, 2 ; Half bit duration in cycles ; .text ; .global serial_setup ; void serial_setup(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .global putc ; void putc(unsigned c); .global puts ; void puts(char *s); .global getc ; unsigned getc(void); ; .p2align 1,0 ; align on a word boundary serial_setup: ; - Setup serial I/O bitmasks and bit duration (32 minimum) mov ARG1, &out_bit_mask ; Save serial output bitmask mov ARG2, &in_bit_mask ; Save serial input bitmask bis ARG1, &P1DIR ; Setup output pin bis ARG1, &P1OUT ; bic ARG2, &P1DIR ; Setup input pin bis ARG2, ARG1 ; bic ARG1, &P1SEL ; Setup peripheral select mov ARG3, ARG1 ; sub #16, ARG3 ; Adjust count for loop overhead rla ARG3 ; Multiply by 2 because NOP is two bytes mov ARG3, &bit_dur ; Save bit duration sub #32, ARG1 ; Adjust count for loop overhead mov ARG1, &half_dur ; Save half bit duration ret ; Return ; ; - Send a single char putc: ; Char to tx in R15 ; R12, R13, R14, R15 trashed mov &out_bit_mask, R12 ; Serial output bitmask mov &bit_dur, R14 ; Bit duration bis #0x0300, ARG1 ; Add Stop bit(s) to tx char jmp bit_low ; Send start bit... ; tx_bit: mov R14, R13 ; Get bit duration tx_delay: nop ; 4 cycle loop sub #8, R13 ; jc tx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; rra ARG1 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low: bic.b R12, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high: bis.b R12, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; ret ; Return when all bits sent ; ; ; - Send a NULL terminated string puts: ; Tx string using putc push R11 ; mov ARG1, R11 ; String pointer in R15, copy to R11 putsloop: ; mov.b @R11+, ARG1 ; Get a byte, inc pointer tst.b ARG1 ; Test if end of string jz putsx ; Yes, exit... call #putc ; Call putc jmp putsloop ; putsx: pop R11 ; ret ; ; getc: ; - Get a char mov &bit_dur, R14 ; Bit duration mov &in_bit_mask, R13 ; Input bitmask mov #0x01FF, ARG1 ; 9 bits - 8 data + stop ; rx_start: ; Wait for start bit mov &P1IN, R12 ; Get serial input and R13, R12 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, R13 ; Wait for 1/2 bit time ; rx_delay: nop ; Bit delay sub #8, R13 ; jc rx_delay ; subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov &P1IN, R12 ; Get serial input and &in_bit_mask, R12 ; rrc ARG1 ; Shift in a bit ; mov R14, R13 ; Setup bit timer jc rx_delay ; Next bit... ; rla ARG1 ; Move stop bit to carry swpb ARG1 ; Move rx byte to lower byte, start bit in msb ret ; Return with rx char and start bit in R15, stop bit in carry -rick zborgerd, gordon, woodgrain and 3 others 6 Quote Link to post Share on other sites
Theshadowwalker91 0 Posted December 4, 2011 Share Posted December 4, 2011 how would i go about reading serial data sent from an arduino. i the arduino is sending this Serial1.print ('<'); //start Serial1.print ('5'); // address 1-5 Serial1.print ("001"); // Foreground is Blue Serial1.print ("010"); // Background is Green Serial1.print ("100"); // Marker is Red Serial1.print ('>'); // end Quote Link to post Share on other sites
oPossum 1,083 Posted December 4, 2011 Author Share Posted December 4, 2011 unsigned state, c, n, addr, fgr, fgg, fgb, bgr, bgg, bgb, mkr, mkg, mkb; for(state = 0; { c = getc(); if(c == '<') { state = 1; } else if(c == '>') { if(state == 11) { // End of packet - do something } state = 0; } else if(c >= '0' && c <= '9') { n = c - '0'; if(state > 1 && n > 1) state = 0; switch(state) { case 1: ++state; addr = n; break; case 2: ++state; fgr = n; break; case 3: ++state; fgg = n; break; case 4: ++state; fgb = n; break; case 5: ++state; bgr = n; break; case 6: ++state; bgg = n; break; case 7: ++state; bgb = n; break; case 8: ++state; mkr = n; break; case 9: ++state; mkg = n; break; case 10: ++state; mkb = n; break; default: break; } } else { state = 0; } } bluehash and Theshadowwalker91 2 Quote Link to post Share on other sites
Theshadowwalker91 0 Posted December 11, 2011 Share Posted December 11, 2011 also i ment how would i read the data and based on it turn on an led Quote Link to post Share on other sites
Theshadowwalker91 0 Posted December 18, 2011 Share Posted December 18, 2011 can anyone here help me. i am not sure how to use this code to turn on an led based on the serial data that is recived. Quote Link to post Share on other sites
rockets4kids 204 Posted April 29, 2012 Share Posted April 29, 2012 [ EDIT: be sure to see updated post below ] Many thanks to Rick and oPossum for helping me get this up and running with gcc 4.6.3. In the process we found a few problems in the original code where word access is made to port registers rather than byte mode. Here is what I have: sw_serial.S ;------------------------------------------------------------------------ ; File: sw_serial.S - msp430-gcc software only async serial routines ; ; 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 . ; ; ; Desc: blocking versions of putchar(), getchar(), and puts() that ; use cycle counting for accurate sampling and sending. Features ; very small code size, allows use of any pin, and doesn't interfere ; with the use of timers. ; ; Change Log: ; 2012-Jan-04 rick@kimballsoftware.com ; Changes for gcc, renamed function names to ; allow gcc printf() to work, conditional defines to allow ; for smaller code, disabled puts() by default so not to ; conflict with libc version. renamed jump labels to ; reduce symbol table pollution. ; ; 2011-Oct-23 rick@kimballsoftware.com ; Initial port to msp430-gcc ; ; 2012-Apr-28 rockets4kids@gmail.com ; rolled in include file ; fixed I/O ops to byte (. mode ; ; See Also: ; Detailed information about original code here: ; http://www.43oh.com/forum/viewtopic.php?f=10&t=1727 ; ;------------------------------------------------------------------------ ; TODO: Add optional sleep mode in getchar() which will disable MCU until ; incoming pin edge detect triggers interrupt. ; TODO: Allow for mulitple serial ports ;------------------------------------------------------------------------ #include //------------------------------------------------------------------------------ // define PC,SP,SR as gcc only uses the register names // #define PC r0 #define SP r1 #define SR r2 //------------------------------------------------------------------------------ // define argument registers // C function arguments are passed in R15-R12 // // Note: these registers can be used without preservation // #define ARG1 R15 #define ARG2 R14 #define ARG3 R13 #define ARG4 R12 #define ENABLE_GETCHAR /* enable getchar() */ #define ENABLE_PUTCHAR /* enable putchar() */ #undef ENABLE_PUTS /* disable puts() as it isn't ISO conforming */ #define ENABLE_AUTO_GIE /* call __dint() .. __eint() on getchar() putchar() */ .file "sw_serial.S" ;------------------------------------------------------------------------ ; Unitialized SRAM local variables ;------------------------------------------------------------------------ .lcomm rx_bit_mask, 2 ; Serial in pin mask .lcomm tx_bit_mask, 2 ; Serial out pin mask .lcomm bit_dur, 2 ; Bit duration in cycles .lcomm half_dur, 2 ; Half bit duration in cycles ;------------------------------------------------------------------------ ; Exposed Function Symbols ;------------------------------------------------------------------------ .text ; use the "text" section for all code below .global init_serial ; void init_serial(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .global init_serial1 ; void init_serial(_serial_ios *ios); #ifdef ENABLE_GETCHAR .global getchar ; int getchar(void); #endif #ifdef ENABLE_PUTCHAR .global putchar ; int putchar(uint8_t c); #endif #ifdef ENABLE_PUTS .global puts ; int puts(const char *s); NOTE: no appended newline #endif ;------------------------------------------------------------------------ ; Serial Function Implementations ;------------------------------------------------------------------------ .p2align 1,0 ; align on a word boundary ;-------------------------------------------------------------------------------- ; void init_serial(int txPinMask, int rxPinMask, int bitDuration) ;-------------------------------------------------------------------------------- .type init_serial,@function init_serial: ; Setup serial I/O bitmasks and bit duration (minimum of 32) mov ARG1, &tx_bit_mask ; Save serial output bitmask mov ARG2, &rx_bit_mask ; Save serial input bitmask bis.b ARG1, &P1DIR ; set output pin bis.b ARG1, &P1OUT bic.b ARG2, &P1DIR ; clear input pin bis ARG2, ARG1 #ifdef __MSP430FR5739__ bic.b ARG1, &P1SEL0 ; force output pin to digial I/O no pullups bic.b ARG1, &P1SEL1 ; force output pin to digial I/O no pullups #else bic.b ARG1, &P1SEL ; force output pin to digial I/O no pullups #endif mov ARG3, ARG1 ; Compute bit duration sub #16, ARG3 ; Adjust count for loop overhead rla ARG3 ; Multiply by 2 because NOP is two bytes mov ARG3, &bit_dur ; Save bit duration sub #32, ARG1 ; Adjust count for loop overhead mov ARG1, &half_dur ; Save half bit duration ret ; ready to rx/tx .Lfe1: .size init_serial,.Lfe1-init_serial #ifdef ENABLE_GETCHAR ;-------------------------------------------------------------------------------- ; int getchar(void) - read one character (blocking) ;-------------------------------------------------------------------------------- .p2align 1,0 ; align on a word boundary .type getchar,@function getchar: bic #GIE, SR ; disable global interrupts mov &bit_dur, R14 ; Bit duration mov &rx_bit_mask, R13 ; Input bitmask mov #0x01FF, ARG1 ; 9 bits - 8 data + stop .rx_start: ; Wait for start bit mov.b &P1IN, R12 ; Get serial input and R13, R12 ; Mask and test bit jc .rx_start ; Wait for low... mov &half_dur, R13 ; Wait for 1/2 bit time .rx_delay: nop ; Bit delay sub #8, R13 jc .rx_delay subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 mov.b &P1IN, R12 ; Get serial input and &rx_bit_mask, R12 rrc ARG1 ; Shift in a bit mov R14, R13 ; Setup bit timer jc .rx_delay ; Next bit... rla ARG1 ; Move stop bit to carry swpb ARG1 ; Move rx byte to lower byte, start bit in msb bis #GIE, SR ; enable global interrupts ret ; Return with rx char and start bit in R15, stop bit in carry .Lfe3: .size getchar,.Lfe3-getchar #endif #ifdef ENABLE_PUTCHAR ;-------------------------------------------------------------------------------- ; int putchar(uint8_t c) - writes the character c to serial out ;-------------------------------------------------------------------------------- .p2align 1,0 ; align on a word boundary .type putchar,@function putchar: ; Char to tx in R15, R12, R13, R14, R15 trashed bic #GIE, SR ; disable global interrupts mov &tx_bit_mask, R12 ; Serial output bitmask mov &bit_dur, R14 ; Bit duration bis #0x0300, ARG1 ; Add Stop bit(s) to tx char jmp .bit_low ; Send start bit... .tx_bit: mov R14, R13 ; Get bit duration .tx_delay: nop ; 4 cycle loop sub #8, R13 jc .tx_delay subc R13, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 rra ARG1 ; Get bit to tx, test for zero jc .bit_high ; If high... .bit_low: bic.b R12, &P1OUT ; Send zero bit jmp .tx_bit ; Next bit... .bit_high: bis.b R12, &P1OUT ; Send one bit jnz .tx_bit ; If tx data is not zero, then there are more bits to send... bis #GIE, SR ; enable global interrupts ret ; Return when all bits sent .Lfe2: .size putchar,.Lfe2-putchar #endif #ifdef ENABLE_PUTS ;-------------------------------------------------------------------------------- ; int puts(const char *s) - writes the string s to serial out. ;-------------------------------------------------------------------------------- .p2align 1,0 ; align on a word boundary .type puts,@function puts: push R11 ; TX string using putchar mov ARG1, R11 ; String pointer in R15, copy to R11 (temp reg) .putsloop: mov.b @R11+, ARG1 ; Get a byte, inc pointer tst.b ARG1 ; Test if end of string jz .putsx ; Yes, exit... call #putchar ; Call putchar jmp .putsloop .putsx: pop R11 ; restore original R11 ret ; .Lfe4: .size puts,.Lfe4-puts #endif sw_serial.h void init_serial(unsigned txPinMask, unsigned rxPinMask, unsigned bitDuration); int getchar(void); int putchar(int c); int puts(const char *s); main.c #include #include #include "sw_serial.h" void main(void) { int c; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) init_serial (BIT1, BIT2, 1000000 / 9600); // Send a string puts ("\r\nRunning...\r\n"); for (; { // Do forever c = getchar(); // Get a char putchar (c); // Echo it back } } Makefile lazy.elf: sw_serial.S main.c msp430-gcc -Os sw_serial.S main.c -o lazy.elf -mmcu=msp430g2211 install: lazy.elf mspdebug rf2500 "prog lazy.elf" clean: rm -f *~ *.elf bluehash and gordon 2 Quote Link to post Share on other sites
rockets4kids 204 Posted April 29, 2012 Share Posted April 29, 2012 I did not realize it at the time, but the code I was working from hed edits beyond oPossum's original code. I have gone back and re-patched for gcc from oPossum's code -- hopefully not introducing any new bugs this time! I did make one change, to re-name all the the public functions to start with "serial_" for the sake of clarity. serial.S #include #define PC r0 #define SP r1 #define SR r2 #define ARG1 R15 #define ARG2 R14 #define ARG3 R13 #define ARG4 R12 ; serial.asm .lcomm in_bit_mask, 2 ; Serial in pin .lcomm out_bit_mask, 2 ; Serial out pin .lcomm bit_dur, 2 ; Bit duration in cycles .lcomm half_dur, 2 ; Half bit duration in cycles ; .text ; .global serial_setup ; void serial_setup(unsigned out_mask, unsigned in_mask, unsigned bit_duration); .global serial_putc ; void serial_putc(unsigned c); .global serial_puts ; void serial_puts(char *s); .global serial_getc ; unsigned serial_getc(void); ; .p2align 1,0 ; align on a word boundary (GCC) ; serial_setup: ; - Setup serial I/O bitmasks and bit duration (32 minimum) mov ARG1, &out_bit_mask ; Save serial output bitmask mov ARG2, &in_bit_mask ; Save serial input bitmask bis.b ARG1, &P1DIR ; Setup output pin bis.b ARG1, &P1OUT ; bic.b ARG2, &P1DIR ; Setup input pin bis ARG2, ARG1 ; bic.b ARG1, &P1SEL ; Setup peripheral select mov ARG3, ARG1 ; sub #16, ARG3 ; Adjust count for loop overhead rla ARG3 ; Multiply by 2 because NOP is two bytes mov ARG3, &bit_dur ; Save bit duration sub #32, ARG1 ; Adjust count for loop overhead mov ARG1, &half_dur ; Save half bit duration ret ; Return ; ; - Send a single char serial_putc: ; Char to tx in ARG1 ; ARG1, ARG2, ARG3, ARG4 trashed mov &out_bit_mask, ARG4 ; Serial output bitmask mov &bit_dur, ARG3 ; Bit duration bis #0x0300, ARG1 ; Stop bit(s) jmp bit_low ; Send start bit... ; tx_bit: mov ARG3, ARG2 ; Get bit duration tx_delay: nop ; 4 cycle loop sub #8, ARG2 ; jc tx_delay ; subc ARG2, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; rra ARG1 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low: bic.b ARG4, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high: bis.b ARG4, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; ret ; Return when all bits sent ; ; ; - Send a NULL terminated string serial_puts: ; Tx string using serial_putc push R11 ; mov ARG1, R11 ; String pointer in ARG1, copy to R11 putsloop: ; mov.b @R11+, ARG1 ; Get a byte, inc pointer tst.b ARG1 ; Test if end of string jz putsx ; Yes, exit... call #serial_putc ; Call serial_putc jmp putsloop ; putsx: pop R11 ; ret ; ; serial_getc: ; - Get a char mov &bit_dur, ARG3 ; Bit duration mov &in_bit_mask, ARG2 ; Input bitmask mov #0x01FF, ARG1 ; 9 bits - 8 data + stop ; rx_start: ; Wait for start bit mov.b &P1IN, ARG4 ; Get serial input and ARG2, ARG4 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, ARG2 ; Wait for 1/2 bit time ; rx_delay: nop ; Bit delay sub #8, ARG2 ; jc rx_delay ; subc ARG2, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov.b &P1IN, ARG4 ; Get serial input and &in_bit_mask, ARG4 ; rrc ARG1 ; Shift in a bit ; mov ARG3, ARG2 ; Setup bit timer jc rx_delay ; Next bit... ; rla ARG1 ; Move stop bit to carry swpb ARG1 ; Move rx byte to lower byte, start bit in msb ret ; Return with rx char and start bit in ARG1, stop bit in carry ; serial.h void serial_setup (unsigned out_mask, unsigned in_mask, unsigned duration); void serial_putc (unsigned); void serial_puts (char *); unsigned serial_getc (void); main.c #include #include "serial.h" void main(void) { char c; // Disable watchdog WDTCTL = WDTPW + WDTHOLD; // Use 1 MHz DCO factory calibration DCOCTL = 0; BCSCTL1 = CALBC1_1MHZ; DCOCTL = CALDCO_1MHZ; // Setup the serial port // Serial out: P1.1 (BIT1) // Serial in: P1.2 (BIT2) // Bit rate: 9600 (CPU freq / bit rate) serial_setup (BIT1, BIT2, 1000000 / 9600); // Send a string serial_puts ("\r\nRunning...\r\n"); for (; { // Do forever c = serial_getc (); // Get a char serial_putc (c); // Echo it back } } Makefile main.elf: serial.S main.c msp430-gcc -Os serial.S main.c -o main.elf -mmcu=msp430g2211 install: main.elf mspdebug rf2500 "prog main.elf" clean: rm -f *~ *.elf woodgrain and oPossum 2 Quote Link to post Share on other sites
DecebaL 0 Posted January 31, 2013 Share Posted January 31, 2013 Hi! Please help someone. How to use this code with even parity bits? Quote Link to post Share on other sites
roadrunner84 466 Posted February 1, 2013 Share Posted February 1, 2013 I'm not a real ASM guy, but I'm quite familiar with it, so I'll give it a try: This is my modified serial_putc: ; - Send a single char serial_putc: ; Char to tx in ARG1 ; ARG1, ARG2, ARG3, ARG4 trashed push R10 ;>Have another register to play with push R11 ;>Have another register to play with mov #0, R11 ;>Clear out R11 (odd parity with #1) mov #0x0006, R10 ;>Set R10 to "parity and stop to go" mov &out_bit_mask, ARG4 ; Serial output bitmask mov &bit_dur, ARG3 ; Bit duration sub #8, ARG3 ;>We need another 8 cycles for parity magic bis #0x0600, ARG1 ;>Stop bit(s) jmp bit_low ; Send start bit... ; tx_bit: mov ARG3, ARG2 ; Get bit duration tx_delay: nop ; 4 cycle loop sub #8, ARG2 ; jc tx_delay ; subc ARG2, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 xor ARG1, R11 ;>calculate parity (1 cycle) cmp R10, ARG1 ;>next bit to send is parity? (1 cycle) jne bit_out_w ;>no? output bit (2 cycles) bit #1, R11 ;>parity bit set? (1 cycle) addc #0, ARG1 ;>add parity to data byte (1 cycle) jmp bit_out ;>skip the compensating delay (2 cycles) bit_out_w: nop ;> nop ;> nop ;> nop ;> bit_out: rra ARG1 ; Get bit to tx, test for zero jc bit_high ; If high... bit_low: bic.b ARG4, &P1OUT ; Send zero bit jmp tx_bit ; Next bit... bit_high: bis.b ARG4, &P1OUT ; Send one bit jnz tx_bit ; If tx data is not zero, then there are more bits to send... ; pop R11 ;>Restore R11 pop R10 ;>Restore R10 ret ; Return when all bits sent You can use it for either parity (even or odd). I'll be writing the receive part now, do you want to actually check the parity, or just assume everything is ok? This is the receive routine, I did not verify the parity (since you cannot return any error anyway). Instead, the parity bit is stored in the higher byte of the result. Would you change void main(void) { char c; ... to void main(void) { short c; ... you could check bit 0x0100 for the parity information and process it in C code if you wish. The parity bit is passed as is, so it's not status information on the validity of the data. serial_getc: ; - Get a char mov &bit_dur, ARG3 ; Bit duration mov &in_bit_mask, ARG2 ; Input bitmask mov #0x03FF, ARG1 ;>10 bits - 8 data + parity + stop ; rx_start: ; Wait for start bit mov.b &P1IN, ARG4 ; Get serial input and ARG2, ARG4 ; Mask and test bit jc rx_start ; Wait for low... ; mov &half_dur, ARG2 ; Wait for 1/2 bit time ; rx_delay: nop ; Bit delay sub #8, ARG2 ; jc rx_delay ; subc ARG2, PC ; 0 to 3 cycle delay nop ; 3 nop ; 2 nop ; 1 ; mov.b &P1IN, ARG4 ; Get serial input and &in_bit_mask, ARG4 ; rrc ARG1 ; Shift in a bit ; mov ARG3, ARG2 ; Setup bit timer jc rx_delay ; Next bit... ; rla ARG1 ; Move stop bit to carry rla ARG1 ;>Move parity bit to carry addc #0, ARG1 ;>Set LSB to parity bit swpb ARG1 ;>Move rx byte to lower byte, start or parity bit in msb ; Any real parity checking could be done here, or on-the-fly during the delay cycles ret ; Return with rx char and start bit in ARG1, stop bit in carry ; DecebaL and oPossum 2 Quote Link to post Share on other sites
jazz 209 Posted January 30, 2014 Share Posted January 30, 2014 Instead of breakpoint debugging I am using fast logging (http://forum.43oh.com/topic/2646-software-debugging-without-hardware-tools). On MSP430F5xx USB devices by adding one extra CDC (http://forum.43oh.com/topic/2972-sbw-msp430f550x-based-programmer/?p=25923) and on MSP430x2xx devices by hardware UART (http://forum.43oh.com/topic/2972-sbw-msp430f550x-based-programmer/?p=34398). Right now, working on project based on entry level MSP430x2xx devices without hardware UART, and don't like at all timer based soft UART. Code presented here is universal, with LP 9600 bps as target rate. It is too slow for debugging, and I'm not using LP locked to 9600 bps. Just removed from original code, part related to delay, and it is (almost) perfectly matched to 115200 bps with MSP430x2xx running on 1 MHz. And total code size (for UART TX) is close to nothing. #define DBGPDIR P1DIR #define DBGPOUT P1OUT #define DBGPBIT BIT2 ;-------------------------------------------------------------------- ; DbgInit ;-------------------------------------------------------------------- DbgInit bis.b #DBGPBIT, &DBGPDIR ; TX pin bis.b #DBGPBIT, &DBGPOUT ; TX High ret ;-------------------------------------------------------------------- ; DbgUartTX R15 -> Uart ;-------------------------------------------------------------------- DbgUartTX ; Byte R15 -> Uart ; 1000000 / 115200 = 8.681 9 CLK push.w R14 push.w R15 mov.w #DBGPBIT, R14 and.w #000FFh, R15 add.w #00300h, R15 ; Stop bit(s) jmp DbgUartTXLow ; Send start bit... DbgUartTXBit rra.w R15 ; 1 Get bit to tx, test for zero jc DbgUartTXHigh ; 2 If high... DbgUartTXLow bic.b R14, &DBGPOUT ; 4 Send zero bit jmp DbgUartTXBit ; 2 Next bit... DbgUartTXHigh bis.b R14, &DBGPOUT ; 4 Send one bit jnz DbgUartTXBit ; 2 If tx data is not zero, then more bits to send... pop.w R15 pop.w R14 ret Rickta59 1 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.