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.
I have the UART loopback example working at 1Mbps baud rate with no problems. I used a 4MHz SMCLK for the UART clock. These results are using an eternal clock on the MSP430 EVM.
When interfaced with the BQ79600EVM and the a custom BQ79616, the uart receive interrupt is firing soon after I try a single device read command. I can see the UCOE flag is set. Is there anything wrong in the setup/use of the UART driver?
I have setup a 100 bit delay for the BQ79600 chip to respond so the MSP430 has time to switch from uart transmit to uart receive. Is there an ideal number for the MSP430 for this to happen?
I am using the external clock in this setup.
#define BQUART EUSCI_A1_BASE #define BQUART_DISABLE EUSCI_A_UART_disable #define BQUART_CLOCKSOURCE EUSCI_A_UART_CLOCKSOURCE_SMCLK #define BQUART_PARITY EUSCI_A_UART_NO_PARITY #define BQUART_BITORDER EUSCI_A_UART_LSB_FIRST #define BQUART_STOPBIT EUSCI_A_UART_ONE_STOP_BIT #define BQUART_MODE EUSCI_A_UART_MODE #define BQUART_OVERSAMPLING EUSCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION #define BQUART_INIT EUSCI_A_UART_init #define BQUART_initParam EUSCI_A_UART_initParam #define BQUART_enable EUSCI_A_UART_enable #define BQUART_disable EUSCI_A_UART_disable #define BQUART_REG P2OUT #define BQUART_TX_PORT GPIO_PORT_P2 #define BQUART_RX_PORT GPIO_PORT_P2 #define BQUART_RX_PIN GPIO_PIN6 #define BQUART_TX_PIN GPIO_PIN5 #define BQUART_SELECT_FUNCTION GPIO_SECONDARY_MODULE_FUNCTION #define BQUART_enableInterrupt EUSCI_A_UART_enableInterrupt #define BQUART_RX_INT EUSCI_A_UART_RECEIVE_INTERRUPT #define BQUART_clearInterrupt EUSCI_A_UART_clearInterrupt #define BQUART_TXBUF UCA1TXBUF #define BQUART_RXBUF UCA1RXBUF #define BQUART_ISR USCI_A1_ISR #define BQUART_VECTOR USCI_A1_VECTOR #define BQUART_IFG UCA1IFG #define BQUART_IV UCA1IV #define BQUART_BUSY (UCA1STATW&UCBUSY) void Clock_Init() { #ifdef EXT_CLK GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_PJ, GPIO_PIN4 + GPIO_PIN5, GPIO_PRIMARY_MODULE_FUNCTION ); // Set PJ.6 and PJ.7 as Primary Module Function Input, HFXT. GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_PJ, GPIO_PIN6 + GPIO_PIN7, GPIO_PRIMARY_MODULE_FUNCTION ); // Check if one FRAM waitstate is needed for 5962, 5994 device as well! FRAMCtl_A_configureWaitStateControl(FRAMCTL_A_ACCESS_TIME_CYCLES_1); uint32_t u32ClockFrequencyCheck = 0u; // JA - Enable lxft & HXFT CS_setExternalClockSource(32768, 16000000); CS_initClockSignal(CS_SMCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_4); CS_initClockSignal(CS_MCLK, CS_HFXTCLK_SELECT, CS_CLOCK_DIVIDER_1); //Set ACLK=LFXT CS_initClockSignal(CS_ACLK, CS_LFXTCLK_SELECT, CS_CLOCK_DIVIDER_1); //Set the appropriate drive values for each oscillator for the launchpad vs. actual schematic. CS_turnOnLFXT(CS_LFXT_DRIVE_3); // CS_turnOnLFXT(CS_LFXT_DRIVE_0); CS_turnOnHFXT(CS_HFXT_DRIVE_16MHZ_24MHZ); // JA - SMCLK appears to be running extremely slowly when sourced from HFXT // JA - Check SMCLK, MCLK clock frequencies u32ClockFrequencyCheck = CS_getMCLK(); u32ClockFrequencyCheck = CS_getSMCLK(); #endif #ifdef DCO_CLK // Configure one FRAM waitstate as required by the device datasheet for MCLK // operation beyond 8MHz _before_ configuring the clock system. FRCTL0 = FRCTLPW | NWAITS_1; // Clock System Setup CSCTL0_H = CSKEY_H; // Unlock CS registers CSCTL1 = DCOFSEL_0; // Set DCO to 1MHz // Set SMCLK = MCLK = DCO, ACLK = VLOCLK CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK; // Per Device Errata set divider to 4 before changing frequency to // prevent out of spec operation from overshoot transient CSCTL3 = DIVA__4 | DIVS__4 | DIVM__4; // Set all corresponding clk sources to divide by 4 for errata CSCTL1 = DCOFSEL_4 | DCORSEL; // Set DCO to 16MHz // Delay by ~10us to let DCO settle. 60 cycles = 20 cycles buffer + (10us / (1/4MHz)) __delay_cycles(60); CSCTL3 = DIVA__1 | DIVS__4 | DIVM__1; // SMCLK=2Mhz MCLK=16MHz CSCTL0_H = 0; // Lock CS registers #endif } void UART_Init(void){ GPIO_setAsPeripheralModuleFunctionInputPin( BQUART_TX_PORT, BQUART_TX_PIN + BQUART_RX_PIN, BQUART_SELECT_FUNCTION ); BQUART_initParam param = {0}; param.clockPrescalar = 4, param.firstModReg = 0, param.secondModReg = 0, param.selectClockSource = BQUART_CLOCKSOURCE; param.parity = BQUART_PARITY; param.msborLsbFirst = BQUART_BITORDER; param.numberofStopBits = BQUART_STOPBIT; param.uartMode = BQUART_MODE; param.overSampling = BQUART_OVERSAMPLING; if(STATUS_FAIL == BQUART_INIT(BQUART, ¶m)) { return; } BQUART_enable(BQUART); BQUART_clearInterrupt(BQUART, BQUART_RX_INT); BQUART_enableInterrupt(BQUART, BQUART_RX_INT); } void uartSend(int length, uint8_t * data){ uint8_t i; for (i = 0; i < length; i++){ while (!(UCA1IFG & UCTXIFG)); BQUART_TXBUF = data[i]; } } void uartReceive(BYTE * data, BYTE length){ while (length > 0){ while (BQUART_BUSY); *data = BQUART_RXBUF; data++; length--; } } //****************************************************************************** // SPI_B1 Interrupt ************************************************************ //****************************************************************************** #pragma vector=BQUART_VECTOR /******************************************************************************* USCI_B1_ISR ****************************************************************** ******************************************************************************* * Function: B1 Interrupt Routine ********************************************************************************/ __interrupt void BQUART_ISR(void) { switch(__even_in_range(BQUART_IV, USCI_UART_UCTXCPTIFG)) { case USCI_NONE: break; case USCI_UART_UCRXIFG: BQUART_IFG &= ~UCRXIFG; __bic_SR_register_on_exit(LPM0_bits); // Exit LPM0 on reti break; case USCI_UART_UCTXIFG: break; case USCI_UART_UCSTTIFG: break; case USCI_UART_UCTXCPTIFG: break; default: break; } } #endif
1) Using UCBUSY for receive is just flat out wrong. If a steady stream of data is being received then the time between when the receiver state machine finishes up (somewhere in the final stop bit) and the next start bit is short. Really short at 1Mbps.
2) Reading the IV register will have reset RXIFG so no need to do that again in the ISR.
3) Waking up the main task to handle the data is not going to work. The usual method is to put the data into a queue. The main task can then check to see if there is data in the queue.
4) Even with a 16Mhz clock you don't have a lot of time to deal with each byte of data.
5) It takes no time at all for the MSP430 to switch the UART from transmit to receive. In fact they work simultaneously. Which means you could get a receive interrupt before the transmit code is finished.
I looked at the loopback example and I see the only processing done in the receive ISR is assigning
EUSCI_A_UART_receiveData(EUSCI_A0_BASE).
I eliminated other things I had in the ISR.
My setup is MSP-EXP430FR5994 -> BQ79600EVM -> custom BQ79616
When reading from the BQ79600EVM, a read command is issued for the specific register.
Then a ReadFrameReq is sent out. This involves a write message through the UART.
Here is where you say that the receive can happen even before the transmit ends. Can you explain more about the transmit and receive working simultaneously? I see Figure 30-1 in SLAU367P on page 769.
I don’t have RTOS in the firmware, there is a main loop. Here is what I tried to restructure the uart receive, I don’t have uartReceive anymore. This still does not work. I can use some more pointers.
#pragma vector=BQUART_VECTOR /******************************************************************************* USCI_B1_ISR ****************************************************************** ******************************************************************************* * Function: B1 Interrupt Routine ********************************************************************************/ __interrupt void BQUART_ISR(void) { switch(__even_in_range(BQUART_IV, USCI_UART_UCTXCPTIFG)) { case USCI_NONE: break; case USCI_UART_UCRXIFG: RXData[idx] = EUSCI_A_UART_receiveData(BQUART); idx++; if (idx == uartRxLen) rxComplete = 1; break; case USCI_UART_UCTXIFG: break; case USCI_UART_UCSTTIFG: break; case USCI_UART_UCTXCPTIFG: break; default: break; } } #endif
The receiver and transmitter are independent. Sharing a bit rate generator and not much else. So if data arrives while the transmitter is sending something, the receiver is going to handle it.
You say it doesn't work. How doesn't it work? Is there no data at all in the receive buffer? Data that looks wrong? Not enough data? All of these are clues to the problem. (Too much data would cause trouble and a likely buffer overrun.)
I have a breakpoint at the first step ReadReg. If I step into this, it goes straight into the UART ISR, overrun flag is set. Instead of stepping in, I put a breakpoint at WriteFrame and run the program until here. Then I put a breakpoint in the ISR and run the program until here. I find one byte is received (not the one expected), the idx increments and then the ISR does not continue triggering until the uartRxLen.
Even if I wait to enable the receive interrupt until uartSend, somehow the UART ISR is firing. How can this be? If all of uartRxLen is received, I disable the receive interrupt.
Did you try using DMA to your UART receive and Transmit operation?
As David suggested, use queue to push data using DMA and check the queue once the DMA transfer is complete
**Attention** This is a public forum