Linux下PCI设备驱动开发详解(五)

这篇具有很好参考价值的文章主要介绍了Linux下PCI设备驱动开发详解(五)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

Linux下PCI设备驱动开发详解(五)

本章及其以后的几章,我们将从用户态软件、内核态驱动、FPGA逻辑介绍一个通过PCI Express总线实现CPU和FPGA数据通信的简单框架。

这个框架就是开源界非常有名的RIFFA(reuseable integration framework for FPGA accelerators),它是一个FPGA加速器的一种可重用性集成框架,是一个第三方开源PCIe框架。

该框架要求具备一个支持PCIe的工作站和一个带有PCIe连接器的FPGA板卡。RIFFA支持windows、linux,altera和xilinx,可以通过c/c++、python、matlab、java驱动来实现数据的发送和接收。驱动程序可以在linux或windows上运行,每一个系统最多支持5个FPGA device。

在用户端有独立的发送和接收端口,用户只需要编写几行简单代码即可实现和FPGA IP内核通信。

riffa使用直接存储器访问(DMA)传输和中断信号传输数据。这实现了PCIe链路上的高带宽,运行速率可以达到PCIe链路饱和点。

开源地址:https://github.com/KastnerRG/riffa

一、riffa体系结构

riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

在硬件方面,简化了接口,以便通过FIFO简便的将数据取出或存入。数据的传输由riffa的rx和tx DMA engine模块用分散聚合方法来实现。rx engine模块收集上位机来的有效数据,收集完成发给channel模块,tx engine收集channel模块传送来的数据,打包发给PCI express端点。

在软件方面,PC接收FPGA板卡数据是用户应用程序调用库函数fpga_recv,然后由FPGA端启动。用户应用程序线程进入内核驱动程序,然后开始接收上游FPGA的读请求,将数据分包发送,如果没收到请求,将会等待它达到。

启动发送函数后,服务器将建立一个散列收集元素的列表,将数据存储地址和长度等信息放入其中,将其写入共享缓冲区。用户应用程序将缓冲区地址和数据长度等信息发送给FPGA。FPGA读取散射收集数据,然后发出相应地址的数据写入请求,如果散列收集元素列表的地址有多个,FPGA将通过中断发出多次请求。

TX搬移的数据全部写入缓存区后,驱动程序读取FPGA写入的字节数,确认是否与发送数据长度一致。这样就完成了传输。其过程如下图所示:

riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

PC机发送数据到FPGA板卡过程与PC机接收FPGA板卡数据过程相似,下图说明了该流程。 刚开始也是用户应用程序调用库函数fpga_send,传输线程进入内核驱动程序,然后FPGA启动传输。

启动fpga_send,服务器将申请一些空间,将要发送的数据写入其中,然后建立一个分散收集列表,将存储数据的地址和长度放入其中,并将分散收集列表的地址和要发生的数据长度等信息发给FPGA。FPGA 收到列表地址后,读取该列表的信息,然后发出相应地址和长度的读请求,然后将数据存储,最后一起发给FPGA板卡。

riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

驱动程序首先调用pci_present()检查PCI总线是否被linux内核支持,如果系统支持PCI总线结构,这个函数的返回值为0,如果驱动程序在调用这个函数时得到一个非0的返回值,那么驱动程序就必须得中止自己的任务。调用pci_register_driver()函数来注册PCI设备的驱动程序,此时需要提供一个“demo_pci_driver”结构,在该结构中给出的probe探测例程负责完成对硬件的检测工作。

下面将从user logic -> PCIe IP -> 驱动层 -> library-> 用户态C++/C按照实例一一进行分析,包括理论基础、实际操作、源代码分析。

首先我们先从FPGA xilinx integrated block for PCI express分析,因为这个有承上启下的作用。

二、PCIe hard IP分析

1. PCIE IP 核配置

AXI总线时钟选择62.5M,AXI总线接口位宽设置为64bit。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

在IDs界面是PCIe设备的相关信息,主机在上电时BIOS系统中识别到的PCIe设备,就是通过这些ID号来进行识别的。

在本实验中,关于ID的设定全部保持为默认值即可,若用户对ID进行了更改,可能导致计算机在启动时不能正确识别设备从而导致蓝屏死机。

Vendor ID是厂商ID,本实验中的厂商ID代值的就是Xilinx;

Device ID代表了PCIe设备,其中7指的是Xilinx 7 系列FPGA,02指的是使用的PCIe 2.0的协议,1指的是含有一个PCIe的传输lane;

Base class Menu指的是PCIe设备的种类,常见的有声卡、显卡、网卡等,各种不同种类的设备都有其对应的驱动,若驱动与其PCIe的种类不对应,就会导致系统的内存访问错误,从而导致蓝屏。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

在PCIe的bars配置界面对PCIe的bar进行设置,BAR空间对应的就是在内存中开辟一段空间用于存放PCIe设备的信息。只使用到一个bar0一个bar且将其内存空间的大小设置为1k。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

IP核的负载选择最大负载长度为512字节,勾选对数据进行缓冲。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

在中断配置界面,取消勾选传统类型的中断,只选择消息类型的中断。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

在share logic界面取消勾选包含其他逻辑,这样在PCIe的IP核中就包含了全部功能。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

在IP核接口参数配置界面,只选择其中用于配置核控制的参数,这是由于riffa框架的特性所提供的。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

下面代码是实际的top level,

PCIeGen1x4If64 PCIeGen1x4If64_i
        (//---------------------------------------------------------------------
         // PCI Express (pci_exp) Interface                                     
         //---------------------------------------------------------------------
         // Tx
         .pci_exp_txn                               ( PCI_EXP_TXN ),
         .pci_exp_txp                               ( PCI_EXP_TXP ),        
         // Rx
         .pci_exp_rxn                               ( PCI_EXP_RXN ),
         .pci_exp_rxp                               ( PCI_EXP_RXP ),        
         //---------------------------------------------------------------------
         // AXI-S Interface                                                     
         //---------------------------------------------------------------------
         // Common
         .user_clk_out                              ( user_clk ),
         .user_reset_out                            ( user_reset ),
         .user_lnk_up                               ( user_lnk_up ),
         .user_app_rdy                              ( user_app_rdy ),
         // TX
         .s_axis_tx_tready                          ( s_axis_tx_tready ),
         .s_axis_tx_tdata                           ( s_axis_tx_tdata ),
         .s_axis_tx_tkeep                           ( s_axis_tx_tkeep ),
         .s_axis_tx_tuser                           ( s_axis_tx_tuser ),
         .s_axis_tx_tlast                           ( s_axis_tx_tlast ),
         .s_axis_tx_tvalid                          ( s_axis_tx_tvalid ),
         // Rx
         .m_axis_rx_tdata                           ( m_axis_rx_tdata ),
         .m_axis_rx_tkeep                           ( m_axis_rx_tkeep ),
         .m_axis_rx_tlast                           ( m_axis_rx_tlast ),
         .m_axis_rx_tvalid                          ( m_axis_rx_tvalid ),
         .m_axis_rx_tready                          ( m_axis_rx_tready ),
         .m_axis_rx_tuser                           ( m_axis_rx_tuser ),
         .tx_cfg_gnt                                ( tx_cfg_gnt ),
         .rx_np_ok                                  ( rx_np_ok ),
         .rx_np_req                                 ( rx_np_req ),
         .cfg_trn_pending                           ( cfg_trn_pending ),
         .cfg_pm_halt_aspm_l0s                      ( cfg_pm_halt_aspm_l0s ),
         .cfg_pm_halt_aspm_l1                       ( cfg_pm_halt_aspm_l1 ),
         .cfg_pm_force_state_en                     ( cfg_pm_force_state_en ),
         .cfg_pm_force_state                        ( cfg_pm_force_state ),
         .cfg_dsn                                   ( cfg_dsn ),
         .cfg_turnoff_ok                            ( cfg_turnoff_ok ),
         .cfg_pm_wake                               ( cfg_pm_wake ),
         .cfg_pm_send_pme_to                        ( 1'b0 ),
         .cfg_ds_bus_number                         ( 8'b0 ),
         .cfg_ds_device_number                      ( 5'b0 ),
         .cfg_ds_function_number                    ( 3'b0 ),
         //---------------------------------------------------------------------
         // Flow Control Interface                                              
         //---------------------------------------------------------------------
         .fc_cpld                                   ( fc_cpld ),
         .fc_cplh                                   ( fc_cplh ),
         .fc_npd                                    ( fc_npd ),
         .fc_nph                                    ( fc_nph ),
         .fc_pd                                     ( fc_pd ),
         .fc_ph                                     ( fc_ph ),
         .fc_sel                                    ( fc_sel ),
         //---------------------------------------------------------------------
         // Configuration (CFG) Interface                                       
         //---------------------------------------------------------------------
         .cfg_device_number                         ( cfg_device_number ),
         .cfg_dcommand2                             ( cfg_dcommand2 ),
         .cfg_pmcsr_pme_status                      ( cfg_pmcsr_pme_status ),
         .cfg_status                                ( cfg_status ),
         .cfg_to_turnoff                            ( cfg_to_turnoff ),
         .cfg_received_func_lvl_rst                 ( cfg_received_func_lvl_rst ),
         .cfg_dcommand                              ( cfg_dcommand ),
         .cfg_bus_number                            ( cfg_bus_number ),
         .cfg_function_number                       ( cfg_function_number ),
         .cfg_command                               ( cfg_command ),
         .cfg_dstatus                               ( cfg_dstatus ),
         .cfg_lstatus                               ( cfg_lstatus ),
         .cfg_pcie_link_state                       ( cfg_pcie_link_state ),
         .cfg_lcommand                              ( cfg_lcommand ),
         .cfg_pmcsr_pme_en                          ( cfg_pmcsr_pme_en ),
         .cfg_pmcsr_powerstate                      ( cfg_pmcsr_powerstate ),
         //------------------------------------------------//
         // EP Only                                        //
         //------------------------------------------------//
         .cfg_interrupt                             ( cfg_interrupt ),
         .cfg_interrupt_rdy                         ( cfg_interrupt_rdy ),
         .cfg_interrupt_assert                      ( cfg_interrupt_assert ),
         .cfg_interrupt_di                          ( cfg_interrupt_di ),
         .cfg_interrupt_do                          ( cfg_interrupt_do ),
         .cfg_interrupt_mmenable                    ( cfg_interrupt_mmenable ),
         .cfg_interrupt_msienable                   ( cfg_interrupt_msienable ),
         .cfg_interrupt_msixenable                  ( cfg_interrupt_msixenable ),
         .cfg_interrupt_msixfm                      ( cfg_interrupt_msixfm ),
         .cfg_interrupt_stat                        ( cfg_interrupt_stat ),
         .cfg_pciecap_interrupt_msgnum              ( cfg_pciecap_interrupt_msgnum ),
         //---------------------------------------------------------------------
         // System  (SYS) Interface                                             
         //---------------------------------------------------------------------
         .sys_clk                                    ( pcie_refclk ),
         .sys_rst_n                                  ( pcie_reset_n )
         );

从顶层代码接口可以看出来,TX/RX差分信号、AXIS数据common接口信号、tx/rx数据面信号、FC流控信号、configuration(CFG)interface、EP中断信号、系统时钟/复位信号。

详细使用参考xilinx PCIe spec官方文档。

PCIe IP位于整个设计架构的这个位置:
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

2. tx_engine和rx_engine

下面我们分析一下tx_engine和rx_engine这两个核心模块,这两个模块负责转换axis data和tlp data。

我们先看一下top level的源代码:

riffa_wrapper_ac701
        #(/*AUTOINSTPARAM*/
          // Parameters
          .C_LOG_NUM_TAGS               (C_LOG_NUM_TAGS),
          .C_NUM_CHNL                   (C_NUM_CHNL),
          .C_PCI_DATA_WIDTH             (C_PCI_DATA_WIDTH),
          .C_MAX_PAYLOAD_BYTES          (C_MAX_PAYLOAD_BYTES))
    riffa
        (
         // Outputs
         .CFG_INTERRUPT                 (cfg_interrupt),
         .M_AXIS_RX_TREADY              (m_axis_rx_tready),
         .S_AXIS_TX_TDATA               (s_axis_tx_tdata[C_PCI_DATA_WIDTH-1:0]),
         .S_AXIS_TX_TKEEP               (s_axis_tx_tkeep[(C_PCI_DATA_WIDTH/8)-1:0]),
         .S_AXIS_TX_TLAST               (s_axis_tx_tlast),
         .S_AXIS_TX_TVALID              (s_axis_tx_tvalid),
         .S_AXIS_TX_TUSER               (s_axis_tx_tuser[`SIG_XIL_TX_TUSER_W-1:0]),
         .FC_SEL                        (fc_sel[`SIG_FC_SEL_W-1:0]),
         .RST_OUT                       (rst_out),
         .CHNL_RX                       (chnl_rx[C_NUM_CHNL-1:0]),
         .CHNL_RX_LAST                  (chnl_rx_last[C_NUM_CHNL-1:0]),
         .CHNL_RX_LEN                   (chnl_rx_len[(C_NUM_CHNL*`SIG_CHNL_LENGTH_W)-1:0]),
         .CHNL_RX_OFF                   (chnl_rx_off[(C_NUM_CHNL*`SIG_CHNL_OFFSET_W)-1:0]),
         .CHNL_RX_DATA                  (chnl_rx_data[(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0]),
         .CHNL_RX_DATA_VALID            (chnl_rx_data_valid[C_NUM_CHNL-1:0]),
         .CHNL_TX_ACK                   (chnl_tx_ack[C_NUM_CHNL-1:0]),
         .CHNL_TX_DATA_REN              (chnl_tx_data_ren[C_NUM_CHNL-1:0]),
         // Inputs
         .M_AXIS_RX_TDATA               (m_axis_rx_tdata[C_PCI_DATA_WIDTH-1:0]),
         .M_AXIS_RX_TKEEP               (m_axis_rx_tkeep[(C_PCI_DATA_WIDTH/8)-1:0]),
         .M_AXIS_RX_TLAST               (m_axis_rx_tlast),
         .M_AXIS_RX_TVALID              (m_axis_rx_tvalid),
         .M_AXIS_RX_TUSER               (m_axis_rx_tuser[`SIG_XIL_RX_TUSER_W-1:0]),
         .S_AXIS_TX_TREADY              (s_axis_tx_tready),
         .CFG_BUS_NUMBER                (cfg_bus_number[`SIG_BUSID_W-1:0]),
         .CFG_DEVICE_NUMBER             (cfg_device_number[`SIG_DEVID_W-1:0]),
         .CFG_FUNCTION_NUMBER           (cfg_function_number[`SIG_FNID_W-1:0]),
         .CFG_COMMAND                   (cfg_command[`SIG_CFGREG_W-1:0]),
         .CFG_DCOMMAND                  (cfg_dcommand[`SIG_CFGREG_W-1:0]),
         .CFG_LSTATUS                   (cfg_lstatus[`SIG_CFGREG_W-1:0]),
         .CFG_LCOMMAND                  (cfg_lcommand[`SIG_CFGREG_W-1:0]),
         .FC_CPLD                       (fc_cpld[`SIG_FC_CPLD_W-1:0]),
         .FC_CPLH                       (fc_cplh[`SIG_FC_CPLH_W-1:0]),
         .CFG_INTERRUPT_MSIEN           (cfg_interrupt_msienable),// TODO: Rename
         .CFG_INTERRUPT_RDY             (cfg_interrupt_rdy),
         .USER_CLK                      (user_clk),
         .USER_RESET                    (user_reset),
         .CHNL_RX_CLK                   (chnl_rx_clk[C_NUM_CHNL-1:0]),
         .CHNL_RX_ACK                   (chnl_rx_ack[C_NUM_CHNL-1:0]),
         .CHNL_RX_DATA_REN              (chnl_rx_data_ren[C_NUM_CHNL-1:0]),
         .CHNL_TX_CLK                   (chnl_tx_clk[C_NUM_CHNL-1:0]),
         .CHNL_TX                       (chnl_tx[C_NUM_CHNL-1:0]),
         .CHNL_TX_LAST                  (chnl_tx_last[C_NUM_CHNL-1:0]),
         .CHNL_TX_LEN                   (chnl_tx_len[(C_NUM_CHNL*`SIG_CHNL_LENGTH_W)-1:0]),
         .CHNL_TX_OFF                   (chnl_tx_off[(C_NUM_CHNL*`SIG_CHNL_OFFSET_W)-1:0]),
         .CHNL_TX_DATA                  (chnl_tx_data[(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0]),
         .CHNL_TX_DATA_VALID            (chnl_tx_data_valid[C_NUM_CHNL-1:0]),
         .RX_NP_OK                      (rx_np_ok),
         .TX_CFG_GNT                    (tx_cfg_gnt),
         .RX_NP_REQ                     (rx_np_req)
         /*AUTOINST*/);

这个模块可以通过C_NUM_CHNL配置通道个数,C_PCI_DATA_WIDTH配置PCIe data的位宽,C_LOG_NUM_TAGS配置PCIe tag的个数。

module riffa_wrapper_ac701负责将xilinx PCIe IP的TX、RX、Configuration、flow control、中断信号转换为riffa的输入输出信号。

阅读riffa_wrapper_ac701.v源代码发现这个模块分为两个模块:

· translation_xilinx
· engine_layer
· riffa

transtion_xilinx:负责提供统一的PCIe接口信息,比如altera、xilinx;

engine_layer:负责封装了tx_engine和rx_engine。其中tx engine负责上传DMA通道(写通道),即Interface: TX Classic;rx engine负责下发DMA通道(读通道),即Interface: RX Classic;

riffa:负责将tx/rx engine的信号转换为user logic的通道信号,方便我们使用,接口代码如下:

     input [C_NUM_CHNL-1:0]                     CHNL_RX_CLK, 
     output [C_NUM_CHNL-1:0]                    CHNL_RX, 
     input [C_NUM_CHNL-1:0]                     CHNL_RX_ACK, 
     output [C_NUM_CHNL-1:0]                    CHNL_RX_LAST, 
     output [(C_NUM_CHNL*32)-1:0]               CHNL_RX_LEN, 
     output [(C_NUM_CHNL*31)-1:0]               CHNL_RX_OFF, 
     output [(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0] CHNL_RX_DATA, 
     output [C_NUM_CHNL-1:0]                    CHNL_RX_DATA_VALID, 
     input [C_NUM_CHNL-1:0]                     CHNL_RX_DATA_REN,
    
     input [C_NUM_CHNL-1:0]                     CHNL_TX_CLK, 
     input [C_NUM_CHNL-1:0]                     CHNL_TX, 
     output [C_NUM_CHNL-1:0]                    CHNL_TX_ACK,
     input [C_NUM_CHNL-1:0]                     CHNL_TX_LAST, 
     input [(C_NUM_CHNL*32)-1:0]                CHNL_TX_LEN, 
     input [(C_NUM_CHNL*31)-1:0]                CHNL_TX_OFF, 
     input [(C_NUM_CHNL*C_PCI_DATA_WIDTH)-1:0]  CHNL_TX_DATA, 
     input [C_NUM_CHNL-1:0]                     CHNL_TX_DATA_VALID, 
     output [C_NUM_CHNL-1:0]                    CHNL_TX_DATA_REN

对应整个实际框架的这一部分,如下图所示:
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

3. user logic

经过tx engine和rx engine模块,输出CHNL_RX_*和CHNL_TX_*信号,下面我们看一下user如何使用的,源代码如下:

generate
    for (chnl = 0; chnl < C_NUM_CHNL; chnl = chnl + 1) begin : test_channels
        chnl_tester 
                #(
                  .C_PCI_DATA_WIDTH(C_PCI_DATA_WIDTH)
                  ) 
        module1 
                (.CLK(user_clk),
                 .RST(rst_out),    // riffa_reset includes riffa_endpoint resets
                 // Rx interface
                 .CHNL_RX_CLK(chnl_rx_clk[chnl]), 
                 .CHNL_RX(chnl_rx[chnl]), 
                 .CHNL_RX_ACK(chnl_rx_ack[chnl]), 
                 .CHNL_RX_LAST(chnl_rx_last[chnl]), 
                 .CHNL_RX_LEN(chnl_rx_len[32*chnl +:32]), 
                 .CHNL_RX_OFF(chnl_rx_off[31*chnl +:31]), 
                 .CHNL_RX_DATA(chnl_rx_data[C_PCI_DATA_WIDTH*chnl +:C_PCI_DATA_WIDTH]), 
                 .CHNL_RX_DATA_VALID(chnl_rx_data_valid[chnl]), 
                 .CHNL_RX_DATA_REN(chnl_rx_data_ren[chnl]),

                 // Tx interface
                 .CHNL_TX_CLK(chnl_tx_clk[chnl]), 
                 .CHNL_TX(chnl_tx[chnl]), 
                 .CHNL_TX_ACK(chnl_tx_ack[chnl]), 
                 .CHNL_TX_LAST(chnl_tx_last[chnl]), 
                 .CHNL_TX_LEN(chnl_tx_len[32*chnl +:32]), 
                 .CHNL_TX_OFF(chnl_tx_off[31*chnl +:31]), 
                 .CHNL_TX_DATA(chnl_tx_data[C_PCI_DATA_WIDTH*chnl +:C_PCI_DATA_WIDTH]), 
                 .CHNL_TX_DATA_VALID(chnl_tx_data_valid[chnl]), 
                 .CHNL_TX_DATA_REN(chnl_tx_data_ren[chnl])
                 );    
    end
endgenerate

这个模块的用于执行RIFFA TX 和 RX 接口。在RX接口上接收数据并保存最后接收的值。在TX接口上发送回相同数量的数据。返回的数据从接收到的最后一个值开始,重置并递增,直到等于TX接口上发回的(4字节)字数的值结束。
riffa: bad number of channels,PCI设备驱动开发详解,linux,驱动开发,fpga开发,c语言

三、总结

这篇文章通过经典开源项目RIIFA的FPGA部分,结合源代码详细分析了框架部分的Xilinx PCIe hard IP、TX/RX engine和RIFFA模块,最后结合了user logic部分的chnl_tester,介绍了如何使用CHNL_TX_*和CHNL_RX_*接口。

四、未完待续

Linux下PCI设备驱动开发详解(六),将结合经典开源项目RIIFA,详细介绍内核态驱动的设计、开发、安装等。

五、参考资料

https://blog.csdn.net/qq_41332806/article/details/105864632文章来源地址https://www.toymoban.com/news/detail-783896.html

到了这里,关于Linux下PCI设备驱动开发详解(五)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 宋宝华《Linux设备驱动开发详解》 宋老师csdn上分享的网盘已失效,特意新增的。

    https://pan.baidu.com/s/1rCbRUmnDtjE4jHNB5eQ8CQ 提取码:t12r 案例代码: https://pan.baidu.com/s/1lSMGxLnEFwO0aJGORqx8Og 提取码: bglj Linux设备驱动开发详解:基于最新的Linux4.0内核 (电子与嵌入式系统设计丛书) (宋宝华 著)电子书: https://download.csdn.net/download/MINGTING1323/86831055

    2024年02月13日
    浏览(44)
  • Linux驱动开发笔记(四):设备驱动介绍、熟悉杂项设备驱动和ubuntu开发杂项设备Demo

    若该文为原创文章,转载请注明原文出处 本文章博客地址:https://hpzwl.blog.csdn.net/article/details/134533533 红胖子网络科技博文大全:开发技术集合(包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结合等等)持续更新中… 上一篇:《Linux驱动开发笔记(三

    2024年02月05日
    浏览(53)
  • 设备驱动开发详解

    设备驱动程序是嵌入式系统中与硬件设备交互的关键部分。它负责将操作系统与硬件设备之间进行有效的通信和数据交换。在本篇博客中,我们将详细介绍设备驱动开发的过程,并提供C语言实例帮助理解。 1.1 设备驱动概述 设备驱动程序是在操作系统中实现设备与应用程序之

    2024年02月04日
    浏览(36)
  • 4、Linux驱动开发:设备-设备号&设备号注册

    🍅点击这里查看所有博文   随着自己工作的进行,接触到的技术栈也越来越多。给我一个很直观的感受就是,某一项技术/经验在刚开始接触的时候都记得很清楚。往往过了几个月都会忘记的差不多了,只有经常会用到的东西才有可能真正记下来。存在很多在特殊情况下有

    2024年02月15日
    浏览(57)
  • Linux驱动开发实战(一)——设备驱动模型

    在早期的Linux内核中并没有为设备驱动提供统一的设备模型。随着内核的不断扩大及系统更加复杂,编写一个驱动程序越来越困难,所以在Linux2.6内核中添加了一个统一的设备模型。这样,写设备驱动程序就稍微容易一些了。本章将对设备模型进行详细的介绍。 设备驱动模型

    2024年02月16日
    浏览(51)
  • Linux设备驱动开发 - 虚拟时钟Clock驱动示例

    By: fulinux E-mail: fulinux@sina.com Blog: https://blog.csdn.net/fulinus 喜欢的盆友欢迎点赞和订阅! 你的喜欢就是我写作的动力! 很多设备里面系统时钟架构极其复杂,让学习Clock驱动的盆友头大。这里我参考S3C2440的clock驱动写了一个virtual clock,即虚拟时钟驱动,分别包含clock的provider和

    2023年04月21日
    浏览(42)
  • Linux -- 字符设备驱动--LED的驱动开发(初级框架)

    看原理图确定引脚,确定引脚输出什么电平才能点亮 / 熄灭 LED 看主芯片手册,确定寄存器操作方法:哪些寄存器?哪些位?地址是? 编写驱动:先写框架,再写硬件操作的代码 注意 :在芯片手册中确定的寄存器地址被称为 物理地址 ,在 Linux 内核中无法直接使用。 需要使

    2024年04月28日
    浏览(37)
  • 嵌入式Linux驱动开发 04:基于设备树的驱动开发

    前面文章 《嵌入式Linux驱动开发 03:平台(platform)总线驱动模型》 引入了资源和驱动分离的概念,这篇文章将在前面基础上更进一步,引入设备树的概念。 在平台总线驱动模型中资源和驱动已经从逻辑上和代码组织上进行了分离,但每次调整资源还是会涉及到内核,所以现

    2024年02月16日
    浏览(70)
  • 正点原子嵌入式linux驱动开发——Linux 网络设备驱动

    网络驱动是linux里面驱动三巨头之一 ,linux下的网络功能非常强大,嵌入式linux中也常常用到网络功能。前面已经讲过了字符设备驱动和块设备驱动,本章就来学习一下linux里面的 网络设备驱动 。 本次笔记中讨论的都是有线网络! 提起网络,一般想到的硬件就是“网卡”。在

    2024年01月17日
    浏览(71)
  • 嵌入式Linux系统中的设备驱动开发:从设备树到驱动实现

    大家好,今天给大家介绍 嵌入式Linux系统中的设备驱动开发:从设备树到驱动实现 ,文章末尾附有分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全! 可进群免费领取。 在嵌入式Linux系统中,设备驱动是连接硬件设备和操作系统之间的桥梁。

    2024年02月19日
    浏览(66)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包