Interrupt based USART transmission and reception

Go To Last Post
10 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have written interrupt based transmission and reception code. If RX_MAX_SIZE is increased to say 25, there is no issue. But if I run the code written in main(), with RX_MAX_SIZE=2 (Just testing purpose I did), things work fine as long as I send single character from the terminal. The moment I send multiple characters from the terminal, system freezes. If multiple character is sent, data may be lost, but should not hang I guess. There seems to be small bug somewhere. Could not find out the exact cause. Attached complete source files. 

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When you send a string or any other byte I am guessing there is a null terminator, or carriage return terminator added to the end of the string so thats why you cannot send more than one byte with RX_MAX_SIZE=2  THE terminator takes up one byte.

 

JIm

I would rather attempt something great and fail, than attempt nothing and succeed - Fortune Cookie

 

"The critical shortage here is not stuff, but time." - Johan Ekdahl

 

"If you want a career with a known path - become an undertaker. Dead people don't sue!" - Kartman

"Why is there a "Highway to Hell" and only a "Stairway to Heaven"? A prediction of the expected traffic load?"  - Lee "theusch"

 

Speak sweetly. It makes your words easier to digest when at a later date you have to eat them ;-)  - Source Unknown

Please Read: Code-of-Conduct

Atmel Studio6.2/AS7, DipTrace, Quartus, MPLAB user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Well the first thing that strikes me is that you have non extern variable definitions in the .h. Both .c files include that header so they will BOTH create copies of those variables. You "get away with it" because these will be .common but it is extraordinarily unwise. Apart from the fact that the buffer pointers should be private to the implementing module anyway, if they really need to be exposed they should be defined in the module .c and declared in the module .h

 

It seems your Tx stuf (for example) just "writes regardless". So say the buffer is [2] and you try to send "hello" then h then e will be put in the buffer but then the buffer will wrap and 'l' will overrite 'h', the second 'l' will over-write 'e' then the buffer will wrap and 'o' will over-write the first 'l' so before anything even gets transmitted the buffer will only hold "ol" with the 'l' being the first to send. Now perhaps that is what you intend but some systems would have a "if buffer is full wait for the interrupt to consume some characters to open a gap so the char to be Txd can be added".

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

RX_VECT will take care of the ring buffer overflow [if(!RX_BUFFER_FULL)]. So extra characters more than 2 will be lost. Also Tx buffer is 25 and this should be good enough for sending the string twice. If there is a data loss, it would have been a different issue. Now micro freezes. Could be some kind of dead lock!! I do not have debugger and need to post errors to LEDs or LCD.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joneewheelock wrote:
I do not have debugger
Try the simulator. But for things like interrupt synchronisation debug it is 1,000 times easier with an ICE.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Could this also be a problem of some variables being updated inside ISR as well? I have not disabled Interrupts inside writeToTxRing() and readFromRxRing(). In for(index=0;index<RxFIFOSize;index++), RxFIFOSize is used and it may get altered inside ISR also. Let me try to install Atmel Studio and use the simulator (Not familiar in debugging with ISRs. Need to study a bit)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am not going to scrutinise every line of your code but as you'll see in well known/respected ringbuffer implementation such as that by Dean Camera atomicity protection may need to play a part in your code for anything that is accessed in both execution contexts and is wide enough to warrant protection

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
accessed in both execution contexts and is wide enough to warrant protection
or implements some read/modify/write.

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Got the problem. In USART_RX_VECT, I am checking the flag RX_BUFFER_FULL and if that happens, I am not clearing UDR0. So ISR occurs continuously. 

 

Just curious: At what rate ISR occurs in such scenario? I get it at around 166KHz (Toggled LED inside the ISR).

 

Secondly: In smaller embedded code, is it not a wise decision to have enough buffer size so that we need not check for buffer overrun etc? We could reduce lot of code. Of course I agree that this depends on the implementation. But in case more than one transaction may not happen especially in point to point communication, I guess we could allocate buffer for lengthiest transaction and optimize the code for size and speed. If buffer overrun occurs, again we have to implement error handling etc.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I fixed the problem. But I have difficulty in understanding synchronization issue with Ring Buffer write and read (from USART_UDRE_vect). Attached is the updated code.

Refe to USART0SendByte() with #define USING_ISR. In this code, I wait in case <currentPosition==TxTail>. Normally this case is rare if buffer size is good enough. But I see that following part is executed in every write.

  while(currentPosition==TxTail)
    {
        #ifdef DEBUG
        static uint8_t cnt=0x31;
        dbg_putchar(cnt++);
        #endif // DEBUG
    }

That means USART_UDRE_vect() is updating the tail before currentPosition compared. There should not be any issue if we use <while(currentPosition==TxTail)> I guess. But one extra while loop is getting wasted right. What is the best way to handle such scenario? Where should I disable interrupt using ATOMIC_BLOCK? Or what if I keep the difference of two between head and tail is maintained? May be that will improve performance?

Attachment(s):