Screen detector

From S1MP3 Wiki
Jump to: navigation, search

This is a program written by Kidscraker. Source code is to be found and posted here.

Beginners guide (windows)

  1. Get the latest s1giveio from
  2. Plug in your player, then get it into firmware upgrade mode (it's in the system menu)
  3. The operating system should ask for a driver. you should install the one in the s1giveio folder
  4. Try to run s1giveio. If you get to the prompt, then everything is ok
  5. Get z88dk from , and install it
  6. svn checkout svn:// ,or get it from
  7. Compile LCD_Detect routines from /trunk/LCD_Detect
  8. Run it, if it works, then it will probably display the display port/pin on the screen (i'm not sure, it never worked for me)
    The lcd detect binary needs to be loaded to , and run from offset 0x3400<


  • LCD detect needs to be able to read from the screen. if it is not possible to read from the screen, then it won't work, you will have to test every potential port/pin by hand
  • you can use the commands in the datasheets, to try your lcd screen. you can get the potential LCD ports/pins list from LCD_Detect program.
  • Beware , if you want to find your screen by hand, then you have to select the ce3 line.
  • When finding your lcd, you don't have to initialize it, it's already initialized by the firmware.
  • when useing s1giveio all the numbers you enter are in hexa.


If you found the display port/pin, then you can go ahead and try the kernel. (in /trunk/Swan Alpha)

  1. change the display port/pin in the lcd driver source file
  2. compile and test with s1giveio
  3. if it doesn't work, then try to remove the lcd init code from the lcd source, and recompile.
  4. The kernel needs to be loaded to , and run from offset 0!

How does the program works

I looked in to the programming method for LCD displays, and learned they have two modes: data mode, where you write the raw data to the screen, and command mode, where you do things like position the cursor. The mode is controlled by a GPIO line which must be turned on or off. Since we know that manufacturers like to rewire the GPIO different in every player, I guessed that this was the cause of the problem.

The first thing i found while playing around is that writing to any address 0x8000-0xFFFF ends up at the LCD data input. So it looks like the ATJ's CE3 line (also known as "LCD enable" in some docs) is wired directly to the internal address bus highest bit.

So I disassembled every file in my player's firmware ( for i in `ls`; do echo $i; z80dasm $i > $i.asm; done) and looked for writes (ld) to any address above 0x8000 (inclusive.) (Using grep, of course.) Obviously there were a lot. From looking at the examples I noticed that 0x8000 and 0x8001 is normally used for accessing the LCD, so I narrowed the search to these addresses. Only a few firmware modules actually had these addresses, most notable the files UI_xxxx.DRV.

I looked more closely at the UI_L0724.DRV disassembly (L=latin?), and found this:

    push   bc              ; 000805 C5
    in     a,($f4)         ; 000806 DB F4
    and    $fb             ; 000808 E6 FB
    out    ($f4),a         ; 00080A D3 F4
    ld     a,c             ; 00080C 79
    ld     ($8000),a       ; 00080D 32 00 80
    pop    bc              ; 000810 C1
    ret                    ; 000811 C9

    in     a,($f4)         ; 000812 DB F4
    or     $04             ; 000814 F6 04
    out    ($f4),a         ; 000816 D3 F4
    ld     a,(hl)          ; 000818 7E
    ld     ($8001),a       ; 000819 32 01 80
    inc    hl              ; 00081C 23
    djnz   $0818           ; 00081D 10 F9
    ret                    ; 00081F C9

These are clearly subroutines!

The first subroutine turns off a GPIO line, and the second turns one on... just what we are looking for. Also, they both write to the LCD. The second one writes the data from (hl) to (hl+b) so it looks like a routine to copy graphics to the LCD. The first one only ever writes one byte, so it looks like it's passing a command. It seems like a convention to use 0x8000 when sending a command, and 0x8001 when sending data, although these addresses are interchangeable.

After googling for 8080 lcd programming commands for a while, I found this PDF with some LCD commands:

Sure enough, once I had the correct port and bit, these commands worked on my display, at least the simple ones did.

BTW the display I was using is not actually LCD, but mono OLED. I'm 99% certain all display types will use exactly the same commands - although the pixels will be packed differently on colour displays - you will still see something, even if it looks like garbage...

--Ali1234 (from the mail list)

Useful Documents