?? c518.txt
字號:
發(fā)信人: reflection (似水流年), 信區(qū): EEtechnology
標(biāo) 題: C51 Primer (7) Accessing External Memory mapped
發(fā)信站: 南京大學(xué)小百合站 (Wed Nov 24 12:00:35 1999), 轉(zhuǎn)信
7 Accessing External Memory Mapped
Peripherals
Commonly, extra IO ports are added to 8051s to compensate for the loss of Po
rts 0 and 2. This is normally done by making the additional device(s) appear
to be just external RAM bytes. Thus they are addressed by the MOVX A,@DPTR
instruction. Typically UARTS, additional ports and real time clock devices a
re added to 8031s as xdata-mapped devices.
The simplest approach to adding external devices is to attach the /RD and or
/WR lines to the device. Provided that only one device is present and that
it only has one register, no address decoding is necessary. To access this d
evice from C simply prefix an appropriately named variable with "xdata". Thi
s will cause the compiler to use MOVX A,@DTPR instructions when getting data
in or out. In actual fact the linker will try to allocate a real address to
this but, as no decoding is present, the device will simply be enabled by /
WR or /RD.
In practice life is rarely this simple. Usually a mixture of RAM, UARTS, por
ts, EEPROM and other devices may all be attached to the 8031 by being mapped
into the xdata space. Some sort of decoding is provided by discrete logic o
r (more usually) a PAL.
Here the various registers of the different devices will appear at fixed loc
ations in the xdata space. With normal on-chip resources the simple "data bo
ok" name can be used to access them, so ideally these external devices shoul
d be the same.
There are three basic approaches to this:
Use normal variables, char, ints etc, located by the linker
Use pointers and offsets, either via the XBYTE macros or directly with user-
defined pointers.
Use the _At_ and _ORDER directives.
In detail, these may be implemented as shown in the following sections.
7.1 The XBYTE And XWORD Macros
To allow memory-mapped devices to be accessed from C, a method is required t
o effectively force pointers to point to fixed addresses. C51 provides many
methods of achieving this, the simplest of which are the XBYTE[addr16] and X
WORD[addr16] macros
For instance:
The byte wide PORT8_DDI register of a memory mapped IO device is at 8000H. T
o access it from C it must be declared thus:
#include "absacc.h"; /*Contains macro definitions */
#define port8_ddi XBYTE[0x8000]
#define port8_data XBYTE[0x8001]
To use it then,
port8_ddi = 0xFF ;
input_val = port8_data ;
To access a word at an even external address:
#define word_reg XWORD[0x4000]
/* gives a word variable at 8000H */
Ignoring the pre-defined XWORD macro, the equivalent C line is:
#define word_reg_ptr ((unsigned int *) 0x24000L)
/*creates a pointer to a word (int) at address 8000H*/
To use this address then,
*word_reg_ptr = 0xFFFF ;
Note that the address 8000H corresponds to 4000H words, hence the " 0x24000L
".
Here are some examples with the code produced:
#define XBYTE ((unsigned char volatile *) 0x20000L)
#define XWORD ((unsigned int volatile *) 0x20000L)
main() {
char x ;
int y ;
x = XBYTE[0x8000] ;
0000 908000 MOV DPTR,#08000H
0003 E0 MOVX A,@DPTR
0004 FF MOV R7,A
0005 8F00 R MOV x,R7
y = XWORD[0x8000/sizeof(int)] ;
}
0007 908000 MOV DPTR,#08000H
000A E0 MOVX A,@DPTR
000B FE MOV R6,A
000C A3 INC DPTR
000D E0 MOVX A,@DPTR
000E FF MOV R7,A
000F 8E00 R MOV y,R6
0011 8F00 R MOV y+01H,R7
}
0013 ?C0001:
0013 22 RET
However the address indicated by "word_reg" is fixed and can only be defined
at compile time, as the contents of the square brackets may only be a const
ant. Any alteration to the indicated address is not possible with these macr
o-based methods. This approach is therefore best suited to addressing locati
ons that are fixed in hardware and unlikely to change at run time.
Note the use of the volatile storage class modifier. This is essential to pr
event the optimiser removing data reads from external ports.
See section 7.4 for more details.
Note: the header file "absacc.h" must be included at the top of the source f
ile as shown above. This contains the prototype for the XBYTE macro. (see pa
ge 9-15 in the C51 manual)
7.2 Initialised XDATA Pointers
In many cases the external address to be pointed at is known at compile time
but may need to be altered at some point during execution. Thus some method
of making a pointer point at an intial specific external address is require
d.
Probably the simplest way of setting up such a pointer is to let the C_INIT
program set the pointer to a location. However the initial address must be k
nown at compile time. If the pointer is to be altered at run time, just equa
te it (without the "*" at run time) to the new address.
Note: this automatic initialisation was not supported on earlier versions of
C51.
Simply do:
/* Spaced pointer */
xdata char xdata *a_ptr = 0x8000 ;
/* Generic Pointer */
xdata char *a_ptr = 0x028000L ;
Here the pointer is setup to point at xdata address 0x8000. Note that the sp
aced *a_ptr can only point at xdata locations as a result of the second xdat
a used in its declaration. In the generic *a_ptr case, the "02" tells C51 th
at an xdata address is intended.
An example might be:
6 xdata char xdata *ptr = 0x8000 ;
7
8
9 main() {
11 1 char x ;
13 1 ptr += 0xf0 ;
0000 900000 R MOV DPTR,#ptr+01H
0003 E0 MOVX A,@DPTR
0004 24F0 ADD A,#0F0H
0006 F0 MOVX @DPTR,A
0007 900000 R MOV DPTR,#ptr
000A E0 MOVX A,@DPTR
000B 3400 ADDC A,#00H
000D F0 MOVX @DPTR,A
15 1 x = *ptr ;
16 1
17 1 }
000E E0 MOVX A,@DPTR
000F FE MOV R6,A
0010 A3 INC DPTR
0011 E0 MOVX A,@DPTR
0012 F582 MOV DPL,A
0014 8E83 MOV DPH,R6
0016 E0 MOVX A,@DPTR
0017 F500 R MOV x,A
17 1 }
0019 22 RET
7.3 Run Time xdata Pointers
The situation often occurs that you need to point at addresses in the xdata
space which are only known at run time. Here the xdata pointer is setup in t
he executable code.
The best way to achieve this is to declare an "uncommitted" pointer at compi
le time and to then equate it to an address when running:
char xdata *xdata_ptr ; /* Uncommitted pointer */
/* to xdata memory */
main() {
xdata_ptr=(char xdata*) 0x8000 ; /*Point at 0x8000 in */
/*xdata */
}
An alternative is to declare a pointer to the xdata space and simply equate
it to a variable.
Here is an example:
char xdata *ptr ; /* This is a spaced pointer!!! */
main(){
start_address = 0x8000 ; /*Variable containing address*/
/*to be pointed to */
0000 750080 R MOV start_address,#080H
0003 750000 R MOV start_address+01H,#00H
ptr = start_address ;
000C AE00 R MOV R6,start_address
000E AF00 R MOV R7,start_address+01H
0010 8E00 R MOV ptr,R6
0012 8F00 R MOV ptr+01H,R7
0014 ?C0001:
while(1) {
x = *ptr++ ;
0014 0500 R INC ptr+01H
0016 E500 R MOV A,ptr+01H
0018 AE00 R MOV R6,ptr
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -