smart3250中的静态I/O映射情况

根据网络大虾们的指导,基本上搞清楚了smart3250中的静态I/O映射情况。写个blog供以后参考。

****************************网络摘录**************************************

内核提供了在系统启动时通过map_desc结构体静态创建I/O资源到内核地址空间的线性映射表(即page table)的方式,这种映射表是一种一一映射的关系。程序员可以自己定义该I/O内存资源映射后的虚拟地址。创建好了静态映射表,在内核或驱动中访问该 I/O资源时则无需再进行ioreamp动态映射,可以直接通过映射后的I/O虚拟地址去访问它。

machine_desc结构体的成员包含了体系架构相关部分的几个最重要的初始化函数,包括map_io,init_irq, init_machine以及phys_io , timer成员等。这里的map_io成员即内核提供给用户的创建外设I/O资源到内核虚拟地址静态映射表的接口函数。Map_io成员函数会在系统初始化过程中被调用,流程如下:

Start_kernel -> setup_arch() --> paging_init() --> devicemaps_init()中被调用Machine_desc结构体通过MACHINE_START宏来初始化。

****************************网络摘录**************************************

在board-smartarm3250.c文件中的MACHINE_START

MACHINE_START (LPC3XXX, "SmartARM3250 board with the LPC3250 Microcontroller")

       /* Maintainer: Kevin Wells, NXP Semiconductors */

       .phys_io  = UART5_BASE,

       .io_pg_offst    = ((io_p2v (UART5_BASE))>>18) & 0xfffc,

       .boot_params  = 0x80000100,

       //.map_io        = lpc32xx_map_io,

       .map_io          = smartarm3250_map_io,

       .init_irq   = lpc32xx_init_irq,

       .timer             = &lpc32xx_timer,

       .init_machine  = smartarm3250_board_init,

MACHINE_END

 

map_io方法对应的函数

static void __init smartarm3250_map_io(void)

{

    lpc32xx_map_io();

    iotable_init(smartarm3250_io_desc, ARRAY_SIZE(smartarm3250_io_desc));

}

 

先追踪第一个函数

void __init lpc32xx_map_io(void)

{

       iotable_init (lpc32xx_io_desc, ARRAY_SIZE (lpc32xx_io_desc));

}

 

 

以下是lpc32xx_io_desc的定义:

static struct map_desc smartarm3250_io_desc[] __initdata = {

    {   /* nCS2, CAN SJA1000 */

        .virtual  = io_p2v(EMC_CS2_BASE),

        .pfn      = __phys_to_pfn(EMC_CS2_BASE),

        .length   = SZ_1M,

        .type     = MT_DEVICE

    },

    {   /* nCS1, CF Card */

        .virtual  = io_p2v(EMC_CS1_BASE),

        .pfn      = __phys_to_pfn(EMC_CS1_BASE),

        .length   = SZ_1M,

        .type     = MT_DEVICE

    }

 

};

 

现在追踪第二个函数

arch-lpc32xx.c文件中

smartarm3250_io_desc结构体的定义

static struct map_desc lpc32xx_io_desc[] __initdata = {

       {

              .virtual    = io_p2v(AHB0_START),

              .pfn        = __phys_to_pfn(AHB0_START),

              .length            = AHB0_SIZE,

              .type              = MT_DEVICE

       },

       {

              .virtual    = io_p2v(AHB1_START),

              .pfn        = __phys_to_pfn(AHB1_START),

              .length            = AHB1_SIZE,

              .type              = MT_DEVICE

       },

       {

              .virtual    = io_p2v(FABAPB_START),

              .pfn        = __phys_to_pfn(FABAPB_START),

              .length            = FABAPB_SIZE,

              .type              = MT_DEVICE

       },

       {

              .virtual    = io_p2v(IRAM_BASE),

              .pfn        = __phys_to_pfn(IRAM_BASE),

              .length            = (SZ_64K * 4),

              .type              = MT_DEVICE

       },

};

由上可知,smartarm3250开发板静态映射的物理地址有如下

基地址名称

实际物理地址

大小

范围

EMC_CS2_BASE

0xE2000000

SZ_1M(0x00100000)

0xE2000000-0xE2100000

EMC_CS1_BASE

0xE1000000

SZ_1M(0x00100000)

0xE1000000-0xE1100000

AHB0_START

0x20020000

AHB0_SIZE()

(MLC_BASE - SLC_BASE) + SZ_4K

(0x200A8000-0x20020000)+ 0x00001000

 

 

0x20020000-0x200A9000

AHB1_START

0x31000000

AHB1_SIZE()

(EMC_BASE - DMA_BASE) + SZ_4K

 

(0x31080000-0x31000000)+ 0x00001000

 

 

0x31000000-0x31081000

FABAPB_START

0x40004000

FABAPB_SIZE()

(I2C2_BASE - CLK_PM_BASE) + SZ_4K

 

(0x400A8000- 0x40004000)+ 0x00001000

 

 

 

0x40004000-0x400A9000

IRAM_BASE

0x08000000

SZ_64K * 4()

0x00040000

0x08000000-0x08040000

这些基地址的实际物理地址在include/mach/platform.h中可以找到

以上地址可以在驱动程序中直接调用如下两个函数:

__raw_readl(register_address);

__raw_writel(register_content,register_address);

这样在linux中控制单片机和用裸机程序控制单片机就没什么分别了。

以上地址中,还有未映射的地址部分。如果要在linux中用到,可以在驱动中的probe方法里,调用ioremap()函数,之后就能用了。

上面说介绍的物理地址都是经过io_p2v(x)映射的。

#define IO_BASE         0xF0000000

#define io_p2v(x) (IO_BASE | (((x) & 0xff000000) >> 4) | ((x) & 0x000fffff))

这个宏的意思是:

假设一个数,如0xABCDE123从前到后的16进制值顺序为12345678,即A对应1,B对应2,以此类推。

那么经过这个宏后变为:

AABDE123,即这个数的后5个数不会变,第一个数分裂为2个,去掉原来的第三个数。然后组合起来。

由上可知,如果想让映射后的地址与原来的物理地址一一对应,不产生冲突,所有被映射的地址的8位16进制数的第3个数应相同。lpc3250中,这个第3个数是0

====

http://blog.csdn.net/yongan1006/article/details/7094662

在 C++ ,如果你想要实现两个不同数据类型的相互转换,一般可以通过模板和静态成员函数、类型别名(typedef),或者是通过一些智能指针(smart pointers)如 `std::shared_ptr` 和 `std::unique_ptr` 来间接实现。这里我们看几个例子: 1. **模板函数**: 如果这两个数据类型有一定的关联,比如都是数值类型并且可以做算术运算,你可以编写一个通用的模板函数,接受这两种类型作为参数。 ```cpp template<typename T1, typename T2> T1 convertToOtherType(T2 value) { // 这里假设T1和T2都可以进行直接转换 return static_cast<T1>(value); } ``` 2. **类型别名**: 如果数据类型是已知的,可以直接为它们创建类型别名。 ```cpp typedef int TypeA; typedef double TypeB; // 现在TypeA和TypeB可以互相赋值 TypeA myValue = 10.5; // 将double转换为int TypeB anotherValue = myValue; // 将int转换回double ``` 3. **智能指针**: 当涉及到引用计数的对象时,如 `std::shared_ptr`,可以在一个共享所有权的基础上将一种类型的指针转换成另一种。 ```cpp #include <memory> class A {}; class B {}; // 创建一个A的智能指针 std::shared_ptr<A> aPtr(new A); // 如果A有一个成员变量B,可以转换成B的智能指针 if (auto bMember = dynamic_cast<B*>(&*aPtr)) { // 如果B存在则转换 std::shared_ptr<B> bShared(bMember); // 使用bMember的指针创建B的共享指针 } ``` 4. **包装类**: 如果需要更复杂的一对一映射,你可以创建一对包装类,每个类都有从另一个类型转换到自身的构造函数。 ```cpp class DataWrapperA { public: explicit DataWrapperA(double d) : data(d) {} operator double() const { return data; } private: double data; }; DataWrapperA wrapMyDouble(double d) { return DataWrapperA(d); } // 现在可以将double转换为DataWrapperA,反之亦然 ``` 总之,选择哪种方法取决于你具体的需求和数据类型的特点。记住,安全总是第一位的,所以在转换时要考虑边界条件和潜在的异常情况
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值