RK3288 android7.1.2 android studio 用户空间调用Linux spi_dev.c 通过spi ioctl 进行spi单字节/多字节读写(进阶篇六)

1.初始化open/close SPI device 

#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define TAG "terawins" // 这个是自定义的LOG的标识
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG ,__VA_ARGS__) // 定义LOGD类型
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,TAG ,__VA_ARGS__) // 定义LOGI类型
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,TAG ,__VA_ARGS__) // 定义LOGW类型
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,TAG ,__VA_ARGS__) // 定义LOGE类型
#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,TAG ,__VA_ARGS__) // 定义LOGF类型

static unsigned char mode=SPI_MODE_0;
static unsigned char bits = 8;
static unsigned char delay = 10;
static unsigned int speed = 10000000;

#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))

/**************************************************************************
 * unsigned char u8BusIndex 是从UI 中获取的使用spidev2.x  表示使用0 还是 1
 * 这里cs 硬件连接的是0
 *
 **************************************************************************/
int SPI_open(unsigned char u8BusIndex) {
    char szDev[16] = {0};
    int fd,ret;
    sprintf(szDev, "/dev/spidev2.%d", u8BusIndex);
    fd = open(szDev, O_RDWR);
    //LOGD("*************************************************fd = %d", fd);

    if (fd < 0) {
        LOGE( "can not open SPI device\n" );
    }

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

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

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

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


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

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

    LOGD("spi mode: %d\n", mode);
    LOGD("bits per word: %d\n", bits);
    LOGD("max speed: %d Hz (%d MHz)\n", speed, speed/1000000);

    return fd;
}

int SPI_close(int dev_fh) {
    return close(dev_fh);
}

2.SPI 单字节写

1)定义tx 长度 cmd + addr + data (6字节);

2).len 表示发送总数据的长度(cmd + addr + data);

3)ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   MESSAGE(1)表示:半双工;MESSAGE(2)表示全双工;

4)单字节写 rx 数据长度为与data 长度一致,写了1个字节rx就设定为1(根据实际情况,也不可不设定);

void SPI_write_single(int fd, int addr, unsigned char data) {

    int ret;
    uint8_t tx[6] = {0};
    uint8_t rx[1] = {0};

    tx[0] = 0x01;
    tx[1] = (unsigned char)(addr >> 24 & 0xFF);
    tx[2] = (unsigned char)(addr >> 16 & 0xFF);
    tx[3] = (unsigned char)(addr >> 8 & 0xFF);
    tx[4] = (unsigned char)(addr & 0xFF);
    tx[5] = data;

    struct spi_ioc_transfer tr = {
            .tx_buf = (unsigned long) tx,   //定义发送缓冲区指针

            .rx_buf = (unsigned long) rx,   //定义接收缓冲区指针

            .len = ARRAY_SIZE(tx),

            .delay_usecs = delay,

            .speed_hz = speed,

            .bits_per_word = bits,
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);//执行spidev.c中ioctl的default进行数据传输

    if (ret < 0) {
        LOGD("can't send spi message");
    }
}

3.SPI 单字节读

1)定义tx 长度 cmd + addr + Dummy(15字节) ,有些spi slave 读的时候需要发送一些固定数量的空字节之后,才开始读data,该例子的Dummy 数量为10 ,发送了十个0x00,之后rx开始接收数据(rx在第十六个数组rx[15]里存放了接收的数据);

2)tx和rx 的len 读的时候,数组长度设定为一致;

3)ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   MESSAGE(1)表示:半双工;MESSAGE(2)表示全双工;

unsigned char SPI_read_single(int fd, int addr) {

    int ret,i;
    uint8_t tx[16] = {0};
    uint8_t rx[16] = {0};

    tx[0] = 0x02;
    tx[1] = (unsigned char)(addr >> 24 & 0xFF);
    tx[2] = (unsigned char)(addr >> 16 & 0xFF);
    tx[3] = (unsigned char)(addr >> 8 & 0xFF);
    tx[4] = (unsigned char)(addr & 0xFF);

    for(i = 5;i < 16;i++){
        tx[i] = 0x00;
    }

    struct spi_ioc_transfer tr = {
            .tx_buf = (unsigned long) tx,   //定义发送缓冲区指针

            .rx_buf = (unsigned long) rx,   //定义接收缓冲区指针

            .len = ARRAY_SIZE(tx),

            .delay_usecs = delay,

            .speed_hz = speed,

            .bits_per_word = bits,
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);//执行spidev.c中ioctl的default进行数据传输

    if (ret < 0) {
        LOGD("can't send spi message");
    }

    return rx[15];
}

4.SPI 多字节写

1)定义tx 长度 cmd + addr + data ;

2).len 表示发送总数据的长度(cmd + addr + data);

3)ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   MESSAGE(1)表示:半双工;MESSAGE(2)表示全双工;

4)一般tx 缓存区的buffer 限定在4096,如果想每次burst 的data 大于4096 个,就要去修改spidev.c内容,修改后重新编译内核,如下;

static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);

static unsigned bufsiz = 4096;//tx 大小
module_param(bufsiz, uint, S_IRUGO);
MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");

 切记,tx 的大小4096 是总的cmd + addr + data 长度,所以如果每次burst data 数量等于4096,再加上cmd+addr >4096 ,buffer 就会爆掉;burst 指的是只发送一次cmd 和addr ,后面写很多个data;

void SPI_nbytes_write(int fd, int addr, unsigned char *data, unsigned int len) {

    int ret,i;
    uint8_t tx[4096] = {0};
    uint8_t rx[4096] = {0};

    tx[0] = 0x01;
    tx[1] = (unsigned char)(addr >> 24 & 0xFF);
    tx[2] = (unsigned char)(addr >> 16 & 0xFF);
    tx[3] = (unsigned char)(addr >> 8 & 0xFF);
    tx[4] = (unsigned char)(addr & 0xFF);

    for(i = 0;i

5.SPI 多字节读

1)定义tx 长度 cmd + addr + data ,rx 长度和tx一致;

2).len 表示发送总数据的长度(cmd + addr + data);

3)ioctl(fd, SPI_IOC_MESSAGE(1), &tr);   MESSAGE(1)表示:半双工;MESSAGE(2)表示全双工;

4)一般tx 缓存区的buffer 限定在4096,如果想每次burst 的data 大于4096 个,就要去修改spidev.c内容,修改后重新编译内核,如下;

static LIST_HEAD(device_list);
static DEFINE_MUTEX(device_list_lock);

static unsigned bufsiz = 4096;//tx 大小
module_param(bufsiz, uint, S_IRUGO);
MODULE_PARM_DESC(bufsiz, "data bytes in biggest supported SPI message");

 切记,rx 的大小4096 是总的cmd + addr + data 长度,所以如果每次burst data 数量等于4096,再加上cmd+addr >4096 ,buffer 就会爆掉;burst 指的是只发送一次cmd 和addr ,后面读很多个data; 

void SPI_nbyte_read(int fd, int addr, unsigned char *data, unsigned int len) {

    int ret,i;
    uint8_t tx[4096]={0};
    uint8_t rx[4096]={0};

    tx[0] = 0x02;
    tx[1] = (unsigned char)(addr >> 24 & 0xFF);
    tx[2] = (unsigned char)(addr >> 16 & 0xFF);
    tx[3] = (unsigned char)(addr >> 8 & 0xFF);
    tx[4] = (unsigned char)(addr & 0xFF);

    struct spi_ioc_transfer tr = {
            .tx_buf = (unsigned long) tx,   //定义发送缓冲区指针

            .rx_buf = (unsigned long) rx,   //定义接收缓冲区指针

            .len = 15+len,

            .delay_usecs = delay,

            .speed_hz = speed,

            .bits_per_word = bits,
    };

    ret = ioctl(fd, SPI_IOC_MESSAGE(2), &tr);//执行spidev.c中ioctl的default进行数据传输

    if (ret < 0) {
        LOGD("can't send spi message");
    }else {
        for(i = 0;i < len;i++){
            data[i] = rx[15+i];
        }
    }
}

rk3288 spi硬件连接可参考:https://blog.csdn.net/Chhjnavy/article/details/100158719

你可能感兴趣的:(RK3288,Linux,树莓派,rk3288,android,c/c++,ioctl,spidev)