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.

Stellaris Launchpad DMX on multiple UART's



Hi,

I have 2 questions, more like 1 big question and a big doubt.

Let's suppose I'm trying to make a DMX transmitter on the launchpad (LM4F) about 6 DMX streams using 6 UART's (2 to 8) what would be the best approach to do that ? I need to keep the signal integrity (6 of them) while doing other stuff in the meanwhile (like reading from USB and/or other heavy CPU tasks).

The next question, or more like problem, is that I've been trying for a couple of days to trigger UART TX interrupt and I never get it triggered... here is my sample code:

Note: I do have UART1IntHandler in the vector table, and I shortened the code for better reading

// UART 1 Interrupt Handler
void UART1IntHandler(void)
{
    unsigned long ulInts = ROM_UARTIntStatus(UART1_BASE, true);
    ROM_UARTIntClear(UART1_BASE, ulInts);

    UARTprintf("Got TX Interrupt");
}

// Initialization
void init()
{
    ROM_FPULazyStackingEnable();
    ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN);

    // Initialize debug UART
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    GPIOPinConfigure(GPIO_PA0_U0RX);
    GPIOPinConfigure(GPIO_PA1_U0TX);
    ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    UARTStdioInit(0);
}

// TX Only
void initUart1()
{
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    GPIOPinConfigure(GPIO_PB1_U1TX);
    ROM_GPIOPinTypeUART(GPIO_PORTB_BASE, GPIO_PIN_1);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1);
    ROM_UARTConfigSetExpClk(UART1_BASE, ROM_SysCtlClockGet(), DMXSPEED, DMXFORMAT);
    ROM_UARTFIFOLevelSet(UART1_BASE, UART_FIFO_TX1_8, UART_FIFO_RX1_8);
    ROM_UARTIntDisable(UART1_BASE, 0xFFFFFFFF);
    ROM_UARTIntEnable(UART1_BASE, UART_INT_TX);
    ROM_IntEnable(INT_UART1);
    ROM_UARTEnable(UART1_BASE);
}

// main function.
int main(void) {
    init();

    UARTprintf("Init completed.\nStarting UART1 Init.\n");

    initUart1();

    UARTprintf("Uart1 Init Completed.\nSending data to UART1 to trigger INT.\n");

    ROM_UARTCharPutNonBlocking(UART1_BASE, 10);

    while(1)
    {
    }
}

Best regards.

  • Rui,

    I am not familiar with DMX, so I cannot comment on the implementation.  Using 6 UARTs and a CPU intensive task should not pose a problem -- the UART modules are slow comparatively.  You may want to use an OS such as FreeRTOS or Sys/BIOS to allow efficient resource sharing.

    I do not see anything immediately wrong with your code.  Can you tell me the values of DMXSPEED and DMXFORMAT?

    Thanks,

    Sean 

  • DMX protocol is 8-N-2 at 250,000 baud.  DMX protocol requires the transmission of a break signal that is at least 88us (22 bit times), followed by a mark after break of at least 8us (2 bit times) before each frame of data.

     

  • I presume the interrupt is declared in two places...

    Note: I do have UART1IntHandler in the vector table, and I shortened the code for better reading

    You need to have the procedure declared extern as well in Startup...

    like here...

    **************************

    /*****************************************************************************
    //
    // External declaration for the reset handler that is to be called when the
    // processor is started
    //
    //*****************************************************************************
    extern void _c_int00(void);
    extern interrupt void Timer0IntHandler(void); // see below where this can be hooked in for e.g.
    extern interrupt void ADCIntHandler(void);

    //*****************************************************************************
    //
    // Linker variable that marks the top of the stack.
    //
    //*****************************************************************************
    extern unsigned long __STACK_TOP;

    *********************

    IntDefaultHandler,                      // PWM Generator 2
        IntDefaultHandler,                      // Quadrature Encoder 0
        ADCIntHandler,                      // ADC Sequence 0
        ADCIntHandler,                      // ADC Sequence 1
        ADCIntHandler,                      // ADC Sequence 2
        ADCIntHandler,                      // ADC Sequence 3
        IntDefaultHandler,                      // Watchdog timer
        Timer0IntHandler,                      // Timer 0 subtimer A
        IntDefaultHandler,                      // Timer 0 subtimer B
        IntDefaultHandler,                      // Timer 1 subtimer A

    **********************

  • Btw  this code...

    ************************

    {
        unsigned long ulInts = ROM_UARTIntStatus(UART1_BASE, true);
        ROM_UARTIntClear(UART1_BASE, ulInts);

        UARTprintf("Got TX Interrupt");
    }

    ****************************

    is going to play havoc with Interrupt handlers...

    It takes too long to run inside an interrupt -- I know I did it with the ADC with Interrupts in the SHaring Forum -- but it is a disaster for sending data cleanly.

    http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/473/t/212263.aspx

    Put the printf inside a while loop based on a variable like "NewData" being set or something... In your main while loop...

    Set "NewData" or whatever inside your Interrupt loop...

    I have not looked too closely at what you are doing so interpret freely.

  • Also not shown/missing IntMasterEnable() call.

    Petrei

  • Dave Robinson said:

    Put the printf inside a while loop based on a variable like "NewData" being set or something... In your main while loop...

    Set "NewData" or whatever inside your Interrupt loop...

    Use a Ring Buffer (aka "Circular Buffer") between main() and the ISR.

    TI provide a ring buffer implementation in the Stellarisware 'Utils' - and there's plenty more about...

  • Thanks for all the help, I have to be honest, wasn't expecting so much help, thanks.

    Now, on to the subject.

    @Sean

    I'm going to give FreeRTOS a go, and see how it works out, but I need to be able to efficiently (and correctly) generate the DMX streams before, which is related to the tx interrupt issue I have.

    DMXSPEED is 250000 and DMXFORMAT  is UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_TWO | UART_CONFIG_PAR_NONE

    Also, slandrum explained already the DMX protocol.

    @Dave Robinson

    Yes the interrupt callback is also declared external, or else the compile would fail.

    About the call to UARTprintf inside the interrupt, it's a small debug test to see if the callback is reached, I also tried with the onboard leds to have a visual notification, the callback is never called which is my problem :S

    @Petrei

    I just added ROM_IntMasterEnable() right after initUart1() in main() no changes, still doesn't interrupt, and I tried the ROM_IntMasterEnable() before initUart1() in main() no changes either.

    Thank you very much for the help, I'm going to give a try of FreeRTOS, still I'm curious why I this doesn't work, what am I doing wrong :S

  • Andy:

    I know what a ring buffer is -- but thanks. ;-) Been at this a long time... I am just trying to stick as much as possible to the test the way he wrote it. I have seen anomalies in even small programs when the UART print routines are used inside an interrupt.

    Back to business...

    Try sending from UART1 to UART2 instead of using the same UART -- see if that works better.

    Alter your code accordingly. Put the interrupt for TX on 1 and for receive on two... see if that works.

    And the TI RTOS or FreeRTOS might work out -- but yes you do have to watch your overhead with an OS in the mix and multiple streams...

    I have used both -- not much with the new TI_RTOS -- but soon I will do more work with it.

    Cheers.

  • After tinkering a little bit more, some more searches on google related to DMX and stellarisware, I came uppon a thread (this one http://e2e.ti.com/support/microcontrollers/stellaris_arm_cortex-m3_microcontroller/f/471/t/44618.aspx) where a user suggested to add:

    HWREG(console_uart_base_addr + UART_O_CTL) |= UART_CTL_EOT;

    Which I promptly did add at the end of my uart init function, and behold, it's working!! the TX interrupt got called, and I didn't need to enable and use the FIFO at all also (that I didn't want to use) so I think this sorts my problem out.

    I made a grep on stellariware driverlib and there's nothing in the API that sets that register, so I'm guessing right now that for MCU's that support EOT we can only do it through HWREG am I right ?

    I've been reading about FreeRTOS and it sounds interesting, will probably implement the thing in FreeRTOS as it helps a lot to keep the data integrity with it's queueing and semaphores, thanks a bunch for the help.

  • Rui,

    I'm glad to hear it is working.  There is a function called UARTTxIntModeSet that sets the EOT bit.  Just pass the UART_TXINT_MODE_EOT parameter.

    Sean

  • Thank you very much Sean, that was the API function I was after, just tested it and it's working fine.

    If I manage to have this working as I intend it to, I'll release the whole project for everyone to use and/or help improve it, now on to dive into FreeRTOS, I'll eventually have a got at TI_RTOS too, and no RTOS at all to figure out what's best for the project.

    Thanks everyone for all the help.