NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » RXCn: USART Receive Complete

March 18, 2016
by sask55
sask55's Avatar

I am attempting to get a better understanding of the RXC0 bit in the UCSR0A Control and status register. I must have some misconceptions about what is going on in the hardware and do not fully understand the RXC0 bit as it is detailed in the data sheet.

It seams to me that the RXC0 bit should be cleared by the hardware each time the RXB Data register is read in the code using UDR0. Then if more data is still available in the USART buffer the hardware would reset the RXC0 bit to indicate a waiting byte in the RXB Data register.

I have set up a very simple test, but I do not understand what I am getting for results. It does not appear that the RXC0 bit is ever cleared by hardware when reading the RX register byte using UDR0.

This is the bit of code I am running in the main loop.

   if(((UCSR0A & (1<<RXC0)) > 0));
    {

     read_byte= UDR0;
    // if(read_byte >0)
    // {
    PORTC ^= (1<<4);
    uart_process(read_byte);
    //}

    }

I have my oscilloscope probe on the PORTC pin 4 which is configured as a output pin. I am simply toggling the output to that PC4 pin each time the through the main, but only if the RXC0 bit is set. Even when no RX data is being received by the USART, my oscilloscope indicates that the bit is continually toggling. I can completely unplug the USART adapter the RXC0 bit is always set. The output pin toggles. I don't see how there could possibly be a byte in the RX data buffer after reading it thousands of times.

I then added an addition IF statement to test if the UDR0 is returning a 0. YES it is. The oscilloscope indicates no activity on PC4 if I eliminate the 0 values from the stream of UDR0 's read.

I would appreciate it if anyone could clarify what the Is going on. How do I make use of the RXC0 bit? How and when is this bit cleared?

March 20, 2016
by BobaMosfet
BobaMosfet's Avatar

sask55--

I don't think your understanding is necessarily the problem, if you've initialized everything properly. RXCn is high if unread data exists in the 1-byte buffer, and is cleared (0) otherwise. UDRn can be a zero value-- which has nothing to do with data having been read or not, so don't check for UDRn's value, you'll confuse yourself.

You didn't say whether or not you'd initialized the serial port for interrupts on receive or not. You also didn't say what baudrate. For testing/educational purposes, slower is always better to start with.

I caution against using XOR in this case, because you don't know the state the bit is in to begin with per se. Instead, AND for ON, and OR for OFF, when you know each state exists. This may seem primative, but if it allows you to prove something, then it establishes a code-reference you can go back to, if changing the code fails, so you have something you know is concrete and proven to compare against.

Lastly-- instead of 'PORTC ^= (1<<4)', actually name the pin using the compiler defines so you aren't off by 1: 'PORTC ^= (1<<PC4)' is Pin 27, for example.

The main things is-- I think you're simply overlooking something small, and it's throwing you off, so go caveman and get really simple until it works.

BM

March 20, 2016
by sask55
sask55's Avatar

BM

Thanks for the reply.

A bit of background.

I was attempting to avoid the use of a USART RX interrupt in this project, by polling the TXCn bit outside of an interrupt. My thought was to read the incoming USART bytes at a time that I have more control, rather than when they arrive in the RX buffer. My code is already making use of two timer interrupts and I am attempting to eliminate any possible interrupt clashes by only reading the USRT RX when there is no possibility of the timer interrupts being active.

For the most part the USART is working I can both send TX and receive RX between the micro and the PC. I can transmit USART data both ways with no problem. If I use UDR0 within a USART RX interrupt the TXC0 bit seams to clear as expected. However, if I use UDR0 outside of an interrupt the TXC0 bit never clears, or at least I can see that the code section that contains the UDR0 call is executed on every pass thru the loop. If I remove the USART RX interrupt and do the same test in the MAIN, then the TXC0 bit status check never returns a 0 (cleared bit). The result of the TXC0 bit always being a 1 (set bit) is that the code never stops reading UDRO and will return the same RX byte indefinitely. I have now determined that the Byte returned by UDR0 is not always a 0 value it is whatever value was the last byte at the end of the USART transition received.

This is all unexplainable by me, the code I have used as a purge to flush the RX buffer as part of the USART initiation does not hang. Since this bit of code is casing no noticeable issues it would appear that the RXC0 bit does clear in order to drop out of the while loop. I speculate that this could possibly be because, the only time I ever call this function is on start-up before any USART Rx is ever received. Perhaps RXC0 is 0 to start with and there is no requirement for the hardware to clear it. This bit of code is not part of any interrupt and comes pretty much directly from an example in the data sheet. So! if this code is expected to work why am I seeing the results I am?

        void USART_flush( void ){   
unsigned char dummy;
while ( UCSR0A & (1<<RXC0) ) dummy = UDR0;
}

It seems that the USART is working fine. My test is indicating if UDR0 is being read (called), that is all that I was testing for. The TXC0 bit does not seem to clear in hardware when the UDR0 call is outside of an RX interrupt. As a result, I am getting an endless stream of the same byte returned from UDR0 when in fact the USART transition had ended, but the code has no way to determine this. In fact, as would be expected, the micro is so busy reading the same RX byte and sending it to be processed that practically nothing else is getting done.

As of now I am resorting to using the RX interrupt to trigger the next UDRO read. This appears to be working. I don’t think possible interrupt clashes are as much of an issue as I thought. I still do not really understand why I cannot use the UDR0 outside of an interrupt and get the TXC0 bit to clear when the last of the data has been read from the RX buffer.

As you have said it is likely something very simple that I have overlooked. I am having some trouble putting my finger on it. I have more or less moved on using the RX interrupt as a work around.

Darryl

March 21, 2016
by BobaMosfet
BobaMosfet's Avatar

sask55-

Expectations are tricky things. I find my expectations are flexible until I know everything :)

Turn interrupts off Initialize port, baudrate, error rate, interrupts or not on receive Turn interrupts on

You don't need to clear the serial buffer- it's just one byte. (you can't do it before interrupts are turned back on, anyway, as the serial driver won't work properly (yes, it relies on interrupts to run)) And it's unlikely anything is coming in, anyway. If it does, once you turn interrupts on, and it isn't something you recognize, discard it.

Overall, interrupts are not the enemy, they are your friend. They will save you time, allowing you to use cycles more effeciently, and usually you're not going to notice a conflict between them unless they are all too close in sync, or one is so busy it occassionally gets clobbered. This can be mitigated by intelligent software design.

BM

March 21, 2016
by sask55
sask55's Avatar

BM

Things appear to working well since I am using the RX interrupt. I don't see any evidence of any problems showing up do to the possibility that a interrupt timer is firing when the RX interrupt is executing or vise Vera. If there is a issue it could possibly be very subtle and difficult to notice. Something like, the occasional UART RX byte not being completely proceeded would be very difficult to notice.

I was actually attempting to make certain that the TX buffer on the PC is empty. Basically I want to be sure the PC has no USART bytes waiting to be transmitted once the UART communication is established. That is why I have the flush buffer function after the UART is set up, just to make 100% certain I am starting with a clean slate each time I start up the com

Thanks for the comments.

Darryl

Post a Reply

Please log in to post a reply.

Did you know that our USB NerdKit works on Windows, Linux, and Mac OS X? Learn more...