Go Down

Topic: Mega External Memory Interface Library (Read 911 times) previous topic - next topic

DigitalJohnson

Sep 24, 2012, 01:39 am Last Edit: Sep 29, 2012, 03:03 am by DigitalJohnson Reason: 1
I have written a small library to use the External Memory Interface on the Mega1280/2560. I still get confused by some of the pointer stuff, so if there's a better way of doing things, please let me know so that I may learn more. I'm looking for BETA testors, constructive comments, tips etc. I have succesfully used this library on an Arduino Mega1280 using a texas instraments bq3287EA RTC. See the library comments for details. I was able to read/write the RTC's registers as locations in RAM, as well as read/write to the RAM located in the RTC. I added address range checking. If the address is out of range, read functions return NULL and write functions won't write anything. I had to post the .cpp file seperately because of the size limit.

Here's the .h file,

ExMem.h:
Code: [Select]

// ExMem.h created for project ExMem Library on 09/17/2012 05:49:48

#ifndef ExMem_h
#define ExMem_h

#include <Arduino.h>

class exmem
{
    public:
        exmem();
        void enable(uint8_t addressWidth = 16, uint16_t lowerLimit = 0x0000,
                          uint8_t upperSectorWaitState = 0x00, uint8_t lowerSectorWaitState = 0x00);
        void disable(void);
        uint8_t readLower(uint16_t address);
        uint8_t readUpper(uint16_t address);
        void writeLower(uint16_t address, uint8_t data);
        void writeUpper(uint16_t address, uint8_t data);
};

extern exmem ExMem; // Create an external instance named ExMem

#endif
DigitalJohnson

MarkT

I'd suggest editing the subject line to be useful - ie include the keywords "Mega external memory interface library", make it easier for people to notice and search for it - you'll get more testers that way :)
[ I won't respond to messages, use the forum please ]

DigitalJohnson

DigitalJohnson

WizenedEE

80 characters per line is very good idea.

DigitalJohnson

Here's the .cpp file,

ExMem.cpp:
Code: [Select]

ExMem.cpp:
[code]

// ExMem.cpp created for project ExMem Library on 09/17/2012 05:49:06

#include "ExMem.h"

// Pointer to first External Memory address.
uint8_t volatile *pExtMemory = reinterpret_cast <uint8_t volatile *> (0x2200);

// Offset from start of ext. memory(*pExtMemory) to start of upper sector.
static uint16_t upperSectorOffset = 0x0000;

// Highest accessable address.
static uint16_t upperLimit = 0xFFFF;

// Sector size = Highest valid address + 1.
static uint16_t upperSize = 0xDE00;
static uint16_t lowerSize = 0xDE00;

exmem::exmem()
{
}

// Using enable() with no parameters selects the default parameters.
// Any invalid value results in the default value being set.

// Valid addressWidth values =
// 8, 10, 11, 12, 13, 14, 15, 16(default)

// Valid upperSectorBoundry values =
// NONE(default), 0x4000, 0x6000, 0x8000, 0xA000, 0xC000, 0xE000
//     *note    NONE(default) = NO lower sector

// Valid wait-state values for Upper and Lower sectors = 0(default), 1, 2, 3
// 0 = no wait-states
// 1 = 1 wait-state for read/write
// 2 = 2 wait-states for read/write
// 3 = 2 wait-states for read/write plus 1 wait-state after address to bus

void exmem::enable(uint8_t addressWidth, uint16_t upperSectorBoundry,
                              uint8_t upperSectorWaitState, uint8_t lowerSectorWaitState)
{
   // Release unused address pins from Port C
   switch (addressWidth)
   {
       // Clear External Memory High Mask register bits
       XMCRB &= 0xF8;
       case 8: // Releases all Port C pins (Mega pins 30-37)
           // Set highest accessable memory address
           upperLimit = 0x00FF;
           // Set External Memory High Mask register bits
           XMCRB = 0x07;        
           break;
       case 10: // Releases Port C7-C2 (Mega pins 30-35)
           upperLimit = 0x03FF;
           XMCRB = 0x06;
           break;
       case 11: // Releases Port C7-C3 (Mega pins 30-34)
           upperLimit = 0x07FF;
           XMCRB = 0x05;
           break;
       case 12: // Releases Port C7-C4 (Mega pins 30-33)
           upperLimit = 0x0FFF;
           XMCRB = 0x04;
           break;
       case 13: // Releases Port C7-C5 (Mega pins 30-32)
           upperLimit = 0x1FFF;
           XMCRB = 0x03;
           break;
       case 14: // Releases Port C7-C6 (Mega pins 30-31)
           upperLimit = 0x3FFF;
           XMCRB = 0x02;
           break;
       case 15: // Releases Port C7 (Mega pin 30)
           upperLimit = 0x7FFF;
           XMCRB = 0x01;
           break;
       default: // Use all Port C pins(default)
           upperLimit = 0xFFFF;
           break;
   }
   // Adjust upperSectorBoundry for addressWidth
   uint16_t boundry;
   if (addressWidth < 15)
   {
       boundry = 0x0000;
   }
   else if (addressWidth < 16)
   {
       boundry = constrain(upperSectorBoundry, 0x0000, 0x6000);
   }
   else
   {
       boundry = upperSectorBoundry;
   }

   // Clears External Memory Upper Sector Limit bits
   XMCRA &= 0x8F;
   // Sets the address boundry between lower and upper sectors
   switch (boundry)
   {
       case 0x4000: // Sets upper sector at 0x4000
           // Sets upper sector offset
           upperSectorOffset = 0x1E00;
           // Sets External Memory Upper Sector Limit bits
           XMCRA |= 0x20;
           break;
       case 0x6000: // Sets upper sector at 0x6000
           upperSectorOffset = 0x3E00;
           XMCRA |= 0x30;
           break;
       case 0x8000: // Sets upper sector at 0x8000
           upperSectorOffset = 0x5E00;
           XMCRA |= 0x40;
           break;
       case 0xA000: // Sets upper sector at 0xA000
           upperSectorOffset = 0x7E00;
           XMCRA |= 0x50;
           break;
       case 0xC000: // Sets upper sector at 0xC000
           upperSectorOffset = 0x9E00;
           XMCRA |= 0x60;
           break;
       case 0xE000: // Sets upper sector at 0xE000
           upperSectorOffset = 0xBE00;
           XMCRA |= 0x70;
           break;
       default: // Sets upper sector at 0x0000(default)
           upperSectorOffset = 0x0000;
           break;
   }
   // Set upper/lower sector sizes
   if (0 < upperSectorOffset)
   {
       lowerSize = upperSectorOffset;
       upperSize = ((1 + exp(2, addressWidth)) - (0x2200 + upperSectorOffset));
   }
   else
   {
       lowerSize = upperSize = ((1 + exp(2, addressWidth)) - 0x2200);
   }
   // Clears Upper Sector Wait State register bits
   XMCRA &= 0xF3;
   // Sets the upper sector wait-state
   switch (upperSectorWaitState)
   {
       case 1: // 1 wait-state for read/write
           XMCRA |= 0x04;
           break;
       case 2: // 2 wait-states for read/write
           XMCRA |= 0x08;
           break;
       case 3: // 2 wait-states for read/write and 1 wait-state after address
           XMCRA |= 0x0C;
           break;
       default: // No wait-states
           break;
   }
   // Clears the Lower Sector Wait State register bits
   XMCRA &= 0xFC;
   // Sets the lower sector wait-state
   switch (lowerSectorWaitState)
   {
       case 1: // 1 wait-state for read/write
           XMCRA |= 0x01;
           break;
       case 2: // 2 wait-states for read/write
           XMCRA |= 0x02;
           break;
       case 3: // 2 wait-states for read/write and 1 wait-state after address
           XMCRA |= 0x03;
           break;
       default: // No wait-states
           break;
   }
   // Enable External Memory Interface
   XMCRA |= 0x80;
}

void exmem::disable(void)
{
   // Disable External Memory Interface
   XMCRA &= 0x7F;
}

////////////////////////////////////////////////////////////////////////////////
// The following functions Read To or Write From the device(s) connected to the
// External Memory Interface. The functions read/write a byte value from/to an
// address in the upper or lower sector. Lower sector addresses start at 0x0000
// to upperSectorBoundry - 1. Upper sector addressess start at 0x0000 to the
// highest accessable address - upperSectorBoundry. The highest address is
// selected with the enable() function's addressWidth parameter. If there is
// only an upper sector then the lower sector's range will be the same as the
// upper sector's. Both upper and lower functions can be used if there is only
// an upper sector. They will have the same effect.
////////////////////////////////////////////////////////////////////////////////

uint8_t exmem::readLower(uint16_t address)
{
   // Create a variable to holds the data.
   uint8_t data;
   // Check if address is out of range.
   if (address >= lowerSize)
   {
       // Out of range returns NULL byte.
       data = 0x00;
   }
   else // Address is within range.
   {
       // Create a pointer to the lower sector address being read.
       volatile uint8_t *pMemory = (pExtMemory + address);
       // Load variable with data stored at the address.
       data = *pMemory;
   }
       return data; // Return with data.
}

uint8_t exmem::readUpper(uint16_t address)
// Create a variable to holds the data.
uint8_t data;
// Check if address is out of range.
if (address >= upperSize)
{
   // Out of range returns NULL byte.
   data = 0x00;
}
else // Address is within range.
{
   // Create a pointer to the upper seotor address being read.
volatile uint8_t *pMemory = (pExtMemory + upperSectorOffset + address);
// Load variable with the data stored at the address.
data = *pMemory;
}
return data; // Return with data;
}

void exmem::writeLower(uint16_t address, uint8_t data)
{
   // Only perform write if address is within range.
   if (address < lowerSize)
   {
       // Create a pointer
       volatile uint8_t *pMemory;
       // Assign the address being pointed to.
       pMemory = (volatile uint8_t *)(pExtMemory + address);
       // Put the data at the address being pointed to.
       *pMemory = (uint8_t)(data);
   }
}

void exmem::writeUpper(uint16_t address, uint8_t data)
// Only perform write if address is within range.
if (address < upperSize)
{
   // Create a pointer
   volatile uint8_t *pMemory;
   // Assign the address being pointed to.
   pMemory = (volatile uint8_t *)(pExtMemory + upperSectorOffset + address);
   // Put the data at the address being pointed to.
   *pMemory = (uint8_t)(data);

exmem ExMem = exmem(); // Create an instance named ExMem


Thanks again for your time,
DigitalJohnson
[/code]
DigitalJohnson

DigitalJohnson

These comments were in the .cpp file.

Code: [Select]

////////////////////////////////////////////////////////////////////////////////
// This Library is written for the Arduino Mega 1280/2560. See the ATmega1280/
// 2560 data sheet on how to connect your hardware to the External Memory
// Interface of the ATmega. I have successfully tested this library with a
// Mega1280 and the texas instramens bq3287EA Real-Time Clock. I used a 74ACH573
// transparent latch between the mega and the RTC as per the data sheet. I tied
// the AD7:0 pins from the mega(pins 22-29) to the AD7:0 pins of the RTC
// (pins 4-11). I also tied AD7 of the mega(pin 29) to D7 of the latch. Then I
// tied the EXTRAM pin of the RTC to the Q7 output of the latch to access the
// upper 128 bytes of ram on the RTC. Use the ExMem.enable() function to set up
// and turn on the External Memory Interface. I used enable(8, 0x0000, 1, 0)
// for my tests, (8 = 8 bit addressWidth, 0x0000 = only an upper sector,
// 1 = 1 wait-state(upper sector), 0 = 0 wait-state (lower sector)). If there's
// only an upper sector, you can omit the last parameter.
////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////
// You can have two different wait-state settings if needed. (eg. Two
// hardware devices each having different timing specs). If only one wait
// state setting is needed use the default(0x0000). Otherwise entering a
// valid value creates an upper and a lower sector, each having it's own
// wait-state set with the enable() function. If the default is used there
// is only an upper sector. However, both "Upper" and "Lower" functions can
// still be used, as they will have the same effect.
////////////////////////////////////////////////////////////////////////////


DigitalJohnson

Go Up