在实验室研究了一段时间的裸板程序,放假回家了本来还想继续玩下去的,结果USB转串口线出问题了,不能在我的笔记本上玩裸板,只好先看看U-boot移植。
我的虚拟机环境是RedHat 5,昨天晚上尝试解压U-boot源码包的时候报如下错误:
tar: uboot1.1.6/include/asm-arm/arch: Cannot create symlink to `arch-s3c64xx': Operation not supported
tar: uboot1.1.6/include/asm-arm/proc: Cannot create symlink to `proc-armv': Operation not supported
tar: uboot1.1.6/include/regs.h: Cannot create symlink to `s3c6410.h': Operation not supported
tar: uboot1.1.6/include/asm: Cannot create symlink to `asm-arm': Operation not supported
tar: uboot1.1.6/tools/crc32.c: Cannot create symlink to `../lib_generic/crc32.c': Operation not supported
tar: uboot1.1.6/tools/environment.c: Cannot create symlink to `../common/environment.c': Operation not supported
tar: Exiting with failure status due to previous errors
我刚开始以为是权限问题,也不对啊,我用的是root。后来上网查过资料,原来解压U-boot源码包不能在共享文件夹下进行。因为宿主机的文件系统和虚拟机上的Linux文件系统不同,是不能创建上述的一些链接文件。
把源码包拷贝到Linux文件系统上一个地方,解压就解决问题了。
//总得来说三个主要步骤 //(1)映射虚拟内存,注册中断等 //(2)填充结构体struct imx_i2c_struct //(3)调用i2c_register_adapter注册I2C设备 static int __init i2c_imx_probe(struct platform_device *pdev) { //分析了几个驱动发现,平台驱动有很多相似的地方,比如说在prode里一般都会定义 //一个platform_data结构体,一个对应设备的结构体比如struct imx_i2c_struct struct imx_i2c_struct *i2c_imx; struct resource *res; struct imxi2c_platform_data *pdata; //__iomem表示指针是指向一个I/O的内存空间 void __iomem *base; //resource_size_t = u32 resource_size_t res_size; int irq; int ret; dev_dbg(&pdev->dev, "<%s>\n", __func__); //获取IO资源和中断资源 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) { dev_err(&pdev->dev, "can't get device resources\n"); return -ENOENT; } //获取中断资源 irq = platform_get_irq(pdev, 0); if (irq < 0) { dev_err(&pdev->dev, "can't get irq number\n"); return -ENOENT; } pdata = pdev->dev.platform_data; if (pdata && pdata->init) { ret = pdata->init(&pdev->dev); if (ret) return ret; } res_size = resource_size(res); //检测该IO资源是否可用,若可用,并标志为已用 if (!request_mem_region(res->start, res_size, DRIVER_NAME)) { ret = -EBUSY; goto fail0; } //映射物理地址到虚拟内存 base = ioremap(res->start, res_size); if (!base) { dev_err(&pdev->dev, "ioremap failed\n"); ret = -EIO; goto fail1; } //给i2c_imx分配内存,并初始化为0 i2c_imx = kzalloc(sizeof(struct imx_i2c_struct), GFP_KERNEL); if (!i2c_imx) { dev_err(&pdev->dev, "can't allocate interface\n"); ret = -ENOMEM; goto fail2; } //填充结构体i2c_imx strcpy(i2c_imx->adapter.name, pdev->name); //i2c_adapter,Linux的I2C驱动框架中的主要数据结构(i2c_driver、i2c_client、i2c_adapter和i2c_algorithm)之一出现了 //对应于物理上的一个适配器 i2c_imx->adapter.owner = THIS_MODULE; //i2c_algorithm也出现了 //i2c_algorithm主要提供通信的函数 i2c_imx->adapter.algo = &i2c_imx_algo; i2c_imx->adapter.dev.parent = &pdev->dev; i2c_imx->adapter.nr = pdev->id; i2c_imx->irq = irq; i2c_imx->base = base; i2c_imx->res = res; /* Get I2C clock */ //开启I2C时钟源 i2c_imx->clk = clk_get(&pdev->dev, "i2c_clk"); if (IS_ERR(i2c_imx->clk)) { ret = PTR_ERR(i2c_imx->clk); dev_err(&pdev->dev, "can't get I2C clock\n"); goto fail3; } /* Request IRQ */ //注册中断函数i2c_imx_isr ret = request_irq(i2c_imx->irq, i2c_imx_isr, 0, pdev->name, i2c_imx); if (ret) { dev_err(&pdev->dev, "can't claim irq %d\n", i2c_imx->irq); goto fail4; } /* Init queue */ //初始化queue init_waitqueue_head(&i2c_imx->queue); /* Set up adapter data */ //把I2C_imx保存到adapter中,最终可以调用i2c_get_adapdata获取 i2c_set_adapdata(&i2c_imx->adapter, i2c_imx); /* Set up clock divider */ //这个pdata->bitrate在板级配置文件中设置 if (pdata && pdata->bitrate) i2c_imx_set_clk(i2c_imx, pdata->bitrate); else i2c_imx_set_clk(i2c_imx, IMX_I2C_BIT_RATE); /* Set up chip registers to defaults */ writeb(0, i2c_imx->base + IMX_I2C_I2CR); writeb(0, i2c_imx->base + IMX_I2C_I2SR); /* Add I2C adapter */ //重要的函数来了, //i2c_add_numbered_adapter最终调用i2c_register_adapter添加I2C控制器 ret = i2c_add_numbered_adapter(&i2c_imx->adapter); if (ret < 0) { dev_err(&pdev->dev, "registration failed\n"); goto fail5; } /* Set up platform driver data */ platform_set_drvdata(pdev, i2c_imx); //打印调试信息 dev_dbg(&i2c_imx->adapter.dev, "claimed irq %d\n", i2c_imx->irq); dev_dbg(&i2c_imx->adapter.dev, "device resources from 0x%x to 0x%x\n", i2c_imx->res->start, i2c_imx->res->end); dev_dbg(&i2c_imx->adapter.dev, "allocated %d bytes at 0x%x \n", res_size, i2c_imx->res->start); dev_dbg(&i2c_imx->adapter.dev, "adapter name: \"%s\"\n", i2c_imx->adapter.name); dev_dbg(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n"); return 0; /* Return OK */ fail5: free_irq(i2c_imx->irq, i2c_imx); fail4: clk_put(i2c_imx->clk); fail3: kfree(i2c_imx); fail2: iounmap(base); fail1: release_mem_region(res->start, resource_size(res)); fail0: if (pdata && pdata->exit) pdata->exit(&pdev->dev); return ret; /* Return error number */ }
从爸爸公司拿了一条好的USB转串口线回来,我的OK6410终于可以和我的笔记本连接上了,secureCRT显示和接收按键都没有问题,感谢爸爸!
如果secureCRT能显示U-boot启动信息,但是就是不能接收按键,那么可以先看看有没有设置流控制,如果设置了,那么都流控制设置成无,也就是什么都不选。如果还是不行...那么
1.换个终端试试,例如DNW、minicom、超级终端...
2.换台地电脑试试,网上有人说重装系统,真的是大动干戈...
如果以上都试过了,还是不行,就是你的USB转串口坏掉了,赶紧换一条吧。
USB转串口好了,接下来又可以玩裸板了,按照韦东山老师的教学视频,知道怎么玩系统时钟了,分享一下。
我们的OK6410开发板上的晶振频率是12Mhz
外部晶振提供的12Mhz给S3C6410中的APLL,设置一定的参数可提高系统时钟,可以让CPU跑得更快
在S3C6410的芯片手册上,系统控制-》时钟架构
MUX多路选择器 0:可以原原本本输入12MHz,1:是经过APLL提升的时钟频率
上图的ARMCLK就是CPU时钟
设置APLL
如果我们要设置CPU时钟频率为532MHz,我们可以使用芯片手册上提供给我们的FOUT公司进行进行计算
FOUT = MDIV * FIN / (PDIV * 2^SDIV) = 532MHz
FIN就是晶振频率12Mhz,其余的参数要自己设定
DIV分频器
ARMCLK = DOUTAPLL / (ARM_RADIO + 1)
设置LOCK_TIME
设置APLL_LOCK_TIME
ARM时钟频率提高需要一定时间,所要要设置APPL_LOCK_TIME,当中CPU不工作
APLL给ARM CPU使用
MPLL给主设备、HCLK(内存,DDR),PCLK(外设片上模块)
EPLL给其它模块
OTHERS寄存器设置为异步模式
读入OTHERS内存的值,并bic清0xc0
当各种时钟使用不同的频率,所以要设置成异步
循环判断,等待设置完成
其实也不用清零的,因为从芯片手册删可以看出,复位的时候就是零
然后等待异步模式设置完成,那就要等待bit8~bit11为0即可,至于为什么,S3C6410的手册介绍的还不是很清楚...
DOUT为分频
设置CLK_DVIO
设置ARM_RATIO 0 主核分频为1分频
设置HCLCKX2_RATIO 1 将输入的时钟进行2分频
设置HCLK_RATIO 1 再将输入的时钟2分频,能供内存使用
设置PCLK_RATIO 3 其他RATIO的设置
设置好了,才启动ARLL,然后再设置MUX切换时钟
设置APLL,先配置APLL_CON寄存器,公式为MDIV * Fin / (PDIV * 2^SDIV) = 266 * 12 / (3 * 2^1) = 532
最高位为使能端(1 << 31)
MDIV (266 << 16)
PDIV (3 << 8)
SDIV 1
设置MPLL,同APLL设置
设置MUX切换时钟,设置CLOCK_SRC
MPLL_SET[1] 0:FINMAPLL,1:FOUTMPLL
APLL_SET[0] 0:FINMAPLL,1:FOUTMPLL
先设置参数,再使能,再切换
以下是芯片手册的寄存器地址和相关值的位
下面贴出代码clock.c的代码:
在汇编启动代码中,在跳转到main函数之前,加上一下一句,即可设置时钟
bl clock_init
main函数,我就按照韦东山老师的视频教学上说的,写流水灯代码,可以看到如果延时不够,则流水灯跑得非常快。
在编写这个程序的Makefile就OK了,啊...写得有点累了