evansm7 / pico-mac

Run the popular umac emulator right on your Pi Pico!
425 stars 28 forks source link

Video output via I2C OLED module #8

Closed alex-arknetworx closed 3 months ago

alex-arknetworx commented 3 months ago

Hi Evansm7,

Great work on bringing another emulated system to the RP2040! It's great to see the growing list like neo6502, pico-rv32ima and decstation2040!

I noticed you mentioned some video improvements you would like to make in the readme.md alluding to LCD support. I was wondering if you think it would be possible to write the mac framebuffer (or even a sub set of the pixel space for tiny panels) out to a SPI connected LCD module (e.g. to a ST7735 tft controller)?

If i were to experiment with this, is video.c a good place to start understanding where the mac framebuffer is being accessed?

evansm7 commented 3 months ago

Yo! Have a look at main.c, and the video setup. It sets the framebuffer scan-out from umac_ram + umac_get_fb_offset(), the address in the host of the framebuffer. Today that’s a constant, but is technically wrong as the Mac can change the FB base (via a VIA IO bit), but applications in general don’t seem to ever do this. Anyway, from that base you have a plain 512x342x1 buffer you could output to another LCD! Looking forward to hearing how your experiments progress 🙂

alex-arknetworx commented 3 months ago

Hi Evansm7,

Appreciate your comments and the heads up about the variable nature of the Mac FB index. I will keep you posted on any developments :)

alex-arknetworx commented 3 months ago

Hi Evansm7,

I followed your advice but decided to downgrade from SPI and use a 128x64 monochrome OLED via I2C. Based on the SSD1306 driver and using GitHub repository daschr/pico-ssd1306 I added minimal code and have successfully managed to get the System 3 desktop to display on the OLED and can click on the menus and move the mouse around with excellent refresh rate without changing any timing in your code.

For reference I am using a WaveShare pico-zero board with 2Mb. See attached photo as proof of concept, which was hard to capture as the camera refresh rate can see a moving black line as the OLED updates. To the eye there is no black line.

My next development would be to pan my 128x64 bit selection to keep the mouse centered so you can access the full System 3 screen. Also probably would like to remove the VGA as not required anymore :)

Happy to share the modified source files with you directly.

pico_mac_oled

evansm7 commented 3 months ago

That’s really cool! (I like those screens a lot.) well done, hope you’re pushing to a repo somewhere? Fork away! If you remove the VGA it’ll be slightly faster (maybe imperceptible but can’t hurt). I like the follow-mouse thing; are there Mac global variables with the pointer coordinates?

alex-arknetworx commented 2 months ago

Hi Evansm7, yes, you have correctly predicted that using umac_cursor_x and _y will introduce pointer drift :) however the result is still pretty cool for a quick first go and i can pan around the screen and see and click on everything as long as the pointer doesn't hit the screen bounds as the relative movement still coming from HID then causes drift. Something for me to solve, either by trying to find the memory location of the System OS pointer or maybe something fancy like right mouse click to pan the screen without passing HID updates to umac, in order to re-center it.

I really need to spend time in GitHub and sort out all my forking: all my edits are on local clones. None the less, for everyone interested in trying an OLED or that want to get the project running on a WaveShare RP2040-Zero, here are my modified source files, which still include VGA support. You will also need to put ssd1306.c in /src/ and ssd1306.h and font.h in /include/ from GitHub repository daschr/pico-ssd1306

main.c.txt hw.h.txt CMakeLists.txt

alex-arknetworx commented 2 months ago

Now that the OLED is usable, how about a new app that targets a small screen for Pico-Mac? I managed to get MacASM V1.2 to run on System 1 on Pico-Mac. It won't compile assembly on the pico because the disk is locked / write-protected but writing some assembly on the disk image on mini-vmac, compiling it there and then transferring the img back to the pico build.... a new application! pico_mac_firstNewApp

all2coolnick commented 2 months ago

Now that the OLED is usable, how about a new app that targets a small screen for Pico-Mac? I managed to get MacASM V1.2 to run on System 1 on Pico-Mac. It won't compile assembly on the pico because the disk is locked / write-protected but writing some assembly on the disk image on mini-vmac, compiling it there and then transferring the img back to the pico build.... a new application! pico_mac_firstNewApp

Hi alex-arknetworx I've been trying to get pico-mac running on a Pico Zero and am having no joy. You have managed it so I wondered if you could tell me if you had to do anything other than change the GPIO assignments in hw.h. I've defined them as follows (though I'm not using GPIO_VID_CLK as I did not need to on my normal Pico):

define GPIO_VID_DATA 6

define GPIO_VID_VS 7

define GPIO_VID_CLK 9

define GPIO_VID_HS 8

I'm getting nothing on the VGA monitor after re-building and flashing. I also re-assinged the LED pin so I could at least see the flashing LED

define GPIO_LED_PIN 14

But that did not flash. I know all the GPIOs I'm using are functioning as I have tested each of them with an external LED and simple Micropython blink program. Did you use the extended 208K memory in the umac and pico-mac builds? I did but can't see why that would matter.

alex-arknetworx commented 2 months ago

Hi all2coolnick,

I've had a look back at my 'VGA Only' build and I think the only modifications I made was to the hw.h GPIO assignments. However I used GPIO 10 through 13 as these were along the bottom edge of the board. In later revisions I did change the LED GPIO to 16 as per the zero pin assignment guide (picture attached), but actually it still doesn't blink maybe because it might need to be set up as a PWM.

I would have a go with your own build using:

define GPIO_VID_DATA 10

define GPIO_VID_VS 11

define GPIO_VID_CLK 12

define GPIO_VID_HS 13

For reference I was using the original 128K memory version of the repo along with a Philips 241V LCD monitor via VGA and the correct resistor network. I can send my UF2 file from this build which you could try with VGA wired as above (10 thru 13) to see if its a build problem or a hardware problem. Also my board has part number RP2040-Zero SKU 20187 with 2Mb flash. If you still have problems let me know and I can also send you my whole source directory.

ce08607-rp2040-zero-pinout_3130485a4f6

all2coolnick commented 2 months ago

Thanks for the reply alex-arknetworx and for the download. I’ll give that a try. From what I’ve read, using the onboard RGB led is a little complicated and needs the Neopixel library.

all2coolnick commented 2 months ago

I’ve just seen Matt’s reply in another issue thread saying that for the VGA lines “the pins must be contiguous and in ascending order of data, VS, CLK, HS.” I bet that will be it as I swapped round the last two so that I had the three I needed on the edge pins which are easier to breadboard.

alex-arknetworx commented 2 months ago

I’ve just seen Matt’s reply in another issue thread saying that for the VGA lines “the pins must be contiguous and in ascending order of data, VS, CLK, HS.” I bet that will be it as I swapped round the last two so that I had the three I needed on the edge pins which are easier to breadboard.

Good pickup there all2coolnick. Hope you've managed to get VGA going on your Zero board.

all2coolnick commented 1 month ago

FINALLY got pico-mac working on the Pico Zero. Turned out the Zero I had was duff (serves me right for buying an unbranded Waveshare knockoff). I've also got my hands on a couple of the 2.0" 480x640 display modules I want to use. It's the smallest I can find that can show the full 512x342 Mac image (Matt, you may remember I X'd you about wanting to output to a small LCD to build a miniature Mac 128K). It's a DXWY D200N2409V0 2.0" 480x640 TFT using the ST7701S driver (https://www.aliexpress.com/item/1005007523031911.html). It supports RGB 565 parallel input so once it's in that mode, it should be quite straight forward but I believe it needs initialising via SPI and here I've hit a wall due to my lack of C knowledge. I have hunted high and low but can't find an existing driver for that driver written in C that I can compile for the rp2040. DXWY sent me the data sheets for their module and the ST7701S driver, plus an LCD init string text file which I'm not sure what to do with (all attached). I think I can probably figure it out if I'm pushed in the right direction and find a thread to pull on, so hoping one of you might be able to help . Thanks ST7701S.pdf D200N2409V0 SPEC.pdf 2.0VGA LCD init.txt

alex-arknetworx commented 3 weeks ago

Hi @all2coolnick great you sorted out the zero board.

In regards to LCD output, when i posted this thread i was initially going to use a Waveshare color 1.8" 128x160 SPI connected LCD, however I quickly realized I could achieve what i wanted far easier and cheaper and just used an OLED over I2C - this was in keeping with @evansm7 minimal cost approach :)

However: my color LCD has a ST7735 controller, which uses SPI for initial config and ALSO to cyclically receive a bytestream containing the latest frame. Having a quick look at your specs, it seems there are multiple ways to get the FB data into it: MIPI, 16-bit RGB (TTL) parallel, but these introduce unique issues like either having to PIO a MIPI interface (is this even doable without a MIPI PHY) or clock out the FB bytes onto the individual RGB bit lines ... are there even enough I/O's on a Zero, possibly if you tie a bunch together to sort of create a 1bit to 16bit conversion, definitely sounds PIO and more a question for @evansm7

If the ST7701S can receive FB data via SPI your in luck without having to add additional hardware or make major source code changes. I have had success with using GitHub repo /bablokb/pico-st7735 to get a Zero to drive my Waveshare LCD. Have a look there and you might be able to to work out how to get the SPI up and running at least.

As far as code changes, i had to introduce my own code for OLED support because VGA is totally different to what you need when sending data over a serial bus. If you look at my main.c posted above in previous comments this is my basic structure for getting my OLED to work - you will have to write a similar program but for SPI.

include the additional headers for the OLED library

edit static void io_init() to also init io pins for I2C

create void oledInit() and call this from main() to create an SSD1306 object pointed at the I2C port

create void writeFB(uint8_t *fb_in) and call this from main() and pass in the pointer to the umac frame buffer - this is where all the magic happens, and you can think of this as some sort of display driver. Ignoring what i'm doing to only select part of the framebuffer dependent on mouse movements, every call of this function clears the entire OLED and then conditionally sets each pixel if it is set in the umac Framebuffer. I also have to reverse the order as technically the Macintosh FB is big endian and I need little endian logic to work hence the funny 7 - bit % 8. To work with a color panel you would have to expand every 1 bit from the Macintosh FB out to suit a color RGB565 format, a simple copy would not work as your going from 1 bit to 16bit.

Hope this gives you some direction to head in.

all2coolnick commented 2 weeks ago

Hi Alex,

Thanks so much for the extra info and sorry for the delay replying. I also got a bit more clarity from the LCD module manufacturer about the required SPI initialisation process. I’m just waiting for some free time to try this all out.

I’ll let you know if I succeed.

Thanks