avr-libc-dev
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [avr-libc-dev] USI to UART


From: Bob Paddock
Subject: Re: [avr-libc-dev] USI to UART
Date: Wed, 14 Jun 2006 07:58:23 -0400
User-agent: Opera M2/8.54 (Win32, build 7730)

On Mon, 12 Jun 2006 14:20:44 -0400, Cairns, Dustin <address@hidden> wrote:

Has anyone used the USI as a UART based on the application note from
ATMEL AVR307?  This app note uses the Tiny26 and I am trying to port
this to the Mega3250 but I cannot get it working.

I was able to get AVR307 to work on the Mega325.  It was a real pain
to do it.  You have to recalculate all of the constants,
and in someplaces change the sign of operations, because
of the change of direction of the counter between the two parts.
Obviously Atmel did not put a great deal of thought into the statement
"The drivers can be adapted to the ATtiny2313 or ATmega169 USI modules
by *minor* changes to the code".

I can't give you all of the code as it is from my Day Job,
but this should get you in the right direction.  Take note of changes
in sign compared to AVR307:

#define USI_TIMER_PRESCALE      (8UL)
#define USI_CLK                 (F_CPU/USI_TIMER_PRESCALE)

#if( (1UL) ==  USI_TIMER_PRESCALE )
#define TIMER0_SETUP (_BV(WGM01)|_BV(CS00)|_BV(COM0A0)); // Start Timer0, CTC mode /1
#define INTERRUPT_LATENCY (3)
#endif

#if( (8UL) ==  USI_TIMER_PRESCALE )
#define TIMER0_SETUP (_BV(WGM01)|_BV(CS01)|_BV(COM0A0)); // Start Timer0, CTC mode /8
#define INTERRUPT_LATENCY (3)
#endif

#define TIMER0_USI_9600         ((USI_CLK/9600UL)-1)
#define TIMER0_USI_38400        ((USI_CLK/38400UL)-1)
#define TIMER0_USI_RX_9600 (((TIMER0_USI_9600/2)+1) - INTERRUPT_LATENCY) /* Center of first data bit */ #define TIMER0_USI_RX_38400 (((TIMER0_USI_38400/2)+1)- INTERRUPT_LATENCY)

#define UART_RX_BUFFER_SIZE (64) /* 2,4,8,16,32,64,128 or 256 bytes */
#define UART_TX_BUFFER_SIZE     (64)

#define DATA_BITS                 8
#define START_BIT                 1
#define STOP_BIT                  1
#define HALF_FRAME                5

#define USI_COUNTER_MAX_COUNT     16
#define USI_COUNTER_TRANSMIT (USI_COUNTER_MAX_COUNT - HALF_FRAME)
#define USI_COUNTER_RECEIVE (USI_COUNTER_MAX_COUNT - (START_BIT + DATA_BITS) )

void UART_Baud_Set( uint16_t baud_u16 )
{
    if( 38400 == baud_u16 )
      {
            ocr0a_reload_u8    = TIMER0_USI_38400;
            ocr0a_reload_rx_u8 = TIMER0_USI_RX_38400;
      }
    else
      { // 9600
            ocr0a_reload_u8    = TIMER0_USI_9600;
            ocr0a_reload_rx_u8 = TIMER0_USI_RX_9600;
      }

usi_ctr_setup_u8 = 0xF0 | // Clear all USI interrupt flags. USI_COUNTER_RECEIVE; // Preload the USI counter to generate interrupt.
}

// Initialize USI for UART transmission.
void UART_Initialize_Transmitter( void )
{
  uint8_t sreg_u8 = SREG;
  __disable_interrupt();

  TCNT0   = 0x00;
  OCR0A   = ocr0a_reload_u8;
  TCCR0A  = TIMER0_SETUP;               // Start Timer 0

USICR = (1<<USIOIE)| // Enable USI Counter OVF interrupt.
           (1<<USIWM0)|                 // Select Three Wire mode.
(1<<USICS0); // Select Timer0 OCR as USI Clock source.

USIDR = 0xFF; // Make sure MSB is '1' before enabling USI_DO.
  USISR  = 0xF0 |                       // Clear all USI interrupt flags.
0x0F; // Preload the USI counter to generate interrupt at first USI clock.
  USI_DDR |= _BV(USI_DO);               // Configure USI_DO as output.

  ongoing_Transmission_From_Buffer = TRUE;

  SREG = sreg_u8;
}

/* Initialize USI for UART reception.
* Note that this function only enables pinchange interrupt on the USI Data Input pin.
 * The USI is configured to read data within the pinchange interrupt.
 */
void UART_Initialize_Receiver( void )
{
USI_PORT |= (_BV(USI_DO)|_BV(USI_DI)|_BV(USI_SCK)); // Enable pull up on USI DO, DI and SCK pins. USI_DDR &= ~(_BV(USI_DO)|_BV(USI_DI)|_BV(USI_SCK)); // Set USI DI, DO and SCK pins as inputs.
    USICR  =  0;                                           // Disable USI.
PCMSK0 = _BV(USI_DI); // Enable pin change on USI_DI input EIFR = (1<<PCIF0); // Clear pin change interrupt flag. EIMSK |= (1<<PCIE0); // Enable pin change interrupt USI pins
}


/* Timer/Counter0 Compare Match is used to clock the USI:
* USI_UART_Initialize_Transmitter() does not enable the vector, as it is not needed. * USI_UART_Initialize_Receiver() initially loads OCR0A with the 1.5-bit time point, * to sample the middle of the first data bit. We reload OCR0A here to the 1-bit time point,
 * then disable the IRQ as the hardware takes it from there.
 */
SIGNAL( TIMER0_COMP_vect )
{
    TCCR0A = 0;
    TIMSK0 = 0;                 // Output Compare Match IRQ disabled
    TCNT0  = 0;
    OCR0A  = ocr0a_reload_u8;
    TCCR0A = TIMER0_SETUP;      // Start Timer 0
}









reply via email to

[Prev in Thread] Current Thread [Next in Thread]