Control a CRT with the Raspberry Pi DPI

I managed to send video signals to a Mac Classic’s internal CRT monitor from a BeagleBone Black back in 2016, and it seems like this is a topic that a lot of people are still interested in. A recent discussion gave me the idea to try and do the same thing with a Raspberry Pi, and I wanted to document the experiment in this article.

Introduction

Important update: As of right now, the Macintosh Classic CRT related parts of this article are only valid if you use a Raspberry Pi 4! Older versions won’t work. However, the DPI interface is available on all other 40-pin Raspberry Pi models, and the rest of the article remains valid for those.

Please also note that this is an approach that worked for my Mac Classic, not an official guide or a universal method that’ll work for all of you. Please also see the comments for fixes that other readers have implemented!

If you remember the original series and this article about exact timings on the Pi, I somewhere concluded that it simply wasn’t possible. At least not in the same way it is on the BBB. While the sync signals could be generated precisely on the Raspberry Pi, it was not capable of sending the pixel data to the monitor fast enough in the full resolution.

While I still think that’s true, I didn’t think about the possibility to use the Pi’s display hardware to do the job for me, like a commenter on the original series pointed out. So the main goal of this article is to configure the Raspberry Pi in a way that allows the framebuffer to be rendered on the Macintosh Classic’s monochrome CRT display.

The Display Parallel Interface (DPI)

You might have seen some Raspberry Pi display HATs that only connect via the GPIO interface. Those use the DPI mode of the 40-Pin GPIO Raspberry Pi, which is one of the alternate functions of the GPIO.

If selected, the GPIO pinout of the Pi changes:

Figure 1: The GPIO pins in DPI mode (Source)

This configuration allows parallel RGB displays to be attached to the Raspberry Pi GPIO. Several color modes are available:

  • RGB24 (8 bits per color)
  • RGB666 (6 bits per color)
  • RGB565 (5 bits red, 6 green, and 5 blue)

However, this also means that most of the GPIO pins can’t be utilized for other tasks while the Pi operates in the DPI mode.

This interface is controlled by the GPU firmware and can be configured with special config.txt parameters. Furthermore, you’ll also have to load and enable the correct Linux Device Tree overlay, just like with the original BBB version.

Enabling the ALT2 (DPI) Mode of the GPIO

As mentioned, the mode is enabled by loading the correct Linux Device Tree overlay. But first, you’ll have to disable I2C and SPI, because those will conflict with some of the video pins. To do that, edit the config.txt file:

sudo nano /boot/config.txt

In that file, comment out the following two lines:

dtparam=i2c_arm=on
dtparam=spi=on

They should now look like this:

# dtparam=i2c_arm=on
# dtparam=spi=on

Once that’s done, put the GPIO in the Alt2 mode by loading the DTO:

# 24-Bit mode
dtoverlay=dpi24
# 18-Bit mode
# dtoverlay=dpi18

Note that both DTOs are already installed by default. They are located in the following folder:

/boot/overlays

That’s all you need to do to enable the DPI mode! Let’s take a look at how you can configure the graphics card to output the right sync signals.

Configuring the video hardware

As mentioned earlier, the DPI mode can be configured by placing special attributes in the config.txt file. I wrote this small Java application that’ll allow you to quickly enter all the necessary information. It will then generate the attributes for you, and you only need to add them to the config.txt file:

Figure 2: The RPi DPI-Calculator

This tool is universal and can also be used to create the configuration properties for other displays. The various fields and parameters are explained on the app’s download page. I used the following two attributes for the Macintosh Classic CRT:

dpi_output_format=0x76017
dpi_timings=512 0 14 178 0 342 0 0 4 24 0 0 0 60 0 15667200 1

Just add them to the end of the config.txt file.

Configure the framebuffer and setup a custom video mode

You can either use a pre-configured timing mode, or define a custom one. In this case, no standard video-mode could be used to interface the display. Therefore, I had to define a custom video mode, which can be done by setting the following two flags in the config.txt file:

dpi_group=2
dpi_mode=87

This will make sure that the dpi_timings parameter, described above, is used by the driver when the Raspberry Pi boots up.

As the last step, the framebuffer has to be configured. I used the following settings for the Mac Classic CRT:

overscan_left=0
overscan_right=0
overscan_top=0
overscan_bottom=0
framebuffer_width=512
framebuffer_height=342
enable_dpi_lcd=1
display_default_lcd=1

The last two lines will make sure that the video signals get generated and that the DPI is used to output the contents of the frame buffer.

The overscan values can be used to center the image if it should be off-center. However, mine was fine right away, so I didn’t use those values.

The completed config.txt file

These are all the lines I added to the config.txt file for the Macintosh Classic CRT:

dtoverlay=dpi24
overscan_left=0
overscan_right=0
overscan_top=0
overscan_bottom=0
framebuffer_width=512
framebuffer_height=342
enable_dpi_lcd=1
display_default_lcd=1
dpi_group=2
dpi_mode=87
dpi_output_format=0x76017
dpi_timings=512 0 14 178 0 342 0 0 4 24 0 0 0 60 0 15667200 1

Hooking everything up

Connect the HSYNC line of the Raspberry Pi (Physical Pin #5) and the VSYNC line of the Pi (Physical Pin #3) to the HSYNC and VSYNC lines of the display. Unfortunately, my display’s synchronization signals use a voltage of 0V and 5V for the digital LOW and HIGH state. However, the Raspberry Pi only outputs 3.3V. Therefore, I also needed to add a logic level converter to the two sync signals. Don’t forget to connect a ground wire of the display to a GND pin on the Pi (See fig. 4).

Next, connect the color lines of the Raspberry Pi to the display. This step varies, depending on your configuration and display. The following GPIO pins can be used to transmit the color information:

Figure 3: color data lines in various color modes

I used mode 7, which means that there are 8-bits per color. If you, however, use mode 3, for example, the red data-bits get transmitted on the GPIO pins 24 to 20, green pixel information gets sent over the pins 17 to 12, and blue over GPIO 8 to 4. This configuration allows you to use some GPIO pins for other tasks.

The Mac Classic’s display is a one-bit monochrome display, so I used a single color line to connect the data-line of the screen. That’s a very quick and dirty solution, and I’ll properly hook the screen up in another article. For now, this is all I needed to do:

Figure 4: The connections I had to make to control the Macintosh Classic CRT
(View full size image)

This method was enough to verify whether the signal generation works properly.

Luckily, it did almost right away. Here are a few quick pictures I took:

As you can see both, the console, as well as the desktop, can be displayed perfectly fine. However, as mentioned before, the colors are completely off, which is fine for now. I’ll fix that later.

Problems and solutions

Compatibility
As some commenters have brought up, older Raspberry Pi Models can’t produce a pixel clock frequency that suits the Macintosh Classic CRT. Therefore, the Macintosh Classic related sections of this article only hold for the Raspberry Pi 4. With it, you can achieve a close enough output:

Figure 5

Furthermore, there may be differences in the various iterations or versions for different regions/countries of the Macintosh Classic. However, that’s just speculations.

Overscan
If you remember the BBB series, one problem was, that the Macintosh Classic’s CRT display circuitry expects the HSYNC signal to become HIGH (and thus inactive) exactly 110 pixels after the video data had already started:

Figure 6: The HSYNC signal that the CRT expects

However, the Pi can only generate an HSYNC signal that gets HIGH just before the data gets transmitted. Or, in other words, the data gets transmitted just after the HSYNC is done, which is the way to go for HDMI and VGA.

My first workaround for this problem was to increase the number of pixels per line by 110, use a left-overscan of -110 pixels, and then make the HSYNC pulse 110 dots longer. This worked reasonably well. One of the pictures from the slideshow above shows this workaround. However, this way, every line took longer than it should, which caused refreshing artifacts and flicker.

You might have noticed that my finished configuration from above doesn’t contain this workaround. It turned out, that the display simply ignored the incorrect portion of the HSYNC pulse and happily rendered the data anyway. So in the end, it was much less of a problem than I had first thought.

Troubleshooting
Another thing, that I noticed, is that when you leave the Mac Classic CRT’s data line floating (not connected to anything), it displays all pixels at full brightness (blank white screen) as long as the HSYNC and VSYNC lines are correct. This is good for troubleshooting. If you don’t see this happening (or if the display produces a clearly audible buzzing or humming sound) try swapping the HSYNC and VSYNC lines.

Voltages
Make sure that you supply the correct voltages! The synchronization lines on the Macintosh Classic CRT use 5V and the data line uses 3.3V. Utilize a logic level converter (or any similar technique) to overcome this issue.

Display is still blank after troubleshooting
If the Mac Classic CRT displays a full white screen with the data pin floating but it doesn’t display anything with it connected, try to use a different color output of the Raspberry Pi.

Supported Raspberry Pi Versions
The DPI interface is available on all 40-pin Raspberry Pi versions (including the Zero). The instructions for the Macintosh Classic CRT, mentioned in this article, will currently only work on a Raspberry Pi 4.

Sources

[Figure 1] Screenshot from pinout.xyz
[Figure 3] Official Raspberry Pi Hardware documentation
[Figure 4] Raspberry Pi 3 Vector Graphic
[Figure 6] Mac Classic II Developer Notes

Raspberry Pi video options (overview)

Summary

The old BBB based project was a lot of fun to create. However, it’s extremely outdated nowadays as well as inconvenient to use. Furthermore, I never managed to display the contents of the framebuffer with that method.

That’s where this mini-project comes in. While the BBB is practically dead, the Raspberry Pi is more than alive. Luckily, it’s very easy to set up the DPI mode and configure it to work with almost any display, even 30-year-old CRTs. This method allows me to render the desktop and the console output without any complicated programs and hardware modifications.

80 thoughts on “Control a CRT with the Raspberry Pi DPI

  1. Hello! Great write up

    I have macintosh SE and i tryed your solution
    However i have a couple questions and i am not sure if you could help:

    Macintosh se does accept hsync and vsync from rpi 4 without level converter
    But the image has a bit of ditortion: have diagonal lines and its to much streched vertically
    Any ideas how to make it fit?

    Thx

    Like

    1. Ok looks like i understund what is going on

      I am having inverted colors
      I am using the config from KiritoTech by the way:

      dtoverlay=vga666
      enable_dpi_lcd=1
      display_default_lcd=1

      dpi_group=2
      dpi_mode=87

      dpi_timings=512 1 14 178 0 342 1 0 4 24 0 0 0 60 0 15667200 1

      Like

      1. Hello!

        I’m also having inverted colors, both when using the config from KiritoTech and the config in the original post.

        Were you able to solve it?

        Like

      2. I’m sorry for late replay.
        I am busy at work right now, I really want to final build for this.

        By the way you are having inverted colors?

        dpi_timings=512 1 14 178 0 342 1 0 4 24 0 0 0 60 0 15667200 1
        Change last digit to 0.
        dpi_timings=512 1 14 178 0 342 1 0 4 24 0 0 0 60 0 15667200 0

        Mine was orignally inverted color from this site and adrians.
        So I tried changed last digit to 1 and it gave me correct colors.

        Like

          1. I can see my older post.

            Maybe you can change to 0.
            From:
            dpi_timings=512 1 14 178 0 342 1 0 4 24 0 0 0 60 0 15667200 1
            To:
            dpi_timings=512 0 14 178 0 342 0 0 4 24 0 0 0 60 0 15667200 1

            Like

  2. Hi! Loved this project! I just purchased a Mac Classic to attempt this myself and make the machine usable for the modern world. Do you have a diagram to show which cables on the CRT Display are the SYNC/GRND/DATA? or are they already labeled?

    Like

  3. I’m sorry for long time no response.

    It is true CRT is pure digital signal.

    There was Micron xceed hardware mod from digital to analog (which is working around on 1 volt).

    After research, and I came up with those neck crt pcb are same on my Macintosh Classic 2. (possible on Classic too)

    So I made small pcb for crt neck pcb, and very small modification on orignal crt pcb. (see picture link below)
    https://ibb.co/3vpPzyy
    https://ibb.co/t8sPSys

    Next, I need vga signal into 1 wire grayscale output. (which I did on breadboard, no pcb yet)
    It is bassically mixing rgb color into grayscale signal. (rgb to grayscale mod)
    https://ibb.co/mNmjJxx

    I will post pcb design later when it’s complete.

    KiritoTech

    Liked by 1 person

  4. On the Mac Classic and Classic II the CRT screen brightness is not controlled via a potentiometer, but rather it is controlled by a signal from the logic board, I believe that is on pin 9. Has anyone used the RPi to drive this brightness control?

    Like

    1. Yes, I think that is correct. Typically, you could use a slider in the Mac’s operating system to regulate the brightness. I think it’s a PWM signal. The official repair guide contains a detailed description of what signal the display circuit expects. I haven’t tried it myself, though.

      Like

  5. Hi great project! The Mac CRT is monchrome and is usually driven with a digital video signal, so either black or white. I believe if the video signal is modulated between 0 and 5V the CRT will display a grayscale image. Has anyone tried using more bits from the DPI interface to create an analog video signal? For example, feeding Green[7..0] into a DAC?

    Like

    1. Oh, it looks like the Mac Classic CRT circuitry is designed for digital video, so it looks like we’re stuck with only black and white pixels, no true grayscale, at least not without more elaborate hardware hacks to the PCB that fits on the end of the CRT tube. KiritoTech has shown some impressive results with dithering though. (if one turns the pixel on and off fast enough, the phosphor will generate the grayscale level!)

      Liked by 1 person

  6. So cool! I made a little web site “emulating” the classic Macintosh OS, and adding a 1-bit webcam “app”: https://mockintosh.com, would be super neat to try it out on a proper Macintosh CRT.. Maybe adding an internal or external webcam šŸ™‚

    How difficult would you say this project is for a total electronics/hardware beginner?

    Like

    1. Hi,
      Thanks for sharing your project — It looks awesome so far, and I’ll absolutely check back on your project in the future! šŸ™‚
      I’d say the complexity of adding a camera depends on your exact setup. I’ve seen some projects that completely replace the internals of the classic Macintosh with new hardware (including the display). In this article, I discussed using a Raspberry Pi, which more or less also counts as a regular modern PC. Adding a camera should be as easy as plugging in a USB webcam with both of these options. However, other approaches, for example, using an FPGA or an MCU that can run a high-level OS such as Linux, might require more tinkering and a deeper understanding of the USB protocol. However, for most such MCUs, you can usually also find USB drivers. Anyway, I’d say using custom hardware would most likely require a deeper understanding of the entire process.

      Like

      1. Thanks for your reply. I’d definitely want to use the original CRT as you have done here, together with a Raspberry Pi and run a browser in kiosk mode. I’ll try to get my hands on a Macintosh Classic.

        Like

  7. So cool! I made a little web site “emulating” the classic Macintosh OS, and adding a 1-bit webcam “app”: https://mockintosh.com, would be super neat to try it out on a proper Macintosh CRT.. Maybe adding an internal or external webcam šŸ™‚

    How difficult would you say this project is for a total electronics/hardware beginner?

    Like

  8. Hi, I did little progess.
    I have also found out about this hardware (pcb and crt)
    Videosignal is just 1-0-1, not variable signal. It is ttl signal.
    I sound out there was third party hardware from mono to greyscale.
    To bad it works only for macintosh SE/30.

    I found circuit at: https://68kmla.org/bb/index.php?threads/se-30-micron-xceed-clear-plastic-goodie.7598/page-2

    Which I have also circuit for mac classic, well it looked same.
    So I have designed small pcb, with vga666 adaptor, and level convertor.
    This is what I get.

    cli colortest: https://ibb.co/n7HsX26

    Videoclip trought cli omxplarer: https://ibb.co/tQhTnVM

    Liked by 1 person

    1. Hi!
      Thank you for sharing! I love the progress you’re making, fantastic work! I think the SE/30 and the Macintosh Classic had a very similar (if not the exact same) CRT, but I might be completely wrong here. So I think what works for the SE/30 could also work for the Mac Classic display. Oh yeah, and you’re right. According to Wikipedia, there’s an adapter board for the SE/30 that allows it to display grayscale video (not only digital B/W). It’s apparently also the only non-color compact Mac that can do so.

      Like

      1. I have video uploaded.
        It works good after more modifying custom hardware.
        Results is good for now.
        See yourself how it came out.

        KiritoTech

        Liked by 2 people

        1. I’m sorry for taking this long to reply to you. Your comment somehow slipped through my WP notifications — that really shouldn’t have happened. Either way, fantastic results! The output to the CRT is clear and sharp. Thanks again for sharing all your insights and tips & tricks. I truly appreciate it, and I’m sure people struggling with getting the CRT display to work will find them helpful too!

          Like

  9. I like your work.
    But both configuration does not work.
    Yours does not display, Adrian’s work sort of, but not centered.
    I have edited config.txt.
    Only I need is:

    dtoverlay=vga666
    enable_dpi_lcd=1
    display_default_lcd=1

    dpi_group=2
    dpi_mode=87

    dpi_timings=512 1 14 178 0 342 1 0 4 24 0 0 0 60 0 15667200 1

    And this works!

    It is sort of mixed work from your and Adrians.

    Notice dpi_timings is yours, but it is 512 0….342 0, I set it to 512 1….342 1.

    P.s. it is running from Pi4.

    Liked by 1 person

      1. I have to admit, at first try somehow I destroyed 3B+….
        I don’t know what went wrong, I use SN74AHCT125N level convertor.
        Btw, here is picture of my result:
        https://ibb.co/j6qNDx6

        And now we have to find solution add other color into 1 signal.
        Maybe add small diode or small resistor in parallel. Like VGA666 adaptor.

        Liked by 1 person

        1. I have small progess of crt.

          I find config.txt setting you can add dithering.

          Info you can find at: https://retropie.org.uk/forum/topic/28071/piboy-dmg-18bit-color-banding

          I have only connected video line on pin 10 (green7) and 12 (red4).

          For color test I used 265 color test pattern.
          https://askubuntu.com/questions/821157/print-a-256-color-test-pattern-in-the-terminal

          This is before I set dither.
          https://ibb.co/pjgfV3m

          Add this line to end.
          hvs_set_dither=0x3110
          And this is what you get.
          https://ibb.co/qkNQyDC

          I haven’t tried all pins and dither settings, just lucky find this and random guess settings and pins.

          Liked by 1 person

          1. Hello!

            Thank you a lot for sharing this information! Fantastic progress. I’m super glad that my article helped you and you got the CRT working so well! I’ve kinda gone away from using just the Raspberry Pi for this project. Instead, I’m working on a universal solution that I hope will work for many more devices (two new updates are coming this Wednesday and next week).

            Either way, thanks again for sharing the dithering config. I knew that there was a way to enable it, but I couldn’t find a proper link back in 2016 when I first started using the Mac Classic CRT.

            Like

Leave your two cents, comment here!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.