主题 : 请问为什么程序开启mmu后,不能循环执行,不能使led闪烁? 复制链接 | 浏览器收藏 | 打印
级别: 侠客
UID: 11182
精华: 0
发帖: 69
金钱: 350 两
威望: 70 点
综合积分: 138 分
注册时间: 2009-11-29
最后登录: 2011-11-27
楼主  发表于: 2010-01-19 15:41

 请问为什么程序开启mmu后,不能循环执行,不能使led闪烁?

请问有朋友做韦东山的《嵌入式linux应用开发完全手册》里的第7章mmu实验么?

为什么开启mmu后,led灯不能循环闪烁?而是就一直亮着或者灭着?

程序是没问题的,同样的程序在没开启mmu的情况下是可以循环闪烁的,请高手指点。

led闪烁程序如下
             while(1)
         {
          GPBCON =0X15400;        // 设置GPB5-6-7-8为输出口,LED1-2-3-4点亮
         
          GPBDAT = 0x00000000;    // GPB5-6-7-8输出0,LED1-2-3-4点亮
          delay(90000);
          GPBDAT = 0x7ff;         // GPB5-6-7-8输出1,LED1-2-3-4熄灭
          delay(90000);
          }        
         return 0;
}

同样的程序,在不开启mmu的时候,led等可以闪烁,但是开启mmu的情况下,led灯就一直灭着。也就是程序不能执行完第一次后再继续循环执行,好像执行一次就结束了,不再跳回去继续循环了。即在whlie(1)循环里,只执行到程序的最后一句,就不再回去循环了。

另外我在写驱动模块的时候,没有直接去操作物理地址,

我已经设置了va到pa的映射了。而且操作的时候,也是操作映射后的地址,

请高手指点怎么调整程序,让开启mmu的情况下led也可以循环执行。
感激不尽。
级别: 新手上路
UID: 11414
精华: 0
发帖: 15
金钱: 85 两
威望: 23 点
综合积分: 30 分
注册时间: 2009-12-07
最后登录: 2010-03-10
1楼  发表于: 2010-01-19 17:17
貌似还是地址的问题。
对于mmu,你都改了什么,贴一下。
级别: 侠客
UID: 11182
精华: 0
发帖: 69
金钱: 350 两
威望: 70 点
综合积分: 138 分
注册时间: 2009-11-29
最后登录: 2011-11-27
2楼  发表于: 2010-01-19 17:19

 回 1楼(zwinger) 的帖子

unsigned long virtuladdr, physicaladdr;
    unsigned long *mmu_tlb_base = (unsigned long *)0x30000000;
    
    /*
     * Steppingstone的起始物理地址为0,第一部分程序的起始运行地址也是0,
     * 为了在开启MMU后仍能运行第一部分的程序,
     * 将0~1M的虚拟地址映射到同样的物理地址
     */
    virtuladdr = 0;
    physicaladdr = 0;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                            MMU_SECDESC_WB;

    /*
     * 0x56000000是GPIO寄存器的起始物理地址,
     * GPBCON和GPBDAT这两个寄存器的物理地址0x56000010、0x56000014,
     * 为了在第二部分程序中能以地址0xA0000010、0xA0000014来操作GPBCON、GPBDAT,
     * 把从0xA0000000开始的1M虚拟地址空间映射到从0x56000000开始的1M物理地址空间
     */
    virtuladdr = 0xA0000000;
    physicaladdr = 0x56000000;
    *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                            MMU_SECDESC;

    /*
     * SDRAM的物理地址范围是0x30000000~0x33FFFFFF,
     * 将虚拟地址0xB0000000~0xB3FFFFFF映射到物理地址0x30000000~0x33FFFFFF上,
     * 总共64M,涉及64个段描述符
     */
    virtuladdr = 0xB0000000;
    physicaladdr = 0x30000000;
    while (virtuladdr < 0xB4000000)
    {
        *(mmu_tlb_base + (virtuladdr >> 20)) = (physicaladdr & 0xFFF00000) | \
                                                MMU_SECDESC_WB;
        virtuladdr += 0x100000;
        physicaladdr += 0x100000;
    }
}

/*
* 启动MMU
*/
void mmu_init(void)
{
    unsigned long ttb = 0x30000000;

__asm__(
    "mov    r0, #0\n"
    "mcr    p15, 0, r0, c7, c7, 0\n"    /* 使无效ICaches和DCaches */
    
    "mcr    p15, 0, r0, c7, c10, 4\n"   /* drain write buffer on v4 */
    "mcr    p15, 0, r0, c8, c7, 0\n"    /* 使无效指令、数据TLB */
    
    "mov    r4, %0\n"                   /* r4 = 页表基址 */
    "mcr    p15, 0, r4, c2, c0, 0\n"    /* 设置页表基址寄存器 */
    
    "mvn    r0, #0\n"                  
    "mcr    p15, 0, r0, c3, c0, 0\n"    /* 域访问控制寄存器设为0xFFFFFFFF,
                                         * 不进行权限检查
                                         */    
    /*
     * 对于控制寄存器,先读出其值,在这基础上修改感兴趣的位,
     * 然后再写入
     */
    "mrc    p15, 0, r0, c1, c0, 0\n"    /* 读出控制寄存器的值 */
    
    /* 控制寄存器的低16位含义为:.RVI ..RS B... .CAM
     * R : 表示换出Cache中的条目时使用的算法,
     *     0 = Random replacement;1 = Round robin replacement
     * V : 表示异常向量表所在的位置,
     *     0 = Low addresses = 0x00000000;1 = High addresses = 0xFFFF0000
     * I : 0 = 关闭ICaches;1 = 开启ICaches
     * R、S : 用来与页表中的描述符一起确定内存的访问权限
     * B : 0 = CPU为小字节序;1 = CPU为大字节序
     * C : 0 = 关闭DCaches;1 = 开启DCaches
     * A : 0 = 数据访问时不进行地址对齐检查;1 = 数据访问时进行地址对齐检查
     * M : 0 = 关闭MMU;1 = 开启MMU
     */
    
    /*  
     * 先清除不需要的位,往下若需要则重新设置它们    
     */
                                        /* .RVI ..RS B... .CAM */
    "bic    r0, r0, #0x3000\n"          /* ..11 .... .... .... 清除V、I位 */
    "bic    r0, r0, #0x0300\n"          /* .... ..11 .... .... 清除R、S位 */
    "bic    r0, r0, #0x0087\n"          /* .... .... 1... .111 清除B/C/A/M */

    /*
     * 设置需要的位
     */
    "orr    r0, r0, #0x0002\n"          /* .... .... .... ..1. 开启对齐检查 */
    "orr    r0, r0, #0x0004\n"          /* .... .... .... .1.. 开启DCaches */
    "orr    r0, r0, #0x1000\n"          /* ...1 .... .... .... 开启ICaches */
    "orr    r0, r0, #0x0001\n"          /* .... .... .... ...1 使能MMU */
    
    "mcr    p15, 0, r0, c1, c0, 0\n"    /* 将修改的值写入控制寄存器 */
    : /* 无输出 */
    : "r" (ttb) );
}


首先感谢您的关注,

这里是mmu的设置和初始化。唉,实在是搞不懂为什么。
级别: 新手上路
UID: 11414
精华: 0
发帖: 15
金钱: 85 两
威望: 23 点
综合积分: 30 分
注册时间: 2009-12-07
最后登录: 2010-03-10
3楼  发表于: 2010-01-22 15:12
不知道lz现在情况如何了。
没看出什么问题(我不是高手)。。。

建议:

步骤1/
启动mmu,但是GPIO部分地址转换就不要做了,也就是说设置mmu table的时候,将vir-addr设置成与phy-addr相同的值。
后续的所有设备操作,依旧使用物理地址操作。
这样的话,不需要对设备地址进行修改,也能在mmu使能的情况下运行。
如果这一步骤过不了,那就是别的问题了。

步骤2/
在上述修改的基础上,修改mmu table的GPIO影射部分(就像贴出来的那样)。
再修改对应的设备操作地址为vir-addr。
编译后运行看看结果怎么样。