Clock Ticks per command - UART

Thread Starter

AgentSmithers

Joined Jan 14, 2011
77
Hi everyone!
I'm almost wrapped up on getting this Soft UART down to a science, So I'll sound by laying down my foundation and see if I'm on the right track. I am currently hooked up to a GPS module and am receiving a 4800 BUAD communication from the unit. Right now I am sleeping in Microsecond's to help bitbang the incoming stream. However what is the best way to do this?

1: 1Second / 4800Buad / = 0.00020833333
or
2: A different forumla is required?

Should I always have the UC sleep in US or should I sleep by Ticks?

Inbetween bytes coming through the communication I need to check to see if the Char I received was a '$' and a LF on the end to mark the end of the communication. However It appears it effects the timing of the incoming message. What is the best way to resolve this issue by the book? Calculate how much time in UC the checks take and subtract it from the sleep in UC (Some what calibrate it to the code) or is there another alternative? If I do calculate the difference it appears my sending and recv timing will have to be a different value because this check won't exist when sending data?
Thank you for your input!
-Agent

Code:
while(true)
    {
        while(PINA & (1<<UART_GPSRX_INTERRUPT))
        {
        }
           
        _delay_us(SleepRX4800 * 1.5);
        for(uint8_t i = 0; i < 8; i += 1)
        {
            if(PINA & (1<<UART_GPSRX_INTERRUPT)) //RX PIN IS HIGH
            {
                uart_GPS_rx_buffer[uart_GPS_rx_buff_end] |= (1 << i); //RX PIN IS HIGH, try not to change any code here its timing sensitive
            }
            else
            {
                uart_GPS_rx_buffer[uart_GPS_rx_buff_end] &= ~(1 << i); //RX PIN IS LO
            }
   
            if(i != (UART_RX_BUFFER_SIZE - 1))
            {
                _delay_us(SleepRX4800);
            }
        }
       
        if(uart_GPS_rx_buffer[0] == '$' && uart_GPS_rx_buffer[uart_GPS_rx_buff_end] == 0x0A)
        {
            break;
        }
       
        if(uart_GPS_rx_buffer[0] == '$')
        {
            uart_GPS_rx_buff_end++;
        }
    }
 

Papabravo

Joined Feb 24, 2006
21,228
If every transmitter and receiver operated at the exact same frequency then your method might work. In practice different ends of the cable will have different bit timing. I don't think there is much point in going to sleep between bits. Since the communications are asynchronous you can sleep between characters. That way if the talker on the other end has a fast crystal you won't miss anything.
 

MrChips

Joined Oct 2, 2009
30,824
With literally thousands of MCUs with UARTs to choose from, why are you using a software UART instead of a hardware solution?
 

Thread Starter

AgentSmithers

Joined Jan 14, 2011
77
PapaBravo, Thanks for the input however I am not following. What is an alternative to sleeping when waiting for the next signal when bitBanging?

I am choosing to use a Software UART because I want to learn and I want to understand how it work's. i am aware of plenty of ATMega's that have hardware UART but I rather educate myself and overcome this challenge rather then buying myself out of it.

Thanks both for the reply.
 

Papabravo

Joined Feb 24, 2006
21,228
The alternative to sleeping is to monitor the time base to determine the next sample point or use a periodic interrupt to determine the next sample point. Waking up from sleep is not very precise from a timing point of view. This has to do with how long it takes to stabilize the oscillator and come out of sleep state.
 

John P

Joined Oct 14, 2008
2,026
Use an initial edge-triggered interrupt to detect the start bit of each character, then a timer-based interrupt to read each data bit. I'd call it fairly challenging to do this however, if you haven't got an oscilloscope to check the timing as you go along.
 

Thread Starter

AgentSmithers

Joined Jan 14, 2011
77
Use an initial edge-triggered interrupt to detect the start bit of each character, then a timer-based interrupt to read each data bit. I'd call it fairly challenging to do this however, if you haven't got an oscilloscope to check the timing as you go along.
I do use the falling Edge to detect the start bit then after that use delay_us to delay inbetween bit sampling. Is this what you are saying is the correct way?
I use The ATTiny84 with a 8MHZ oscillator accurate enough for 9600buad and in code using ISR(PCINT_vect) to detect these changes then find if its rising or falling then execute my code above.
But is that the best way to implement it from a software point of view?


I definitely agree. It's nonsense to invent a wheel the second time.
Agreed, However education isn't nonsense and thus I find myself wanting to continue my way to figuring this out instead of buying my way through this.
 
Top