ICE40HX8K AD9225 ADC with Nmigen

This is a first stab at getting the AD9225 ADC working with the ICE48HX8K. I don’t really know my way around python or Nmigen, so these notes most likely do not represent the right way of doing things. But it somewhat works…

The AD9225 is a part pulled from an old CCD camera. It’s a 25MSPS 12bit ADC. I’m not driving it this fast in this test, nor is the UART currently dumping all 12bits. Most likely the Resource can be better refactored so that the clock and data pins are part of the same Resource… Anyway, here’s the code:

#!/usr/bin/python3

from nmigen import *
from uart import *
from nmigen_boards.ice40_hx8k_b_evn import *
from nmigen.build import *

from pll import PLL


class Top(Elaboratable):

    def elaborate(self, platform):
        # B1 is clock
        adcclk = [ Resource("ad9225clk", 0, Pins("B1", dir="o"), Attrs(IO_STANDARD="SB_LVCMOS")) ]

        adc = [ Resource("ad9225", 0, Pins("B2 C1 C2 D1 D2 E2 F1 F2 G1 G2 H1", dir="i"),  Attrs(IO_STANDARD="SB_LVCMOS")) ]
        platform.add_resources(adc)
        platform.add_resources(adcclk)

        # PLL Stuff

        # If you don't specify dir='-', you will experience a world
        # of debugging pain.
        clk_pin = platform.request(platform.default_clk, dir='-')

        m = Module()
        pll = PLL(freq_in_mhz=12, freq_out_mhz=96)

        m.domains += pll.domain     # override the default 'sync' domain

        timer = Signal(28)

        #Connect TX to B12
        led0 = platform.request('led', 0)
        muart = platform.request('uart')
        data  = platform.request('ad9225',0)
        dataclk  = platform.request('ad9225clk',0)
        dataA = Signal(8)
        rdy   = Signal(1)

        with m.If(timer[25]):
            m.d.sync += [
              rdy.eq(1),
              timer.eq(0)
            ]
        with m.Else():
            m.d.sync += [
                timer.eq(timer + 1)
            ]

        with m.If(rdy == 1):
            m.d.sync += [
                rdy.eq(0)
            ]


        m.d.sync += [
            dataA.eq(data.i[0:8] + 0x60),
        ]

        m.d.comb += [
            pll.clk_pin.eq(clk_pin),
            dataclk.eq(timer[20])
        ]

        # UART

        uart = UART(divisor=10000)
        uart.tx_o = muart.tx


        m.d.comb += [
            uart.tx_data.eq(dataA),
            uart.tx_rdy.eq(rdy)
        ]

        m.submodules += [pll, uart]

        return m


if __name__ == '__main__':
    platform = ICE40HX8KBEVNPlatform()
    platform.build(Top(), do_program=True)

The above code should output ADC values via the FT2232. This is what I get when driving the ADC with a 0.1Hz 3v square wave. The AD9225 is running at 3.3v (analog and digital):

jbnb_______________bmjalaocbkbka______________ckklbmbmamoc_______________clakbobnbmldh______________nbmblajboblald______________akbkmobmn_ka_______________cncmal]h_lelk______________kbm_