AM335x学习记录

更新时间:2023-11-07 21:17:01 阅读量: 教育文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

AM335x 学习笔记

1 硬件及其开发环境篇

1.1 开发环境的搭建

1.1.1 路由器方式的NFS启动

1) 通过路由器的方式来启动NFS文件系统

设置路由器局域网的网关:192.168.1.1,然后将开发板和PC都连接在路由器的LAN端口,并且采用DCHP的方式来实现tftp和nfs。 2) uEnv.txt

serverip=192.168.1.27

rootpath=/opt/ti-sdk-am335x-evm/targetNFS bootfile=uImage-am335x-evm.bin ip_method=dhcp

tftp_nfs_boot=echo Booting from network...; dhcp ${loadaddr} ${bootfile}; run net_args; bootm ${loadaddr} uenvcmd=run tftp_nfs_boot

1.1.2 Root用户登陆

#sudo passwd root #****** #******

#sudo –s –H 切换到root用户

然后就可以重启虚拟机,以用户root来登陆

1.1.3 中文字库问题

#locale –a 查看

是否有zh_CN,zh_CN.gb18030,zh_CN.gb2312等 #vim /var/lib/locales/supported.d/local

#dpkg-reconfigure locales

#locale-gen zh_CN.GB18030 #locale-gen zh_CN.GB2312 #locale-gen zh_CN.GBK

1.1.4 环境变量设置路径

#vim /etc/envinoment

常用的3个永久设置路径 ? #vim /etc/envirnoment ? #vim /etc/profile

? #vim ~/.bashrc (/root/.bashrc)

1.1.5 设置ubuntu的上网ip

设置为 bridge连接方式,设定静态IP地址.

1.1.6 更改sh工具

#rm /bin/sh

# ln –s /bin/bash /bin/sh #apt-get install fakeroot

1.1.7 安装必须的工具

#apt-get install vim

#apt-get install build-essential #apt-get install libtool

#apt-get install bsion(干什么用的还不清楚)

GNU autotools主要包括三个工具 autoconf, automake,libtool

1.1.8 虚拟机开发工具的安装

$ sudo apt-get install build-essential libncurses-dev flex bison autoconf automake libmpfr-dev texinfo nfs-kernel-server tftpd-hpa libcloog-ppl

1.2 AM335x BeagleBone 的NFS启动

Sd卡的识别:在/media/下面显示内容 在/dev/sd* 下显示分区 卸载:#unmount /dev/sdb1

这个是在AM335X-LINUX-PSP-04.06.00.03里面找的 1) 制作sd启动盘 MLO+uboot.img+uImage+rootfs

#!/bin/bash

if [[ -z $1 || -z $2 || -z $3 || -z $4 ]] then fi

if ! [[ -e $2 ]] then fi

if ! [[ -e $3 ]] then fi

if ! [[ -e $4 ]] then fi

if ! [[ -e $5 ]] then fi

echo \read ans

if ! [ $ans == 'y' ] then fi

echo \DRIVE=$1

dd if=/dev/zero of=$DRIVE bs=1024 count=1024

SIZE=`fdisk -l $DRIVE | grep Disk | awk '{print $5}'` echo DISK SIZE - $SIZE bytes

CYLINDERS=`echo $SIZE/255/63/512 | bc` echo CYLINDERS - $CYLINDERS

exit

echo \exit

echo \exit

echo \exit

echo \exit

echo \

echo \mksd-am335x \echo \Example: mksd-am335x /dev/sdc MLO u-boot.img uImage nfs.tar.gz\exit

{

echo ,9,0x0C,* echo ,,,-

} | sfdisk -D -H 255 -S 63 -C $CYLINDERS $DRIVE echo \

mkfs.vfat -F 32 -n boot \mkfs.ext3 -L rootfs \echo \mount \cp $2 /mnt/MLO cp $3 /mnt/u-boot.img cp $4 /mnt/uImage umount \mount \

tar zxvf $5 -C /mnt &> /dev/null chmod 755 /mnt umount \echo \

2) 建立uEnv.txt

(我是将tf卡放入读卡器,在虚拟机下面vim编写的。应该在xp上用读卡器读出来,用文本文件编写uEnv.txt也可以的)

bootargs=console=ttyo0,115200n8 root=/dev/nfs (ttyo0 小写的o,不是数字0) nfsroot=192.168.1.27:/opt/ti-sdk-am335x-evm/targetNFS rw noinitrd ip=192.168.1.100:192.168.1.27:192.168.1.1:255.255.255.0 ipaddr=192.168.1.100 serverip=192.168.1.27 netmask=255.255.255.0 ethaddr=00:08:ee:05:4d:7e autoload=no bootdelay=3

bootcmd=tftp 0x81000000 uImage-am335x;bootm

如果只是这样,在将制作好的tf卡插入beaglebone,还是会默认从mmc启动

U-Boot# mmc rescan

U-Boot# fatload mmc 0 0x81000000 uEnv.txt U-Boot# env import -t 0x81000000 $filesize U-Boot# boot

有时候会出现“bootm 问题” :解决方法:boot 8100000000 (不要0x也可以,要也可以) 这样就可以从nfs挂载启动

注意:在启动linux后,会停止,等一会后就可以进入文件系统。

serverip=192.168.1.27

rootpath=/opt/ti-sdk-am335x-evm/targetNFS bootfile=uImage-am335x-evm.bin ip_method=dhcp

net_args=setenv bootargs console=ttyO0,115200n8 root=/dev/nfs nfsroot=${serverip}:${rootpath},${nfsopts} rw noinitrd

ip=${ip_method}

tftp_nfs_boot=echo Booting from network...; dhcp ${loadaddr} ${bootfile}; run net_args; bootm ${loadaddr} uenvcmd=run tftp_nfs_boot

1.3 常见问题

1) win7 64位安装问题(不能正常的启动gui)

修改文件/etc/init/rc-sysinit.conf env DEFAULT_RUNLEVEL=5

2) VIM

在启动vim时,当前用户根目录下的.vimrc文件会被自动读取,该文件可以包含一些设置甚至脚本,所以,一般情况下把.vimrc文件创建在当前用户的根目录下比较方便,即创建的命令为: $vi ~/.vimrc

Set number 保存退出

3)Ubuntu 循环登陆问题

原因:我自己在/etc/environment 里面不正确修改了PATH,导致这种情况的出现,2次了。

解决办法:用ctrl+F1+Alt进入终端(注意,不要ctrl+Alt+F1,因为虚拟机会捕捉到ctrl+alt,导致后面的ctrl+Alt+F1无效。

进入终端后连ls,都提示找不到路径,说明PATH有问题,可以用echo $PATH查看。

修改:export PATH = /bin:/sbin:/usr/bin:/usr/sbin,这样就可以用ls,vi等命令了。就用vim编辑错误的PATH路径,然后重启就ok。

2 AM335x外设

2.1 AM335x LCD驱动控制

LCD分为2个部分:

1. 激光LCD控制器,同步的(Hclk,Vclk,R,G,B,等) 2. LIDD控制器,异步的(CS,WE,OE,ALE,DATA)

1)AM335x的LCDC控制器是OMAPL138的升级版本 不同之处:

? 中断配置和状态寄存器的不同 ? 升级到2048*2048的分辨率 ? 24位的数据宽度 AM335x的LCDC

LCDC有2个时钟源L3外设时钟和L4LS

3 uboot相关

3.1 bootloader

分为3级boot stage,其中第1级为内部ROM,第2,3级都是基于uboot的。 第1级 :AM335x 内部的ROM

第2级 :标记为 SPL,它是不可以交互的【non-interactive】,一个特别的uboot版本 第3级 :标记为simply U-Boot.

ROM 可以从下面的设备中读取 SPL image ①non-XIP(SD/MMC,NAND)

image有一个header. 8个字节(入口点和image的长度) ②外设(uart)

ROM 通过uart读取image到内部的0x402f0400,并且执行。不需要image的header Uboot二级设计原理

AM335x内部RAM大小为128K,其中底部的18K用作ROM,1 KB at the start (0x402f0000 - 0x402f0400) is secure,

不可以被访问。剩下就109K,可以用来放uboot映像和用作stack。

你不可能期望所有的uboot都小于110K(这还不包括stack,heap所用的空间);所以采用2级boot stage. 初级只是完成必要的设备初始化(如,Nand,MMC,I2C等),第2级就完成剩下的初始化部分(如,时钟,以太网,定时器等等)

3.2 Uboot 配置和编译

$ make O=am335x CROSS_COMPILE=arm-arago-linux-gnueabi- ARCH=arm am335x_evm

O=am335x 作为目录 重新配置之前要删除

$ rm -rf ./am335x

生成2个文件:MLO和u-boot.bin

串口的配置

? Baud rate: 115,200 ? Data bits: 8 ? Parity: None ? Stop bits: 1

? Flow control: None

? Transmit delay: 0 msec/char, 100 msec/line 通过CCS烧写uboot

你可以烧写SPL&uboot到nand设备上面,然后配置成nand启动。使用PSP提供的nand flash writer 不通过CCS烧写uboot

? Both the stages of U-Boot need to be flashed on the same media. ? MLO is the binary for SPL and u-boot.img is the binary for U-Boot ① Uart flash模式

配置成uart启动模式 通过uart加载uboot 烧写SPL bootloader 烧写uboot bootloader

烧写完成后,设置成合适的启动模式 ② SD flash 模式 .启动模式

Nand模式启动:

Micron Nand parts (page size 2KB, block size 128KB) are supported on AM335XEVM platforms. NAND 布局

+------------+-->0x00000000-> SPL start (SPL copy on 1st block) | |

| |-->0x0001FFFF-> SPL end

| |-->0x00020000-> SPL.backup1 start (SPL copy on 2nd block) | |

| |-->0x0003FFFF-> SPL.backup1 end

| |-->0x00040000-> SPL.backup2 start (SPL copy on 3rd block) | |

| |-->0x0005FFFF-> SPL.backup2 end

| |-->0x00060000-> SPL.backup3 start (SPL copy on 4th block) | |

| |-->0x0007FFFF-> SPL.backup3 end | |-->0x00080000-> U-Boot start

| | | |-->0x002BFFFF-> U-Boot end | |-->0x00260000-> ENV start | | | |

| |-->0x0027FFFF-> ENV end

| |-->0x00280000-> Linux Kernel start | | | | | | | |

| |-->0x0077FFFF-> Linux Kernel end | |-->0x00780000-> File system start | | | | | | | | | | | | | | | | | | | | | | | |

+------------+-->0x10000000-> NAND end (Free end)

Writing to Nand

U-Boot# nand write 【需要和0x800 (2048) bytes对齐】

【Note】:Offset & len fields should be in align with 0x800 (2048) bytes. On writing 3000 (0xbb8) bytes, len field can be aligned to 0x1000 ie 4096 bytes. Offset field should be aligned to page start address, multiple of 2048 bytes.

If a bad block is encountered during the write operation, it is skipped and the write operation continues from next 'good' block.

For example, to write 0x40000 bytes from memory buffer at address 0x80000000 to NAND - starting at block 32 (offset 0x400000):

U-Boot# nand write 0x80000000 0x400000 0x40000

Reading from Nand

To read len bytes of data from NAND block at a particular offset to the memory buffer in DDR located at addr:

U-Boot# nand read

If a bad block is encountered during the read operation, it is skipped and the read operation continues from next 'good' block.

For example, to read 0x40000 bytes from NAND - starting at block 32 (offset 0x400000) to memory buffer at address 0x80000000:

U-Boot# nand read 0x80000000 0x400000 0x40000

Marking a bad block

Some of the blocks in the NAND may get corrupted over a period of time. In such cases you should explicitly mark such blocks as bad so that the image that you are writing to NAND does not end up getting corrupted. To forcefully mark a block as bad:

U-Boot# nand markbad

For example, to mark block 32 (assuming erase block size of 128Kbytes) as bad block - offset = blocknum * 128 * 1024:

U-Boot# nand markbad 0x400000

Viewing bad blocks

To view the list of bad blocks:

U-Boot# nand bad

Note ?

The user marked bad blocks can be viewed by using this command only after a reset.

Erasing Nand

To erase NAND blocks in a particular the address range or using block numbers:

U-Boot# nand erase

Note ?

start offset addr & len fields should should align to 0x20000 (64*2048) bytes, i.e. block size 128KB.

This commands skips bad blocks (both factory and user marked) encountered within the specified range. For example, to erase blocks 32 through 34:

U-Boot# nand erase 0x00400000 0x40000

NAND ECC algorithm selection

NAND flash memory, although cheap, suffers from problems like bit flipping which lead to data corruption. However by making use of some error correction coding (ECC) techniques it is possible to work around this problem. For the data stored in NAND flash, U-Boot supports following NAND ECC schemes

1. S/W ECC (Hamming code)

2. H/W ECC (Hamming code, BCH4, BCH8) Current releases do not support BCH4.

BCH Flash OOB Layout

For any ECC scheme we need to add some extra data while writing so as to detect and correct (if possible) the errors introduced by the NAND part. In case of BCH scheme some bytes are needed to store the ECC related info.

The section of NAND memory where addition info like ECC data is stored is referred to as Out Of Band or OOB section. The first 2 bytes are used for Bad block marker – 0xFFFF => Good block The next ‘N’ bytes is used for BCH bytes N = B *

1. B = 8 bytes per 512 byte sector in BCH4 2. B = 14 bytes per 512 byte sector in BCH8 3. B = 26 bytes per 512 byte sector in BCH16

So for a 2k page-size NAND flash with 64-byte OOB size, we will use BCH8. This will consume 2 + (14*4) = 58 bytes out of 64 bytes available.

The NAND flash part used in EVM does not have enough spare area to support BCH16.

ECC Schemes and their context of usage ECC type S/W ECC Not used Usage H/W ECC - Hamming Code Should use this scheme only for flashing the U-Boot ENV variables. H/W ECC – BCH8 Should use this scheme while flashing any image/binary other than the U-Boot ENV variables. To select ECC algorithm for NAND:

U-Boot# nandecc [sw | hw ]

Usage:

sw - Set software ECC for NAND hw - Set hardware ECC for NAND - 0 for Hamming code 1 for bch4 2 for bch8 3 for bch16 Currently we support only Software, Hamming Code and BCH8. We do not support BCH4 and BCH16

ECC schemes usage table ECC schemes usage table Component SPL U-boot Linux Default ECC scheme used by the ECC scheme to be used to flash component BCH8 Hamming BCH8 BCH8 BCH8 BCH8 the component BCH8 Hamming/BCH8 BCH8 ECC schemes supported by the component

File System Environment variables NA NA BCH8 Hamming NA NA Flashing Linux Kernel from U-Boot TFTP the kernel uImage to DDR.

U-Boot# mw.b 0x82000000 0xff 0x500000 U-Boot# tftp 0x82000000

Now flash the kernel image to NAND at the appropriate offset (refer to NAND layout section for the offsets)

U-Boot# nandecc hw 2

U-Boot# nand erase 0x00280000 0x00500000

U-Boot# nand write 0x82000000 0x00280000 0x500000

Note ?

Image_size should be aligned to page size of 2048 (0x800) bytes

UBIFS file system flashing

In AM335X, UBIFS file system is used in NAND flash as it is next generation flash file system. 1. creating of UBIFS file system image is described over here 2. Follow the steps mentioned below to Flash UBIFS image

Note: In case of AM335x, file system partition is starting from 0x780000. So from U-Boot, flashing offset for file system from U-Boot is 0x780000 and from Linux MTD partition number 7 should used for flashing file file system.

UBIFS file system flashing from U-Boot

Get the UBIFS image to U-Boot from tftp or MMC/SD or UART. Lets consider an example of MMC card. Since we copy the data to NAND, Empty/Erase the required RAM. Then, get the UBIFS image to U-Boot Load the memory with 0xFF

u-boot# mw.b 0x82000000 0xFF

filesystem image size is upward aligned to NAND page size.

Load the UBIFS file system image, in the example below from MMC as

u-boot# mmc rescan

u-boot# fatload mmc 0 0x82000000 ubi.img

Erase the NAND. Switch to BCH8 ECC and the flash the image assuming NAND partition to be erased starts from \block size.

u-boot# nand erase 0x00780000 0xF880000 u-boot# nandecc hw 2

u-boot# nand write 0x82000000 0x780000 0xFC0000

UBIFS file system flashing from Linux

?

Flash the UBI file system image (ubi.img) to MTD partition \

ubiformat /dev/mtd -f ubi.img -s 512 -O 2048

Assuming 7th mtd partition, we can use the following command to flash the ubifs image to partition 7.

#ubiformat /dev/mtd7 -f ubi.img -s 512 -O 2048

4 linux相关

4.1 linux小技巧

#cat /proc/meminof 查看memory map #free 查看剩余的内存

#cat /proc/iomem 可以查看IO(或者说外设的)物理地址范围

Linux启动的最后的一步就是调用用户空间的init进程Ubuntu 开发环境搭建

4.2 linux下的gpio编程

Beaglebone GPIO 学习

通过GPIO点亮LED需要三个步骤: 1.选定具体GPIO口;

2.设置GPIO口的工作模式; 3.编写控制程序。

2.设置GPIO口的工作模式

BeagleBone的引脚工作模式设置比较方便,在/sys/kernel/debug/omap_mux文件下有每个引脚的模式设定文件。在终端输入:# ls /sys/kernel/debug/omap_mux就可以查看到。扩展插排P8的Pin3对应GPIO1_6,由下表可知对应设置文件为gpmc_ad6。同理,GPIO1_7对应的文件为gpmc_ad7,TIMER4对应的文件为gprnc_advn_ale。

3. 编写控制程序

GPIO的配置文件在/sys/class/gpio目录下,控制程序可以分为四个步骤:

配置GPIO:在/sys/class/gpio目录下可以看到文件export,调用该文件以实现配置。该文件对所有GPIO编号,从0开始。GPIOn_x的编号为32*n+x,例如此处用的GPIO1_6的编号为32*1+6=38。在终端输入:# echo \> /sys/class/gpio/export,在此回到目录/sys/class/gpio下,可以看到产生了一个新的目录./gpio38,里面包含了该IO口的输入输出设置等配置文件。注意:export文件只有root写权限,执行上述命令或者以后用C编写的可执行文件要以ROOT身份执行。

设置GPIO的方向(输入输出)

输入:# echo \,即设置该GPIO为输出。

设置GPIO的输出电平:在终端输入:#echo \,即设置GPIO输出高电平 输入echo \设置GPIO输出低电平。 关闭GPIO

输入:#echo \,即删除GPIO配置文件,可以看到目录gpio38已经被删除。 下面是C语言编写的GPIO控制例程,实现LED的每隔一秒闪烁一次。

#include #include #include #include int main(void) {

FILE *p=NULL; int i=0;

p = fopen(\ fprintf(p,\ fclose(p);

p = fopen(\ fprintf(p,\ fclose(p);

for(i=0;i<100;i++) {

p = fopen(\ fprintf(p,\ sleep(1); fclose(p);

p = fopen(\ fprintf(p,\ sleep(1); fclose(p); }

p = fopen(\ fprintf(p,\ fclose(p); return 0;

}

Linux下面操作IO

#define TIA8_GPIO1_PA (0x4804C000) #define TIA8_GPIO_CLEARDATAOUT (0x190) #define TIA8_GPIO_SETDATAOUT #define TIA8_GPIO_CTRL #define TIA8_GPIO_OE #define LED1 #define LED2 #define LED3 #define LED4

(0x194) (0x130) (0x134)

( 1 << 21) ( 1 << 22) ( 1 << 23) ( 1 << 24)

void __iomem *base = ioremap【_nocache】(TIA8_GPIO1_PA,0x2048); __raw_writel(LED1,(base+TIA8_GPIO_SETDATAOUT)); __raw_writel(LED2,(TIA8_GPIO_SETDATAOUT+base)); __raw_writel(LED3,(TIA8_GPIO_CLEARDATAOUT+base)); __raw_writel(LED4,(TIA8_GPIO_CLEARDATAOUT+base));

运行成功的例子: #include #include #include

#include #include #include #include #include #include

MODULE_LICENSE(\

static DECLARE_COMPLETION(work); static int status;

static int gpio_num = 53;

//32*n+gpio GPIO1_21 = 32*1+21 = 53; static int __init gpio_init(void) { printk(KERN_INFO \ status = gpio_request(gpio_num,\ if(status < 0) { printk(\ return status; } gpio_direction_output(gpio_num,1); gpio_set_value(gpio_num,1); return 0; }

static void __exit gpio_exit(void)

{ printk(KERN_INFO \ gpio_set_value(gpio_num,0); gpio_free(gpio_num); }

module_init(gpio_init); module_exit(gpio_exit);

4.3 AM335x-MUX配置

(1)重要的数据结构 /**

* struct mux_partition - 包含分区相关信息 * @name: 当前分区名

* @flags: 本分区的特定标志 * @phys: 物理地址 * @size: 分区大小

* @base: ioremap 映射过的虚拟地址 * @muxmodes: 本分区mux节点链表头 * @node: 分区链表头 */

struct omap_mux_partition { const char *name; u32 flags; u32 phys; u32 size;

void __iomem *base; struct list_head muxmodes; struct list_head node; };

这个数据结构中包含了芯片中几乎所有定义好的mux的数据,它在mux数据初始化函数omap_mux_init中初始化,并添加到全局mux_partitions链表中(通过node成员)。而其中的muxmodes是所有mux信息节点的链表头,用来链接以下数据结构: /**

* struct omap_mux_entry - mux信息节点 * @mux: omap_mux结构体 * @node: 链表节点 */

struct omap_mux_entry { struct omap_mux mux; struct list_head node; };

而在以上数据结构中,struct omap_mux是记录单个mux节点数据的结构体: /**

* struct omap_mux - omap mux 寄存器偏移和值的数据

* @reg_offset: 从Control Module寄存器基地址算起的mux寄存器偏移 * @gpio: GPIO 编号

* @muxnames: 引脚可用的信号模式字符串指针数组 * @balls: 封装中可用的引脚 */

struct omap_mux { u16 reg_offset; u16 gpio;

#ifdef CONFIG_OMAP_MUX

char *muxnames[OMAP_MUX_NR_MODES]; #ifdef CONFIG_DEBUG_FS

char *balls[OMAP_MUX_NR_SIDES]; #endif #endif };

有了已经初始化好的struct mux_partition结构体,我们可以利用mux.h提供的许多函数方便的初始化各mux寄存器: board-am335xevm.c(其中自定义了一个重要的结构体struct pinmux_config) 在板级初始化代码(比如board-am335xevm.c)运行完芯片特定的MUX初始化函数(am33xx_mux_init(board_mux);)之后,也可以在各子系统初始化时通过上面的接口函数修改配置MUX,比如在am33xx中使用了自己封装的一个函数和结构体:

/* 模块引脚复用结构体 */ struct pinmux_config {

const char *string_name; /* 信号名格式化字符串,“模式0字符串.目标模式字符串“ */ int val; /* 其他mux寄存器可选配置值 */ };

上面初始化过的结构体和接口函数的定义都是带有\和“__initdata”的,所以这些都只能在内核初始化代码中使用,一旦系统初始化结束并进入了文件系统,这些定义都会被free。所有它们不能在内核模块(.ok)中被调用,否则你就等着Oops吧。因为一个芯片的引脚复用一般是硬件设计的时候定死的,一般不可能在启动后更改。如果你是在要在模块中改变引脚复用配置,你只能通过自己ioremap相关寄存器再修改它们来实现。

总结:

如何在linux中实现AM335x外设管脚复用配置 1)/* 模块引脚复用结构体 */

引用下面的结构体配置,因为它是在board-am335x.c中的,没有导出来 struct pinmux_config {

const char *string_name; /* 信号名格式化字符串,“模式0字符串.目标模式字符串“ */ int val; /* 其他mux寄存器可选配置值 */ };

2) 下面的就是自己要定义的

static struct pinmux_config d_can_ia_pin_mux[] = {

{\

{\ {NULL, 0}, };

3)在你的外设的初始化函数中

static void d_can_init(int evm_id, int profile) {

switch (evm_id) {

case IND_AUT_MTR_EVM:

if ((profile == PROFILE_0) || (profile == PROFILE_1)) { setup_pin_mux(d_can_ia_pin_mux);//这里来配置 /* Instance Zero */ am33xx_d_can_init(0); }

break;

case GEN_PURP_EVM:

if (profile == PROFILE_1) {

setup_pin_mux(d_can_gp_pin_mux); /* Instance One */

am33xx_d_can_init(1); }

break; default: break; } }

4.4 SPI设备驱动一般的步骤

1)设备注册

设备的创建

在板级初始化时将tsc2005的名称,地址和相关的信息加入到链表board_list中,该链表定义在driver/spi/spi.c中,记录了具体开发板上的SPI设备信息

1. static struct spi_board_info xxxx_spi_board_info[] __initdata = { 2. …… 3. {

4. .modalias = \,

5. .platform_data = &tsc2005_config, 6. .controller_data = &touchscreen_spi_cfg, 7. .mode = SPI_MODE_1,

8. .irq = OMAP_GPIO_IRQ(TS_GPIO), 9. .max_speed_hz = 700000, 10. .bus_num = 0, 11. .chip_select = 2, 12. },

设备的注册

Tsc2005设备信息通过函数spi_register_board_info()加入到链表board_list中

1. static void __init omap_xxxx_init(void)

2. {

3. omap_i2c_init(); 4. ……

5. spi_register_board_info(xxxx_spi_board_info, 6. ARRAY_SIZE(xxxx_spi_board_info)); 7. …… 8. }

Tsc2005 spi_device的创建并添加

Tsc2005 spi_device的创建并添加在SPI控制器驱动注册过程中完成,SPI 控制器驱动的注册可以参考4.2.2节,spi_register_master()函数在注册SPI控制器驱动的过程会扫描5.1.1中提到的SPI设备链表board_list,如果该总线上有对应的SPI设备,则创建相应的 spi_device,并将其添加到SPI的设备链表中

图5.2创建并添加spi_device

2)Tsc2005设备驱动注册

1. static struct spi_driver tsc2005_driver = { 2. .driver = {

3. .name = \, 4. .owner = THIS_MODULE, 5. },

6. #ifdef CONFIG_PM

7. .suspend = tsc2005_suspend, 8. .resume = tsc2005_resume, 9. #endif

10. .probe = tsc2005_probe,

11. .remove = __devexit_p(tsc2005_remove), 12. };

图5.3 tsc2005设备驱动的注册

在模块加载的时候首先调用tsc2005_init(),然后tsc2005_init()调用函数spi_register_driver()注册tsc2005_driver结构体。

[html] view plaincopy

1. int spi_register_driver(struct spi_driver *sdrv) 2. {

3. sdrv->driver.bus = &spi_bus_type; 4. if (sdrv->probe)

5. sdrv->driver.probe = spi_drv_probe; 6. if (sdrv->remove)

7. sdrv->driver.remove = spi_drv_remove; 8. if (sdrv->shutdown)

9. sdrv->driver.shutdown = spi_drv_shutdown; 10. return driver_register(&sdrv->driver); 11. }

函数spi_register_driver()初始化该驱动的总线为spi_bus_type,然后使用函数driver_register(&sdrv->driver)注册该驱动,因此内核会在SPI总线上遍历所有SPI设备,由于该tsc2005 设备驱动的匹配因子name变量为“tsc2005”,因此正好和在5.1.2里创建的chip->modalias为“tsc2005”的SPI 设备匹配。因此SPI设备驱动的probe函数tsc2005_probe()将会被调用,具体代码如下:

[html] view plaincopy

1. static int __devinit tsc2005_probe(struct spi_device *spi) 2. {

3. struct tsc2005 *tsc;

4. struct tsc2005_platform_data *pdata = spi->dev.platform_data; 5. int r; 6. ……

7. tsc = kzalloc(sizeof(*tsc), GFP_KERNEL); 8. ……

9. dev_set_drvdata(&spi->dev, tsc); 10. tsc->spispi = spi;

11. spi->dev.power.power_state = PMSG_ON; 12. spi->mode = SPI_MODE_0; 13. spi->bits_per_word = 8; 14. ……

15. spi_setup(spi);

16. r = tsc2005_ts_init(tsc, pdata); 17. …… 18. }

在tsc2005_probe()函数中,完成一些具体tsc2005设备相关的初始化等操作,这边就不再详述

SPI设备驱动用户空间的支持

和I2C一样,SPI也具有一个通用的设备的动程序,通过一个带有操作集file_operations的标准字符设备驱动为用户空间提供了访问接口。

此驱动模型是针对SPI设备的,只有注册board info时modalias是”spidev”的才能由此驱动访问。访问各个slave的基本框架是一致的,具体的差异将由从设备号来体现,代码部分位于drivers/spi/spidev.c。 在drivers/spi/spidev.c中,首先定义了SPI设备驱动spidev_spi:

1. static struct spi_driver spidev_spi = { 2. .driver = {

3. .name = \, //这个很重要 4. .owner = THIS_MODULE, 5. },

6. .probe = spidev_probe,

7. .remove = __devexit_p(spidev_remove), 8. };

spidev_spi注册代码如下:

1. static int __init spidev_init(void) 2. {

3. int status; 4. ……

5. status = register_chrdev(SPIDEV_MAJOR, \ 6. if (status < 0) 7. return status; 8.

9. spidev_class = class_create(THIS_MODULE, \ 10. ……

11. status = spi_register_driver(&spidev_spi); 12. …… 13. }

14. module_init(spidev_init);

首先注册了一个主设备号为SPIDEV_MAJOR,操作集为spidev_fops,名字为“spi”的字符设备。在文件

如,uart0

需要:打开uart0的时钟

判断CLKSTCTRL里面对应的uart0的时钟状态位

void UART0ModuleClkConfig(void) {

/* Writing to MODULEMODE field of CM_WKUP_UART0_CLKCTRL register. */ HWREG(SOC_CM_WKUP_REGS + CM_WKUP_UART0_CLKCTRL) |= CM_WKUP_UART0_CLKCTRL_MODULEMODE_ENABLE; /* Waiting for MODULEMODE field to reflect the written value. */

while(CM_WKUP_UART0_CLKCTRL_MODULEMODE_ENABLE !=

(HWREG(SOC_CM_WKUP_REGS + CM_WKUP_UART0_CLKCTRL) & CM_WKUP_UART0_CLKCTRL_MODULEMODE)); /*

** Waiting for CLKACTIVITY_UART0_GFCLK field in CM_WKUP_CLKSTCTRL ** register to attain desired value. */

while(CM_WKUP_CLKSTCTRL_CLKACTIVITY_UART0_GFCLK != (HWREG(SOC_CM_WKUP_REGS + CM_WKUP_CLKSTCTRL) & CM_WKUP_CLKSTCTRL_CLKACTIVITY_UART0_GFCLK)); /*

** Waiting for IDLEST field in CM_WKUP_UART0_CLKCTRL register to attain ** desired value. */

while((CM_WKUP_UART0_CLKCTRL_IDLEST_FUNC << CM_WKUP_UART0_CLKCTRL_IDLEST_SHIFT) !=

(HWREG(SOC_CM_WKUP_REGS + CM_WKUP_UART0_CLKCTRL) & CM_WKUP_UART0_CLKCTRL_IDLEST)); }

5.5 UART模块

特点:

波特率可达3.6864M

UART0 provides wakeup capability

Only UART 1 provides full modem control signals

5.6 设备ID

5.7 GPMC L3 Slow Interconnect

特点:

1)支持类型:类SRAM或ASIC,NOR,PSRAM,NAND 2)100M的外部接口时钟频率(针对单个设备而言的)

GPMC Clock ConfigurationGPMC Software Reset

GPMC_SYSCONFIG[1] SOFTRESET=1,无条件的复位GPMC,等效于硬件复位。 GPMC_SYSSTATUS[0] RESETDONE=1,指示复位完成。 GPMC Power Management

5.8 LCD控制器

DMA从帧buffer中读取数据到FIFO中,它的职责就是保证FIFO中的数据总是满的。而Raster控制器就不断的从FIFO中取出数据发送到TFT。

Supports up to WXGA (1366x768) resolution.

512 word deep internal FIFO

Pixel Clock (LCD_PCLK)

Pixel Clock (LCD_PCLK)

CLKDIV 不能等于0或1 DMA引擎的配置

To enable DMA transfers, the LIDD_DMA_EN bit (in the LIDD_CTRL register) or the LCDEN bit (in the RASTER_CTRL register) should be written with 1. LCD控制器的中断 Raster模式:

FIFO下溢出,DMA的速度跟不上,导致FIFO空。IRQSTATUS_RAW【FUF】= 1

【系统带宽的限制,或者错误的设置了LCD_PCLK】,那么只能关闭Raster控制器来清除中断标志。 Frame Buffer,就是内存中一块连续的区域

16/24BPP模式下的buffer中包含32字节的调色板

12-, 16-, and 24-BPP modes do not need a palette; i.e., the pixel data is the desired RGB value. However, the first 32 bytes are still considered a palette. The first entry should be 4000h (bit 14 is 1) while the remaining entries must be filled with 0.

drivers/spi/spidev.c中,SPI_MAJOR被定义为153。在spidev.c中spidev_fops的定义如下:

1. struct file_operations spidev_fops = { 2. .owner = THIS_MODULE,

3. /* REVISIT switch to aio primitives, so that userspace 4. * gets more complete API coverage. It'll simplify things 5. * too, except for the locking. 6. */

7. .write = spidev_write, 8. .read = spidev_read, 9. .unlocked_ioctl = spidev_ioctl, 10. .open = spidev_open, 11. .release = spidev_release, 12. };

该操作集是用户空间访问该字符设备的接口。

然后调用函数spi_register_driver(&spidev_spi)将spidev_spi 驱动注册到SPI 核心层中,spidev_spi驱动注册过程中会扫描SPI总线上的所有SPI设备,一旦扫描到关键字modalias为”spidev”的SPI设备时,则与该SPI驱动匹配,匹配函数spidev_probe()被调用,具体的注册流程图如下:

图5.1 SPIdev_driver注册过程

spidev_probe ()函数的代码如下:

1. static int spidev_probe(struct spi_device *spi) 2. {

3. struct spidev_data *spidev; 4. int status; 5. unsigned long minor; 6.

7. /* Allocate driver data */

8. spidev = kzalloc(sizeof(*spidev), GFP_KERNEL); 9. if (!spidev) 10. return -ENOMEM; 11.

12. /* Initialize the driver data */ 13. spidev->spi = spi; 14. ……

15. minor = find_first_zero_bit(minors, N_SPI_MINORS); 16. if (minor < N_SPI_MINORS) { 17. struct device *dev; 18.

19. spidev->devt = MKDEV(SPIDEV_MAJOR, minor);

20. dev = device_create(spidev_class, &spi->dev, spidev->devt, 21. spidev, \,

22. spi->master->bus_num, spi->chip_select); 23. status = IS_ERR(dev) ? PTR_ERR(dev) : 0; 24. } else {

25. dev_dbg(&spi->dev, \); 26. status = -ENODEV; 27. }

28. if (status == 0) {

29. set_bit(minor, minors);

30. list_add(&spidev->device_entry, &device_list); 31. } 32. ……. 33. }

在匹配函数spidev_probe()中,会首先为spidev_data结构体分配内存空间,该结构体定义如下:

1. struct spidev_data { 2. dev_t devt; 3. spinlock_t spi_lock; 4. struct spi_device *spi;

5. struct list_head device_entry;

6. /* buffer is NULL unless this device is open (users > 0) */ 7. struct mutex buf_lock; 8. unsigned users; 9. u8 *buffer; 10. };

结构体中包含了spi_device结构体,device_entry链表头等成员变量。

分配完spidev_data结构体后对其进行初始化,然后创建spi设备,成功后将该spidev_data添加到device_list链表中,该链表维护这些modalias为”spidev”的SPI设备。device_list链表定义在spidev.c中如下:

这些SPI设备以SPIDEV_MAJOR为主设备号,以函数find_first_zero_bit()的返回值为从设备号创建并注册设备节点。如果系统有udev或者是hotplug,那么就会在/dev下自动创建相关的设备节点了,其名称命名方式为spidevB.C,B为总线编号,C为片选序号。 6.2 Spidev的打开

Spidev的open函数如下:

1. static int spidev_open(struct inode *inode, struct file *filp) 2. {

3. struct spidev_data *spidev; 4. int status = -ENXIO; 5.

6. lock_kernel();

7. mutex_lock(&device_list_lock); 8.

9. list_for_each_entry(spidev, &device_list, device_entry) { 10. if (spidev->devt == inode->i_rdev) { 11. status = 0; 12. break; 13. } 14. }

15. if (status == 0) {

16. if (!spidev->buffer) {

17. spidev->buffer = kmalloc(bufsiz, GFP_KERNEL); 18. if (!spidev->buffer) {

19. dev_dbg(&spidev->spi->dev, \); 20. status = -ENOMEM; 21. } 22. }

23. if (status == 0) { 24. spidev->users++;

25. filp->private_data = spidev; 26. nonseekable_open(inode, filp); 27. } 28. } else

29. pr_debug(\, iminor(inode)); 30.

31. mutex_unlock(&device_list_lock); 32. unlock_kernel(); 33. return status; 34. } 35.

Open操作是用户空间程序和内核驱动交互的第一步,首先会遍历device_list链表,然后根据设备节点号进行

匹配查找对应的spidev_data节点从而找到相应的从设备,然后给spidev分配buffer空间,最后filp的private_data被赋值为spidev,而最终返回给用户空间的就是这个struct file结构体。对于SPI 驱动来说,用户空间所获得的就是spidev这个关键信息,在其中可以找到所有有关的信息如spidev的SPI设备。

用open函数将spidev设备打开以后,就可以通过ioctl函数的各种命令来对modalias为”spidev”的SPI设备进行读写等操作,也可以通过 read和write函数完成对SPI设备的读写。

对SPI设备的具体操作在这里不再具体阐述,可以参看spidev.c源代码。

4.4.1 SPI on BeagleBone AM335x

在linuxkernelpsp/arch/arm/mach-omap2/board-am335xevm.c:中

/* Beaglebone Rev A3 and after */

static struct evm_dev_cfg beaglebone_dev_cfg[] = { {mii1_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {usb0_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {usb1_init, DEV_ON_BASEBOARD, PROFILE_NONE}, {mmc0_init, DEV_ON_BASEBOARD, PROFILE_NONE},

{spi1_init, DEV_ON_BASEBOARD, PROFILE_ALL}, {NULL, 0, 0}, };

add {spi1_init, DEV_ON_BASEBOARD, PROFILE_ALL}, to the struct.

search for spi_board_info am335x_spi1_slave_info and replace the default \, have it point to spidev instead.

static struct spi_board_info am335x_spi1_slave_info[] = { { .modalias = \spidev\ .platform_data = &am335x_spi_flash, .irq = -1, .max_speed_hz = 10000000, .bus_num = 2, .chip_select = 0, .mode = SPI_MODE_0, }, };

4.5 AM335x/AM3517 串口修改

1) uboot的串口

2) linux内核的串口

3) 文件系统的串口

IP的参数

noinitrd init=/linuxrc console=ttySAC0 root=/dev/nfsnfsroot=192.168.10.100:/opt/EmbedSky/TQ2416/root_nfs ip=192.168.10.200:192.168.10.100:192.168.10.1:255.255.255.0:www.embedsky.net:eth0:off

5 裸机篇

Cotex-A8的beaglebone的两种裸机启动方式 Beaglebone的板子总共种有4种启动程序方式,现在我只研究了2种,现在记录下来这两种无操作系统的启动方式,概括来说,主要是需要一个引导程序,再加一个应用程序,就可以启动AM335x这个芯片了:

1、在SD引导阶段:

(1)首先需要引导程序MLO文件,拷贝到SD卡中。这个MLO文件是通用的引导文件,可以用starterware中的…\\tools\\ti_image\\tiimage.exe这个软件经由starterware中的.bin文件生成。生成一次就够,一般不需要改动。 (2)然后需要应用程序(应用程序一律要命名为app,无后缀名),该app文件可以用starterware安装目录下的…\\tools\\ti_image\\tiimage.exe这个软件经由starterware中的.bin文件生成。 (3)程序可以自动运行了。 2、UART启动阶段

(1)然后启动串口通信软件SecureCRT(我现在用的是这个软件,也可以用其他的,比如putty等等)连接到Beaglebone板。若连接好了UART,屏幕会不停地打印CCCC……

(2)然后将刚刚生成的boot.bin文件通过串口软件SecureCRT发送到Beaglebone板。(这个文件必须在每次发送程序之前发送)

(3)最后将需要的程序(后缀名为.bin的文件)通过串口发送到Beaglebone板,程序就可以运行了

AM335x 汇编 void CPUirqe(void) {

/* Enable IRQ in CPSR */

asm(\ mrs r0, CPSR\\n\\t\ \ bic r0, #0x80\\n\\t\ \ msr CPSR, r0\}

5.1 AM335x 中断系统

Priority Masking

To enable faster processing of high-priority interrupts, a programmable priority masking threshold is provided (the MPU_INTC.INTC_THRESHOLD[7:0] PRIORITYTHRESHOLD field). 小于或者等于这个门限的所有中断将被屏蔽。 a priority threshold of 0 is treated the same way as priority 1.

PRIORITY and PRIORITYTHRESHOLD fields values can be set between 0x0 and 0x7F; 0x0 is the highest priority and 0x7F is the lowest priority. 0xFF 会禁止优先级屏蔽的功能。如果不需要的话。

中断优先级相同:the highestnumbered interrupt is serviced first.(编号最高的中断优先级高)

INTC_ILR0 to INTC_ILR127

如果同时来了多个中断,MPU对中断根据FIQnIRQ位进行整理,填充到INTC_PENDING_IRQn or

INTC_PENDING_FIQn,如果当前没有中断正在处理,INTC再次有效FIQnIRQ,并且进行优先级冲裁,产生中断。

INTC仅仅识别电平类型的中断

共分成4个组,【0,1,2,3】对应128个中断源,每个独立的中断源可以分成FIQ和IRQ类型。

The INTC supports only level-sensitive incoming interrupt detection. A peripheral asserting an interrupt maintains it

until software has handled the interrupt and instructed the peripheral to deassert the interrupt。 软件中断产生 主要用来调试

INTC_ISR_SET0【1,2,3】 w1会产生软件中断 INTC_ISR_CLEAR0【1,2,3】 w1会清除软件中断 INTC_MIR_SET0【1,2,3】 中断屏蔽设置,写1屏蔽 INTC_MIR_CLEAR0【1,2,3】 中断屏蔽清除,写1清除屏蔽 INTC_ITR0【1,2,3】 原始中断寄存器,未屏蔽前的。

INTC_PENDING_IRQ0【1,2,3】 屏蔽后的中断挂起寄存器,IRQ类型的 INTC_PENDING_FIQ0【1,2,3】 屏蔽后的中断挂起寄存器,FIQ类型的 INTC_SIR_IRQ 当前有效的IRQ中断号

INTC_SIR_FIQ 当前有效的FIQ中断号

INTC_PROTECTION 中断保护寄存器 w1,保护模式使能,只能在特权模式下访问

INTC_IRQ_PRIORITY 当前有效的IRQ的中断优先级 INTC_FIQ_PRIORITY 当前有效的FIQ的中断优先级

INTC_THRESHOLD 中断优先级的门限,0xff禁止门限(复位后)

5.2 AM335x互联架构

?Initiator Ports L3F

–Cortex A8 MPUSS 128-bit initiator port0 and 64-bit initiator port1 –SGX530 128-bit initiator port

–3 TPTC 128-bit read initiator ports –3 TPTC 128-bit write initiator ports –LCDC 32-bit initiator port

–2 PRU-ICSS1 32-bit initiator ports

–2 port Gigabit Ethernet Switch (2PGSW) 32-bit initiator port –Debug Subsystem 32-bit initiator port ?L3S

–USB 32-bit CPPI DMA initiator port –USB 32-bit Queue Manager initiator port –P1500 32-bit initiator port Target Ports: ?L3F

–EMIF 128-bit target port

–3 TPTC CFG 32-bit target ports –TPCC CFG 32-bit target port –OCM RAM0 64-bit target port –DebugSS 32-bit target port –SGX530 64-bit target port –L4_FAST 32-bit target port ?L3S

–4 L4_PER peripheral 32-bit target ports –GPMC 32-bit target port –McASP0 32-bit target port –McASP1 32-bit target port –ADC_TSC 32-bit target port –USB 32-bit target port

–MMHCS2 32-bit target port

–L4_WKUP wakeup 32-bit target port

5.3 INTC的功耗管理

INTC有3个时钟域

? Interface clock ? Functional clock ? Synchronizer clock

如果Autoidle = 1,那么当buf interface 没有活动时,Interface clock就会关闭。

there is no activity on the bus interface, the interface clock is disabled internally to the module, thus reducing power consumption。

如果bus interface又有了新的活动,interface clock 会无延时的恢复。 INTC_IDLE

复位后,FuncIdle=0 The functional clock auto-idle power-saving mode is enabled。

在这种模式下 there is no active interrupt (IRQ or FIQ interrupt being processed or generated) or no pending incoming interrupt, functional clock将会关闭,以减低功耗。当这个时候来了一个未屏蔽的中断时,functional clock将会重新开启,并且INTC开始处理中断。如果不用这种减低功耗的模式,那么中断延时将会减少1个时钟周期。If this mode is disabled, the interrupt latency is reduced by one cycle.复位后,这种模式是使能的(FuncIdle=0) synchronizer clock 用来同步外部的异步中断

The synchronizer clock allows external asynchronous interrupts to be resynchronized before they are masked。 synchronizer clock的自动功耗节省模式【Turbo位】

The synchronizer input clock has an auto-idle power-saving mode

如果使能了Turbo=1,那么中断延时会从4个增加到6个 functional clock,默认是禁止的。看你的需求了。

5.4 AM335x 时钟系统

使能一个外设的时钟模块

分成了几个时钟域,看你要使能的外设属于哪一个?一般_PER_,_WKUP_。然后使能。

本文来源:https://www.bwwdw.com/article/3a62.html

Top