Quick Links:

MegaRAM

The MegaRAM Shield for Arduino Mega/Mega2560 adds 128 kilobytes of external fast-access RAM directly mapped to the address space of the microcontroller. Use it for processing large, fast incoming data streams like images or audio, or for buffering data prior to writing to slower SD cards or FLASH memories.

This is not a “kit”, there is nothing to solder, and no extra connectors or components to buy. It is fully assembled and ready to work right out of the box. Compatible with Arduino Mega and Mega2560 and compatible boards.

For a shield with four times as much RAM, consider our QuadRAM shield.

 

  • The MegaRAM Shield

    ../assets/images/ad190_01.gif

    The MegaRAM Shield is small and plugs in to the Arduino Mega/Mega2560 expansion connector on the right side. Other shields can still plug in to their usual place without interference. Also, unused pins from the expansion connector (D43-D53, +5V, GND) are brought out to 0.1" pads.

    MegaRAM Shield
  • Minimal Interference / Maximum Flexibility

    ../assets/images/ad190_02.gif

    The MegaRAM Shield adds 128 kilobytes of fast external RAM to your Arduino Mega or Mega2560, directly mapped into the microcontroller's address space.

    MegaRAM Shield
  • Simple to Use

    ../assets/images/ad190_03.gif

    Fully assembled and ready to work, the MegaRAM shield plugs in to the Arduino Mega/Mega2560 expansion connector. No additional power supply, connectors, or components are required.

    MegaRAM Shield

 

 

$19.95

Features

The MegaRAM shield includes the following features:

  • 128 kilobytes of external zero-wait-state SRAM
  • SRAM directly mapped into microcontroller address space -- no serial or I2C interface required, no libraries needed
  • Compatible with Arduino Mega or Mega2560 (or compatible boards)
  • Powered directly from Arduino -- no additional power supply required
  • Compact design extends away from the center of the Arduino, allowing other shields to plug in and stack without interference
  • Unused pins on Mega expansion header (D43-D53, SPI pins, +5V, GND) are brought out to pads on 0.1” centers for easy interfacing

Sample Code

Here are some sample sketches that illustrate different ways to use the 128 kilobytes of RAM on the MegaRAM shield:

  • RAM Test
  • This sketch shows how we test each MegaRAM shield prior to shipment. It also demonstrates how to use bank control and high memory masking to access the full 128 kilobytes of external RAM.

  • Simple Control
  • This sketch demonstrates the simplest way to access the external RAM, with no bank control, to access ~56 kilobytes of external RAM. The sketch computes a 16384-point complex FFT of a test sinusoid.

Usage

Enabling the External Memory Interface

Most of the pins used for accessing external RAM are automatically taken care of by the microcontroller. In order to enable the external memory interface, the SRE bit in the XMCRA (External Memory Control Register A) has to be set:

XMCRA = _BV(SRE);

The external RAM on the MegaRAM is fast enough to support zero-wait-state operation so all other bits in the XMCRA register can be set to 0.

Enabling the External RAM Device

The actual RAM device itself has to be enabled by setting PL7 (Arduino digital pin D42) high:

pinMode(42, OUTPUT); digitalWrite(42, HIGH);

If this pin is set to LOW then the expansion header pins can be used for other purposes and external RAM will be disabled.

Reserved Pins

When external RAM is enabled, pins PA0-PA7 (digital pins D22 through D29), PC0-PC7 (digital pins D30 through D37), PG0-PG2 (digital pins D39 through D41), and PD7 (digital pin D38) are reserved for the external memory interface.

As described above, pin PL7 (digital pin D42) is reserved for the external RAM device enable pin.

Bank Selection

Pin PD7 (digital pin D38) is used to select between two 64 kilobyte RAM banks, which together form the 128 kilobyte external RAM. The usage of this pin is described below in the RAM Access Options section.

Expansion Pins

Unused pins from the expansion connector are brought out to pads on 0.1” centers for easy interfacing. The picture below shows which pins are brought out and their positions on the MegaRAM shield.

RAM Access Options

The MegaRAM shield provides 128 kilobytes of external RAM, but the ATmega1280/2560 address bus is only 16 bits wide, meaning the microcontroller can only access 64 kilobytes of RAM at a time. Furthermore, part of the 64 kilobyte address space is used by the ATmega1280/2560 processor for internal registers and the 8 kilobytes of internal RAM. In this section we look at the details of how to work with these limitations of the microcontroller.

Simplest Approach -- 56 kilobytes

The simplest approach to using the MegaRAM shield is to do nothing. Here is the memory map of the ATmega1280/2560 processor, showing the locations of internal registers, internal RAM, and external RAM (the memory map is Figure 8-2 from the Atmel ATmega1280/2560 datasheet).

Memory from addresses 0x0200 through 0x21FF is the normal 8 kilobytes of internal SRAM. Memory from locations 0x2200 through 0xFFFF (56832 bytes) is external SRAM provided by the MegaRAM shield.

Therefore, if all you need is ~56 kilobytes of RAM, just start accessing memory at memory location 0x2200 and higher. Here’s an example that shows how to fill this 56 kilobyte region with an increasing sequence of 8-bit numbers:

void test(void) { // Fill 56832 bytes of external RAM

  unsigned char *ptr;

  unsigned count=0;

 

  XMCRA = _BV(SRE); // Enable external memory interface

  pinMode(42, OUTPUT); digitalWrite(42, HIGH); // Enable RAM device

 

  pinMode(38, OUTPUT);   // Make the bank selection bit an output

  digitalWrite(38, LOW); // Select bank 0 (see below for discussion)

 

  for (ptr = (unsigned char *)0x2200U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

}

Bank Control -- 111 kilobytes

If you want to access more than ~56 kilobytes of RAM, you will have to get around the microcontroller’s limited 64 kilobyte address space. The actual RAM device has a 17-bit address bus -- the 17th bit is provided by microcontroller pin PD7 (digital pin D38) while the lower 16 bits come from the microcontroller itself.

This means that by setting D38 high and low, you can switch between two totally separate 64 kilobyte banks of RAM. In each bank, ~56 kilobytes (56832 bytes) is directly visible starting at address 0x2200, just like before. This means that by controlling D38 we have access to 2 banks of RAM, with 56832 bytes in each bank, for a total of 113664 bytes (or about 111 kilobytes) of RAM.

Here’s the same code example from above, which first fills the first 56832-byte bank with numbers, then switches to the second bank and fills it too.

void test(void) { // Fill 56832 bytes per bank of external RAM, two banks

  unsigned char *ptr;

  unsigned count=0;

 

  XMCRA = _BV(SRE); // Enable external memory interface

  pinMode(42, OUTPUT); digitalWrite(42, HIGH); // Enable RAM device

  pinMode(38, OUTPUT);   // Make the bank selection bit an output

 

  digitalWrite(38, LOW);  // First fill the lower bank

  for (ptr = (unsigned char *)0x2200U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

 

  digitalWrite(38, HIGH); // Now fill the upper bank

  for (ptr = (unsigned char *)0x2200U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

}

In summary, accessing ~111 kilobytes of the available 128 kilobytes on the MegaRAM shield is fairly straightforward. To get at that last 17 kilobytes is going to take a bit more work.

High Memory Mask -- 128 kilobytes

The reason we can’t easily access that last 17 kilobytes is because the address range from 0x0000 to 0x21FF is reserved for the microcontroller’s internal registers and internal RAM. The way to work around this limitation is to use a feature called high memory masking (see Section 9.4.2 of the Atmel ATmega1280/2560 datasheet which describes the XMCRB register). The principle is similar to the bank selection mechanism above, except we now use two bank select pins to select between four 32 kilobyte memory banks. These four 32 kilobyte memory banks represent the entire 128 kilobyte external RAM.

Normally, all the pins in Port C (PC0 through PC7) are driven by the external memory interface whenever an external memory access occurs. PC7 is connected to address bit 16 (and PD7, the bank selection bit, is connected to address bit 17). This means that by controlling both PD7 and PC7 (instead of letting PC7 be driven by the microcontroller), we can control access to one of four 32 kilobyte banks, each of which uses address lines 1 through 15. The XMCRB register lets us do this; by setting the XMM0 bit in XMCRB to 1, PC7 is “released” by the microcontroller and becomes a normal digital port pin.

We still have the problem that memory accesses in the range 0x0000 through 0x21FF are used for internal registers and memory, and do not cause external memory accesses. This problem is easily fixed: always generate memory accesses at address 0x8000 and above. The memory range 0x8000 through 0xFFFF represents a 32 kilobyte memory bank. The choice of bank is controlled by controlling pins PC7 and PD7.

The code that shows full access to the 128 kilobyte RAM on the MegaRAM shield is shown below.

void test(void) { // Fill 32768 bytes per bank of external RAM, four banks

  unsigned char *ptr;

  unsigned count=0;

 

  XMCRA = _BV(SRE); // Enable external memory interface

  pinMode(42, OUTPUT); digitalWrite(42, HIGH); // Enable RAM device

  pinMode(38, OUTPUT);   // Make the bank selection bit an output

  XMCRB = _BV(XMM0);     // Release PC7 (digital pin D30)

  pinMode(30, OUTPUT);   // Make PC7 an output

 

  digitalWrite(38, LOW);  // First fill 32768 bytes in bank 0

  digitalWrite(30, LOW);  // PD7=0, PC7=0

  for (ptr = (unsigned char *)0x8000U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

 

  digitalWrite(38, LOW);  // Now fill 32768 bytes in bank 1

  digitalWrite(30, HIGH); // PD7=0, PC7=1 

  for (ptr = (unsigned char *)0x8000U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

 

  digitalWrite(38, HIGH);  // Now fill 32768 bytes in bank 2

  digitalWrite(30, LOW);   // PD7=1, PC7=0 

  for (ptr = (unsigned char *)0x8000U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

 

  digitalWrite(38, HIGH);  // Finally, fill 32768 bytes in bank 3

  digitalWrite(30, HIGH);  // PD7=1, PC7=1 

  for (ptr = (unsigned char *)0x8000U; ptr != 0; ) {

    *ptr++ = (unsigned char) (count++);

  }

}

For a more practical example, see our memory test sketch (RAMTest.pde) to see how this high memory mask approach is used.

Technical Data

Here is the schematic of the MegaRAM shield.

 

The MegaRAM shield was designed in the USA and is assembled in the USA using lead-free components and lead-free manufacturing and assembly processes.

Proudly located in Michigan, USA

Copyright © 2013 Rugged Circuits LLC