Skip to main content

Basic Usage of the External EIM Bus on Colibri iMX7

This article wants to demonstrate the basic register setups to be able to access the external system bus (EIM) of the Colibri iMX7.

  • The EIM will be setup to operate in multiplexed, asynchronous mode
  • You will need to adjust timing parameters and other configurations, in order to match your requirements.
    Please refer to the iMX7 reference manual for details about the register settings.

/// @file iMX7_EIM_Demo.c
/// @copyright Copyright (c) 2017 Toradex AG
/// @brief Basic demonstration how how to use the EIM bus of the
/// Colibri iMX7. \n
/// The Bus is configured as follows:
/// * Multiplexed Mode
/// * 8 combined Address / Data Signals
/// * use Chip select nCS0 (SODIMM 105)
///
/// @test Tested on: Colibri iMX7D
/// Windows Embedded Compact 7 (V1.0)
/// Visual Studio 2008
/// Toradex CE Libraries V2.0

#include <windows.h>
#include "mapmem.h"
#include "clk_imx7.h"
#include "gpio_imx7.h"


// WEIM clock root and clock gate registers
#define CCM_BASE_ADDRESS 0x30380000
#define CCM_CCGR22 0x30384160
#define CCM_TARGET_ROOT83 0x3038A980

/* WEIM registers */
typedef struct
{
UINT32 EIM_CS0GCR1;
UINT32 EIM_CS0GCR2;
UINT32 EIM_CS0RCR1;
UINT32 EIM_CS0RCR2;
UINT32 EIM_CS0WCR1;
UINT32 EIM_CS0WCR2;
UINT32 EIM_CS1GCR1;
UINT32 EIM_CS1GCR2;
UINT32 EIM_CS1RCR1;
UINT32 EIM_CS1RCR2;
UINT32 EIM_CS1WCR1;
UINT32 EIM_CS1WCR2;
UINT32 EIM_CS2GCR1;
UINT32 EIM_CS2GCR2;
UINT32 EIM_CS2RCR1;
UINT32 EIM_CS2RCR2;
UINT32 EIM_CS2WCR1;
UINT32 EIM_CS2WCR2;
UINT32 EIM_CS3GCR1;
UINT32 EIM_CS3GCR2;
UINT32 EIM_CS3RCR1;
UINT32 EIM_CS3RCR2;
UINT32 EIM_CS3WCR1;
UINT32 EIM_CS3WCR2;
UINT32 EIM_CS4GCR1;
UINT32 EIM_CS4GCR2;
UINT32 EIM_CS4RCR1;
UINT32 EIM_CS4RCR2;
UINT32 EIM_CS4WCR1;
UINT32 EIM_CS4WCR2;
UINT32 EIM_CS5GCR1;
UINT32 EIM_CS5GCR2;
UINT32 EIM_CS5RCR1;
UINT32 EIM_CS5RCR2;
UINT32 EIM_CS5WCR1;
UINT32 EIM_CS5WCR2;
UINT32 EIM_WCR;
UINT32 EIM_DCR;
UINT32 EIM_DSR;
UINT32 EIM_WIAR;
UINT32 EIM_EAR;
}tEIM_CSP_WEIM_REGS, *ptEIM_CSP_WEIM_REGS;

//-----------------------------------------------------------------------------
// Configure the IOs for the iMX7 EIM bus
/// @param[in] hGpio handle received from Gpio_Init()
/// @retval TRUE Success
/// @retval FALSE Failure
BOOL Eim_ConfigureIos(HANDLE hGpio)
{
int i;
BOOL fSuccess = TRUE;

const uIo eimIo[] =
{
COLIBRI_PIN( 89), // RW
COLIBRI_PIN( 91), // OE
COLIBRI_PIN(105), // CS0_B
COLIBRI_PIN(150), // LBA_B
COLIBRI_PIN(111), // AD0
COLIBRI_PIN(113), // AD1
COLIBRI_PIN(115), // AD2
COLIBRI_PIN(117), // AD3
COLIBRI_PIN(119), // AD4
COLIBRI_PIN(121), // AD5
COLIBRI_PIN(123), // AD6
COLIBRI_PIN(125) // AD7
};

/// The EIM functionality is on Alternate Function 4 for all EIM pins.
for (i = 0; i < _countof(eimIo); i++)
fSuccess &= Imx7Gpio_SetConfigString(hGpio, eimIo[i], NULL, L"AltFn=4", StoreVolatile);

return fSuccess;
}

//*****************************************************************************
/// Main function
/// @param[in] argc number of command line arguments
/// @param[in] argv array containing command line arguments
/// @retval 1 Success
/// @retval 0 Failure
int wmain(int argc, _TCHAR* argv[])
{
BOOL fSuccess = TRUE;
HANDLE hMap;
HANDLE hGpio;

volatile ptEIM_CSP_WEIM_REGS pEimReg;
volatile DWORD *clkRegs;
volatile DWORD tmp;
volatile BYTE *extBus;
volatile DWORD *targetAddr;
int i;

// Enable EIM Clock, OSC_24MHz
hMap = Map_Init();
clkRegs = Map_MapMemory(CCM_BASE_ADDRESS, 0x10000);
targetAddr = clkRegs + (CCM_CCGR22 - CCM_BASE_ADDRESS)/4;
*targetAddr &= ~0xFFFFFFFF;
targetAddr = clkRegs + (CCM_TARGET_ROOT83 - CCM_BASE_ADDRESS)/4;
*targetAddr |= 0x10000000;
targetAddr = clkRegs + (CCM_CCGR22 - CCM_BASE_ADDRESS)/4;
*targetAddr |= 0x03;

// configure EIM GPIOs
hGpio = Imx7Gpio_Init(NULL);
fSuccess &= Eim_ConfigureIos(hGpio);
fSuccess &= Imx7Gpio_Deinit(hGpio);

// Configure CS0 properties for multiplexed, asynchronous operation
pEimReg = (ptEIM_CSP_WEIM_REGS)Map_MapMemory(0x30bc0000, 0x1000);

// Some of the settings below are not relevant for multiplexed, asynchronous
// operation. For details, refer to the iMX7 Reference Manual...
pEimReg->EIM_CS0GCR1 = 0x0064a089; // Bit 31-28 8 words page size (for sync. read/write)
// Bit 27 write allowed
// Bit 26-24 Gap between chip selects = 0 (for async.)
// Bit 23 Address shifted according to port size
// Bit 22-20 CS pulse width >= 6 EIM clocks
// Bit 19 User Mode access allowed
// Bit 18-16 8 bit data port resides on DATA[7:0]
// Bit 15-14 Burst Clock Start 0 delay
// Bit 13-12 Burst Clock divisor = 1
// Bit 10-8 Burst Length = 4
// Bit 7-6 CRE signal disabled
// Bit 5 READ monitors WAIT signal
// Bit 4 WRITE monitors WAIT signal
// Bit 3 Multiplexed mode
// Bit 2 Async. mode for WRITE
// Bit 1 Async. Mode for READ
// Bit 0 CS enabled

pEimReg->EIM_CS0GCR2 = 0x00001002; // Bit 12 ignore GRANT signal
// Bit 8 DTACK disable
// Bit 1-0 Address Hold time = 2 cycles

// further timings can be set in the following registers:
//pEimReg->EIM_CS0RCR1 = 0x00002000;
//pEimReg->EIM_CS0RCR2 = 0x00000000;
//pEimReg->EIM_CS0WCR1 = 0x00000400;
//pEimReg->EIM_CS0WCR2 = 0x00000000;


// Access memory at CS0 address.
// The address range for nCS0 is 0x28000000 to 0x28FFFFFF (128MB).
// However, we map only 64kB here.
extBus = Map_MapMemory(0x28000000, 0x10000);

// When hitting a breakpoint anywhere below, the debugger will read a large block of data and
// create a lot of toggling on all EIM pins.
// 16 x Write
for (i = 0; i <= 15; i++)
*(extBus + i) = 0x00; ///< write

// 16 x Read
for (i = 0; i <= 15; i++)
tmp = *(extBus + i); ///< read

return 1;
}



Send Feedback!