zedboard——adau1761之axi-i2c.c及axi-i2c.ko内核加载调试(三)

  最近在调试zebboard开发板的adau1761音频接口,加载的i2s内核ko时,出现如下错误:Unable to handle kernel NULL pointer dereference at virtual address 000000b8,内核执行到regmap_write(i2s->regmap, AXI_I2S_REG_RESET, AXI_I2S_RESET_GLOBAL)是出现了空指针引用错误,即i2s->regmap指针异常。
查看源代码(axi-i2s.c):

static int axi_i2s_probe(struct platform_device *pdev)
{
    struct resource *res;
    struct axi_i2s *i2s;
    void __iomem *base;
    int ret;

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);//为设备结构分配内存,用这个函数分配出来的内存会自动释放
    printk("i2s : %d %p\n", __LINE__, i2s);
    if (!i2s)
        return -ENOMEM;

    platform_set_drvdata(pdev, i2s);
    printk("i2s : %d %p\n", __LINE__, i2s);

    res = platform_get_resource(pdev, IORESOURCE_MEM, 0);//得到寄存器地址资源
    base = devm_ioremap_resource(&pdev->dev, res);//申请资源,然后进行IO映射,ioremap的功能将一个IO地址空间映射到内核的虚拟地址空间上去,返回值就是虚拟地址
    printk("res : %d %p\n", __LINE__, res); 
    printk("base : %d %p\n", __LINE__, base); 

    if (IS_ERR(base))
        return PTR_ERR(base);

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);//为设备结构分配内存
    i2s->regmap = devm_regmap_init_mmio(&pdev->dev, base,
        &axi_i2s_regmap_config);                   //i2s对应的是mmio类型
    if (IS_ERR(i2s->regmap))
        return PTR_ERR(i2s->regmap);
    printk("i2s : %d %p\n", __LINE__, i2s);
    printk("i2s->regmap : %d %p\n", __LINE__, i2s->regmap);

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);//为设备结构分配内存
    i2s->clk = devm_clk_get(&pdev->dev, "axi");//根据设备树获得axi模块时钟的时钟
    if (IS_ERR(i2s->clk))
        return PTR_ERR(i2s->clk);
    printk("i2s : %d %p\n", __LINE__, i2s);
    printk("i2s->regmap : %d %p\n", __LINE__, i2s->regmap);
    printk("i2s->clk : %d %p\n", __LINE__, i2s->clk);

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);//为设备结构分配内存
    i2s->clk_ref = devm_clk_get(&pdev->dev, "ref");//根据设备树获得参考mclk时钟
    if (IS_ERR(i2s->clk_ref))
        return PTR_ERR(i2s->clk_ref);

    printk("i2s : %d %p\n", __LINE__, i2s);
    printk("i2s->regmap : %d %p\n", __LINE__, i2s->regmap);
    printk("i2s->clk_ref : %d %p\n", __LINE__, i2s->clk_ref);

    ret = clk_prepare_enable(i2s->clk);//使能i2s模块的时钟
    if (ret)
        return ret;

    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);//为设备结构分配内存
    printk("i2s : %d %p\n", __LINE__, i2s);
    printk("i2s->regmap : %d %p\n", __LINE__, i2s->regmap);

    //对iis的dma赋值,包括起始地址,地址位宽字节数以及突发传输数据长度
    i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO;
    i2s->playback_dma_data.addr_width = 4;
    i2s->playback_dma_data.maxburst = 1;

    i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO;
    i2s->capture_dma_data.addr_width = 4;
    i2s->capture_dma_data.maxburst = 1;

    printk("ucas : %d %s\n", __LINE__, __FUNCTION__);
    i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME;
    printk("ucas : %d %s\n", __LINE__, __FUNCTION__);
    i2s->ratnum.den_step = 1;
    i2s->ratnum.den_min = 1;
    i2s->ratnum.den_max = 64;

    i2s->rate_constraints.rats = &i2s->ratnum;
    i2s->rate_constraints.nrats = 1;

    printk("i2s->regmap : %d %p\n", __LINE__, i2s->regmap);
    regmap_write(i2s->regmap, AXI_I2S_REG_RESET, AXI_I2S_RESET_GLOBAL);//复位IIS控制模块

    ret = devm_snd_soc_register_component(&pdev->dev, &axi_i2s_component,
                     &axi_i2s_dai, 1);
    if (ret)
        goto err_clk_disable;

    printk("ucas : %d %s\n", __LINE__, __FUNCTION__);
    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
    ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0);
    if (ret)
        goto err_clk_disable;

    printk("ucas : %d %s\n", __LINE__, __FUNCTION__);
    i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);
    return 0;

err_clk_disable:
    clk_disable_unprepare(i2s->clk);
    return ret;
}

源代码截图如下,里面显示了代码的行号,后面调试输出和代码的行号对比,查看输出。
这里写图片描述
这里写图片描述
加载i2s.ko文件后,Putty工具端口的输出如下图:
这里写图片描述
查看工具的输出:
i2s : 194 de476f10
i2s : 199 de476f10
res : 203 de52c3c0
base : 204 e099a000
i2s : 214 de7a5a10
可以看到打印194行和199行,i2s的虚拟地址均是de476f10,即执行193行的语句:i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);获得的i2s虚拟地址是de476f10,但是214行打印的i2s地址却变成了de7a5a10,这是为啥。对比源代码的行号,发现是执行了209行的代码:i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);i2s的地址变成了de7a5a10,即重新分配了一个i2s结构体大小的空间。
执行215行打印的i2s->regmap的虚拟地址是de7b8800, 此时还不是空指针。
i2s->regmap : 215 de7b8800
但是执行222行,打印出的i2s->regmap地址确实null了,也就是这时已经导致了空指针的出现。
i2s : 221 de7a5710
i2s->regmap : 222 (null)
查看源代码217行,重新执行了以下语句;
i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);即重新又分配了空间,空间的首地址赋给i2s,地址是221行打印的地址de7a5710,即因为i2s的地址已经改变,导致了新分配的i2s结构体内部的i2s->regmap还未赋地址值,即是空指针。所以在内核执行到262行regmap_write(i2s->regmap, AXI_I2S_REG_RESET, AXI_I2S_RESET_GLOBAL)调用i2s->regmap时出现了空指针应用错误,找到了问题的所在,即多次执行i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL);语句导致第一次分配的i2s地址已经改变。

解决方法,把axi_i2s_probe函数内部除了第一处的i2s = devm_kzalloc(&pdev->dev, sizeof(*i2s), GFP_KERNEL)不用注释掉,其余的均要注释掉,防止再次分配空间导致i2s地址变动。
这里写图片描述
看来网站提供的原始驱动也不一定就是绝对没问题的(汗???),还是要自己移植动手验证才行。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: ADAU1701是一款数字信号处理器(DSP)芯片,可以用于音频处理和混响等应用。下面是ADAU1701单片机加载程序的过程: 1. 首先,我们需要编写ADAU1701的程序,在电脑软件中使用类C语言进行编程。这个程序包括了需要进行音频处理的算法和设置参数等内容。 2. 在编写好程序后,我们需要将程序通过USB或者其他通信方式上传到ADAU1701芯片中。这一步需要使用ADAU1701的开发板或者其他支持ADAU1701的硬件设备进行。 3. 在硬件设备连接好后,我们需要将开发板或者设备与电脑连接。然后,通过相应的软件将编写好的程序发送到ADAU1701芯片中。 4. 上传程序的过程需要等待一些时间,具体时间根据程序大小和传输速度而定。一旦程序上传完成,ADAU1701芯片就可以开始按照程序的设定进行音频处理了。 需要注意的是,加载ADAU1701单片机程序时需要确保程序和硬件设备的兼容性,同时可能需要一定的电脑基础和相关的开发工具使用知识。 总结起来,ADAU1701的单片机加载程序过程包括编写程序、连接硬件设备、上传程序到芯片和等待程序加载完成。通过这个过程,我们可以实现ADAU1701芯片的音频处理功能。 ### 回答2: ADAU1701 单片机是一款专门用于音频信号处理的片上系统。要加载程序到ADAU1701单片机中,一般需要以下步骤: 1. 首先,准备好要加载的程序代码。可以使用SigmaStudio软件进行编程和设计音频处理算法,并生成可加载ADAU1701单片机的程序文件。 2. 将ADAU1701单片机与计算机连接。可以使用USB转I2C接口转换器等连接方式,将单片机与计算机进行连。 3. 打开SigmaStudio软件,并选择连接单片机的接口。在软件中选择合适的接口,如USB转I2C接口转换器,与单片机建立连接。 4. 在SigmaStudio软件中选择或创建需要加载的程序文件。通过导入、加载或编程生成的方式,将要加载的程序文件导入到SigmaStudio软件中。 5. 设置ADAU1701单片机的内部参数。根据需要,可以设置输入、输出接口、各种滤波器、增益、延迟等参数。 6. 点击软件中的“加载到硬件”按钮。将程序加载ADAU1701单片机的内部存储器中。 7. 确认加载成功。软件界面会显示加载状态和结果。可以通过观察单片机指示灯的闪烁等方式,确认程序已经加载成功。 8. 断开连接。在加载成功后,可以断开ADAU1701单片机与计算机的连接。 总的来说,加载程序到ADAU1701单片机中主要通过SigmaStudio软件和适当的连接方式来完成,并且需要确保连接的正确性和加载的成功。加载程序后,ADAU1701单片机就可以根据程序中的算法和参数,对音频信号进行处理和调节。 ### 回答3: ADAU1701是一款集成了数字信号处理(DSP)功能的单片机。要加载程序到ADAU1701单片机中,需要以下步骤: 1. 准备开发环境:首先需要准备好相关的硬件和软件开发工具。硬件方面需要连接一个可编程的ADAU1701开发板,软件方面需要安装SigmaStudio,这是一款专为ADAU1701设计的图形化开发工具。 2. 编写DSP程序:使用SigmaStudio打开一个新的项目,通过图形化界面设计DSP程序。SigmaStudio提供了丰富的DSP算法库和模块,可以方便地设计出符合需求的信号处理流程。通过简单的拖拽和连接模块,可以构建出各种复杂的音频处理程序。 3. 连接硬件:将ADAU1701开发板通过USB或者其他接口连接到计算机,确保开发板正常供电并与SigmaStudio正常通信。 4. 下载并运行程序:在SigmaStudio中选择"Compile"按钮,将设计好的DSP程序编译生成二进制文件。然后选择"Download"按钮,将编译好的二进制文件下载到连接的ADAU1701开发板中。 5. 验证程序:下载完成后,可以通过音频输入和输出设备来验证程序的效果。将音频源连接到ADAU1701开发板的输入端口,将输出端口连接到音频放大器或扬声器。通过测试和观察输出效果,可以评估程序的正确性和性能。 总结:ADAU1701单片机加载程序的过程包括准备开发环境、编写DSP程序、连接硬件、下载程序和验证程序等步骤。通过SigmaStudio提供的图形化界面和丰富的算法库,开发者可以轻松地设计出符合需求的音频处理程序,并将其加载ADAU1701单片机中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值