GPIO物理地址与虚拟地址的变换

本文详细解析了SC8810平台上的GPIO配置方法及其相关寄存器地址映射,包括GPIO的虚拟与物理地址转换、GPIO操作宏定义等内容。

./kernel/arch/arm/mach-sc8810/include/mach/regs_global.h
./u-boot/arch/arm/include/asm/arch-sc8810/regs_global.h 
./mach-sc8810/board-sp8810/gpio_cfg.c  gpio配置规划
kernel/arch/arm/mach-sc8810/include/mach/regs_gpio.h:
#define GPIO_BASE                            SPRD_GPIO_BASE
#define GPIO_PG_BASE                    GPIO_BASE
#define GPI_PG0_BASE                GPIO_BASE
kernel/arch/arm/mach-sc8810/include/mach/hardware.h:
#define SPRD_GPIO_BASE           0xE0031000

kernel/arch/arm/mach-sc8810/include/mach/adi_hal_internal.h  定义了GPIO的物理地址和虚拟地址之间的转换函数


#define ADI_PHYS    SPRD_MISC_PHYS//0x82000000
#define __adi_virt_to_phys(x) ((x) - SPRD_ADI_BASE + ADI_PHYS)
#define __adi_phy_to_virt(x) ((x)-ADI_PHYS + SPRD_ADI_BASE) // x-0x82000000+0xE0037000; 就是x+0x5E037000,也就是 虚拟地址到物理地址的偏移是 0x5E037000, 与 函数中的不符!!!

SC8810 Device Spec.pdf 的p102页 表5-1 SC8810重启之后的内存地址映射表 中 指明了 
0x80000000~0x8fffffff 为外设地址空间,其中0x82000480为GPIO(模拟控制功能段)的基地址(在0x820005ff结束); 0x8A000000为剩下的一段 GPIO的基地址。GPIO所有的基地址请参考:6.8.4节P507页内容


kernel/arch/arm/mach-sc8810/include/mach/regs_adi.h
./mach-sc8810/include/mach/hardware.h 中定义了硬件物理地址和虚拟地址的映射关系,及硬件地址相关的宏
特别重要的一个宏是 #define SPRD_MISC_BASE          0xE0037000,其他很多宏都是在这个宏的基础上进行偏移的。
/* GPIO */
#define SPRD_GPIO_BASE           0xE0031000 //虚拟地址
#define SPRD_GPIO_PHYS           0x8a000000 //物理地址
#define SPRD_GPIO_SIZE           SZ_4K

/* registers for watchdog ,RTC, touch panel, aux adc, analog die... */
#define SPRD_MISC_BASE          0xE0037000  //MISC类 模块的虚拟地址
#define SPRD_MISC_PHYS          0x82000000  //MISC类 模块的物理地址
#define SPRD_MISC_SIZE          SZ_4K    //那么物理地址到虚拟地址的偏移为:
                                        //0xE0037000-0x82000000 =0x5E037000
                                        //正好是 __adi_phy_to_virt 的转换偏移;


./mach-sc8810/include/mach/regs_adi.h: #define SPRD_ADI_BASE SPRD_MISC_BASE//0xE0037000
./mach-sc8810/include/mach/regs_adi.h: #define  ADI_BASE   SPRD_ADI_BASE  //0x82000000
./mach-sc8810/include/mach/regs_gpio.h: #define GPIO_BASE   SPRD_GPIO_BASE


./mach-sc8810/include/mach/board.h  
 定义了gpio的某些struct和一些全局变量( int sprd_3rdparty_gpio_tp_rst; int sprd_3rdparty_gpio_tp_irq; )

./mach-sc8810/include/mach/board.h :
 /* platform device data structures */
 struct sprd_platform_data
 {
  void (*panel_power)(int on);
  unsigned has_vsync_irq:1;
 };
 //这个是gpio_cfg.c文件中用到的结构,定义了一个gpio_initdata结构数组。
 struct gpio_initdata {
  int* gpio;
  int io;
 };


kernel/arch/arm/mach-sc8810/gpio.c  
 gpio各种操作函数的定义

mach-sc8810/include/mach/gpio.h
 //定义了一些GPIO相关的宏,比如gpio号的最大值、最小值

 #include <linux/init.h>

 #define GPIO_MIN_PIN_NUM  16
 #define GPIO_MAX_PIN_NUM      (205 + 16)
 //定义充电探测口
 #define CHARGER_DETECT_GPIO 162
 //定义USB的口
 #define USB_DM_GPIO 145
 #define USB_DP_GPIO 146

 #define ARCH_NR_GPIOS   GPIO_MAX_PIN_NUM// TODO: steve.zhan
 //特别注意:这里定义了 gpio_get_value等函数,linux内核也有这个函数的实现(貌似加入了BUG_ON的宏)。kernel/include/asm-generic/gpio.h
 #define gpio_get_value __gpio_get_value
 #define gpio_set_value __gpio_set_value
 #define gpio_to_irq  __gpio_to_irq

 定义各种操作的宏
 #define GPIO_DEFAUT_HIGH        (1 << 31)
 #define GPIO_DEFAUT_LOW         (0 << 31)
 #define GPIO_DIRECTION_OUTPUT   (1 << 30)
 #define GPIO_DIRECTION_INPUT        (1 << 29)
 #define GPIO_LOGIC_TRUE         (1<< 28)
 #define GPIO_LOGIC_FALSE            (0 << 28)


 #define GPIO_INDEX_MAX          (0xffff)

 extern __must_check int sprd_alloc_gpio_irq(unsigned gpio);
 extern int irq_to_gpio(unsigned long irq);
 extern void sprd_free_gpio_irq(int irq);
 #include <asm-generic/gpio.h>

 extern void __init sprd_gpio_init(void);

 

//-----------------

kernel/arch/arm/mach-sc8810/gpio_phy.h 中的 __get_base_addr 函数说明:

 #define NR_D_DIE_GPIOS 147

 static __inline u32 __get_base_addr (u32 gpio_id)
 {
  if (gpio_id > NR_D_DIE_GPIOS) //148~159保留
  {
   if (gpio_id < 176 + 16) //手册上 (176+16)号gpio之前的基地址都是0x80的step,
    return __adi_phy_to_virt(0x82000480);//GPIO(模拟控制)的基地址;另外还有小于这个区段的GPIO号的基地址是0x8A000000;
   return __adi_phy_to_virt(0x820004c0);//超过192号GPIO其基地址就是0x820004c0,中间没有步进0x80
  }

  return ((gpio_id>>4) -1) * 0x80 + (u32) GPIO_BASE;//<=147号的GPIO口的基地址//GPIO_BASE:0xE0031000;
 //可以假定,0x8a0000000 的虚拟地址是 0xE0031000, 
 //那么虚拟地址到物理地址的偏移是:0x56031000 ,
 //这个值与 __adi_phy_to_virt 这个宏转换机制不一样。难道这段GPIO是用的另外一个偏移来映射的?
 }

 


//********ldo-SIM相关的引脚寄存器地址*********\\


 --------reference-start:
 /*
     /* registers for watchdog ,RTC, touch panel, aux adc, analog die... */
 #define SPRD_MISC_BASE          0xE0037000 // 虚拟地址;
 #define SPRD_MISC_PHYS          0x82000000 // 物理地址;
 #define SPRD_MISC_SIZE          SZ_4K   //映射区域大小;
 */
 --reference-end--------;

 //Analog die register define            for 8810 fixed begin
 #define         SPRD_ANA_BASE   (SPRD_MISC_BASE + 0x600)
 #define   ANA_REG_BASE         SPRD_ANA_BASE   //  0x82000600

 #define   ANA_AGEN              (ANA_REG_BASE + 0x00)
 #define   ANA_MODULE_ARM_RST    (ANA_REG_BASE + 0x04)
 #define   ANA_LDO_PD_SET        (ANA_REG_BASE+ 0x08)
 #define   ANA_LDO_PD_RST        (ANA_REG_BASE + 0x0C)
 #define   ANA_LDO_PD_CTL0        (ANA_REG_BASE + 0x10)
 #define   ANA_LDO_PD_CTL1        (ANA_REG_BASE + 0x14) //(0xE0037000 +0x600)+0x14 = 0xE0037614(虚拟地址)
              //对应的物理地址是0x82000000 +0x600 + 0x14 
 #define   ANA_LDO_VCTL0         (ANA_REG_BASE + 0x18)
 #define   ANA_LDO_VCTL1         (ANA_REG_BASE + 0x1C)
 #define   ANA_LDO_VCTL2         (ANA_REG_BASE + 0x20)
 #define   ANA_LDO_VCTL3         (ANA_REG_BASE + 0x24)
 #define   ANA_LDO_VCTL4         (ANA_REG_BASE + 0x28)
 #define   ANA_LDO_SLP0           (ANA_REG_BASE + 0x2C)
 #define   ANA_LDO_SLP1           (ANA_REG_BASE + 0x30)
 #define   ANA_LDO_SLP2           (ANA_REG_BASE + 0x34)
 #define   ANA_DCDC_CTRL             (ANA_REG_BASE + 0x38)
 #define   ANA_DCDC_CTRL_DS           (ANA_REG_BASE + 0x3C)
 #define   ANA_DCDC_CTRL_CAL           (ANA_REG_BASE + 0x40)
 #define   ANA_DCDCARM_CTRL            (ANA_REG_BASE + 0x44)
 #define   ANA_DCDCARM_CTRL_CAL      (ANA_REG_BASE + 0x48)
 #define   ANA_PLL_CTRL         (ANA_REG_BASE + 0x4C)
 #define   ANA_APLLMN               (ANA_REG_BASE + 0x50)
 #define   ANA_APLLWAIT         (ANA_REG_BASE + 0x54)
 #define   ANA_RTC_CTRL         (ANA_REG_BASE + 0x58)
 #define   ANA_TRF_CTRL          (ANA_REG_BASE + 0x5C)
 #define   ANA_CHGR_CTRL0         (ANA_REG_BASE + 0X60)
 #define   ANA_CHGR_CTRL1          (ANA_REG_BASE + 0X64)
 #define   ANA_LED_CTRL          (ANA_REG_BASE + 0X68)
 #define   ANA_VIBRATOR_CTRL0          (ANA_REG_BASE + 0X6C)
 #define   ANA_VIBRATOR_CTRL1          (ANA_REG_BASE + 0X70)
 #define   ANA_AUDIO_CTRL          (ANA_REG_BASE + 0X74)
 #define   ANA_AUDIO_PA_CTRL0                   (ANA_REG_BASE + 0X78)
 #define   ANA_AUDIO_PA_CTRL1          (ANA_REG_BASE + 0X7C)
 #define   ANA_MIXED_CTRL          (ANA_REG_BASE + 0X80)
 #define   ANA_STATUS          (ANA_REG_BASE + 0X84)
 #define   ANA_RST_STATUS          (ANA_REG_BASE + 0X88)
 #define   ANA_MCU_WR_PROT          (ANA_REG_BASE + 0X8C)
 #define   ANA_VIBR_WR_PROT          (ANA_REG_BASE + 0X90)
 #define   ANA_INT_CPI_DEBUG          (ANA_REG_BASE + 0X94)
 #define   ANA_HWRST_RTC          (ANA_REG_BASE + 0X98)
 #define   ANA_IF_SPR_CTRL          (ANA_REG_BASE + 0X9C)
 #define   ANA_CHIP_ID_LOW          (ANA_REG_BASE + 0XF8)
 #define   ANA_CHIP_ID_HIGH          (ANA_REG_BASE + 0XFC)

 #define ANA_CHGR_CTL0 ANA_CHGR_CTRL0
 #define ANA_CHGR_CTL1 ANA_CHGR_CTRL1
 //fixed end

### STM32虚拟仪器功能实现方案 #### 1. 虚拟仪器的概念 虚拟仪器是一种基于计算机软件和硬件技术的测量控制系统,通过结合通用PC的强大计算能力和专用数据采集模块的功能来完成传统物理仪器的任务。STM32作为一款高性能微控制器,可以通过其丰富的外设资源(如ADC、DAC、UART、SPI、I2C等)以及强大的处理能力,配合特定的固件设计,实现虚拟仪器的核心功能。 --- #### 2. 使用STM32实现虚拟仪器的关键要素 为了实现虚拟仪器功能,需要考虑以下几个方面: - **信号采集** 利用STM32内置的高精度模数转换器(ADC),可以实时采样输入信号并将其数字化[^1]。例如,在音频分析仪中,可通过ADC获取声音波形的数据。 - **信号处理** 基于ARM Cortex-M内核的高效运算能力,可以在嵌入式环境中运行FFT算法或其他复杂的数字信号处理(DSP)算法,从而提取频率成分或滤除噪声。 - **数据显示传输** 可以利用LCD显示屏或者通过USB接口将处理后的结果发送到主机端进行显示。对于后者,可采用CDC类驱动程序构建虚拟串口连接;如果希望进一步扩展,则可以选择MSC模式保存实验记录至外部存储设备[^3]。 - **用户界面控制** 如果需要增加人机互动体验,还可以借助HID协议定义按键操作逻辑,允许使用者调整参数设置而无需重新烧录固件。 --- #### 3. 具体实施方案——以简易示波器为例 下面给出一种具体的实现思路,即制作一个简单的单通道数字示波器。 ##### (1) 硬件准备 - 主控芯片:选用具备较高工作频率和支持DMA功能的型号,比如`STM32F4xx`系列; - 输入缓冲电路:保护MCU免受过高电压损害的同时降低阻抗影响; - 显示单元:OLED屏幕或者其他图形化液晶面板; - 数据储存元件:Flash芯片用于暂存长时间观测序列。 ##### (2) 软件架构概述 整个项目的流程大致分为初始化阶段、循环检测状态变化部分以及中断服务子程序三大部分组成。 ###### 初始化配置 ```c // 配置系统时钟为最大值以便获得更快的速度 SystemClock_Config(); // 启动定时器触发机制同步AD转换过程 TIM_HandleTypeDef htim; HAL_TIM_Base_Init(&htim); // 设置好相应的GPIO引脚方向性和上下拉电阻属性 MX_GPIO_Init(); ``` ###### 循环主体结构 持续查询是否有新的事件发生,一旦发现立即响应执行对应的动作命令。 ```c while (1){ if(new_event_flag == SET){ Process_Event(); // 处理各类可能到来的消息请求 new_event_flag = RESET; } } ``` ###### 中断回调函数 每当一次完整的A/D变换结束之后就会自动跳转到这里面继续后续的工作流。 ```c void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc){ Save_Sample_Data(hadc->Instance); // 将当前读取得到的结果妥善保管起来备用 Update_Display_Buffer(); // 更新绘图区域的内容等待刷新呈现给最终观察者看 } ``` 以上仅为框架示意代码片段,实际开发过程中还需要补充更多的细节考量因素进去才行。 --- #### 4. 工具链推荐 考虑到兼容性和易用性问题,建议使用Keil MDK环境编写源码,并参照已有的开源项目模板加快进度。例如前面提到过的关于如何搭建带有PDF生成功能的虚拟磁盘实例就非常值得借鉴学习一番[^2]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值