返回文章列表

MAX11300 工業I/O子系統驅動解析

本文深入分析 MAX11300 工業 I/O 子系統驅動程式,解析其核心功能、裝置初始化流程與 IIO 子系統整合。探討驅動程式如何透過裝置樹組態埠與 I/O 通道,以及如何設定 ADC、DAC 和 GPIO 等不同工作模式。此外,文章也說明如何使用 libgpiod 工具驗證 MAX11300 驅動程式的 DAC

嵌入式系統 驅動程式開發

MAX11300 是一款多功能工業 I/O 晶片,具備 ADC、DAC 和 GPIO 等功能。本文分析其 Linux 驅動程式,著重於裝置樹的埠組態、I/O 通道分配,以及不同工作模式的設定。驅動程式利用 max11300_alloc_ports 函式,根據裝置樹中各埠的組態屬性,設定對應的 ADC、DAC 或 GPIO 模式。針對 ADC 和 DAC,驅動程式會讀取參考電壓、取樣率等引數;而 GPIO 則會記錄埠編號和模式,供後續操作使用。此外,max11300_setup_port_8_mode 等函式則負責設定 IIO 通道規格,例如通道型別、資料格式和位元組序等。理解這些核心功能,有助於開發者更有效地整合 MAX11300 至工業 I/O 系統。

MAX11300 工業I/O子系統驅動分析與實作

MAX11300是一款高度可組態的工業I/O裝置,支援多種工作模式,包括ADC、DAC、GPIO等功能。本文將深入分析其驅動程式的實作,特別是在工業I/O子系統中的整合。

MAX11300 埠組態與I/O通道分配

驅動程式透過max11300_alloc_ports函式來分配並組態I/O通道。此函式會遍歷裝置樹中的子節點,並根據每個埠的組態屬性進行相應的設定。

程式碼解析

static int max11300_alloc_ports(struct max11300_state *st)
{
    unsigned int i, curr_port = 0, num_ports = st->num_ports, port_mode_6_count = 0, offset = 0;
    struct iio_dev *iio_dev = iio_priv_to_dev(st);
    struct iio_chan_spec *ports;
    struct fwnode_handle *child;
    u32 reg, tmp;
    int ret;

    device_for_each_child_node(st->dev, child) {
        ret = fwnode_property_read_u32(child, "reg", &reg);
        if (ret || reg >= ARRAY_SIZE(st->port_modes))
            continue;

        ret = fwnode_property_read_u32(child, "port-mode", &tmp);
        if (!ret)
            st->port_modes[reg] = tmp;
        else {
            dev_info(st->dev, "port mode is not found\n");
            continue;
        }

        // 根據不同的埠模式進行相應的屬性讀取與設定
        switch (st->port_modes[reg]) {
        case PORT_MODE_7:
            // 設定ADC相關屬性
            break;
        case PORT_MODE_8:
            // 設定ADC相關屬性及負輸入通道
            ret = fwnode_property_read_u32(child, "negative-input", &tmp);
            if (!ret)
                st->adc_negative_port[reg] = tmp;
            else {
                dev_info(st->dev, "Bad value for negative ADC channel\n");
                return -EINVAL;
            }
            break;
        case PORT_MODE_9: case PORT_MODE_10:
            // 設定ADC相關屬性
            break;
        case PORT_MODE_5: case PORT_MODE_6:
            // 設定DAC相關屬性
            if ((st->port_modes[reg]) == PORT_MODE_6) {
                port_mode_6_count++;
                dev_info(st->dev, "there are %d channels in mode_6\n", port_mode_6_count);
            }
            break;
        case PORT_MODE_1:
            // 設定GPIO輸入模式
            st->gpio_offset[offset] = reg;
            st->gpio_offset_mode[offset] = PORT_MODE_1;
            offset++;
            st->num_gpios++;
            break;
        case PORT_MODE_3:
            // 設定GPIO輸出模式
            st->gpio_offset[offset] = reg;
            st->gpio_offset_mode[offset] = PORT_MODE_3;
            offset++;
            st->num_gpios++;
            break;
        }
    }
}

內容解密:

  1. 裝置樹遍歷:使用device_for_each_child_node宏遍歷裝置樹中的每個子節點,並讀取reg屬性以確定埠編號。
  2. 埠模式設定:根據port-mode屬性設定埠的工作模式,並根據不同模式讀取相應的組態屬性。
  3. ADC/DAC屬性設定:針對不同的埠模式,讀取並設定相關的ADC或DAC屬性,如參考電壓、取樣率等。
  4. GPIO組態:將組態為GPIO模式的埠進行編號並儲存其模式,用於後續的GPIO操作。

IIO通道規格設定

max11300_setup_port_8_mode函式用於設定特定埠模式下的IIO通道規格。

程式碼解析

static void max11300_setup_port_8_mode(struct iio_dev *iio_dev,
                                       struct iio_chan_spec *chan, bool output,
                                       unsigned id, unsigned id2,
                                       unsigned int port_mode)
{
    chan->type = IIO_VOLTAGE;
    chan->differential = 1;
    chan->address = port_mode;
    chan->indexed = 1;
    chan->output = output;
    chan->channel = id;
    chan->channel2 = id2;
    chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
    chan->scan_type.sign = 's';
    chan->scan_type.realbits = 12;
    chan->scan_type.storagebits = 16;
    chan->scan_type.endianness = IIO_BE;
    chan->extend_name = "mode_8_ADC";
}

內容解密:

  1. 通道型別設定:將通道型別設為IIO_VOLTAGE,並標記為差分模式。
  2. 位元組儲存設定:設定資料儲存格式為大端序(IIO_BE),實際位元數為12位,儲存位元數為16位。
  3. 通道資訊遮罩:設定info_mask_separate以支援原始資料讀取。
  4. 副檔名稱:為通道設定副檔名稱,以便於識別其功能。

MAX11300 多埠轉換器驅動程式解析

MAX11300 是一款由 Maxim 提供的多功能、多埠轉換器,廣泛應用於工業自動化、資料採集等領域。本文將深入分析 MAX11300 的 Linux 驅動程式原始碼,探討其核心功能實作、裝置初始化流程以及 IIO 子系統的整合。

驅動程式核心結構

MAX11300 驅動程式的核心結構主要包括以下幾個部分:

  1. 裝置結構體 (struct max11300_state):用於儲存裝置的相關資訊,如裝置指標、操作函式集等。
  2. IIO 裝置結構體 (struct iio_dev):代表一個 IIO 裝置,包含了裝置的通道資訊、操作介面等。
  3. 通道設定函式 (max11300_setup_port_*_mode):根據不同的埠模式(PORT_MODE_*)設定通道屬性。

裝置初始化流程

MAX11300 裝置的初始化流程主要在 max11300_probe 函式中完成,主要步驟包括:

  1. 分配 IIO 裝置記憶體:使用 devm_iio_device_alloc 分配 IIO 裝置結構體記憶體。
  2. 初始化裝置結構體:將裝置指標、操作函式集等資訊儲存到 struct max11300_state 中。
  3. 重設裝置:透過寫入 DCR_ADDRESS 暫存器,將裝置重設為預設狀態。
  4. 讀取裝置 ID:讀取裝置 ID 以驗證裝置是否正常。
  5. 組態 DACREF 和 ADCCTL:設定 DACREF 和 ADCCTL 暫存器,以組態裝置的工作模式。
  6. 組態 IIO 通道:呼叫 max11300_alloc_portsmax11300_set_port_modes 組態 IIO 通道屬性。

程式碼實作

int max11300_probe(struct device *dev, const char *name, const struct max11300_rw_ops *ops)
{
    // ...

    /* 分配 IIO 裝置記憶體 */
    iio_dev = devm_iio_device_alloc(dev, sizeof(*st));
    if (!iio_dev)
        return -ENOMEM;

    /* 初始化裝置結構體 */
    st = iio_priv(iio_dev);
    st->dev = dev;
    st->ops = ops;

    // ...

    /* 重設裝置 */
    reg = DCR_ADDRESS;
    write_val = RESET;
    ret = ops->reg_write(st, reg, write_val);
    if (ret != 0)
        goto error;

    // ...

    /* 組態 IIO 通道 */
    ret = max11300_alloc_ports(st);
    if (ret)
        goto error;

    ret = max11300_set_port_modes(st);
    if (ret)
        goto error_reset_device;

    // ...
}

內容解密:

  1. max11300_probe 函式是裝置驅動程式的核心入口點,負責初始化 MAX11300 裝置。
  2. 使用 devm_iio_device_alloc 分配 IIO 裝置記憶體,並將裝置指標和操作函式集儲存到 struct max11300_state 中。
  3. 重設裝置並讀取裝置 ID 以驗證裝置是否正常。
  4. 組態 DACREF 和 ADCCTL 暫存器,以設定裝置的工作模式。
  5. 呼叫 max11300_alloc_portsmax11300_set_port_modes 組態 IIO 通道屬性。

IIO 子系統整合

MAX11300 驅動程式透過 IIO 子系統提供與使用者空間的介面,主要涉及以下幾個方面:

  1. IIO 裝置註冊:使用 iio_device_register 將 IIO 裝置註冊到 IIO 子系統中。
  2. 通道屬性組態:透過 max11300_alloc_portsmax11300_set_port_modes 組態通道屬性,如通道型別、方向等。

程式碼實作

int max11300_alloc_ports(struct max11300_state *st)
{
    // ...

    /* 組態通道屬性 */
    for (i = 0; i < num_ports; i++) {
        switch (st->port_modes[i]) {
        case PORT_MODE_5:
            max11300_setup_port_5_mode(iio_dev, &ports[curr_port], true, i, PORT_MODE_5);
            curr_port++;
            break;
        // ...
        }
    }

    // ...
}

內容解密:

  1. max11300_alloc_ports 函式負責組態 IIO 通道的屬性。
  2. 根據不同的埠模式(PORT_MODE_*),呼叫相應的通道設定函式(如 max11300_setup_port_5_mode)來設定通道屬性。
  3. 將組態好的通道屬性儲存到 struct iio_chan_spec 結構體中。

工業I/O子系統中的GPIO控制與MAX11300裝置驅動驗證

在工業I/O子系統中,GPIO(General Purpose Input/Output)控制是重要的介面之一。Linux核心提供了libgpiod函式庫來與GPIO字元裝置互動,取代了從Linux 4.8開始被棄用的GPIO sysfs介面。本章節將介紹如何使用libgpiod工具來控制GPIO,並以MAX11300裝置驅動為例進行驗證。

安裝libgpiod函式庫和工具

首先,需要在Raspberry Pi上安裝libgpiod函式庫和工具。透過以下指令可以完成安裝:

sudo apt-get install gpiod libgpiod-dev libgpiod-doc

安裝完成後,可以使用libgpiod提供的六個命令列工具來存取GPIO驅動程式:

  • gpiodetect:列出系統中所有gpiochips的名稱、標籤和GPIO線路數量。
  • gpioinfo:列出指定gpiochips的所有線路名稱、消費者、方向、活動狀態和其他旗標。
  • gpioget:讀取指定GPIO線路的值。
  • gpioset:設定指定GPIO線路的值。
  • gpiofind:根據線路名稱查詢gpiochip名稱和線路偏移。
  • gpiomon:等待GPIO線路上的事件,並指定要監控的事件。

MAX11300裝置驅動驗證

  1. 載入模組:首先,需要載入MAX11300裝置驅動模組。

    insmod max11300-base.ko
    insmod max11300.ko
    

    載入後,核心日誌將顯示MAX11300裝置的初始化過程,包括裝置ID的讀取和各通道的組態。

  2. 檢查裝置檔案:載入模組後,MAX11300裝置將在/sys/bus/iio/devices/目錄下建立對應的裝置檔案。

    cd /sys/bus/iio/devices/iio:device0
    ls
    

    列表中將顯示與MAX11300裝置相關的各個通道檔案,例如in_voltage0_mode_7_ADC_rawout_voltage2_mode_5_DAC_raw

  3. DAC輸出與ADC讀取驗證:將port2(DAC)連線到port0(ADC),並進行以下操作:

    • 寫入DAC值
      echo 500 > out_voltage2_mode_5_DAC_raw
      
      這將設定DAC輸出值,核心日誌將顯示相關的暫存器操作。
    • 讀取ADC值
      cat in_voltage0_mode_7_ADC_raw
      
      這將讀取ADC的值,理論上應該接近於之前設定的DAC值(500)。

程式碼解密:

上述步驟涉及的核心程式碼主要包括MAX11300裝置驅動的實作,涵蓋了SPI通訊、暫存器組態以及I/O操作的實作。具體來說:

  • max11300_probe()函式:負責初始化MAX11300裝置,包括讀取裝置ID、組態各個通道的工作模式等。
  • out_voltage2_mode_5_DAC_rawin_voltage0_mode_7_ADC_raw檔案操作:對應於DAC輸出和ADC讀取的操作,分別呼叫驅動程式中的寫DAC暫存器和讀ADC暫存器的函式。

透過以上實驗和程式碼分析,可以驗證MAX11300裝置驅動的正確性和libgpiod工具的有效性,為工業I/O子系統的開發和除錯提供了有力的支援。