Pointer to a register on a 16 bit controller

810 Views Asked by At

How do you declare a pointer on a 16 bit Renesas RL78 microcontroller using IAR's EWB RL78 compiler to a register which has a 20 bit address?

Ex:

static int *ptr = (int *)0xF1000;

The above does not work because pointers are 16 bit addresses.

1

There are 1 best solutions below

10
On BEST ANSWER

If the register in question is an on-chip peripheral, then it is likely that your toolchain already includes a processor header with all registers declared, in which case you should use that. If for some reason you cannot or do not wish to do that, then you could at least look at that to see how it declares such registers.

In any event you should at least declare the address volatile since it is not a regular memory location and may change beyond the control and knowledge of your code as part of the normal peripheral behaviour. Moreover you should use explicit sized data types and it is unlikely that this register is signed.

#include <stdint.h>

...

static volatile uint16_t* ptr = (uint16_t*)0xF1000u ;

Added following clarification of target architecture:

The IAR RL78 compiler supports two data models - near and far. From the IAR compiler manual:

● The Near data model can access data in the highest 64 Kbytes of data memory

● The Far data model can address data in the entire 1 Mbytes of data memory.

The near model is the default. The far model may be set using the compiler option: --data_model=far; this will globally change the pointer type to allow 20 bit addressing (pointers are 3 bytes long in this case).

Even without specifying the data model globally it is possible to override the default pointer type by explicitly specifying the pointer type using the keywords __near and __far. So in the example in the question the correct declaration would be:

static volatile uint16_t __far* ptr = (uint16_t*)0xF1000u ;

Note the position of the __far keyword is critical. Its position can be used to declare a pointer to far memory, or a pointer in far memory (or you can even declare both to and in far memory).

On an RL78, 0xF1000 in fact refers to the start of data flash rather then a register as stated in the question. Typically a pointer to a register would not be subject to alteration (which would mean it referred to a different register), so might reasonably be declared const:

static volatile uint16_t __far* const ptr = (uint16_t*)0xF1000u ;

Similarly to __far the position of const is critical to the semantics. The above prevents ptr from being modified but allows what ptr refers to to be modified. Being flash memory, this may not always be desirable or possible, so it is possible that it could reasonably be declared a const pointer to a const value.

Note that for RL78 Special Function Registers (SFR) the IAR compiler has a keyword __sfr specifically for addressing registers in the area 0xFFF00-0xFFFFF:

Example:

#pragma location=0xFFF20
__no_init volatile uint8_t __sfr PORT1;  // PORT1 is located at address 0xFFF20

Alternative syntax using IAR specfic compiler extension:

__no_init volatile uint8_t __sfr PORT1 @ 0xFFF20 ;