This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Calculation for 9600 8 N1 baudrate

Other Parts Discussed in Thread: MSP430G2231

 

Hello Forum,

 

i am using Launch pad and i have gone thru the s/w uart sample code with 2400bps baudrate, but i need baud rate at 9600bps. what maths should i do to get the desired baudrate ? i am using 1Mhz DCO and no external xtal.

 

Regards,

Nischay

  • I haven't played with this software uart, but basically it means just making all 2400Bd timer values /4.
    How to calculate it in a formula depends on the code. And maybe one formula isn't enough (depending on how RX and TX are done)

  • If you clock the timer at 1MHz and want to transmit/receive serially at 9600b/s, you need:

    1000000 / 9600 = 104 (and 1/16th)

    cycles of the clock to transmit/receive a "bit"

    (I do not know what others call this kind of math. I call it 6th grade math. But I had not been in 6th grade, so I am not sure.)

  • old_cow_yellow said:
    I do not know what others call this kind of math. I call it 6th grade math.

    I don't think it's the math, it's a basic nonunderstanding of how the demo code works. Which is easy to acquire (the non-understanding!).

    As I said, I don't know the code. if I knew, I'd surely too puzzled at first about what it does and how to adapt it.
    The tricky thing is not doing the math, but finding the formula.

  • Nischay,

    if you open up the code that comes with the LaunchPad, you should be able to see the UART timing definition right at the beginning of the code:

     

    //   Conditions for 9600/4=2400 Baud SW UART, SMCLK = 1MHz [TimerA = SMCLK/8]

    #define     Bitime_5              0x05*4                      // ~ 0.5 bit length + small adjustment

    #define     Bitime                13*4                           //0x0D    

    For 9600baud communication, simply remove the multiplication by 4 in both definitions.

    Or you can use the uart function calls in the attached files.

    #include "uart.h"
    unsigned char timerA_UART_mode = 0;
    unsigned int txData; 
    //------------------------------------------------------------------------------
    // Function configures Timer_A for full-duplex UART operation
    //------------------------------------------------------------------------------
    void TimerA_UART_init(void)
    {
      DCOCTL = 0x00;                          // Set DCOCLK to 1MHz
      BCSCTL1 = CALBC1_1MHZ;
      DCOCTL = CALDCO_1MHZ;
      BCSCTL2 &= ~DIVS_3;                     // SMCLK = 1MHz  
      
      P1SEL |= UART_TXD + UART_RXD;            // Timer function for TXD/RXD pins
    //  P1SEL |= UART_TXD ;
      P1DIR |= UART_TXD;                        // TXD 
      P1DIR &= ~UART_RXD;
      
      TACCTL0 = OUT;                          // Set TXD Idle as Mark = '1'
      // TACCTL1 = SCS + CM1 + CAP + CCIE;       // Sync, Neg Edge, Capture, Int
      TACTL = TASSEL_2 + MC_2;                // SMCLK, start in continuous mode
      timerA_UART_mode = 1;
    }
    //------------------------------------------------------------------------------
    // Function unconfigures Timer_A for full-duplex UART operation
    //------------------------------------------------------------------------------
    void TimerA_UART_shutdown(void)
    {
      timerA_UART_mode = 0;
      P1SEL &= ~(UART_TXD + UART_RXD);            // Timer function for TXD/RXD pins
    //  P1SEL &= ~(UART_TXD );            // Timer function for TXD/RXD pins  
      TACCTL1 &= ~CCIE;                           // Sync, Neg Edge, Capture, Int
      TACTL &= ~MC_3;                             // Clear TA modes --> Stop Timer Module
      P1OUT &= ~UART_TXD;
    }
    //------------------------------------------------------------------------------
    // Outputs one byte using the Timer_A UART
    //------------------------------------------------------------------------------
    void TimerA_UART_tx(unsigned char byte)
    {
        while (TACCTL0 & CCIE);                 // Ensure last char got TX'd
        TACCR0 = TAR;                           // Current state of TA counter
        TACCR0 += UART_TBIT;                    // One bit time till first bit
        txData = byte;                          // Load global variable
        txData |= 0x100;                        // Add mark stop bit to TXData
        txData <<= 1;                           // Add space start bit
        TACCTL0 = OUTMOD0 + CCIE;               // Set TXD on EQU2 (idle), Int
        __bis_SR_register( LPM0_bits + GIE);
    }
    //------------------------------------------------------------------------------
    // Prints a string over using the Timer_A UART
    //------------------------------------------------------------------------------
    void TimerA_UART_print(char *string)
    {
        while (*string) {
            TimerA_UART_tx(*string++);
        }
    }
    //------------------------------------------------------------------------------
    // Timer_A UART - Transmit Interrupt Handler
    //------------------------------------------------------------------------------
    #pragma vector = TIMER0_A0_VECTOR
    __interrupt void Timer_A0_ISR(void)
    {
        static unsigned char txBitCnt = 10;
        if (!timerA_UART_mode)
          __bic_SR_register_on_exit(LPM3_bits+GIE); 
        else
        {
          TACCR0 += UART_TBIT;                    // Add Offset to CCRx
          if (--txBitCnt == 0)                    // All bits TXed?
          {                    
              TACCTL0 &= ~CCIE;                   // All bits TXed, disable interrupt
              txBitCnt = 10;
              __bic_SR_register_on_exit(LPM0_bits+GIE);
          }
          else {
              if (txData & 0x01) {
                TACCTL0 &= ~OUTMOD2;              // TX Mark '1'
              }
              else {
                TACCTL0 |= OUTMOD2;               // TX Space '0'
              }
              txData >>= 1;
              
          }
        }
    }     
    .

    5661.uart.h

     

    Regards,

    Dung

  • Dung Dang said:

    //   Conditions for 9600/4=2400 Baud SW UART, SMCLK = 1MHz [TimerA = SMCLK/8]

    #define     Bitime_5              0x05*4                      // ~ 0.5 bit length + small adjustment

    #define     Bitime                13*4                           //0x0D    

    That works because the timer is clocked at ~125 kHz. And

    125000 / 9600 = 13 (and a small fraction)

    If the timer is clocked by 1 MHz, 104 is the right answer.

     

  • Thank you all for your valuable inputs !


    Coming from 8051 & AVR background, i find MSP430 bit hard to work with (No offence). all the uCs which i worked with had HW uarts on them. on one occasion i needed a 2nd uart on 8051, so used the following  SW uart code meant for 8051/2 micros. interesting feature about the code is it doesn't use any hardware timers, just delays. can i implement the same on Msp430.

    as a side note, generic 8051 divides the xtal freq by 12 to derive at machine cycle


    Here's the code:



    txd_pin EQU     P3.1            ;Transmit on this pin
    rxd_pin EQU     P3.0            ;Receive on this pin

    ;Formula to calculate the bit time delay constant
    ;This constant is calculated as: (((crystal/baud)/12) - 5) / 2
    ;crystal is the frequency of crystal in Hz
    ;baud is required baudrate
    ;Please try to keep baudrate below 9600
    ;to get best results :)

    BITTIM  EQU     45;             (((11059200/9600)/12) - 5) / 2

    ;--------------------------------------------
    ;To send data serially
    ;For C programs
    ;Protype definition:
    ;               void putc(unsigned char);
    ;Usage:
    ;               putc(data);
    ;Return:
    ;               This function returns nothing
    ;
    ;For Assembly Programs:
    ;
    ;Usage:
    ;       data to be send has to be moved to R7
    ;       for example:
    ;               mov R7,#'a'
    ;               lcall _putc
    ;--------------------------------------------
    RSEG ?SU?PUTC
    _putc:
            push ACC
            Push PSW
            mov a,r7
            CLR txd_pin                     ;Drop line for start bit
            MOV R0,#BITTIM          ;Wait full bit-time
            DJNZ R0,$                       ;For START bit
            MOV R1,#8                       ;Send 8 bits
    putc1:
            RRC A                           ;Move next bit into carry
            MOV txd_pin,C           ;Write next bit
            MOV R0,#BITTIM          ;Wait full bit-time
            DJNZ R0,$                       ;For DATA bit
            DJNZ R1,putc1           ;write 8 bits
            SETB txd_pin            ;Set line high
            RRC A                           ;Restore ACC contents
            MOV R0,#BITTIM          ;Wait full bit-time
            DJNZ R0,$                       ;For STOP bit
            POP PSW
            pop ACC
            RET

    ;--------------------------------------------
    ;To receive data Serially
    ;If you want to use this routine in your
    ;C program then define function prototype
    ; as:
    ;       unsigned char getc(void);
    ;
    ;       Usage:
    ;               data = getc();
    ;       Return value:
    ;               Returns data received
    ;
    ;
    ;If you are using it in assembly program
    ;       Usage:
    ;               lcall getc
    ;       Return:
    ;               data received is stored in R7
    ;--------------------------------------------

    RSEG ?SU?GETC
    getc:  
            Push ACC
            Push PSW
            JB rxd_pin,$            ;Wait for start bit
            MOV R0,#BITTIM/2        ;Wait 1/2 bit-time
            DJNZ R0,$                       ;To sample in middle
            JB rxd_pin,getc         ;Insure valid
            MOV R1,#8                       ;Read 8 bits
    getc1:
            MOV R0,#BITTIM          ;Wait full bit-time
            DJNZ R0,$                       ;For DATA bit
            MOV C,rxd_pin           ;Read bit
            RRC A                           ;Shift it into ACC
            DJNZ R1,getc1           ;read 8 bits
            mov r7,a
            POP PSW
            pop ACC
            RET                                     ;go home

     

    Regards,

    Nischay


     

  • Nischay,

    There are many kinds of MSP430. Some have 4 USARTs, some (as in G2xx1 and G2xx2) have none. If you want to use the CPU to do bit-banging, it is okay too. For example, to use P1.1 as TXD at 9600 b/s with a MCLK of 1 MHz, you could have:

      #define P1BIT     BIT1
      #define BIT_TIME  ((1000000/9600-9)/3)
      // Transmit the byte in R12 at 9600 bps with MCL = 1 MHz
      putc:
              add     #0x0100,R12      //add a stop bit
              bic.b   #P1BIT,&P1OUT    //send start bit
      p$1:    mov     #BIT_TIME,R13
      p$2:    dec     R13
              jnz     p$2
              rra     R12
              jc      p$3
              bic.b   #P1BIT,&P1OUT    //send "0" bit
              jmp     p$1
      //
      p$3:    bis.b   #P1BIT,&P1OUT    //send "1" bit
              jnz     p$1
              ret

    But you must not enable interrupts and you are wasting hundreds of uA to keep the CPU running to do it this way.

  • Mr.Nischay Kumar V said:
    Coming from 8051 & AVR background, i find MSP430 bit hard to work with

    I started with  both, AVR and MSP, at the same time. In fact all of my mid-level library code and most of the low-level stuff too works on both, just with occasional #ifdefs here and there when it comes down to the hardware registers. So there are not so many differences at all. The 8051 is a different thing.

    Mr.Nischay Kumar V said:
    all the uCs which i worked with had HW uarts on them

    The very most MSPs have one or two too, some have up to 4 and 4 I2c (or up to 8 SPI alternatively), only the very-low-cost types don't have one. (I also worked with PICs - I ported some projects from PIC to MSP - and there were some without hardware UART too)

    Mr.Nischay Kumar V said:
    interesting feature about the code is it doesn't use any hardware timers, just delays. can i implement the same on Msp430.

    Sure. But it is inefficient. If you do busy-waiting by delays, the MSP can neither do anything in between (every interrupt would break your timing and useful main code is not possible too unless you tiem it with great effort) nor can it go into sleep mode and preserve energy.

    You can use a mixture by using a hardware timer for determining the time, but do not use ISRs but busy-waiting for the timer to expire. This way, otehr things can be done in the background. Any ISR beign executed during the delay will not enlarge the delay as logn as it exits before the delay ends. The only critical point is when an ISR is triggered before delay end but executes longr than the remeaining time. This can be circumvented by adding a threshold value the is before the end of the delay by the amount of time the slowest ISR requires. Once the threshold has passed, interrupts are disabled, so your busy-waiting main loop will be able to exactly continue when the delay ends.

     

  •  

    Thanks for all your replies !

    @Jens i get what you are saying. 

    @OCY,  i tried the code which you posted but doesn't seem to work. iam using L.aunchpad. a bit counter was missing in the code so i added a bit counter variable and tried but not working.


    Also can you explain why we have to subtract 9d and divide the result by 3 ?


    here's my code :


    ; SW UART WITHOUT USING HW TIMER


    ;*******************************************************************************
    ;*******************************************************************************
    #include  "msp430x20x2.h"


    TXD EQU  00000010B                  ; TXD on P1.1
    RXD EQU  00000100B                  ; RXD on P1.2

    ;   CPU Registers Used
    #define SBUF      R4           ; data to be sent is in SBUF
    #define BITCNT  R5           ; counter to track no:of bits

    ; 9600 BAUDRATE  

    BITTIME EQU 32D      ;  {(1000000/9600)-9}/3              


    ;-------------------------------------------------------------------------------
                ORG     0F800h                  ; Program Reset
    ;-------------------------------------------------------------------------------
    RESET         MOV.W #0280h,SP                                          ; Initialize stackpointer
    StopWDT     MOV.W #WDTPW+WDTHOLD,&WDTCTL   ; Stop WDT
                                                                                                         ; Set DCO to 1 MHz:
                          MOV.B &CALBC1_1MHZ,&BCSCTL1  ; Set range
                          MOV.B &CALDCO_1MHZ,&DCOCTL   ; Set DCO step + modulation
                     

    SetupP1     BIS.B #TXD,&P1DIR               ; P1.1 TXD AS output
                         BIS.B #TXD,&P1OUT             ; TXD HIGH
                         BIS.B #TXD,&P1REN             ; ENABLE INTERNAL PULL-UP RESISTOR
               
     MAIN:          MOV.B #'A',SBUF                    ; load ASCII 'A' into SBUF
     
     SEND_START:     BIC.B #TXD,&P1OUT
                                     MOV.B #08D,BITCNT           ; COUNTER FOR 8 BITS
                                     MOV.W #BITTIME,R6
                              L1:  DEC.W R6
                                      JNZ L1
               
               
     SEND_BYTE:     RRA SBUF                  ; rotate right thru carry
                                  JC SEND_ONE               ; check if the bit is 1 or 0
               
     SEND_ZERO:   BIC.B #TXD,&P1OUT 
                                 MOV.W #BITTIME,R6
                         L2:  DEC.W R6
                                JNZ L2
                                DEC.B BITCNT
                                JNZ SEND_BYTE
                                JMP SEND_STOP            ;
               
               
                
     SEND_ONE:   BIS.B #TXD,&P1OUT
                               MOV.W #BITTIME,R6
                       L3: DEC.W R6
                             JNZ L3
                             DEC.B BITCNT
                             JNZ SEND_BYTE
                             JMP SEND_STOP
               
               
     SEND_STOP:  BIS.B #TXD,&P1OUT           ; send last stop bit which is high
                                MOV.W #BITTIME,R6
                        L4:  DEC.W R6
                               JNZ L4
               
      DELAY:            MOV.W #10000D,R7            ; 10ms delay
                        L5: DEC.W R7
                              JNZ L5    
               
               
                              JMP MAIN                                 ; keep repeating

    ;-------------------------------------------------------------------------------
    ;           Interrupt Vectors
    ;-------------------------------------------------------------------------------
                ORG     0FFFEh                  ; MSP430 RESET Vector
                DW      RESET                   ;
               
               
                END


    Regards,


    Nischay



     

  • Mr.Nischay Kumar V said:
    Also can you explain why we have to subtract 9d and divide the result by 3

    Yes. The countdown loop requires 3 cycles for each count (decrement and breanch = 3 MCLK cycles), so the count must be divided by 3. The subtraction of 9 compensates for the instructions between the wait loops. Else you'd drift apart from the timing due to the non-0 execution time when calling the bit-output function and loadign the output bit.

     

  • Mr.Nischay Kumar V said:
      @OCY,  i tried the code which you posted but doesn't seem to work. iam using L.aunchpad. a bit counter was missing in the code so i added a bit counter variable and tried but not working.

    I do not know why it did not work for you. Possible reasons are:

    (a) You enabled the internal pull-up resistor for the TXD pin. This will cause problems when you use TXD as an output.

    (b) Your 1MHz calibration stored in INFO-A is not accurate enough.

    (c) You modified that code and introduced a problem. For example, the bit counter you added distorted the timing.

    (d) Other reasons. You did not tell me how you tested it or how you concluded that it does not work.

    Thus I tested it on my Launchpad with the following code (with IAR KickStart from TI slac050z.zip)

    #include <msp430.h>
    const char string[] = "Hello, world!\n\r";
    void putc( char ch );
    void main( void )
    {
      int i;
      BCSCTL3 = LFXT1S_2;
      BCSCTL1 = CALBC1_1MHZ;
      DCOCTL = CALDCO_1MHZ;
      P2SEL = 0;
      P2OUT = 0;
      P2DIR = 0;
      P2REN = 0xFF;
      P1OUT = BIT1;
      P1DIR = BIT6|BIT4|BIT1|BIT0;
      P1REN = 0xA0; //pull down floating input pins
      P1SEL = BIT4|BIT0; //show SMCLK & ACLK at P1.4 & P1.0
      WDTCTL = WDTPW|WDTHOLD;
      while (1)
      {
        for (i = 0; i < sizeof(string); i++)
        {
          putc(string[i]);
          __delay_cycles(100000);
        }
      }
    }

    Note that I put ACLK on P1.0 and SMCLK on P1.4 so that I can examine them with an oscilloscope.

    This works for me. I did notice that the code I sent you had some small flaws. But it works despite of the flaws. I revised the code for putc.c as follows.

    #include <msp430.h>
            public  putc
    #define P1BIT   2
    #define BIT_TIME ((1000000/9600-11)/3)
            rseg    CODE
    putc:
            add     #0x0300,R12
    p$1:    bic.b   #P1BIT,&P1OUT ; 4 MCLKs
            jmp     p$2           ; 2
    p$2:    mov     #BIT_TIME,R13 ; 2
    p$3:    dec     R13 ; 1 MCLKs
            jnz     p$3 ; 2
            rra     R12           ; 1
            jnc     p$1           ; 2
            bis.b   #P1BIT,&P1OUT ; 4
            jnz     p$2          ; 2
            ret
            END

    By the way, I wrote another little program 1108.ACOAC.zip for the Launchpad. It has a buffered input routine to receive characters from a PC "terminal" and echo back. (Using 9600 bps in both direction.) But I advise you to try it first "as is" before you try to modify it and conclude that it does not work.

  •  

    Dear OCY,  i am sorry if i have offended you in any way by saying your code doesn't seem to work.

    May be i should have been more careful when saying that, what i meant was that it didn't work for me. that's why i posted my modified code so that gurus like you can point out my mistakes.

    thanks for going thru my code and pointing out the mistakes, yes, i have enabled internal pull-up resistor may be that's causing the problem and i added a bit counter and that disturbed the whole timing routine.

    Sorry for asking this, but the new code "putc" doesn't have bit counter, should we not keep track of the 8 bits ( +1 stop bit) ?

    or may be i am not concentrating


    i'll try the new code "as is" and let you know


    Regards

    Nischay

  • Thanks OCY, the code you sent me is working perfectly ! .

    The problem was i had enabled pull-up resistor on Txd pin, i disabled it and the code worked. Also i figured it out that instead of using a separate Bitcntr, you have added 300h to the value to be sent to the com port, and after 9 bit rotations, you are checking for Zero in the register.

    Now i have a new problem. i tried running the internal temp sensor demo code (msp430x20x2_adc10_temp) "as is " but  the program keeps resetting  itself during debugging ( i use IAR).

    Also, can you check my code for unpacking 4 digit packed BCD number contained in 16bit register here R12.

     

  • Thanks OCY, the code you sent me is working perfectly ! .

    The problem was i had enabled pull-up resistor on Txd pin, i disabled it and the code worked. Also i figured it out that instead of using a separate Bitcntr, you have added 300h to the value to be sent to the com port, and after 9 bit rotations, you are checking for Zero in the register.

    Now i have a new problem. i tried running the internal temp sensor demo code (msp430x20x2_adc10_temp) "as is " but  the program keeps resetting  itself during debugging ( i use IAR).

    Also, can you ( or any other guru) check my code for unpacking 4 digit packed BCD number contained in 16bit register here R13.


    BYTE_ONE   EQU 200H
    BYTE_TWO  EQU 201H
    VAL1     EQU 202H
    VAL2     EQU 203H
    VAL3     EQU 204H
    VAL4     EQU 205H




    UNPACK:                   ;R13 HAS 4 BCD VALUES WHICH HAVE TO UNPACKED
           PUSH R13                       
           MOV.W R13,R4
           AND.W #0FF00H,R4
           SWPB R4
           MOV.B R4,&BYTE_ONE
         
           POP R13
           MOV.W R13,R4
           AND.W #00FFH,R4
           MOV.B R4,&BYTE_TWO
           
           MOV.B &BYTE_ONE,R4
           AND.B #0F0H,R4
           SWPB R4
           MOV.B R4,&VAL1
          
           MOV.B &BYTE_ONE,R4
           AND.B #0FH,R4
           SWPB R4
           MOV.B R4,&VAL2
          
           MOV.B &BYTE_TWO,R4
           AND.B #0F0H,R4
           SWPB R4
           MOV.B R4,&VAL3
          
           MOV.B &BYTE_TWO,R4
           AND.B #0FH,R4
           SWPB R4
           MOV.B R4,&VAL4
             
          
           RET


    Regards,

    Nischay

     

  • I think you misunderstood the SWPB instruction. It swaps the upper and lower bytes within a word. It does not swap the upper and lower nibbles within a byte. You also have quite a number of unnecessary instructions here and there. They are not harmful, just unnecessary. If you want this to be compatible with the current IAR c-compiler, you should use R12 instead of R13 to pass the argument. Also you could use R13, R14, or R15 instead of R4 as scratchpad. Those registers need not be preserved. But R4 to R11 should be reserved.
  •  

    Thanks for your reply,

    Yes, i searched the MSP430 instruction set for "SWPB.B" instruction but there is non and SWPB is only a word instr.  i code in assembly and not C, will that still have restrictions on my register usage.

    can you please modify my code to unpack 4 digit BCD ?


    Regards,

    Nischay

  •  

    OCY, clearly i had got confused with the "SWPB" instr and later i carefully revised my code for unpacking BCD numbers and here it is:

    UNPACK:                   ;R13 HAS 4 BCD VALUES -1234
                                
           MOV.W R13,R4
           AND.W #0FF00H,R4
           SWPB R4
           MOV.B R4,&BYTE_ONE             ; 12
           MOV.W R13,R4
           AND.W #00FFH,R4
           MOV.B R4,&BYTE_TWO             ; 34
          
           MOV.B &BYTE_ONE,R4
           AND.B #0F0H,R4
           CLRC
           RRC R4
           RRC R4
           RRC R4
           RRC R4
           MOV.B R4,&VAL1                 ; 1
          
           MOV.B &BYTE_ONE,R4
           AND.B #0FH,R4
           MOV.B R4,&VAL2                 ; 2
          
           MOV.B &BYTE_TWO,R4
           AND.B #0F0H,R4
           CLRC
           RRC R4
           RRC R4
           RRC R4
           RRC R4
           MOV.B R4,&VAL3                 ; 3
          
           MOV.B &BYTE_TWO,R4
           AND.B #0FH,R4
           MOV.B R4,&VAL4                 ; 4
             
          
           RET

    My above code did what i needed, now i have seen your code and i got to say it has a "Master's touch" and is definitely faster and efficient than my revised code ( i am still immersed in 8 bit methodology) and MSP430 being a 16 bit MCU i got to learn to exploit the 16 bit architecture.

    Once again Thanks a lot for your valuable support and time.

    Today i was able to complete the task of displaying Temp. sensed by internal temp.sensor of MSP430G2231 and display the values on com port. To get accurate results or say consistent result, in my code i take 4 samples and average the result before displaying the value.

    Ti's sample demo code "ADC10.temp" has some bugs and the code keeps resetting, i modified the original code by disabling interrupts and used polling method and the code worked.

    i'd be interested to hear from those you have used the original code unmodified.

    Regards,

    Nischay

     

**Attention** This is a public forum