AVR304 software serial

Go To Last Post
66 posts / 0 new

Pages

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

curtvm wrote:

Since you seem to want to make the irq version work...

 

You should probably clear the timer interrupt flag before enabling the timer interrupt. Since the timer is still running, the flag is getting set unless you are quick enough to get back to putChar (no delay in use). Since the flag is set, you get an isr firing sooner than you planned.

 

    ...... (rest of the putchar() code)

  CLEAR_TX_PIN( );                 // Clear TX line...start of preamble

  CLEAR_TIMER_INTERRUPT( );
  ENABLE_TIMER_INTERRUPT( );        // Enable o/p compare interrupt
}

[\quote]

Thanks Curt. If you see the code the timer interrupt is disabled after the stop bit is sent out. The code snippet is as follows.        

 // Go to idle after stop bit was sent.
  case TRANSMIT_STOP_BIT:
    DISABLE_TIMER_INTERRUPT( );           // Stop the timer interrupts.
    state = IDLE;                         // Go back to idle.
    ENABLE_EXTERNAL0_INTERRUPT( );        // Enable reception again.
  break;

So the interrupt is disabled and enabled again in the putchar() code. Hope this clarifies.

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

sparrow2 wrote:

???

It is a bit tedious and confusing to breakpoint the entire string. So I will try to print just one char 'T' and check. 

Since the T also is wrong you don't need to change anything. (you should already have found the error by then). 

To trace the problem, it is simpler to output just one char. It may be that the issue is with a large number of chars being printed. Sounds illogical, but let me check. I can also use my oscilloscope to see one char easily in single sweep mode.

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

> If you see the code the timer interrupt is disabled after the stop bit is sent out

 

The timer is still running, though. Since it is running, a compare match sets the compare flag. And since the flag is set when the irq is enabled again, you will get to the isr as soon as you enable the irq, and what you thought was going to be a 1 bit time wait, is now no bit time wait.

 

It does seem odd they could put out appnote code that has this problem, but it seems so unless I'm missing something obvious.

Last Edited: Tue. Mar 9, 2021 - 02:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

 

The timer is still running, though. Since it is running, a compare match sets the compare flag.

Please let me know if I understood yo correctly. The putchar() code is:

static void putChar( const unsigned char c )
{
  while( state != IDLE )
  {
    ;                // Don't send while busy receiving or transmitting.
  }

  state = TRANSMIT;
  DISABLE_EXTERNAL0_INTERRUPT( );  // Disable reception.
  SwUartTXData = c;             // Put byte into TX buffer.
  SwUartTXBitCount = 0;         //set bit count 0

  TCCR_P &= ~(( 1 << CS21 )|( 1 << CS20 )); // Reset prescaler counter.
  TCNT = 0;                        // Clear counter register.
  TCCR_P |= (( 1 << CS21 )|( 1 << CS20 )); // CTC mode. Start prescaler clock.

  CLEAR_TX_PIN();               // Clear TX line...start of preamble.

  CLEAR_TX_PIN( );                 // Clear TX line...start of preamble

  ENABLE_TIMER_INTERRUPT( );        // Enable o/p compare interrupt
}

Here, the timer is reset and started before the timer interrupt is enabled. So the timer is already running. Now, if we clear the interrupt flag just before enabling it again, how will that help? The timer is already running and few microseconds have passed before the flag if cleared and set again. I understand clearing the interrupt flag does not affect the timing? 

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

curtvm wrote:
The timer is still running, though. Since it is running, a compare match sets the compare flag. And since the flag is set when the irq is enabled again, you will get to the isr as soon as you enable the irq, and what you thought was going to be a 1 bit time wait, is now no bit time wait.

+1

 

in #27, I wrote:
My guess is it's something to do with the timer being allowed to "free run" during the delay; and/or not being properly re-synced/re-started for subsequent iterations of the 'for' loop ...

 

In #6, I wrote:
But it doesn't look like you have any proper handling for the IDLE state ?

so perhaps entry to IDLE should stop (and reset?) the timer?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

> Now, if we clear the interrupt flag just before enabling it again, how will that help?

 

It seems like I'm doing too much explaining, so must not be making it very clear.

 

Timer is still running while you delay.

On a compare match, compare flag is set. Doesn't matter that the irq is disabled. A match sets the flag.

 

Now, back to putChar for some more printing-

You clear TCNT to 0.

OCR is set to give an irq in 1 bit time.

The timer irq is enabled.

problem here- the timer flag is already set so we jump to the isr here instead of waiting until the tcnt/ocr match

 

 

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

awneil wrote:

in #27, I wrote:
My guess is it's something to do with the timer being allowed to "free run" during the delay; and/or not being properly re-synced/re-started for subsequent iterations of the 'for' loop ...

 

In #6, I wrote:
But it doesn't look like you have any proper handling for the IDLE state ?

so perhaps entry to IDLE should stop (and reset?) the timer?

I feel you are right Awneil. There is no IDLE state in switch statement. The IDLE state is merely to dictate that no char may be written if not in this state. 

I think I may have to rewrite the code to include IDLE handler or look at the code mentioned by Curt in the link  https://godbolt.org/z/ox3Eaq

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

curtvm wrote:

> Now, if we clear the interrupt flag just before enabling it again, how will that help?

 

It seems like I'm doing too much explaining, so must not be making it very clear.

 

Timer is still running while you delay.

On a compare match, compare flag is set. Doesn't matter that the irq is disabled. A match sets the flag.

 

Now, back to putChar for some more printing-

You clear TCNT to 0.

OCR is set to give an irq in 1 bit time.

The timer irq is enabled.

problem here- the timer flag is already set so we jump to the isr here instead of waiting until the tcnt/ocr match

 

 

I understand. How will it be if I stop the timer before the delay loop and let putchar() restart it? Also, I can disable the interrupt flag itself. I will check the code and try. Effectively:

- stop timer, clear flag, disable timer interrupt

- delay loop

 

After the delay, when the program goes to execute the code, the time will start again. Would this be right?

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

Add the clearing of the flag, Try it. It either helps, or it doesn't.

 

 

 

>or look at the code mentioned

 

If other irq's are in use, you can surround this function with saving/disabling/restoring interrupts. That would at least allow interrupts to fire between chars.

 

static int txPut(char c, FILE* f){

    u8 sreg = SREG;

    asm("cli");
    txLow(); //start 1 bit low
    __builtin_avr_delay_cycles( F_CPU/BAUD - 3 ); //tweak as needed
    for( u8 i = 0; i < 8; i++, c >>= 1 ){
        if( c & 1 ) txHigh(); else txLow();
        __builtin_avr_delay_cycles( F_CPU/BAUD - 8 );
    }
    txHigh(); //stop 2 bits

    SREG = sreg; //timing no longer important
    __builtin_avr_delay_cycles( F_CPU/BAUD *2 ); //not important if takes longer

    return 0;
}

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

curtvm wrote:

Add the clearing of the flag, Try it. It either helps, or it doesn't.

 

 

 

>or look at the code mentioned

 

 

Ok Curt. I will fist try to edit my code. Else I will work on the code you mention. Anyway, I have to get it working. I am looking at more projects where I will need a soft uart.

Thanks.

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

amorawala wrote:
stop the timer before the delay loop 

Wouldn't it make more sense to have the end of your stop bit handling stop the timer?

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:

amorawala wrote:
stop the timer before the delay loop 

Wouldn't it make more sense to have the end of your stop bit handling stop the timer?

Right. I can do so easily. Also, to be sure, clear the timer flag & interrupt. 

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

It make totally sense with a hanging ISR, that way there will be no start bit (yes but shorter than 1/2 bit time).

So some of the low data bits become the start bit.

 

My guess is that this is written for the mega8 and works, then the mega328 is added and some of the ISR things is working a bit different.

 

 

 

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

curtvm wrote:

Since you seem to want to make the irq version work...

 

You should probably clear the timer interrupt flag before enabling the timer interrupt. Since the timer is still running, the flag is getting set unless you are quick enough to get back to putChar (no delay in use). Since the flag is set, you get an isr firing sooner than you planned.

Hello all. After due consultations with yo all, the issue seems to be solved. As suggested by Curt & Awneil, I have stopped he timer, cleared the OCR flag bit, disabled the OCIE interrupt after the TRANSMIT_STOP_BIT.

The code snippet is shown

 // Go to idle one bit time after stop bit was sent. This ensures one stop bit.
  case TRANSMIT_STOP_BIT:
	TCCR_P &= ~(( 1 << CS21 )|( 1 << CS20 )); // Reset prescaler counter, stop timer.
	TCNT = 0;                        // Clear counter register.
	CLEAR_TIMER_INTERRUPT( );			//reset OCR flag bit
    DISABLE_TIMER_INTERRUPT( );           // Stop the timer interrupts.
    state = IDLE;                         // Go back to idle.
    ENABLE_EXTERNAL0_INTERRUPT( );        // Enable reception again.
  break;

I have removed cli() and sei() from before and after the delay loop. 

After building the code, I checked the output, it is proper now. I have also tried this at 38400 Baud ( it was at 9600 Baud first). All ok for now.

Thanks a lot to all the experts who assisted in solving the issue.

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

amorawala wrote:
the issue seems to be solved

Great - thanks for feedback.

 

Please mark the solution - see Tip #5:

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...

Pages