#include <stdint.h> | |
#include <unistd.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdarg.h> | |
#include <getopt.h> | |
#include <fcntl.h> | |
#include <sys/ioctl.h> | |
#include <linux/types.h> | |
#include <linux/spi/spidev.h> | |
#define SPI_DEBUG 1 | |
#define DEBUG_SWITCH 1 /* 打开调试信息打印功能 */ | |
#define ERR_DEBUG_SWITCH 1 /* 打印错误信息打印功能 */ | |
/** | |
* 简单打印调试信息 | |
*/ | |
#if DEBUG_SWITCH | |
#define pr_debug(fmt,args...) printf(fmt, ##args) | |
#else | |
#define pr_debug(fmt,args...) /*do nothing */ | |
#endif | |
/** | |
* 错误信息打印 | |
* 自动打印发生错误时代码所在的位置 | |
*/ | |
#if ERR_DEBUG_SWITCH | |
#define pr_err(fmt,args...) printf("\nError:\nFile:<%s> Fun:[%s] Line:%d\n "fmt, __FILE__, __FUNCTION__, __LINE__, ##args) | |
#else | |
#define pr_err(fmt,args...) /*do nothing */ | |
#endif | |
/* | |
* 说明:SPI通讯实现 | |
* 方式一: 同时发送与接收实现函数: SPI_Transfer() | |
* 方式二:发送与接收分开来实现 | |
* SPI_Write() 只发送 | |
* SPI_Read() 只接收 | |
* 两种方式不同之处:方式一,在发的过程中也在接收,第二种方式,收与发单独进行 | |
* Created on: 2013-5-28 | |
* Author: lzy | |
*/ | |
static char device[64] = {0}; | |
static uint8_t mode = 0; /* SPI通信使用全双工,设置CPOL=0,CPHA=0。 */ | |
static uint8_t bits = 8; /* 8bits读写,MSB first。*/ | |
static uint32_t speed = 12 * 1000 * 1000;/* 设置12M传输速度 */ | |
static uint16_t delay = 0; | |
static int g_SPI_Fd = 0; | |
static void pabort(const char *s) | |
{ | |
perror(s); | |
abort(); | |
} | |
/** | |
* 功 能:同步数据传输 | |
* 入口参数 : | |
* TxBuf -> 发送数据首地址 | |
* len -> 交换数据的长度 | |
* 出口参数: | |
* RxBuf -> 接收数据缓冲区 | |
* 返回值:0 成功 | |
* 开发人员:Lzy 2013-5-22 | |
*/ | |
int SPI_Transfer(const uint8_t *TxBuf, uint8_t *RxBuf, int len) | |
{ | |
int ret; | |
int fd = g_SPI_Fd; | |
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) | |
pr_err("can't send spi message"); | |
else | |
{ | |
#if SPI_DEBUG | |
int i; | |
pr_debug("\nmbtk: send spi message Succeed"); | |
pr_debug("\nmbtk: SPI Send [Len:%d]: ", len); | |
for (i = 0; i < len; i++) | |
{ | |
if (i % 8 == 0) | |
printf("\n\t"); | |
printf("0x%02X ", TxBuf[i]); | |
} | |
printf("\n"); | |
pr_debug("mbtk: SPI Receive [len:%d]:", len); | |
for (i = 0; i < len; i++) | |
{ | |
if (i % 8 == 0) | |
printf("\n\t"); | |
printf("0x%02X ", RxBuf[i]); | |
} | |
printf("\n"); | |
#endif | |
} | |
return ret; | |
} | |
/** | |
* 功 能:发送数据 | |
* 入口参数 : | |
* TxBuf -> 发送数据首地址 | |
* len -> 发送与长度 | |
*返回值:0 成功 | |
* 开发人员:Lzy 2013-5-22 | |
*/ | |
int SPI_Write(uint8_t *TxBuf, int len) | |
{ | |
int ret; | |
int fd = g_SPI_Fd; | |
ret = write(fd, TxBuf, len); | |
if (ret < 0) | |
pr_err("SPI Write error\n"); | |
else | |
{ | |
#if SPI_DEBUG | |
int i; | |
pr_debug("\nSPI Write [Len:%d]: ", len); | |
for (i = 0; i < len; i++) | |
{ | |
if (i % 8 == 0) | |
printf("\n\t"); | |
printf("0x%02X ", TxBuf[i]); | |
} | |
printf("\n"); | |
#endif | |
} | |
return ret; | |
} | |
/** | |
* 功 能:接收数据 | |
* 出口参数: | |
* RxBuf -> 接收数据缓冲区 | |
* rtn -> 接收到的长度 | |
* 返回值:>=0 成功 | |
* 开发人员:Lzy 2013-5-22 | |
*/ | |
int SPI_Read(uint8_t *RxBuf, int len) | |
{ | |
int ret; | |
int fd = g_SPI_Fd; | |
ret = read(fd, RxBuf, len); | |
if (ret < 0) | |
pr_err("SPI Read error\n"); | |
else | |
{ | |
#if SPI_DEBUG | |
int i; | |
pr_debug("SPI Read [len:%d]:", len); | |
for (i = 0; i < len; i++) | |
{ | |
if (i % 8 == 0) | |
printf("\n\t"); | |
printf("0x%02X ", RxBuf[i]); | |
} | |
printf("\n"); | |
#endif | |
} | |
return ret; | |
} | |
/** | |
* 功 能:打开设备 并初始化设备 | |
* 入口参数 : | |
* 出口参数: | |
* 返回值:0 表示已打开 0XF1 表示SPI已打开 其它出错 | |
* 开发人员:Lzy 2013-5-22 | |
*/ | |
int SPI_Open(void) | |
{ | |
int fd; | |
int ret = 0; | |
if (g_SPI_Fd != 0) /* 设备已打开 */ | |
return 0xF1; | |
fd = open(device, O_RDWR); | |
if (fd < 0) | |
pabort("can't open device"); | |
else | |
pr_debug("SPI - Open Succeed. Start Init SPI...\n"); | |
g_SPI_Fd = 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"); | |
pr_debug("spi mode: %d\n", mode); | |
pr_debug("bits per word: %d\n", bits); | |
pr_debug("max speed: %d KHz (%d MHz)\n", speed / 1000, speed / 1000 / 1000); | |
return ret; | |
} | |
/** | |
* 功 能:关闭SPI模块 | |
*/ | |
int SPI_Close(void) | |
{ | |
int fd = g_SPI_Fd; | |
if (fd == 0) /* SPI是否已经打开*/ | |
return 0; | |
close(fd); | |
g_SPI_Fd = 0; | |
return 0; | |
} | |
/** | |
* 功 能:自发自收测试程序 | |
* 接收到的数据与发送的数据如果不一样 ,则失败 | |
* 说明: | |
* 在硬件上需要把输入与输出引脚短跑 | |
* 开发人员:Lzy 2013-5-22 | |
*/ | |
int SPI_LookBackTest(void) | |
{ | |
int ret, i; | |
const int BufSize = 16; | |
uint8_t tx[BufSize], rx[BufSize]; | |
bzero(rx, sizeof(rx)); | |
for (i = 0; i < BufSize; i++) | |
tx[i] = i; | |
pr_debug("\nSPI - LookBack Mode Test...\n"); | |
ret = SPI_Transfer(tx, rx, BufSize); | |
if (ret > 1) | |
{ | |
ret = memcmp(tx, rx, BufSize); | |
if (ret != 0) | |
{ | |
pr_err("LookBack Mode Test error\n"); | |
// pabort("error"); | |
} | |
else | |
pr_debug("SPI - LookBack Mode OK\n"); | |
} | |
return ret; | |
} | |
int main(int argc, char *argv[]) | |
{ | |
int ret = 0; | |
if(argc == 2) | |
{ | |
memset(device, 0x0, 64); | |
memcpy(device, argv[1], strlen(argv[1])); | |
printf("device: %s\n", device); | |
} | |
else | |
{ | |
printf("format: mbtk_spi_write <dev>\n"); | |
return -1; | |
} | |
ret = SPI_Open(); | |
if (ret) | |
return ret; | |
SPI_LookBackTest(); | |
// unsigned char buf[10]; | |
// SPI_Write(buf, 10); | |
// SPI_Read(buf, 10); | |
SPI_Close(); | |
return 0; | |
} | |