linux下使用spidev与蓝牙模块BC7602通讯(附波形图)

相关介绍

  • BC7602是一个蓝牙透传芯片,可以使用串口或者SPI与其通讯
  • spidev是linux下SPI的通用驱动
  • spi-pipe是开源spidev测试工具spitools中的命令

波形图

信号说明:

  • 黄色:CS
  • 绿色:CLK
  • 紫色:MOSI
  • 蓝色:MISO

SPI模式说明:

  • mode:0
  • lsb:0
  • bits:8
  • speed:1000000
  • spiready:0

下图是使用自己用c语言编写的spidev测试工具发送0x09 0x00 0x00的波形。
源码见文末。
命令:spitool -d /dev/spidev0.0 -s 1000000 -v 090000 -t
image
下图是使用spi-pipe发送0x09 0x00 0x00的波形。
从波形可以看出spi-pip将三个字节分成三次发出,最显著的特点是CS信号不连续。
这种方式是无法与BC7602通讯成功的。
命令:printf '\x09\x00\x00' | spi-pipe -d /dev/spidev0.0 |hexdump -C
image
image
image

点击查看代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <linux/ioctl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <getopt.h>
#include <linux/spi/spidev.h>

#define MAX_BUFF_SIZE 256
static int g_spiFd = 0;
static char mode = 0; /*  CPOL=0,CPHA=0。 */
static char bits = 8; /* 8bits,MSB first。*/
static unsigned short delay = 0;

static void pabort(const char *s)
{
	perror(s);
	abort();
}

int ascStr2Hex(char *pStr, char *pRec)
{
	int val = 0;
	char *pRecTmp = pRec;
	while (*pStr)
	{
		if (*pStr == ' ')
		{
			pStr++;
			continue;
		}
		if (sscanf(pStr, "%02X", &val) == 1)
		{
			*pRecTmp++ = val & 0xff;
			pStr += 2;
		}
		else
		{
			return 0;
		}
	}
	return pRecTmp - pRec;
}

int spiOpen(const char *dev, unsigned speed)
{
	int fd;
	int ret = 0;

	if (g_spiFd != 0)
		return 0xF1;

	fd = open(dev, O_RDWR);
	if (fd < 0)
		pabort("can't open device");
	else
		printf("SPI - Open Succeed. Start Init SPI...\n");

	g_spiFd = fd;
	/*
* spi mode
*/
	ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
	if (ret == -1)
		pabort("can't set spi mode");

	ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
	if (ret == -1)
		pabort("can't get spi mode");

	/*
* bits per word
*/
	ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't set bits per word");

	ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
	if (ret == -1)
		pabort("can't get bits per word");

	/*
* max speed hz
*/
	ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't set max speed hz");

	ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
	if (ret == -1)
		pabort("can't get max speed hz");

	printf("spi mode: %d\n", mode);
	printf("bits per word: %d\n", bits);
	printf("max speed: %d KHz (%d MHz)\n", speed / 1000, speed / 1000 / 1000);

	return ret;
}

int spiClose(void)
{
	int fd = g_spiFd;

	if (fd == 0)
	{
		return 0;
	}
	close(fd);
	g_spiFd = 0;

	return 0;
}

int spiWrite(char *pTxBuf, int len)
{
	int ret;
	int fd = g_spiFd;

	ret = write(fd, pTxBuf, len);
	if (ret < 0)
	{
		perror("SPI Write error");
	}
	return ret;
}

int spiRead(char *pRxBuf, int len)
{
	int ret;
	int fd = g_spiFd;
	ret = read(fd, pRxBuf, len);
	if (ret < 0)
	{
		perror("SPI Read error");
	}
	return ret;
}

int spiTransfer(const char *txBuf, char *rxBuf, int len)
{
	int ret;
	int fd = g_spiFd;

	struct spi_ioc_transfer tr = {
		.tx_buf = (unsigned long)txBuf,
		.rx_buf = (unsigned long)rxBuf,
		.len = len,
		.delay_usecs = delay,
	};

	ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
	if (ret < 1)
	{
		printf("can't send spi message\n");
	}
	return ret;
}

void print_usage(FILE *stream, int exit_code)
{
	fprintf(stream, "Usage: option [ dev... ] \n");
	fprintf(stream,
			"\t-h  --help     Display this usage information.\n"
			"\t-l  --loop     Auto repeat ms,0 means not auto repeat\n"
			"\t-t  --together Receive at the same time when sending\n"
			"\t-d  --device   E.g. /dev/spidev0.0\n"
			"\t-s  --speed    E.g. 10M:10000000\n"
			"\t-v  --value    The cmd hex string\n"
			"\t-r  --read     Read bytes count\n");
	exit(exit_code);
}

int main(int argc, char *argv[])
{
	char *pWriteBuf = "35 32 30 31 33 31 34";
	char readBuf[MAX_BUFF_SIZE];
	int i = 0, len = 0, nread = 0, loop = 0, together = 0;
	int needRead = 0;
	int next_option;
	unsigned speed;
	char *device;
	int speed_flag = 0, device_flag = 0;
	const char *const short_options = "hl:td:s:v:r:";
	char cmd[MAX_BUFF_SIZE] = {0};

	const struct option long_options[] = {
		{"help", 0, NULL, 'h'},
		{"loop", 1, NULL, 'l'},
		{"together", 0, NULL, 't'},
		{"device", 1, NULL, 'd'},
		{"speed", 1, NULL, 's'},
		{"value", 1, NULL, 'v'},
		{"read", 1, NULL, 'r'},
		{NULL, 0, NULL, 0}};

	if (argc < 2)
	{
		print_usage(stdout, 0);
		exit(0);
	}

	while (1)
	{
		next_option = getopt_long(argc, argv, short_options, long_options, NULL);
		if (next_option < 0)
			break;
		switch (next_option)
		{
		case 'h':
			print_usage(stdout, 0);
			break;
		case 'l':
			loop = atoi(optarg);
			break;
		case 't':
			together = 1;
			break;
		case 'd':
			device = optarg;
			device_flag = 1;
			break;
		case 's':
			speed = atoi(optarg);
			speed_flag = 1;
			break;
		case 'v':
			pWriteBuf = optarg;
			break;
		case 'r':
			needRead = atoi(optarg);
			needRead = needRead > MAX_BUFF_SIZE ? 256 : needRead;
			break;
		case '?':
			print_usage(stderr, 1);
			break;
		default:
			abort();
		}
	}

	if ((!device_flag) || (!speed_flag))
	{
		print_usage(stderr, 1);
		exit(0);
	}

	len = ascStr2Hex(pWriteBuf, cmd);
	if (len == 0)
	{
		perror("cmd format failed");
		return -1;
	}

	spiOpen(device, speed);
	do
	{
		printf("SEND[%03d]: ", len);
		for (i = 0; i < len; i++)
			printf("%02X ", cmd[i]);
		printf("\n");
		if (together)
		{
			nread = spiTransfer(cmd, readBuf, len);
		}
		else
		{
			spiWrite(cmd, len);
			if (needRead)
			{
				nread = spiRead(readBuf, needRead);
			}
		}

		if (nread > 0)
		{
			printf("RECV[%03d]: ", nread);
			for (i = 0; i < nread; i++)
				printf("%02X ", readBuf[i]);
			printf("\n");
		}
		usleep(loop * 1000);
	} while (loop);
	return 0;
}

posted @ 2021-11-29 14:05  bert_qin  阅读(729)  评论(0编辑  收藏  举报