指向 16 位控制器上寄存器的指针
Pointer to a register on a 16 bit controller
如何使用 IAR 的 EWB RL78 编译器在 16 位 Renesas RL78 微控制器上声明指向具有 20 位地址的寄存器的指针?
例如:
static int *ptr = (int *)0xF1000;
上面的方法不起作用,因为指针是 16 位地址。
如果有问题的寄存器是一个 on-chip 外围设备,那么您的工具链可能已经包含一个处理器 header 并声明了所有寄存器,在这种情况下您应该使用它。如果出于某种原因您不能或不想这样做,那么您至少可以看看它是如何声明此类寄存器的。
在任何情况下,您至少应该声明地址 volatile
,因为它不是常规内存位置,并且作为正常外围设备行为的一部分,可能会超出您的代码的控制和知识范围。此外,您应该使用明确大小的数据类型,并且该寄存器不太可能被签名。
#include <stdint.h>
...
static volatile uint16_t* ptr = (uint16_t*)0xF1000u ;
添加了以下目标架构说明:
IAR RL78 编译器支持两种数据模型 - near 和 far。来自 IAR 编译器手册:
● 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.
近模型是默认模型。可以使用编译器选项设置远模型:--data_model=far
;这将全局更改指针类型以允许 20 位寻址(在这种情况下指针长 3 个字节)。
即使没有全局指定数据模型,也可以通过使用关键字 __near
和 __far
显式指定指针类型来覆盖默认指针类型。所以在问题的例子中正确的声明是:
static volatile uint16_t __far* ptr = (uint16_t*)0xF1000u ;
请注意 __far
关键字的位置很重要。它的位置可以用来声明一个指针to far memory,或者一个指针in far memory(或者你甚至可以同时声明to和in far内存)。
在 RL78 上,0xF1000 实际上是指数据闪存的开始,而不是问题中所述的 register。通常,指向寄存器的指针不会受到更改(这意味着它指向不同的寄存器),因此可以合理地声明为 const:
static volatile uint16_t __far* const ptr = (uint16_t*)0xF1000u ;
与__far
类似,const
的位置对语义至关重要。以上防止 ptr
被修改,但允许修改 ptr
所指的内容。作为闪存,这可能并不总是可取或可能的,因此可以合理地将其声明为指向常量值的常量指针。
请注意,对于 RL78 特殊功能寄存器 (SFR),IAR 编译器有一个关键字 __sfr
专门用于寻址 0xFFF00-0xFFFFF 区域中的 寄存器 :
示例:
#pragma location=0xFFF20
__no_init volatile uint8_t __sfr PORT1; // PORT1 is located at address 0xFFF20
使用 IAR 特定编译器扩展的替代语法:
__no_init volatile uint8_t __sfr PORT1 @ 0xFFF20 ;
如何使用 IAR 的 EWB RL78 编译器在 16 位 Renesas RL78 微控制器上声明指向具有 20 位地址的寄存器的指针?
例如:
static int *ptr = (int *)0xF1000;
上面的方法不起作用,因为指针是 16 位地址。
如果有问题的寄存器是一个 on-chip 外围设备,那么您的工具链可能已经包含一个处理器 header 并声明了所有寄存器,在这种情况下您应该使用它。如果出于某种原因您不能或不想这样做,那么您至少可以看看它是如何声明此类寄存器的。
在任何情况下,您至少应该声明地址 volatile
,因为它不是常规内存位置,并且作为正常外围设备行为的一部分,可能会超出您的代码的控制和知识范围。此外,您应该使用明确大小的数据类型,并且该寄存器不太可能被签名。
#include <stdint.h>
...
static volatile uint16_t* ptr = (uint16_t*)0xF1000u ;
添加了以下目标架构说明:
IAR RL78 编译器支持两种数据模型 - near 和 far。来自 IAR 编译器手册:
● 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.
近模型是默认模型。可以使用编译器选项设置远模型:--data_model=far
;这将全局更改指针类型以允许 20 位寻址(在这种情况下指针长 3 个字节)。
即使没有全局指定数据模型,也可以通过使用关键字 __near
和 __far
显式指定指针类型来覆盖默认指针类型。所以在问题的例子中正确的声明是:
static volatile uint16_t __far* ptr = (uint16_t*)0xF1000u ;
请注意 __far
关键字的位置很重要。它的位置可以用来声明一个指针to far memory,或者一个指针in far memory(或者你甚至可以同时声明to和in far内存)。
在 RL78 上,0xF1000 实际上是指数据闪存的开始,而不是问题中所述的 register。通常,指向寄存器的指针不会受到更改(这意味着它指向不同的寄存器),因此可以合理地声明为 const:
static volatile uint16_t __far* const ptr = (uint16_t*)0xF1000u ;
与__far
类似,const
的位置对语义至关重要。以上防止 ptr
被修改,但允许修改 ptr
所指的内容。作为闪存,这可能并不总是可取或可能的,因此可以合理地将其声明为指向常量值的常量指针。
请注意,对于 RL78 特殊功能寄存器 (SFR),IAR 编译器有一个关键字 __sfr
专门用于寻址 0xFFF00-0xFFFFF 区域中的 寄存器 :
示例:
#pragma location=0xFFF20
__no_init volatile uint8_t __sfr PORT1; // PORT1 is located at address 0xFFF20
使用 IAR 特定编译器扩展的替代语法:
__no_init volatile uint8_t __sfr PORT1 @ 0xFFF20 ;