hallo,
i have been working on the software uart with processor f2013 for a few days and still can't get it work correctly. I just found an original code from ti source code. It suits the whole family msp430x20x3 and should also suits my processor.
hier is the original codes:
//******************************************************************************// MSP430F20xx Demo - Timer_A, Ultra-Low Pwr UART 2400 Echo, 32kHz ACLK//// Description: Use Timer_A CCR0 hardware output modes and SCCI data latch// to implement UART function @ 2400 baud. Software does not directly read and// write to RX and TX pins, instead proper use of output modes and SCCI data// latch are demonstrated. Use of these hardware features eliminates ISR// latency effects as hardware insures that output and input bit latching and// timing are perfectly synchronised with Timer_A regardless of other// software activity. In the Mainloop the UART function readies the UART to// receive one character and waits in LPM3 with all activity interrupt driven.// After a character has been received, the UART receive function forces exit// from LPM3 in the Mainloop which echo's back the received character.// ACLK = TACLK = LFXT1 = 32768Hz, MCLK = SMCLK = default DCO// //* An external watch crystal is required on XIN XOUT for ACLK *// //// MSP430F20xx// -----------------// /|\| XIN|-// | | | 32kHz// --|RST XOUT|-// | |// | CCI0B/TXD/P1.5|-------->// | | 2400 8N1// | CCI0A/RXD/P1.1|<--------//#define RXD 0x02 // RXD on P1.1#define TXD 0x20 // TXD on P1.5// Conditions for 2400 Baud SW UART, ACLK = 32768#define Bitime_5 0x06 // ~ 0.5 bit length + small adjustment#define Bitime 0x0E // 427us bit length ~ 2341 baudunsigned int RXTXData;unsigned char BitCnt;void TX_Byte (void);void RX_Ready (void);// M. Buccini / L. Westlund// Texas Instruments Inc.// October 2005// Built with CCE Version: 3.2.0 and IAR Embedded Workbench Version: 3.40A//******************************************************************************#include <msp430x20x3.h>void main (void){ WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer CCTL0 = OUT; // TXD Idle as Mark TACTL = TASSEL_1 + MC_2; // ACLK, continuous mode P1SEL = TXD + RXD; // P1DIR = TXD; //// Mainloop for (;;) { RX_Ready(); // UART ready to RX one Byte _BIS_SR(LPM3_bits + GIE); // Enter LPM3 w/ interr until char RXed TX_Byte(); // TX Back RXed Byte Received }}// Function Transmits Character from RXTXData Buffervoid TX_Byte (void){ BitCnt = 0xA; // Load Bit counter, 8data + ST/SP while (CCR0 != TAR) // Prevent async capture CCR0 = TAR; // Current state of TA counter CCR0 += Bitime; // Some time till first bit RXTXData |= 0x100; // Add mark stop bit to RXTXData RXTXData = RXTXData << 1; // Add space start bit CCTL0 = CCIS0 + OUTMOD0 + CCIE; // TXD = mark = idle while ( CCTL0 & CCIE ); // Wait for TX completion}// Function Readies UART to Receive Character into RXTXData Buffervoid RX_Ready (void){ BitCnt = 0x8; // Load Bit counter CCTL0 = SCS + OUTMOD0 + CM1 + CAP + CCIE; // Sync, Neg Edge, Cap}// Timer A0 interrupt service routine#pragma vector=TIMERA0_VECTOR__interrupt void Timer_A (void){ CCR0 += Bitime; // Add Offset to CCR0// TX if (CCTL0 & CCIS0) // TX on CCI0B? { if ( BitCnt == 0) CCTL0 &= ~ CCIE; // All bits TXed, disable interrupt else { CCTL0 |= OUTMOD2; // TX Space if (RXTXData & 0x01) CCTL0 &= ~ OUTMOD2; // TX Mark RXTXData = RXTXData >> 1; BitCnt --; } }// RX else { if( CCTL0 & CAP ) // Capture mode = start bit edge { CCTL0 &= ~ CAP; // Switch from capture to compare mode CCR0 += Bitime_5; } else { RXTXData = RXTXData >> 1; if (CCTL0 & SCCI) // Get bit waiting in receive latch RXTXData |= 0x80; BitCnt --; // All bits RXed? if ( BitCnt == 0)//>>>>>>>>>> Decode of Received Byte Here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< { CCTL0 &= ~ CCIE; // All bits RXed, disable interrupt _BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR) }//>>>>>>>>>> Decode of Received Byte Here <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< } }}
The only thing i changed is the header.(from #include <msp430x20x3.h> to #include "msp430f2013.h")
and i set the baud rate to 2400. but it still did'nt work. Can some1 pls help me? tnx.
Do you have the external 32768Hz crystal attached to XT1? Else ACLK won't run with the expected frequency (if at all, on some 2xx MSPs without VLO, it's simply dead then)
_____________________________________Before posting bug reports or ask for help, do at least quick scan over this article. It applies to any kind of problem reporting. On any forum. And/or look here.If you cannot discuss your problem in the public, feel free to start a private conversation: click on my name and then 'start conversation'. But please do so only if you really cannot do it in a public thread, as I usually read all threads. And I prefer to answer where others can profit from it (or contribute to it) too.
Hi Michael,
thank you for answer. It doesn't have the external crystal. And i found out in the datasheet. When there is no external crystal, the ACLK is sourced from the VLO of 12 KHz. So i modified the Bitime from 0xE to 0x5 and keep the baud rate at 2400. But it still wont work.
And in the code there are two definitions of Bitime. (#define Bitime_5 0x06 // ~ 0.5 bit length + small adjustment #define Bitime 0x0E // 427us bit length ~ 2341 baud)
What is the use of Bitime_5 in the RX function? Can i just replace it with Bitime?
Thank you for your help!
zhenyu Xi
zhenyu xiWhen there is no external crystal, the ACLK is sourced from the VLO of 12 KHz
zhenyu xiWhat is the use of Bitime_5 in the RX function? Can i just replace it with Bitime?
thanks a lot for your help!
sorry to bother you again. But i really have a problem. It's still about the software uart. I switched the processor from msp430f2013 to msp430fg4168. I know it has hardware uart, but i still like to programm a software one for it. The clock is at 1MHz and the Baud rate is 9600.
So, here is the problem. Like you said, the Bit_time_5 is the time for half a bit. So we can read the bit in the middle. And it should be about 52 (104 for one bit). But when i set it to 52, it doesn't work. Only when i set it to about 100 (95 to 120 would also work), it functions well.
Even when it works, there is still problem. In the codes i deleted the transmitting part. And i add " if(RXByte == 'a') P2OUT ^= BIT0; " to the recieving part. If it recieves an "a", the processor toggles the output at pin2.0. This pin is connected to the oscilloscope so i can see a edge coming when an "a" is sent. I used Hterm als Hyper Terminal from the PC. In Hterm you can set the stop bits to 1 or 2. When i send the charactors bytewise, it works perfert with 1 or 2 stop bits. But when send the charactors in series, it only works with 2 stopbits. For example, with 2 stopbits i send "aaa", and in the oscillosope i can see 3 edges. But with 1 stopbit, i can only see 1 edge.
Actually i also tried this code together with the transmission code. It turns out to be the same. With 2 stopbits, when i send "aaa", i recieve exactly "aaa". With 1 stopbits, when i send "aaa", i recieve "axx".
I also thought about it. Maybe when i sent the charactors in series, the startbit the of the second byte came too early. At this moment, the interrupt was still disabled, because the processor was still dealing with the first byte. This could lead to bits lost of the second byte. But i'm not sure and couldn't figure out a way to solve it. Can you pls help me? Thank you in advance.
Here are the codes i used:
//********************************************************************************************
#include "msp430fg4618.h"#include "stdbool.h"#define RXD BIT2 // RXD on P1.2#define Bit_time 104 // 9600 Baud, SMCLK=1MHz (1MHz/9600)=104#define Bit_time_5 104 // Time for half a bit.unsigned char BitCnt; // Bit count, used when transmitting byteunsigned int RXByte; // Value recieved once hasRecieved is setbool isReceiving; // Status for when the device is receivingbool hasReceived; // Lets the program know when a byte is received// Function Definitionsvoid Transmit(void);void main(void){ WDTCTL = WDTPW + WDTHOLD; // Stop WDT P1DIR &= ~RXD; // Select input at recieving side P1IES |= RXD; // RXD low edge interrupt P1IFG &= ~RXD; // Clear RXD (flag) before enabling interrupt P1IE |= RXD; // Enable RXD interrupt
P2DIR |= BIT0; // Select output direction P2OUT &= ~BIT0; // Output = 0 isReceiving = false; // Set initial values hasReceived = false; __bis_SR_register(GIE); // interrupts enabled while(1) { if (hasReceived) // If the device has recieved a value { hasReceived = false; // Clear the flag if(RXByte == 'a') { P2OUT ^= BIT0; // toggle the ouput at P2.0, it's only to check whether recieving is working well. } } if (~hasReceived) // Loop again if another value has been received __bis_SR_register(CPUOFF + GIE); // LPM0, the ADC interrupt will wake the processor up. This is so that it does not // endlessly loop when no value has been Received. } }// Port 1 interrupt service routine#pragma vector=PORT1_VECTOR__interrupt void Port_1(void){ isReceiving = true; P1IE &= ~RXD; // Disable RXD interrupt P1IFG &= ~RXD; // Clear RXD IFG (interrupt flag) TACTL = TASSEL_2 + MC_2; // SMCLK, continuous mode CCR0 = TAR; // Initialize compare register CCR0 += Bit_time_5; // Set time till first bit CCTL0 = OUTMOD1 + CCIE; // disable transmission and enable the interrupt RXByte = 0; // Initialize RXByte BitCnt = 0x9; // Load Bit counter, 8 bits + ST}// Timer A0 interrupt service routine#pragma vector=TIMERA0_VECTOR__interrupt void Timer_A0 (void){ CCR0 += Bit_time; // Add Offset to CCR0 if ( BitCnt == 0) { TACTL = TASSEL_2; // SMCLK, timer off (for power consumption) CCTL0 &= ~ CCIE ; // Disable interrupt isReceiving = false; if ( (RXByte & 0x201) == 0x200) // Validate the start and stop bits are correct { RXByte = RXByte >> 1; // Remove start bit RXByte &= 0xFF; // Remove stop bit hasReceived = true; P1IFG &= ~RXD; // clear RXD IFG (interrupt flag) P1IE |= RXD; // enabled RXD interrupt } __bic_SR_register_on_exit(CPUOFF); // Enable CPU so the main while loop continues }
else { if ( (P1IN & RXD) == RXD) // If bit is set? RXByte |= 0x400; // Set the value in the RXByte RXByte = RXByte >> 1; // Shift the bits down BitCnt --; } }
zhenyu xihen i send the charactors bytewise, it works perfert with 1 or 2 stop bits. But when send the charactors in series, it only works with 2 stopbits.
But in your code, you replaced the 1/2 bit time by a full 1/1 bit time. So the code is done waiting at the very moment the next start bit comes (in case of one stopbit). And misses the falling edge. With two stopbits, you just added a 1-bit dfelay between two immediately following bytes, and now your software is ready for the next byte. Typing the characters one by one acts as if you added a few thousands of stopbits manually. :)
However, I don't know why your code doesn't work with Bit_time_5 = 52. I didn't analyze the code in detail and , sorry, don't have the time to do it now.
But why don't you try to go through the code by hand and 'simulate' what's happening, on a piece of paper? After doing so, you should exactly know how the code works and why. And likely you'll also know where your problem is. I usually do it the same way.