[Resolved] UART failing to detect breaks that it should

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

[Resolved] UART failing to detect breaks that it should

3,367件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ohoulihan on Thu Jul 30 07:38:57 MST 2015
Short version:

I'm using an NXP LPC1347 to decode DMX signals. It's working on some vendor's DMX but not others. I've tracked the issue down to the UART not detecting shorter length breaks, even though these shorter breaks are still much bigger than the the minimum that the user manual says should be detected.

What's going on? How can I detect these?

Long version:

The DMX protocol is roughly RS-485. Essentially it's a break (logical low for more than 90 us), a blip of a high, then 513 frames of data ( each 1 low start bit, 8 data bits, 2 high stop bits) at 250,000 baud.

Some DMX signals are being received perfectly, however for others, we are almost never getting break or frame error interrupts. We're still getting all the data and data interrupts - it's just useless since we don't know when it starts or stops.

Here's a DMX signal that we can read just fine:

[img]http://leancoder-share.s3.amazonaws.com/paste/chieshae.png[/img]

Here's one  that's mostly not firing break interrupts:

[img]http://leancoder-share.s3.amazonaws.com/paste/pohngeig.png[/img]

The NXP manual LPC1345 user manual says that

"When RXD1 is held in the spacing state (all 0 zeros) for one full character transmission (start, data, parity, stop), a break interrupt occurs. Once the break condition has been detected, the receiver goes idle until RXD1 goes to marking state (all ones)."

Given that our data is being sent at 250,000 baud (4us per bit), and that one full character transmission is 11 bits (1 start + 8 data + 2 stop), and each bit is 4us, then each a single character is 44us. So according to the manual, any time the line is held low for 44us we should get a break interrupt. But that's way less than the 130us break that is failing to give us a break interrupt.

What does the UART actually require to trigger breaks? How can we get this 130us break to trigger?
ラベル(1)
0 件の賞賛
返信
5 返答(返信)

3,126件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ohoulihan on Thu Aug 06 13:37:55 MST 2015
This turned out to be a software problem in my code.

It actually surprising, that it ever worked, and even more surprising that it was always working perfectly for many DMX signals.

The thing I did not understand, is that breaks could be "inside" the queue of data. Reading from the RBR advances the queue, and the next slot in the queue could contain a break, even inside the same interrupt. I needed to be checking for a break after each read of the RBR.

In hindsight, it makes perfect sense.

In the previous, broken code, I was doing roughly:

    while(true){
        // Read LPC_USART->IIR
        if(is_break){
            // handle_break
            // throwaway LPC_USART->RBR;
        }else if(has_data){
            while(// LSR shows Read Data Ready in the RBR) { 
                // Read byte from LPC_USART->RBR
            }
        }
    }

   
In the new, working code, I'm doing:

    while(true){
        // Read LPC_USART->IIR
        if(is_break){
            // handle_break
            // throwaway LPC_USART->RBR;
        }else if(has_data){
            // Read one byte from LPC_USART->RBR
        }
    }





Full, now working, code below:


void uart_receive_handler(void)
{
    uint32_t interrupt_status = 0;
    uint32_t receive_status = 0;
    uint32_t interrupt_active  = 0;
    uint32_t interrupt_type = 0;
    uint8_t trashcan = 0;

    while(TRUE) {

        interrupt_status = LPC_USART->IIR;
        interrupt_active = (interrupt_status & 1) == 0x0; // Funky because bit low means active
        if( interrupt_active == FALSE ) {
            break;
        }
        interrupt_type = (interrupt_status >> 1) & 0x7; // Grab bytes the three bytes, starting at bit 2
        
        // If something other than a character
        // --
        if(interrupt_type == 0x1) { // 0x1 == THRE
        //Send more data
        uart_transmit_next();

        }else if(interrupt_type == 0x3) { // 0x3 == LSR
            receive_status = LPC_USART->LSR;

            // If  break
            if(receive_status & UART_LSR_BI) {
                // Ship off what we have received
                receive_complete();
                // throw away blank break value by reading from fifo
                trashcan = LPC_USART->RBR;
                trashcan = trashcan; // hide "never used" compiler warning.
            // Other errors
            } else if(receive_status & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE|UART_LSR_RXFE)) {
                // Throw away the rest of this packet.
                trashcan = LPC_USART->RBR;
                clean_packet = FALSE;
            }else{
                
            }

        // If data ready
        // 0x2 = Data ready, 0x6 =  leftover data ready (CTI)
        // --
        } else if(interrupt_type == 0x2 || interrupt_type == 0x6) { 
            dmx_buffer_add_byte(&receive_local_buffer, LPC_USART->RBR);
            if(dmx_buffer_is_full_rdm_packet(&receive_local_buffer)){
            receive_complete();
            }
        }
    }
}

0 件の賞賛
返信

3,126件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ohoulihan on Wed Aug 05 08:19:02 MST 2015
Thanks Ian.

I've got the dummy read in, so that's not it.

if(receive_status & UART_LSR_BI) {
            // Ship off what we have received
            receive_complete();
            // throw away blank break value by reading from fifo
            trashcan = LPC_USART->RBR;


I'd love to hear what you find on how short you can detect breaks.
0 件の賞賛
返信

3,126件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by IanB on Sat Aug 01 11:38:06 MST 2015
DMX has 8 data bits, so 1 start bit, EIGHT data bits and 2 stop bits makes 44µs, not 36µs.

i had trouble with it not detecting breaks, but my problem was that I forgot the dummy read of RBR that resets the break-detection mechanism.

I have to say I haven't checked how short a break it will detect. I'll do that and see what happens!
0 件の賞賛
返信

3,126件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ohoulihan on Fri Jul 31 04:58:30 MST 2015
Here's the instrumented version of the interrupt handler:


void uart_receive_handler(void)
{
    uint32_t interrupt_status = 0;
    uint32_t receive_status = 0;
    uint32_t interrupt_active  = 0;
    uint32_t interrupt_type = 0;
    uint8_t trashcan = 0;

    while(TRUE) {

        interrupt_status = LPC_USART->IIR;
        interrupt_active = (interrupt_status & 1) == 0x0; // Funky because bit low means active
        if( interrupt_active == FALSE ) {
            break;
        }
        interrupt_type = (interrupt_status >> 1) & 0x7; // Grab bytes the three bytes, starting at bit 2
        receive_status = LPC_USART->LSR;

        if(interrupt_type == 0x1) { // 0x1 == THRE
        //Send more data
        uart_transmit_next();

        }else if(interrupt_type == 0x3) { // 0x3 == LSR
            counters.interrupts +=1;
            if(receive_status & UART_LSR_OE){
                counters.lsr_oe += 1;
            }
            if(receive_status & UART_LSR_PE){
                counters.lsr_pe += 1;
            }
            if(receive_status & UART_LSR_FE){
                counters.lsr_fe += 1;
            }
            if(receive_status & UART_LSR_BI){
                counters.lsr_bi += 1;
            }
            if(receive_status & UART_LSR_RXFE){
                counters.lsr_rxfe += 1;
            }

            // If  break
            if(receive_status & UART_LSR_BI) {
            // Ship off what we have received
            recieve_complete();
                // throw away blank break value by reading from fifo
                trashcan = LPC_USART->RBR;
                trashcan = trashcan; // hide "never used" compiler warning.

                // Other errors
            } else if(receive_status & (UART_LSR_FE|UART_LSR_OE|UART_LSR_PE|UART_LSR_RXFE)) {
                // Throw away the rest of this packet.
                trashcan = LPC_USART->RBR;
                clean_packet = FALSE;
            }
    // If also data ready
    if(receive_status & UART_LSR_RDR){
        counters.lsr_rdr_alt += 1;
trashcan = LPC_USART->RBR;
    }

            // If data ready
            // --
        } else if(interrupt_type == 0x2 || interrupt_type == 0x6) { // 0x2 = Data ready, 0x6 =  leftover data ready (CTI)
            while(LPC_USART->LSR & UART_LSR_RDR) { // LSR shows Read Data Ready in the RBR
                counters.lsr_rdr += 1;
                dmx_buffer_add_byte(&receive_local_buffer, LPC_USART->RBR);
            }
            if(dmx_buffer_is_full_rdm_packet(&receive_local_buffer)){
            // Ship off what we have received
            recieve_complete();
            }
        }
    }
}
0 件の賞賛
返信

3,126件の閲覧回数
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by aisella on Thu Jul 30 20:59:56 MST 2015
Could you please me post the code?
Thanks!
0 件の賞賛
返信