Extra Memory for a PIC Processor - Dynamic Ram
Update Feb2007 I had for a while been toying with the idea of hooking up a RAM chip, Dynamic or Static to a PIC Processor. The PIC Processors manage to pack a big list of peripheral features into (sometimes) tiny packages but if a large set of data needs to be processed, they can be a little short on RAM. The idea of hooking up a RAM Chip or other storage chip to the micro's i/o ports is not a new one, and access to the chip would involve calling a routine with the required RAM address. What was putting me off was that in order to address a big enough memory, quite a few i/o lines would be required. Recently Elector magazine published an article using an ATTiny2313 processor with a DRAM chip and latch to control an lcd display. Time, I thought to have a go with a PIC 16F876(a) Processor. The Elector article used a HY514400 1M by 4Bit dram salvaged from an old sim memory unit. The author had been able to reduce the number of pins required by multiplexing the data and address lines. I had hoped to use a 256k by 4 dram from an old video card, but I found that the chips must have been 'reclaimed' and had shorter pins than could be reliably plugged into a breadboard. The only other drams I had (not soldered onto something) were a couple of TMS4416 16k by 4 drams, one of these was pressed into service. The data I could find (via google) on the 4416 indicated that as the /cas line was also related to the chip enable function, multiplexing the data and address lines would not work (newer chips may work differently). I used all of PORT B for the 8 address lines and the lower 4 bits of PORT A for the data lines. That left /G, /WR, /CAS and /RAS. These were handled by 4 bits from PORT C. the reason for keeping the Data, Address and Control lines on separate ports was to simplify the amount of bit twidling needed to address and read/write a memory location. I used Port C0 = /RAS, C1 = /CAS, C2 = /G (enable) and C3 = /WR.
Here is the code I used to read and write the DRAM:- Mem_Read and Mem_Write call the RAM_Read and RAM_Write routines twice per byte and allow the 16k by 4 bit DRAM to be accessed as a block 8k by 8. The upper address bits are ignored so the memory is repeated at 8k blocks throughout the virtual 64k address space. DRAM memory cells need to be constantly read in order to 'refresh' the data stored. In order to do this simply, I called a refresh routine when ever the program needed to pause for a serial or other i/o device. As there were no long loops within the main program this routine accessed the relevant locations often enough to maintain the data. If your program may go for longer periods without being able to call a similar refresh routine, a timer interupt should be used to ensure that the refresh is performed. ImprovementsAs speed was not my main concern, I did not try to optimise the timing of the DRAM access, I just toggled the /ras,/cas,/g and /wr bits in the same order as the data sheet timing diagram suggested and it worked. Faster Access will be possible by using assembly language and more accurate timing of the control pulses. To use other DRAMs, it is a good idea to try and find a data sheet. As I found with the 4416 dram, the way the chip treats the column address may vary - in the 4416, bits 1-6 are used (not 0-5 as I had expected). Also, with a data sheet, it is possible to follow the timing diagrams for the cas, ras, g/oe and rw pins so that they can be toggled in the right order. Once you have the memory wired and have filled it with values, dumped it back to the console, a test with real data should be next. I use a serial link with 'Hyper Terminal' to 'talk' to the processor and it has a function to send a text file to the serial port. Here are simple routines for storing that text and then printing it back to the terminal:- Note: There are no tests for the size of the file, if it is larger than the ram chip, it will simply wrap round and over write itself. The textPrint function can be called as 'textprint(0)' where the text will simply be sent to the serial port (via putch) or textPrint(1) where a linefeed will be added to return characters. q
void textLoad(void) |
![]()
Introduction |