/************************************************************************************/ /* DRAM Controller für AVRs */ /* */ /* Mit diesen Funktionen lässt sich ein 512k*8, 512k*16, 1024k*8 oder ein 1024k*16 */ /* DRAM an einem AVR verwenden. Die Adressierung ist dabei linear als Bytes, oder */ /* oder als Words (nur für *16 DRAMs). Bei der Adressierung von Byteadressen werden */ /* zuerst alle Low Bytes, dann alle High Bytes adressiert. Das höchstwertigste Bit */ /* unterscheidet also zwischen High und Low Byte. Dies ist bei der Verwendung von */ /* Bytes und Words zu beachten. */ /* */ /* Der Refresh des Speichers geschieht im Hintergrund mittels Timer 0. Die Refresh */ /* Routine benötigt bei 18,432MHz etwa 5% der CPU Leistung. */ /************************************************************************************/ #include #include #include #include #include "dram.h" #include "uart.h" #define DRAMPORT PORTA //D0-7, D8-15, A0-7 werden hier angeschlossen #define DRAMCONTROL PORTD //A8, A9, A10, LCAS, UCAS, RAS, WE, OE benötigen einen kompletten Port. Die nicht benutzen Bits werden mit 0 beschrieben ! //Um diese Pins trotzdem nutzen zu können, kann man einen Port mit einigen durch Sonderfunktionen (z.B. UART) //belegten Pins verwenden, da diese Pins vom PORT Register nicht beinflusst werden. #define A8 7 #define A9 1 #define A10 0 #define RAS 2 #define CASL 4 #define CASH 5 #define WE 3 #define OE 6 #define DRAMBITS 16 //8 oder 16bit #define DRAMWORD 256 //256, 512 oder 1024 (Anzahl an Words (1 Word = 8 oder 16bit)) #define DRAMSIZE DRAMWORD*(DRAMBITS/8) //Größe in kByte const unsigned char PROGMEM muster[13]={13,150,170,85,254,130,5,134,0,127,160,234,25}; unsigned char mem_init(void) { unsigned long i; unsigned char modulo; TCCR0=4; //Timer0: 72kHz TIMSK=2; //Timer Interrupt: 281Hz für Refresh DRAMCONTROL=255; asm volatile("clr __tmp_reg__" "\n" //DRAMPorts = Ausgang "dec __tmp_reg__" "\n" "out %0-1, __tmp_reg__ " "\n\t" "out %1-1, __tmp_reg__ " "\n\t" : : "I" (_SFR_IO_ADDR(DRAMCONTROL)),"I" (_SFR_IO_ADDR(DRAMPORT)) ); modulo=0; for (i=0;i<(long)1024*DRAMSIZE;i++) //Speichertest { write_byte((i), pgm_read_byte(&muster[modulo])); modulo++; if (modulo==13) modulo=0; } modulo=0; for (i=0;i<(long)1024*DRAMSIZE;i++) { if (read_byte(i)!=pgm_read_byte(&muster[modulo])) return 0; modulo++; if (modulo==13) modulo=0; } return 1;} void writeMem(void) { unsigned long i; unsigned int c; for (i=0;i<(long)1024*DRAMSIZE;i++) { while ((c = uart_getc()) & UART_NO_DATA); write_byte(i, (char)c&255); } } void readMem(void) { unsigned long i; for (i=0;i<(long)1024*DRAMSIZE;i++) { uart_putc(read_byte(i)); } } char read_byte(unsigned long adresse) { unsigned register char temp, daten; cli(); asm volatile("out %3, %B4 " "\n\t" //out RAS Adress "ldi %0, (%5+%6+%7+%8+%9)" "\n\t" //Load Command #if (DRAMWORD==256) "bst %C4, 1" "\n\t" //Load A8 (adresse.17 laden) "bld %0, %10" "\n\t" // ( A8 schreiben) #elif (DRAMWORD==1024) "bst %C4, 2" "\n\t" //Load A8, A9 (adresse.18 laden) "bld %0, %10" "\n\t" // ( A8 schreiben) "bst %C4, 3" "\n\t" // (adresse.19 laden) "bld %0, %11" "\n\t" // ( A9 schreiben) #elif (DRAMWORD==4096) "bst %C4, 3" "\n\t" //Load A8,9,10 (adresse.19 laden) "bld %0, %10" "\n\t" // ( A8 schreiben) "bst %C4, 4" "\n\t" // (adresse.20 laden) "bld %0, %11" "\n\t" // ( A9 schreiben) "bst %C4, 5" "\n\t" // (adresse.21 laden) "bld %0, %12" "\n\t" // ( A10 schreiben) #endif "out %2, %0 " "\n\t" //out RAS Adress "cbr %0, (%7)" "\n\t" // "nop" "\n\t" "out %2, %0 " "\n\t" //Latch RAS Adress #if (DRAMWORD==256) "bst %C4, 0" "\n\t" //Load A8 (adresse.16 laden) "bld %0, %10" "\n\t" // ( A8 schreiben) #elif (DRAMWORD==1024) "bst %C4, 0" "\n\t" //Load A8, A9 (adresse.16 laden) "bld %0, %10" "\n\t" // ( A8 schreiben) "bst %C4, 1" "\n\t" // (adresse.17 laden) "bld %0, %11" "\n\t" // ( A9 schreiben) #elif (DRAMWORD==4096) "bst %C4, 0" "\n\t" //Load A8,9,10 (adresse.16 laden) "bld %0, %10" "\n\t" // ( A8 schreiben) "bst %C4, 1" "\n\t" // (adresse.17 laden) "bld %0, %11" "\n\t" // ( A9 schreiben) "bst %C4, 2" "\n\t" // (adresse.18 laden) "bld %0, %12" "\n\t" // ( A10 schreiben) #endif "out %3, %A4 " "\n\t" //out CAS Adress "out %2, %0 " "\n\t" //out CAS Adress #if ((DRAMWORD==256)&&(DRAMBITS==16)) "sbrs %C4, 2" "\n\t" //High Byte "cbr %0, (%5)" "\n\t" //Load Command (CASL aktivieren) "sbrc %C4, 2" "\n\t" //Low Byte "cbr %0, (%6)" "\n\t" //Load Command (CASH aktivieren) #elif ((DRAMWORD==1024)&&(DRAMBITS==16)) "sbrs %C4, 4" "\n\t" //High Byte "cbr %0, (%5)" "\n\t" //Load Command (CASL aktivieren) "sbrc %C4, 4" "\n\t" //Low Byte "cbr %0, (%6)" "\n\t" //Load Command (CASH aktivieren) #elif (DRAMBITS==8) "cbr %0, (%5)" "\n\t" //Load Command (CASL aktivieren) #endif "out %2, %0 " "\n\t" //Latch CAS Adress // "nop" "\n\t" "out %3-1, __zero_reg__" "\n\t"//DDR = Input "cbr %0, (%8)" "\n\t" //Load Command "out %2, %0 " "\n\t" //activate OE "ldi %0, (%5+%6+%7+%8+%9)" "\n\t" "nop" "\n\t" "in %1, %3-2 " "\n\t" //Read Data "out %2, %0 " "\n\t" //End Write Cycle "ser %0 " "\n\t" "out %3-1,%0 " "\n\t" //DDR = Output : "=&w" (temp),"=r" (daten) : "I" (_SFR_IO_ADDR(DRAMCONTROL)), "I" (_SFR_IO_ADDR(DRAMPORT)),"r" (adresse), "M" (1<