Go Down

Topic: Mega External Memory Interface Library (Read 978 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
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy