This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Accessing External Memory Devices

Hey all,

I am using uVision 3 and a Phytec 2294 board.

I have an external memory device connected to the phytec expansion board. The external device is using /CS0, although from talking to phytec, I am not sure if that is quite right.

I have set up the external memory space in the project options like so:
Start: 0x80000000 Size: 0x4

When I define a variable like :

#define volatile var x __at 0x8000000

and step through my code, any write/read to that variable doesnt seem to take place at the right addresses.

Can anyone give a clue as to what I may have missed?
Thanks

Doug

Parents
  • "I have set up bank 3 to be 8 bit wide , set wait states, etc."

    So you have code to write the configuration value into BCFG3, or does the IDE generate code to do this for you?

    "In the target options, I have specifed external memory space 0x83000000 with a size of 4 bytes for now, since I only need a few addresses to get going."

    But have you defined any variable to be there? That is, a variable with a defining declaration to allocate storage space there? Using the macro like we've discussed should generate code to read/write to that location, but it does not allocate storage space (which is not necessarily a problem, but it won't show up in a memory map).

    "It is to my understanding that when I access a variable defined at a particualr address, it will assert the appropriate chip select signal"

    Yes, regardless of whether you have a normal storage-allocating defining declaration and linker controls to locate it at that particular address, or use a macro, the chip select would be your indication that you are accessing your memory space.

    Is your board jumpered correctly to route the chip select where you want it?

Reply
  • "I have set up bank 3 to be 8 bit wide , set wait states, etc."

    So you have code to write the configuration value into BCFG3, or does the IDE generate code to do this for you?

    "In the target options, I have specifed external memory space 0x83000000 with a size of 4 bytes for now, since I only need a few addresses to get going."

    But have you defined any variable to be there? That is, a variable with a defining declaration to allocate storage space there? Using the macro like we've discussed should generate code to read/write to that location, but it does not allocate storage space (which is not necessarily a problem, but it won't show up in a memory map).

    "It is to my understanding that when I access a variable defined at a particualr address, it will assert the appropriate chip select signal"

    Yes, regardless of whether you have a normal storage-allocating defining declaration and linker controls to locate it at that particular address, or use a macro, the chip select would be your indication that you are accessing your memory space.

    Is your board jumpered correctly to route the chip select where you want it?

Children
  • The IDE has a "wizard" type interface that lets me set up the banks.


    I have defined a variable at the location 0x83000000

    I have verified that the CS0 signal from the micro is routed correctly to the external device.

    Thanks

    Doug

  • "The IDE has a "wizard" type interface that lets me set up the banks."

    How does the wizard get the configured value into the BCFG3 register?

    "I have defined a variable at the location 0x83000000

    I have verified that the CS0 signal from the micro is routed correctly to the external device.


    This is an area of (my) confusion -- isn't 0x83000000 /CS3?

  • Ooops...

    I have been mistyping my addresses in the forum lol I have defined an address at 0x80000000 not 0x83000000. Sorry about that.

    I am assuming that the wizard "magically" puts it there somehow, I have verified that the bank register has the correct values as well.

    Doug

  • Then skimming chapters 4 and 5 of your hardware manual, I'm guessing that the ARM is either booting out of internal flash and CS0 is available for your use, or that at some point after booting from a CS0-selected memory device, CS0 is then later remapped to 0x80000000 for your use, right?

    If this dual mapping is an area of possible confusion or contention, can you use one of the other of CS1-3?

  • Then skimming chapters 4 and 5 of your hardware manual, I'm guessing that the ARM is either booting out of internal flash and CS0 is available for your use, or that at some point after booting from a CS0-selected memory device, CS0 is then later remapped to 0x80000000 for your use, right?

    when the cpu starts, it begins execution at address 0x00000000., but I think I could tell it to REMAP anywhere I wanted to in theory. It may just be easier to use a different CS. What do you think. Primarily I wanted to know if my methodolgies to address this outside memory were correct.

    Because when I looked in the disassembly, when I wrote to my address, it was still writing in the 0x00000000 space.

    Thanks

    Doug

  • Let's put aside any issues related to linker-located data objects and simply access memory locations directly. Take the incomplete snippet below and look at its disassembly. You should see code generated to read from those addresses. If so, then you should be able to incorporate it into a test on the actual hardware, while playing around with the BCFGn registers and probing the CSn signals on the board with a scope to look for activity.

    #define ADDR_TO_P(addr) ((volatile unsigned char *)(addr))
    
    void foo(void)
    {
        unsigned char b;
    
        for (;;)
        {
            b = *ADDR_TO_P(0x80000000);
            b = *ADDR_TO_P(0x81000000);
            b = *ADDR_TO_P(0x82000000);
            b = *ADDR_TO_P(0x83000000);
        }
    }

  • Dan,

    Thanks again.

    When I plug that code in to my program, I get the following:

    *** error 65: access violation at 0x80000000 : no 'read' permission

    *** error 65: access violation at 0x80000001 : no 'read' permission

    *** error 65: access violation at 0x80000002 : no 'read' permission

    *** error 65: access violation at 0x80000003 : no 'read' permission

    Is there somewhere I need ot set up access permissions?

  • Well, the good new is that you are no longer accessing 0x00000000. But where is this message coming from -- IDE, simulator, some kind of target OS?

    http://www.keil.com/support/docs/814.htm

    Simulator/debugger perhaps...

  • That last one was my fault, I didnt have those address in my memory map.

    After adding the ranges for those addresses, it went through the code just fine.

    However, when I checked the address of b, it still came back with somethign in the 0x0000000 range. Am i misunderstanding this representation?

    I guess my problem is to find out how to create those adddress mappings automatically, so its that way everytime i download to the chip.

  • "That last one was my fault, I didnt have those address in my memory map."

    That is something that your development/debug environment is requiring.

    "However, when I checked the address of b, it still came back with somethign in the 0x0000000 range. Am i misunderstanding this representation?"

    Sure 'b' is an auto, so has an address on the stack. We're trying to read from absolute addresses 0x80000000, 0x81000000, 0x82000000, and 0x83000000, in as simple a way as possible, into 'b' (a bit bucket) merely for the purpose of causing the hardware to perform bus transactions so you can monitor chip selects.

    "I guess my problem is to find out how to create those adddress mappings automatically, so its that way everytime i download to the chip."

    Well, there's a bit too much IDE/debugger "automagic" stuff going on here. I don't know if wizards are supposed to be writing to your BCFGn registers or if you need to do it in code. What I was trying to get at was enough "stuff" peeled away to get to the root of what configuration allows what chip select to twiddle.

  • Right, I saw in the help file you have to declare all memory space you are trying to use, which makes a moderate amount of sense.

    That is something that your development/debug environment is requiring.

    Sure 'b' is an auto, so has an address on the stack. We're trying to read from absolute addresses 0x80000000, 0x81000000, 0x82000000, and 0x83000000, in as simple a way as possible, into 'b' (a bit bucket) merely for the purpose of causing the hardware to perform bus transactions so you can monitor chip selects.

    OK, I understand that now. Maybe a good test would be to write to those addresses and then try to read from them in the simulator.

    I think that I will give this arest for the day though. You have been more than help ful and I really appreciate it.

    More or less, I wanted to make sure there was no gotchas that I wasnt paying attention to in code or on the hardware that would prevent me from seeing things work. I think im going to have the hardware changed to work off CS3, so I can avoid any CS0 confusion.

    But to recap, all I really need to do, is define a variable at an address, write/read from it, and the chip select should take care of assert the proper signal.

    I think that is it, let me know if I am over simplifying :)

    Thanks again dan

    Doug

  • "But to recap, all I really need to do, is define a variable at an address, write/read from it, and the chip select should take care of assert the proper signal."

    If this new address range is for a memory device, say additional RAM, defining data objects to be allocated there is a good thing. Otherwise, if the new address range is for accessing some hardware registers or the like, defining data objects to be allocated there is, in my opinion, optional and casting an address to structure pointer, union pointer, integer pointer, or whatever and then dereferencing it is equally valid. Both techniques will assert the chip select assuming that the controller registers have been properly configured.

    An no, you are not oversimplifying. It is simple!

    Regards,

    --
    Dan Henry

  • Dan,

    When you say that creating data objects for external hardware registers is optional, how do you mean.

    How can I write to them or read from them, if I do not have them defined? I don't think I quite follow that line of reasoning?

    Thanks

    Doug

  • "When you say that creating data objects for external hardware registers is optional, how do you mean.

    How can I write to them or read from them, if I do not have them defined? I don't think I quite follow that line of reasoning?"


    I am making a distinction between using memory-allocating defining declarations for data objects (variables) and using the conventional direct access means for hardware registers.

    During program development you add code and data objects to your source code to implement your algorithms. You compile the code and link it to become an executable. For a simple system you supply base addresses where the linker should start allocating your code (.text), your data (.data, .bss), your stack, etc. and don't really care where the linker finally locates a particular data object -- just that you be able to access it. You let the linker allocate storage for your data objects and resolve their names to addresses.

    Hardware registers, on the other hand, are typically located at fixed addresses. No matter how you change your program, those hardware register addresses do not change. So it is quite conventional to not involve the linker and to use the kind of direct access means we've been talking about. For example, take a look at lpc22xx.h for your processor. Single registers have this form:

    /* External Memory Controller (EMC) */
    #define BCFG0          (*((volatile unsigned long *) 0xFFE00000))
    Here's a snippet from the Atmel header file for the ARM I am using to illustrate how registers are grouped by function into structures:
    typedef volatile unsigned int AT91_REG; // Hardware register definition
    
    // *****************************************************************************
    //      SOFTWARE API DEFINITION  FOR Memory Controller Interface
    // *****************************************************************************
    typedef struct _AT91S_MC {
    	AT91_REG	 MC_RCR; 	// MC Remap Control Register
    	AT91_REG	 MC_ASR; 	// MC Abort Status Register
    	AT91_REG	 MC_AASR; 	// MC Abort Address Status Register
    	AT91_REG	 Reserved0[1]; 	//
    	AT91_REG	 MC_PUIA[16]; 	// MC Protection Unit Area
    	AT91_REG	 MC_PUP; 	// MC Protection Unit Peripherals
    	AT91_REG	 MC_PUER; 	// MC Protection Unit Enable Register
    } AT91S_MC, *AT91PS_MC;
    
    // *****************************************************************************
    //      SOFTWARE API DEFINITION  FOR Real-Time Clock Alarm and
    //                                   Parallel Load Interface
    // *****************************************************************************
    typedef struct _AT91S_RTC {
    	AT91_REG	 RTC_CR; 	// Control Register
    	AT91_REG	 RTC_MR; 	// Mode Register
    	AT91_REG	 RTC_TIMR; 	// Time Register
    	AT91_REG	 RTC_CALR; 	// Calendar Register
    	AT91_REG	 RTC_TIMALR; 	// Time Alarm Register
    	AT91_REG	 RTC_CALALR; 	// Calendar Alarm Register
    	AT91_REG	 RTC_SR; 	// Status Register
    	AT91_REG	 RTC_SCCR; 	// Status Clear Command Register
    	AT91_REG	 RTC_IER; 	// Interrupt Enable Register
    	AT91_REG	 RTC_IDR; 	// Interrupt Disable Register
    	AT91_REG	 RTC_IMR; 	// Interrupt Mask Register
    	AT91_REG	 RTC_VER; 	// Valid Entry Register
    } AT91S_RTC, *AT91PS_RTC;
    
    #define AT91C_BASE_MC   ((AT91PS_MC) 	0xFFFFFF00) // (MC) Base Address
    #define AT91C_BASE_RTC  ((AT91PS_RTC) 	0xFFFFFE00) // (RTC) Base Address
    In both cases (your ARM and mine), memory-allocating defining declarations are not used and the linker would not be involved for hardware registers. Instead, macros are provided to directly access the registers. The same thing goes for new hardware you are having mapped into the 0x83000000 expansion area.

  • "The same thing goes for new hardware you are having mapped into the 0x83000000 expansion area."

    Unless, of course, that hardware is memory!