在freescale mx6DL 平台上添加spi资源,通过SPI总线挂载两个SPI设备,APP层通过JNI层访问设备文件,通过设备文件实现 SPI 通信
硬件平台 :freescale mx6DL
软件平台:Android4.4.2
系统:Ubuntu14.04
1. 打开系统SPI驱动
kernel_imx/drivers/spi/spi.c
kernel_imx/drivers/spi/spi_imx.c
kernel_imx/drivers/spi/spidev.c
查看 kernel_imx/drivers/spi/Makefile Kconfig文件,保证上面三个文件参加编译
2. kernel_imx/arch/arm/mach-mx6/board-mx6q_sabresd.c
在函数 static void __init mx6_sabresd_board_init(void) 尾部添加
#ifdef __LFL_SPI_
spi_device_init();
#endif//__LFL_SPI_
在当前文件的上部添加 #define __LFL_SPI_
#ifdef __LFL_SPI_
static iomux_v3_cfg_t mx6dl_sabresd_ecspi_pads[] = {
#if 1
/* SPI1 */
MX6DL_PAD_KEY_COL0__ECSPI1_SCLK,
MX6DL_PAD_KEY_ROW0__ECSPI1_MOSI,
MX6DL_PAD_KEY_COL1__ECSPI1_MISO,
MX6DL_PAD_KEY_ROW1__ECSPI1_SS0,
/* SPI2 */
#endif
/* I2C1
MX6DL_PAD_CSI0_DAT8__I2C1_SDA,
MX6DL_PAD_CSI0_DAT9__I2C1_SCL,
*/
/*
UART1 for debug
MX6DL_PAD_CSI0_DAT10__UART1_TXD,
MX6DL_PAD_CSI0_DAT11__UART1_RXD,
*/
/*
MX6DL_PAD_CSI0_DAT8__ECSPI2_SCLK,
MX6DL_PAD_CSI0_DAT9__ECSPI2_MOSI,
MX6DL_PAD_CSI0_DAT10__ECSPI2_MISO,
//MX6DL_PAD_CSI0_DAT11__ECSPI2_SS0,// 如果采用内部片选信号,屏蔽下一行GPIO的声明,打开本处声明
MX6DL_PAD_CSI0_DAT11__GPIO_5_29,
*/
MX6DL_PAD_EIM_CS0__ECSPI2_SCLK,
MX6DL_PAD_EIM_CS1__ECSPI2_MOSI,
MX6DL_PAD_EIM_OE__ECSPI2_MISO,
MX6DL_PAD_EIM_D24__ECSPI2_SS2,
/* SPI3
MX6DL_PAD_DISP0_DAT0__ECSPI3_SCLK,
MX6DL_PAD_DISP0_DAT1__ECSPI3_MOSI,
MX6DL_PAD_DISP0_DAT2__ECSPI3_MISO,
MX6DL_PAD_DISP0_DAT3__ECSPI3_SS0, */ // 如果采用内部片选信号,屏蔽下一行GPIO的声明,打开本处声明
//MX6DL_PAD_DISP0_DAT3__GPIO_4_24,
};
//如果采用内部片选信号,则不添加GPIO的声明
#define SABRESD_ECSPI2_CS0 IMX_GPIO_NR(5, 29) // spi2 cs0
#define SABRESD_ECSPI3_CS0 IMX_GPIO_NR(4, 24) // spi3 cs0
static int mx6q_sabresd_spi_cs1[] = {
MXC_SPI_CS(1),
// SABRESD_ECSPI1_CS0,
};
static const struct spi_imx_master mx6q_sabresd_spi_data1 __initconst = {
.chipselect = mx6q_sabresd_spi_cs1,
.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs1),
};
/* SPI2 cs0 */
static int mx6q_sabresd_spi_cs2[] = {
MXC_SPI_CS(2),// 如果采用内部片选信号,屏蔽下一行GPIO的声明,打开本处声明
// SABRESD_ECSPI2_CS0,
};
static const struct spi_imx_master mx6q_sabresd_spi_data2 __initconst = {
.chipselect = mx6q_sabresd_spi_cs2,
.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs2),
};
/* SPI3 cs0 */
static int mx6q_sabresd_spi_cs3[] = {
MXC_SPI_CS(3),// 如果采用内部片选信号,屏蔽下一行GPIO的声明,打开本处声明
// SABRESD_ECSPI3_CS0,
};
static const struct spi_imx_master mx6q_sabresd_spi_data3 __initconst = {
.chipselect = mx6q_sabresd_spi_cs3,
.num_chipselect = ARRAY_SIZE(mx6q_sabresd_spi_cs3),
};
//spi.h
//#define SPI_CPHA 0x01 /* clock phase */
//#define SPI_CPOL 0x02 /* clock polarity */
//#define SPI_MODE_0 (0|0) /* (original MicroWire) */
//#define SPI_MODE_1 (0|SPI_CPHA)
//#define SPI_MODE_2 (SPI_CPOL|0)
//#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
static struct spi_board_info imx6_sabresd_spi_device[] __initdata = {
#if 1
/* SPI1 */
{
.modalias = "spidev",
.max_speed_hz = 8000000, /* max spi clock (SCK) speed in HZ */
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_1 , // | SPI_CS_HIGH,
},
#endif
/* SPI2 */
{
.modalias = "spidev",
.max_speed_hz = 8000000, /* max spi clock (SCK) speed in HZ */
.bus_num = 1,
.chip_select = 0,
.mode = SPI_MODE_1 , // | SPI_CS_HIGH,
},
#if 0
/* SPI3 */
{
.modalias = "spi_imx",
.max_speed_hz = 8000000, /* max spi clock (SCK) speed in HZ */
.bus_num = 2,
.chip_select = 0,
.mode = SPI_MODE_1 , // | SPI_CS_HIGH,
},
#endif
};
static void spi_device_init(void)
{
printk("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi_device_init\n");
#if 1
printk("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi_device_init 000\n");
// 先初始化管脚
mxc_iomux_v3_setup_multiple_pads(mx6dl_sabresd_ecspi_pads,
ARRAY_SIZE(mx6dl_sabresd_ecspi_pads));
printk("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi_device_init 001\n");
// 添加片选信号
imx6q_add_ecspi(0, &mx6q_sabresd_spi_data1);
imx6q_add_ecspi(1, &mx6q_sabresd_spi_data2);
// imx6q_add_ecspi(2, &mx6q_sabresd_spi_data3);
printk("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi_device_init 002\n");
// 注册设备
spi_register_board_info(imx6_sabresd_spi_device, ARRAY_SIZE(imx6_sabresd_spi_device));
printk("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi_device_init 003\n");
#else
spi_register_board_info(imx6_sabresd_spi_nor_device,
ARRAY_SIZE(imx6_sabresd_spi_nor_device));
#endif
printk("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++ spi_device_init end\n");
}
#endif
3.修改设备权限,否则应用程序无法访问设备
参考: http://blog.csdn.net/richu123/article/details/51204036
/system/core/init/device.c
注意最后的返回值 0666
编译 ./mk_15_6.sh
4.烧写镜像
5.启动系统之后会在 /dev/ 目录生成如下两个设备
6. 编写测试程序
static const char *deviceSpi0 = "/dev/spidev0.0";
static const char *deviceSpi1 = "/dev/spidev1.0";
static U8 mode;
static U8 bits = 8;
static U32 speed = 7000000;
static U16 delay = 0;
static void setAddr(void)
{
int ret;
U8 tx[] = {
0x05, 0x08,
};
/*
U8 tx[] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0x40, 0x00, 0x00, 0x00, 0x00, 0x95,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xDE, 0xAD, 0xBE, 0xEF, 0xBA, 0xAD,
0xF0, 0x0D,
};
*/
U8 rx[ARRAY_SIZE(tx)] = {0};
struct spi_ioc_transfer tr = {
.tx_buf = /* NULL,// */(unsigned long)tx,
.rx_buf = /* NULL,// */ (unsigned long)rx,
.len = ARRAY_SIZE(tx),
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
};
// ret = read(fd,rx,ARRAY_SIZE(tx));
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
if (ret < 1)
pabort("can't send spi message");
for (ret = 0; ret < ARRAY_SIZE(tx); ret++) {
if (!(ret % 6))
cyVoiceE_SysPrintf("");
cyVoiceE_SysPrintf("%.2X ", rx[ret]);
}
cyVoiceE_SysPrintf("");
}
int testSpi(void)
{
int ret = 0;
//parse_opts(argc, argv); /* for what ,unknow*/
fd = open(deviceSpi0, O_RDWR);
if (fd < 0)
pabort("can't open device");
/*
* 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");
cyVoiceE_SysPrintf("spi mode: %d\n", mode);
cyVoiceE_SysPrintf("bits per word: %d\n", bits);
cyVoiceE_SysPrintf("max speed: %d Hz (%d KHz)\n", speed, speed/1000);
setAddr();
// close(fd);
return ret;
}
7. 添加 JNI层接口
JNIEXPORT void JNICALL Java_com_philisense_flxPrsmBusLib_prsmEngine_testSpi(JNIEnv* env,jobject thiz)
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmJNI_testSpi");
testSpi();
}
JNIEXPORT jlong JNICALL Java_com_philisense_flxPrsmBusLib_prsmEngine_createInstJNI(JNIEnv* env,jobject thiz,jint addr)
{
ST_FLX_PRSM_BUS *flxBus = NULL;
int ret = 0;
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_createInstJNI env =0x%x",env);
ret = flxPrsmBusCreateInst(&flxBus,addr);
if(ret >= 0)
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_createInstJNI success");
}
else
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_createInstJNI fail ret = %d",ret);
}
return (jlong)flxBus;
}
JNIEXPORT jint JNICALL Java_com_philisense_flxPrsmBusLib_prsmEngine_processKeyJNI(JNIEnv* env,jobject thiz,jlong ptr,jint key)
{
ST_FLX_PRSM_BUS *flxBus = (ST_FLX_PRSM_BUS *)ptr;
int ret = 0;
// cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_processKeyJNI env =0x%x",env);
ret = flxPrsmBusSetKey(flxBus,key);
if(ret >= 0)
{
// cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_processKeyJNI success");
}
else
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_processKeyJNI fail");
}
return ret;
}
JNIEXPORT jint JNICALL Java_com_philisense_flxPrsmBusLib_prsmEngine_processInstJNI(JNIEnv* env,jobject thiz,jlong ptr)
{
ST_FLX_PRSM_BUS *flxBus = (ST_FLX_PRSM_BUS *)ptr;
int ret = 0;
pSTprsmEngineEnvJni = env;
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_processInstJNI env =0x%x",env);
//test
readCMD();
while(0)
{
ret = flxPrsmBusProcess(flxBus);
if(ret >= 0)
{
// cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_processInstJNI success");
}
else
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_processInstJNI fail");
}
}
return ret;
}
JNIEXPORT jint JNICALL Java_com_philisense_flxPrsmBusLib_prsmEngine_destroyInstJNI(JNIEnv* env,jobject thiz,jlong ptr)
{
ST_FLX_PRSM_BUS *flxBus = (ST_FLX_PRSM_BUS *)ptr;
int ret = 0;
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_destroyInstJNI");
ret = flxPrsmBusDestroyInst(flxBus);
if(ret >= 0)
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_destroyInstJNI success");
}
else
{
cyVoiceE_SysPrintf("\n Java_com_philisense_flxPrsmBusLib_prsmEngine_destroyInstJNI fail");
}
return ret;
}
JNIEXPORT jstring JNICALL Java_com_philisense_flxPrsmBusLib_prsmEngine_getVersionJNI(JNIEnv* env,jobject thiz)
{
jstring jresult = 0 ;
char result[128] = {0};
int ret;
ret = flxPrsmBusGetVersion(result,sizeof(result));
jresult = (*env)->NewStringUTF(env, (const char *)result);
cyVoiceE_SysPrintf("\n Java_com_vcyber_dtw_dtwEngine_getVersionJNI result = %s",result);
return jresult;
}
8. 添加对应的JAVA层接口
package com.philisense.flxPrsmBusLib;
public class prsmEngine {
private long CPtr = 0;
private prsmUiListener pl = null;
/**
* @see 释放相关资源
*/
public synchronized void delete() {
if (CPtr != 0) {
prsmEngine.destroyInstJNI(CPtr);
CPtr = 0;
}
}
/**
* @see 创建实例
* @param p UI消息监控接口
* @param addr 本机地址
*/
public prsmEngine(prsmUiListener p,int addr)
{
pl = p;
if(CPtr == 0)
CPtr = prsmEngine.createInstJNI(addr);
}
/**
* 检查引擎句柄是否为空
* @return 如果为空 返回 true
*/
public boolean isEmpty()
{
boolean ret = false;
if(CPtr == 0)
ret = true;
else
ret = false;
return ret;
}
/**
* @see 处理数据
*/
public void process()
{
prsmEngine.processInstJNI(CPtr);
}
/**
* @see 处理数据
*/
public void processKey(int key)
{
prsmEngine.processKeyJNI(CPtr,key);
}
/**
* @see 获得引擎版本
* @return 引擎版本
*/
public String getVersion()
{
return prsmEngine.getVersionJNI();
}
public void processUIinfo(final int msgID,final byte msg[],final int arg0)
{
if(this.pl != null)
{
this.pl.onDisplayUI(msgID, msg, arg0);
}
}
private final static native long createInstJNI(int addr);
private final static native int destroyInstJNI(long ptr);
private final static native int processKeyJNI(long ptr,int key);
private final static native int processInstJNI(long ptr);
private final static native String getVersionJNI();
public final static native void testSpi();
static {
System.loadLibrary("flxPrsmBus");
}
}
9. 至此 j就可以通过JAVA层接口访问 SPI 设备了
public class prsmTask implements Runnable{
private prsmEngine prsm = null;
public prsmTask(prsmUiListener p)
{
//获得本机的地址
int addr = 100;
//
prsm = new prsmEngine(p,addr);
}
public void processKey(int k)
{
prsm.processKey(k);
}
@Override
public void run() {
// TODO Auto-generated method stub
// prsmEngine.testSpi();
if(prsm.isEmpty() == false)
{
prsm.process();
}
}
}
10, 最后做个简单的总结,1,2,3,4,5部在Android源码里面,6,7,8,9部是在Android的APP中