RK3288 android7.1.2 android studio 用戶空間調用Linux spi_dev.c 通過spi ioctl 進行spi單字節/多字節讀寫(進階篇六)

1.初始化open/close SPI device 

#include <android/log.h>
#include <jni.h>
#include <cstdio>
#include <fcntl.h>
#include <cstdlib>
#include <unistd.h>
#include <linux/spi/spidev.h>

#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<len;i++){
        tx[5+i] = data[i];
        //LOGE("================data[i] = %x", data[i]);
    }
    struct spi_ioc_transfer tr = {
            .tx_buf = (unsigned long) tx,   //定義發送緩衝區指針

            .rx_buf = (unsigned long) rx,   //定義接收緩衝區指針

            .len = 5+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");
    }
}

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章