3

CPU: 8051 based

The following lines of code will set 0xaa value at 0x0aaa address in external flash memory.

mov     a,#0aah
mov     dptr,#X0aaa
movx    @dptr,a

The following is mov

The MOV instruction allows data to be transferred between any internal I-RAM spaces or SFR locations and between accumulator to internal I-RAM spaces or SFR locations.

and and movx instruction descriptions from CPU datasheet

MOVX instruction is used to access the internal X-RAM and e-FLASH area. Only indirect addressing can be used. The choice whether to use a one-byte address, @Ri, where Ri can be either R0 or R1 of the selected register bank, or a two-byte address, @DPTR.

CPU datasheet

Some code that I've seen in examples:

xdata UCHAR * data ecFlashaaa  = (xdata UCHAR *)(0xaaa); 
*ecFlashaaa  = 0xaa;

the code doesn't compile because it doesn't know what is xdata and also confused on data. So somehow I need to explain linker that ecFlashaaa is pointing to e-Flash...

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
Pablo
  • 28,133
  • 34
  • 125
  • 215
  • Do you have the correct compiler? Have you included the proper header files? – Shahbaz Feb 01 '14 at 13:07
  • Yes I do have. Example itself is faulty. There is an `XCL` file included in my project, which defines segments. `-D_XDATA_START=8000 // First address of xdata memory.`, `-D_XDATA_Z_START=_XDATA_START // First address of on chip XDATA memory.`, etc... but I'm not sure if e-Flash is defined there. Even if defined, how can I bind my variable to e-Flash. – Pablo Feb 01 '14 at 13:12
  • I really don't know the micro, so I don't know the details, but if the compiler doesn't understand `xdata` (while the keyword exists in the datasheet!), my best guess is either a wrong compiler or a missing header file. – Shahbaz Feb 01 '14 at 13:18

2 Answers2

3

Data and xdata are probably either compiler extensions or macros (defined in a header file) that qualify the data type.

Writing the code in C is pretty simple. But whether or not it generates the assembler you want is going to depend on how smart your compiler is. Does it know about the different kinds of memory in your system?

What you want to do is declare a pointer to a byte, and then set the value of the pointer (not what it points to) to the address you wish to access. Then you can dereference the pointer and set it to the value you want.

unsigned char *flashptr = (unsigned char *)0xaaa;
*flashptr = 0xaa;

Which is pretty much what you have in the example, without the extra data/xdata in there.

Chris J. Kiick
  • 1,487
  • 11
  • 14
1

The difference between your sample code:

xdata UCHAR * data ecFlashaaa  = (xdata UCHAR *)(0xaaa); 
*ecFlashaaa  = 0xaa;

And the accepted answer is that with xdata the compiler will generate code very similar to your assembly snipet. The literal value 0xaa will be written to location 0xaaa in external RAM (or, in your case, what appears to be a memory mapped EEPROM in the external RAM space) in a few instructions.

The accepted answer with a generic pointer declared unsigned char *flashptr will use a 3-byte type for flashptr where the upper byte will indicate which memory space the address is in. So instead of being declared as a pointer to xdata it is declared as a generic pointer and then assigned a value like {XDATA, 0x0AAA}. Access to generic pointers is by calling a library routine which uses the correct instruction (mov, movc, or movx) to access the memory.

The cost isn't too bad if you use a utility function (e.g. memcpy) which is smart enough to determine the memory type once and then use an optimized copy loop. If you write your own copy loop the performance will be significantly worse if you use a generic pointer unnecessarily.

(The sample code you found that I quoted was probably written for Keil's C51 compiler)

Ben Jackson
  • 90,079
  • 9
  • 98
  • 150