• AVR Freaks

Hot!Trying to figure out DMX mode with 18F45K45 UART

Author
PRWiley
New Member
  • Total Posts : 22
  • Reward points : 0
  • Joined: 2019/07/04 06:16:51
  • Location: Lewisburg PA USA
  • Status: offline
2019/07/18 07:48:31 (permalink)
0

Trying to figure out DMX mode with 18F45K45 UART

After reading TB3204, "DMX-512 using the UART with Protocol Support", I am trying to get a simple DMX Par light to work with a signal sent from a 18F45K45 as a DMX controller. The fixture is in 4 channel mode where CH1 is the master dimmer, CH2 is R, CH3 is G, and CH4 is B. I am new to PIC programming but have experience with Arduino and have a vague understanding of C.
 
I am working with a Curiosity HPC board. The fixture is connected to the board via an inexpensive RS-485 board that uses a MAX485 chip. The fixture is set to address 1. The system clock is set to HFINTOSC and 64_MHz
 
The code I am trying to make work is:
 
1. UART1.c
 

 
 
 
void UART1_Initialize(void)
{
//UART module settings
//From Microchip document TB3204
  
U1CON0bits.MODE = 0b1010; //Select DMX mode
U1CON0bits.TXEN = 1; //Enable transmitter
U1CON0bits.RXEN = 0; //Disable receiver
U1CON2bits.TXPOL = 0; //Standard polarity, TX pin will idle high
U1CON2bits.STP = 0b10; //2 stop bits

//DMX data packet settings
U1P1 = 511; //Total number of data bytes - 1
U1P2 = 0x00; //Not used in DMX controller
U1P3 = 0x00; //Not used in DMX controller

// Baud rate generator settings
U1CON0bits.U1BRGS = 1; //High speed baud generation
U1BRG = 0x3F; //Value for U1BRG for Fosc = 64MHz

//PPS settings for TX functionality on pin RC6
ANSELCbits.ANSELC6 = 0; //Make RC6 a digital I/O
TRISCbits.TRISC6 = 0; //Make RC6 an output
RC6PPS = 0b010011; //Assign TX functionality to RC6
U1ON = 0x01; //Turn on UART module

}

 
2. main.c

 
 
 
int universe[512];
int channel;
void set_up_universe(void);
/*
Main application
*/
void main(void)
{
// Initialize the device
SYSTEM_Initialize();

set_up_universe(); // Create universe data all 0
universe[1] = 255; // Add some intensity data
universe[2] = 255;
universe[3] = 255;
universe[4] = 255;
universe[5] = 255;
universe[6] = 255;
universe[7] = 255;

// If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
// If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
// Use the following macros to:
 
// Enable the Global Interrupts
//INTERRUPT_GlobalInterruptEnable();
 
// Disable the Global Interrupts
//INTERRUPT_GlobalInterruptDisable();
 
 
 
    while (1)
    {
        // Send universe of data
        //__delay_us(60);
        for (channel = 1; channel <= 512; channel ++)
        {
            U1TXB = universe[channel];
        }
    }
}
 
 
 
 
 
void set_up_universe(void)
{
    for (channel=1; channel <= 512; channel++)
 
    {
        universe[channel] = 0;
    }
}

 
When I run main.c I see DMX-looking data on my o-scope (RIGOL DS1054) from RC6. When I run with no delay, the fixture's red LEDs blink on 3 times about a second and then there is a long pause, about 5 seconds. Because I thought the way I am sending data might be fouling up the timing of the DMX, I started experimenting with delays before the packet starts. 
 
When I run with __delay_us(50), the fixture's blue LEDs come on for about 3 seconds and the red LEDs flash on and off for a couple of seconds. 
 
When I run with __delay_us(60), the fixture's green LEDs flash constantly at about 1 sec. At __delay_us(70) the blue and green LEDs flash constantly at about 1 sec. 
 
At __delay_us(90) nothing happens. 
 
If I understood how this was supposed to work better, I would know what the timing clues tell me, but, alas, I don't. My assumption is that what should be happening is all LEDs should on constantly. The problem could be with timing and/or my poor code.
 
I'm not sure what to try next. Can anyone suggest how to debug this?  Many thanks in advance. 
 
I should perhaps note that the fixture works as it is supposed to when used with the Arduino DMX library.
post edited by PRWiley - 2019/07/21 09:29:42

Peter R. Wiley
I feel a lot more like I do now than I did when I came in.
#1

5 Replies Related Threads

    PRWiley
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2019/07/04 06:16:51
    • Location: Lewisburg PA USA
    • Status: offline
    Re: Trying to figure out DMX mode with 18F45K25 UART 2019/07/18 12:11:46 (permalink)
    0
    I dug into the data sheet a bit and it goes beyond what the document I first consulted says. p 482 points out that to ensure that the UART count and the software count of bytes sent after the DMX start code are in sync, TXEN should be toggled after the last byte is free of the transmit shift register. 
     
    So I changed my code for main.c
     
    int universe[512];
    int channel;
    void set_up_universe(void);
    /*
                             Main application
     */
    void main(void)
    {
        // Initialize the device
        SYSTEM_Initialize();
        
        set_up_universe(); // Create universe data all 0
        universe[0] = 255; // Add some intensity data
        universe[1] = 255;
        universe[2] = 255;
        universe[3] = 255;
        universe[4] = 255;
        universe[5] = 255;
        universe[6] = 255;
        universe[7] = 255;
        universe[7] = 255;

        
        // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
        // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
        // Use the following macros to:

        // Enable the Global Interrupts
        //INTERRUPT_GlobalInterruptEnable();

        // Disable the Global Interrupts
        //INTERRUPT_GlobalInterruptDisable();

        while (1)
        {
            // Send universe of data
            //__delay_us(20);
            for (channel = 1; channel <= 512; channel ++)
            {
                while(U1TXIF == 0);
                U1TXB = universe[channel];
            }
            __delay_us(50);
            U1CON0bits.TXEN = 0;
            U1CON0bits.TXEN = 1;
        }
    }

    void set_up_universe(void)
    {
        for (channel=1; channel <= 512; channel++){
            universe[channel] = 0;
        }
    }

     
    This code lights up all LEDs at full intensity with no flickering.
     
    That delay of 50us is essential, no other value works. Also essential is turning TXEN on and off after the 512 channel frames have been sent. I wish I understood why 100%. I think the delay is needed to allow the transmit shift register to empty. If a more experienced person has an explanation . . .

    Peter R. Wiley
    I feel a lot more like I do now than I did when I came in.
    #2
    ric
    Super Member
    • Total Posts : 24581
    • Reward points : 0
    • Joined: 2003/11/07 12:41:26
    • Location: Australia, Melbourne
    • Status: online
    Re: Trying to figure out DMX mode with 18F45K25 UART 2019/07/18 13:23:18 (permalink)
    0
    There is a status bit to tell you when it is empty.
    TRMT

    I also post at: PicForum
    Links to useful PIC information: http://picforum.ric323.co...opic.php?f=59&t=15
    NEW USERS: Posting images, links and code - workaround for restrictions.
    To get a useful answer, always state which PIC you are using!
    #3
    PRWiley
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2019/07/04 06:16:51
    • Location: Lewisburg PA USA
    • Status: offline
    Re: Trying to figure out DMX mode with 18F45K25 UART 2019/07/21 06:55:04 (permalink)
    0
    Actually, on this chip there is no TRMT, at least it does not seem to be in the data sheet. In this case I think it's TXBE (U1FIFObits.TXBE p.504 in data sheet).
     
    I remain confused by 31.4.1 (p. 482) in the data sheet. It says:
     
    Software send the Start Code and then 'n' data bytes by writing the UxTXB register with each byte to be sent in the desired order. A UxTXIF value of '1' indicates when the UxTXB is ready to accept the next byte.
     
    The internal byte counter is not accessible to software. Software needs to keep track of the number of bytes written to UxTXB to ensure that no more and and no less than 'n' bytes are sent because the DMX state machine will automatically insert a Break, and reset its internal counter after 'n' bytes are written. One way to ensure synchronization between hardware and software is to toggle TXEN after the last byte of the universe is completely free of the transmit shift register as indicated by the TXMTIF bit.

     
    From Figure 31-6, it looks like TXMTIF should go high on the 512th byte, after the end of the for loop, but it never seems to be. At least I can't catch it. So, what I am doing is toggling the TXEN after the for loop on the assumption that register must be clear at that moment. Also from Figure 3-16 a "software delay", not mentioned in the text, would appear to be required, and that's the __delay_us(50) (and no other value seems to work).
     
    Here is my current code in main.c

    int universe[512];
    int channel;
    int adc_value;
    int pot_value;
    void set_up_universe(void);
    void get_pot_value(void);
    void send_uni(void);
    /*
    Main application
    */
    void main(void)
    {
    // Initialize the device
    SYSTEM_Initialize();
    ADCC_Initialize();
    LCD_Initialize();


    set_up_universe(); // Create universe data all 0
    // four channel fixture 1
    universe[1] = 255;
    universe[2] = 255;
    universe[3] = 255;
    universe[4] = 255;
    // four channel fixture 2
    universe[5] = 255;
    universe[6] = 255;
    universe[7] = 255;
    universe[8] = 255;
    // four channel fixture 3
    universe[9] = 255;
    universe[10] = 255;
    universe[11] = 255;
    universe[12] = 255;
    // four channel fixture 103
    universe[109] = 255;
    universe[110] = 255;
    universe[111] = 255;
    universe[112] = 255;

    // If using interrupts in PIC18 High/Low Priority Mode you need to enable the Global High and Low Interrupts
    // If using interrupts in PIC Mid-Range Compatibility Mode you need to enable the Global Interrupts
    // Use the following macros to:
    // Enable the Global Interrupts
    //INTERRUPT_GlobalInterruptEnable();
    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    DisplayClr();
    LCDPutStr("STARTING");
    while (1)
    {
    get_pot_value();
    send_uni();
    }
    }
    void send_uni(void)
    {
    // Send universe of data

    U1TXB = 0; // START CODE
    for (channel = 1; channel <= 512; channel ++) // THE UNIVERSE
    {
    while(U1FIFObits.TXBE == 0); // While TX Buffer is not empty
    U1TXB = universe[channel];

    }
    // At end of universe toggle TXEN - see datasheet p. 482 - 31.4
    U1CON0bits.TXEN = 0;
    U1CON0bits.TXEN = 1;
    __delay_us(50);
    }
    void get_pot_value(void){

    adc_value = ADCC_GetSingleConversion(RA0);
    pot_value = adc_value*0.25;
    if(pot_value >= 255)
    {
    pot_value = 255;
    }
    universe[1] = pot_value;
    universe[109] = pot_value;
    }
    void set_up_universe(void)
    {
    for (channel=1; channel <= 512; channel++){
    universe[channel] = 0;
    }
    }

     
    I added U1ERRIEbits.TXMTIE = 1; to the UART initialization because that would appear to required for TXMTIF to be set. The pot on the curiosity board dims the fixture nicely with no latency.
     
    I would really like to understand why I can't read the TXMTIF bit referred to in the data sheet. I've put if statements in various places to try and catch the bit being set high, but it never seems to == 1;
     
    One other observation, maybe this is a bug, but the MCC Notifications has a "HINT" that "DMX Mode is not supported" even though there's a "DMX mode" choice in the Mode dropdown in the MCC System Module tab in the MCC and the DMX seems to work mostly as advertised.

    Attached Image(s)


    Peter R. Wiley
    I feel a lot more like I do now than I did when I came in.
    #4
    Jerry Messina
    Super Member
    • Total Posts : 445
    • Reward points : 0
    • Joined: 2003/11/07 12:35:12
    • Status: offline
    Re: Trying to figure out DMX mode with 18F45K25 UART 2019/07/21 08:58:41 (permalink)
    +1 (1)
    First off, are you sure about that part number? I can't find any reference to an 18F45K25
    I think you mean 18F45K42

    Now, your current code doesn't quite follow what's in the datasheet...

    int universe[512];

    void send_uni(void)
    {
     // Send universe of data
     
     U1TXB = 0; // START CODE
     for (channel = 1; channel <= 512; channel ++) // THE UNIVERSE
     {
     while(U1FIFObits.TXBE == 0); // While TX Buffer is not empty
     U1TXB = universe[channel];
     
     }
     // At end of universe toggle TXEN - see datasheet p. 482 - 31.4
     U1CON0bits.TXEN = 0;
     U1CON0bits.TXEN = 1;
     __delay_us(50);
    }


    Your universe data should be an array of 512 bytes (not int) and they have index 0-511 (not 512), so all your loops need to be '< 512'. The data starts with universe[0] and ends with universe[511]

    Try something like this (untested)...

    unsigned char universe[512];    // uint8_t

    // fill universe[0]-[511] with the data to transmit

    // Send universe of data
    void send_uni(void)
    {
        // 18F45K42 datasheet 31.4.1
        // Software sends the Start Code and the 'n' data bytes by
        // writing the UxTXB register with each byte to be sent in
        // the desired order. A UxTXIF value of '1' indicates when
        // the UxTXB is ready to accept the next byte.

        while (PIR3bits.U1TXIF == 0);   // wait for U1TXIF
        U1TXB = 0; // START CODE
        for (channel = 0; channel < 512; channel ++) // THE UNIVERSE
        {
            while (PIR3bits.U1TXIF == 0);   // wait for U1TXIF
            U1TXB = universe[channel];
        }
     
        // One way to ensure synchronization between hardware and software
        // is to toggle TXEN after the last byte of the universe is
        // completely free of the transmit shift register as
        // indicated by the TXMTIF bit
        while (U1ERRIRbits.TXMTIF == 0);    // wait for TXMTIF before toggling TXEN
        U1CON0bits.TXEN = 0;
        U1CON0bits.TXEN = 1;
    }

    You shouldn't need to set any of the xxxIE bits in order to see the xxxIF flags... they will get set regardless of the IE state.


    post edited by Jerry Messina - 2019/07/21 09:13:42
    #5
    PRWiley
    New Member
    • Total Posts : 22
    • Reward points : 0
    • Joined: 2019/07/04 06:16:51
    • Location: Lewisburg PA USA
    • Status: offline
    Re: Trying to figure out DMX mode with 18F45K25 UART 2019/07/22 08:09:27 (permalink)
    0
    @Jerry
     
    Thanks so much for taking the time to look at my code. I very much appreciate it. Yes, the part number I gave was wrong due to a typo. I've fixed it.
     
    I've tested your suggested code and it works well. A big help. At my present level of understanding, I think it would have taken me awhile to realize one has to look at PIR3bits.U1TXIF. I imagine the delay I was using was having the same effect, albeit much less efficiently. 
    post edited by PRWiley - 2019/07/22 10:35:42

    Peter R. Wiley
    I feel a lot more like I do now than I did when I came in.
    #6
    Jump to:
    © 2019 APG vNext Commercial Version 4.5