Top secrets sources NedoPC pentevo

Rev

Rev 898 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed | ?url?

#include <avr/io.h>
#include <avr/interrupt.h>

#include "mytypes.h"
#include "rs232.h"
#include "pins.h"

//if want Log than comment next string
#undef LOGENABLE

#define BAUD115200 115200
#define BAUD256000 256000
#define UBRR115200 (((F_CPU/16)/BAUD115200)-1)
#define UBRR256000 (((F_CPU/16)/BAUD256000)-1)

//LINE STATUS REGISTER (LSR) bits (16550 chip emulation):
//--------------------------------------------------------
/** The receiver Data Ready (DR) indicator. */
#define LSR_DR     0
/** The Overrun Error (OE) indicator. */
#define LSR_OE     1
/** The Parity Error (PE) indicator. */
#define LSR_PE     2  
/** The Framing Error (FE) indicator. */
#define LSR_FE     3
/** The Break Interrupt (BI) indicator. */
#define LSR_BI     4
/** The Transmitter Holding Register Empty (THRE) indicator. */
#define LSR_THRE   5
/** The Transmitter Empty (TEMT) indicator. */
#define LSR_TEMT   6
/** The FIFO Half-Full indicator (custom flag: on ZX EVO only). */
#define LSR_HF     7    

//LINE CONTROL REGISTER (LCR) bits (16550 chip emulation):
//---------------------------------------------------------
/**
    These two bits specify the number of bits in each transmitted or received serial character.
    Bit 1 Bit 0 Character Length
    0     0     5 Bits
    0     1     6 Bits
    1     0     7 Bits
    1     1     8 Bits
*/

#define LCR_WLS0   0
#define LCR_WLS1   1
/** This bit specifies the number of Stop bits transmitted and received in each serial character. */
#define LCR_STB    2
/** This bit is the Parity Enable bit. */
#define LCR_PEN    3
/** This bit is the Even Parity Select bit. */
#define LCR_EPS    4
/** This bit is the Stick Parity bit. */
#define LCR_SP     5
/** This bit is the Break Control bit. */
#define LCR_BC     6
/** This bit is the Divisor Latch Access Bit (DLAB). */
#define LCR_DLAB   7

//FIFO buffers size ((FIFO_SIZE-1) value used like mask - must be power of 2 and <= 256)
#define FIFO_SIZE  16

//Registers for 16550 emulation:

//Divisor Latch LSB
static UBYTE rs232_DLL;
//Divisor Latch MSB
static UBYTE rs232_DLM;
//Interrupt Enable
static UBYTE rs232_IER;
//Interrupt Identification
static UBYTE rs232_ISR;
//FIFO Control
static UBYTE rs232_FCR;
//Line Control
static UBYTE rs232_LCR;
//Modem Control
static UBYTE rs232_MCR;
//Line Status
static UBYTE rs232_LSR;
//Modem Status
static UBYTE rs232_MSR;
//Scratch Pad
static UBYTE rs232_SCR;
//Fifo In
static UBYTE rs232_FI[FIFO_SIZE];
static UBYTE rs232_FI_start;
static UBYTE rs232_FI_end;
//Fifo Out
static UBYTE rs232_FO[FIFO_SIZE];
static UBYTE rs232_FO_start;
static UBYTE rs232_FO_end;

void rs232_init(void)
{
        // Set baud rate
        UBRR1H = (UBYTE)(UBRR115200>>8);
        UBRR1L = (UBYTE)UBRR115200;
        // Clear reg
        UCSR1A = 0;
        // Enable receiver and transmitter
        UCSR1B = _BV(RXEN)|_BV(TXEN);
        // Set frame format: 8data, 1stop bit
        UCSR1C = _BV(USBS)|_BV(UCSZ0)|_BV(UCSZ1);

        //Set default values:
        rs232_DLM = 0;
        rs232_DLL = 0x01;
        rs232_IER = 0;
        rs232_FCR = 0x01; //FIFO always enable
        rs232_ISR = 0x01;
        rs232_LCR = 0;
        rs232_MCR = 0;
        rs232_LSR = _BV(LSR_THRE)|_BV(LSR_TEMT); //transmitter empty on start
        rs232_MSR = 0xA0; //DSR=CD=1, RI=0
        rs232_SCR = 0xFF;
        rs232_FI_start = rs232_FI_end = 0;
        rs232_FO_start = rs232_FO_end = 0;
}

void rs232_transmit( UBYTE data )
{
        // Wait for empty transmit buffer
        while ( !( UCSR1A & (1<<UDRE)) );
        // Put data into buffer, sends the data
        UDR1 = data;
}

//#ifdef LOGENABLE
void to_log(char* ptr)
{
        while( (*ptr)!=0 )
        {
                rs232_transmit(*ptr);
                ptr++;
        }
}
//#endif


//after DLL or DLM changing
void rs232_set_baud(void)
{
        if ( rs232_DLM|rs232_DLL )
        {
                if ( (rs232_DLM&0x80) != 0 )
                {
                        //AVR mode - direct load UBRR
                        UBRR1H = 0x7F&rs232_DLM;
                        UBRR1L = rs232_DLL;
                }
                else
                {
                        //default mode - like 16550
                        ULONG i = BAUD115200/ ((((UWORD)rs232_DLM)<<8) + rs232_DLL);
                        UWORD rate = ((F_CPU/16)/i)-1;
                        // Set baud rate
                        UBRR1H = (UBYTE)(rate>>8);
                        UBRR1L = (UBYTE)rate;
                }
        }
        else
        {
                // If( ( rs232_DLM==0 ) && ( rs232_DLL==0 ) )
                // set rate to 256000 baud
                UBRR1H = (UBYTE)(UBRR256000>>8);
                UBRR1L = (UBYTE)UBRR256000;
        }
}

//after LCR changing
void rs232_set_format(void)
{
        //set word length and stopbits
        UBYTE format = ((rs232_LCR&(_BV(LCR_WLS0)|_BV(LCR_WLS1)|_BV(LCR_STB)))<<1);

        //set parity (only "No parity","Odd","Even" supported)
        switch( rs232_LCR&(_BV(LCR_PEN)|_BV(LCR_EPS)|_BV(LCR_SP)) )
        {
                case _BV(LCR_PEN):
                        //odd parity
                        format |= _BV(UPM0)|_BV(UPM1);
                        break;
                case _BV(LCR_PEN)|_BV(LCR_EPS):
                        //even parity
                        format |= _BV(UPM1);
                        break;
                //default - parity not used
        }

        UCSR1C = format;
}

void rs232_zx_write(UBYTE index, UBYTE data)
{
#ifdef LOGENABLE
        char log_write[] = "A..D..W\r\n";
        log_write[1] = ((index >> 4) <= 9 )?'0'+(index >> 4):'A'+((index >> 4)-10);
        log_write[2] = ((index & 0x0F) <= 9 )?'0'+(index & 0x0F):'A'+(index & 0x0F)-10;
        log_write[4] = ((data >> 4) <= 9 )?'0'+(data >> 4):'A'+((data >> 4)-10);
        log_write[5] = ((data & 0x0F) <= 9 )?'0'+(data & 0x0F):'A'+((data & 0x0F)-10);
        to_log(log_write);
#endif
        switch( index )
        {
        case 0:
                if ( rs232_LCR&_BV(LCR_DLAB) )
                {
                        rs232_DLL = data;
                        rs232_set_baud();
                }
                else
                {
                        //place byte to transmitter's fifo
                        if ( ( rs232_FO_end != rs232_FO_start ) ||
                             ( rs232_LSR&_BV(LSR_THRE) ) )
                        {
                                rs232_FO[rs232_FO_end] = data;
                                rs232_FO_end = (rs232_FO_end+1)&(FIFO_SIZE-1);

                                //clear fifo empty flag
                                rs232_LSR &= ~(_BV(LSR_THRE)|_BV(LSR_TEMT));
                        }
                        else
                        {
                                //fifo overload
                        }
                }
                break;

        case 1:
                if ( rs232_LCR&_BV(LCR_DLAB) )
                {
                        //write to DLM
                        rs232_DLM = data;
                        rs232_set_baud();
                }
                else
                {
                        //bit 7-4 not used and set to '0'
                        rs232_IER = data&0x0F;
                }
                break;

        case 2:
                if ( data&1 )
                {
                        //FIFO always enable
                        if ( data&(1<<1) )
                        {
                                //receiver FIFO reset
                                rs232_FI_start = rs232_FI_end = 0;
                                //set empty FIFO flag and clear overrun flag
                                rs232_LSR &= ~(_BV(LSR_OE)|_BV(LSR_DR)|_BV(LSR_HF));
                        }
                       
                        if ( data&(1<<2) )
                        {
                                //tramsmitter FIFO reset
                                rs232_FO_start = rs232_FO_end = 0;
                                //set fifo is empty flag
                                rs232_LSR |= _BV(LSR_THRE)|_BV(LSR_TEMT);
                        }
                       
                        rs232_FCR = data&0xC9;
                }
                break;

        case 3:
                rs232_LCR = data;
                rs232_set_format();
                break;

        case 4:
                //bit 7-5 not used and set to '0'
                rs232_MCR = data & 0x1F;
               
                if ( data&(1<<1) )
                {
                        //clear RTS
                        RS232RTS_PORT &= ~_BV(RS232RTS);
                }
                else
                {
                        //set RTS
                        RS232RTS_PORT |= _BV(RS232RTS);
                }
                break;

        case 5:
                //rs232_LSR = data;
                break;

        case 6:
                //rs232_MSR = data;
                break;

        case 7:
                rs232_SCR = data;
                break;
        }
}

UBYTE rs232_zx_read(UBYTE index)
{
        UBYTE data = 0;
        switch( index )
        {
        case 0:
                if ( rs232_LCR&_BV(LCR_DLAB) )
                {
                        data = rs232_DLL;
                }
                else
                {
                        //get byte from fifo in
                        if ( rs232_LSR&_BV(LSR_DR) )
                        {
                                data = rs232_FI[rs232_FI_start];
                                //to next fifo's byte
                                rs232_FI_start = (rs232_FI_start+1)&(FIFO_SIZE-1);

                                if ( rs232_FI_start == rs232_FI_end )
                                {
                                        //set empty FIFO flag
                                        rs232_LSR &= ~(_BV(LSR_DR));
                                }
                               
                                //check to clear half-full flag
                            if ( ((rs232_FI_end-rs232_FI_start)&(FIFO_SIZE-1)) < (FIFO_SIZE/2) )
                                {
                                        rs232_LSR &= ~(_BV(LSR_HF));
                                }
                        }
                }
                break;

        case 1:
                if ( rs232_LCR&_BV(LCR_DLAB) )
                {
                        data = rs232_DLM;
                }
                else
                {
                        data = rs232_IER;
                }
                break;

        case 2:
                data = rs232_ISR;
                break;

        case 3:
                data = rs232_LCR;
                break;

        case 4:
                data = rs232_MCR;
                break;

        case 5:
                data = rs232_LSR;
                break;

        case 6:
                //DSR=CD=1
                data = rs232_MSR;
                //clear flags
                rs232_MSR &= 0xF0;
                break;

        case 7:
                data = rs232_SCR;
                break;
        }
#ifdef LOGENABLE
        static UBYTE last = 0;
        if ( last!=index )
        {
                char log_read[] = "A..D..R\r\n";
                log_read[1] = ((index >> 4) <= 9 )?'0'+(index >> 4):'A'+((index >> 4)-10);
                log_read[2] = ((index & 0x0F) <= 9 )?'0'+(index & 0x0F):'A'+(index & 0x0F)-10;
                log_read[4] = ((data >> 4) <= 9 )?'0'+(data >> 4):'A'+((data >> 4)-10);
                log_read[5] = ((data & 0x0F) <= 9 )?'0'+(data & 0x0F):'A'+((data & 0x0F)-10);
                to_log(log_read);
                last = index;
        }
#endif
        return data;
}

void rs232_task(void)
{
        //send data
        if( (rs232_LSR&_BV(LSR_THRE)) == 0 )
        {
                if ( UCSR1A&_BV(UDRE) )
                {
                        UDR1 = rs232_FO[rs232_FO_start];
                        //to next fifo's byte
                        rs232_FO_start = (rs232_FO_start+1)&(FIFO_SIZE-1);

                        if ( rs232_FO_start == rs232_FO_end )
                        {
                                //set fifo is empty flag
                                rs232_LSR |= _BV(LSR_THRE)|_BV(LSR_TEMT);
                        }
                }
        }

        //receive data
        if( UCSR1A&_BV(RXC) )
        {
                BYTE b = UDR1;
                if ( (rs232_FI_end == rs232_FI_start) &&
                     (rs232_LSR&_BV(LSR_DR)) )
                {
                        //set overrun flag
                        rs232_LSR |= _BV(LSR_OE);
                }
                else
                {
                        //receive data
                        rs232_FI[rs232_FI_end] = b;
                        //to next fifo's byte
                        rs232_FI_end = (rs232_FI_end+1)&(FIFO_SIZE-1);
                        //set data received flag
                        rs232_LSR |= _BV(LSR_DR);
                       
                        //check to set half-full flag
                        if ( (rs232_FI_end == rs232_FI_start) ||
                             (((rs232_FI_end-rs232_FI_start)&(FIFO_SIZE-1)) >= (FIFO_SIZE/2)) )
                        {      
                                rs232_LSR |= _BV(LSR_HF);
                        }
                }
        }

        //statuses
        if( UCSR1A&_BV(FE) )
        {
                //frame error
                rs232_LSR |= _BV(LSR_FE);
        }
        else
        {
                rs232_LSR &= ~_BV(LSR_FE);
        }

        if( UCSR1A&_BV(UPE) )
        {
                //parity error
                rs232_LSR |= _BV(LSR_PE);
        }
        else
        {
                rs232_LSR &= ~_BV(LSR_PE);
        }

        if( RS232CTS_PIN&_BV(RS232CTS) )
        {
                //CTS clear
                if( (rs232_MSR&0x10) != 0 )
                {
#ifdef LOGENABLE
                        to_log("CTS\r\n");
#endif
                        //CTS changed - set flag
                        rs232_MSR |= 0x01;
                }
               
                rs232_MSR &= ~(0x10);
        }
        else
        {
                //CTS set
                if( (rs232_MSR&0x10) == 0 )
                {
#ifdef LOGENABLE
                        to_log("CTS\r\n");
#endif
                        //CTS changed - set flag
                        rs232_MSR |= 0x01;
                }
               
                rs232_MSR |= 0x10;
        }
}