PIC Microcontoller DRAM Memory Method

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;
                }
        }
}