作者:余黔江
硬件平台:S3C6410
软件环境:Linux2.3.6
文件系统:android2.3
一、移植前准备工作
1. 熟悉s3c6410的SPI驱动工作流程
2. 将s3c6410 SPI的TX与RX连接到一起,测试SPI是否正常
3. 在SPI正常的前提下,仔细阅读ssd1353芯片手册,尤其是上电时序部分
二、开始移植SPI总线驱动
1. 在mach-s3c64xx/mach-xxx6410.c中添加如下部分(我用的是SPI0,6410有两个SPI)
s3c64xx_spi_set_info(0,0,2);
spi_register_board_info(s3c6410_spi0_board,ARRAY_SIZE(s3c6410_spi0_board));
1.1. s3c64xx_spi_set_info(0,0,2);
该函数定义在dev-spi.c中
void __init s3c64xx_spi_set_info(int cntrlr, intsrc_clk_nr, int num_cs)
{
structs3c64xx_spi_info *pd;
/* Reject invalidconfiguration */
if (!num_cs ||src_clk_nr < 0
||src_clk_nr > S3C64XX_SPI_SRCCLK_48M) {
printk(KERN_ERR"%s: Invalid SPI configuration\n", __func__);
return;
}
switch (cntrlr) {
case 0:
pd = &s3c64xx_spi0_pdata;
break;
case 1:
pd =&s3c64xx_spi1_pdata;
break;
default:
printk(KERN_ERR"%s: Invalid SPI controller(%d)\n",
__func__,cntrlr);
return;
}
pd->num_cs =num_cs;
pd->src_clk_nr= src_clk_nr;
pd->src_clk_name= spi_src_clks[src_clk_nr];
}
其中static structs3c64xx_spi_info s3c64xx_spi0_pdata = {
.cfg_gpio =s3c64xx_spi_cfg_gpio,
.fifo_lvl_mask =0x7f,
.rx_lvl_offset =13,
};
static int s3c64xx_spi_cfg_gpio(struct platform_device*pdev)
{//此函数初始化SPI相关管脚
switch(pdev->id) {
case 0:
s3c_gpio_cfgpin(S3C64XX_GPC(0),S3C64XX_GPC0_SPI_MISO0);
s3c_gpio_cfgpin(S3C64XX_GPC(1),S3C64XX_GPC1_SPI_CLKO);
s3c_gpio_cfgpin(S3C64XX_GPC(2),S3C64XX_GPC2_SPI_MOSIO);
s3c_gpio_setpull(S3C64XX_GPC(0),S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S3C64XX_GPC(1),S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S3C64XX_GPC(2),S3C_GPIO_PULL_UP);
break;
case 1:
s3c_gpio_cfgpin(S3C64XX_GPC(4),S3C64XX_GPC4_SPI_MISO1);
s3c_gpio_cfgpin(S3C64XX_GPC(5),S3C64XX_GPC5_SPI_CLK1);
s3c_gpio_cfgpin(S3C64XX_GPC(6),S3C64XX_GPC6_SPI_MOSI1);
s3c_gpio_setpull(S3C64XX_GPC(4),S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S3C64XX_GPC(5),S3C_GPIO_PULL_UP);
s3c_gpio_setpull(S3C64XX_GPC(6),S3C_GPIO_PULL_UP);
break;
default:
dev_err(&pdev->dev,"Invalid SPI Controller number!");
return-EINVAL;
}
return 0;
}
1.2. spi_register_board_info(s3c6410_spi0_board,ARRAY_SIZE(s3c6410_spi0_board));
s3c6410_spi0_board----->
static structspi_board_info s3c6410_spi0_board[] = {
[0] = {
.modalias = "spidev",
.bus_num= 0,
.chip_select= 0,
.irq =IRQ_SPI0,
.max_speed_hz= 1000000, //500*1000,
.mode=SPI_MODE_2,/* CPOL=1, CPHA=0 */
.controller_data=&s3c64xx_spi0_csinfo,
},
};
s3c64xx_spi0_csinfo----->
static voidcs_set_level(unsigned line_id, int lvl) {
gpio_direction_output(line_id, lvl);
}
static structs3c64xx_spi_csinfo s3c64xx_spi0_csinfo = {
.fb_delay=100,
.line=S3C64XX_GPC(3),
.set_level=cs_set_level,
};
spi_register_board_info----->在drivers/spi/spi.c中,将spi添加进入到链表中
int __init
spi_register_board_info(struct spi_board_infoconst *info, unsigned n)
{
structboardinfo *bi;
bi =kmalloc(sizeof(*bi) + n * sizeof*info, GFP_KERNEL);//注意观察此处分配大小的奥妙,牛人就是牛人,佩服!
if (!bi)
return-ENOMEM;
bi->n_board_info= n;
memcpy(bi->board_info,info, n * sizeof *info);
mutex_lock(&board_lock);
list_add_tail(&bi->list,&board_list);
mutex_unlock(&board_lock);
return0;
}
2. platform_add_devices(xxx6410_devices, ARRAY_SIZE(xxx6410_devices));中添加设备驱动
2.1. xxx6410_devices ----->
添加 &s3c64xx_device_spi0,
2.1.1 s3c64xx_device_spi0,------>
定义在dev-spi.c中
structplatform_device s3c64xx_device_spi0 = {
.name = "s3c64xx-spi",
.id = 0,
.num_resources =ARRAY_SIZE(s3c64xx_spi0_resource),
.resource =s3c64xx_spi0_resource,
.dev= {
.dma_mask = &spi_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
.platform_data= &s3c64xx_spi0_pdata,
},
};
static struct resource s3c64xx_spi0_resource[] = {
[0]= {
.start= S3C64XX_PA_SPI0,
.end = S3C64XX_PA_SPI0 + 0x100 - 1,
.flags= IORESOURCE_MEM,
},
[1]= {
.start= DMACH_SPI0_TX,
.end = DMACH_SPI0_TX,
.flags= IORESOURCE_DMA,
},
[2]= {
.start= DMACH_SPI0_RX,
.end = DMACH_SPI0_RX,
.flags= IORESOURCE_DMA,
},
[3]= {
.start= IRQ_SPI0,
.end = IRQ_SPI0,
.flags= IORESOURCE_IRQ,
},
};
-------> static struct s3c64xx_spi_info s3c64xx_spi0_pdata = {
.cfg_gpio =s3c64xx_spi_cfg_gpio,
.fifo_lvl_mask = 0x7f,
.rx_lvl_offset = 13,
};
3. spi总线注册以及spi_master的注册 drivers/spi/spi.c
4. s3c6410平台驱动注册drivers/spi/spi_s3c64xx.c
5. 设备驱动注册drivers/spi/spidev.c此部分是重点说明的部分
static int __init spidev_init(void)
{
int status;
/* Claim our256 reserved device numbers. Thenregister a class
* that will key udev/mdev to add/remove /devnodes. Last, register
* the driver which manages those devicenumbers.
*/
BUILD_BUG_ON(N_SPI_MINORS> 256);
status =register_chrdev(SPIDEV_MAJOR, "spi", &spidev_fops);
if (status <0)
returnstatus;
spidev_class = class_create(THIS_MODULE, "spidev");
if(IS_ERR(spidev_class)) {
unregister_chrdev(SPIDEV_MAJOR,spidev_spi_driver.driver.name);
returnPTR_ERR(spidev_class);
}
status = spi_register_driver(&spidev_spi_driver);
if (status <0) {
class_destroy(spidev_class);
unregister_chrdev(SPIDEV_MAJOR,spidev_spi_driver.driver.name);
}
return status;
}
module_init(spidev_init);
spidev_spi_driver------------------->
static structspi_driver spidev_spi_driver = {
.driver = {
.name = "spidev",
.owner = THIS_MODULE,
},
.probe = spidev_probe,
.remove = __devexit_p(spidev_remove),
*/
};
static int__devinit spidev_probe(struct spi_device *spi)
{
struct spidev_data *spidev;
int status,err;
unsigned long minor;
/* Allocate driver data */
spidev = kzalloc(sizeof(*spidev), GFP_KERNEL);//分配spidev数据空间
if (!spidev)
return -ENOMEM;
/* Initialize the driver data */
spidev->spi = spi;
spin_lock_init(&spidev->spi_lock);
mutex_init(&spidev->buf_lock);
INIT_LIST_HEAD(&spidev->device_entry);
/* If we can allocate a minor number, hookup this device.
*Reusing minors is fine so long as udev or mdev is working.
*/
mutex_lock(&device_list_lock);
minor = find_first_zero_bit(minors,N_SPI_MINORS);
if (minor < N_SPI_MINORS) {
struct device *dev;
spidev->devt = MKDEV(SPIDEV_MAJOR,minor);
dev =device_create(spidev_class, &spi->dev, spidev->devt,
spidev, "spidev%d.%d",
spi->master->bus_num,spi->chip_select);
//此处创建设备文件/dev/spidev0.0等文件
status = IS_ERR(dev) ? PTR_ERR(dev): 0;
//sysfs_create_group(&dev->kobj,&attr_group);
} else {
dev_dbg(&spi->dev, "nominor number available!\n");
status = -ENODEV;
}
if (status == 0) {
set_bit(minor, minors);
list_add(&spidev->device_entry,&device_list);
}
mutex_unlock(&device_list_lock);
if (status == 0)
spi_set_drvdata(spi, spidev);
else
kfree(spidev);
//writel(readl(S3C64XX_GPQCON) |S3C64XX_GPQ1_EINT_G9_1, S3C64XX_GPQCON);
//err = request_irq(188,FR_synchronization_irq_hander, IRQF_ONESHOT ,
// "oled_fr_sync",NULL);
//if (err < 0)
// printk("\n***********registerfr sync irq failed.\n");
oled_gpio_init(); //此处对SSD1353控制管脚进行初始化
return status;
}
spidev_fops -------->
static conststruct file_operations spidev_fops = {
.owner = THIS_MODULE,
/* REVISIT switch to aio primitives, sothat userspace
*gets more complete API coverage. It'llsimplify things
*too, except for the locking.
*/
.write = spidev_write,
.read = spidev_read,
.unlocked_ioctl = spidev_ioctl,
.open = spidev_open,
.release = spidev_release,
};
static int spidev_open(struct inode*inode, struct file *filp)
{
struct spidev_data *spidev;
int status= -ENXIO;
mutex_lock(&device_list_lock);
list_for_each_entry(spidev,&device_list, device_entry) {
if (spidev->devt ==inode->i_rdev) {
status = 0;
break;
}
}
if (status == 0) {
if (!spidev->buffer) {
spidev->buffer= kmalloc(bufsiz, GFP_KERNEL);此处分配ram的缓冲区,故每次发送数据最大只能发送4096 byte
if (!spidev->buffer) {
dev_dbg(&spidev->spi->dev,"open/ENOMEM\n");
status = -ENOMEM;
}
}
if (status == 0) {
spidev->users++;
filp->private_data =spidev;
nonseekable_open(inode,filp);
}
} else
pr_debug("spidev: nothing forminor %d\n", iminor(inode));
mutex_unlock(&device_list_lock);
return status;
}
spidev_ioctl --------->
static long
spidev_ioctl(structfile *filp, unsigned int cmd, unsigned long arg)
{
。。。。。。
switch (cmd) {
/* read requests */
case SPI_IOC_RD_MODE:
retval = __put_user(spi->mode& SPI_MODE_MASK,
(__u8 __user*)arg);
break;
case SPI_IOC_RD_LSB_FIRST:
retval = __put_user((spi->mode& SPI_LSB_FIRST) ? 1 : 0,
(__u8 __user*)arg);
break;
case SPI_IOC_RD_BITS_PER_WORD:
retval =__put_user(spi->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
retval =__put_user(spi->max_speed_hz, (__u32 __user *)arg);
break;
/* write requests */
case SPI_IOC_WR_MODE:
retval = __get_user(tmp, (u8 __user*)arg);
if (retval == 0) {
u8 save = spi->mode;
if (tmp & ~SPI_MODE_MASK){
retval = -EINVAL;
break;
}
tmp |= spi->mode &~SPI_MODE_MASK;
spi->mode = (u8)tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev,"spi mode %02x\n", tmp);
}
break;
case SPI_IOC_WR_LSB_FIRST:
retval = __get_user(tmp, (__u8__user *)arg);
if (retval == 0) {
u8 save = spi->mode;
if (tmp)
spi->mode |=SPI_LSB_FIRST;
else
spi->mode &=~SPI_LSB_FIRST;
retval = spi_setup(spi);
if (retval < 0)
spi->mode = save;
else
dev_dbg(&spi->dev,"%csb first\n",
tmp ?'l' : 'm');
}
break;
case SPI_IOC_WR_BITS_PER_WORD:
retval = __get_user(tmp, (__u8__user *)arg);
if (retval == 0) {
u8 save = spi->bits_per_word;
spi->bits_per_word = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->bits_per_word= save;
else
dev_dbg(&spi->dev,"%d bits per word\n", tmp);
}
break;
case SPI_IOC_WR_MAX_SPEED_HZ:
retval = __get_user(tmp, (__u32__user *)arg);
if (retval == 0) {
u32 save = spi->max_speed_hz;
spi->max_speed_hz = tmp;
retval = spi_setup(spi);
if (retval < 0)
spi->max_speed_hz =save;
else
dev_dbg(&spi->dev,"%d Hz (max)\n", tmp);
}
break;
case SPI_IOC_OLED_INIT:
SSD1353_initial(spidev);
retval = 0;
break;
case SPI_IOC_SET_CURSOR:
ioc = (struct spi_ioc_transfer*)arg;
OLED_SetCursor(spidev,ioc->XSpos, ioc->XCpos, ioc->YSpos, ioc->YCpos);
retval = 0;
break;
case SPI_IOC_SET_FONT:
ioc = (struct spi_ioc_transfer*)arg;
FrontSetup(ioc);
break;
case SPI_IOC_CLEAR_SCREEN:
ioc = (struct spi_ioc_transfer*)arg;
OLED_ClearScreen(spidev,ioc->Color);
break;
case SPI_IOC_SCREEN_SLEEP:
ioc = (struct spi_ioc_transfer*)arg;
OLED_Sleep(spidev,ioc->Status);
break;
case SPI_IOC_SEND_STRING:
ioc = (struct spi_ioc_transfer*)arg;
OLED_ClearScreen(spidev,ioc->Color);
OLED_DisplayChar(spidev,15, 40, 0);
break;
default:
}
}
static voidSSD1353_initial(struct spidev_data *spidev)
{
u8 data[2];
LCD_RS(1); //DC 1:data 0:command //DC = 1
LCD_RS(1);
LCD_RESET(1); //RESB 0:reset 1:normal
LCD_RESET(0);
mdelay(5);
LCD_RESET(1);
mdelay(100);
//comm_out8(spidev, 0xae); Display off
//comm_out8(spidev, 0xa8); //Set MUX ratio
data[0] = 0xae; data[1] = 0xa8;
oled_WriteLongCmd(spidev, data, 2);
data_out8(spidev, 0x7f);
comm_out8(spidev, 0xa1); //Display start line
data_out8(spidev, 0x00);
comm_out8(spidev, 0xa2); //Set displayoffset
data_out8(spidev, 0x00);
comm_out8(spidev, 0xa4); //Normal display
comm_out8(spidev, 0xa0); //Set re-map
data_out8(spidev, 0x66); //65K Color
comm_out8(spidev, 0x87); //Master currentcontrol
data_out8(spidev, 0x0f);
comm_out8(spidev, 0x81); //Set contrastlevel for R
data_out8(spidev, 0x75); //Red contrast set
comm_out8(spidev, 0x82); //Set contrastlevel for G
data_out8(spidev, 0x60); //Green contrastset
comm_out8(spidev, 0x83); //Set contrastlevel for B
data_out8(spidev, 0x6a); //Blue contrastset
comm_out8(spidev, 0xb1); //Phase adjust
data_out8(spidev, 0x22);
comm_out8(spidev, 0xb3); //Set frame rate
data_out8(spidev, 0x40);
comm_out8(spidev, 0xbb); //Set Pre-chargelevel
data_out8(spidev, 0x08);
comm_out8(spidev, 0xbe); //VCOMH setting
data_out8(spidev, 0x2f);
comm_out8(spidev, 0xb9);
cleanDDR(spidev); //Clear the whole DDRAM
comm_out8(spidev, 0xaf); //Display on
}
/*******************************************************************************
* FunctionName : OLED_SetCursor
*Description : Sets the cursorposition.
* Input : - Xpos: specifies the Xposition.
* - Ypos: specifies the Yposition.
* Output : None
* Return : None
*******************************************************************************/
void OLED_SetCursor(struct spidev_data*spidev, u8 XSpos,u8 XCpos, u8 YSpos,u8 YCpos) //S: start C: close
{
comm_out8(spidev, 0x15); // Set Column Address
data_out8(spidev, XSpos);
data_out8(spidev, XCpos);
comm_out8(spidev, 0x75); // Set Row Address
data_out8(spidev, YSpos);
data_out8(spidev, YCpos);
}
/*******************************************************************************
* FunctionName : FrontSetup
*Description : Setup a Front LIB onOLED.
* Input : - FontID: This parameter can be one of thefollowing values:
* :
* Output : None
* Return : None
*******************************************************************************/
void FrontSetup(struct spi_ioc_transfer *ioc)
{
CurrentENFront = ioc->Charfont;
Words = ioc->Words;
CharWidth = ioc->CharWidth;
CharHeight = ioc->CharHeight;
BackColor = ioc->BackColor;
TextColor = ioc->TextColor;
CharSize = ioc->CharSize;
//printk("font[38] = %x, Words :%d,CharWidth:%d, CharHeight:%d, BackColor:%x, TextColor:%x, CharSize:%d\n)",CurrentENFront[38], Words, CharWidth, CharHeight, BackColor, TextColor,CharSize);
}
voidOLED_DisplayChar(struct spidev_data *spidev, u8 Column,u8 Row,u8 Ascii)
{
u16 MapAddress =0;
Ascii -= 0x20;
//CharHeight = CurrentENFront[7];
//CharWidth = CurrentENFront[Ascii*4+9];
//MapAddress =CurrentENFront[Ascii*4+10]+CurrentENFront[Ascii*4+11]*256;
for (MapAddress = 0; MapAddress <Words; MapAddress++) //4 // 4 represents the number of words
OLED_DrawChar(spidev, Column + MapAddress* (CharWidth + 1),Row, CurrentENFront+ MapAddress *CharSize);
//OLED_DrawChar(spidev, Column,Row,&CurrentENFront[MapAddress]);
//Xcursor = Column + CharWidth;
//Ycursor = Row;
}
voidOLED_DrawChar(struct spidev_data *spidev, u8 Xpos, u8 Ypos, u8 *buffer)
{
u8index = 0;
u8i = 0,j = 0;
u8 multiple = 0;
u8*buf;
int size;
u16 k = 0;
OLED_SetCursor(spidev,Xpos,Xpos+CharWidth-1,Ypos,Ypos+CharHeight-1);
OLED_WriteRAMPrepare(spidev);
multiple = (CharWidth-1)/8+1;
size = 2 * CharHeight * ((multiple-1) * 8 +(CharWidth -(multiple -1)*8));
printk("\n*** size = %d\n",size);
buf = (u8 *)kcalloc(size+1, sizeof(u8),GFP_KERNEL);
for(index = 0; index < CharHeight; index++)
{
for(j=0;j<(multiple-1);j++) {
for(i=0; i<8; i++)
{
if((buffer[index*multiple+j]&(0x80>>i))== 0x00)
{
//OLED_WriteRAM(spidev,BackColor);
buf[k] = (u8)(BackColor >> 8);
buf[k+1] = (u8)BackColor &0x0f;
}
else
{
//OLED_WriteRAM(spidev, TextColor);
buf[k] =(u8)(TextColor >> 8);
buf[k+1] = (u8)TextColor &0x0f;
}
k +=2;
}
}
for(i=0;i<(CharWidth-(multiple-1)*8);i++)
{
if((buffer[index*multiple+j]&(0x80>>i))== 0x00)
{
//OLED_WriteRAM(spidev,BackColor);
buf[k] =(u8)(BackColor >> 8);
buf[k+1] = (u8)BackColor &0x0f;
}
else
{
//OLED_WriteRAM(spidev, TextColor);
buf[k] = (u8)(TextColor >> 8);
buf[k+1] = (u8)TextColor &0x0f;
}
k += 2;
}
}
printk("\nk = :%d\n", k);
oled_WriteLongData(spidev, buf, k -2);
kfree(buf);
}
三、android测试程序
1. mainactivity.java
packagecom.example.spitest;
importcom.friendlyarm.AndroidSDK.HardwareControler;
importcom.hardware.Hardware;
importandroid.os.Bundle;
importandroid.app.Activity;
importandroid.view.Menu;
importandroid.view.View;
import android.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.Toast;
public classMainActivity extends Activity {
Button send;
Button close;
Button oled_on;
Button oled_off;
String device = "/dev/spidev0.0";
int fd_spi;
int fd_gpio;
Hardware hardware=new Hardware();
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
System.out.println("openSPI:"+(fd_spi=hardware.openSPI()));
//System.out.println("openGPIO:"+(fd_gpio=hardware.openGPIO()));
//hardware.setGPIO(0,20);//RES(115)
//hardware.setGPIO(1, 20);
//hardware.setGPIO(0, 20);
//System.out.println("setGPIO:"+hardware.setGPIO(0,18));
send = (Button)findViewById(R.id.button1);
send.setOnClickListener(newOnClickListener() {
public void onClick(View arg0) {
System.out.println(">>>>>>>>>>>>>>>>transfer:"+hardware.transfer(fd_spi,0xa5));
//System.out.println(">>>>>>>>>>reset"+hardware.reset());
try{
Thread.sleep(1);
} catch(InterruptedException e) {
// TODOAuto-generated catch block
e.printStackTrace();
}
//ssd1353_init();
//write_blue_data();
//System.out.println("transfer");
//System.out.println(">>>>>>>>>>setGPIO"+hardware.setGPIO(35,101));
//System.out.println("write_blue_data");
}
});
close =(Button)findViewById(R.id.button2);
close.setOnClickListener(newOnClickListener() {
public void onClick(View arg0) {
hardware.closeSPI();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
}
});
oled_on =(Button)findViewById(R.id.button3);
oled_on.setOnClickListener(newOnClickListener() {
public void onClick(View arg0) {
hardware.sleep(fd_spi,0);
}
});
oled_off = (Button)findViewById(R.id.button4);
oled_off.setOnClickListener(newOnClickListener() {
public void onClick(View arg0) {
hardware.sleep(fd_spi,1);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu){
// Inflate the menu; this addsitems to the action bar if it is present.
getMenuInflater().inflate(R.menu.main,menu);
return true;
}
}
Hareware.java
package com.hardware;
public class Hardware {
public native int openGPIO();
public native int openSPI();
public native int transfer(int fd,int cmd );
public native int sleep(int fd,int cmd );
public native int setGPIO(int state,int port);
public native int reset();
public native int closeSPI();
public native String unimplementedStringFromJNI();
static {
System.loadLibrary("hardware_jni");
}
}
Hardware_jni.c
#include <stdio.h>
#include <stdlib.h>
#include <linux/input.h>
#include <string.h>
#include <jni.h>
#include <fcntl.h> /*包括文件操作,如open() read() close()write()等*/
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#define SPI_CPHA 0x01
#define SPI_CPOL 0x02
#define SPI_MODE_0 (0|0)
#define SPI_MODE_1 (0|SPI_CPHA)
#define SPI_MODE_2 (SPI_CPOL|0)
#define SPI_MODE_3 (SPI_CPOL|SPI_CPHA)
#define SPI_CS_HIGH 0x04
#define SPI_LSB_FIRST 0x08
#define SPI_3WIRE 0x10
#define SPI_LOOP 0x20
#define SPI_NO_CS 0x40
#define SPI_READY 0x80
#define SPI_IOC_MAGIC 'k'
struct spi_ioc_transfer {
__u64 tx_buf; //用于其他数据buffer,如图片类
__u64 rx_buf;
__u32 len;//buffer长度,即多少字节
__u32 speed_hz;
__u16 delay_usecs; //传输延时
__u8 bits_per_word; //传输位数
__u8 cs_change; //SPI通道选择,本OLED模块固定选0
__u8 XSpos; //x起始地址
__u8 XCpos; //x结束地址
__u8 YSpos; //y起始地址
__u8 YCpos; //y结束地址
__u16 Color; //控制颜色
__u64 Charfont; //字库数组地址
__u8 CharWidth;//文字宽
__u8 CharHeight;//文字高
__u8 Words; //文字数目
__u8 Status; //The screen switch state, such as: 1, close to 0
__u16 BackColor; //文字背景颜色
__u16 TextColor; //文字颜色
__u16 CharSize; //整个字所占字节数
};
/* not all platforms use<asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
#define SPI_MSGSIZE(N) \
((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
/* Read / Write of SPI mode(SPI_MODE_0..SPI_MODE_3) */
#define SPI_IOC_RD_MODE _IOR(SPI_IOC_MAGIC,1, __u8)
#define SPI_IOC_WR_MODE _IOW(SPI_IOC_MAGIC,1, __u8)
/* Read / Write SPI bitjustification */
#define SPI_IOC_RD_LSB_FIRST _IOR(SPI_IOC_MAGIC,2, __u8)
#define SPI_IOC_WR_LSB_FIRST _IOW(SPI_IOC_MAGIC,2, __u8)
/* Read / Write SPI deviceword length (1..N) */
#define SPI_IOC_RD_BITS_PER_WORD _IOR(SPI_IOC_MAGIC,3, __u8)
#define SPI_IOC_WR_BITS_PER_WORD _IOW(SPI_IOC_MAGIC,3, __u8)
/* Read / Write SPI devicedefault max speed hz */
#define SPI_IOC_RD_MAX_SPEED_HZ _IOR(SPI_IOC_MAGIC,4, __u32)
#define SPI_IOC_WR_MAX_SPEED_HZ _IOW(SPI_IOC_MAGIC,4, __u32)
#define SPI_IOC_OLED_INIT _IOR(SPI_IOC_MAGIC,5, __u32)
/* set oled cursor postion*/
#define SPI_IOC_SET_CURSOR _IOR(SPI_IOC_MAGIC,6, __u32)
/* set oled char font*/
#define SPI_IOC_SET_FONT _IOR(SPI_IOC_MAGIC,7, __u32)
/* clear screen buffer*/
#define SPI_IOC_CLEAR_SCREEN _IOR(SPI_IOC_MAGIC,8, __u32)
/* open oled screen*/
#define SPI_IOC_SCREEN_SLEEP _IOR(SPI_IOC_MAGIC,9, __u32)
/* send string*/
#define SPI_IOC_SEND_STRING _IOR(SPI_IOC_MAGIC,10, __u32)
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
int fd_gpio;
int fd_spi;
int fd_oled;
static uint8_t mode;
static uint8_t bits = 8;
static uint32_t speed = 1000000;
static uint16_t delay;
jstring
Java_com_hardware_Hardware_stringFromJNI( JNIEnv* env,
jobject thiz )
{
return (*env)->NewStringUTF(env, "keys from JNI create by xu !");
}
jint Java_com_hardware_Hardware_openSPI(JNIEnv* env,
jobject thiz )
{
int ret = 0;
fd_spi = open("/dev/spidev0.0", O_RDWR);
if (ioctl(fd_spi, SPI_IOC_WR_MODE, &mode) == -1)
ret =-2;
if (ioctl(fd_spi, SPI_IOC_RD_MODE, &mode) == -1)
ret =-3;
if (ioctl(fd_spi, SPI_IOC_WR_BITS_PER_WORD, &bits) ==-1)
ret =-4;
if (ioctl(fd_spi, SPI_IOC_RD_BITS_PER_WORD, &bits) ==-1)
ret =-5;
if (ioctl(fd_spi, SPI_IOC_WR_MAX_SPEED_HZ, &speed) == -1)
ret =-6;
if (ioctl(fd_spi, SPI_IOC_RD_MAX_SPEED_HZ, &speed) == -1)
ret =-7;
//fd_oled = open("sys/class/spidev/spidev0.0/open",O_RDWR);
if (ioctl(fd_spi, SPI_IOC_OLED_INIT, NULL) == -1)
ret =-15;
//read(fd_oled, &ret, 0);
//while(1){
// read(fd_oled,&ret, 0);
// sleep(1);
//}
return fd_spi;
}
jint Java_com_hardware_Hardware_transfer(JNIEnv* env,
jobject thiz,jint fd_spi,jint cmd )
{
int ret, i;
uint8_t *buf;
uint16_t tmp = 0xf800;
uint8_t testfont[] = {
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x7F,0xE0,0x00,0x00,0x7F,0xE0,0x00,0x00,0x71,0xE0,0x00,
0x00,0x30,0xE0,0x00,0x00,0x30,0xE0,0x00,0x00,0x30,0xE0,0x00,0x00,0x30,0xE0,0x00,
0x00,0x3E,0xE0,0x00,0x00,0x3F,0xE0,0x00,0x00,0x73,0xE0,0x00,0x00,0x70,0x60,0x00,
0x00,0xE0,0x70,0x00,0x00,0xE0,0x78,0x00,0x03,0xC0,0x3E,0x02,0x7F,0x80,0x3F,0xFC,
0x3F,0x80,0x1F,0xFC,0x1E,0x00,0x07,0xF8,0x00,0x00,0x03,0xF0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"凡",0*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,
0x00,0x07,0x80,0x00,0x00,0x07,0xF0,0x00,0x00,0x03,0xF8,0x00,0x00,0x00,0x00,0x00,
0x3F,0xFF,0xFF,0xFE,0x3F,0xFF,0xFF,0xFC,0x7C,0x03,0x81,0xFC,0x00,0x03,0x80,0x18,
0x00,0x07,0xF0,0x00,0x00,0x07,0xFF,0x80,0x00,0x0F,0x07,0x80,0x00,0x1E,0x07,0x00,
0x00,0x3C,0x07,0x00,0x00,0x78,0x07,0x00,0x01,0xF0,0x06,0x00,0x07,0xE0,0x0E,0x00,
0x1F,0xC8,0x1E,0x00,0x7F,0x0E,0xFC,0x00,0x3C,0x07,0xF8,0x00,0x00,0x01,0xE0,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"方",1*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x30,0x38,0x00,0x03,0x73,0x38,0x00,0x03,0x77,0x38,0x00,0x01,0xF4,0x38,0x00,
0x0F,0xFF,0x3F,0xF0,0x1F,0xFF,0x3F,0xF0,0x01,0xB4,0x63,0x00,0x03,0xBE,0x63,0x00,
0x07,0x26,0xE3,0x00,0x08,0x61,0xB7,0x00,0x18,0xF8,0x1E,0x00,0x3F,0xFF,0x1E,0x00,
0x61,0x8C,0x0F,0x00,0x01,0xDC,0x1F,0xC0,0x00,0xF8,0x3B,0xF0,0x00,0x7E,0x71,0xFE,
0x07,0xEE,0xE0,0xFE,0x0F,0x01,0xC0,0x7C,0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"数",2*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x01,0x01,0x80,0x08,0x03,0xFF,0x80,0x1F,0xFF,0xFF,0x80,0x1F,0x80,0x81,0x80,
0x01,0x80,0xC1,0x80,0x03,0x00,0xC1,0x80,0x03,0x00,0xC1,0x80,0x07,0x01,0xC1,0x80,
0x0F,0x99,0xC1,0x80,0x1F,0xF9,0xC1,0x9C,0x7B,0x11,0xFF,0xFC,0x73,0x11,0x80,0x3C,
0x03,0x10,0x00,0x1C,0x03,0xF7,0xFF,0x9C,0x07,0xFF,0xFF,0x9C,0x00,0x04,0x00,0x38,
0x00,0x00,0x00,0x38,0x00,0x00,0x07,0xF8,0x00,0x00,0x03,0xF0,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,/*"码",3*/
};
uint8_t testfont1[] = {
0x00,0x00,0x0F,0xE0,0x08,0x20,0x08,0x20,0x08,0x20,0x0A,0x20,0x09,0x20,0x08,0xA0,
0x08,0xA0,0x08,0x20,0x10,0x20,0x10,0x22,0x20,0x22,0x20,0x22,0x40,0x1E,0x80,0x00,/*"凡",0*/
0x02,0x00,0x01,0x00,0x01,0x00,0xFF,0xFE,0x04,0x00,0x04,0x00,0x04,0x00,0x07,0xF0,
0x04,0x10,0x04,0x10,0x04,0x10,0x08,0x10,0x08,0x10,0x10,0x10,0x20,0xA0,0x40,0x40,/*"方",1*/
0x08,0x20,0x49,0x20,0x2A,0x20,0x08,0x3E,0xFF,0x44,0x2A,0x44,0x49,0x44,0x88,0xA4,
0x10,0x28,0xFE,0x28,0x22,0x10,0x42,0x10,0x64,0x28,0x18,0x28,0x34,0x44,0xC2,0x82,/*"数",2*/
0x00,0x00,0x01,0xF8,0xFC,0x08,0x10,0x08,0x10,0x88,0x20,0x88,0x3C,0x88,0x64,0xFE,
0x64,0x02,0xA4,0x02,0x24,0x02,0x25,0xFA,0x3C,0x02,0x24,0x02,0x20,0x14,0x00,0x08,/*"码",3*/
0x02,0x00,0x02,0x00,0xFF,0xFE,0x04,0x00,0x04,0x00,0x0F,0xF0,0x08,0x10,0x18,0x10,
0x2F,0xF0,0x48,0x10,0x88,0x10,0x0F,0xF0,0x08,0x10,0x08,0x10,0x08,0x50,0x08,0x20,/*"有",4*/
0x00,0x00,0x7B,0xF8,0x4A,0x08,0x52,0x08,0x53,0xF8,0x62,0x08,0x52,0x08,0x4B,0xF8,
0x4A,0x44,0x4A,0x48,0x6A,0x30,0x52,0x20,0x42,0x10,0x42,0x88,0x43,0x06,0x42,0x00,/*"限",5*/
0x00,0x80,0x04,0x80,0x04,0x80,0x08,0x40,0x08,0x40,0x10,0x20,0x20,0x10,0x42,0x08,
0x82,0x06,0x04,0x00,0x04,0x40,0x08,0x20,0x10,0x20,0x3F,0xF0,0x10,0x10,0x00,0x00,/*"公",6*/
0x00,0x00,0x3F,0xF8,0x00,0x08,0x00,0x08,0x7F,0xE8,0x00,0x08,0x00,0x08,0x1F,0x88,
0x10,0x88,0x10,0x88,0x10,0x88,0x10,0x88,0x1F,0x88,0x10,0x88,0x00,0x28,0x00,0x10,/*"司",7*/
};
buf = malloc(sizeof(uint8_t) * 160 * 128);
for(i = 0; i < 160 * 128; i+=2){
//memcopy(buf++,tmp, sizeof(uint16_t));
buf[i] = 0x00;
buf[i+1] = 0xf8;
}
#if 1
struct spi_ioc_transfer tr = {
.len = 4,
//.len = 1,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.XSpos = 0,
.XCpos = 70,
.YSpos = 30,
.YCpos = 70,
.Color = 0x3333,
.Charfont = (unsigned long)testfont1,
.CharWidth = 16,
.CharHeight =16,
.BackColor = 0x02ef,
.TextColor = 0xf800,
.CharSize = 16 * 2,
.Words = 8,
};
ret = ioctl(fd_spi, SPI_IOC_SET_FONT, &tr);
ret = ioctl(fd_spi, SPI_IOC_SET_CURSOR, &tr);
struct spi_ioc_transfer tr1 = {
.tx_buf = (unsigned long)buf,
.len = 4096,
//.len =1,
.delay_usecs = delay,
.speed_hz = speed,
.bits_per_word = bits,
.XSpos = 30,
.XCpos = 70,
.YSpos = 30,
.YCpos = 70,
.Color = 0x3333,
};
ret = ioctl(fd_spi, SPI_IOC_SEND_STRING, &tr1);
if (ret < 1)
//return ret;
#endif
free(buf);
//read(fd_oled, &ret, 0);
return 0;
}
jint Java_com_hardware_Hardware_sleep(JNIEnv* env,
jobject thiz,jint fd_spi,jint cmd )
{
int ret;
struct spi_ioc_transfer tr = {
.Status = cmd,
};
ret = ioctl(fd_spi, SPI_IOC_SCREEN_SLEEP, &tr);
return ret;
}
jint Java_com_hardware_Hardware_closeSPI(JNIEnv* env,
jobject thiz )
{
close(fd_spi);
return 1;
}