准备工作:
1.搭建adbwireless 环境
参考:https://blog.youkuaiyun.com/Chhjnavy/article/details/97643584
https://blog.youkuaiyun.com/Chhjnavy/article/details/98845930
2.熟悉使用jni 将C与java互通
参考:https://blog.youkuaiyun.com/Chhjnavy/article/details/94721080
目标板:rk3288 android
系统:android7.1.2
1.源码根目录:/kernel/arch/arm/boot/dts 在rk3288-miniarm.dts 文件中添加spi 设备节点
&spi2 {
status = "okay";
max-freq = <50000000>;
spidev@0 {
compatible = "rockchip,spi_tinker";
reg = <0>;
spi-max-frequency = <50000000>;
spi-cpha = <1>;
};
spidev@1 {
compatible = "rockchip,spi_tinker";
reg = <1>;
spi-max-frequency = <50000000>;
spi-cpha = <1>;
};
};
2.make menuconfig 添加驱动模块
3.kernel 重新编译后,将最终的镜像烧录SD卡,通过终端可以在/dev 下看到spidev2.0 spidev2.1 两个设备节点
其中 spidev2.0 spidev2.1 中的数字2 表示bus num ,小数点后的0 和 1 分别表示使用的是选通信号cs0 ,cs1
对应的物理引脚如下所示:
使用杜邦线将rk3288 的spi 引脚与flash spi引脚对接 : GP8B1_SPI2TXD = DI 、 GP8B0_SPI2RXD = DO
GP8A6_SPI2CLK = CLK 、 GP8A7_SPI2CSN0 = CS 、 GND = GND
4.通过open 打开spidev2.0 设备(CS 连接的是GP8A7_SPI2CSN0 )获取设备号
/*
* 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) {
perror( "can not open SPI device\n" );
}
ret = ioctl(fd, SPI_IOC_WR_MODE,&mode);
if (ret == -1)
LOGD("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE,&mode);
if (ret == -1)
LOGD("can't get spi mode");
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
LOGD("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
LOGD("can't get bits per word");
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
LOGD("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
LOGD("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;
}
5.通过 spi 提供的结构体 struct spi_ioc_transfer xfer[7]; 来配置spi 发送时序
/*
Command Type MX25L25645G
RDID 9Fh Manufacturer ID Memory Type Memory Density
C2 20 19
RES ABh Electronic ID
18
REMS 90h Manufacturer ID Device ID
C2 18
QPIID AFh Manufacturer ID Memory Type Memory Density
C2 20 19
*/
int SPI_readFlashID(unsigned int u8BusIndex)
{
int ret;
int fd;
uint8_t readIDCmd[1];
uint8_t readDummy[1];
uint8_t readDummy2[1];
uint8_t readADD[1];
uint8_t dataID[3] = {0};
fd = SPI_open(u8BusIndex);
if(fd < 0){
LOGD("fail open device ==================fd = %d", fd);
return -1;
}
struct spi_ioc_transfer xfer[7];
memset(xfer, 0, sizeof(xfer));
readIDCmd[0]=0x9F;
xfer[0].tx_buf =(unsigned long)readIDCmd;
xfer[0].len = 1;
readDummy[0]=0x00;
xfer[1].tx_buf =(unsigned long)readDummy;
xfer[1].len = 1;
readDummy2[0]=0x00;
xfer[2].tx_buf =(unsigned long)readDummy2;
xfer[2].len = 1;
readADD[0]=0x00;
xfer[3].tx_buf =(unsigned long)readADD;
xfer[3].len = 1;
xfer[4].rx_buf = (unsigned long)dataID;
xfer[4].len = 1;
xfer[5].rx_buf = (unsigned long)(dataID+1);
xfer[5].len = 1;
xfer[6].rx_buf = (unsigned long)(dataID+2);
xfer[6].len = 1;
ret = ioctl(fd, SPI_IOC_MESSAGE(7), xfer);
if (ret < 0)
{
LOGD("********************Error: SPI_IOC_MESSAGE\n");
return -1;
}
LOGD("dataID[0]************************************************* = %x", dataID[0]);
LOGD("dataID[1]************************************************* = %x", dataID[1]);
LOGD("dataID[2]************************************************* = %x", dataID[2]);
return ret;
}
6.在jni 中直接调用 函数 int SPI_readFlashID(unsigned int u8BusIndex) 即可打印看到spi ID ,完整code 如下:
#include <stdio.h>
#include<stdlib.h>
#include <math.h>
#include <linux/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <jni.h>
#include<android/log.h>
#include <unistd.h>
#include <getopt.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <linux/gpio.h>
#define TAG "myDemo-jni" // 这个是自定义的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类型
#define TAG "myDemo-jni" // 这个是自定义的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类型
#define _Included_com_example_t613_spi_Java_Interface
static unsigned char mode=SPI_MODE_0;
static unsigned char bits = 8;
static unsigned char delay = 10;
static unsigned int speed = 2200000;
#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) {
perror( "can not open SPI device\n" );
}
ret = ioctl(fd, SPI_IOC_WR_MODE,&mode);
if (ret == -1)
LOGD("can't set spi mode");
ret = ioctl(fd, SPI_IOC_RD_MODE,&mode);
if (ret == -1)
LOGD("can't get spi mode");
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
if (ret == -1)
LOGD("can't set bits per word");
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
if (ret == -1)
LOGD("can't get bits per word");
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
if (ret == -1)
LOGD("can't set max speed hz");
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
if (ret == -1)
LOGD("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);
}
/*
Command Type MX25L25645G
RDID 9Fh Manufacturer ID Memory Type Memory Density
C2 20 19
RES ABh Electronic ID
18
REMS 90h Manufacturer ID Device ID
C2 18
QPIID AFh Manufacturer ID Memory Type Memory Density
C2 20 19
*/
int SPI_readFlashID(unsigned int u8BusIndex)
{
int ret;
int fd;
uint8_t readIDCmd[1];
uint8_t readDummy[1];
uint8_t readDummy2[1];
uint8_t readADD[1];
uint8_t dataID[3] = {0};
fd = SPI_open(u8BusIndex);
if(fd < 0){
LOGD("fail open device ==================fd = %d", fd);
return -1;
}
struct spi_ioc_transfer xfer[7];
memset(xfer, 0, sizeof(xfer));
readIDCmd[0]=0x9F;
xfer[0].tx_buf =(unsigned long)readIDCmd;
xfer[0].len = 1;
readDummy[0]=0x00;
xfer[1].tx_buf =(unsigned long)readDummy;
xfer[1].len = 1;
readDummy2[0]=0x00;
xfer[2].tx_buf =(unsigned long)readDummy2;
xfer[2].len = 1;
readADD[0]=0x00;
xfer[3].tx_buf =(unsigned long)readADD;
xfer[3].len = 1;
xfer[4].rx_buf = (unsigned long)dataID;
xfer[4].len = 1;
xfer[5].rx_buf = (unsigned long)(dataID+1);
xfer[5].len = 1;
xfer[6].rx_buf = (unsigned long)(dataID+2);
xfer[6].len = 1;
ret = ioctl(fd, SPI_IOC_MESSAGE(7), xfer);
if (ret < 0)
{
LOGD("********************Error: SPI_IOC_MESSAGE\n");
return -1;
}
LOGD("dataID[0]************************************************* = %x", dataID[0]);
LOGD("dataID[1]************************************************* = %x", dataID[1]);
LOGD("dataID[2]************************************************* = %x", dataID[2]);
return ret;
}
extern "C"
{
JNIEXPORT jbyteArray JNICALL Java_com_example_t613_1spi_Java_1Interface_SPI_1read(JNIEnv *env, jobject instance, jbyte u8BusIndex, jint u32RegStart, jint nLen)
{
int nRet;
unsigned char u8Read[2] = {0};
int szTmp[1] = {-1};
jbyteArray jResult = env->NewByteArray(nLen + 1);
unsigned char *pTmp = (unsigned char*)malloc(nLen + 1);
if(!pTmp) {
env->SetByteArrayRegion(jResult, 0, 1, (jbyte*)szTmp);
}else {
nRet = SPI_readFlashID((unsigned char)u8BusIndex);
for(int i = 0; i < nLen; i++)
{
pTmp[i + 1] = u8Read[i];
}
pTmp[0] = nRet;
if(nRet)
{
env->SetByteArrayRegion(jResult, 0, 1, (jbyte*)pTmp);
}
else
{
env->SetByteArrayRegion(jResult, 0, nLen + 1, (jbyte*)pTmp);
}
free(pTmp);
}
LOGD("=================================================================");
return jResult;
}
JNIEXPORT jint JNICALL Java_com_example_t613_1spi_Java_1Interface_SPI_1write(JNIEnv *env, jobject instance, jbyte u8BusIndex, jint u32RegStart, jbyteArray _szBufWrite)
{
jint nRet;
jint nLen = env->GetArrayLength(_szBufWrite);
jbyte *pszWrite = env->GetByteArrayElements(_szBufWrite, NULL);
for(int i = 0; i < nLen; i++)
{
if(nRet) break;
}
env->ReleaseByteArrayElements(_szBufWrite, pszWrite, 0);
return nRet;
}
}
注意:
1)通过终端给/dev/spidev2.0 可执行权限
chmod 777 /dev/spidev2.0
2)jni code 中只是调用一下,UI 中并没有显示出ID, ID 通过logcat 打印看到。
完整app code 链接如下(点击read 即可在android studio logcat 下看到打印的flash ID):https://download.youkuaiyun.com/download/chhjnavy/11644546