This article wants to demonstrate the basic register setups to be able to access the external system bus (EIM) of the Colibri iMX6.
/// @file iMX6_EIM_Demo.c /// @copyright Copyright (c) 2017 Toradex AG /// @brief Basic demonstration how how to use the EIM bus of the /// Colibri iM6. \n /// The Bus is configured as follows: /// * Multiplexed Mode /// * 8 combined Address / Data Signals /// * use Chip select nCS0 (SODIMM 105) /// Note: Stepping through the code with the debugger might /// freeze the system, because the debugger tries to read /// large address ranges around the mapped registers. /// /// @test Tested on: Colibri iMX6DL /// Windows Embedded Compact 7 (V1.3b4) /// Visual Studio 2008 /// Toradex CE Libraries V2.0 #include <windows.h> #include "mapmem.h" #include "clk_imx6.h" #include "gpio_imx6.h" #define CCM_BASE_ADDRESS 0x020C4000 #define EIM_BASE_ADDRESS 0x021B8000 #define EIMBUS_BASE_ADDRESS 0x08000000 // iMX6 CCM typedef struct { DWORD CCM_CCR; // CCM Control Register DWORD CCM_CCDR; // CCM Control Divider Register DWORD CCM_CSR; // CCM Status Register DWORD CCM_CCSR; // CCM Clock Switcher Register DWORD CCM_CACRR; // CCM Arm Clock Root Register DWORD CCM_CBCDR; // CCM Bus Clock Divider Register DWORD CCM_CBCMR; // CCM Bus Clock Multiplexer Register DWORD CCM_CSCMR1; // CCM Serial Clock Multiplexer Register 1 DWORD CCM_CSCMR2; // CCM Serial Clock Multiplexer Register 2 DWORD CCM_CSCDR1; // CCM Serial Clock Divider Register 1 DWORD CCM_CS1CDR; // CCM SSI1 Clock Divider Register DWORD CCM_CS2CDR; // CCM SSI2 Clock Divider Register DWORD CCM_CDCDR; // CCM D1 Clock Divider Register DWORD CCM_CHSCCDR; // CCM HSC Clock Divider Register DWORD CCM_CSCDR2; // CCM Serial Clock Divider Register 2 DWORD CCM_CSCDR3; // CCM Serial Clock Divider Register 3 DWORD rsvd_020c4040; DWORD rsvd_020c4044; DWORD CCM_CDHIPR; // CCM Divider Handshake In-Process Register DWORD rsvd_020c404c; DWORD rsvd_020c4050; DWORD CCM_CLPCR; // CCM Low Power Control Register DWORD CCM_CISR; // CCM Interrupt Status Register DWORD CCM_CIMR; // CCM Interrupt Mask Register DWORD CCM_CCOSR; // CCM Clock Output Source Register DWORD CCM_CGPR; // CCM General Purpose Register DWORD CCM_CCGR0; // CCM Clock Gating Register 0 DWORD CCM_CCGR1; // CCM Clock Gating Register 1 DWORD CCM_CCGR2; // CCM Clock Gating Register 2 DWORD CCM_CCGR3; // CCM Clock Gating Register 3 DWORD CCM_CCGR4; // CCM Clock Gating Register 4 DWORD CCM_CCGR5; // CCM Clock Gating Register 5 DWORD CCM_CCGR6; // CCM Clock Gating Register 6 DWORD rsvd_020c4084; DWORD CCM_CMEOR; // CCM Module Enable Overide Register } CCM_REGS, *ptCCM_REGS; // iMX6 EIM typedef struct { DWORD EIM_CS0GCR1; // 021B_8000 Chip Select n General Configuration Register 1 DWORD EIM_CS0GCR2; // 021B_8004 Chip Select n General Configuration Register 2 DWORD EIM_CS0RCR1; // 021B_8008 Chip Select n Read Configuration Register 1 DWORD EIM_CS0RCR2; // 021B_800c Chip Select n Read Configuration Register 2 DWORD EIM_CS0WCR1; // 021B_8010 Chip Select n Write Configuration Register 1 DWORD EIM_CS0WCR2; // 021B_8010 Chip Select n Write Configuration Register 2 DWORD EIM_CS1GCR1; // 021B_8018 Chip Select n General Configuration Register 1 DWORD EIM_CS1GCR2; // 021B_801c Chip Select n General Configuration Register 2 DWORD EIM_CS1RCR1; // 021B_8020 Chip Select n Read Configuration Register 1 DWORD EIM_CS1RCR2; // 021B_8020 Chip Select n Read Configuration Register 2 DWORD EIM_CS1WCR1; // 021B_8028 Chip Select n Write Configuration Register 1 DWORD EIM_CS1WCR2; // 021B_802c Chip Select n Write Configuration Register 2 DWORD EIM_CS2GCR1; // 021B_8030 Chip Select n General Configuration Register 1 DWORD EIM_CS2GCR2; // 021B_8030 Chip Select n General Configuration Register 2 DWORD EIM_CS2RCR1; // 021B_8038 Chip Select n Read Configuration Register 1 DWORD EIM_CS2RCR2; // 021B_803c Chip Select n Read Configuration Register 2 DWORD EIM_CS2WCR1; // 021B_8040 Chip Select n Write Configuration Register 1 DWORD EIM_CS2WCR2; // 021B_8040 Chip Select n Write Configuration Register 2 DWORD EIM_CS3GCR1; // 021B_8048 Chip Select n General Configuration Register 1 DWORD EIM_CS3GCR2; // 021B_804c Chip Select n General Configuration Register 2 DWORD EIM_CS3RCR1; // 021B_8050 Chip Select n Read Configuration Register 1 DWORD EIM_CS3RCR2; // 021B_8050 Chip Select n Read Configuration Register 2 DWORD EIM_CS3WCR1; // 021B_8058 Chip Select n Write Configuration Register 1 DWORD EIM_CS3WCR2; // 021B_805c Chip Select n Write Configuration Register 2 DWORD EIM_WCR; // 021B_8090 EIM Configuration Register DWORD EIM_WIAR; // 021B_8094 EIM IP Access Register DWORD EIM_EAR; // 021B_8098 Error Address Register } EIM_REGS, *ptEIM_REGS; //----------------------------------------------------------------------------- // Configure the IOs for the iMX6 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(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 0 for all EIM pins. /// (this is different for the iMX7) for (i = 0; i < _countof(eimIo); i++) fSuccess &= Imx6Gpio_SetConfigString(hGpio, eimIo[i], NULL, L"AltFn=0", 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_REGS pEimReg; volatile ptCCM_REGS clkRegs; volatile DWORD tmp; volatile BYTE *extBus; int i; hMap = Map_Init(); // === Enable EIM Clock // ACLK_EIM_SLOW_SEL = 00b (derive clock from AXI) // ACLK_EIM_SLOW_PODF = 111b (divide by 8) clkRegs = (ptCCM_REGS)Map_MapMemory(CCM_BASE_ADDRESS, 0x1000); clkRegs->CCM_CSCMR1 = (((clkRegs->CCM_CSCMR1 & ~0x60000000) | 0x03800000) ^ 0x00600000); // CG5 = 11b (clock always on) clkRegs->CCM_CCGR6 |= 0x00000c00; // === Configure EIM Bus mode pEimReg = (ptEIM_REGS)Map_MapMemory(EIM_BASE_ADDRESS, 0x1000); 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; // === configure EIM GPIOs hGpio = Imx6Gpio_Init(NULL); fSuccess &= Eim_ConfigureIos(hGpio); fSuccess &= Imx6Gpio_Deinit(hGpio); // Access memory at CS0 address. // The address range for nCS0 is 0x08000000 to 0x0ffeffff (127MB). // However, we map only 64kB here. extBus = Map_MapMemory(EIMBUS_BASE_ADDRESS, 0x10000); // 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 fSuccess &= Map_Deinit(hMap); return fSuccess; }