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.

Help on adding DMA function to a RTOS project for 1294 LaunchPad

Hi,

I have read through RTOS get started and user manual several times and import RTOS projects running on LaunchPad, but only have limited experience at RTOS now.

After running uart_dma project from "TivaWare_C_Series-2.1.1.71" and RTOS project mutex with TM4C1294 Launch Pad, I want to insert DMA function to the RTOS proejct. Before modifying .cfg file, I simply rename uart_dma source C main() function to a general function main0(). The needed header file and library paths are added. The new (added uart DMA function) .c file can pass build. I think that DMA and Uart interrupt function do not register in the RTOS project. They should behave like a general function. I want to modify the uart_dma function to its appropriate places (into tasks, initialize before RTOS running) gradually.

To my surprise, the code is stuck at loop: 

    for(ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++)
    {
        g_ui8TxBuf[ui16Idx] = ui16Idx;
    }
UART_TXBUF_SIZE is 256. When I pause the LauchPad out of running (It should not run stuck at some where before a desired breakpoint). It shows 

Void Hwi_excDumpRegs(UInt lr)
{
Hwi_ExcContext *excp;
Char *ttype;
UInt coreId = 0;
Char *name;

excp = Hwi_module->excContext[coreId];


Although optimization is turned off, the code may not shows running through line exactly. I suspect that the following line causes the above Hwi dump:

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);

I am not clear about how to deal with the above enable code in RTOS for LaunchPad. Could you give me some advice?

Thanks,

udma_mutex_EK_TM4C1294XL.zip

Void task1(UArg arg0, UArg arg1);
Void task2(UArg arg0, UArg arg1);

Int resource = 0;
Semaphore_Handle sem;
Task_Handle tsk1;
Task_Handle tsk2;

Int finishCount = 0;

/*
 *  ======== main ========
 */
extern int main0(void);
Int main()
{
    Task_Params taskParams;

    /* Call board init functions */
    Board_initGeneral();
    main0();

void
InitUART1Transfer(void)
{
    uint_fast16_t ui16Idx;

    //
    // Fill the TX buffer with a simple data pattern.
    //
    for(ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++)
    {
        g_ui8TxBuf[ui16Idx] = ui16Idx;
    }



static uint32_t ui32PrevSeconds;
static uint32_t ui32PrevXferCount;
static uint32_t ui32PrevUARTCount = 0;
uint32_t ui32XfersCompleted;
uint32_t ui32BytesTransferred;

//
// Set the clocking to run directly from the crystal at 120MHz.
//
g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
SYSCTL_OSC_MAIN |
SYSCTL_USE_PLL |
SYSCTL_CFG_VCO_480), 120000000);

//
// Enable peripherals to operate when CPU is in sleep.
//
ROM_SysCtlPeripheralClockGating(true);

//
// Enable the GPIO port that is used for the on-board LED.
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);

//
// Enable the GPIO pins for the LED (PN0).
//
ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0);

//
// Initialize the UART.
//
ConfigureUART();
UARTprintf("\033[2J\033[H");
UARTprintf("uDMA Example\n");

//
// Show the clock frequency on the display.
//
UARTprintf("Tiva C Series @ %u MHz\n\n", g_ui32SysClock / 1000000);

//
// Show statistics headings.
//
UARTprintf("CPU\tRemaining\tMemory\t\t\t UART\n");
UARTprintf("Usage\tTime\t\tTransfers\t\t Transfers\n");

//
// Configure SysTick to occur 100 times per second, to use as a time
// reference. Enable SysTick to generate interrupts.
//
ROM_SysTickPeriodSet(g_ui32SysClock / SYSTICKS_PER_SECOND);
ROM_SysTickIntEnable();
ROM_SysTickEnable();

//
// Initialize the CPU usage measurement routine.
//
CPUUsageInit(g_ui32SysClock, SYSTICKS_PER_SECOND, 2);

//
// Enable the uDMA controller at the system level. Enable it to continue
// to run while the processor is in sleep.
//
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);

//
// Enable the uDMA controller error interrupt. This interrupt will occur
// if there is a bus error during a transfer.
//
ROM_IntEnable(INT_UDMAERR);

//
// Enable the uDMA controller.
//
ROM_uDMAEnable();

//
// Point at the control table to use for channel control structures.
//
ROM_uDMAControlBaseSet(pui8ControlTable);

//
// Initialize the uDMA memory to memory transfers.
//
InitSWTransfer();

//
// Initialize the uDMA UART transfers.
//
InitUART1Transfer();

//
// Remember the current SysTick seconds count.
//
ui32PrevSeconds = g_ui32Seconds;

//
// Remember the current count of memory buffer transfers.
//
ui32PrevXferCount = g_ui32MemXferCount;

//
// Loop until the button is pressed. The processor is put to sleep
// in this loop so that CPU utilization can be measured.
//
while(1)
{

  • Excuse me. The format in above post makes reading difficult. I would rephrase my question here clearly.

    I know UART and DMA interrupt handler should be registered in RTOS. The initialization code should be run before RTOS
    BIOS_start(); /* does not return */

    My question is: Does the Uart initialization code should run or not?

    //
    // Enable the UART peripheral, and configure it to operate even if the CPU
    // is in sleep.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART1);
    .......
    In my present test, it causes:

    Void Hwi_excDumpRegs(UInt lr)
    {
    Hwi_ExcContext *excp;
    Char *ttype;
    UInt coreId = 0;
    Char *name;

    excp = Hwi_module->excContext[coreId];



    Can you give me some advice on how to add DMA to a RTOS project?
    Thanks,

    ............................
    This is the uart_dma code:

    void
    SysTickHandler(void)
    {
    static uint32_t ui32TickCount = 0;

    //
    // Increment the tick counter.
    //
    ui32TickCount++;

    //
    // If the number of ticks per second has occurred, then increment the
    // seconds counter.
    //
    if(!(ui32TickCount % SYSTICKS_PER_SECOND))
    {
    g_ui32Seconds++;
    }

    //
    // Call the CPU usage tick function. This function will compute the amount
    // of cycles used by the CPU since the last call and return the result in
    // percent in fixed point 16.16 format.
    //
    g_ui32CPUUsage = CPUUsageTick();
    }

    //*****************************************************************************
    //
    // The interrupt handler for uDMA errors. This interrupt will occur if the
    // uDMA encounters a bus error while trying to perform a transfer. This
    // handler just increments a counter if an error occurs.
    //
    //*****************************************************************************
    void
    uDMAErrorHandler(void)
    {
    uint32_t ui32Status;

    //
    // Check for uDMA error bit
    //
    ui32Status = ROM_uDMAErrorStatusGet();

    //
    // If there is a uDMA error, then clear the error and increment
    // the error counter.
    //
    if(ui32Status)
    {
    ROM_uDMAErrorStatusClear();
    g_ui32uDMAErrCount++;
    }
    }

    //*****************************************************************************
    //
    // The interrupt handler for uDMA interrupts from the memory channel. This
    // interrupt will increment a counter, and then restart another memory
    // transfer.
    //
    //*****************************************************************************
    void
    uDMAIntHandler(void)
    {
    uint32_t ui32Mode;

    //
    // Check for the primary control structure to indicate complete.
    //
    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SW);
    if(ui32Mode == UDMA_MODE_STOP)
    {
    //
    // Increment the count of completed transfers.
    //
    g_ui32MemXferCount++;

    //
    // Configure it for another transfer.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW, UDMA_MODE_AUTO,
    g_ui32SrcBuf, g_ui32DstBuf,
    MEM_BUFFER_SIZE);

    //
    // Initiate another transfer.
    //
    ROM_uDMAChannelEnable(UDMA_CHANNEL_SW);
    ROM_uDMAChannelRequest(UDMA_CHANNEL_SW);
    }

    //
    // If the channel is not stopped, then something is wrong.
    //
    else
    {
    g_ui32BadISR++;
    }
    }

    //*****************************************************************************
    //
    // The interrupt handler for UART1. This interrupt will occur when a DMA
    // transfer is complete using the UART1 uDMA channel. It will also be
    // triggered if the peripheral signals an error. This interrupt handler will
    // switch between receive ping-pong buffers A and B. It will also restart a TX
    // uDMA transfer if the prior transfer is complete. This will keep the UART
    // running continuously (looping TX data back to RX).
    //
    //*****************************************************************************
    void
    UART1IntHandler(void)
    {
    uint32_t ui32Status;
    uint32_t ui32Mode;

    //
    // Read the interrupt status of the UART.
    //
    ui32Status = ROM_UARTIntStatus(UART1_BASE, 1);

    //
    // Clear any pending status, even though there should be none since no UART
    // interrupts were enabled. If UART error interrupts were enabled, then
    // those interrupts could occur here and should be handled. Since uDMA is
    // used for both the RX and TX, then neither of those interrupts should be
    // enabled.
    //
    ROM_UARTIntClear(UART1_BASE, ui32Status);

    //
    // Check the DMA control table to see if the ping-pong "A" transfer is
    // complete. The "A" transfer uses receive buffer "A", and the primary
    // control structure.
    //
    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT);

    //
    // If the primary control structure indicates stop, that means the "A"
    // receive buffer is done. The uDMA controller should still be receiving
    // data into the "B" buffer.
    //
    if(ui32Mode == UDMA_MODE_STOP)
    {
    //
    // Increment a counter to indicate data was received into buffer A. In
    // a real application this would be used to signal the main thread that
    // data was received so the main thread can process the data.
    //
    g_ui32RxBufACount++;

    //
    // Set up the next transfer for the "A" buffer, using the primary
    // control structure. When the ongoing receive into the "B" buffer is
    // done, the uDMA controller will switch back to this one. This
    // example re-uses buffer A, but a more sophisticated application could
    // use a rotating set of buffers to increase the amount of time that
    // the main thread has to process the data in the buffer before it is
    // reused.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG,
    (void *)(UART1_BASE + UART_O_DR),
    g_ui8RxBufA, sizeof(g_ui8RxBufA));
    }

    //
    // Check the DMA control table to see if the ping-pong "B" transfer is
    // complete. The "B" transfer uses receive buffer "B", and the alternate
    // control structure.
    //
    ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT);

    //
    // If the alternate control structure indicates stop, that means the "B"
    // receive buffer is done. The uDMA controller should still be receiving
    // data into the "A" buffer.
    //
    if(ui32Mode == UDMA_MODE_STOP)
    {
    //
    // Increment a counter to indicate data was received into buffer A. In
    // a real application this would be used to signal the main thread that
    // data was received so the main thread can process the data.
    //
    g_ui32RxBufBCount++;

    //
    // Set up the next transfer for the "B" buffer, using the alternate
    // control structure. When the ongoing receive into the "A" buffer is
    // done, the uDMA controller will switch back to this one. This
    // example re-uses buffer B, but a more sophisticated application could
    // use a rotating set of buffers to increase the amount of time that
    // the main thread has to process the data in the buffer before it is
    // reused.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG,
    (void *)(UART1_BASE + UART_O_DR),
    g_ui8RxBufB, sizeof(g_ui8RxBufB));
    }

    //
    // If the UART1 DMA TX channel is disabled, that means the TX DMA transfer
    // is done.
    //
    if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_UART1TX))
    {
    //
    // Start another DMA transfer to UART1 TX.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC, g_ui8TxBuf,
    (void *)(UART1_BASE + UART_O_DR),
    sizeof(g_ui8TxBuf));

    //
    // The uDMA TX channel must be re-enabled.
    //
    ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1TX);
    }
    }

    //*****************************************************************************
    //
    // Initializes the UART1 peripheral and sets up the TX and RX uDMA channels.
    // The UART is configured for loopback mode so that any data sent on TX will be
    // received on RX. The uDMA channels are configured so that the TX channel
    // will copy data from a buffer to the UART TX output. And the uDMA RX channel
    // will receive any incoming data into a pair of buffers in ping-pong mode.
    //
    //*****************************************************************************
    void
    InitUART1Transfer(void)
    {
    uint_fast16_t ui16Idx;

    //
    // Fill the TX buffer with a simple data pattern.
    //
    for(ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++)
    {
    g_ui8TxBuf[ui16Idx] = ui16Idx;
    }

    //
    // Enable the UART peripheral, and configure it to operate even if the CPU
    // is in sleep.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART1);

    //
    // Configure the UART communication parameters.
    //
    ROM_UARTConfigSetExpClk(UART1_BASE, g_ui32SysClock, 115200,
    UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
    UART_CONFIG_PAR_NONE);

    //
    // Set both the TX and RX trigger thresholds to 4. This will be used by
    // the uDMA controller to signal when more data should be transferred. The
    // uDMA TX and RX channels will be configured so that it can transfer 4
    // bytes in a burst when the UART is ready to transfer more data.
    //
    ROM_UARTFIFOLevelSet(UART1_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);

    //
    // Enable the UART for operation, and enable the uDMA interface for both TX
    // and RX channels.
    //
    ROM_UARTEnable(UART1_BASE);
    ROM_UARTDMAEnable(UART1_BASE, UART_DMA_RX | UART_DMA_TX);

    //
    // This register write will set the UART to operate in loopback mode. Any
    // data sent on the TX output will be received on the RX input.
    //
    HWREG(UART1_BASE + UART_O_CTL) |= UART_CTL_LBE;

    //
    // Put the attributes in a known state for the uDMA UART1RX channel. These
    // should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART1RX,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);

    //
    // Configure the control parameters for the primary control structure for
    // the UART RX channel. The primary contol structure is used for the "A"
    // part of the ping-pong receive. The transfer data size is 8 bits, the
    // source address does not increment since it will be reading from a
    // register. The destination address increment is byte 8-bit bytes. The
    // arbitration size is set to 4 to match the RX FIFO trigger threshold.
    // The uDMA controller will use a 4 byte burst transfer if possible. This
    // will be somewhat more effecient that single byte transfers.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
    UDMA_ARB_4);

    //
    // Configure the control parameters for the alternate control structure for
    // the UART RX channel. The alternate contol structure is used for the "B"
    // part of the ping-pong receive. The configuration is identical to the
    // primary/A control structure.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 |
    UDMA_ARB_4);

    //
    // Set up the transfer parameters for the UART RX primary control
    // structure. The mode is set to ping-pong, the transfer source is the
    // UART data register, and the destination is the receive "A" buffer. The
    // transfer size is set to match the size of the buffer.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG,
    (void *)(UART1_BASE + UART_O_DR),
    g_ui8RxBufA, sizeof(g_ui8RxBufA));

    //
    // Set up the transfer parameters for the UART RX alternate control
    // structure. The mode is set to ping-pong, the transfer source is the
    // UART data register, and the destination is the receive "B" buffer. The
    // transfer size is set to match the size of the buffer.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG,
    (void *)(UART1_BASE + UART_O_DR),
    g_ui8RxBufB, sizeof(g_ui8RxBufB));

    //
    // Put the attributes in a known state for the uDMA UART1TX channel. These
    // should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART1TX,
    UDMA_ATTR_ALTSELECT |
    UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK);

    //
    // Set the USEBURST attribute for the uDMA UART TX channel. This will
    // force the controller to always use a burst when transferring data from
    // the TX buffer to the UART. This is somewhat more effecient bus usage
    // than the default which allows single or burst transfers.
    //
    ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_UART1TX, UDMA_ATTR_USEBURST);

    //
    // Configure the control parameters for the UART TX. The uDMA UART TX
    // channel is used to transfer a block of data from a buffer to the UART.
    // The data size is 8 bits. The source address increment is 8-bit bytes
    // since the data is coming from a buffer. The destination increment is
    // none since the data is to be written to the UART data register. The
    // arbitration size is set to 4, which matches the UART TX FIFO trigger
    // threshold.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 |
    UDMA_DST_INC_NONE |
    UDMA_ARB_4);

    //
    // Set up the transfer parameters for the uDMA UART TX channel. This will
    // configure the transfer source and destination and the transfer size.
    // Basic mode is used because the peripheral is making the uDMA transfer
    // request. The source is the TX buffer and the destination is the UART
    // data register.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC, g_ui8TxBuf,
    (void *)(UART1_BASE + UART_O_DR),
    sizeof(g_ui8TxBuf));

    //
    // Now both the uDMA UART TX and RX channels are primed to start a
    // transfer. As soon as the channels are enabled, the peripheral will
    // issue a transfer request and the data transfers will begin.
    //
    ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1RX);
    ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1TX);

    //
    // Enable the UART DMA TX/RX interrupts.
    //
    ROM_UARTIntEnable(UART1_BASE, UART_INT_DMATX | UART_INT_DMATX);

    //
    // Enable the UART peripheral interrupts.
    //
    ROM_IntEnable(INT_UART1);
    }


    //*****************************************************************************
    //
    // Initializes the uDMA software channel to perform a memory to memory uDMA
    // transfer.
    //
    //*****************************************************************************
    void
    InitSWTransfer(void)
    {
    uint_fast16_t ui16Idx;

    //
    // Fill the source memory buffer with a simple incrementing pattern.
    //
    for(ui16Idx = 0; ui16Idx < MEM_BUFFER_SIZE; ui16Idx++)
    {
    g_ui32SrcBuf[ui16Idx] = ui16Idx;
    }

    //
    // Enable interrupts from the uDMA software channel.
    //
    ROM_IntEnable(INT_UDMA);

    //
    // Put the attributes in a known state for the uDMA software channel.
    // These should already be disabled by default.
    //
    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SW,
    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
    (UDMA_ATTR_HIGH_PRIORITY |
    UDMA_ATTR_REQMASK));

    //
    // Configure the control parameters for the SW channel. The SW channel
    // will be used to transfer between two memory buffers, 32 bits at a time.
    // Therefore the data size is 32 bits, and the address increment is 32 bits
    // for both source and destination. The arbitration size will be set to 8,
    // which causes the uDMA controller to rearbitrate after 8 items are
    // transferred. This keeps this channel from hogging the uDMA controller
    // once the transfer is started, and allows other channels cycles if they
    // are higher priority.
    //
    ROM_uDMAChannelControlSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT,
    UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 |
    UDMA_ARB_8);

    //
    // Set up the transfer parameters for the software channel. This will
    // configure the transfer buffers and the transfer size. Auto mode must be
    // used for software transfers.
    //
    ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT,
    UDMA_MODE_AUTO, g_ui32SrcBuf, g_ui32DstBuf,
    MEM_BUFFER_SIZE);

    //
    // Now the software channel is primed to start a transfer. The channel
    // must be enabled. For software based transfers, a request must be
    // issued. After this, the uDMA memory transfer begins.
    //
    ROM_uDMAChannelEnable(UDMA_CHANNEL_SW);
    ROM_uDMAChannelRequest(UDMA_CHANNEL_SW);
    }

    //*****************************************************************************
    //
    // Configure the UART and its pins. This must be called before UARTprintf().
    //
    //*****************************************************************************
    void
    ConfigureUART(void)
    {
    //
    // Enable the GPIO Peripheral used by the UART.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

    //
    // Enable UART0
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0);

    //
    // Configure GPIO Pins for UART mode.
    //
    ROM_GPIOPinConfigure(GPIO_PA0_U0RX);
    ROM_GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);

    //
    // Initialize the UART for console I/O.
    //
    UARTStdioConfig(0, 115200, g_ui32SysClock);
    }