嵌入式科普(32)指向寄存器的指针变量2---可变指针
一、概述
- 嵌入式科普(23)指向寄存器的指针变量1
,总结就是指向寄存器的指针要谨慎使用强制类型转换
-
寄存器数据是易变的,通常用可变指针去访问
-
可变指针有三种写法:
volatile int* p;
int* volatile p;
volatile int* volatile p;
二、参考资料
https://en.cppreference.com/w/c/language/volatile
https://en.cppreference.com/w/cpp/language/cv
https://en.cppreference.com/w/c/language/const
https://learn.microsoft.com/zh-cn/cpp/cpp/const-and-volatile-pointers?view=msvc-170
https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
https://zhuanlan.zhihu.com/p/423212827
三、通过int*偏移去访问寄存器
-
通常的外设驱动库:一组外设寄存器通常是结构体,外设的实例使用结构体指针访问寄存器
-
stm32 hal库uart:USART_TypeDef *Instance;
#define __IO volatile /*!< Defines 'read / write' permissions */
/**
* @brief Universal Synchronous Asynchronous Receiver Transmitter
*/
typedef struct
{
__IO uint32_t CR1; /*!< USART Control register 1, Address offset: 0x00 */
__IO uint32_t CR2; /*!< USART Control register 2, Address offset: 0x04 */
__IO uint32_t CR3; /*!< USART Control register 3, Address offset: 0x08 */
__IO uint32_t BRR; /*!< USART Baud rate register, Address offset: 0x0C */
__IO uint32_t GTPR; /*!< USART Guard time and prescaler register, Address offset: 0x10 */
__IO uint32_t RTOR; /*!< USART Receiver Time Out register, Address offset: 0x14 */
__IO uint32_t RQR; /*!< USART Request register, Address offset: 0x18 */
__IO uint32_t ISR; /*!< USART Interrupt and status register, Address offset: 0x1C */
__IO uint32_t ICR; /*!< USART Interrupt flag Clear register, Address offset: 0x20 */
__IO uint32_t RDR; /*!< USART Receive Data register, Address offset: 0x24 */
__IO uint32_t TDR; /*!< USART Transmit Data register, Address offset: 0x28 */
__IO uint32_t PRESC; /*!< USART Prescaler register, Address offset: 0x2C */
} USART_TypeDef;
/**
* @brief UART handle Structure definition
*/
typedef struct __UART_HandleTypeDef
{
USART_TypeDef *Instance; /*!< UART registers base address */
UART_InitTypeDef Init; /*!< UART communication parameters */
....
} UART_HandleTypeDef;
-
rzn2l通过int*偏移去访问定时器计数寄存器
volatile uint32_t * volatile gtp_ptr ;
volatile uint32_t * volatile ptr ;
uint32_t smStatus1 = 0;
uint32_t smStatus2 = 0;
uint32_t smStatus3 = 0;
uint32_t smStatus4 = 0;
/*******************************************************************************************************************//**
* main() is generated by the FSP Configuration editor and is used to generate threads if an RTOS is used. This function
* is called by main() when no RTOS is used.
**********************************************************************************************************************/
void hal_entry(void)
{
#if defined(BSP_MCU_GROUP_RZN2H)
#if (defined(BSP_CFG_CORE_CR52) && (0 == BSP_CFG_CORE_CR52))
/* Set "1" to CA550_CTRL. */
R_MPU_AC->CPU_CTRL |= 0x00000100;
#endif
#endif
/* TODO: add your own code here */
R_GPT_Open(&g_timer0_ctrl, &g_timer0_cfg);
R_GPT_Enable(&g_timer0_ctrl);
R_GPT_Start(&g_timer0_ctrl);
gtp_ptr = (uint32_t *)g_timer0_ctrl.p_reg;
ptr = gtp_ptr + 0x48/4;
while(1)
{
smStatus1 = ((uint32_t*)gtp_ptr)[0x48/4];
smStatus2 = gtp_ptr[0x12];
smStatus3 = *ptr;
smStatus4 = *(uint32_t*)(0x90002048);
}
}
#define HW_EscReadByte(ByteValue, Address) ((ByteValue) = (((UINT8 *) pEsc)[(Address)]))
-
直接使用指针访问地址
uint32_t smStatus4 = 0;
smStatus4 = *(uint32_t*)(0x90002048);
四、优化等级和编译器版本
-
-none同volatile
-
-o1甚至更高优化等级需加volatile
-
gcc12版本以上比10.3以下版本,对volatile指针优化有不同
五、总结
-
首先volatile修饰是为了告诉编译器
-
访问寄存器指针需注意易变属性
-
通过offset方式访问寄存器更要注意易变属性
volatile int* p; p指向的数据是易变的
int* volatile p; 变量p是易变的
volatile int* volatile p; 都是易变的
-
编译器版本优化有差异
-
volatile int* volatile p;货真价实
-
下一节总结volatile和const