现在的位置: 首页 > 综合 > 正文

bcm4330蓝牙分析总结

2018年02月15日 ⁄ 综合 ⁄ 共 4575字 ⁄ 字号 评论关闭

     对于蓝牙无论最底层的硬件驱动如何实现,都会在HCI层进行统一。也就是说,HCI在主机端的驱动主要是为上层提供统一接口,让上层协议不依赖于具体的硬件实现。HCI在硬件中的固件与HCI在主机端的驱动通信方式有多种,比如UART,USB和SDIO等。

       HCI层在所有的设备面前都被抽象为一个hci_dev结构体,因此,无论实际的设备是哪种蓝牙设备、通过什么方式连接到主机,都需要向HCI层和蓝牙核心层注册一个hci_dev设备,注册过程由hci_registe_dev()函数来完成,同时也可以通过hci_unregister_dev()函数卸载一个蓝牙设备。

具体的蓝牙驱动有很多,常用的在linux内核都自带有驱动。比如:hci_vhci.c为蓝牙虚拟主控制器驱动程序,hci_uart.c(或者hci_ldisc.c/
hci_H4.C)
为串口接口主控制器驱动程序,btusb.cUSB接口主控制器驱动程序,btsdio.cSDIO主控制器驱动程序。

 

总结一下,蓝牙驱动的三个步骤:

1, 串口驱动必须要先就绪(uart蓝牙而言),这是cpu和蓝牙模块之间的桥梁。

2, 蓝牙初始化,模块上电和PSKEY的设置。

3, 通过hciattach建立串口和蓝牙协议层之间的数据连接通道。

 

蓝牙模块上电

        一般是通过一个GPIO来控制的,通常是先高再低再高;

PSKEY的设置

        通过串口发送命令给蓝牙模块,对于串口必须要知道的是要能通讯,必须得设好波特率,另外一方面蓝牙模块的晶振频率也必须要设,否则它不知道该怎么跳了;当然不同的芯片可能初始化的过程也不一样,也许还要下载firmware等等,一般是通过bccmd来完成的。

 

经过上面的设置基本上蓝牙模块以及可以正常工作了;

        但是还没有和上面的协议层建立纽带关系,也就是说从uart收到的数据还没有传给hci层;

        如何把uart也就是蓝牙模块传上来的数据交给hci层,在驱动里面是通过一个叫做disc的机制完成的,这个机制本意是用来做过滤或者限制收上来的字符的,但是在蓝牙驱动里面则直接把数据传给了蓝牙协议层,再也不回到串口的控制了;

Uart交给hci层的前面对比图:

 

简单总结一下,数据的流程,

基本上是:

1, uart口取得蓝牙模块的数据;

2, uart口通过ldisc传给hci_uart;

3, hci_uart传给在其上的bcsp

4, bcsp传给hci层;

5, hci层传给l2cap

6, l2cap层再传给rfcomm

 

 

Rfkill平台设备部分

static structresource nabi2_bcm4330_rfkill_resources[] = {

         {

                   .name   = "bcm4330_nshutdown_gpio",

                   .start  = TEGRA_GPIO_PD0,

                   .end    = TEGRA_GPIO_PD0,

                   .flags  = IORESOURCE_IO,

         },

         {

                   .name   = "bcm4330_nreset_gpio",

                   .start  = TEGRA_GPIO_PU0,

                   .end    = TEGRA_GPIO_PU0,

                   .flags  = IORESOURCE_IO,

         },

};

static structplatform_device nabi2_bcm4330_rfkill_device = {

         .name = "bcm4330_rfkill",

         .id             = -1,

         .num_resources  = ARRAY_SIZE(nabi2_bcm4330_rfkill_resources),

         .resource       = nabi2_bcm4330_rfkill_resources,

};

 

Rfkill平台驱动部分(主要用来给蓝牙上电和下电)

static intbcm4330_bt_rfkill_set_power(void *data, bool blocked)

{

模块上电和下电操作。

         }

static const structrfkill_ops bcm4330_bt_rfkill_ops = {

         .set_block =bcm4330_bt_rfkill_set_power,

};

static int bcm4330_rfkill_probe(structplatform_device *pdev){

……

         bt_rfkill = rfkill_alloc("bcm4330Bluetooth", &pdev->dev,

                            RFKILL_TYPE_BLUETOOTH,&bcm4330_bt_rfkill_ops, NULL);

       rfkill_register(bt_rfkill);

……

}

static struct platform_driverbcm4330_rfkill_driver = {

         .probe= bcm4330_rfkill_probe,

         .driver= {

                      .name = "bcm4330_rfkill",

                      .owner = THIS_MODULE,

         },

};

static int __init bcm4330_rfkill_init(void)

{

         returnplatform_driver_register(&bcm4330_rfkill_driver);

}

 

        Rfkill驱动很简单,仅仅是注册了一个bcm4330_rfkill_driver的平台驱动。在彼配的时候会注册一个rfkill_ops
bcm4330_bt_rfkill_ops 
函数集。当用户操作/sys/class/rfkill/rfkill0/state时将会调用到bcm4330_bt_rfkill_set_power这个函数,用来给蓝牙上电和关电。

 

        蓝牙驱动在内核里面有(个别产品有自己专门的驱动除外,即便如此专门的驱动实现架构也跟内核自带的一模一样),对于串口蓝牙的驱动是:/kernel/drivers/Bluetooth/hci_ldisc.c

        这个驱动其实没什么好讲的,hci提供了统一的接口函数,不管是蓝牙模块是usb,sdio,uart……都只需要实现这些接口就行了。

所有蓝牙驱动都只是围绕一个hci_dev结构体,然后完成下面这些函数就行了。

         hdev->open  = hci_uart_open;

         hdev->close = hci_uart_close;

         hdev->flush = hci_uart_flush;

         hdev->send  = hci_uart_send_frame;

         hdev->destruct = hci_uart_destruct;

所有的接口在hci层做了统一,hci层负责跟蓝牙协议通信,所以你只要实现hci层提供的接口,协议你无需多管。

 

蓝牙初始化XXX_init.rc文件添加如下:

 

……

# bluetooth

# bluetooth MAC address programming

         chown bluetooth bluetooth /system/etc/bluetooth   #设备该目录有蓝牙权限

         setprop ro.bt.bdaddr_path"/system/etc/bluetooth/bdaddr"  #设置蓝牙地址路径 

         chmod 0660/sys/class/rfkill/rfkill0/state                      #rfkill文件具有可读可写权限

         chmod 0660/sys/class/rfkill/rfkill0/type

         chown bluetooth bluetooth/sys/class/rfkill/rfkill0/state #rfkill文件具有蓝牙权限

         chown bluetooth bluetooth/sys/class/rfkill/rfkill0/type

 

#BCM #bccmd 主要用来初始化蓝牙,比如说上电,设置波特率,下载firmware……

       #具体参照brcm_patchram_plus.c这个文件有详细的使用说明

service hciattach/system/bin/brcm_patchram_plus --enable_hci --scopcm=0,2,0,0,0,0,0,0,0,0 \

--baudrate 3000000 --patchram /etc/firmware/bcm4330.hcd--enable_lpm --tosleep=5000 --create_bdaddr /dev/ttyHS2 

#创建蓝牙地址(因为bcm4330没有物理蓝牙地址),使用uart2hci连接。

    user bluetooth

    group bluetooth net_bt_admin

disabled

 

……

 

蓝牙驱动依赖是蓝牙协议在android里面已支持bluez协议,我们只需要要配制的时候选上bluez协议就可以了。

CONFIG_BT =y

CONFIG_BT_RFCOMM =y

CONFIG_BT_BNEP = y

CONFIG_BT_CMTP =y

CONFIG_BT_L2CAP=y

CONFIG_BT_SCO=y

如果是linux的话,或者你还需要自己再移植bluez协议。

 

好了,到这里蓝牙就可以使用了,进入蓝牙测试。

1、  蓝牙上电

# echo  1 >/sys/class/rfkill/rfkill0/state

2、  蓝牙初始化

# XXX_init.rc里面做好了。

3、  测试蓝牙驱动

# hciconfig

      说明蓝牙驱动已经正常初始化并加载了。

4、  激活蓝牙

#hciconfig   hci0    up

# hciconfig

说明蓝牙已经初激活了。

5、  查看蓝牙地址

# hcitool   dev

6、  扫描周围蓝牙设备

# hcitool  scan

 

出现上面的类似画面说明蓝牙已经工作正常了。

 

7、上面是用命令测试,要在android上使用的话,还需要把蓝牙配制上。

找到相对应的BoadConfig.mk文件设置BOARD_HAVE_BLUETOOTH

               BOARD_HAVE_BLUETOOTH:= true

抱歉!评论已关闭.