Keil Logo

C51: How to Directly Address Multiple Consecutive SFRS


Information in this article applies to:

  • C51 any Version
  • CX51 any Version
  • C251 any Version

QUESTION

Can I use structures to access data in the direct area of my 8051? I would also like to address several byte wide SFRs as one data element. I wrote the following code:

typedef union {
  char bits8;
  int bits16;
  long bits32;
} PAGE_TYPE;

PAGE_TYPE data* PageData = 0xBC;

But this generates an indirect read through a register.

Is there a more optimal solution to this problem?

ANSWER

It is not possible to locate variables of any kind, except sfrs, in the SFR memory area.

When you located the union at BCH and obtained indirect addressing, you were actually accessing the portion of idata that resides between 80H and FFH. This overlays the SFR area, which also resides between 80H and FFH. In fact, when you locate any variable between 80H and FFH, it is located in idata, not the SFR area.

However there are two ways to solve this problem

1. Solution directly in the C Language

One solution is to declare each SFR with a separate name and perform shifting operations. For example:

sfr EDATA1 = 0xBC;
sfr EDATA2 = 0xBD;
sfr EDATA3 = 0xBE;
sfr EDATA4 = 0xBF;

#define READ16 ((EDATA1 << 8 ) | (EDATA2))
#define READ32 ((EDATA1 << 24 ) | (EDATA2 << 16 ) | (EDATA3 << 8 ) | (EDATA4))

Another more optimal solution uses type casting:

sfr EDATA1 = 0xBC;
sfr EDATA2 = 0xBD;
sfr EDATA3 = 0xBE;
sfr EDATA4 = 0xBF;

void main (void)  {
  unsigned long lval;

  EDATA1 = ((unsigned char *) &lval) [0];
  EDATA2 = ((unsigned char *) &lval) [1];
  EDATA3 = ((unsigned char *) &lval) [2];
  EDATA4 = ((unsigned char *) &lval) [3];
}

The code generated for this solution appears as follows:

0000 8500BC R MOV EDATA1,asdf
0003 8500BD R MOV EDATA2,asdf+01H
0006 8500BE R MOV EDATA3,asdf+02H
0009 8500BF R MOV EDATA4,asdf+03H
000C 22 RET

2. Solution via Assembler define

In assembly language you may define the address of the SFR as a PUBLIC symbol. For example:

--- SRFSYM.A51 ---
PUBLIC ADRES
   EDATA_SFR  DATA  0xBC
END

Now you may access the SFR as a long value in the C source code by using an extern variable definition:

extern unsigned long data EDATA_SFR;

unsigned long v;

void test (void)  {
  v = EDATA_SFR;
  EDATA_SFR = 123456;
}

MORE INFORMATION

SEE ALSO


Last Reviewed: Thursday, February 25, 2021


Did this article provide the answer you needed?
 
Yes
No
Not Sure
 
  Arm logo
Important information

This site uses cookies to store information on your computer. By continuing to use our site, you consent to our cookies.

Change Settings

Privacy Policy Update

Arm’s Privacy Policy has been updated. By continuing to use our site, you consent to Arm’s Privacy Policy. Please review our Privacy Policy to learn more about our collection, use and transfers
of your data.