1111import picodvi
1212import displayio
1313
14+ # The connections from the Xerox 820
1415vdata = board .D9 # Followed by hsync on D10 & vsync on D11
15- pixel_sync_out = board .D5
16- pixel_frequency = 10_694_250 # oddly specific
16+ # The nominal frequency of the Xerox 820 video circuitry. Can modify by steps
17+ # of approximately ±42000 to improve display stability
18+ pixel_frequency = 10_694_250
19+ # The PIO peripheral is run at a multiple of the pixel frequency. This must be less
20+ # than the CPU speed, normally 120MHz.
1721clocks_per_pixel = 10
22+ # The "fine pixel offset", shifts the sample time by this many sub-pixels
1823fine_pixel = 0
24+ # A pin that shows when the Pico samples the pixel value. With an oscilloscope, this can
25+ # be used to help fine tune the pixel_frequency & fine_pixel numbers. Ideally, the rising
26+ # edge of pixel_sync_out is exactly in the middle of time a pixel is high/low.
27+ pixel_sync_out = board .D5
28+
29+ # Details of the Xerox display timing. You may need to modify `blanking_lines` and
30+ # `blanking_pixels` to adjust the vertical and horizontal position of the screen content.
31+ # Normally you wouldn't change `active_lines` or `active_pixels`.
1932active_lines = 240
2033blanking_lines = 18
2134active_pixels = 640
2235blanking_pixels = 58
2336total_lines = active_lines + blanking_lines
2437
25- displayio .release_displays ()
26-
38+ # Pins for the DVI connector
2739dvi_pins = dict (
2840 clk_dp = board .CKP ,
2941 clk_dn = board .CKN ,
3547 blue_dn = board .D2N ,
3648)
3749
50+ # Set up the display. Try 640x240 first (this mode is likely to be added in CircuitPython
51+ # 9.1.x) then 640x480, which works in CircuitPython 9.0.x.
3852try :
53+ displayio .release_displays ()
3954 dvi = picodvi .Framebuffer (640 , 240 , ** dvi_pins , color_depth = 1 )
4055except ValueError :
4156 print (
4863# Clear the display
4964ulab .numpy .frombuffer (dvi , dtype = ulab .numpy .uint8 )[:] = 0
5065
51- def instruction_gen ():
66+ # Create the "control stream". The details are discussed in the Learn article
67+ def control_gen ():
5268 yield total_lines - 2
5369 for _ in range (blanking_lines ):
5470 yield from (1 , 0 ) # 0 active pixels is special-cased
5571 for _ in range (active_lines ):
5672 yield from (blanking_pixels - 1 , active_pixels - 1 )
5773
74+ control = array .array ("L" , control_gen ())
5875
59- instruction = array .array ("L" , instruction_gen ())
60- print (instruction )
61-
76+ # These little programs are run on the RP2040's PIO co-processor, and handle the pixel
77+ # data and sync pulses.
6278jmp_0 = adafruit_pioasm .Program ("jmp 0" )
6379
6480program = adafruit_pioasm .Program (
@@ -90,12 +106,13 @@ def instruction_gen():
90106"""
91107)
92108
109+ # Set up PIO to transfer pixels from Xerox
93110pio = rp2pio .StateMachine (
94111 program .assembled ,
95112 frequency = pixel_frequency * clocks_per_pixel ,
96113 first_in_pin = vdata ,
97114 in_pin_count = 3 ,
98- # in_pin_pull_up=True,
115+ in_pin_pull_up = True ,
99116 first_sideset_pin = pixel_sync_out ,
100117 auto_pull = True ,
101118 pull_threshold = 32 ,
@@ -105,6 +122,7 @@ def instruction_gen():
105122 ** program .pio_kwargs ,
106123)
107124
125+ # Set up the DVI framebuffer memory as a capture target
108126words_per_row = 640 // 32
109127first_row = (dvi .height - 240 ) // 2 # adjust text to center if in 640x480 mode
110128buf = memoryview (dvi ).cast ("L" )[
@@ -114,6 +132,7 @@ def instruction_gen():
114132
115133b = array .array ("L" , [0 ])
116134
135+ # Repeatedly transfer pixels from Xerox into DVI framebuffer.
117136while True :
118137 pio .run (jmp_0 .assembled )
119138 pio .clear_rxfifo ()
0 commit comments