您尚未登录。

楼主 #1 2019-06-05 17:06:56

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,349
积分: 9202

使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

参考链接: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 WIFI




固件下载地址: https://github.com/armbian/firmware/tree/master/brcm


参考链接:

https://github.com/torvalds/linux/blob/master/Documentation/devicetree/bindings/net/broadcom-bluetooth.txt

https://github.com/RoEdAl/alarm-bluetooth-raspberrypi/blob/master/bcmbt-overlay.dts

https://lkml.org/lkml/2019/2/28/1215




4.13/4.14 驱动的差异还蛮大的:
https://github.com/torvalds/linux/blob/v4.13/drivers/bluetooth/hci_bcm.c
https://github.com/torvalds/linux/blob/v4.14/drivers/bluetooth/hci_bcm.c


https://github.com/torvalds/linux/commit/33cd149e767be9afbab9fcd3d5165a2de62313c8#diff-6fa55bc95c463db86bd2105025cc42c8


                        uart1_pg_pins: uart1-pg-pins {
                                pins = "PG6", "PG7", "PG8", "PG9";
                                function = "uart1";
                        };
&uart1 {
        pinctrl-0 = <&uart1_pg_pins>;
        pinctrl-names = "default";
        status = "okay";

       bluetooth {
               compatible = "brcm,bcm43438-bt";
               max-speed = <921600>;

                vbat-supply = <&reg_vcc3v3>;
                vddio-supply = <&reg_vcc3v3>;
                device-wakeup-gpios = <&pio 1 13 GPIO_ACTIVE_HIGH>; /* PB13 */
                host-wakeup-gpios = <&pio 1 12 GPIO_ACTIVE_HIGH>; /* PB12 */
                shutdown-gpios = <&pio 1 11 GPIO_ACTIVE_HIGH>; /* PB11 */
       };
};

https://github.com/torvalds/linux/blob/master/drivers/bluetooth/hci_bcm.c

测试中...





离线

楼主 #2 2019-06-07 12:28:29

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,349
积分: 9202

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

http://distro.ibiblio.org/fatdog/source/700/patches/brcm_patchram_plus.c

https://whycan.cn/t_2233.html#p16357

https://whycan.cn/t_245.html#p5165

/*******************************************************************************
 *
 *  Copyright (C) 2009-2011 Broadcom Corporation
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/*****************************************************************************
**                                                                           
**  Name:          brcm_patchram_plus.c
**
**  Description:   This program downloads a patchram files in the HCD format
**                 to Broadcom Bluetooth based silicon and combo chips and
**				   and other utility functions.
**
**                 It can be invoked from the command line in the form
**						<-d> to print a debug log
**						<--patchram patchram_file>
**						<--baudrate baud_rate>
**						<--bd_addr bd_address>
**						<--enable_lpm>
**						<--enable_hci>
**						<--use_baudrate_for_download>
**						<--scopcm=sco_routing,pcm_interface_rate,frame_type,
**							sync_mode,clock_mode,lsb_first,fill_bits,
**							fill_method,fill_num,right_justify>
**
**							Where
**
**							sco_routing is 0 for PCM, 1 for Transport,
**							2 for Codec and 3 for I2S,
**
**							pcm_interface_rate is 0 for 128KBps, 1 for
**							256 KBps, 2 for 512KBps, 3 for 1024KBps,
**							and 4 for 2048Kbps,
**
**							frame_type is 0 for short and 1 for long,
**
**							sync_mode is 0 for slave and 1 for master,
**
**							clock_mode is 0 for slabe and 1 for master,
**
**							lsb_first is 0 for false aand 1 for true,
**
**							fill_bits is the value in decimal for unused bits,
**
**							fill_method is 0 for 0's and 1 for 1's, 2 for
**								signed and 3 for programmable,
**
**							fill_num is the number or bits to fill,
**
**							right_justify is 0 for false and 1 for true
**
**						<--i2s=i2s_enable,is_master,sample_rate,clock_rate>
**
**							Where
**
**							i2s_enable is 0 for disable and 1 for enable,
**
**							is_master is 0 for slave and 1 for master,
**
**							sample_rate is 0 for 8KHz, 1 for 16Khz and
**								2 for 4 KHz,
**
**							clock_rate is 0 for 128KHz, 1 for 256KHz, 3 for
**								1024 KHz and 4 for 2048 KHz.
**
**						<--no2bytes skips waiting for two byte confirmation
**							before starting patchram download. Newer chips
**                          do not generate these two bytes.>
**						<--tosleep=number of microsseconds to sleep before
**							patchram download begins.>
**						uart_device_name
**
**                 For example:
**
**                 brcm_patchram_plus -d --patchram  \
**						BCM2045B2_002.002.011.0348.0349.hcd /dev/ttyHS0
**
**                 It will return 0 for success and a number greater than 0
**                 for any errors.
**
**                 For Android, this program invoked using a 
**                 "system(2)" call from the beginning of the bt_enable
**                 function inside the file 
**                 system/bluetooth/bluedroid/bluetooth.c.
**
**                 If the Android system property "ro.bt.bcm_bdaddr_path" is
**                 set, then the bd_addr will be read from this path.
**                 This is overridden by --bd_addr on the command line.
**  
******************************************************************************/

#include <stdio.h>
#include <getopt.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include <stdlib.h>

#ifdef ANDROID
#include <termios.h>
#else
#include <sys/termios.h>
#include <sys/ioctl.h>
#include <limits.h>
#endif

#include <string.h>
#include <signal.h>

#ifdef ANDROID
#include <cutils/properties.h>
#define LOG_TAG "brcm_patchram_plus"
#include <cutils/log.h>
#undef printf
#define printf LOGD
#undef fprintf
#define fprintf(x, ...) \
  { if(x==stderr) LOGE(__VA_ARGS__); else fprintf(x, __VA_ARGS__); }

#endif //ANDROID

#ifndef N_HCI
#define N_HCI	15
#endif

#define HCIUARTSETPROTO		_IOW('U', 200, int)
#define HCIUARTGETPROTO		_IOR('U', 201, int)
#define HCIUARTGETDEVICE	_IOR('U', 202, int)

#define HCI_UART_H4		0
#define HCI_UART_BCSP	1
#define HCI_UART_3WIRE	2
#define HCI_UART_H4DS	3
#define HCI_UART_LL		4

typedef unsigned char uchar;

int uart_fd = -1;
int hcdfile_fd = -1;
int termios_baudrate = 0;
int bdaddr_flag = 0;
int enable_lpm = 0;
int enable_hci = 0;
int use_baudrate_for_download = 0;
int debug = 0;
int scopcm = 0;
int i2s = 0;
int no2bytes = 0;
int tosleep = 0;
int baudrate = 0;

struct termios termios;
uchar buffer[1024];

uchar hci_reset[] = { 0x01, 0x03, 0x0c, 0x00 };

uchar hci_download_minidriver[] = { 0x01, 0x2e, 0xfc, 0x00 };

uchar hci_update_baud_rate[] = { 0x01, 0x18, 0xfc, 0x06, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00 };

uchar hci_write_bd_addr[] = { 0x01, 0x01, 0xfc, 0x06,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

uchar hci_write_sleep_mode[] = { 0x01, 0x27, 0xfc, 0x0c,
	0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
	0x00, 0x00 };

uchar hci_write_sco_pcm_int[] =
	{ 0x01, 0x1C, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };

uchar hci_write_pcm_data_format[] =
	{ 0x01, 0x1e, 0xFC, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00 };

uchar hci_write_i2spcm_interface_param[] =
	{ 0x01, 0x6d, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00 };

uchar hci_write_uart_clock_setting_48Mhz[] =
	{ 0x01, 0x45, 0xfc, 0x01, 0x01 };

int
parse_patchram(char *optarg)
{
	char *p;

	if (!(p = strrchr(optarg, '.'))) {
		fprintf(stderr, "file %s not an HCD file\n", optarg);
		exit(3);
	}

	p++;

	if (strcasecmp("hcd", p) != 0) {
		fprintf(stderr, "file %s not an HCD file\n", optarg);
		exit(4);
	}

	if ((hcdfile_fd = open(optarg, O_RDONLY)) == -1) {
		fprintf(stderr, "file %s could not be opened, error %d\n", optarg, errno);
		exit(5);
	}

	return(0);
}

void
BRCM_encode_baud_rate(uint baud_rate, uchar *encoded_baud)
{
	if(baud_rate == 0 || encoded_baud == NULL) {
		fprintf(stderr, "Baudrate not supported!");
		return;
	}

	encoded_baud[3] = (uchar)(baud_rate >> 24);
	encoded_baud[2] = (uchar)(baud_rate >> 16);
	encoded_baud[1] = (uchar)(baud_rate >> 8);
	encoded_baud[0] = (uchar)(baud_rate & 0xFF);
}

typedef struct {
	int baud_rate;
	int termios_value;
} tBaudRates;

tBaudRates baud_rates[] = {
	{ 115200, B115200 },
	{ 230400, B230400 },
	{ 460800, B460800 },
	{ 500000, B500000 },
	{ 576000, B576000 },
	{ 921600, B921600 },
	{ 1000000, B1000000 },
	{ 1152000, B1152000 },
	{ 1500000, B1500000 },
	{ 2000000, B2000000 },
	{ 2500000, B2500000 },
	{ 3000000, B3000000 },
#ifndef __CYGWIN__
	{ 3500000, B3500000 },
	{ 4000000, B4000000 }
#endif
};

int
validate_baudrate(int baud_rate, int *value)
{
	unsigned int i;

	for (i = 0; i < (sizeof(baud_rates) / sizeof(tBaudRates)); i++) {
		if (baud_rates[i].baud_rate == baud_rate) {
			*value = baud_rates[i].termios_value;
			return(1);
		}
	}

	return(0);
}

int
parse_baudrate(char *optarg)
{
	baudrate = atoi(optarg);

	if (validate_baudrate(baudrate, &termios_baudrate)) {
		BRCM_encode_baud_rate(baudrate, &hci_update_baud_rate[6]);
	} else {
		return(1);
	}

	return(0);
}

int
parse_bdaddr(char *optarg)
{
	int bd_addr[6];
	int i;

	sscanf(optarg, "%02X:%02X:%02X:%02X:%02X:%02X",
		&bd_addr[5], &bd_addr[4], &bd_addr[3],
		&bd_addr[2], &bd_addr[1], &bd_addr[0]);

	for (i = 0; i < 6; i++) {
		hci_write_bd_addr[4 + i] = bd_addr[i];
	}

	bdaddr_flag = 1;

	return(0);
}

int
parse_enable_lpm(char *optarg)
{
	enable_lpm = 1;
	return(0);
}

int
parse_use_baudrate_for_download(char *optarg)
{
	use_baudrate_for_download = 1;
	return(0);
}

int
parse_enable_hci(char *optarg)
{
	enable_hci = 1;
	return(0);
}

int
parse_scopcm(char *optarg)
{
	int param[10];
	int ret;
	int i;

	ret = sscanf(optarg, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
		&param[0], &param[1], &param[2], &param[3], &param[4],
		&param[5], &param[6], &param[7], &param[8], &param[9]);

	if (ret != 10) {
		return(1);
	}

	scopcm = 1;

	for (i = 0; i < 5; i++) {
		hci_write_sco_pcm_int[4 + i] = param[i];
	}

	for (i = 0; i < 5; i++) {
		hci_write_pcm_data_format[4 + i] = param[5 + i];
	}

	return(0);
}

int
parse_i2s(char *optarg)
{
	int param[4];
	int ret;
	int i;

	ret = sscanf(optarg, "%d,%d,%d,%d", &param[0], &param[1], &param[2],
		&param[3]);

	if (ret != 4) {
		return(1);
	}

	i2s = 1;

	for (i = 0; i < 4; i++) {
		hci_write_i2spcm_interface_param[4 + i] = param[i];
	}

	return(0);
}

int
parse_no2bytes(char *optarg)
{
	no2bytes = 1;
	return(0);
}

int
parse_tosleep(char *optarg)
{
	tosleep = atoi(optarg);

	if (tosleep <= 0) {
		return(1);
	}

	return(0);
}

void
usage(char *argv0)
{
	printf("Usage %s:\n", argv0);
	printf("\t<-d> to print a debug log\n");
	printf("\t<--patchram patchram_file>\n");
	printf("\t<--baudrate baud_rate>\n");
	printf("\t<--bd_addr bd_address>\n");
	printf("\t<--enable_lpm>\n");
	printf("\t<--enable_hci>\n");
	printf("\t<--use_baudrate_for_download> - Uses the\n");
	printf("\t\tbaudrate for downloading the firmware\n");
	printf("\t<--scopcm=sco_routing,pcm_interface_rate,frame_type,\n");
	printf("\t\tsync_mode,clock_mode,lsb_first,fill_bits,\n");
	printf("\t\tfill_method,fill_num,right_justify>\n");
	printf("\n\t\tWhere\n");
	printf("\n\t\tsco_routing is 0 for PCM, 1 for Transport,\n");
	printf("\t\t2 for Codec and 3 for I2S,\n");
	printf("\n\t\tpcm_interface_rate is 0 for 128KBps, 1 for\n");
	printf("\t\t256 KBps, 2 for 512KBps, 3 for 1024KBps,\n");
	printf("\t\tand 4 for 2048Kbps,\n");
	printf("\n\t\tframe_type is 0 for short and 1 for long,\n");
	printf("\t\tsync_mode is 0 for slave and 1 for master,\n");
	printf("\n\t\tclock_mode is 0 for slabe and 1 for master,\n");
	printf("\n\t\tlsb_first is 0 for false aand 1 for true,\n");
	printf("\n\t\tfill_bits is the value in decimal for unused bits,\n");
	printf("\n\t\tfill_method is 0 for 0's and 1 for 1's, 2 for\n");
	printf("\t\tsigned and 3 for programmable,\n");
	printf("\n\t\tfill_num is the number or bits to fill,\n");
	printf("\n\t\tright_justify is 0 for false and 1 for true\n");
	printf("\n\t<--i2s=i2s_enable,is_master,sample_rate,clock_rate>\n");
	printf("\n\t\tWhere\n");
	printf("\n\t\ti2s_enable is 0 for disable and 1 for enable,\n");
	printf("\n\t\tis_master is 0 for slave and 1 for master,\n");
	printf("\n\t\tsample_rate is 0 for 8KHz, 1 for 16Khz and\n");
	printf("\t\t2 for 4 KHz,\n");
	printf("\n\t\tclock_rate is 0 for 128KHz, 1 for 256KHz, 3 for\n");
	printf("\t\t1024 KHz and 4 for 2048 KHz.\n\n");
	printf("\t<--no2bytes skips waiting for two byte confirmation\n");
	printf("\t\tbefore starting patchram download. Newer chips\n");
	printf("\t\tdo not generate these two bytes.>\n");
	printf("\t<--tosleep=microseconds>\n");
	printf("\tuart_device_name\n");
}

int
parse_cmd_line(int argc, char **argv)
{
	int c;
	int ret = 0;

	typedef int (*PFI)();

	PFI parse[] = { parse_patchram, parse_baudrate,
		parse_bdaddr, parse_enable_lpm, parse_enable_hci,
		parse_use_baudrate_for_download,
		parse_scopcm, parse_i2s, parse_no2bytes, parse_tosleep};

	while (1) {
		int this_option_optind = optind ? optind : 1;
		int option_index = 0;

		static struct option long_options[] = {
			{"patchram", 1, 0, 0},
			{"baudrate", 1, 0, 0},
			{"bd_addr", 1, 0, 0},
			{"enable_lpm", 0, 0, 0},
			{"enable_hci", 0, 0, 0},
			{"use_baudrate_for_download", 0, 0, 0},
			{"scopcm", 1, 0, 0},
			{"i2s", 1, 0, 0},
			{"no2bytes", 0, 0, 0},
			{"tosleep", 1, 0, 0},
			{0, 0, 0, 0}
		};

		c = getopt_long_only (argc, argv, "d", long_options,
				&option_index);

		if (c == -1) {
			break;
		}

		switch (c) {
			case 0:
				if (debug) {
					printf ("option %s",
						long_options[option_index].name);
					if (optarg)
						printf (" with arg %s", optarg);
					printf ("\n");
				}

				ret = (*parse[option_index])(optarg);

				break;
			case 'd':
				debug = 1;
				break;

			case '?':
				//nobreak
			default:
				usage(argv[0]);
				break;
		}

		if (ret) {
			usage(argv[0]);
			break;
		}
	}

	if (ret) {
		return(1);
	}

	if (optind < argc) {
		if (debug)
			printf ("%s \n", argv[optind]);
		if ((uart_fd = open(argv[optind], O_RDWR | O_NOCTTY)) == -1) {
			fprintf(stderr, "port %s could not be opened, error %d\n",
					argv[optind], errno);
		}
	}

	return(0);
}

void
init_uart()
{
	tcflush(uart_fd, TCIOFLUSH);
	tcgetattr(uart_fd, &termios);

#ifndef __CYGWIN__
	cfmakeraw(&termios);
#else
	termios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP
                | INLCR | IGNCR | ICRNL | IXON);
	termios.c_oflag &= ~OPOST;
	termios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
	termios.c_cflag &= ~(CSIZE | PARENB);
	termios.c_cflag |= CS8;
#endif

	termios.c_cflag |= CRTSCTS;
	tcsetattr(uart_fd, TCSANOW, &termios);
	tcflush(uart_fd, TCIOFLUSH);
	tcsetattr(uart_fd, TCSANOW, &termios);
	tcflush(uart_fd, TCIOFLUSH);
	tcflush(uart_fd, TCIOFLUSH);
	cfsetospeed(&termios, B115200);
	cfsetispeed(&termios, B115200);
	tcsetattr(uart_fd, TCSANOW, &termios);
}

void
dump(uchar *out, int len)
{
	int i;

	for (i = 0; i < len; i++) {
		if (i && !(i % 16)) {
			fprintf(stderr, "\n");
		}

		fprintf(stderr, "%02x ", out[i]);
	}

	fprintf(stderr, "\n");
}

void
read_event(int fd, uchar *buffer)
{
	int i = 0;
	int len = 3;
	int count;

	while ((count = read(fd, &buffer[i], len)) < len) {
		i += count;
		len -= count;
	}

	i += count;
	len = buffer[2];

	while ((count = read(fd, &buffer[i], len)) < len) {
		i += count;
		len -= count;
	}

	if (debug) {
		count += i;

		fprintf(stderr, "received %d\n", count);
		dump(buffer, count);
	}
}

void
hci_send_cmd(uchar *buf, int len)
{
	if (debug) {
		fprintf(stderr, "writing\n");
		dump(buf, len);
	}

	write(uart_fd, buf, len);
}

void
expired(int sig)
{
	hci_send_cmd(hci_reset, sizeof(hci_reset));
	alarm(4);
}

void
proc_reset()
{
	signal(SIGALRM, expired);


	hci_send_cmd(hci_reset, sizeof(hci_reset));

	alarm(4);

	read_event(uart_fd, buffer);

	alarm(0);
}

void
proc_patchram()
{
	int len;

	hci_send_cmd(hci_download_minidriver, sizeof(hci_download_minidriver));

	read_event(uart_fd, buffer);

	if (!no2bytes) {
		read(uart_fd, &buffer[0], 2);
	}

	if (tosleep) {
		usleep(tosleep);
	}

	while (read(hcdfile_fd, &buffer[1], 3)) {
		buffer[0] = 0x01;

		len = buffer[3];

		read(hcdfile_fd, &buffer[4], len);

		hci_send_cmd(buffer, len + 4);

		read_event(uart_fd, buffer);
	}

	if (use_baudrate_for_download) {
		cfsetospeed(&termios, B115200);
		cfsetispeed(&termios, B115200);
		tcsetattr(uart_fd, TCSANOW, &termios);
	}
	proc_reset();
}

void
proc_baudrate()
{

	if (baudrate > 3000000) {
		hci_send_cmd(hci_write_uart_clock_setting_48Mhz,
			sizeof(hci_write_uart_clock_setting_48Mhz));

		read_event(uart_fd, buffer);
	}

	hci_send_cmd(hci_update_baud_rate, sizeof(hci_update_baud_rate));

	read_event(uart_fd, buffer);

	cfsetospeed(&termios, termios_baudrate);
	cfsetispeed(&termios, termios_baudrate);
	tcsetattr(uart_fd, TCSANOW, &termios);

	if (debug) {
		fprintf(stderr, "Done setting baudrate\n");
	}
}

void
proc_bdaddr()
{
	hci_send_cmd(hci_write_bd_addr, sizeof(hci_write_bd_addr));

	read_event(uart_fd, buffer);
}

void
proc_enable_lpm()
{
	hci_send_cmd(hci_write_sleep_mode, sizeof(hci_write_sleep_mode));

	read_event(uart_fd, buffer);
}

void
proc_scopcm()
{
	hci_send_cmd(hci_write_sco_pcm_int,
		sizeof(hci_write_sco_pcm_int));

	read_event(uart_fd, buffer);

	hci_send_cmd(hci_write_pcm_data_format,
		sizeof(hci_write_pcm_data_format));

	read_event(uart_fd, buffer);
}

void
proc_i2s()
{
	hci_send_cmd(hci_write_i2spcm_interface_param,
		sizeof(hci_write_i2spcm_interface_param));

	read_event(uart_fd, buffer);
}

void
proc_enable_hci()
{
	int i = N_HCI;
	int proto = HCI_UART_H4;
	if (ioctl(uart_fd, TIOCSETD, &i) < 0) {
		fprintf(stderr, "Can't set line discipline\n");
		return;
	}

	if (ioctl(uart_fd, HCIUARTSETPROTO, proto) < 0) {
		fprintf(stderr, "Can't set hci protocol\n");
		return;
	}
	fprintf(stderr, "Done setting line discpline\n");
	return;
}

#ifdef ANDROID
void
read_default_bdaddr()
{
	int sz;
	int fd;

	char path[PROPERTY_VALUE_MAX];

	char bdaddr[18];
	int len = 17;
	memset(bdaddr, 0, (len + 1) * sizeof(char));

	property_get("ro.bt.bdaddr_path", path, "");
	if (path[0] == 0)
		return;

	fd = open(path, O_RDONLY);
	if (fd < 0) {
		fprintf(stderr, "open(%s) failed: %s (%d)", path, strerror(errno),
				errno);
		return;
	}

	sz = read(fd, bdaddr, len);
	if (sz < 0) {
		fprintf(stderr, "read(%s) failed: %s (%d)", path, strerror(errno),
				errno);
		close(fd);
		return;
	} else if (sz != len) {
		fprintf(stderr, "read(%s) unexpected size %d", path, sz);
		close(fd);
		return;
	}

	if (debug) {
		printf("Read default bdaddr of %s\n", bdaddr);
	}

	parse_bdaddr(bdaddr);
}
#endif


int
main (int argc, char **argv)
{
#ifdef ANDROID
	read_default_bdaddr();
#endif

	if (parse_cmd_line(argc, argv)) {
		exit(1);
	}

	if (uart_fd < 0) {
		exit(2);
	}

	init_uart();

	proc_reset();

	if (use_baudrate_for_download) {
		if (termios_baudrate) {
			proc_baudrate();
		}
	}

	if (hcdfile_fd > 0) {
		proc_patchram();
	}

	if (termios_baudrate) {
		proc_baudrate();
	}

	if (bdaddr_flag) {
		proc_bdaddr();
	}

	if (enable_lpm) {
		proc_enable_lpm();
	}

	if (scopcm) {
		proc_scopcm();
	}

	if (i2s) {
		proc_i2s();
	}

	if (enable_hci) {
		proc_enable_hci();

		while (1) {
			sleep(UINT_MAX);
		}
	}

	exit(0);
}

# ./patch  -d  --patchram bcm43438a1.hcd  --enable_hci --bd_addr 11:22:33:44:55:
66 --no2bytes --tosleep 1000 /dev/ttyS1
option patchram with arg bcm43438a1.hcd
option enable_hci
option bd_addr with arg 11:22:33:44:55:66
option no2bytes
option tosleep with arg 1000
/dev/ttyS1
writing
01 03 0c 00


writing
01 03 0c 00
writing
01 03 0c 00


writing
01 03 0c 00

初始化命令没有回复.










git clone https://github.com/bluekitchen/btstack.git

cd btstack/port/posix-h4

make CC=/opt/buildroot-2018.08.2/output/host/bin/arm-buildroot-linux-gnueabihf-gcc





离线

#3 2019-06-10 20:12:24

zhenfanhei
会员
注册时间: 2018-01-18
已发帖子: 301
积分: 231
个人网站

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

果然坛主发贴了,搞起BT来了,PCM都还连上去了,到时候可以弄弄蓝牙音箱功能什么的





离线

楼主 #4 2019-06-11 10:21:42

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,349
积分: 9202

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

用一楼的方法没有驱动,用二楼的方法在其他V3s板子搞定了AP6212蓝牙,晚些时候我再到华嵌S3板子测试。





离线

#5 2019-06-11 11:08:11

zhenfanhei
会员
注册时间: 2018-01-18
已发帖子: 301
积分: 231
个人网站

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

晕哥威武,不过说蓝牙还真是有点弱,不能一连一大片,也不能高速,也不能远距离





离线

楼主 #6 2019-06-11 11:18:03

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,349
积分: 9202

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

Bluetooth2.1 貌似只能连一个, 4.x 就可以连一大片了, 不过这两个协议不是兼容关系。

BCM43438同时支持 Bluetooth2.1 和 4.x (BLE),

https://github.com/bluekitchen/btstack 同时支持这两种协议栈。



https://whycan.cn/t_245.html#p5165





离线

#7 2019-06-11 14:53:15

zhenfanhei
会员
注册时间: 2018-01-18
已发帖子: 301
积分: 231
个人网站

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

多点连接接多个传感器还是比较有用处的,这个可以,





离线

#8 2020-02-01 23:41:49

aodzip
会员
注册时间: 2019-10-15
已发帖子: 130
积分: 100

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

加一铲子土,硬核开蓝牙。

我是自己后焊的BCM43438,表面喷了黑漆,不是亮晶晶的那款,hcd要用这个。
https://github.com/armbian/firmware/blob/master/ap6212/bcm43438a1.hcd

devmem 0x01c20828 32 0x771733 # 设置PB11工作模式为输出

devmem 0x01c20834 32 0x804 # 设置PB11输出高电平

brcm_patchram_plus -d  --patchram /lib/firmware/brcm/bcm43438a1.hcd --enable_hci --bd_addr 11:22:33:44:55:66 --no2bytes --tosleep 1000 /dev/ttyS1
跑完了好像会一直卡死,直接^C掉

hciattach /dev/ttyS1 bcm43xx 1500000 flow bdaddr 11:22:33:44:55:66
挂载HCI设备

期待大佬出DTS版,devmem一点都不清真

固件下载与挂载设备

...
01 03 0c 00
received 7
04 0e 04 01 03 0c 00
writing
01 01 fc 06 66 55 44 33 22 11
received 7
04 0e 04 01 01 fc 00
Done setting line discpline
^C
# hciattach /dev/ttyS1 bcm43xx 1500000 flow bdaddr 11:22:33:44:55:66
bcm43xx_init
Patch not found, continue anyway
Set BDADDR UART: 11:22:33:44:55:66
Set Controller UART speed to 1500000 bit/s
Device setup complete
# hciconfig -a
hci0:   Type: Primary  Bus: UART
        BD Address: 11:22:33:44:55:66  ACL MTU: 1021:8  SCO MTU: 64:1
        DOWN
        RX bytes:612 acl:0 sco:0 events:30 errors:0
        TX bytes:398 acl:0 sco:0 commands:30 errors:0
        Features: 0xbf 0xfe 0xcf 0xfe 0xdb 0xff 0x7b 0x87
        Packet type: DM1 DM3 DM5 DH1 DH3 DH5 HV1 HV2 HV3
        Link policy: RSWITCH SNIFF
        Link mode: SLAVE ACCEPT

蓝牙发现

# hciconfig hci0 up
# hcitool scan
Scanning ...
        3C:CD:36:**:**:**       Xin的iPhone
        A0:C5:89:**:**:**       ThinkPad-X1

最近编辑记录 aodzip (2020-02-01 23:49:05)

离线

#9 2020-02-02 12:10:35

aodzip
会员
注册时间: 2019-10-15
已发帖子: 130
积分: 100

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

简单的UART1四线DTS

&pio {
    uart1_rcts_pins: uart1_rcts_pins {
        pins = "PG8", "PG9";
        function = "uart1";
        bias-pull-up;
    };
};

&uart1 {
    pinctrl-0 = <&uart1_pins_a>, <&uart1_rcts_pins>;
    pinctrl-names = "default";
    status = "okay";
};

最近编辑记录 aodzip (2020-02-02 12:25:19)

离线

#10 2020-02-16 00:04:44

aodzip
会员
注册时间: 2019-10-15
已发帖子: 130
积分: 100

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

好像我的BCM43438A1在patchram之前不响应和获取芯片版本相关的指令,有可能是早期版本的BUG。
但是这不会影响patchram的写入,可以修改Linux驱动暂时忽略掉这个问题,当patchram写入后,Linux会重新尝试获取芯片信息。
linux/drivers/bluetooth/btbcm.c

	/* Read Local Version Info */
	skb = btbcm_read_local_version(hdev);
	if (IS_ERR(skb)){
		if(hdev->bus == HCI_UART){
			ver = 0;
			rev = 0;
			subver = 0;
			bt_dev_info(hdev, "BCM: btbcm_read_local_version failed!\n");
		}else{
			return PTR_ERR(skb);
		}
	}else{
		ver = (struct hci_rp_read_local_version *)skb->data;
		rev = le16_to_cpu(ver->hci_rev);
		subver = le16_to_cpu(ver->lmp_subver);
		kfree_skb(skb);
		/* Read controller information */
		if (!reinit) {
			err = btbcm_read_info(hdev);
			if (err)
				return err;
		}
	}

离线

#11 2020-02-16 00:15:42

aodzip
会员
注册时间: 2019-10-15
已发帖子: 130
积分: 100

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

配套上面代码修改的DTS,可以实现几乎完美的BT

&pio {
    uart1_rcts_pins: uart1_rcts_pins {
        pins = "PG8", "PG9";
        function = "uart1";
        bias-pull-up;
    };
};

&uart1 {
    pinctrl-0 = <&uart1_pins_a>, <&uart1_rcts_pins>;
    pinctrl-names = "default";
    status = "okay";
    bluetooth {
        compatible = "brcm,bcm43438-bt";
        clocks = <&rtc 1>;
        clock-names = "lpo";
        vbat-supply = <&reg_vcc3v3>;
        vddio-supply = <&reg_vcc3v3>;
        device-wakeup-gpios = <&pio 1 13 GPIO_ACTIVE_HIGH>;
        host-wakeup-gpios = <&pio 1 12 GPIO_ACTIVE_HIGH>;
        shutdown-gpios = <&pio 1 11 GPIO_ACTIVE_HIGH>;
    };
};

最近编辑记录 aodzip (2020-02-16 00:16:16)

离线

楼主 #12 2020-02-16 19:31:16

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,349
积分: 9202

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

@aodzip 大赞, 感谢分享!





离线

#13 2020-02-16 19:52:33

aodzip
会员
注册时间: 2019-10-15
已发帖子: 130
积分: 100

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

晕哥 说:

@aodzip 大赞, 感谢分享!

晕哥大佬过奖

离线

#14 2020-02-28 11:59:43

tobunto
会员
注册时间: 2019-03-04
已发帖子: 9
积分: 9

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

请教下,我在3.10内核,debian系统下调试AP6212蓝牙功能,在使用brcm_patchram_plus配置初始化参数,加载固件时很快结束,没看到有命令应答,在hciattach时会发生超时错误,hciattach命令只有使用any才会产生hci0设备,但hci0设备的地址都为空,也没发送接收字节,没法启动蓝牙,不知道哪儿出问题了。
bluetooth1.jpgbluetooth2.jpg

离线

#15 2020-02-28 15:27:55

我心飞翔
会员
注册时间: 2019-12-25
已发帖子: 82
积分: 82

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

enable_hci 加一个 -d 参数, 可以输出调试信息。

离线

#16 2020-02-28 15:36:06

tobunto
会员
注册时间: 2019-03-04
已发帖子: 9
积分: 9

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

这就是加了调试信息的-d,串口终端命令行输入问题导致的没显示出来,具体命令是
brcm_patchram_plus -d  -patchram /lib/firmware/bcm4343a1.hcd -enable_hci -bd_addr 11:22:33:44:55:66 -no2bytes -tosleep 1000 /dev/ttySC0

离线

#17 2020-03-01 12:13:37

tobunto
会员
注册时间: 2019-03-04
已发帖子: 9
积分: 9

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

@晕哥
       晕哥,我根据你2楼的连接,重新下载brcm_patchram_plus.c源码,编译后再执行初始化,有初始化命令01 03 0c 00发出,但没回应,跟你2楼情况有些一样,你当时没回应问题怎么解决的。

离线

楼主 #18 2020-03-01 12:20:14

晕哥
管理员
注册时间: 2017-09-06
已发帖子: 9,349
积分: 9202

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

注意电源引脚,看 bt 是否使能了





离线

#19 2020-03-01 12:26:15

aodzip
会员
注册时间: 2019-10-15
已发帖子: 130
积分: 100

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

华嵌的板子吗

devmem 0x01c20828 32 0x771733 # 设置PB11工作模式为输出
devmem 0x01c20834 32 0x804 # 设置PB11输出高电平

这两条跑一下,可以临时测试用

(所以我自己做的板子把WL和BT的使能调整到AXP209上了

离线

#20 2020-03-01 12:28:43

tobunto
会员
注册时间: 2019-03-04
已发帖子: 9
积分: 9

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

君正的x1000E,我文件系统下手动操作下bt使能和唤醒管脚试试

离线

#21 2020-03-13 18:43:05

AaronHo
会员
注册时间: 2020-03-08
已发帖子: 13
积分: 13

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

不错的技术贴.回去参考一下,正在准备搞定5.5.9内核AP6212 wifi驱动.

离线

#22 2020-06-08 17:44:39

checkout
会员
注册时间: 2018-11-09
已发帖子: 173
积分: 168

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

请问这个解决了吗?
我在nanopi-m1-plus上按照2楼的方法,也出现Bluetooth hci0 timeout command 0x1003 tx timeout的错误。
真系头大

tobunto 说:

请教下,我在3.10内核,debian系统下调试AP6212蓝牙功能,在使用brcm_patchram_plus配置初始化参数,加载固件时很快结束,没看到有命令应答,在hciattach时会发生超时错误,hciattach命令只有使用any才会产生hci0设备,但hci0设备的地址都为空,也没发送接收字节,没法启动蓝牙,不知道哪儿出问题了。
bluetooth1.jpgbluetooth2.jpg

最近编辑记录 checkout (2020-06-08 17:45:09)

离线

#23 2020-07-13 13:58:34

桓恒亘
会员
注册时间: 2020-07-13
已发帖子: 1
积分: 1

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

各位大神有在 全志 Camdroid上调试过 AP6212 的蓝牙功能吗?

离线

#24 2020-07-14 13:21:24

MyWaKeng
会员
注册时间: 2020-07-14
已发帖子: 22
积分: 1.5

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

貌似这板子折腾成果不错,有空我也搞一个玩玩。

离线

#25 2023-11-10 17:28:02

muxi01
会员
注册时间: 2020-10-24
已发帖子: 62
积分: 144

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

@晕哥,请教一下brcmfmac43430-sdio.clm_blob 这个文件是做什么的,我目前/lib/brcm目录下只放了brcmfmac43430-sdio.txt brcmfmac43430-sdio.bin文件,加载模块的时候,可以识别到wlan0,但是配置不了WIFI。

# wpa_supplicant -Dnl80211 -iwlan0 -c/etc/wpa_supplicant.conf
Successfully initialized wpa_supplicant
wlan0: CTRL-EVENT-SCAN-FAILED ret=-22 retry=1
wlan0: CTRL-EVENT-SCAN-FAILED ret=-22 retry=1
wlan0: CTRL-EVENT-SCAN-FAILED ret=-22 retry=1
wlan0: CTRL-EVENT-SCAN-FAILED ret=-22 retry=1
wlan0: CTRL-EVENT-SCAN-FAILED ret=-22 retry=1
^Cwlan0: CTRL-EVENT-DSCP-POLICY clear_all
wlan0: CTRL-EVENT-DSCP-POLICY clear_all
nl80211: deinit ifname=wlan0 disabled_11b_rates=0
wlan0: CTRL-EVENT-TERMINATING
#  iwconfig  wlan0
wlan0     IEEE 802.11  ESSID:off/any
          Mode:Managed  Access Point: Not-Associated   Tx-Power=31 dBm
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:on

#  iw
iwconfig  iwgetid   iwlist    iwpriv    iwspy
#  iwlist wlan0 scanning
wlan0     Interface doesn't support scanning : Invalid argument



# iwconfig  wlan0 essid wifishare key qwer1234
Error for wireless request "Set Encode" (8B2A) :
    invalid argument "qwer1234".

# iwlist  wlan0 scanning
[ 1658.378623] ieee80211 phy0: brcmf_run_escan: error (-52)
[ 1658.384010] ieee80211 phy0: brcmf_cfg80211_scan: scan error (-52)
wlan0     Interface doesn't support scanning : Invalid exchange

最近编辑记录 muxi01 (2023-11-10 17:46:40)

离线

#26 2023-11-13 14:23:50

muxi01
会员
注册时间: 2020-10-24
已发帖子: 62
积分: 144

Re: 使用华嵌HQEmbed S3 开发板, 驱动经典的无线芯片 BCM43438(AP6212) 的 蓝牙Bluetooth

@muxi01
bin文件更换成fw_bcm43438b.bin就可以了

离线

页脚

工信部备案:粤ICP备20025096号 Powered by FluxBB

感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信(wechat): whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn