树莓派I2C控制DLPDLCR230NPEVM(python改写c)+注意事项

树莓派控制230EVM是通过I2C和Parallel RGB,这里主要介绍I2C。

由于官网的例程是python语言,想要改成C语言,重点在于I2C函数的写。

以下代码为读取adc电源的例程。(16位)

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 



int i2c_write_bytes(int fd, unsigned short slave_addr, unsigned short reg_addr, unsigned char *data, int len)
{
  unsigned char *data_wr = NULL;
  int ret = -1;

  data_wr = (unsigned char *)malloc(len + 2);
  if (!data_wr) {
    printf("%s, malloc failed!\n", __func__);
    return -1;
  }

  data_wr[0] = reg_addr / 0xff;
  data_wr[1] = reg_addr % 0xff;
  memcpy(&data_wr[2], data, len);

  ioctl(fd, I2C_SLAVE, slave_addr);
  ioctl(fd, I2C_TIMEOUT, 1);
  ioctl(fd, I2C_RETRIES, 1);

  ret = write(fd, data_wr, len+2);
  if (ret < 0) {
    printf("%s, write failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

   printf("%s, write ok, num: %d\n", __func__, ret); //

  if (data_wr != NULL) {
    free(data_wr);
    data_wr = NULL;
  }

  return ret;
}

int i2c_read_bytes(int fd, unsigned short slave_addr, unsigned short reg_addr, unsigned char *data, int len)
{
  unsigned char addr[2] = { 0 };
  int ret = -1;

  ioctl(fd, I2C_SLAVE, slave_addr);
  ioctl(fd, I2C_TIMEOUT, 1);
  ioctl(fd, I2C_RETRIES, 1);

  addr[0] = reg_addr / 0xff;
  addr[1] = reg_addr % 0xff;

  ret = write(fd, addr, 2);
  if (ret < 0) {
    printf("%s, write failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  ret = read(fd, data, len);
  if (ret < 0) {
    printf("%s, read failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  // printf("%s, read ok, num: %d\n", __func__, ret);

  return ret;
}

float adc_read_votage(char * dev, unsigned short slave_addr, unsigned short reg_addr, int len)
{
  int fd = -1;
  unsigned char buf[2] = { 0 };
  float ret = 0.0;
  
  fd = open(dev, O_RDWR);
  if (fd < 0) {
    printf("%s, open failed!\n", __func__);
    return -1;
  }
  
  if(i2c_read_bytes(fd, slave_addr, reg_addr, buf, len) < 0){
    printf("%s, i2c read failed!\n", __func__);
    return -1;
  }
  
  // calculate votage value
  ret = (float)((buf[0]<<4) + (buf[1] >> 4))/255*3.4*20.32/4.32;
  
  close(fd);
  
  return ret;
}


 int main(void)
 {
   int fd = -1;
  
   int len = 2;
   int i = 0;

   float value = 0.0;
  
   fd = open("/dev/i2c-7", O_RDWR);
   if (fd < 0) {
     printf("%s, open failed!\n", __func__);
     return -1;
  
  
   close(fd);

   return 0;
 }

原本的python程序如下。(调用的函数及其他文件未附上,可在官网下载查看)

本代码是最简短完成该功能的。(注释部分可恢复)

import struct
import time

from enum import Enum

import sys, os.path
python_dir = (os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
sys.path.append(python_dir)
from api.dlpc343x_xpr4 import *
from api.dlpc343x_xpr4_evm import *
from linuxi2c import *
import i2c

class Set(Enum):
    Disabled = 0
    Enabled = 1

def main():
        '''
        Initializes the Raspberry Pi's GPIO lines to communicate with the DLPDLCR230NPEVM,
        and configures the DLPDLCR230NPEVM to project RGB666 parallel video input received from the Raspberry Pi.
        It is recommended to execute this script upon booting the Raspberry Pi.
        '''

        gpio_init_enable = True          # Set to FALSE to disable default initialization of Raspberry Pi GPIO pinouts. TRUE by default.
        i2c_time_delay_enable = False    # Set to FALSE to prevent I2C commands from waiting. May lead to I2C bus hangups with some commands if FALSE.
        i2c_time_delay = 0.8             # Lowering this value will speed up I2C commands. Too small delay may lead to I2C bus hangups with some commands.
        protocoldata = ProtocolData()

        def WriteCommand(writebytes, protocoldata):
            '''
            Issues a command over the software I2C bus to the DLPDLCR230NP EVM.
            Set to write to Bus 7 by default
            Some commands, such as Source Select (splash mode) may perform asynchronous access to the EVM's onboard flash memory.
            If such commands are used, it is recommended to provide appropriate command delay to prevent I2C bus hangups.
            '''
            # print ("Write Command writebytes ", [hex(x) for x in writebytes])
            if(i2c_time_delay_enable): 
                time.sleep(i2c_time_delay)
            i2c.write(writebytes)       
            return

        def ReadCommand(readbytecount, writebytes, protocoldata):
            '''
            Issues a read command over the software I2C bus to the DLPDLCR230NP EVM.
            Set to read from Bus 7 by default
            Some commands, such as Source Select (splash mode) may perform asynchronous access to the EVM's onboard flash memory.
            If such commands are used, it is recommended to provide appropriate command delay to prevent I2C bus hangups.
            '''
            # print ("Read Command writebytes ", [hex(x) for x in writebytes])
            if(i2c_time_delay_enable): 
                time.sleep(i2c_time_delay)
            i2c.write(writebytes) 
            readbytes = i2c.read(readbytecount)
            return readbytes

        # ##### ##### Initialization for I2C ##### #####
        # register the Read/Write Command in the Python library
        DLPC343X_XPR4init(ReadCommand, WriteCommand)
        i2c.initialize()
        if(gpio_init_enable): 
           InitGPIO()
        # ##### ##### Command call(s) start here ##### #####  

        print("Setting DLPC3436 Input Source to Raspberry Pi...")
        Summary = WriteDisplayImageCurtain(1,Color.Black)
        Summary = WriteSourceSelect(Source.ExternalParallelPort, Set.Disabled)
        #Summary = WriteInputImageSize(1920, 1080)

        print("Configuring DLPC3436 Source Settings for Raspberry Pi...")
        #Summary = WriteActuatorGlobalDacOutputEnable(Set.Enabled)
        #Summary = WriteExternalVideoSourceFormatSelect(ExternalVideoFormat.Rgb666)
        #Summary = WriteVideoChromaChannelSwapSelect(ChromaChannelSwap.Cbcr)
        #Summary = WriteParallelVideoControl(ClockSample.FallingEdge,  Polarity.ActiveHigh,  Polarity.ActiveLow,  Polarity.ActiveLow)
        #Summary = WriteColorCoordinateAdjustmentControl(0)
        #Summary, BitRate, PixelMapMode = ReadFpdLinkConfiguration()
        #Summary = WriteDelay(50)
        time.sleep(1)
        Summary = WriteDisplayImageCurtain(0,Color.Black)

        # ##### ##### Command call(s) end here ##### #####
        i2c.terminate()


if __name__ == "__main__" : main()

此代码用C语言改写的如下,添加了投图的功能。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define slave_address 0x1b

#define WriteDisplayImageCurtain    0x16   //0x01
#define WriteSourceSelect           0x05   // 0x01
#define WriteInputImageSize    0x60      //1920*1080
#define WriteActuatorGlobalDacOutputEnable 0xae   //0x01
#define WriteExternalVideoSourceFormatSelect  0x6d //0x02
#define WriteVideoChromaChannelSwapSelect   0x4d  //0x08
#define WriteParallelVideoControl  0x6B   //0x02
#define WriteColorCoordinateAdjustmentControl 0x86   //0x00
#define ReadFpdLinkConfiguration
#define WriteDelay

int i2c_write_bytes(int fd, unsigned short slave_addr, unsigned short reg_addr, unsigned char *data, int len)
{
  unsigned char *data_wr = NULL;
  int ret = -1;

  data_wr = (unsigned char *)malloc(len + 1); //将申请的动态内存的“地址”复制给指针变量data_wr
  if (!data_wr) {
    printf("%s, malloc failed!\n", __func__);      
    return -1;
  }

  data_wr[0] = reg_addr;

  memcpy(&data_wr[1], data, len); //由data所指内存区域复制len个字节到data_wr所指内存区域

  ioctl(fd, I2C_SLAVE, slave_addr); //设置从机地址
  ioctl(fd, I2C_TIMEOUT, 1); //设置超时
  ioctl(fd, I2C_RETRIES, 1); //设置重试次数

  ret = write(fd, data_wr, len+1);
  if (ret < 0) {
    printf("%s, write failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  // printf("%s, write ok, num: %d\n", __func__, ret);

  if (data_wr != NULL) {
    free(data_wr);
    data_wr = NULL;
  }

  return ret;
}

int i2c_read_bytes(int fd, unsigned short slave_addr, unsigned short reg_addr, unsigned char *data, int len)
{
  unsigned char addr[2] = { 0 };
  int ret = -1;

  ioctl(fd, I2C_SLAVE, slave_addr);
  ioctl(fd, I2C_TIMEOUT, 1);
  ioctl(fd, I2C_RETRIES, 1);

  addr[0] = reg_addr / 0xff; 
  addr[1] = reg_addr % 0xff;  

  ret = write(fd, addr, 2);
  if (ret < 0) {
    printf("%s, write failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  ret = read(fd, data, len);
  if (ret < 0) {
    printf("%s, read failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  // printf("%s, read ok, num: %d\n", __func__, ret);

  return ret;
}

int main(void)
{
  int fd = -1;  
  //int len = 2;
  printf("Initializing Raspberry Pi Default Settings for DLPC3436...\n");
  system("raspi-gpio set 0 op pn");
  system("raspi-gpio set 1-27 ip pn");
  sleep(1);
  system("gpio drive 0 5");
  system("raspi-gpio set 22 op pn");
  system("raspi-gpio set 23 op pn");
  system("raspi-gpio set 0-21 a2 pn");
  system("raspi-gpio set 25 op dh");
  
  fd = open("/dev/i2c-7", O_RDWR);
  if (fd < 0) {
    printf("%s, open failed!\n", __func__);
    return -1;
  }
  unsigned char send_data[12] = {0x01,0x01,0x00,0x07,0x38,0x04,0x01,0x02,0x00,0x02,0x00,0x00};
  //unsigned char rec_data[1] = {0x00};
  printf("send regisiter data is %d !\n", send_data[0]);
  printf("Setting DLPC3436 Input Source to Raspberry Pi...\n");
  i2c_write_bytes(fd, slave_address, 0x16, &send_data[0], 1);  //WriteDisplayImageCurtain 
  i2c_write_bytes(fd, slave_address, 0x05, &send_data[1], 2);   //WriteSourceSelect    //0x01 
  //i2c_write_bytes(fd, slave_address, 0x60, &send_data[2], 4);   //WriteInputImageSize  4byte
  
  printf("Configuring DLPC3436 Source Settings for Raspberry Pi...\n");
  //i2c_write_bytes(fd, slave_address, 0xae, &send_data[6], 1);   //WriteActuatorGlobalDacOutputEnable     0xae   //0x01
  //i2c_write_bytes(fd, slave_address, 0x6d, &send_data[7], 1);   //WriteExternalVideoSourceFormatSelect   0x6d   //0x02
  //i2c_write_bytes(fd, slave_address, 0x4d, &send_data[8], 1);   //WriteVideoChromaChannelSwapSelect      0x4d   //0x08
  //i2c_write_bytes(fd, slave_address, 0x6b, &send_data[9], 1);   //WriteParallelVideoControl              0x6B   //0x02
  //i2c_write_bytes(fd, slave_address, 0x86, &send_data[10], 1);   //WriteColorCoordinateAdjustmentControl 0x86   //0x00
  //i2c_write_bytes(fd, slave_address, 0x16, &send_data[11], 1);   //ReadFpdLinkConfiguration              0x4c  
  //i2c_write_bytes(fd, slave_address, 0x16, &send_data[12], 1);   //WriteDelay
  sleep(1);
  i2c_write_bytes(fd, slave_address, 0x16, &send_data[11], 1);   //WriteDisplayImageCurtain
  printf("write regisiter data successed !\n");
  
  system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 01.png");
  sleep(0.0001);
  system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 02.png");
  sleep(0.0001);
  system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 03.png");
  /sleep(0.0001);
  system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 04.png");
  sleep(0.0001);
  system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 05.png");
  
  
   //i2c_read_bytes(fd, 0x1b, 0x61, rec_data, 1);
   //printf("read regisiter data is %d !\n", rec_data[0]);
   close(fd);

  return 0;
}

 清晰版如下。

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define slave_address 0x1b

#define WriteDisplayImageCurtain    0x16   
#define WriteSourceSelect           0x05   


int i2c_write_bytes(int fd, unsigned short slave_addr, unsigned short reg_addr, unsigned char *data, int len)
{
  unsigned char *data_wr = NULL;
  int ret = -1;

  data_wr = (unsigned char *)malloc(len + 1); //将申请的动态内存的“地址”复制给指针变量data_wr
  if (!data_wr) {
    printf("%s, malloc failed!\n", __func__);      
    return -1;
  }

  data_wr[0] = reg_addr;

  memcpy(&data_wr[1], data, len); //由data所指内存区域复制len个字节到data_wr所指内存区域

  ioctl(fd, I2C_SLAVE, slave_addr); //设置从机地址
  ioctl(fd, I2C_TIMEOUT, 1); //设置超时
  ioctl(fd, I2C_RETRIES, 1); //设置重试次数

  ret = write(fd, data_wr, len+1);
  if (ret < 0) {
    printf("%s, write failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  // printf("%s, write ok, num: %d\n", __func__, ret);

  if (data_wr != NULL) {
    free(data_wr);
    data_wr = NULL;
  }

  return ret;
}

int i2c_read_bytes(int fd, unsigned short slave_addr, unsigned short reg_addr, unsigned char *data, int len)
{
  unsigned char addr[2] = { 0 };
  int ret = -1;

  ioctl(fd, I2C_SLAVE, slave_addr);
  ioctl(fd, I2C_TIMEOUT, 1);
  ioctl(fd, I2C_RETRIES, 1);

  addr[0] = reg_addr / 0xff; //取高8位
  addr[1] = reg_addr % 0xff;  //取低8位

  ret = write(fd, addr, 2);
  if (ret < 0) {
    printf("%s, write failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  ret = read(fd, data, len);
  if (ret < 0) {
    printf("%s, read failed, ret: 0x%x\n", __func__, ret);
    return ret;
  }

  // printf("%s, read ok, num: %d\n", __func__, ret);

  return ret;
}

int main(void)
{
  int fd = -1;  
  
  printf("Initializing Raspberry Pi Default Settings for DLPC3436...\n");
  system("raspi-gpio set 0 op pn");
  system("raspi-gpio set 1-27 ip pn");
  sleep(1);
  system("gpio drive 0 5");
  system("raspi-gpio set 22 op pn");
  system("raspi-gpio set 23 op pn");
  system("raspi-gpio set 0-21 a2 pn");
  system("raspi-gpio set 25 op dh");
  
  fd = open("/dev/i2c-7", O_RDWR);
  if (fd < 0) {
    printf("%s, open failed!\n", __func__);
    return -1;
  }
  unsigned char send_data[3] = {0x01,0x01,0x00};

  printf("Setting DLPC3436 Input Source to Raspberry Pi...\n");
  i2c_write_bytes(fd, slave_address, WriteDisplayImageCurtain , &send_data[0], 1);  
  i2c_write_bytes(fd, slave_address, WriteSourceSelect, &send_data[1], 2);   
  sleep(1);
  i2c_write_bytes(fd, slave_address, WriteDisplayImageCurtain , &send_data[2], 1);   
  
  //system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 01.png");
  //sleep(1);
  //system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 02.png");
  //sleep(1);
  //system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 03.png");
  //sleep(1);
  //system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 04.png");
  //sleep(1);
  //system("sudo fbi -d /dev/fb0 -T 1 -noverbose -a 05.png");
  
   close(fd);

  return 0;
}

补充:

1.230EVM主控投影的芯片是DLP3436,官网下载的手册有记录每一个寄存器的功能,对应python中的函数。比如WriteDisplayImageCurtain ,在手册中是

树莓派I2C控制DLPDLCR230NPEVM(python改写c)+注意事项_第1张图片

所以我想要实现 python中的Summary = WriteDisplayImageCurtain(1,Color.Black),只需要将0X01写入0x16h寄存器即可。此函数只需写入8位,所以len=1。

2.有些函数是需要写入16位,比如WriteSourceSelect,在手册中看不出来

树莓派I2C控制DLPDLCR230NPEVM(python改写c)+注意事项_第2张图片

可在python中WriteSourceSelect具体函数中看出

 setbits写了两次

def WriteSourceSelect(Source,  ExternalCalibrationEnable):
    "Selects the source of the image to be displayed."
    global Summary
    Summary.Command = "Write Source Select"
    Summary.Successful = True
    global ProtocolData
    ProtocolData.CommandDestination = 0;
    try:
        writebytes=list(struct.pack('B',5))
        ProtocolData.OpcodeLength = 1;
        packerinit()
        value = setbits(Source.value, 3, 0)
        writebytes.extend(list(struct.pack('B',value)))
        packerinit()
        value = setbits(ExternalCalibrationEnable.value, 1, 0)
        writebytes.extend(list(struct.pack('B',value)))
        _writecommand(writebytes, ProtocolData)
    except ValueError as ve:
        print("Exception Occurred ", ve)
        Summary.Successful == False
    finally:
        return Summary

3.查看i2c总线上占用情况,可使用指令

i2cdump -f -y 7 0x1b

此处使用i2c-7,地址位0x1b树莓派I2C控制DLPDLCR230NPEVM(python改写c)+注意事项_第3张图片

查看i2c地址,可使用指令

i2cdetect -y -a 7

树莓派I2C控制DLPDLCR230NPEVM(python改写c)+注意事项_第4张图片

4.运行程序之后,gpio引脚会发生变化,可通过以下指令查看 。

raspi-gpio get

树莓派I2C控制DLPDLCR230NPEVM(python改写c)+注意事项_第5张图片

 5.强制改变i2c总线上某寄存器地址,可通过如下指令。

i2cset -f -y 7 0x1b 0x16 0x01

(i2c-7,地址0x1b,给0x16寄存器 写0x01 )

你可能感兴趣的:(驱动开发,c语言,python)