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.

MSPM0L1306-Q1: UART-SPI Bridge

Part Number: MSPM0L1306-Q1
Other Parts Discussed in Thread: TLC6C5748-Q1, MSPM0L1306, SYSCONFIG

Hello,

Context:

I am working on a reference design that involves pushing data from a launchpad to a reference design board using UART. The MSPM0L on the board will then send this data to the TLC6C5748-Q1 via SPI. I am creating code for the MSPM0L1306 on the board.

Code for the SPI transactions between the MSPM0L1306 and TLC6C5748 is implemented in the project (it is based on the spi_controller_multibyte_fifo_dma_interrupts example), but code for UART event handling is missing.

Since I am new to both UART and SPI, I opted to create a simple test setup using two launchpads to create code that handles both UART and SPI communication. I am using the spi_controller_multibyte_fifo_dma_interruptsspi_peripheral_multibyte_fifo_dma_interrupts example, and adding some code from the uart_rw_multibyte_fifo_poll example. I can confirm that all the examples work for me. Overall, here are the conditions I expect for a successful test:

1) Peripheral sends a message via UART to controller.

2) Controller receives message. Controller replaces contents of gTxPacket with the uART message.

3) Controller & Peripheral fill up their TXFIFO. 

4) Controller begins SPI transaction, and the same steps as the multibyte_fifo example occur.

Problem:

I am having trouble adding code to support the UART interface. When I run my code to test step 1, the Peripheral TX line stays low. It won't go high again even after resetting both launchpads. The only way to reset it is to power-cycle the boards.

When I disconnect TX and RX between the launchpads, I see the correct UART Message.

Can you provide guidance on how to go about fixing this? I suspect that it is either something with spi_controller_multibyte_fifo_dma_interrupts or sysconfig setup. Here is my code:

spi_controller_multibyte_fifo_dma_interrupts

/*
 * Copyright (c) 2020, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ti_msp_dl_config.h"

/*
 * Number of bytes for SPI packet size
 * The packet will be transmitted by the SPI controller.
 * This example uses FIFOs, and the maximum FIFO size is 4.
 */
#define SPI_PACKET_SIZE (4)

/* Data for SPI to transmit */
uint8_t gTxPacket[SPI_PACKET_SIZE] = {'M', 'S', 'P', '!'};

/* Data for SPI to receive */
uint8_t gRxPacket[SPI_PACKET_SIZE];

volatile bool gSPIDataTransmitted, gDMATXDataTransferred,
    gDMARXDataTransferred;

#define UART_PACKET_SIZE (4)

/* Delay for 5ms to ensure UART TX is idle before starting transmission */
#define UART_TX_DELAY (160000)

/* Data for UART to transmit */
uint8_t uARTtxPacket[UART_PACKET_SIZE] = {'A', 'D', '!', '!'};

/* Data received from UART */
uint8_t uARTrxPacket[UART_PACKET_SIZE];

volatile bool gCheckUART;

int main(void)
{
    SYSCFG_DL_init();
    NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
    NVIC_EnableIRQ(UART_0_INST_INT_IRQN);
    delay_cycles(UART_TX_DELAY);

    #if (ENABLE_LOOPBACK_MODE == true)
        /* Enable the internal loopback mode */
        DL_UART_enableLoopbackMode(UART_0_INST);
    #endif

    for (uint8_t i = 0; i < UART_PACKET_SIZE; i++) {
           uARTrxPacket[i] = DL_UART_receiveDataBlocking(UART_0_INST);
        }

    //while(gUARTEvent == false)
      //  __WFE();

    gSPIDataTransmitted   = false;
    gDMATXDataTransferred = false;
    gDMARXDataTransferred = false;

    /*
     * Configure DMA source, destination and size to transfer data from
     * gTxPacket to TXDATA. The DMA transfer will start when TX interrupt is
     * set, which it should already be set (which indicates that the SPI is
     * ready to transfer) so the DMA will begin this transfer when the channel
     * is enabled.
     */
    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gTxPacket[0]);
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&SPI_0_INST->TXDATA));
    DL_DMA_setTransferSize(
        DMA, DMA_CH0_CHAN_ID, sizeof(gTxPacket) / sizeof(gTxPacket[0]));

    /*
     * Configure DMA source, destination and size from RXDATA to gRxPacket.
     * The DMA transfer will start when the RX interrupt is set, which happens
     * when the device receives data.
     */
    DL_DMA_setSrcAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(&SPI_0_INST->RXDATA));
    DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t) &gRxPacket[0]);
    DL_DMA_setTransferSize(DMA, DMA_CH1_CHAN_ID, SPI_PACKET_SIZE);
    DL_DMA_enableChannel(DMA, DMA_CH1_CHAN_ID);

    DL_SYSCTL_disableSleepOnExit();
    NVIC_EnableIRQ(SPI_0_INST_INT_IRQN);

    /*
     * The SPI TX interrupt is already set, indicating the SPI is ready to
     * transmit data, so enabling the DMA will start the transfer
     */
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    /*
     * Wait in SLEEP mode until SPI_PACKET_SIZE bytes have been transferred
     * from gTxPacket to the SPI TXFIFO, and the DMA interrupt is triggered
     */
    while (false == gDMATXDataTransferred) {
        __WFE();
    }

    /*
     * Wait until the SPI has transmitted all the data and the TXFIFO
     * is empty
     */
    while (false == gSPIDataTransmitted) {
        __WFE();
    }

    /*
     * Wait in SLEEP mode until SPI_PACKET_SIZE bytes have been transferred
     * from SPI TXFIFO to gRxPacket, and the DMA interrupt is triggered
     */
    while (false == gDMARXDataTransferred) {
        __WFE();
    }

    /*
     * Set a SW breakpoint to check results.
     * If this example is used with the
     * spi_peripheral_multibyte_fifo_dma_interrupts example,
     * the expected data that will be received in gRxPacket is
     * {0x1, 0x2, 0x3, 0x4}.
     */
    __BKPT(0);

    while (1) {
        __WFI();
    }
}

void SPI_0_INST_IRQHandler(void)
{
    switch (DL_SPI_getPendingInterrupt(SPI_0_INST)) {
        case DL_SPI_IIDX_DMA_DONE_TX:
            /* DMA is done transferring data from gTxPacket to TXFIFO */
            gDMATXDataTransferred = true;
            break;
        case DL_SPI_IIDX_TX_EMPTY:
            /* SPI is done transmitting data and TXFIFO is empty */
            gSPIDataTransmitted = true;
            break;
        case DL_SPI_IIDX_DMA_DONE_RX:
            /* DMA is done transferring data from RXFIFO to gRxPacket*/
            gDMARXDataTransferred = true;
        default:
            break;
    }
}

void UART_0_INST_IRQHandler(void)
{
    switch (DL_UART_Main_getPendingInterrupt(UART_0_INST)) {
        case DL_UART_MAIN_IIDX_RX:
        {
            gCheckUART = true;
            // data = DL_UART_Main_receiveData(UART_0_INST);
            // DL_UART_Main_transmitData(UART_0_INST, data);
            break;
        }
        default:
            break;
    }
}

spi_peripheral_multibyte_fifo_dma_interrupts 

/*
 * Copyright (c) 2020, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include "ti_msp_dl_config.h"

/*
 * Number of bytes for SPI packet size
 * The packet will be transmitted by the SPI peripheral.
 * This example uses FIFOs, and the maximum FIFO size is 4.
 */
#define SPI_PACKET_SIZE (4)

/* Data for SPI to transmit */
uint8_t gTxPacket[SPI_PACKET_SIZE] = {0x1, 0x2, 0x3, 0x4};

/* Data for SPI to receive */
uint8_t gRxPacket[SPI_PACKET_SIZE];

volatile bool gSPIDataTransmitted, gDMARXDataTransferred,
    gDMATXDataTransferred;

#define UART_PACKET_SIZE (4)

/* Delay for 5ms to ensure UART TX is idle before starting transmission */
#define UART_TX_DELAY (160000)

/* Data for UART to transmit */
uint8_t uARTtxPacket[UART_PACKET_SIZE] = {'T', 'I', '!', '!'};

/* Data received from UART */
uint8_t uARTrxPacket[UART_PACKET_SIZE];

int main(void)
{
    SYSCFG_DL_init();
    NVIC_ClearPendingIRQ(UART_0_INST_INT_IRQN);
    NVIC_EnableIRQ(UART_0_INST_INT_IRQN);

    delay_cycles(UART_TX_DELAY);

    #if (ENABLE_LOOPBACK_MODE == true)
        /* Enable the internal loopback mode */
        DL_UART_enableLoopbackMode(UART_0_INST);
    #endif

    /* Fills TX FIFO with data and transmits the data */
    DL_UART_Main_fillTXFIFO(UART_0_INST, &uARTtxPacket[0], UART_PACKET_SIZE);

    /* Wait until all bytes have been transmitted and the TX FIFO is empty */
    while (DL_UART_Main_isBusy(UART_0_INST))
        ;

    /*
     * Wait to receive the UART data
     * This loop expects UART_PACKET_SIZE bytes
     */
        /*
    for (uint8_t i = 0; i < UART_PACKET_SIZE; i++) {
       uARTrxPacket[i] = DL_UART_receiveDataBlocking(UART_0_INST);
    }*/

    gSPIDataTransmitted   = false;
    gDMARXDataTransferred = false;
    gDMATXDataTransferred = false;

    /*
     * Configure DMA source, destination and size to transfer data from
     * gTxPacket to TXDATA. The DMA transfer will start when TX interrupt is
     * set, which it should already be set (which indicates that the SPI is
     * ready to transfer) so the DMA will begin this transfer when the channel
     * is enabled. However the SPI Peripheral will not actually start
     * transmitted data until the SPI Controller initiates a transaction.
     */



    DL_DMA_setSrcAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t) &gTxPacket[0]);
    DL_DMA_setDestAddr(DMA, DMA_CH0_CHAN_ID, (uint32_t)(&SPI_0_INST->TXDATA));
    DL_DMA_setTransferSize(
        DMA, DMA_CH0_CHAN_ID, sizeof(gTxPacket) / sizeof(gTxPacket[0]));
    DL_DMA_enableChannel(DMA, DMA_CH0_CHAN_ID);

    /*
     * Configure DMA source, destination and size from RXDATA to gRxPacket.
     * The DMA transfer will start when the RX interrupt is set, which happens
     * when the device receives data.
     */
    DL_DMA_setSrcAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t)(&SPI_0_INST->RXDATA));
    DL_DMA_setDestAddr(DMA, DMA_CH1_CHAN_ID, (uint32_t) &gRxPacket[0]);
    DL_DMA_setTransferSize(DMA, DMA_CH1_CHAN_ID, SPI_PACKET_SIZE);
    DL_DMA_enableChannel(DMA, DMA_CH1_CHAN_ID);

    DL_SYSCTL_disableSleepOnExit();
    NVIC_EnableIRQ(SPI_0_INST_INT_IRQN);

    /*
     * Wait in SLEEP mode until data is transferred and DMA interrupt
     * is triggered
     */
    while (false == gDMATXDataTransferred) {
        __WFE();
    }

    /*
     * Wait until the SPI has transmitted all the data and the TXFIFO
     * is empty
     */
    while (false == gSPIDataTransmitted) {
        __WFE();
    }

    /*
     * Wait in SLEEP mode until data is received and DMA interrupt
     * is triggered
     */
    while (false == gDMARXDataTransferred) {
        __WFE();
    }

    /*
     * Set a SW breakpoint to check results.
     * If this example is used with the
     * spi_controller_multibyte_fifo_dma_interrupts example,
     * the expected data to receive in gRxPacket is
     * {'M', 'S', 'P', '!'}.
     */
    __BKPT(0);

    while (1) {
        __WFI();
    }
}

void SPI_0_INST_IRQHandler(void)
{
    switch (DL_SPI_getPendingInterrupt(SPI_0_INST)) {
        case DL_SPI_IIDX_DMA_DONE_TX:
            /* DMA is done transferring data from gTxPacket to TXFIFO */
            gDMATXDataTransferred = true;
            break;
        case DL_SPI_IIDX_TX_EMPTY:
            /* SPI is done transmitting data and TXFIFO is empty */
            gSPIDataTransmitted = true;
            break;
        case DL_SPI_IIDX_DMA_DONE_RX:
            /* DMA is done transferring data from RXFIFO to gRxPacket*/
            gDMARXDataTransferred = true;
            break;

        default:
            break;
    }
}


Let me know if you need anymore information.

Thanks!

  • Hi David,

    How are you configuring the UART pin on the RX side and what pin are you using? It seems like it might be holding the TX line low for some reason. Really it shouldn't act on that line beyond sampling it. 

    Best Regards,
    Brandon Fisher

  • Hey Brandon,

    For both projects, Pin 22 is UART0.RX and Pin 21 is UART0.TX. For my test, I tie Peripheral TX with Controller RX, and Controller TX with Peripheral RX.

    The UART for both projects are configured very similar to to the uart_rw_multibyte_fifo_poll project. The only addition I made was an interrupt which I don't think should change much. 

    Sysconfig for Controller board:

    I should also mention that the Controller board (The board receiving the UART message) is a pre-production launchpad. The peripheral board is a production launchpad.

    Thanks,

    David Martinez

  • Thanks David,

    I should also mention that the Controller board (The board receiving the UART message) is a pre-production launchpad. The peripheral board is a production launchpad.

    Are you using two different SDK and CCS installations for this? 

    I want to ensure you aren't encountering any issues due to mismatched software/tools versions and silicon revisions. Your software versions need to match what is described here based on your silicon versions: https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1204644/faq-mspm0-sdk-important-note-for-early-mspm0-customers

    Best Regards,
    Brandon Fisher

  • Hey Brandon,

    I am using CCS Eclipse 12.3 with SDK version 1.0.1.03. I see from the FAQ that pre-production copies do not meet the standard for these versions. What issues can arise from using these versions with a pre-production copy?

    I have another production launchpad I can try this on to see if I can get different results.

    Best,

    David Martinez

  • David,

    There are quite a few differences between the two silicon revisions that the SDK and support package (tied to your CCS version) are taking care of under the hood. 

    Its hard to say everything that could happen, but a peripheral/pin initializing wrong, failing to start, or behaving strangely is what I commonly see. The behavior you are seeing could easily be cause by this, especially since the production launchpad appears to transmit correctly when you disconnect it from the pre-production one.

    I would advise you to try your other production launchpad, and ideally update to CCS12.4 and SDK Version 1.10.x as well, as they contain some bug fixes. 

    Best Regards,
    Brandon Fisher

  • Brandon,

    Thanks for the clarification. I'll retry the test with 2 production launchpads and let you know what I find.

    - David Martinez

  • Hey Brandon,

    I retried the test and saw similar results with production launchpads.

    Here are some things I noticed:

    • When resetting the peripheral board with the controller board running, the TX line will go low and stay low as we've seen before. To make testing simple, I wanted to press the restart button on the peripheral board while the controller is waiting for a UART message. 
    • The Peripheral code is stuck on line 79 (while (DL_UART_Main_isBusy(UART_0_INST))). Even when the UART message is sent (With or without controller board connected) it is stuck. Why is this the case? My understanding of this line is that once the TXFIFO is empty, it fires an interrupt to exit this loop.
    • The TX line will only be restored if I restart both boards at the same time, but let go of the reset button on the peripheral board first.

    I am still using the same CCS and SDK version as before.

    - David Martinez

  • Hi David,

    The Peripheral code is stuck on line 79 (while (DL_UART_Main_isBusy(UART_0_INST))). Even when the UART message is sent (With or without controller board connected) it is stuck. Why is this the case? My understanding of this line is that once the TXFIFO is empty, it fires an interrupt to exit this loop.

    That Busy status flag should clear and the code should be able to proceed. You shouldn't need any specific interrupt enabled for this to occur. 

    I don't see anything in your code that is obviously causing this. Both production launchpads are MSPM0L correct? 

    If you flash the RW_Multibyte_FIFO_Poll example on both boards and connect them as you have them now, do you see the same failure? 

    When you get stuck on line 79, what is the value in the UART0_STAT register? You can check this in CCS if you go to View-> Registers while debugging. 

    Best Regards,
    Brandon Fisher

  • Hey Brandon,

    When you get stuck on line 79, what is the value in the UART0_STAT register? You can check this in CCS if you go to View-> Registers while debugging. 

    I was unable to reproduce this error when both boards are connected, but when they are disconnected, I found that connecting TX for the peripheral will fix this.

    I flashed both production boards (Both MSPM0L1306) with RW_Multibyte_FIFO_Poll example and they work using PA8 and PA9 as RX/TX. However, when I change the pin configuration so that PA17 is UART0.TX and PA18 is UART0.RX, the boards give similar behavior to my project. For some reason, only one board can behave correctly at a time. When I reset both boards, only the board that I release reset first will behave correctly. In the picture below, I release peripheral first and then later release reset for controller first. Is there a pin configuration I am missing? I tried removing header J11 but this did not fix the problem.

  • For posterity, this particular issue was solved offline.

    The issue was happening because PA18 is the default BSL Invocation pin. When one device is reset but PA18 (UART_RX) is connected to the other devices PA17 (UART_TX), the high line cause the device to boot into BSL mode. 

    It is possible to disable or move the BSL Invocation pin to another pin using the NONMAIN configuration section in SysConfig. 

    Best Regards,
    Brandon Fisher