Other Parts Discussed in Thread: MSP430WARE
Tool/software: Code Composer Studio
Hello,
I'm using the myUART_5529 example which can be found here: http://processors.wiki.ti.com/index.php/MSP_UART
It works very nice until I try to change the system clocks. The default speed is set to 8MHz from SMCLK. The clock configuration is as below:
#include "initclocks.h" // ---------------------------------------------------------------------------- // myClocks.c (for lab_04a_clock project) ('F5529 Launchpad) // // This routine sets ACLK to run from REFO, then configures MCLK and SMCLK to // run from the and high-freq internal clock source (DCO). // // Oscillators: // DCO = 8MHz (default is ~1MHz) Internal high-frequency oscillator // REFO = 32KHz Internal 32KHz reference oscillator // MODOSC = 5MHz Internal 5MHz oscillator // VLO = ~10KHz Internal very low power, low frequency oscillator // XT1 = --KHz (not configured) External crystal input // XT2 = --MHz (not configured) External crystal input // // Reference Clock: // FLL = REFO = 32KHz Internal reference clock; used for calibrating DCO at runtime // Internal Clocks: // ACLK = REFO = 32KHz // SMCLK = DCO = 8MHz // MCLK = DCO = 8MHz // MODCLK = MODOSC = 5MHz (default) // ---------------------------------------------------------------------------- //***** Defines *************************************************************** //VLO - ~10 KHz //REFO - 32768 Hz //XT1 - LF:<50 KHz //XT1 - HF: 4 MHz max //XT2 - 4-40 MHz //DCO - 100 KHz to CPU max //MODOSC - 5 MHz or 5 MHz/128 used by Flash or ADC #define LF_CRYSTAL_FREQUENCY_IN_HZ 32768 // 32KHz #define HF_CRYSTAL_FREQUENCY_IN_HZ 8000000 // 40MHz #define MCLK_DESIRED_FREQUENCY_IN_KHZ 8000 // 25MHz #define MCLK_FLLREF_RATIO MCLK_DESIRED_FREQUENCY_IN_KHZ / ( UCS_REFOCLK_FREQUENCY / 1024 ) // Ratio = 250 #define XT_TIMEOUT 50000 //***** Global Variables ****************************************************** uint32_t myACLK = 0; uint32_t mySMCLK = 0; uint32_t myMCLK = 0; uint8_t returnValue = 0; bool bReturn = STATUS_FAIL; //***** initClocks ************************************************************ inline void initClocks(void) { // Connect pins to clock crystals GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_P5, GPIO_PIN5 + // XOUT on P5.5 GPIO_PIN4 + // XIN on P5.4 GPIO_PIN3 + // XT2OUT on P5.3 GPIO_PIN2 // XT2IN on P5.2 ); // // Output the ACLK and MCLK signals to their respective pins - which allows you to // // watch them with a logic analyzer (ACLK on P1.0, SMCLK on P2.2, MCLK on P7.7) // GPIO_setAsPeripheralModuleFunctionOutputPin( // GPIO_PORT_P1, // GPIO_PIN0 // ACLK on P1.0 (Shared with LED1 on jumper JP8) // ); // GPIO_setAsPeripheralModuleFunctionOutputPin( // GPIO_PORT_P2, // GPIO_PIN2 // SMCLK on P2.2 (Boosterpack - Right side (J5) pin 2) // ); //************************************************************************** // Configure core voltage level //************************************************************************** // Set core voltage level to handle 25MHz clock rate PMM_setVCore( PMM_CORE_LEVEL_3 ); //************************************************************************** // Configure Oscillators //************************************************************************** // Set the XT1/XT2 crystal frequencies used on the LaunchPad, and connected // to the clock pins, so that driverlib knows how fast they are (these are // needed for the DriverLib clock 'get' and crystal start functions) UCS_setExternalClockSource( LF_CRYSTAL_FREQUENCY_IN_HZ, // XT1CLK input HF_CRYSTAL_FREQUENCY_IN_HZ // XT2CLK input ); // Initialize the XT1 crystal oscillator (using a timeout in case there is a problem with the crystal) // - This requires P5.4 and P5.5 pins to be connected (and configured) as clock input pins. // - Another alternative is to use the non-timeout function which "hangs" if XT1 isn't configured; // UCS_turnOnXT1( CS_XT1_DRIVE_0, UCS_XCAP_3 ); (in fact, we used the non-timeout function to setup XT2) // - The "WithTimeout" function used here will always exit, even if XT1 fails to initialize. // You must check to make sure XT1 was initialized properly... in a real application, you would // usually replace the while(1) with a more useful error handling function. bReturn = UCS_turnOnLFXT1WithTimeout( UCS_XT1_DRIVE_0, UCS_XCAP_3, XT_TIMEOUT ); if ( bReturn == STATUS_FAIL ) { while( 1 ); } // Initializes the XT2 crystal oscillator with no timeout. // In case of failure, code hangs here. // For time-out instead of code hang use UCS_turnOnXT2WithTimeout(). UCS_turnOnXT2(UCS_XT2_DRIVE_24MHZ_32MHZ); // This is an example of turning on XT2 with the the timeout option. // bReturn = UCS_turnOnXT2WithTimeout( // UCS XT2 DRIVE 4MHZ 8MHZ, // XT2_TIMEOUT // ); // // if ( bReturn == STATUS_FAIL ) // { // while( 1 ); // } // Verify if the default clock settings are as expected myACLK = UCS_getACLK(); mySMCLK = UCS_getSMCLK(); myMCLK = UCS_getMCLK(); //************************************************************************** // Configure Clocks //************************************************************************** // Set ACLK to use REFO as its oscillator source (32KHz) UCS_initClockSignal( UCS_ACLK, // Clock you're configuring UCS_REFOCLK_SELECT, // Clock source UCS_CLOCK_DIVIDER_1 // Divide down clock source by this much ); // Set REFO as the oscillator reference clock for the FLL UCS_initClockSignal( UCS_FLLREF, // Clock you're configuring UCS_REFOCLK_SELECT, // Clock source UCS_CLOCK_DIVIDER_1 // Divide down clock source by this much ); // Set MCLK and SMCLK to use the DCO/FLL as their oscillator source (8MHz) // The function does a number of things: Calculates required FLL settings; Configures FLL and DCO, // and then sets MCLK and SMCLK to use the DCO (with FLL runtime calibration) UCS_initFLLSettle( MCLK_DESIRED_FREQUENCY_IN_KHZ, // MCLK frequency MCLK_FLLREF_RATIO // Ratio between MCLK and FLL's reference clock source ); // // Optional lab step set MCLK to run from REFO // // This will make the LED blink very sloooowly in our while{} loop // UCS_initClockSignal( UCS_BASE, // UCS_MCLK, // Clock you're configuring // UCS_REFOCLK_SELECT, // Clock source // UCS_CLOCK_DIVIDER_1 // Divide down clock source by this much // ); // Select XT2 as SMCLK source // We have to Re-do this call ... Why? If you use UCS_initFLLSettle() to // setup MCLK, it also configures SMCLK; therefore, you should call this // function after setting up MCLK /*UCS_initClockSignal( UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1 );*/ // Verify that the modified clock settings are as expected myACLK = UCS_getACLK(); mySMCLK = UCS_getSMCLK(); myMCLK = UCS_getMCLK(); }
If I uncomment this:
UCS_initClockSignal( UCS_SMCLK, UCS_XT2CLK_SELECT, UCS_CLOCK_DIVIDER_1 );
Then the UART prints garbage. I checked SMCLK via UCS_getSMCLK() call and it is returning 8000000 as expected. Without the UCS_initClockSignal() the SMCLK returns 8192000 and UART runs fine.
Strangely, if I set XT2 crystal to run at 8192000 (same as working version), it stills prints garbage. I'm missing something?
Thanks!
P.S. below is the myUART.c function:
// ---------------------------------------------------------------------------- // uart.c ('FR6989 Launchpad) // ---------------------------------------------------------------------------- //***** Header Files ********************************************************** #include "myUart.h" #include "string.h" //***** Defines *************************************************************** //#define MYUART_IDLE 0 //#define MYUART_WRITE 1 //#define MYUART_ECHO 2 //***** Function Prototypes *************************************************** //static unsigned char Eol( unsigned char ); //***** Global Variables ****************************************************** static unsigned short txBufLen = 0; // Number of bytes left to output; decremented as each character is sent //--------------------------------------------------------------------------------------------- // struct Uart_t myUart; // // This structure defines the resources used by the UART functions of the USCI_A port. // The typedef is found in the associated header file (myUart.h). The goal was to try and // encapsulate the various port settings into a single structure, so as to make it easier to // port this code to a new device. // - Some of the fields are are defined by the device (Base Address, Number of UART channels). // - Others are defined by the hardware board layout - in most cases, the UARTs can actually be // assigned to a few different Port/Pin locations. // - Finally, there are a number of "channel variables" which are used to indicate the status // of the port at runtime. //--------------------------------------------------------------------------------------------- struct Uart_t myUart = { NUM_CHANNELS, // Number of Uarts on the device .Channels[0] = { USCI_A0_BASE, // Base Address of USCI_A port GPIO_PORT_P4, // GPIO Port settings for TX pin GPIO_PIN4, NULL, // F5229 peripheral pin configuration does not have multiple SEL bits GPIO_PORT_P4, // GPIO Port settings for RX pin GPIO_PIN5, NULL, // F5229 peripheral pin configuration does not have multiple SEL bits 0, // Baud Rate 0, // Open - UART port has been opened and configured 1, // TxBusy - 0, // TxRDY 1, // RxBusy 0, // RxRDY NOECHO // RxEcho }, .Channels[1] = { USCI_A1_BASE, // Base Address of USCI_A port GPIO_PORT_P3, // GPIO Port settings for TX pin GPIO_PIN4, NULL, // F5229 peripheral pin configuration does not have multiple SEL bits GPIO_PORT_P3, // GPIO Port settings for RX pin GPIO_PIN5, NULL, // F5229 peripheral pin configuration does not have multiple SEL bits 0, // Baud Rate 0, // Open - UART port has been opened and configured 1, // TxBusy - 0, // TxRDY 1, // RxBusy 0, // RxRDY DOECHO // RxEcho } }; // The following structure will configure the USCI_A port to run at 9600 baud from an 8MHz SMCLK // The baud rate values were calculated at: software-dl.ti.com/.../index.html USCI_A_UART_initParam myUart_Param_9600_8N1_SMCLK8MHz = { USCI_A_UART_CLOCKSOURCE_SMCLK, 52, // clockPrescalar 1, // firstModReg 0, // secondModReg USCI_A_UART_NO_PARITY, USCI_A_UART_LSB_FIRST, USCI_A_UART_ONE_STOP_BIT, USCI_A_UART_MODE, USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION }; // The following structure will configure the USCI_A port to run at 115200 baud from an 8MHz SMCLK // The baud rate values were calculated at: software-dl.ti.com/.../index.html USCI_A_UART_initParam myUart_Param_115200_8N1_SMCLK8MHz = { USCI_A_UART_CLOCKSOURCE_SMCLK, 4, // clockPrescalar 3, // firstModReg 5, // secondModReg USCI_A_UART_NO_PARITY, USCI_A_UART_LSB_FIRST, USCI_A_UART_ONE_STOP_BIT, USCI_A_UART_MODE, USCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION }; // The following structure will configure the USCI_A port to run at 9600 baud from an 32KHz ACLK // The baud rate values were calculated at: software-dl.ti.com/.../index.html USCI_A_UART_initParam myUart_Param_9600_8N1_ACLK32Kz = { USCI_A_UART_CLOCKSOURCE_ACLK, 3, // clockPrescalar 0, // firstModReg 3, // secondModReg USCI_A_UART_NO_PARITY, USCI_A_UART_LSB_FIRST, USCI_A_UART_ONE_STOP_BIT, USCI_A_UART_MODE, USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION }; //***************************************************************************** // myUart_init() // // Initialize the UART functionality of the USCI peripheral // - The "myUart_Instance" parameter allows the user to setup any of the UARTs // (Two UARTS are available on the 'FR6989) // - This function verifies that the DriverLib UART init function returns // successfully // - Waiting for the UART to send data can be done with either "polling" or // "interrupts"; this init routine enables the USCI UART interrupts //***************************************************************************** int myUart_init( uint16_t myUart_Instance, uint32_t BaudRate, USCI_A_UART_initParam *param ) { // Get this channel's USCI's base address from myUart structure uint16_t BaseAddr = myUart.Channels[myUart_Instance].BaseAddress; // Abort and return an error if the channel has already been initialized if( myUart.Channels[myUart_Instance].Open ) return( STATUS_ALREADY_OPEN ); // Initialize the UART using one of the two sets of parameters provided (or modify the parameters above to meet your needs) if( STATUS_FAIL == USCI_A_UART_init( BaseAddr, param )) return( STATUS_INIT_FAILED ); // Baud rate retained for future clock adjustment function myUart.Channels[myUart_Instance].BaudRate = BaudRate; // Enable (i.e. turn on) the UART USCI_A_UART_enable( BaseAddr ); // Set the status flags for this instance of our UART channel myUart.Channels[myUart_Instance].Open = 1; // Indicate the port has been opened and initialized myUart.Channels[myUart_Instance].TxBusy = 0; // Set TX port to "not busy" (since we are not actively sending data, yet) myUart.Channels[myUart_Instance].RxBusy = 0; // Set RX port to "not busy" (since we are not actively receiving data, yet) myUart.Channels[myUart_Instance].TxRDY = 1; // TX port is ready by default, since the transmit buffer is empty) myUart.Channels[myUart_Instance].RxRDY = 0; // RX port is not ready by default, as there's nothing yet to read // Return successful, if we made it this far return( STATUS_INIT_SUCCESSFUL ); } //***************************************************************************** // myUart_writeBuf() // // Configures UART to send a buffer of data // - The USCI_A_UART_transmitData() DriverLib function handles sending one // byte of data, whereas this function will send an entire buffer // - This is a 'blocking' function - that is, it does not exit until the whole // buffer has been sent; rather than a wait-loop, though, this function waits // using LPM0 (and the transmit interrupt) // - If the UART is not busy sending data already, this function sends the // first byte of data, then lets the UART ISR send the rest of the data // // Parameters // - myUart_Instance: Let's you select which UART to send the buffer; no error // checking is done, as it is assumed you successfully // initialized the UART // - *txBuf: Buffer of data to be written to UART port; function // checks that the buffer does not have a NULL address // - BufLen: How many bytes do you want to send (you don't have to // send the whole buffer which was passed). If a value of // zero is passed, the function will calculate the buffer // length for you // - doCrLf: Do you want to send a Carriage Return and Linefeed // after the data buffer has been sent? (1 Yes; 0 N0) // - Return: This function returns the number of characters sent //***************************************************************************** int myUart_writeBuf( uint16_t myUart_Instance, unsigned char *txBuf, uint16_t BufLen, int DoCrLf ) { uint16_t BaseAddr = myUart.Channels[myUart_Instance].BaseAddress; // Get this channel's USCI's base address from myUart structure unsigned char out = 0; int ret = -1; // Variable which will hold return value for this function // Exit if there is no transmit buffer if( txBuf == NULL ) return( STATUS_FAIL_NOBUFFER ); // Exit the function if we're already busy writing, else set the 'busy' flag if ( myUart.Channels[myUart_Instance].TxBusy ) return( STATUS_FAIL_BUSY ); else myUart.Channels[myUart_Instance].TxBusy = 1; // Check if the transmit length was provided as a parameter; if it's zero, // calculate the size of the buffer (i.e. number of chars to transmit) if ( BufLen == 0 ) txBufLen = strlen( (const char *)txBuf ); else txBufLen = BufLen; // Add to transmit length for carriage return (enter) and linefeed, if requested by user if ( DoCrLf ) { txBufLen += 2; } // Since 'txBufLen' is decremented during transfers, retain the original value ret = txBufLen; // Enable USCI_Ax TX interrupt USCI_A_UART_enableInterrupt( BaseAddr, USCI_A_UART_TRANSMIT_INTERRUPT); // Keep sending characters until complete while( txBufLen >> 0 ) { if ( myUart.Channels[myUart_Instance].TxRDY == 1 ) // Check if TX port is ready (if we got here, it should be ready) { myUart.Channels[myUart_Instance].TxRDY = 0; // Clear the ready bit now that we're planning to send a byte out = *txBuf; // Read from buffer (note that this reads past end of buffer if we're doing CRLF) txBuf++; // Move buffer pointer to next item to be sent if ( DoCrLf ) { // If doing CRLF, replace 'out' with the CR or LF if ( txBufLen == 2 ) out = ASCII_LINEFEED; else if ( txBufLen == 1 ) out = ASCII_ENTER; } txBufLen--; // Decrement the transmit count USCI_A_UART_transmitData( BaseAddr, out ); // Send the data to the transmit port if ( myUart.Channels[myUart_Instance].TxRDY == 0 ) // Test TxRDY to help prevent race condition where interrupt occurs before we reach this step __low_power_mode_0(); // Sleep CPU until woken up by transmit ready interrupt event } // (other LPMx modes could be used, depending upon clock requirements) } // Disable the UART transmit interrupt USCI_A_UART_disableInterrupt( BaseAddr, USCI_A_UART_TRANSMIT_INTERRUPT); // Return the length of the string that was sent return (int) ret; } //***************************************************************************** // myUart_readBuf() // // This function receives a buffer of data via the UART. This is a blocking // function, thus it will not return until the full length has been received. // // Parameters: // - myUart_Instance: Let's you select which UART should recieve the buffer; // no error checking is done, as it is assumed you // successfully initialized the UART // - *rxBuf: Buffer that the received data should be written into; // this function checks that the buffer doesn'tt have a // NULL address (if so, it exits // - *rxSize: How many bytes do you want to receive; a default size // of 1 line (80 bytes) is used if a "0" is passed; // Note that receiving a carriage return or linefeed will // force the function to stop receiving data, even if the // 'Length' of bytes has not yet been received; // Finally, we used a pointer for the size so that the // actual number of received bytes is returned // - Return: The status of the function //***************************************************************************** int myUart_readBuf( uint16_t myUart_Instance, unsigned char *rxBuf, uint16_t *rxSize ) { uint16_t BaseAddr = myUart.Channels[myUart_Instance].BaseAddress; // Check if TX port is ready (if we got here, it should be ready) unsigned int ret = STATUS_INIT_SUCCESSFUL; // Variable to hold function status (initialize as 'successful') unsigned int i = 0; // Local variable used in 'for' loop unsigned char in[3] = { 0, 0, 0 }; // Temporary variable to hold received data (only 1 byte will be used for rec'd data; extra locations to add CRLF) uint8_t inLen = 0; // Current length of "in" array uint16_t rxBufLen = 0; // Current length of input buffer // Exit if there is no read buffer if( rxBuf == NULL ) return( STATUS_FAIL_NOBUFFER ); // Exit the function if we're already busy reading, else set the 'busy' flag if ( myUart.Channels[myUart_Instance].RxBusy ) return( STATUS_FAIL_BUSY ); else myUart.Channels[myUart_Instance].RxBusy = 1; // If '0' is passed as the "number of bytes to read", set to default size if ( *rxSize == 0 ) *rxSize = DEFAULT_MAX_READ; // If recieve "echo" feature is enabled, wait until the transmit channel isn't busy if ( myUart.Channels[myUart_Instance].RxEcho ) { if ( myUart.Channels[myUart_Instance].TxBusy == 1 ) { __low_power_mode_0(); } } // Clear and enable USCI_Ax RX interrupt USCI_A_UART_clearInterrupt( BaseAddr, USCI_A_UART_RECEIVE_INTERRUPT); USCI_A_UART_enableInterrupt( BaseAddr, USCI_A_UART_RECEIVE_INTERRUPT); // Keep transmitting until the receive data buffer has reached the specified rxSize while ( rxBufLen < *rxSize ) { // We 'missed' reading the data in time if RxRDY ever goes above '1' if ( myUart.Channels[myUart_Instance].RxRDY >> 1 ) ret = STATUS_RX_MISSED_REAL_TIME; // If not ready, sleep until we get a receive interrupt event that sets the RxRDY flag if ( myUart.Channels[myUart_Instance].RxRDY == 0 ) { __low_power_mode_0(); } else { myUart.Channels[myUart_Instance].RxRDY = 0; // If Rx is ready, clear the ready bit in[0] = USCI_A_UART_receiveData( BaseAddr ); // Read byte from the RX receive buffer inLen = 1; // Set 'in' buffer length to '1' byte // If input byte is CR (or linefeed) add the other character to 'in' switch ( in[0] ) { case ASCII_LINEFEED: in[1] = ASCII_ENTER; inLen++; // Increment the size of 'in' buffer length *rxSize = rxBufLen; // Set receive size to current buffer length to force the function to complete break; case ASCII_ENTER: in[1] = ASCII_LINEFEED; inLen++; // Increment the size of 'in' buffer length *rxSize = rxBufLen; // Set receive size to current buffer length to force the function to complete break; } // Copy 'in' character(s) to the data receive buffer for ( i = 1; i <= inLen; i++ ) { *( rxBuf + rxBufLen ) = in[i-1]; rxBufLen++; } // If 'echo' is enabled, trasmit the newly received character(s) back to sender (for terminals without 'local echo') if ( myUart.Channels[myUart_Instance].RxEcho ) { if ( !myUart.Channels[myUart_Instance].TxBusy ) // Wait until transmit isn't busy, before sending character(s) { myUart_writeBuf( CHANNEL_1, (unsigned char *)in, inLen, NOCRLF ); } } } } // Disable the RX interrupt and set the port to 'not busy' USCI_A_UART_disableInterrupt( BaseAddr, USCI_A_UART_RECEIVE_INTERRUPT); myUart.Channels[myUart_Instance].RxBusy = 0; // Return with status return ( ret ); } /*//***************************************************************************** // USCI_A0 Interrupt Service Routine //***************************************************************************** #pragma vector = USCI_A0_VECTOR __interrupt void myUart0_isr(void) { int chan = 0; switch ( __even_in_range( UCA0IV, USCI_UCTXIFG )) { case USCI_NONE: break; // UART receive interrupt case USCI_UCRXIFG: myUart.Channels[chan].RxRDY++; // Interrupt tells us that that the UART RX buffer is ready to read break; // UART transmit interrupt case USCI_UCTXIFG: myUart.Channels[chan].TxRDY = 1; // Interrupt tells us that that the UART TX buffer is available for writing if ( txBufLen == 0 ) myUart.Channels[chan].TxBusy = 0; // Set the Tx as 'not busy' if full buffer has been transfered break; // // case USCI_UART_UCSTTIFG: // __no_operation(); // break; // // case USCI_UART_UCTXCPTIFG: // __no_operation(); // break; } // Exit low-power mode: // Now that we either have received a byte - or are ready to transmit // a another byte - we need to wake up the CPU (since our read/write // routines enter LPM while waiting for the UART to do its thing) _low_power_mode_off_on_exit(); }*/ //***************************************************************************** // USCI_A1 Interrupt Service Routine //***************************************************************************** #pragma vector = USCI_A1_VECTOR __interrupt void myUart1_isr(void) { int chan = 1; switch ( __even_in_range( UCA1IV, USCI_UCTXIFG )) { case USCI_NONE: break; // UART receive interrupt case USCI_UCRXIFG: myUart.Channels[chan].RxRDY++; // Interrupt tells us that that the UART RX buffer is ready to read break; // UART transmit interrupt case USCI_UCTXIFG: myUart.Channels[chan].TxRDY = 1; // Interrupt tells us that that the UART TX buffer is available for writing if ( txBufLen == 0 ) myUart.Channels[chan].TxBusy = 0; // Set the Tx as 'not busy' if full buffer has been transfered break; // // case USCI_UART_UCSTTIFG: // __no_operation(); // break; // // case USCI_UART_UCTXCPTIFG: // __no_operation(); // break; } // Exit low-power mode: // Now that we either have received a byte - or are ready to transmit // a another byte - we need to wake up the CPU (since our read/write // routines enter LPM while waiting for the UART to do its thing) _low_power_mode_off_on_exit(); }