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
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.
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
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.)
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!).old_cow_yellow said:I do not know what others call this kind of math. I call it 6th grade math.
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;
}
}
}
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.
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:Coming from 8051 & AVR background, i find MSP430 bit hard to work with
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:all the uCs which i worked with had HW uarts on them
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.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.
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
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:Also can you explain why we have to subtract 9d and divide the result by 3
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
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