AD9265 no-OS Driver

See drivers/adc/ad9265 (doxygen) for the Doxygen documentation.

Supported Devices

Overview

The AD9265 is a 16-bit, 125MSPS analog-to-digital converter (ADC) ideal for communications applications requiring high performance at low cost. It employs a multistage differential pipelined architecture with integrated output error correction, ensuring accurate 16-bit resolution and no missing codes across its operating temperature range of -40°C to +85°C. The ADC includes a broad bandwidth differential sample-and-hold input and supports user-selectable input ranges. It features a differential clock input for conversion control and offers output formats in parallel 1.8V CMOS or LVDS. The device includes a 3-wire SPI-compatible interface for configuration and control, and is housed in a Pb-free, 48-lead LFCSP with options for flexible power-down to enhance power efficiency.

Applications

  • Communications

  • Multimode digital receivers (3G)

    • GSM, EDGE, W-CDMA, LTE, CDMA2000, WiMAX, and TD-SCDMA

  • Smart antenna systems

  • General-purpose software radios

  • Broadband data applications

  • Ultrasound equipment

Operation Modes

The AD9265 supports the following operation modes:

  • Normal Mode: Standard ADC conversion mode for signal acquisition.

  • Full Power-Down: Enters a complete power-down state to conserve energy when the ADC is not in use.

  • Standby Mode: Stops conversions but maintains quick startup time for intermittent data capture applications.

  • Test Mode: Outputs predefined test patterns (PN9, PN23, checkerboard, one-zero toggle) for interface validation and debugging.

Device Configuration

Data Conversion Functions

The ad9265_spi_read and ad9265_spi_write functions facilitate SPI communication with the AD9265 device. ad9265_spi_read reads register values and stores the response, while ad9265_spi_write sends commands and data to write to specific registers. These functions enable configuration and real-time data operations for high-speed data acquisition.

Configuration and Setup Functions

The ad9265_setup function initializes the AD9265 device, setting up SPI communication, output mode, and calibration. It ensures correct device operation and alignment with system requirements. ad9265_outputmode_set configures the output data format to offset binary, two's complement, or Gray code, based on system needs. ad9265_calibrate adjusts delay settings for accurate data conversion, essential for high-speed data acquisition systems.

Power Management Functions

Power management is implemented by configuring specific registers in the AD9265 through SPI commands. Though explicit power management functions like power_down are not separately defined, adjusting output mode and communication settings aids in efficient power management, crucial for energy conservation in embedded systems.

Debugging and Testing Functions

ad9265_testmode_set configures the AD9265 to output test patterns for interface validation and integration checks. The function supports predefined test modes like the one-zero toggle, allowing developers to debug and verify system performance before production deployment.

Device Removal Function

The ad9265_remove function is responsible for preparing the AD9265 device for safe removal by deallocating resources. It employs no_os_spi_remove to disconnect the SPI interface and no_os_free to free the allocated memory of the device structure, ensuring resource release and maintaining system stability. The function returns an integer status of the SPI removal operation, which indicates whether the removal was successful. This comprehensive cleanup routine ensures that no resources are left allocated after the device is removed, preventing potential memory leaks or system issues.

Driver Initialization Example

#include "no_os_error.h"
#include "no_os_print_log.h"
#include "xil_cache.h"
#include "xparameters.h"
#include "axi_adc_core.h"
#include "axi_dmac.h"
#include "ad9265.h"
#include "no_os_spi.h"
#include "xilinx_spi.h"
#include "parameters.h"

int main(void)
{
    int32_t status;

    /* Initialize SPI structures */
    struct xil_spi_init_param xil_spi_param = {
        .type = SPI_PS,
    };

    struct no_os_spi_init_param ad9265_spi_param = {
        .device_id = SPI_DEVICE_ID,
        .max_speed_hz = 10000000u,
        .chip_select = 0,
        .mode = NO_OS_SPI_MODE_0,
        .extra = &xil_spi_param,
        .platform_ops = &xil_spi_ops,
    };

    /* ADC Core */
    struct axi_adc_init ad9265_core_param = {
        .name = "ad9265_core",
        .num_channels = 1,
        .base = RX_CORE_BASEADDR
    };
    struct axi_adc *ad9265_core;

    /* AXI DMAC */
    struct axi_dmac_init ad9265_dmac_param = {
        .name = "ad9265_dmac",
        .base = RX_DMA_BASEADDR,
        .irq_option = IRQ_DISABLED
    };
    struct axi_dmac *ad9265_dmac;

    /* AD9265 Initialization */
    struct ad9265_init_param ad9265_param = {
        .spi_init = ad9265_spi_param
    };
    struct ad9265_dev *ad9265_device;

    #ifdef XILINX_PLATFORM
    /* Enable the instruction cache. */
    Xil_ICacheEnable();
    /* Enable the data cache. */
    Xil_DCacheEnable();
    #endif /* XILINX_PLATFORM */

    status = axi_adc_init(&ad9265_core, &ad9265_core_param);
    if (status != 0) {
        pr_err("axi_adc_init() error: %s\n", ad9265_core->name);
        return -1;
    }

    status = axi_dmac_init(&ad9265_dmac, &ad9265_dmac_param);
    if (status != 0) {
        pr_err("axi_dmac_init() error: %s\n", ad9265_dmac->name);
        return -1;
    }

    status = ad9265_setup(&ad9265_device, ad9265_param, *ad9265_core);
    if (status != 0) {
        pr_err("ad9265_setup() failed!\n");
        return -1;
    }

    status = ad9265_testmode_set(ad9265_device, TESTMODE_ONE_ZERO_TOGGLE);
    if (status != 0) {
        pr_err("ad9265_testmode_set() TESTMODE_ONE_ZERO_TOGGLE failed!\n");
        return -1;
    }

    struct axi_dma_transfer read_transfer = {
        .size = 16384 * 2,
        .transfer_done = 0,
        .cyclic = NO,
        .src_addr = 0,
        .dest_addr = (uintptr_t)ADC_DDR_BASEADDR
    };

    status = axi_dmac_transfer_start(ad9265_dmac, &read_transfer);
    if (status != 0) {
        pr_err("axi_dmac_transfer_start() failed!\n");
        return -1;
    }

    /* Wait until transfer finishes */
    status = axi_dmac_transfer_wait_completion(ad9265_dmac, 500);
    if (status < 0)
        return status;

    Xil_DCacheInvalidateRange((uintptr_t)ADC_DDR_BASEADDR, 16384 * 2);

    pr_info("Capture done.\n");

    status = ad9265_testmode_set(ad9265_device, TESTMODE_OFF);
    if (status != 0) {
        pr_err("ad9265_testmode_set() TESTMODE_OFF failed!\n");
        return -1;
    }

    pr_info("Done\n");

    #ifdef XILINX_PLATFORM
    /* Disable the instruction cache. */
    Xil_ICacheDisable();
    /* Disable the data cache. */
    Xil_DCacheDisable();
    #endif /* XILINX_PLATFORM */

    return 0;
}