其实内核是支持tvp5150的驱动,但是驱动安装后,又不知道如何进行iic控制。(才疏学浅,被自己的浅薄给难住了),然后换了思路,要不用应用层来控制得了,反正就是iic的设置。
平台:ls2k1000
系统:linux3.10+中标文件系统。
连接:iic0
tvp的iic设备地址是0xBA或者0xB8,这里根据原理图,确认是0xBA(D7引脚接上拉)
程序运行的方法:
./tvp5150_test w 用于配置指定寄存器(默认使用tvp5150_reg.cfg)
./tvp5150_test w tvp5150_reg.cfg 用于配置指定寄存器(由文件指定寄存器及值)
./tvp5150_test r 用于读取指定寄存器(默认使用tvp5150_reg.cfg)
./tvp5150_test r tvp5150_reg.cfg 用于读取指定寄存器(由文件指定寄存器)
[root@localhost tvp5150]# ./tvp5150_test w
1. Set register 0:
val 0 (0)
2. Set register 0x1:
val 21 (0x15)
3. Set register 0x2:
val 0 (0)
4. Set register 0x3:
val 1 (0x1)
5. Set register 0x6:
val 16 (0x10)
6. Set register 0x7:
val 96 (0x60)
7. Set register 0x8:
val 0 (0)
8. Set register 0x9:
val 128 (0x80)
9. Set register 0xa:
val 128 (0x80)
10. Set register 0xb:
val 0 (0)
11. Set register 0xc:
val 128 (0x80)
12. Set register 0xd:
val 71 (0x47)
13. Set register 0xe:
val 0 (0)
14. Set register 0xf:
val 8 (0x8)
15. Set register 0x11:
val 0 (0)
16. Set register 0x12:
val 0 (0)
17. Set register 0x13:
val 0 (0)
18. Set register 0x14:
val 0 (0)
19. Set register 0x15:
val 1 (0x1)
20. Set register 0x16:
val 128 (0x80)
21. Set register 0x18:
val 0 (0)
22. Set register 0x19:
val 0 (0)
23. Set register 0x1a:
val 12 (0xc)
24. Set register 0x1b:
val 20 (0x14)
25. Set register 0x1c:
val 0 (0)
26. Set register 0x1d:
val 0 (0)
27. Set register 0x1e:
val 0 (0)
28. Set register 0x28:
val 0 (0)
29. Set register 0x2e:
val 15 (0xf)
30. Set register 0x2f:
val 1 (0x1)
31. Set register 0xbb:
val 0 (0)
32. Set register 0xc0:
val 0 (0)
33. Set register 0xc1:
val 0 (0)
34. Set register 0xc2:
val 4 (0x4)
35. Set register 0xc8:
val 128 (0x80)
36. Set register 0xc9:
val 0 (0)
37. Set register 0xca:
val 0 (0)
38. Set register 0xcb:
val 78 (0x4e)
39. Set register 0xcc:
val 0 (0)
40. Set register 0xcd:
val 1 (0x1)
41. Set register 0xcf:
val 0 (0)
42. Set register 0xd0:
val 0 (0)
43. Set register 0xfc:
val 127 (0x7f)
end
源码贴出,直接gcc编译即可
/*
* @Author: dazhi
* @Date: 2022-05-17 10:57:01
* @Last Modified by: dazhi
* @Last Modified time: 2022-05-18 09:51:32
*/
#include <stdio.h>
#include <linux/i2c.h>
#include <linux/i2c-dev.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <string.h>
#define FILENAME "tvp5150_reg.cfg"
#define I2C_FILE_NAME "/dev/i2c-0"
#define IIC_DEV_ADDR 0x5d //iic的设备地址
static int set_i2c_register(int file,
unsigned char addr,
unsigned char reg,
unsigned char value) {
unsigned char outbuf[2];
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[1];
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = outbuf;
/* The first byte indicates which register we'll write */
outbuf[0] = reg;
/*
* The second byte indicates the value to write. Note that for many
* devices, we can write multiple, sequential registers at once by
* simply making outbuf bigger.
*/
outbuf[1] = value;
/* Transfer the i2c packets to the kernel and verify it worked */
packets.msgs = messages;
packets.nmsgs = 1;
if(ioctl(file, I2C_RDWR, &packets) < 0) {
perror("Unable to send data");
return 1;
}
return 0;
}
static int get_i2c_register(int file,
unsigned char addr,
unsigned char reg,
unsigned char *val) {
unsigned char inbuf, outbuf;
struct i2c_rdwr_ioctl_data packets;
struct i2c_msg messages[2];
/*
* In order to read a register, we first do a "dummy write" by writing
* 0 bytes to the register we want to read from. This is similar to
* the packet in set_i2c_register, except it's 1 byte rather than 2.
*/
outbuf = reg;
messages[0].addr = addr;
messages[0].flags = 0;
messages[0].len = sizeof(outbuf);
messages[0].buf = &outbuf;
/* The data will get returned in this structure */
messages[1].addr = addr;
messages[1].flags = I2C_M_RD/* | I2C_M_NOSTART*/;
messages[1].len = sizeof(inbuf);
messages[1].buf = &inbuf;
/* Send the request to the kernel and get the result back */
packets.msgs = messages;
packets.nmsgs = 2;
if(ioctl(file, I2C_RDWR, &packets) < 0) {
perror("Unable to send data");
return 1;
}
*val = inbuf;
return 0;
}
int main(int argc, char **argv) {
FILE* fp;
char * filenamep = FILENAME;
char buf[128];
char buf1[8];
int len;
int reg;
unsigned char val;
char *p;
char rw = 0; //1表示读,2表示写
char rw_flag = 0; //用于写寄存器的时候的标志位,1表示获取寄存器正确,0表示获取寄存器错
int count = 0;
int i2c_file;
if(argc != 3 && argc != 2)
{
printf("Usage: %s r | w [regfile.cfg]\n",argv[0]);
printf("r 的意思是读寄存器的值,读哪些寄存器由regfile.cfg的寄存器区域指定\n");
printf("w 的意思是写寄存器的值,写哪些寄存器由regfile.cfg的寄存器区域指定\n");
printf(" 写入寄存器值由regfile.cfg的值区域指定\n");
printf("参数不指定regfile.cfg文件,将使用默认配置文件tvp5150_reg.cfg\n");
}
else //只有两个参数的时候
{
if(strcmp(argv[1], "r") == 0)
rw = 1;
else if(strcmp(argv[1], "w") == 0)
rw = 2;
if(rw!=1 && rw != 2)
{
printf("参数1 rw 指定错误,请重新输入\n");
printf("Usage: %s r [regfile.cfg] 表示读寄存器\n",argv[0]);
printf("Usage: %s w [regfile.cfg] 表示写寄存器\n",argv[0]);
return -1;
}
if(argc == 3)
{
filenamep = argv[2];
}
//打开文件
fp = fopen(filenamep,"r");
if(fp == NULL)
{
printf("文件%s打开失败!!\n",filenamep);
printf("使用方法: %s r | w regfile.cfg\n",argv[0]);
printf("r 的意思是读寄存器的值,读哪些寄存器由tvp5150_reg.cfg的寄存器区域指定\n");
printf("w 的意思是写寄存器的值,写哪些寄存器由tvp5150_reg.cfg的寄存器区域指定\n");
printf(" 写入寄存器值由tvp5150_reg.cfg的值区域指定\n");
return -1;
}
}
// Open a connection to the I2C userspace control file.
if ((i2c_file = open(I2C_FILE_NAME, O_RDWR)) < 0) {
perror("Unable to open i2c control file");
fclose(fp);
exit(1);
}
//一行一行读
while(1)
{
if(feof(fp)) //文件结尾
break;
if(NULL == fgets(buf, sizeof buf, fp)) //读文件失败,或者读到文件结尾
break;
//读出来了
len = strlen(buf);
if(len > 255 || len < 5) //不可能读出这么多数据,长度不合理
continue;
if(buf[0] == '#') //# 号开头直接跳过
continue;
//printf("buf = %s",buf);
p = strtok(buf,","); //使用逗号分割。
reg = strtol(p, NULL, 0); //进行16进制解析
snprintf(buf1,sizeof buf1,"0x%02hhx",reg);
if(strncmp(p,buf1,strlen(buf1)) == 0)
{
// printf("reg get\n");
if(reg == 0xff) //最后一个寄存器,跳出
break;
if(rw == 1) //读寄存器
{
if(get_i2c_register(i2c_file, IIC_DEV_ADDR, reg, &val)) {
printf("Unable to get register!\n");
}
else {
printf("%d. Register %#x: \n\tval %d (%#x)\n", count+1,reg, (int)val, (int)val);
}
}
else if(rw == 2)
{
rw_flag = 1;
}
}
if(rw == 2) //写寄存器的时候,才需要值
{
p = strtok(NULL,","); //使用逗号分割。
if(p == NULL)
continue;
val = strtol(p, NULL, 0);
snprintf(buf1,sizeof buf1,"0x%02hhx",val);
if(strncmp(p,buf1,strlen(buf1)) == 0) //转换的值与之前的值相等
{
// printf("val get\n");
if(rw_flag == 1)
{
if(set_i2c_register(i2c_file, IIC_DEV_ADDR, reg, val)) {
printf("Unable to get register!\n");
}
else {
printf("%d. Set register %#x: \n\tval %d (%#x)\n",count+1, reg, val, val);
}
rw_flag = 0; //标志位清0
}
}
}
count ++;
}
fclose(fp);
close(i2c_file);
printf("end\n");
return 0;
}
配置文件示例:(这是驱动中截出来的!!!)
# 井号开头表示注释,程序不解析
# 数据只有两个字节,用逗号隔开,第一个数据表示寄存器地址(称为寄存器区域),第二个表示需要设置的值(称为值区域)
# /*TVP5150_VD_IN_SRC_SEL_1*/
0x00,0x00
# /*TVP5150_ANAL_CHL_CTL*/
0x01,0x15
# /*TVP5150_OP_MODE_CTL*/
0x02,0x00
# /*TVP5150_MISC_CTL*/
0x03,0x01
# /*TVP5150_COLOR_KIL_THSH_CTL*/
0x06,0x10
# /*TVP5150_LUMA_PROC_CTL_1*/
0x07,0x60
# /*TVP5150_LUMA_PROC_CTL_2*/
0x08,0x00
# /*TVP5150_BRIGHT_CTL*/
0x09,0x80
# /*TVP5150_SATURATION_CTL*/
0x0a,0x80
# /*TVP5150_HUE_CTL*/
0x0b,0x00
# /*TVP5150_CONTRAST_CTL*/
0x0c,0x80
# /*TVP5150_DATA_RATE_SEL*/
0x0d,0x47
# /*TVP5150_LUMA_PROC_CTL_3*/
0x0e,0x00
# /*TVP5150_CONF_SHARED_PIN*/
0x0f,0x08
# /*TVP5150_ACT_VD_CROP_ST_MSB*/
0x11,0x00
# /*TVP5150_ACT_VD_CROP_ST_LSB*/
0x12,0x00
# /*TVP5150_ACT_VD_CROP_STP_MSB*/
0x13,0x00
# /*TVP5150_ACT_VD_CROP_STP_LSB*/
0x14,0x00
# /*TVP5150_GENLOCK*/
0x15,0x01
# /*TVP5150_HORIZ_SYNC_START*/
0x16,0x80
# /*TVP5150_VERT_BLANKING_START*/
0x18,0x00
# /*TVP5150_VERT_BLANKING_STOP*/
0x19,0x00
# /*TVP5150_CHROMA_PROC_CTL_1*/
0x1a,0x0c
# /*TVP5150_CHROMA_PROC_CTL_2*/
0x1b,0x14
# /*TVP5150_INT_RESET_REG_B*/
0x1c,0x00
# /*TVP5150_INT_ENABLE_REG_B*/
0x1d,0x00
# /*TVP5150_INTT_CONFIG_REG_B*/
0x1e,0x00
# /*TVP5150_VIDEO_STD*/
0x28,0x00
# /*TVP5150_MACROVISION_ON_CTR*/
0x2e,0x0f
# /*TVP5150_MACROVISION_OFF_CTR*/
0x2f,0x01
# /*TVP5150_TELETEXT_FIL_ENA*/
0xbb,0x00
# /*TVP5150_INT_STATUS_REG_A*/
0xc0,0x00
# /*TVP5150_INT_ENABLE_REG_A*/
0xc1,0x00
# /*TVP5150_INT_CONF*/
0xc2,0x04
# /*TVP5150_FIFO_INT_THRESHOLD*/
0xc8,0x80
# /*TVP5150_FIFO_RESET*/
0xc9,0x00
# /*TVP5150_LINE_NUMBER_INT*/
0xca,0x00
# /*TVP5150_PIX_ALIGN_REG_LOW*/
0xcb,0x4e
# /*TVP5150_PIX_ALIGN_REG_HIGH*/
0xcc,0x00
# /*TVP5150_FIFO_OUT_CTRL*/
0xcd,0x01
# /*TVP5150_FULL_FIELD_ENA*/
0xcf,0x00
# /*TVP5150_LINE_MODE_INI*/
0xd0,0x00
# /*TVP5150_FULL_FIELD_MODE_REG*/
0xfc,0x7f
# /* end of data */
0xff,0xff
# 0xff为最后一个寄存器,之后的所有寄存器都不再解析和设置
目前通信测试正常,功能没有测试,因为没有对应的视频信号及接口。
这只是一个通信的例子,请根据实际情况修改。