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
下图是使用spi-pipe发送0x09 0x00 0x00的波形。
从波形可以看出spi-pip将三个字节分成三次发出,最显著的特点是CS信号不连续。
这种方式是无法与BC7602通讯成功的。
命令:printf '\x09\x00\x00' | spi-pipe -d /dev/spidev0.0 |hexdump -C
点击查看代码
#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;
}