导航

    全志在线开发者论坛

    • 注册
    • 登录
    • 搜索
    • 版块
    • 话题
    • 在线文档
    • 社区主页

    Tina linux用屏幕转换芯片时I2C初始化问题

    Linux
    3
    13
    1670
    正在加载更多帖子
    • 从旧到新
    • 从新到旧
    • 最多赞同
    回复
    • 在新帖中回复
    登录后回复
    此主题已被删除。只有拥有主题管理权限的用户可以查看。
    • L
      lztmfx LV 5 最后由 编辑

      T113S3使用NCS8801 LVDS转EDP芯片,需要LCD驱动里面通过I2C初始化NCS8801,但是实际测试发现,tina linux的i2c晚于disp驱动加载,这样disp驱动里面获取不到有效的i2c适配器。有什么方法让i2c在disp前加载?另外看别的帖子说不建议在disp里面用硬件i2c初始化,推荐用GPIO模拟,看了SDK里面ST7789V也是用GPIO模拟SPI,但是SPI write的时候,引脚的输入输出是固定的,不用切换引脚状态,但是I2C的SDA引脚在发送完数据后需要切换为input模式来接收ACK信号的,这样如果用lcd设备树里面的这种方式是不行的吧?这个还可以在disp驱动里面通过代码切换lcd_gpio_X的参数吗?如输入改为输出。

      lcd_gpio_0 = <&pio PG 12 1 0 3 0>;
      lcd_gpio_1 = <&pio PG 13 1 0 3 0>;
      

      如果直接在disp驱动使用下面这种方式:

      #define I2C_SCL  204
      #define I2C_SDA  205
      #define I2C_SCL_LOW()  gpio_set_value(I2C_SCL, 0)
      #define I2C_SDA_HIGH() gpio_direction_output(I2C_SDA, 1)
      

      开机会有一堆报错

      [    0.650948] 8<--- cut here ---
      [    0.650952] Unable to handle kernel NULL pointer dereference at virtual address 00000000
      [    0.650960] pgd = (ptrval)
      [    0.658090] uart3: ttyS3 at MMIO 0x2500c00 (irq = 35, base_baud = 1500000) is a SUNXI
      ▒▒  0.660901] [00000000] *pgd=00000000
      [    0.669008] sw_console_setup()1807 - console setup baud 115200 parity n bits 8, flow n
      [    0.671684] Internal error: Oops: 5 [#1] PREEMPT SMP ARM
      [    0.696238] Modules linked in:
      [    0.696238] Modules linked in:
      [    0.696249] CPU: 0 PID: 21 Comm: kworker/0:1 Not tainted 5.4.61 #159
      [    0.696249] CPU: 0 PID: 21 Comm: kworker/0:1 Not tainted 5.4.61 #159
      [    0.696256] Hardware name: Generic DT based system
      [    0.696256] Hardware name: Generic DT based system
      [    0.702736] printk: console [ttyS3] enabled
      [    0.702736] printk: console [ttyS3] enabled
      [    0.716144] Workqueue: events start_work
      [    0.716144] Workqueue: events start_work
      [    0.716154] PC is at LCD_panel_init+0x44/0x13c
      [    0.716154] PC is at LCD_panel_init+0x44/0x13c
      [    0.716162] LR is at LCD_panel_init+0x40/0x13c
      [    0.716162] LR is at LCD_panel_init+0x40/0x13c
      [    0.726281] printk: bootconsole [earlycon0] disabled
      [    0.726281] printk: bootconsole [earlycon0] disabled
      [    0.735110] pc : [<c03962cc>]    lr : [<c03962c8>]    psr: 60000013
      [    0.735110] pc : [<c03962cc>]    lr : [<c03962c8>]    psr: 60000013
      [    0.735114] sp : c714de20  ip : 00000000  fp : 00000000
      [    0.735114] sp : c714de20  ip : 00000000  fp : 00000000
      [    0.735117] r10: 00000001  r9 : 00000000  r8 : c0b1bb66
      [    0.735117] r10: 00000001  r9 : 00000000  r8 : c0b1bb66
      [    0.735124] r7 : c0b1bb50  r6 : 00000000  r5 : 0000000b  r4 : c714c000
      [    0.735124] r7 : c0b1bb50  r6 : 00000000  r5 : 0000000b  r4 : c714c000
      [    0.821770] r3 : 50ca96b2  r2 : 50ca96b2  r1 : 06c7e000  r0 : 00000026
      [    0.821776] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
      [    0.821783] Control: 10c5387d  Table: 4000406a  DAC: 00000051
      [    0.829589] sun8iw20-pinctrl 2000000.pinctrl: 2000000.pinctrl supply vcc-pb not found, using dummy regulator
      [    0.837001] Process kworker/0:1 (pid: 21, stack limit = 0x(ptrval))
      [    0.837006] Stack: (0xc714de20 to 0xc714e000)
      [    0.837017] de20: 00000000 50ca96b2 c730fa00 c7391000 c7390000 00000001 c0c5d028 c0373c88
      [    0.837032] de40: c08272ba c730fa00 c714de98 c07248e0 00000000 00000000 00000000 c036dcf4
      [    0.843742] uart uart4: uart4 supply uart not found, using dummy regulator
      [    0.854390] de60: 00000000 00000000 00020002 c714de6c c714de6c 50ca96b2 c7070c00 c06ea2ac
      [    0.854399] de80: c714c000 00000001 00000000 00000000 c0c596e8 c036df5c 00000001 00000000
      [    0.854407] dea0: 00000000 00000000 00000004 00000000 00000002 00000002 00000000 00000008
      [    0.854416] dec0: 00000000 50ca96b2 00000000 c714c000 c0c59350 00000002 c0c596e8 c0369d10
      [    0.861637] uart4: ttyS4 at MMIO 0x2501000 (irq = 36, base_baud = 1500000) is a SUNXI
      [    0.866247] dee0: 00000001 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    0.866256] df00: 00000000 00000000 00000000 50ca96b2 00000000 c0c591e0 00000001 c0369e28
      [    0.866269] df20: c7040100 c76b6880 c0c594b8 c76b9900 00000000 00000000 c0c594bc c012f0ac
      [    0.876002] uart uart5: uart5 supply uart not found, using dummy regulator
      [    0.884498] df40: c7040100 c0c594b8 c7040100 c7040114 c76b6880 c714c000 c76b6898 c0b02d00
      [    0.884508] df60: c0b0b27c c012f6d0 00000000 c701e880 c714c000 c701e840 c7040100 c012f49c
      [    0.884517] df80: c704bec4 c701e89c 00000000 c0133f24 c701e840 c0133e04 00000000 00000000
      [    0.884527] dfa0: 00000000 00000000 00000000 c01010e8 00000000 00000000 00000000 00000000
      [    0.892457] uart5: ttyS5 at MMIO 0x2501400 (irq = 37, base_baud = 1500000) is a SUNXI
      [    0.901302] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    0.901310] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000 00000000 00000000
      [    0.901333] [<c03962cc>] (LCD_panel_init) from [<c0373c88>] (disp_lcd_enable+0x2a4/0x2e0)
      [    0.901349] [<c0373c88>] (disp_lcd_enable) from [<c036dcf4>] (disp_device_attached_and_enable+0x140/0x260)
      [    0.911201] misc dump reg init
      [    0.919574] [<c036dcf4>] (disp_device_attached_and_enable) from [<c036df5c>] (bsp_disp_device_switch+0x8c/0xec)
      [    0.919586] [<c036df5c>] (bsp_disp_device_switch) from [<c0369d10>] (disp_device_set_config+0xd8/0x100)
      [    0.919597] [<c0369d10>] (disp_device_set_config) from [<c0369e28>] (start_work+0xf0/0x174)
      [    0.919610] [<c0369e28>] (start_work) from [<c012f0ac>] (process_one_work+0x144/0x20c)
      [    0.919626] [<c012f0ac>] (process_one_work) from [<c012f6d0>] (worker_thread+0x234/0x2d8)
      [    1.108057] [<c012f6d0>] (worker_thread) from [<c0133f24>] (kthread+0x120/0x12c)
      [    1.116309] [<c0133f24>] (kthread) from [<c01010e8>] (ret_from_fork+0x14/0x2c)
      [    1.124361] Exception stack(0xc714dfb0 to 0xc714dff8)
      [    1.129992] dfa0:                                     00000000 00000000 00000000 00000000
      [    1.139112] dfc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
      [    1.148231] dfe0: 00000000 00000000 00000000 00000000 00000013 00000000
      [    1.155610] Code: e2878016 e5cd3003 ebf6fd7c e3a06000 (e5963000)
      [    1.162481] ---[ end trace a3d10cdfd74119e3 ]---
      
      

      最后就是官方LCD调试PDF文档里面提到过SPI,I2C初始化的方式,是通过读取设备树信息probe设备的方式,那理论上这种也是需要i2c在disp之前加载吧,而且他T113S3的设备树貌似无法匹配手册上的方法。

      1 条回复 最后回复 回复 引用 分享 1
      • L
        lztmfx LV 5 最后由 编辑

        用上面的方法二报错是其他原因报的错,排查后不报错了,不过I2C还是通讯不上

        L 1 条回复 最后回复 回复 引用 分享 0
        • L
          lztmfx LV 5 @lztmfx 最后由 编辑

          @lztmfx 在 Tina linux用屏幕转换芯片时I2C初始化问题 中说:

          用上面的方法二报错是其他原因报的错,排查后不报错了,不过I2C还是通讯不上

          GPIO模拟I2C调通了,贴下主要部分:

          #define I2C_SCL  204 //PG12
          #define I2C_SDA  205 //PG13
          
          #define I2C_SCL_HIGH() (gpio_set_value(I2C_SCL, 1))
          #define I2C_SCL_LOW()  (gpio_set_value(I2C_SCL, 0))
          #define I2C_SDA_HIGH() gpio_direction_input(I2C_SDA) // 释放SDA(外部上拉拉高)
          #define I2C_SDA_LOW()  gpio_direction_output(I2C_SDA, 0)
          #define I2C_SDA_READ() gpio_get_value(I2C_SDA)
          
          static void i2c_start(void)
          {
              I2C_SDA_HIGH();
              I2C_SCL_HIGH();
          	udelay(5);
              I2C_SDA_LOW();
          	udelay(5);
              I2C_SCL_LOW();
          }
          
          static void i2c_stop(void)
          {
              I2C_SDA_LOW();
              I2C_SCL_HIGH();
          	udelay(5);
              I2C_SDA_HIGH();
          	udelay(5);
          }
          

          注意使用完GPIO后要释放掉,否则后面用到这两个IO的驱动就要报错了,因为这两个IO是真正的I2C PIN,后面I2C驱动用得到,我这个案例就是驱动需要I2C初始化,但是LCD驱动在I2C驱动之前加载,在LCD驱动里面用不了硬件I2C的功能,查了资料,如果从调整驱动加载顺序的思路入手,能查到的方法要么不实际要么没有任何效果。不能让I2C在LCD前加载那就只能GPIO模拟I2C了,参考ST7789V GPIO模拟SPI看着不可行,实际没有测试,因为模拟SPI的GPIO可以不切换方向,而I2C SDA在ACK时需要切换输出为输入,在设备树定义gpio_x的方法不知道怎么在驱动切换GPIO方向,最终使用gpio_request()的方法申请GPIO来做

          H T 2 条回复 最后回复 回复 引用 分享 3
          • H
            Hansk LV 3 最后由 编辑

            您好我也正在调这个,方便请教一下吗?

            1 条回复 最后回复 回复 引用 分享 0
            • H
              Hansk LV 3 最后由 编辑

              此回复已被删除!
              1 条回复 最后回复 回复 引用 分享 0
              • H
                Hansk LV 3 @lztmfx 最后由 编辑

                @lztmfx 您好,请问下这个8801芯片的初始化是放在了哪里? uboot还是kernel

                L 1 条回复 最后回复 回复 引用 分享 0
                • L
                  lztmfx LV 5 @Hansk 最后由 编辑

                  @hansk 我是放在kernel,uboot我没搞了,搞uboot就为了显示个logo没这个需求

                  H 1 条回复 最后回复 回复 引用 分享 0
                  • H
                    Hansk LV 3 @lztmfx 最后由 编辑

                    @lztmfx 您好,请问方便指导一下吗?能否加个联系方式

                    L 1 条回复 最后回复 回复 引用 分享 0
                    • L
                      lztmfx LV 5 @Hansk 最后由 编辑

                      @hansk 发不了联系方式的,你看我资料能不能发邮件

                      H 1 条回复 最后回复 回复 引用 分享 0
                      • H
                        Hansk LV 3 @lztmfx 最后由 编辑

                        @lztmfx 可以呀,感谢大佬。c87fc484-b247-45c2-b08a-2fc31d8d3e6c-image.png

                        L 1 条回复 最后回复 回复 引用 分享 0
                        • T
                          tivon LV 6 @lztmfx 最后由 编辑

                          @lztmfx 谢谢,可能有用

                          1 条回复 最后回复 回复 引用 分享 0
                          • L
                            lztmfx LV 5 @Hansk 最后由 编辑

                            @hansk

                            #define I2C_SCL_HIGH() (gpio_set_value(I2C_SCL, 1))
                            #define I2C_SCL_LOW()  (gpio_set_value(I2C_SCL, 0))
                            #define I2C_SDA_HIGH() gpio_direction_input(I2C_SDA) // 释放SDA(外部上拉拉高)
                            #define I2C_SDA_LOW()  gpio_direction_output(I2C_SDA, 0)
                            #define I2C_SDA_READ() gpio_get_value(I2C_SDA)
                            
                            void init_gpio(void)
                            {
                            	int ret = 0;
                            	ret = gpio_request(I2C_SDA, NULL);
                            	if(ret != 0)
                            	{
                            		printk("\n\n\n%s,%d,ncs8801 panel\n\n\n\n",__func__,__LINE__);
                            	}
                            	ret = gpio_request(I2C_SCL, NULL);
                            	if(ret != 0)
                            	{
                            		printk("\n\n\n%s,%d,ncs8801 panel\n\n\n\n",__func__,__LINE__);
                            	}
                            
                            	// 配置SCL为输出,初始高电平
                                gpio_direction_output(I2C_SDA, 1);
                                // SDA初始化为输出高电平(开漏模式需结合外部上拉)
                                gpio_direction_output(I2C_SCL, 1);
                            }
                            
                            void deinit_gpio(void)
                            {
                                gpio_free(I2C_SCL);
                                gpio_free(I2C_SDA);
                            }
                            
                            static void i2c_start(void)
                            {
                                I2C_SDA_HIGH();
                                I2C_SCL_HIGH();
                            	udelay(5);
                                I2C_SDA_LOW();
                            	udelay(5);
                                I2C_SCL_LOW();
                            }
                            
                            static void i2c_stop(void)
                            {
                                I2C_SDA_LOW();
                                I2C_SCL_HIGH();
                            	udelay(5);
                                I2C_SDA_HIGH();
                            	udelay(5);
                            }
                            
                            static int i2c_write_byte(uint8_t data)
                            {
                                int ack = 0;
                                int i;
                                for (i = 7; i >= 0; i--)
                                {
                                    (data & (1 << i)) ? I2C_SDA_HIGH() : I2C_SDA_LOW();
                                    udelay(2);
                                    I2C_SCL_HIGH();
                                    udelay(5);
                                    I2C_SCL_LOW();
                                    udelay(2);
                                }
                            
                                // 释放 SDA 以便从机发送 ACK
                                I2C_SDA_HIGH();
                                I2C_SCL_HIGH();
                                udelay(2);
                                ack = I2C_SDA_READ() == 0; // 读取 ACK
                                I2C_SCL_LOW();
                                return ack;
                            }
                            
                            static uint8_t i2c_read_byte(int ack)
                            {
                                uint8_t data = 0;
                                int i;
                                
                                // 先设定 SDA 为输入模式
                                gpio_direction_input(I2C_SDA);
                                
                                for (i = 7; i >= 0; i--)
                                {
                                    I2C_SCL_HIGH();
                                    udelay(2);
                                    data |= (I2C_SDA_READ() << i);
                                    I2C_SCL_LOW();
                                    udelay(2);
                                }
                                
                                // 发送 ACK 或 NACK
                                if (ack)
                                    I2C_SDA_LOW();
                                else
                                    I2C_SDA_HIGH(); // 释放 SDA 发送 NACK
                            
                                I2C_SCL_HIGH();
                                udelay(5);
                                I2C_SCL_LOW();
                                
                                return data;
                            }
                            
                            int i2c_based_gpio_write(uint8_t i2cid, uint8_t addr, uint8_t send_val)
                            {
                                i2c_start();
                                if (!i2c_write_byte((i2cid << 1)))
                            	{
                                    i2c_stop();
                                    return -1;
                                }
                                if (!i2c_write_byte(addr))
                            	{
                                    i2c_stop();
                                    return -1;
                                }
                                if (!i2c_write_byte(send_val))
                            	{
                                    i2c_stop();
                                    return -1;
                                }
                                i2c_stop();
                                return 0;
                            }
                            
                            int i2c_based_gpio_write_lists(uint8_t i2cid, const struct reg_data *list, size_t count) {
                                size_t i;
                                for (i = 0; i < count; i++) {
                                    if (i2c_based_gpio_write(i2cid, list[i].reg, list[i].val) < 0) {
                                        return -1;
                                    }
                                }
                                return 0;
                            }
                            
                            int i2c_based_gpio_read(uint8_t i2cid, uint8_t addr, uint8_t *recv_val)
                            {
                                i2c_start();
                                if (!i2c_write_byte((i2cid << 1)))
                            	{
                                    i2c_stop();
                                    return -1;
                                }
                                if (!i2c_write_byte(addr))
                            	{
                                    i2c_stop();
                                    return -1;
                                }
                                
                                i2c_start();
                                if (!i2c_write_byte((i2cid << 1) | 1))
                            	{
                                    i2c_stop();
                                    return -1;
                                }
                                *recv_val = i2c_read_byte(1);
                                i2c_stop();
                                return 0;
                            }
                            

                            i2c读写部分都在这儿了,写部分没问题了,读部分不知道有没有问题,写正常就点亮了我就没排查读了,我读ncs8801s时相关寄存器的值和预期不一样,但是屏亮了,我暂时不管了,后面有时间再看是值确实不对还是读的时序不对导致读出的值不对

                            H 1 条回复 最后回复 回复 引用 分享 0
                            • H
                              Hansk LV 3 @lztmfx 最后由 编辑

                              @lztmfx ok,明白感谢👍 👍

                              1 条回复 最后回复 回复 引用 分享 0
                              • 1 / 1
                              • First post
                                Last post

                              Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号

                              行为准则 | 用户协议 | 隐私权政策