COMMON.H
#define PORTBIT(port, bit) ((unsigned)&(port)*8+(bit)) #define TESTBIT(var, bit) ((var) & (1 <<(bit))) #define SETBIT(var, bit) ((var) |= (1 << (bit))) #define CLRBIT(var, bit) ((var) &= ~(1 << (bit))) DRAM.C
#include <pic.h> #include <common.h> // dram.c -- adapted from dram.src in parallax assembly by Craig Lee // Upon power up or reset, this program starts sampling pin ra.0 and // recording its state in sequential addresses of a 1Mb dynamic RAM. // When the DRAM is full, the program plays back the recorded bits // in a continuous loop. //Sin = ra.0 ; Signal generator input //RAS = ra.1 ; DRAM row-address strobe //WR = ra.2 ; DRAM write line (0 = write) //Dout = ra.3 ; DRAM data line //CAS = rc.3 ; DRAM column-address strobe //adrb_lo = rb ; Low bits of address bus //adrb_hi = rc ; High bits of address bus //Din = rc.2 ; DRAM Q line //Sout = rc.5 ; Signal out to speaker #define Sin RA0 // Signal generator input #define RAS RA1 // DRAM row-address strobe #define WR RA2 // DRAM write line (0 = write) #define Dout RA3 // DRAM data line #define CAS RC3 // DRAM column-address strobe #define adrb_lo PORTB // Low bits of address bus #define adrb_hi PORTC // High bits of address bus #define Din RC2 // DRAM Q line #define Sout RC5 // Signal out to speaker #define BYTE unsigned char #define WORD unsigned int //; Put variable storage above special-purpose registers. // org 8 //r_ctr ds 1 ; Refresh counter //row_lo ds 1 ; Eight LSBs of row address //row_hi ds 1 ; Two MSBs of row address //col_lo ds 1 ; Eight LSBs of column address //col_hi ds 1 ; Two MSBs of column address //flags ds 1 ; Holder for bit variable flag //flag = flags.0 ; Overflow flag for 20-bit address BYTE r_ctr; // Refresh counter BYTE row_lo; // Eight LSBs of row address BYTE row_hi; // Two MSBs of row address BYTE col_lo; // Eight LSBs of column address BYTE col_hi; // Two MSBs of column address bit flag; // Overflow flag for 20-bit address //; Remember to change device info when programming part. // device pic16c55,xt_osc,wdt_off,protect_off // reset start //; Set starting point in program ROM to zero // org 0 //start setb RAS ; Disable RAS and CAS before // setb CAS ; setting ports to output. // mov !ra,#1 ; Make ra.0 (Sin) an input. // mov !rb,#0 ; Make rb (low addresses) output. // mov !rc,#00000100b ; Make rc.2 (Din) an input. // clr flags ; Clear the variables. // clr row_lo // clr row_hi // clr col_lo // clr col_hi // call refresh ; Initialize DRAM. void init(void); void record(void); void play(void); void refresh(void); void write(void); void read(void); void inc_xy(void); void init(void) { RAS = 1; // Disable RAS and CAS before CAS = 1; // setting ports to output. TRISA = 0xFF; // set RA0 as input TRISB = 0x00; // set address bus LSB as output TRISC = 0x04; // set Din as input flag = 0; // clear flag row_lo = 0; // clear temp row address row_hi = 0; // col_lo = 0; // clear temp column address col_hi = 0; // } void main(void) { init(); record(); while(1) { play(); } } //:record call refresh ; Refresh the DRAM. // call write ; Write Sin bit to DRAM. // call inc_xy ; Increment row and col addresses. // jnb flag,:record ; Repeat until address overflows. void record(void) { while(!flag) { refresh(); write(); inc_xy(); } } //:play call refresh ; Refresh the DRAM. // call read ; Retrieve bit and write to Sout) // call inc_xy ; Increment row and col addresses. // goto :play ; Loop until reset. void play(void) { refresh(); read(); inc_xy(); } //write mov adrb_lo,row_lo ; Put LSBs of row addr onto bus (rb). // AND adrb_hi,#11111100b ; Clear bits adrb_hi.0 and .1. // OR adrb_hi,row_hi ; Put MSBs of row addr onto bus (rc). // clrb RAS ; Strobe in the row address. // movb Dout,Sin ; Supply the input bit to the DRAM, // movb Sout,Sin ; and echo it to the speaker. // mov adrb_lo,col_lo ; Put LSBs of col addr onto bus (rb). // AND adrb_hi,#11111100b ; Clear bits adrb_hi.0 and .1. // OR adrb_hi,col_hi ; Put MSBs of col addr onto bus (rc). // clrb WR ; Set up to write. // clrb CAS ; Strobe in the column address. // setb WR ; Conclude the transaction by // setb RAS ; restoring WR, RAS, and CAS high // setb CAS ; (inactive). // ret void write(void) { adrb_lo = row_lo; // put lsb of row address and adrb_hi = row_hi | 0xFC; // the 2 msb bits to the bus RAS = 0; // strobe the row address Dout = Sin; // put the current bit to the dram Sout = Sin; // and echo it adrb_lo = col_lo; // put lsb of column address and adrb_hi = col_hi | 0xFC; // the 2 msb bits to the bus WR = 0; // set to write CAS = 0; // strobe in the column address WR = 1; // restore to complete write RAS = 1; CAS = 1; } //read mov adrb_lo,row_lo ; Put LSBs of row addr onto bus (rb). // AND adrb_hi,#11111100b ; Clear bits adrb_hi.0 and .1. // OR adrb_hi,row_hi ; Put MSBs of row addr onto bus (rc). // clrb RAS ; Strobe in the row address. // mov adrb_lo,col_lo ; Put LSBs of col addr onto bus (rb). // AND adrb_hi,#11111100b ; Clear bits adrb_hi.0 and .1. // OR adrb_hi,col_hi ; Put MSBs of col addr onto bus (rc). // clrb CAS ; Strobe in the column address. // movb Sout,Din ; Copy the DRAM data to the speaker. // setb RAS ; Conclude the transaction by restoring // setb CAS ; RAS and CAS high (inactive). // ret void read(void) { adrb_lo = row_lo; // put lsb of row address and adrb_hi = row_hi | 0xFC; // the 2 msb bits to the bus RAS = 0; // strobe the row address adrb_lo = col_lo; // put lsb of column address and adrb_hi = col_hi | 0xFC; // the 2 msb bits to the bus CAS = 0; // strobe in the column address Din = Sout; // put the current bit to the dram Sout = Sin; // and echo it RAS = 1; // restore to complete read CAS = 1; } // This routine implements a CAS-before-RAS refresh. The DRAM has an onboard // counter to keep track of row addresses, so the status of the external // address bus doesn't matter. The DRAM requires 512 row addresses be refreshed // each 8 ms, so this routine must be called once every 125 microseconds. // Changing the initial value moved into r_ctr will alter the refresh schedule. // For example, to refresh the entire DRAM, move #0 into r_ctr (256 loops) and // call the routine twice in a row (512). //refresh mov r_ctr,#8 //:loop clrb CAS ; Activate column strobe. // clrb RAS ; Activate row strobe. // setb CAS ; Deactivate column strobe. // setb RAS ; Deactivate row strobe. // djnz r_ctr,:loop ; Repeat. // ret void refresh(void) { char i; i = 8; while(i) { CAS = 0; // toggle em! RAS = 0; CAS = 1; RAS = 1; i--; } } // This routine increments a 20-bit number representing the 1,048,576 addresses // of the DRAM. For convenience, the number is broken into two 10-bit numbers, // which are each stored in a pair of byte variables. Note that wherever the // routine relies on the carry bit to indicate a byte overflow, it uses // the syntax "add variable,#1" not "inc variable." Inc does not set or clear // the carry flag. //inc_xy add row_lo,#1 ; Add 1 to eight LSBs of row addr. // sc ; If carry, add 1 to MSB, else return. // ret // inc row_hi ; Increment MSBs of row address. // sb row_hi.2 ; If we've overflowed 10 bits, clear // ret ; row_ hi and add 1 to column // clr row_hi ; address, else return. // add col_lo,#1 // sc ; If carry, add 1 to MSB, else return. // ret // inc col_hi ; Increment MSBs of col address. // sb col_hi.2 ; If we've overflowed 10 bits, clear // ret ; col_ hi and set the flag to signal // clr col_hi ; main program that we've reached the // setb flag ; end of available memory, then return. // ret void inc_xy(void) { row_lo++; //increment lsb of address if(CARRY) //if carry, add one to msb { row_hi++; } if(TESTBIT(row_hi,2)) //overflowed the 10 bit address? { row_hi = 0; //clear col_lo++; //next column if(CARRY) { col_hi++; } if(TESTBIT(col_hi,2)) { col_hi = 0; flag = 1; } } }