Configuration of UART for MSP432

Hello,

I’m trying to set up a the UART using the freeRTOS calls. I’m using MSP432P401R.


What i have:

At the moment, I have programmed the UART ‘bare metal’ configuring the pins manually, and it worked:

void init_UART_emulador(void){
    UCA0CTLW0 |= UCSWRST;
    UCA0CTLW0 |= UCSSEL__SMCLK;
    UCA0MCTLW = UCOS16;
    UCA0BRW = 3;

    P1DIR |= DIR_UART;                   // PORT P1.0 com a sortida (Data direction: Selector Tx/Rx)
    P1SEL0 &= ~DIR_UART;                 // PORT P1.0 com I/O digital (GPIO)
    P1SEL1 &= ~DIR_UART;
    P1OUT &= ~DIR_UART;                  // Inicialitzem port P1.0 a 0 (Rx)

    P1SEL0 |= BIT2 | BIT3;      //I/O UART function
    P1SEL1 &= ~ (BIT2 | BIT3);

    //Reactivem la linia de comunicacions serie
    UCA0CTLW0 &= ~UCSWRST;
    //Interrupcions
    EUSCI_A0->IFG &= ~EUSCI_A_IFG_RXIFG;    // Clear eUSCI RX interrupt flag
    EUSCI_A0->IE |= EUSCI_A_IE_RXIE;
    NVIC->ICPR[0] |= 1 <<((EUSCIA0_IRQn) & 31); // Comprovem que no hi ha int residual pendent a la USCI
    NVIC->ISER[0] |= 1 <<((EUSCIA0_IRQn) & 31); // Habilitem les int. de la USCI
}

Currently I need a 500kbs baudrate. At the main I have a call of a function init_ucs_24MHz(), which sets the SMCKL to 24Mhz (this function is from a lib so i can’t see what it does internally).


Now, I have downloaded the FreeRTOS demo for my controller. In this demo there’s a Serial file where they configure the UART, so I’m trying to stick with it. Here’s the functions that I have assembled:

void prvConfigureClocks( void )
{
    /* Set Flash wait state for high clock frequency.  Refer to datasheet for
    more details. */
    FlashCtl_setWaitState( FLASH_BANK0, 2 );
    FlashCtl_setWaitState( FLASH_BANK1, 2 );

    /* The full demo configures the clocks for maximum frequency, whereas the
    blinky demo uses a slower clock as it also uses low power features.  Maximum
    freqency also needs more voltage.

    From the datashee:  For AM_LDO_VCORE1 and AM_DCDC_VCORE1 modes, the maximum
    CPU operating frequency is 48 MHz and maximum input clock frequency for
    peripherals is 24 MHz. */
    PCM_setCoreVoltageLevel( PCM_VCORE1 );
    CS_setDCOCenteredFrequency( CS_DCO_FREQUENCY_24 );
    CS_initClockSignal( CS_HSMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
    CS_initClockSignal( CS_SMCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
    CS_initClockSignal( CS_MCLK, CS_DCOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
    CS_initClockSignal( CS_ACLK, CS_REFOCLK_SELECT, CS_CLOCK_DIVIDER_1 );
}
const eUSCI_UART_Config xUARTConfig =
{
    EUSCI_A_UART_CLOCKSOURCE_SMCLK, /* SMCLK Clock Source. */
    3,                            /* BRDIV */
    0,                              /* UCxBRF */
    0,                              /* UCxBRS */
    EUSCI_A_UART_NO_PARITY,         /* No Parity. */
    EUSCI_A_UART_LSB_FIRST,         /* MSB First. */
    EUSCI_A_UART_ONE_STOP_BIT,      /* One stop bit. */
    EUSCI_A_UART_MODE,              /* UART mode. */
    EUSCI_A_UART_OVERSAMPLING_BAUDRATE_GENERATION /* Low Frequency Mode. */
};
void init_uart0(void){
    MAP_GPIO_setAsPeripheralModuleFunctionInputPin( GPIO_PORT_P1, GPIO_PIN2 | GPIO_PIN3, GPIO_PRIMARY_MODULE_FUNCTION );

    /* Use the library functions to initialise and enable the UART. */
    MAP_UART_initModule( EUSCI_A0_BASE, &xUARTConfig );
    MAP_UART_enableModule( EUSCI_A0_BASE );

    MAP_UART_clearInterruptFlag( EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT | EUSCI_A_UART_TRANSMIT_INTERRUPT );
    MAP_UART_enableInterrupt( EUSCI_A0_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT );


    /* The interrupt handler uses the FreeRTOS API function so its priority must
    be at or below the configured maximum system call interrupt priority.
    configKERNEL_INTERRUPT_PRIORITY is the priority used by the RTOS tick and
    (should) always be set to the minimum priority. */
    MAP_Interrupt_setPriority( INT_EUSCIA0, configKERNEL_INTERRUPT_PRIORITY );
    MAP_Interrupt_enableInterrupt( INT_EUSCIA0 );
}

Now, when I use this set up the UART no longer sends any information. I suspect that there’s something wrong with the clock, but I don’t now what.

If you need more information I will gladly provide it,

Thanks!

Which demo are you using? Is it exactly for the same part?

If you replace the UART setup code in init_uart0 with the code from your bare metal application, does it work?

Hello,

I was using the demo for MSP432.

I solved the problem this morning: I was not configuring the PIN P1 in the init_uart0() for the half-duplex, also I was not inicialiting any task or the scheduler, and a few minor other things.

Now I have another problem though: when I use a queue in the IRS routine for the UART it doesn’t read all the bytes. I suspect that the problem is that the queue is too slow for the baudrate (500kbps), but I’m not sure. If I use a global variable + flag it works fine though.

Can you share what error are you facing? Like are you failing to post to queue or is the task failing to keep up?

Yes. The problem exactly is that, in the ISR of the UART, when I receive the first byte, that is, when the following code is first executed:

 if ( (xInterruptStatus & EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG ) != 0x00 ) {
        // FromISR es perque son funcions que es fan desde una ISR i tenen atencio especial
        MAP_UART_clearInterruptFlag(EUSCI_AN_BASE, EUSCI_A_UART_RECEIVE_INTERRUPT_FLAG);
        data = MAP_UART_receiveData(EUSCI_AN_BASE); //rebem la data
        xQueueSendFromISR( RxQueue, &data, &xHigherPriorityTaskWoken );
    } 

I should receive an 0xFF. Then, I should receive another 0xFF, and then more information. However, at the moment I receive only one 0xFF, and the next time that the ISR is called, then it doesn’t receive the other 0xFF, but the ‘more information’. So basically a 0xFF is disappearing.

To give more context, the ISR also gets called with the transmit:

if ((xInterruptStatus & EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG) != 0x00) {
        if (xQueueReceiveFromISR(uartTxQueue, &txByte, &xHigherPriorityTaskWoken) == pdPASS) {
            MAP_UART_transmitData(EUSCI_AN_BASE, txByte);
            // We don't need to re-enable the interrupt here, as the act of
            // writing to the transmit buffer will likely set the flag again
            // if the UART is ready for more data.
        }else{
            MAP_UART_clearInterruptFlag(EUSCI_AN_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT_FLAG);
            // No more data to transmit - disable the transmit interrupt
            MAP_UART_disableInterrupt(EUSCI_AN_BASE, EUSCI_A_UART_TRANSMIT_INTERRUPT);
            Sentit_Dades_Rx(); //Aixo ho posem aqui dsp de que acabi la transmissio
            //Sentit_Dades_Rx();
            // The direction will be switched to RX after the transmission is complete,
        }

In this case I read all the things I want to transmit from a queue, and finally, when I don’t transmit anymore, I shut down the interrupt of transmit and then change the data way. That is, the function Sentit_dades_Rx() is just a call to MAP_GPIO_setOutputLowOnPin(UART_GPIO_PORT_DADES, GPIO_PIN0); which changes the pin0 of the port3 to outputlow (the communication is half-duplex so now I have to receive).

This is almost always due to being “too slow”. First, does the serial port have a FIFO on it? If not at 500k baud you only have 10 us to respond and get the data before the next byte might come. Your first post indicated a processor speed of 48 MHz, which means only 480 instrucitons to respond, including the processing. This could be tight, especially if the interrupt comes during a critical section where the interrupts are disabled for a short while (or longer while if a poorly done critical section is used).

Does you code check for an “Overrun” condition on the serial port?

If the serial port doesn’t have a FIFO, the system may not be able to run the simple Uart driver of the demos at that baud rate, which are indicated to be not really suitable for high speed.

Hello,

Thanks for answering. In fact I’m not using 48Mhz but 24Mhz, so the time to respond is even lower. Earlier I had no problems when doing with bare metal because between sending and receiving there were few instructions and just register manipulation. So it’s probably this problem.

I’m checking the datasheet of the MSP432 and I don’t think it has a FIFO in the serial port. The buffer part reads:

The UCRXIFG interrupt flag is set each time a character is received and loaded into UCAxRXBUF. An interrupt request is generated if UCRXIE is set. UCRXIFG and UCRXIE are reset by a Hard Reset signal or when UCSWRST = 1. UCRXIFG is automatically reset when UCAxRXBUF is read.

And I can’t find any FIFO mentioned there or around.

What do you mean by checking for an Overrun condition?

Also, I indeed read that indication that the demos were not suitable for high speed. It’s not critical if I dont receive the first Byte, as it doesn’t hold information, but I’m curious as how I would have to read it if it is not in that way.

The code you first posted had a comment that it was setting the PROCESSOR to 48 MHz, but the peripheral bus to 24 MHz. If you are dropping the processor to be slow, that will make the problem worse.

Most Serial Ports will have a status register, perhaps the same one that indicates there is data available, to indicate errors in the receptions: no stop bit, bad parity (if in a format with parity), or an overrun condition.

The problem with sometimes not getting the first byte, is you will never know which byte you might loose.

The best soluiton for very high speed data reception is to use DMA, but this often isn’t suitable for serial protocols.

A second method is to have the ISR receive data into a fixed buffer, rather than a queue, and detect when the message is “done” and then flag a task. If this isn’t fast enough, due to critical sections blocking it, you need to put it at an interupt priority that FreeRTOS doesn’t block, and then use some non-FreeRTOS method to signal the program, I often try to find an interrupt that ISR can trigger that will be in the FreeRTOS range, and let that send the notification.

Hello,

Thanks for the information! I will try the buffer thing.