Hi3516A开发--GV7601 硬件设计
GV7601 硬件部分官方手册上有给一些示例,但是不太完整。
这里贴出我们设计的原理图,仅供参考。
网上找到一篇关于GV7601 SPI通信的例子
/*生成ko文件源代码*/
#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <asm/uaccess.h>
#include <linux/delay.h>
//#include <bsp.h>
#include <asm/io.h>
#include <linux/sched.h>
#include <linux/delay.h> //OK
#include <linux/fs.h> //OK
#include <asm/irq.h> //OK
//#include <mach/regs-gpio.h>
//#include <mach/hardware.h> //OK
#include <linux/miscdevice.h> /**鍐呮牳鐗堟湰2.6.32鍔犱互涓嬪ご鏂囦欢***/
//#include <mach/regs-gpio.h>
#include <linux/mm.h> //OK
#include <linux/pci.h> //OK
#include <linux/moduleparam.h> //OK
#include <linux/slab.h> //OK
#include <linux/errno.h> //OK
#include <linux/ioctl.h> //OK
#include <linux/cdev.h> //OK
#include <linux/string.h> //OK
#include <linux/list.h> //OK
#include <asm/atomic.h>
#include <asm/unistd.h>
#define PDEBUG
#ifdef PDEBUG
#define PLOG(fmt,args...) printk(fmt,##args)
#else
#define PLOG(fmt,args...) /*do nothing*/
#endif
#define DEVICE_NAME "GV7601"
#define GV7601_MAJOR 230 //device num
typedef struct tem{
unsigned short address;
unsigned short value;
}command;
command temp;
//寄存器读写定义
#define HW_REG(reg) *((volatile unsigned long *)(reg))
#define Hi3516_gpio_cfgpin(addr,dir) HW_REG(addr) = dir
#define Hi3516_gpio_setpin(addr,value) HW_REG(addr) = value
#define Hi3516_gpio_getpin(addr) HW_REG(addr)
//定义地址偏移
#define CPU_BASE 0x200F0000
#define OFFSET_GPIO2_4 0x00A4 //cs
#define OFFSET_GPIO2_5 0x00A8 //SCLK
#define OFFSET_GPIO2_6 0x00AC //TDI
#define OFFSET_GPIO2_7 0x00B0 //TDO
#define GPIO2_4_SET IO_ADDRESS(0x200F00A4)
#define GPIO2_5_SET IO_ADDRESS(0x200F00A8)
#define GPIO2_6_SET IO_ADDRESS(0x200F00AC)
#define GPIO2_7_SET IO_ADDRESS(0x200F00B0)
#define GPIO1_6_SET IO_ADDRESS(0x200F00D4)
#define GPIO2_BASE 0x20170000
#define GPIO1_BASE 0x20160000
#define GPIO_DIR 0x400
#define GPIO_DATA2_4 IO_ADDRESS(0x20170040) //CS 1<<6 IO_ADDRESS(GPIO2_BASE+(1<<4))
#define GPIO_DATA2_5 IO_ADDRESS(0x20170080) //sclk 1<<7
#define GPIO_DATA2_6 IO_ADDRESS(0x20170100) //tdi 1<<8
#define GPIO_DATA2_7 IO_ADDRESS(0x20170200) //tdo 1<<9
#define GPIO_DATA1_6 IO_ADDRESS(0x20160100) //reset 1<<8
#define GPIO2_DIR IO_ADDRESS(0x20170400)
#define GPIO1_DIR IO_ADDRESS(0x20160400)
#define PIN_SDO 9 //
#define PIN_SDI 8
#define PIN_SCLK 7
#define PIN_CS 6 //
#define SPI_CMD 0
#define SPI_DATA 1
#define FUN_GPIO 0
static int spi_setcs_gv7601(int ) ;
static int spi_sethigh(int );
static int spi_setlow(int ) ;
static unsigned int spi_readIO_gv7601(int ) ;
static int spi_init_gv7601(void) ;
void SPI_send_gv7601(unsigned short,unsigned short ) ;
unsigned short spi_read_gv7601(unsigned short ) ;
static ssize_t spi_write_data_gv7601(struct file *, command __user *, size_t , loff_t *);
static ssize_t spi_read_data_gv7601(struct file *, command __user *, size_t , loff_t *);
static void set_value(void) ;
static int gv7601_ioctl(struct inode *,struct file *,unsigned int ,unsigned long );
// 换成海思的片选信号,两路,低选中一路,高选中一路
static int spi_setcs_gv7601(int number)
{
switch(number)
{
case 1:
Hi3516_gpio_setpin(GPIO_DATA2_4,Hi3516_gpio_getpin(GPIO_DATA2_4)&0xFFEF); //拉低
break;
case 2:
Hi3516_gpio_setpin(GPIO_DATA2_4,Hi3516_gpio_getpin(GPIO_DATA2_4)|0x0010); //拉高
break;
}
return 0;
}
// set gpio pin level, high: 1, low: 0
// cs --6
// sclik --7
// tdi --8
// tdo --9
// 管脚拉高
static int spi_sethigh(int pin)
{
Hi3516_gpio_setpin(GPIO2_DIR,Hi3516_gpio_getpin(GPIO2_DIR)|(1<<(pin-2)));
Hi3516_gpio_setpin(IO_ADDRESS(GPIO2_BASE+(1<<pin)),Hi3516_gpio_getpin(IO_ADDRESS(GPIO2_BASE+(1<<pin)))|(1<<(pin-2)));
return 0;
}
//管脚拉低
static int spi_setlow(int pin)
{
Hi3516_gpio_setpin(GPIO2_DIR,Hi3516_gpio_getpin(GPIO2_DIR)|(1<<(pin-2)));
Hi3516_gpio_setpin(IO_ADDRESS(GPIO2_BASE+(1<<pin)),Hi3516_gpio_getpin(IO_ADDRESS(GPIO2_BASE+(1<<pin)))&(~(1<<(pin-2))));
return 0;
}
// cs --4
// sclik --5
// tdi --6
// tdo --7
// 读管脚数据
static unsigned int spi_readIO_gv7601(int pin)
{
int i;
Hi3516_gpio_setpin(GPIO2_DIR,Hi3516_gpio_getpin(GPIO2_DIR)&(~(1<<(pin-2))));
i=Hi3516_gpio_getpin(IO_ADDRESS(GPIO2_BASE+(1<<pin)));
if (i!=0)
i=1;
return i;
}
// select pin used for gpio 配置管脚为GPIO
// 换成海思的管脚配置即可
static int spi_init_gv7601()
{
//配置成GPIO口
Hi3516_gpio_setpin(GPIO2_4_SET,Hi3516_gpio_getpin(GPIO2_4_SET)&0xFFFC);//cs
Hi3516_gpio_setpin(GPIO2_5_SET,Hi3516_gpio_getpin(GPIO2_5_SET)&0xFFFC);//sclk
Hi3516_gpio_setpin(GPIO2_6_SET,Hi3516_gpio_getpin(GPIO2_6_SET)&0xFFFC);//tdi
Hi3516_gpio_setpin(GPIO2_7_SET,Hi3516_gpio_getpin(GPIO2_7_SET)&0xFFFC);//tdo
Hi3516_gpio_setpin(GPIO1_6_SET,Hi3516_gpio_getpin(GPIO1_6_SET)&0xFFFC);//reset
//配置GPIO输入输出方向
Hi3516_gpio_setpin(GPIO2_DIR,Hi3516_gpio_getpin(GPIO2_DIR)|0x0070);//cs sclk tdi out
Hi3516_gpio_setpin(GPIO2_DIR,Hi3516_gpio_getpin(GPIO2_DIR)&0xFF8F);//td0 in
Hi3516_gpio_setpin(GPIO1_DIR,Hi3516_gpio_getpin(GPIO2_DIR)|0x0040);//reset out
//除clk以外全部置高
spi_sethigh(6);
spi_setlow(7);
spi_sethigh(8);
spi_sethigh(9);
return 0;
}
void SPI_send_gv7601(unsigned short address,unsigned short wdata)
{
unsigned short vsignbit;
// 写地址 16位
spi_setlow(PIN_CS);
ndelay(1000);
for(vsignbit=0x8000;vsignbit>0;vsignbit>>=1)
{
if(address&vsignbit)
spi_sethigh(PIN_SDI);
else
spi_setlow(PIN_SDI);
ndelay(1000);
spi_setlow(PIN_SCLK);
ndelay(2000);
spi_sethigh(PIN_SCLK);
ndelay(1000);
}
ndelay(1000);
spi_setlow(PIN_SCLK);
//spi_setlow(PIN_SDI);
//spi_setlow(PIN_SDO);
udelay(100);
//写数据 16位
for(vsignbit=0x8000;vsignbit>0;vsignbit>>=1)
{
if(wdata&vsignbit)
spi_sethigh(PIN_SDI);
else
spi_setlow(PIN_SDI);
ndelay(1000);
spi_setlow(PIN_SCLK);
ndelay(2000);
spi_sethigh(PIN_SCLK);
ndelay(1000);
}
//spi_sethigh(PIN_SDI);
ndelay(1000);
spi_setlow(PIN_SCLK);
//spi_setlow(PIN_SCLK);
//udelay(300);
//spi_setlow(PIN_SDI);
ndelay(1000);
spi_sethigh(PIN_CS);
}
unsigned short spi_read_gv7601(unsigned short address)
{
unsigned short vsignbit,r_data=0;
//写命令字
spi_setlow(PIN_CS);
ndelay(1000);
for(vsignbit=0x8000;vsignbit>0;vsignbit>>=1)
{
if(address&vsignbit)
spi_sethigh(PIN_SDI);
else
spi_setlow(PIN_SDI);
ndelay(1000);
spi_setlow(PIN_SCLK);
ndelay(2000);
spi_sethigh(PIN_SCLK);
ndelay(1000);
}
//spi_sethigh(PIN_SDI);
ndelay(1000);
spi_setlow(PIN_SCLK);
//udelay(300);
spi_setlow(PIN_SDI);
udelay(10);
for(vsignbit=0x8000;vsignbit>0;vsignbit>>=1)
{
spi_setlow(PIN_SCLK);
ndelay(1000);
if(spi_readIO_gv7601(PIN_SDO)) //读 TDO
{
r_data = r_data|vsignbit;
}
ndelay(1000);
spi_sethigh(PIN_SCLK);
ndelay(2000);
}
spi_setlow(PIN_SCLK);
ndelay(1000);
spi_sethigh(PIN_CS);
return r_data;
}
//向寄存器写入数据
static ssize_t spi_write_data_gv7601(struct file *pFile, command __user *pData, size_t count, loff_t *off)
{
printk("in the write function\n");
//加片选?
//ndelay(100);
memcpy(&temp,pData,count);
unsigned short address, wdata;
address = temp.address;
unsigned short writecommand = 0x0000;
wdata = temp.value;
writecommand = writecommand + address;
SPI_send_gv7601(writecommand,wdata);
//udelay(300);
//SPI_send_gv7601(wdata);
//spi_setlow(PIN_SCLK);
return count;
}
static ssize_t spi_read_data_gv7601(struct file *pFile, command __user *pData, size_t count, loff_t *off)
{
//加片选?
printk("in the read function\n");
unsigned short writecommand = 0x8000;
memcpy(&temp,pData,count);
writecommand = writecommand + temp.address;
//SPI_send_gv7601(writecommand);
//udelay(300);
temp.value=spi_read_gv7601(writecommand);
int ret;
ret=copy_to_user(pData, &temp, sizeof(temp));
if(ret>0)
{
printk("copy data failed\n");
return -1;
}
//spi_setlow(PIN_SCLK);
return count;
}
static void set_value()
{
//初始化配置
}
static int gv7601_ioctl(struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg)
{
return 0;
}
static struct file_operations gv7601_fops = {
.owner = THIS_MODULE,
.compat_ioctl = gv7601_ioctl,
.read = spi_read_data_gv7601,
.write = spi_write_data_gv7601,
};
static int __init spi_gv7601_init(void)
{
int ret;
ret = register_chrdev(GV7601_MAJOR, DEVICE_NAME, &gv7601_fops);
if (ret < 0) {
printk(DEVICE_NAME " can't register major number\n");
return ret;
}
printk("Register spi control.\n");
spi_init_gv7601();
//reset the device
//low
Hi3516_gpio_setpin(IO_ADDRESS(GPIO1_BASE+(1<<8)),Hi3516_gpio_getpin(IO_ADDRESS(GPIO1_BASE+(1<<8)))&(~(1<<(8-2))));
udelay(200);
//high
Hi3516_gpio_setpin(IO_ADDRESS(GPIO1_BASE+(1<<8)),Hi3516_gpio_getpin(IO_ADDRESS(GPIO1_BASE+(1<<8)))|(1<<(8-2)));
//spi_setcs_gv7601(1);
//ndelay(20);
//set_value();
//spi_setcs_gv7601(2);
return 0;
}
static void __exit spi_gv7601_exit(void)
{
unregister_chrdev(GV7601_MAJOR, DEVICE_NAME);
printk(KERN_INFO "unregister spi control.\n");
}
module_init(spi_gv7601_init);
module_exit(spi_gv7601_exit);
MODULE_LICENSE("GSPI");
MODULE_AUTHOR("Dong 100");
MODULE_VERSION("0.1");
MODULE_DESCRIPTION("gv7601 control driver");
/*读取的测试程序*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <string.h>
typedef struct tem{
unsigned short address;
unsigned short value;
}command;
command temp;
int main(int argc, char *argv[])
{
//printf("~~~~%s~~~~~",argv[1]);
//printf("....%c....",*argv[1]+1);
//printf("the char size is %d",sizeof(char));
//printf("the number is %d",strlen(argv[1]));
if (argc<=1||argc>3)
{
printf("wrong command \n ./test_spi 000 for read from 000H\n ./test_spi 000 0012 for write 0012 to adress 000H\n");
return 0;
}
else if (argc==2)
{
if (strlen(argv[1])>3)
{
printf("address is too long, 12bits max");
return 0;
}
char a;
int i;
unsigned short result=0;
printf("read address command\n");
for (i=1;i<=strlen(argv[1]);i++)
{
a=*(argv[1]+i-1);
if (a>='0'&&a<='9')
a=a-'0';
else if (a>='a'&&a<='f')
a=a-'a'+10;
else if (a>='A'&&a<='F')
a=a-'A'+10;
else
return 0;
//printf("now a is %x",a);
//j=strlen(argv[1])-i;
result=result+a;
if (i!=strlen(argv[1]))
result=result<<4;
}
printf("read from address%x\n",result);
int fd;
fd = open("/dev/spi_g",2);
printf("open fd is %d\n",fd);
int ret;
temp.address=result;
temp.value=0x0000;
ret=read(fd,&temp,sizeof(temp));
printf("read value is %x\n",temp.value);
}
else
{
if (strlen(argv[1])>3)
{
printf("address is too long, 12bits max");
return 0;
}
if (strlen(argv[2])>4)
{
printf("data is too long, 16bits max");
return 0;
}
char a;
int i;
unsigned short result,result2=0;
//printf("read address command");
printf("write to address comand\n");
result=0;
for (i=1;i<=strlen(argv[1]);i++)
{
a=*(argv[1]+i-1);
if (a>='0'&&a<='9')
a=a-'0';
else if (a>='a'&&a<='f')
a=a-'a'+10;
else if (a>='A'&&a<='F')
a=a-'A'+10;
else
return 0;
//printf("now a is %x",a);
//j=strlen(argv[1])-i;
result=result+a;
if (i!=strlen(argv[1]))
result=result<<4;
}
result2=0;
for (i=1;i<=strlen(argv[2]);i++)
{
a=*(argv[2]+i-1);
if (a>='0'&&a<='9')
a=a-'0';
else if (a>='a'&&a<='f')
a=a-'a'+10;
else if (a>='A'&&a<='F')
a=a-'A'+10;
else
return 0;
//printf("now a is %x",a);
//j=strlen(argv[1])-i;
result2=result2+a;
if (i!=strlen(argv[2]))
result2=result2<<4;
}
printf("write to address%x,data is %x\n",result,result2);
int fd;
fd = open("/dev/spi_g",2);
printf("open fd is %d\n",fd);
int ret;
temp.address=result;
temp.value=result2;
ret=write(fd,&temp,sizeof(temp));
//printf("read value is %x\n",temp.value);
}
return 0;
}
/*Makefile*/
obj-m += ssp.o
all:
arm-hisiv300-linux-gcc -g -Wall -o ssp_test ssp_test.c
make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- -C /home/zslf/hi3516a/Hi3516A_SDK_V1.0.5.0/osdrv/opensource/kernel/linux-3.4.y SUBDIRS=$(PWD) modules
rm *.o modules.* *.symvers *.mod.c
clean:
@rm -rf ssp_test
make ARCH=arm CROSS_COMPILE=arm-hisiv300-linux- -C /home/zslf/hi3516a/Hi3516A_SDK_V1.0.5.0/osdrv/opensource/kernel/linux-3.4.y SUBDIRS=$(PWD) clean
按源码执行会出现错误:
/home/zslf/hi3516a/Hi3516A_SDK_V1.0.5.0/tools_test/spi测试/ssp.c:334:1: error: unknown field ‘ioctl’ specified in initializer
.ioctl = gv7601_ioctl,
^
问题是由于2.6.36内核之后 去掉了原来的ioctl,添加两个新的成员,所以会出错
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
所以修改源文件中file_operations内.ioctl 改为 .compat_ioctl 即可OK,编译通过,警告咱就忽略了
再无绕指柔: iic的问题二,软件模拟,不应该是开漏加上拉电阻吗
levelgxw: 文章写得比较细,很有学习价值,转载留存以待不时之需。
ckiui3: PR全套安装包 https://blog.csdn.net/tanziyihuijian_/article/details/142236359/
ckiui3: PR全套安装包 https://blog.csdn.net/tanziyihuijian_/article/details/142236359/