Main Page | Modules | Related Pages | Examples

sim/module-src/uart.c

/*
 * Turbo Programmer Utilities, turbo-prog-utils, www.bladox.com 
 *
 * Copyright (C) 2004 BLADOX, s.r.o.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 */

#include <config.h>
#include <tprog/tprog.h>
#include <stdlib.h>
#include <avr/interrupt.h>

#define DEFAULT_SIM_CLK_DIV 2
#define DEFAULT_F 372
#define DEFAULT_D 1
#define DEFAULT_DIVIDER (DEFAULT_F/DEFAULT_D)
u16 simUbrr;

#define SIM_TX_SM_STATE1 (1)
#define SIM_TX_SM_STATE2 (2)
u8 uartTxStateMachine;

#define SIM_UART_RX_FIFO_SIZE 8
u8 uartRxFifo[SIM_UART_RX_FIFO_SIZE];
u8 uartRxFifoNumOfChars;
u8 uartRxFifoTail;
u8 uartRxFifoHead;

u8 inverseConvention;

void init_vars ()
{
  uartRxFifoHead = 0;
  uartRxFifoTail = 0;
  uartRxFifoNumOfChars = 0;

  simUbrr = ((DEFAULT_SIM_CLK_DIV * DEFAULT_DIVIDER) / 8) - 1;

  uartTxStateMachine = SIM_TX_SM_STATE1;
  inverseConvention = 0;
}

void init_uart (void)
{
  //set mode to double speed
  outb (SIM_UART_UCSRA, 0x02);

  // enable receive complete interrupt
  // disable transmit complete interrupt
  // enable receiver
  // disable transmitter because of RXD and TXD connected together
  // to not output log.1 to TXD and RXD
  // we enable transmitter before each char will be send
  outb (SIM_UART_UCSRB, 0x90);

  // asynchronous mode
  // 8 bit data, even parity, 1 stop bit
  outb (SIM_UART_UCSRC, 0x26);

  // set baud rate register to DEFAULT_DIVIDER
  outb (SIM_UART_UBRRH, (simUbrr >> 8));
  outb (SIM_UART_UBRRL, (simUbrr & 0xFF));

  while (uart_chars () != 0)
    uart_get_char ();
}

u8 getInverseConventionChar (u8 directConventionChar)
{
  u8 retVal;
  u8 i;
  u8 mask;
  u8 maskInv;

  retVal = 0;
  mask = 128;
  maskInv = 1;
  for (i = 0; i < 8; i++)
  {
    if ((directConventionChar & mask) != 0)
      retVal |= maskInv;
    mask = mask >> 1;
    maskInv = maskInv << 1;
  }
  retVal = ~retVal;
  return retVal;
}

u8 uart_chars (void)
{
  u8 tmpRxChars;

  cli ();
  tmpRxChars = uartRxFifoNumOfChars;
  sei ();
  return tmpRxChars;
}

u8 uart_get_char (void)
{
  u8 tmpTail;

  cli ();
  if (uartRxFifoNumOfChars > 0)
  {
    uartRxFifoNumOfChars--;
    sei ();
    tmpTail = uartRxFifoTail;
    if (uartRxFifoTail < (SIM_UART_RX_FIFO_SIZE - 1))
      uartRxFifoTail++;
    else
      uartRxFifoTail = 0;

    return uartRxFifo[tmpTail];
  }
  else
  {
    sei ();
    return 0;
  }
}

void uart_send_char (u8 txValue)
{
  u8 txValueTmp;
  u8 iTmp;
  u8 interrupts;

  //store global interrupt enable bit
  interrupts = (inb (SREG) & (1 << SREG_I));

  //cli();
  //check if inverse convention is active
  if (inverseConvention != 0)
    txValueTmp = getInverseConventionChar (txValue);
  else
    txValueTmp = txValue;

  if (uartTxStateMachine == SIM_TX_SM_STATE1)
  {
    // execute delay before transmitting char
    //do delay interval
    delayMs (3);
    uartTxStateMachine = SIM_TX_SM_STATE2;
  }

  // disable receive complete interrupt
  // disable receiver
  outb (SIM_UART_UCSRB, (inb (SIM_UART_UCSRB) & 0x6F));
  //TXD1 pin to log.1
  sbi (SIM_TXD_PORT, SIM_TXD_PORT_PIN);
  //TXD1 pin change direction to output only when transmitting char
  sbi (SIM_TXD_DDR, SIM_TXD_DDR_DD);
  // enable transmitter
  outb (SIM_UART_UCSRB, (inb (SIM_UART_UCSRB) | 0x08));

  // send txValueTmp to UDR register
  sbi (SIM_UART_UCSRA, TXC);
  outb (SIM_UDR, txValueTmp);
  loop_until_bit_is_set (SIM_UART_UCSRA, TXC);
  sbi (SIM_UART_UCSRA, TXC);

  // disable transmitter
  outb (SIM_UART_UCSRB, (inb (SIM_UART_UCSRB) & 0xF7));

  // set TXD1 pin to log.1
  sbi (SIM_TXD_PORT, SIM_TXD_PORT_PIN);

  //TXD1 pin change direction to input to allow receiving
  cbi (SIM_TXD_DDR, SIM_TXD_DDR_DD);

  // clear TXC flag (write log.1 to it)
  sbi (SIM_UART_UCSRA, TXC);

  //restore global interrupt enable bit
  if (interrupts != 0)
    sei ();

  // enable receive complete interrupt
  // enable receiver
  outb (SIM_UART_UCSRB, (inb (SIM_UART_UCSRB) | 0x90));
}

void init_sim_port ()
{
  led_on (LED_SIM);

  // clear RXC flag (write log.1 to it)
  sbi (SIM_UART_UCSRA, RXC);

  // clear TXC flag (write log.1 to it)
  sbi (SIM_UART_UCSRA, TXC);

  // set baud rate to enhanced value from PTS
  outb (SIM_UART_UBRRH, (simUbrr >> 8));
  outb (SIM_UART_UBRRL, (simUbrr & 0xFF));

  //use alternative clk for sim instead  of 8mhz sysctem clk
  //4Mhz for now generated on OCR1A pin
  //SIM_CLKA_ENABLE /set pin to log.1 (active high)
  //(in SIM_MODE CLKA is connected)
  sbi (SIM_CLKA_ENABLE_PORT, SIM_CLKA_ENABLE_PORT_PIN);

  //SIM_RX
  //let it set to input
  //set pin to log.1
  sbi (SIM_RXD_PORT, SIM_RXD_PORT_PIN);
  cbi (SIM_RXD_DDR, SIM_RXD_DDR_DD);

  //SIM_TX
  //let it set to output
  //set pin to log.0
  cbi (SIM_TXD_PORT, SIM_TXD_PORT_PIN);
  sbi (SIM_TXD_DDR, SIM_TXD_DDR_DD);

  //SIM_RST
  //change direction to output 
  //set pin to log.0
  cbi (SIM_RST_PORT, SIM_RST_PORT_PIN);
  sbi (SIM_RST_DDR, SIM_RST_DDR_DD);

  //SIM_RST_ENABLE
  //set pin to log.1
  //(in SIM_MODE SIM_RST is connected)
  ext_sbi (EXT_SIM_RST_ENABLE_PORT, EXT_SIM_RST_ENABLE_PORT_PIN);

  //SIM_IO_ENABLE
  //set pin to log.1
  //(in SIM_MODE SIM_IO is connected)
  ext_sbi (EXT_SIM_IO_ENABLE_PORT, EXT_SIM_IO_ENABLE_PORT_PIN);
}

void uart_irq ()
{
  // next SIM char transmit will execute delay before transmitting char
  uartTxStateMachine = SIM_TX_SM_STATE1;

  // store received character to SIM RX FIFO
  if (inverseConvention != 0)
    uartRxFifo[uartRxFifoHead] = getInverseConventionChar (inb (SIM_UDR));
  else
    uartRxFifo[uartRxFifoHead] = inb (SIM_UDR);

  uartRxFifoNumOfChars++;
  if (uartRxFifoHead < (SIM_UART_RX_FIFO_SIZE - 1))
    uartRxFifoHead++;
  else
    uartRxFifoHead = 0;
}

void uart_change_parity (void)
{
  // asynchronous mode
  // odd parity
  outb (SIM_UART_UCSRC, inb (SIM_UART_UCSRC) | 0x10);
}


Copyright © 2004 BLADOX
Turbo Programmer version 2.0