<?php
/*********************************************
Project : PG 8x8 Midi Matrix 
Version : 0.1
Date    : 17.9.2002
Author  : Matti Leino
Company : Project Groove

PG 8x8 Midi Matrix uses MAXIMs MAX456 video crosspoint switch to route midi signals.
See Maxims datasheet for information: http://www.maxim-ic.com

If you have any questions, feel free to ask: mle@nic.fi

And of course, this code is GPL, so use it any way you want, but please keep these commanted lines in code.

(c) Matti Leino

Chip type           : AT90S2313
Clock frequency     : 4,000000 MHz
Memory model        : Tiny
Internal SRAM size  : 128
External SRAM size  : 0
Data Stack size     : 32         

------ss
---------------------------------------
IOs
PortB 0        LCD RS
PortB 1        LCD RD
PortB 2        LCD EN
PortB 3        free (output)
PortB 4        LCD DB4
PortB 5        LCD DB5
PortB 6        LCD DB6
PortB 7        LCD DB7

PortD 0        free (input)
PortD 1        Rotary Encoder Input A
PortD 2        Rotary Encoder Input B (Ext IRQ 0)
PortD 3        Exec-button (Ext IRQ 1)
PortD 4     /LATCH for matrix
PortD 5     DATA for matrix
PortD 6        WR/SCLK for matrix

---------------------------------------------

*********************************************/

#include <90s2313.h>

// Alphanumeric LCD Module functions
#asm
   
.equ __lcd_port=0x18
#endasm
#include <lcd.h>
#include <delay.h>
#include <stdio.h>


/***************************************
*           Global constants           *
***************************************/
  
#define ENC_CH_A    !PIND.1
#define ENC_CH_B    !PIND.2
#define EXEC            !PIND.3
#define CP_LATCH    PIND.4
#define CP_DATA        PIND.5
#define CP_WR            PIND.6

typedef unsigned char byte;

/*************************************************
* There's two special characters defined.        *
* outOff indicates, as you propably can imagine, *
* if output is not selected for current input.   *
* outOn if output is selected                    *
*************************************************/

flash byte outOff[8]=
{
    
0b0000000,
    
0b0011111,
    
0b0010001,
    
0b0010001,
    
0b0010001,
    
0b0011111,
    
0b0000000,
    
0b0000000
};

flash byte outOn[8]=
{
    
0b0000000,
    
0b0011111,
    
0b0011111,
    
0b0011111,
    
0b0011111,
    
0b0011111,
    
0b0000000,
    
0b0000000
};

/******************************************
* This function is straightly copy/pasted *
* from CodeVisions manual                 *
*******************************************/

void define_char(byte flash *pc,byte char_code)
{
    
byte i,a;
    
= (char_code<<3) | 0x40;
    for(
08i++) lcd_write_byte(a++,*pc++);
}


/***************************************
*           Global variables           *
***************************************/

eeprom byte savedOutArray[8] = { 0x90x90x90x90x90x90x90x9 };
byte inputOpCodes[8] = { 0x00x10x20x30x40x50x60x7 };
byte outputSel[8] = { 0x90x90x90x90x90x90x90x9 };
unsigned char execValue 0;
unsigned char new_limit 8;
unsigned char buff[9];
unsigned char work0 0;
unsigned char work1 0;
unsigned char exec_counter 0;
unsigned char encValue 0;
unsigned char inputValue 0;
unsigned char i 0
unsigned long int CP_data;

/***************************************
*           Global functions           *
***************************************/

void setupIO(void);
void initLCD(void);
void chooseInput(void); 
void chooseOutput(void);
void crunchData(void);
void setCP(void);
void save_e2(void);


/***************************************
* External Interrupt 0 service routine *
***************************************/

interrupt [EXT_INT0void ext_int0_isr(void)
{    
    if(!
ENC_CH_A)
    {
        if(
encValue new_limit)
        {
            
encValue++;
            
delay_ms(15);
        }    
        else
        {
            
encValue 0;
            
delay_ms(15);
        }            
    }
    else
    {
        if(
encValue != 0)
        {
            
encValue--;
            
delay_ms(15);
        }
        else
        {
            
encValue new_limit;
            
delay_ms(15);
        }
    }
        
    
delay_ms(55);
}

/***************************************
* External Interrupt 1 service routine *
***************************************/

interrupt [EXT_INT1void ext_int1_isr(void)
{
    while(
EXEC)
    {    
        
exec_counter++;
        
delay_ms(100);
    }
    
    if(
exec_counter <= 35)
    {
        
execValue 1;    
        
delay_ms(50);
    }
    else
        
save_e2();
        
    
exec_counter 0;
}

/***************************************
*                 MAIN                 *
***************************************/

void main(void)
{
    
setupIO();
    
define_char(outOff,0);
    
define_char(outOn,1);
    
    
_lcd_ready();
    
_lcd_write_data(0xe);
    
lcd_gotoxy(0,0);
    
sprintf(buff"in:%-1uout:"encValue+1);
    
lcd_puts(buff);
    for(
08i++)
        
outputSel[i] = savedOutArray[i];
    
initLCD();
    
lcd_gotoxy(3,0);
    
crunchData();
    
setCP();    
    
/***************************************
*               Main loop              *
***************************************/    

    
while (1)
    {
        if(
encValue == 0
            
lcd_gotoxy(3,0);
        else
            
lcd_gotoxy(encValue-1,1);        
            
        if(
encValue == && execValue == 1)
        {
             
chooseInput();
            
delay_ms(250);
             
encValue 0;
             
execValue 0;
        }

        if(
encValue != && execValue == 1)
        {
            
chooseOutput();
        }
  };


/**************************************************************************************/
/*****************                      FUNCTIONS                       ***************/
/**************************************************************************************/

void setupIO(void)
{
    
// Declare your local variables here

    // Input/Output Ports initialization
    // Port B
    
PORTB=0x00;
    
DDRB=0xFF;

    
// Port D
    
PORTD=0x1F;
    
DDRD=0x70;

    
// Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    // Mode: Output Compare
    // OC0 output: Disconnected
    
TCCR0=0x00;
    
TCNT0=0x00;

    
// Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer 1 Stopped
    // Mode: Output Compare
    // OC1 output: Discon.
    // Noise Canceler: Off
    // Input Capture on Falling Edge

    // These has been disabled cause of the lack of the code memory...=)
    /*
    TCCR1A=0x00;
    TCCR1B=0x00;
    TCNT1H=0x00;
    TCNT1L=0x00;
    OCR1H=0x00;
    OCR1L=0x00;
  */
  
    // External Interrupt(s) initialization
    // INT0: On
    // INT0 Mode: Low level
    // INT1: On
    // INT1 Mode: Low level
    
GIMSK=0xC0;
    
MCUCR=0x00;
    
GIFR=0xC0;

    
// Timer(s)/Counter(s) Interrupt(s) initialization
    
TIMSK=0x00;

    
// Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    
ACSR=0x80;

    
// LCD module initialization
    
lcd_init(8);

    
// Global enable interrupts
    #asm("sei")
}

/*******************************************************************************************************/

void initLCD(void)
{
    for(
08i++)
    {
        
lcd_gotoxy(i,1);
        if( 
outputSel[i] == inputOpCodes[inputValue-1] )        //(outputSel[i] != 0xa)
            
lcd_putchar(1);
        else
            
lcd_putchar(0);
    }
}

/*******************************************************************************************************/

void chooseInput(void)
{
    
new_limit 7;
    
execValue 0;
    while( 
execValue == )
    {
        
inputValue encValue+1;
        
lcd_gotoxy(3,0);
        
sprintf(buff"%-1u"inputValue);
        
lcd_puts(buff);
        
initLCD();            
        
lcd_gotoxy(0,0);
        
delay_ms(50);
    };
    
new_limit 8;


/*******************************************************************************************************/

void chooseOutput(void)
{
    
lcd_gotoxy(encValue-1,1);
    
execValue 0;
    if(
outputSel[encValue-1] != 0x9)
    {
        
lcd_putchar(0);
        
outputSel[encValue-1] = 0x9;
    }
    else
    {
        
lcd_putchar(1);
        
outputSel[encValue-1] = inputOpCodes[inputValue-1];
    }
    
lcd_gotoxy(encValue-1,1);
    
crunchData();
    
setCP();
}

/*******************************************************************************************************/

void crunchData(void)
{
    for(
08i+=2)
    {
        
work0 0;
        
work1 0;
        
work0 outputSel[i];    
        
work1 outputSel[i+1];
        
work0 <<= 4// Shiftataan 4 bittiä vasuriin...
        
work0 &= 0xF0;
        
work0 |= work1// Oorataan siihen work1 -> saadaan tavu, jossa4 ylintä on work0, ja 4 alinta work1
        
CP_data |= work0// Oorataan se CP_dataan.
        
if( )
            
CP_data <<= 8// Shiftataan 8 vasuriin.
    
}
        
/*
        sprintf(buff,"%-lu",CP_data);
        lcd_gotoxy(0,1);
        lcd_puts(buff);
        delay_ms(5000);
        initLCD();
        */
}

/*******************************************************************************************************/

void save_e2(void)
{
    for(
08i++)
        
savedOutArray[i] = outputSel[i];
    
lcd_gotoxy(0,1);
    
lcd_putsf("Saved!  ");
    
delay_ms(3000);
    
initLCD();


/*******************************************************************************************************/

void setCP(void)
{
    
CP_LATCH 0;
    for(
032i++)
    {
        
#asm
            
bst r23,7
           in  r0
,0x10
           bld r0
,5
            out 0x10
,r0
        
#endasm
        
CP_data <<= 1;    
        
CP_WR 1;                        // Kellotetaan Crosspointille.
        
CP_WR 0;
    }
    
delay_us(5);
    
CP_LATCH 1;    
}

// End Of File

/*    for(i = 32; i > 0; i--)
    {
        CP_DATA = (CP_data << i) & 0x1;  
        CP_WR = 1;                        // Kellotetaan Crosspointille.
        CP_WR = 0;
    }*/
    
        /*
                CP_LATCH = 0;
                delay_ms(500);
                CP_LATCH = 1;
                CP_DATA = 0;
                delay_ms(500);
                CP_DATA = 1;
                CP_WR = 0;
                delay_ms(500);
                CP_WR = 1;
                CP_DATA = 0;
                delay_ms(500);
                CP_DATA = 1; 
    */ 
?>