ARM技术论坛
直播中

agdhun

9年用户 470经验值
擅长:可编程逻辑 嵌入式技术 EDA/IC设计 处理器/DSP 接口/总线/驱动 RF/无线
私信 关注
[经验]

【MYD-CZU3EG开发板试用体验】【图像篇】 Sii9022的IIC操作

做图像处理最终结果要么保存到文件内,要么通过一个设备显示出来,HDMI实现了显示渠道的接口,在MYD-CZU3EG这块板卡上,使用了SiI9022这款HDMI发送器,充当了将RGB数据转成HDMI信号发送出去的功能,SiI9022是基于IIC接口进行配置操作,具体有以下几种操作流程:
1.png
Zynq MPSoc使用I2C共有3种模式:
1.     PS I2C Controller+MIO;
2.     PS I2CController+EMIO(PL IO);
3.     PL Logic Driver;
本文基于第二种进行操作,使用EMIO不仅仅可以利用到PS已有的硬核,还可以使用PL端的Chipscope进行波形的抓取,相对于MIO,在内部多了一个逻辑分析仪,相对于PL逻辑实现,无需占用PL逻辑资源;
配置SiI9022前提要先配置MPSoc的I2C controller,Xilinx提供的库函数太过臃肿,故此使用直接寄存器操作:
一般I2C控制器设计的操作流程是:初始化控制器->设置从机地址、数据->启动传输 ->查询状态;MPSoc的初始化控制器流程如下:
1.     备份Interrupt Mask寄存器
2.     设置Interrupt Disabled寄存器为0x2FF
3.     初始化FIFO,清除Transfer Size;
4.     清除Interrupt Status寄存器
5.     设置Mask备份值到Interrupt Enable寄存器;
6.     设置超时周期;
7.     清除Interrupt Status寄存器
8.     设置SCL时钟,SCL时钟根据Control寄存器的DivisorA和DivisorB值计算的,计算公式:I2C系统时钟/22U * (Div_a + 1U) * (Div_b + 1U)
MPSoc通过I2C写数据到从机,一般情况都使用3Phase模式,即从机地址+从机寄存器地址+数据,这种情况下的流程:
1.     等待总线空闲;
2.     设置是否处理应答(ACK_EN)、寻址模式(NEA)、主机模式还是从机模式(MS)、读还是写(RW)、是否需要重启动(HOLD)(Control寄存器)
3.     初始化FIFO,清除Transfer Size;
4.      禁用所有中断设置Interrupt Disabled寄存器为0x2FF
5.      清除Interrupt Status寄存器
6.      写入从机寄存器地址(寄存器偏移0xC);
7.     写入从机寄存器地址需要写入的值(寄存器偏移0xC);(这一步可选)
8.     写入从机地址(寄存器偏移0x8)(在执行这一步写入后,传输已经开始);
9.     读取ISR寄存器的Complete位,来轮询传输是否已经结束;
10.  判断ISR的ARB_LOST、TX_OVF、NACK是否激活,如果都没有激活,表示传输过程没有出现错误
11.  等待总线空闲;
MPSoc通过I2C从从机读数据,一般有两种模式,
l  先执行写操作,但不是真正写,只是设置从机寄存器地址,然后执行Current Read,即在上次写的从机寄存器地址上读数据(此种方式取决于器件是否支持,根据手册,SiI9022是支持这种操作)
l  先写从机寄存器地址、重启动、读数据,此种方式不太方便利用之前I2C写的流程;
本文使用第一种,读流程如下:
1.     执行I2C写操作;
2.     设置是否处理应答(ACK_EN=1)、寻址模式(NEA=1)、主机模式还是从机模式(MS=1)、读还是写(RW=1)、不需要重启动(HOLD=0)(Control寄存器)
3.     清除Interrupt Status寄存器
4.     设置Transfer Size寄存器为1,只读一个Byte数据;
5.     写入从机地址(寄存器偏移0x8)(在执行这一步写入后,传输已经开始);
6.     读取ISR寄存器的RX_DV位,来轮询传输是否已经结束,或者延迟1ms;
7.     判断ISR的ARB_LOST、RX_OVF、RX_UNF、NACK是否激活,如果都没有激活,表示传输过程没有出现错误
8.     等待总线空闲;
使用上述流程对SiI9022操作,操作步骤如下:
  • 设置I2C Brige连通channel1;
  • 写寄存器0xC7值0,进行复位;(从机地址居然是0x3b,手册上是0x76,好奇怪)
  • 读寄存器0x1B-0x1D;

读取SiI9022 ID如下图所示,根据手册,发现器件类型是9022A;

2.png

使用EMIO可以利用Vivado的Chipscope对从PS过来的信号进行捕捉,EMIO并不是PS直接到PL引脚上,而是到PL逻辑入口,具体怎么连接到哪,是否会做某些处理,完全取决于PL Logic;

Vivado的Chipscope捕捉分为Trigger和Capture,Trigger是捕捉到一次匹配条件,抓取设定好的前后多少个数据,而Capture是在满足一次匹配,捕捉一次,有多少个匹配,就会产生多少个点。捕捉低速信号,例如I2C,可以使用Capture,不过需要有scl的N倍频时钟作为捕捉条件;Trigger还有多窗口捕捉,可以实现多次捕捉,一次只捕捉设定好的点数;

下图是捕捉本例的结果:

3.png

写从机地址0x70,数据2,2Phase模式

4.png

写从机地址0x3b,寄存器地址0xC7,数据0,3Phase模式

5.png

读从机地址0x3b,寄存器地址0x1B

6.png

读从机地址0x3b,寄存器地址0x1C

7.png

读从机地址0x3b,寄存器地址0x1D
Main Code:
  1. #include
  2. #include "platform.h"
  3. #include "xil_printf.h"
  4. #include "xil_io.h"
  5. #include "sleep.h"

  6. #define CRL_APB 0xFF5E0000
  7. #define RST_LPD_IOU2 0x238
  8. #define I2C0_BASE     0xFF020000
  9. #define I2C1_BASE     0xFF030000

  10. static u32 i2cc_addr = I2C0_BASE;

  11. u32 Zu_I2c_Init(void)
  12. {
  13.     u32 IntrMaskReg;
  14.         u32 IntrStatusReg;
  15.         IntrMaskReg = Xil_In32(i2cc_addr+0x20);
  16.         Xil_Out32(i2cc_addr+0x28, 0x2FF);
  17.         Xil_Out32(i2cc_addr, 0x40);
  18.         IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  19.         Xil_Out32(i2cc_addr+0x10, IntrStatusReg);
  20.         IntrMaskReg = (u32)0x2FF & (~IntrMaskReg);
  21.         Xil_Out32(i2cc_addr+0x24, IntrMaskReg);
  22.         Xil_Out32(i2cc_addr, 0);
  23.         Xil_Out32(i2cc_addr+0x1C, 0xFF);
  24.         Xil_Out32(i2cc_addr+0x28, 0x2FF);
  25. }

  26. s32 Zu_I2c_BusIsBusy()
  27. {
  28.         u32 ControlReg;
  29.         u32 StatusReg;
  30.         s32        Status;

  31.         ControlReg = Xil_In32(i2cc_addr);
  32.         StatusReg = Xil_In32(i2cc_addr+0x4);
  33.         if (((StatusReg & 0x100) != 0x0U) && ((ControlReg&0x10)==0)) {
  34.                 Status = (s32)TRUE;
  35.         }else {
  36.                 Status = (s32)FALSE;
  37.         }
  38.         return Status;
  39. }

  40. u32 Zu_I2c_Write(u32 phy_addr, u32 reg_addr, u32 *reg_data)
  41. {
  42.         u32 ControlReg;
  43.         u32 Intrs;
  44.         u32 IntrStatusReg;
  45.         u32 Status;
  46.         if(Zu_I2c_BusIsBusy())
  47.         {
  48.                 xil_printf("Bus is Busynr");
  49.                 return 1;
  50.         }
  51.         ControlReg = Xil_In32(i2cc_addr)&(~0x4F);
  52.         ControlReg |= (u32)0x4E;
  53.         Xil_Out32(i2cc_addr, ControlReg);

  54.         Xil_Out32(i2cc_addr+0x28, 0x2FF);// Disabled all interrupt
  55.         Intrs = (u32)0x240;//0x244;
  56.         IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  57.         Xil_Out32(i2cc_addr+0x10, IntrStatusReg);

  58.         Xil_Out32(i2cc_addr+0xC,(u32)(reg_addr));
  59.         if(reg_data != NULL)
  60.                 Xil_Out32(i2cc_addr+0xC,(u32)(*reg_data));
  61. //        Xil_Out32(i2cc_addr+0x14,1);
  62.         Xil_Out32(i2cc_addr+0x8, (u32)phy_addr);
  63.         IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  64.         while ((IntrStatusReg & 1) != 1){    //Check Complete
  65.                 IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  66.                 if ((IntrStatusReg & Intrs) != 0U) {
  67.                         break; //Capture Error
  68.                 }
  69.         }

  70.         if ((IntrStatusReg & Intrs) != 0U) {
  71.                 if (IntrStatusReg & 0x200) {
  72.                         Status = (s32) 1089;
  73.                 } else {
  74.                         Status = (s32)1;
  75.                 }
  76.         } else {
  77.                         Status = (s32)0;
  78.                         while(Zu_I2c_BusIsBusy());
  79.         }
  80.         return Status;
  81. }

  82. u32 Zu_I2c_Read(u32 phy_addr, u32 reg_addr, u32 *reg_data)
  83. {
  84.         u32 IntrStatusReg = 0;
  85.         u32 Intrs = 0;
  86.         u32 StatusReg = 0;
  87.         u32 Status = 0;
  88.         u32 ControlReg = 0;

  89.         Status = Zu_I2c_Write(phy_addr, reg_addr, NULL);
  90.         if(Status != 0)
  91.         {
  92.                 xil_printf("Write Status: %dnr", Status);
  93.                 return Status;
  94.         }

  95.         usleep(250000);
  96.         ControlReg = Xil_In32(i2cc_addr);
  97.         ControlReg |= (u32)0x4F;
  98.         Xil_Out32(i2cc_addr, ControlReg);

  99.         IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  100.         Xil_Out32(i2cc_addr+0x10, IntrStatusReg);

  101.         Xil_Out32(i2cc_addr+0x14,1);
  102.         Xil_Out32(i2cc_addr+0x8, (u32)phy_addr);
  103.         usleep(1000);
  104.         Intrs = (u32)0x2a4;
  105.         IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  106.         if ((IntrStatusReg & Intrs) == 0U) {
  107.                 StatusReg = Xil_In32(i2cc_addr+0x4);

  108.             if((StatusReg & 0x20) != 0U) {
  109.                         *reg_data = Xil_In32(i2cc_addr+0x0C);
  110.                         StatusReg = Xil_In32(i2cc_addr+0x4);
  111.                 }
  112.             else if((StatusReg & 0x40) != 0U) {
  113.                     xil_printf("RX FIFO Overflownr");
  114.                         *reg_data = Xil_In32(i2cc_addr+0x0C);
  115.                         StatusReg = Xil_In32(i2cc_addr+0x4);
  116.                 }
  117. //                IntrStatusReg = Xil_In32(i2cc_addr+0x10);
  118. //                Xil_Out32(i2cc_addr+0x10, IntrStatusReg);
  119. //                Xil_Out32(i2cc_addr+0x08, phy_addr);
  120. //                Xil_Out32(i2cc_addr+0x14,1);
  121. //                IntrStatusReg = Xil_In32(i2cc_addr+0x0C);
  122.         }

  123. //        Xil_Out32(i2cc_addr+0x0C, Xil_In32(i2cc_addr+0x0) & (~0x10));
  124.         if ((IntrStatusReg & Intrs) != 0U) {
  125.                 if (IntrStatusReg & 0x20) {
  126.                         Status = (s32) 1089;
  127.                 } else {
  128.                         Status = (s32)1;
  129.                 }
  130.         } else {
  131.                 Status = (s32)0;

  132.                 while(Zu_I2c_BusIsBusy());
  133.         }

  134.         return Status;
  135. }



  136. void Zu_Set_Scl_Clock(u32 freq)
  137. {
  138.         u32 Div_a;
  139.         u32 Div_b;
  140.         u32 ActualFscl;
  141.         u32 Temp;
  142.         u32 TempLimit;
  143.         u32 LastError;
  144.         u32 BestError;
  145.         u32 CurrentError;
  146.         u32 ControlReg;
  147.         u32 CalcDivA;
  148.         u32 CalcDivB;
  149.         u32 BestDivA;
  150.         u32 BestDivB;
  151.         u32 FsclHzVar = 100000;

  152.         Temp = XPAR_PSU_I2C_0_I2C_CLK_FREQ_HZ / ((u32)22U * FsclHzVar);
  153.         /*
  154.          * If frequency 400KHz is selected, 384.6KHz should be set.
  155.          * If frequency 100KHz is selected, 90KHz should be set.
  156.          * This is due to a hardware limitation.
  157.          */
  158.         if(FsclHzVar > (u32)384600U) {
  159.                 FsclHzVar = (u32)384600U;
  160.         }
  161.         if((FsclHzVar <= (u32)100000U) && (FsclHzVar > (u32)90000U)) {
  162.                 FsclHzVar = (u32)90000U;
  163.         }
  164.         TempLimit = ((XPAR_PSU_I2C_0_I2C_CLK_FREQ_HZ %
  165.                         ((u32)22 * FsclHzVar)) !=         (u32)0x0U) ?
  166.                                                 Temp + (u32)1U : Temp;
  167.         BestError = FsclHzVar;

  168.         BestDivA = 0U;
  169.         BestDivB = 0U;
  170.         for ( ; Temp <= TempLimit ; Temp++)
  171.         {
  172.                 LastError = FsclHzVar;
  173.                 CalcDivA = 0U;
  174.                 CalcDivB = 0U;

  175.                 for (Div_b = 0U; Div_b < 64U; Div_b++) {

  176.                         Div_a = Temp / (Div_b + 1U);

  177.                         if (Div_a != 0U){
  178.                                 Div_a = Div_a - (u32)1U;
  179.                         }
  180.                         if (Div_a > 3U){
  181.                                 continue;
  182.                         }
  183.                         ActualFscl = XPAR_PSU_I2C_0_I2C_CLK_FREQ_HZ /
  184.                                                 (22U * (Div_a + 1U) * (Div_b + 1U));

  185.                         if (ActualFscl > FsclHzVar){
  186.                                 CurrentError = (ActualFscl - FsclHzVar);}
  187.                         else{
  188.                                 CurrentError = (FsclHzVar - ActualFscl);}

  189.                         if (LastError > CurrentError) {
  190.                                 CalcDivA = Div_a;
  191.                                 CalcDivB = Div_b;
  192.                                 LastError = CurrentError;
  193.                         }
  194.                 }
  195.                 if (LastError < BestError) {
  196.                         BestError = LastError;
  197.                         BestDivA = CalcDivA;
  198.                         BestDivB = CalcDivB;
  199.                 }
  200.         }
  201.         ControlReg = Xil_In32(i2cc_addr);
  202.         ControlReg &= ~((u32)0xC000 | (u32)0x3F00);
  203.         ControlReg |= (BestDivA << 14) | (BestDivB << 8);
  204.         Xil_Out32(i2cc_addr, ControlReg);
  205. }

  206. int main()
  207. {
  208.         u32 dev_1 = 0 ;
  209.         u32 dev_2 = 0;
  210.         u32 dev_3 = 0 ;
  211.         u32 dev_4 = 0;
  212.         u32 sii_dev = 0;
  213.         u32 reset = 0;
  214.         u32 Status;
  215.         u32 ov2640_addr = 0x3b;
  216.     init_platform();
  217.     Xil_Out32(0xFF0A0000 + 0x2C4,0x00000001);
  218.         Xil_Out32(0xFF0A0000 + 0x2C8,0x00000001);
  219.         Xil_Out32(0xFF0A0000 + 0x18,0xFFFE0001);
  220.         usleep(2500);
  221.     Zu_I2c_Init();

  222.         //Xil_Out32(0xA0001000, 1);
  223.         Zu_Set_Scl_Clock(100000);
  224.         Zu_I2c_Write(0x70, 0x2, NULL);
  225.         Zu_I2c_Write(0x3b, 0xC7, &reset);
  226.         usleep(250000);
  227.         Status = Zu_I2c_Read(0x3b, 0x1B, &dev_1);
  228.         Status = Zu_I2c_Read(0x3b, 0x1C, &dev_2);
  229.         Status = Zu_I2c_Read(0x3b, 0x1D, &dev_3);
  230.         Status = Zu_I2c_Read(0x3b, 0x30, &dev_4);
  231.         sii_dev = dev_1 | (dev_2 << 8) | (dev_3 << 16) | (dev_4 << 24);
  232.         if(sii_dev== 0xB0)
  233.                 xil_printf("Detect Sii9022nr");
  234.         if(sii_dev== 0x0302B0)
  235.                 xil_printf("Detect Sii9022Anr");
  236.         if(sii_dev== 0x120000B0)
  237.                 xil_printf("Detect Sii9024nr");
  238.         if(sii_dev== 0x120302B0)
  239.                 xil_printf("Detect Sii9024Anr");
  240.         if(sii_dev== 0x123000B4)
  241.                 xil_printf("Detect Sii9136/9334nr");

  242.     cleanup_platform();
  243.     return 0;
  244. }


更多回帖

发帖
×
20
完善资料,
赚取积分