Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Frame buffer Rotation for portrait LCD module #20

Open
all2coolnick opened this issue Nov 21, 2024 · 9 comments
Open

Frame buffer Rotation for portrait LCD module #20

all2coolnick opened this issue Nov 21, 2024 · 9 comments

Comments

@all2coolnick
Copy link

I've made some progress with the little TFT module I told you about. I've got the 3-wire, 9-bit SPI configuration command communication working to put it in RGB mode (I can execute basic commands like all pixels on and all pixels off) so now I'm working on the RGB data. I'm not getting anything on the LCD using the standard picomac video out signals (minus the resistors) but I assume this is because the LCD module is 480x640 portrait (with no rotation command). I'm guessing it can't make sense of the data and sync signals.

I've been trying to understand your video code to find the best way to write the frame buffer out as portrait but I'm stuck. I stepped through pio_video.pio but as I understand it, this is essentially just reading the data from the output shift registers so does not control the order the data is read from the frame buffer. I've looked at video.c but what I can't seem to locate is the code loop that continually reads the frame buffer and sends the data to the pio registers. Could you give me a pointer (no pun intended)?
I thought it might be simpler to modify this code to read the framebuffer in a different order (bottom to top, left to right) but as you wrote all this amazing code, is this how you would do it?
The other option I can think of is trying to modify umac to actually write the frame buffer in portrait but then I would still need to modify the read code so it was sending 640 lines of 480 pixels rather than vice-versa.

I'm linking all the 565RGB data inputs to the LCD panel and driving these directly from the picomac video data pin. I can't think of any reason why that would not work since all I need to send is either all 1s or all 0s. Would you foresee any problems with this approach? The TFT module has two RGB modes; DE and HV. That latter is what I'm trying to use as this does not require the Data Enable which I know you have not implemented yet.

Thanks as always,
N

@all2coolnick
Copy link
Author

Ok, so following a deep dive into the Pico DMA documentation, I can see that’s what is reading from the frame buffer as a continuous stream so reading every 480th bit for a scan line might not be possible with DMA. Could I use the second DMA to copy the frame buffer to a new FB organised as 480x640 and tweek the existing dma to output 480 pixel lines from the new FB?

@all2coolnick
Copy link
Author

Am I right in thinking that the code that writes the video to the frame buffer is part of the Mac ROM, not your umac code?

@evansm7
Copy link
Owner

evansm7 commented Dec 13, 2024

Nick, sorry for the usual late replies! It is not a reflection of my interest in your cool project. :-)

On the HW side, wiring all the data inputs to the single output will probably work "enough" to see something in prototyping but you may need to move to adding an external buffer there (e.g. maybe even driving 4 buffer inputs from the 2040 pin and then driving 4 LCD pins from each of those). 16 pins are a lot to drive from one (and it'll be fairly fast, 25MHz). But it may just work.

The 68K code that writes into the framebuffer -- you're right, it's Quickdraw in the ROM, plus application/OS stuff loaded from disc. I would say it's not fun to hack that end of it.

I think a good approach would be:

  1. Validate a test image (anything at all) on the LCD first, driving it with either your own code, some pico-sdk video/LCD code, or hacking the video.c constants to output 480x640. Then fill the framebuffer with anything (eg. 0-255, 0-255, etc.) and check display is stable. The rest is nice-to-have on top of this step.
  2. Deal with the rotation in pico-mac from the real framebuffer.

It's annoying, but I can't think of a way to make DMA extract say all bit 7s into a row, then all bit 6s, ... etc. One option would be to get the CPU to do this, on the fly. In video_dma_prep_new(), instead of programming DMA to get data from a new line (via video_line_addr()), you could try keeping reading from one line and running a tight loop (in that IRQ routine) to create the line, as fast as possible, by reading vertical strips and extracting bits (a new column each time). Or, same but double-buffer: program DMA quickly with the address of a previously-created line A, then spend time creating the next into a second buffer B, then next IRQ program B and create into A, etc.

Re DE: I will have to add this at some point! I just bought a replacement Ambernic RG35XX LCD panel (3.5" VGA) to try to join in the fun; parts arrive soon. I want to try driving that from the Pico (not necessarily with pico-mac but that would be good too) and that will need DE. Maybe DE mode will help your LCD spring into life?

Other Q for you is does the LCD have any pins that configure H/V scan? I've seen some that have top/bottom and left/right inversion via pins that you strap to Vcc/Gnd, maybe yours really can do landscape somehow? (Is the data sheet online OOI?)
[edit: sorry, I reread and now see you already said "no rotation command" so I guess you've tried that and have checked for other pins-not-commands way of instructing it.]

To try with this code's video output, munge the #define VIDEO_ constants in video.c to match the timing of your LCD. Your HRES will become 480, VRES 640 etc., and also make the VIDEO_FB_HRES/VIDEO_FB_VRES smaller (and even), e.g. try 342x512 or something. You'll see junk but if it's stable that's a great start. (could then write your own code to put a pattern in the framebuffer and test it out maybe?)

Finally once you get step 1 working there is IMHO another option versus rotating the framebuffer.... that is, a portrait Mac :) See #14 -- I had some luck this week with changing video resolution and I just checked, it works at 480x640 too. A wacky portrait Mac would be really cool :) See:
mac_sys3_480x640_2

@all2coolnick
Copy link
Author

Thanks for detailed reply. I will digest all that and look into those option but wanted to let you know that I had also looked at changing the screen pixel dimensions but with a view to using my 2” 480x640 display without rotating the image. It occurred to me that 480 was not much less than the native 512 Mac width so maybe I could put the landscape image across the portrait panel. So, like you, I looked at modifying the Mac ROM and managed to change the screen width to 480 and I have that running in umac. It looks OK. I haven’t had a chance to try this on the LCD yet but this approach presents another problem. In portrait orientation the lcd panel is too tall to fit in the body of the Mac if the Mac is scaled based on the screen image.
I could, as you suggested, go for a portrait Mac (and I may try that for fun) but for the project, I want it to be as close a replica as I can.
So I’m back to needing to rotate the frame buffer. I’ll let you know how I get on, and if you have any more ideas, please do let me know.
Thanks again for your input.
Nick

@all2coolnick
Copy link
Author

all2coolnick commented Dec 31, 2024

Hi Matt,
Finally got some time to work on the LCD. It turns out I can just about fit the LCD in the case in portrait orientation such that the screen width should give an appropriate width image so I've gone back to trying to get the rom-hacked 480 x 342 umac frame buffer output to display across the LCD without the need for FB rotation.
Your advice was sound about stripping it back and starting by trying to get a test image to display on the LCD. I am, however, a bit impatient so before doing that I wanted to give it a try on picomac.
I noted your concern over whether the single GPIO could drive all 16 RGB data inputs but realised that for intitial testing I only need to drive 1 input. I'm driving the highest blue bit with all the other inputs set low and this is giving me a blue image at 50% brightness that is clearly the Mac desktop!
The image is scrambled and a bit tricky to photograph. I'm playing around with the VIDEO_ constants at the moment but from the attached image, what do you think are the most likely setting to change? The diagonal scan lines imply it's not syncing properly although if I remove either of the HSYNC or VSYNC, the image disappears so the signals are definitely getting through.

Can you clarify what VIDEO_HSW and VIDEO_VSW are? Are they the width of the sync pulses?

I'm not sure what the strip down the right hand side is. Sometimes it's there and sometimes not. Maybe I damaged the LCD at some point.
Would it be easier to DM you in some way or email? My email is [email protected]

IMG_2723

@all2coolnick
Copy link
Author

all2coolnick commented Dec 31, 2024

After playing around with porch and clock settings for a few hours, I wasn’t making any progress with the syncing so decided to try setting the frame buffer width back to 512 in hw.h just in case the changes I made to the max rom and umac code had not resulted in a 480x342 frame buffer.
This was the result!
I checked the image against the 480x342 desktop when I run umac from terminal and the desktop does seem to be 480px wide, not 512.
So I'm guessing that although my modified ROM is creating a 480px wide screen image, it's still using a frame buffer of 512 bits per row and I can't see how to change this (all my previous changes were based on locating the values 512 and 342 in close proximity).
I know you said you had been changing the screen dimensions by modifying the Mac ROM. Do you know if you were changing the frame buffer line width?

IMG_2732

@evansm7
Copy link
Owner

evansm7 commented Jan 3, 2025

(replying to the great success reported in #8 (comment) by @all2coolnick )

Finally got picomac running perfectly today on my 2” LCD via RGB565 interface albeit at a slightly reduced screen width of 480px. This is using the WaveShare Pico Zero.

Great to see that screen running! What was the bug, in the end? I didn't completely understand whether it was umac or pico-umac displaying 640 or 512, earlier in the thread, but looks like you solved it. (My first thought was a cmake caching issue maybe?) Most of my "debugging with LCDs" ends up being writing known patterns/lines of particular sizes into the framebuffer to test the scan-out width/position, and so on.

It'll look really great in that 3DP case, well done!

In other LCD news, I finally managed to spend some time on the Anbernic RG35XX replacement I bought from AliExpres (640x480x24 3.5" thing), and finally got it working. It turns out that it, too, needs a bunch of magic SPI commands before taking any RGB. ;( Funny seeing such pixel density with the Mac UI -- and your 480x342 must be even more dense. Biro for scale:

picomac_lcd

I pushed some hacky stuff into https://github.com/evansm7/pico-mac/tree/wip-lcd (in turn based off wip-psram for my convenience, but no strong dependency on the PGA2350/PSRAM stuff) FWIW -- Nick, you won't need this but if anyone else reading needs the DE strobe, then these commits will provide:

  • video: Add DE signal
  • video: Refactor pin config for PIO
    (I'll merge these into main once I add an opt-in config.)

There's also a tweak to reduce the drive strength of the video out pin to 4mA: in the hacky prototype, I tried out driving [7:6] of R,G,B from the one pin without any more buffering. With the 12mA drive (from the picomac drive-VGA stuff) it was ringing horribly and pixels were twinkling/colours shadowed.

@all2coolnick
Copy link
Author

Thanks Matt. The initial problem was that to test the SPI initialisation I was using commands that turned all pixels white then black at the end of the init commands the manufacturer sent me. What I didn’t realise was that these commands took the LCD back out of RGB input mode. When I removed these I got the scrambled image and this was resolved by setting the FB width back to 512px. As far as I can tell, the memory block that the Mac ROM is writing the frame buffer into is still using 512px rows even though I managed to modify the ROM to create a 480px wide screen image.
I didn’t use a disassembler on the ROM, I just searched and replaced values in a hex editor.

What disassembler do you use?
I wanted to make the smallest version of the Macintosh I could but using the 2” LCD I have has meant some compromises including having to reduce the screen pixel width and not being able to put the SD reader in the floppy drive slot (because I have had to use the LCD in portrait orientation which covers the floppy slot). It’s also pretty difficult to use the Mac with such a tiny screen image (at least with my aging eyes).
So I’d like to build one with a larger screen as well. The 3.5” one you used looks a good option. How much was this on AliExpress? I found a few listings for what I think are the same panel but couldn’t see what controller it used.
I’d like to include the screen brightness wheel and I’d like it to make the Macintosh startup chime when turned on. I know there’s no audio support in umac but I assume it would not be too complicated to play the sound through a small speaker as part of the picomac init sequence.

Regarding the video out line. I initially just used the blue msb, then the msb of each colour and once I had it working I gradually increased the number of lines linked to the video data line. I found I was able to drive all 16 rgb inputs linked together with no visible problems to the screen image and without the rp2040 getting hot. From what I could gather from the data sheet, the input current for each rgb input to the lcd controller is only 1uA.
Do you think it would be wise to add a buffer transistor anyway?
I need to design a PCB because the 40-pin breakout board for the lcd flex is too big, so I could add a buffer circuit to that.

@evansm7
Copy link
Owner

evansm7 commented Jan 7, 2025

Hola,

As far as I can tell, the memory block that the Mac ROM is writing the frame buffer into is still using 512px rows even though I managed to modify the ROM to create a 480px wide screen image. I didn’t use a disassembler on the ROM, I just searched and replaced values in a hex editor.

it sounds like some of the code’s patched but not all of it; there are various “words per line” constants too. The code in umac/src/rom.c that is enabled when DISP_WIDTH/HEIGHT are nonstandard should already do all this (fb is then 480 wide).

What disassembler do you use?

I’m just going off of https://www.bigmessowires.com/rom-adapter/plus-rom-listing.asm (one of the reasons I’m sticking to the Mac Plus ROM).

So I’d like to build one with a larger screen as well. The 3.5” one you used looks a good option. How much was this on AliExpress? I found a few listings for what I think are the same panel but couldn’t see what controller it used.

Yeah AE is terrible … It was hard to find the controller. I got this one:

https://www.aliexpress.com/item/1005007347112636.html

I got 2 for about £20 inc shipping.

I’d like to include the screen brightness wheel and I’d like it to make the Macintosh startup chime when turned on. I know there’s no audio support in umac but I assume it would not be too complicated to play the sound through a small speaker as part of the picomac init sequence.

Speaker is the easy bit :) need to add emulation to umac, not terrible but something to do.

Regarding the video out line. I initially just used the blue msb, then the msb of each colour and once I had it working I gradually increased the number of lines linked to the video data line. I found I was able to drive all 16 rgb inputs linked together with no visible problems to the screen image and without the rp2040 getting hot. From what I could gather from the data sheet, the input current for each rgb input to the lcd controller is only 1uA. Do you think it would be wise to add a buffer transistor anyway? I need to design a PCB because the 40-pin breakout in board for the lcd flex is too big, so I could add a buffer circuit to that.

:) current isn’t too much of a worry, it’s more signal integrity with many loads (at 25MHz). It’d be more reliable considering variation in screens to use a (CMOS) buffer IMHO but if it works it works!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants