DPF with AppoTech AX206

From ST2205u wiki
Jump to: navigation, search



If you want to get into development on these DPFs, or use them as a remote screen: there is a SVN source repository with experimental code and various tools at [1]. An alternative firmware is available from the same site. Also, this site [2] publishes the entire original firmware and hardware reference manual of the AX206.

  • The latest list of supported/WIP devices for dpf-ax can be found at [3]
  • You can check if your frame is supported with identify.py from [4].

To distinguish from the AX203 types, the rule of thumb (if you are not able to get hold of the USB IDs, shown below) is:

  • AX206 based frames are listed with 16 mbit or 32 mbit flash, capable of taking ~107 pictures or more
  • Those with 8 mbit and ~130 pictures could be likely AX203

-- Actually, it was found the above is not really true, because many sellers specify wrong flash sizes, and the image capacity varies with the firmware versions. If you get a newer model, it is likely that it has an AX206 or even AX208.

Note that DX and sellers on Ebay write MB (insinuating MegaByte) but in fact it's Megabit. So you have to divide by eight for available MegaBytes.

Supported Devices (Aug 2012)

  • For a recent list see [5]
  • abeyerr_black
  • acme_1
  • agk_violet
  • avlabs_avl969s
  • delightdigi_black
  • coby_dp151_bw - see Coby_DP-151 for comparison of different dp151 varieties
  • coby_dp151_white - see Coby_DP-151 for comparison of different dp151 varieties
  • focalprice144
  • linkdelight

Devices from DealExtreme - Actual chipsets may vary

  • dx21334a
  • dx21334b
  • dx27893 (white)
  • dx27893_2 (white)
  • dx27894 (blue)
  • dx104500
  • dx104838


  • MPlayer: A patch for AX206 frames against MPlayer 2012-05-5 via libdpf[6] is available:[7]
  • st2205term v0.11 now supports ax206: [8]
  • An experimental framebuffer driver is forked from [9], patches for ax206fb and playusb: [10] and [11]
  • pydpf, a Python digital picture frame application, see this:[12]
  • GraphLCD is a project to support graphical LC displays connected to the PC. It is mainly used by the graphlcd plugin for the Video Disc Recorder to display its information. An experimental driver for ax206 is available at: [13]
  • gPhoto2 has support for ax206 since version 2.4.10, download files here[14]
  • setpic-like program called dpfsend for AX206 written by mrlinux (send still images to dpf-ax frames and supports png, jpg and gif formats): http://forum.doozan.com/read.php?9,10541

Hacking Details

  • Full Log of the process of hacking a supported ax206 frame:
python fw/fulldump.py /dev/sr1
Opening generic SCSI device '/dev/sr1'
Manufacturer: Winbond
Size        : 1 MB
Reading 100000 bytes...
Wrote full.bin

python fw/identify.py full.bin 
Looking for buildwin firmware....: Found (320x240 px).
Looking for known version info...: None.
Looking for Openwin..............:
OpenWin        at 0x1280 (0x000682), len 0x74, CRC = 0x174c10b9
Written to openwin_tmp.bin.
Looking for LcdIniTbl............:
Module 37:
LcdInit (Tbl)   at 0x14be (0x04818e)
Module 53:
LcdScheduleTbl  at 0x14c9 (0x0496ff), len 0x00
LcdContrastTbl  at 0x14ca (0x049700), len 0x09
LcdContrastTb2  at 0x14d4 (0x04970a), len 0x0b
LcdBacklightTbl at 0x14e0 (0x049716), len 0x16
LcdIniTbl       at 0x14f9 (0x04972f), len 0xb6, CRC = 0xfbed1394
Written to lcdinitbl_tmp.txt.
Looking for known signatures.....:

Your dpf seems to be compatible with model focal.

Detaching dpf at 4- done.

python fw/restore.py src/fw_focal.bin -f
Found AX206 DPF (bootloader)
Manufacturer: Winbond
Size        : 1 MB
Erase full flash...
Flashing sector 0...
Flashing sector 1...
Executing applet..

Reverse Engineering an unsupported device

This was prepared with notes from [15] and [16]

1. Prepare lcdinit.s with the values from _custom_initseq entries in lcdinitbl_tmp.txt. Look at the src/lcd folder for examples of lcdinit.s for existing supported lcds.
2. Disassemble openwin_tmp.bin. Obtain d52 (8052 Disassembler) from here[17] and do this

d52 -p -b -n openwin_tmp.bin x1280

3. You will get openwin_tmp.d52. Do some cleanup (identify the blit-coordinates, etc.). That's the one to go into lcdblit.s. Following file may help by identifying some often used vars. Create a file named "openwin_tmp.ctl":

; Common stuff for compiling this for 0.2 up with sdcc
; Routines in ROM:

; Writes a byte to the LCD port p3
l 0f25 otp_lcd_write

; Registers
r 00 ar0

; I/O mappings:
k 94 LCD_A0

; The following registers denote the LCD controller context area
; See lcd_setcontext()

; Converted to 0.2 vars
; most dpfs need this mapping..
r 77 _g_blit+x0         ;G_lcd_cxL
r 78 _g_blit+x0+1       ;G_lcd_cxH
r 79 _g_blit+y0         ;G_lcd_cyL
r 7a _g_blit+y0+1       ;G_lcd_cyH
r 7b _g_blit+x1         ;G_lcd_dxL
r 7c _g_blit+x1+1       ;G_lcd_dxH
r 7d _g_blit+y1         ;G_lcd_dyL
r 7e _g_blit+y1+1       ;G_lcd_dyH
; .. some need that mapping
;r 78 _g_blit+x0         ;G_lcd_cxL
;r 79 _g_blit+x0+1       ;G_lcd_cxH
;r 7a _g_blit+y0         ;G_lcd_cyL
;r 7b _g_blit+y0+1       ;G_lcd_cyH
;r 7c _g_blit+x1         ;G_lcd_dxL
;r 7d _g_blit+x1+1       ;G_lcd_dxH
;r 7e _g_blit+y1         ;G_lcd_dyL
;r 7f _g_blit+y1+1       ;G_lcd_dyH

3. Run d52 again.

This method works only for "standard" buildwin builds (luckily most builds are), not for the ones that do their initialization by LcdInit instead LcdInitTbl (see focalprice144) or do anything special.

If it works, add a record to fw/knowndps.py (use the CRCs you got from identify.py) and submit changes at dpf-ax/Tracker/Patches at [18]

Reverse Engineering the firmware

This file[19] is extracted from [20]. You can then disassemble the firmware backup from fulldump.py[21] or ProgSPI[22]. A README is included in the download which gives the instructions on how to use the tool. BIG FAT WARNING: You have to be able to read 8051 assembly code and you HAVE TO know what it is doing.

Backlight Details

This was figured out by superelchi.

"Older" lcds (like the ones in pearl, focal, etc.) use a pwm-signal to control the backlight brightness. Here only the ratio between on and off time of the signal matters, frequency does not (more or less). "Newer" lcds (like the ones in dx21334a/b or newer linkdelight dpfs) control backlight brightness by the frequency of the signal. If the signal frequency is outside the range the lcd needs, backlight will stay off.

Implementing this was a bit tricky, because hackfin uses the RTC (32,768 kHz) to generate the pwm signal. The needed frequency for the "newer" lcds is much higher, so superelchi had to switch to sys-clock as signal source. Sys-clock has a base frequency of 24 MHz but can be doubled to 48 Mhz - what we do to speed things up a bit. If USB is disconnected (and the dpf runs on battery) the clock is reduced to 12 MHz to save power. The frequency tables extracted from the buildwin fw are based on 24 MHz, so frequency- and pwm-values have to be adjusted to the real sys-clock and recalculated on USB connect/disconnect. Thats why you can see a brief flicker if brightness is changed or USB is connected/disconnected. Also (because of rounding errors) there is a slight brightness difference between connected and disconnected USB. This flicker and brightness difference is not visible with the original buildwin fw - reason is unknown.

Software Details

  • Comes loaded with DPFMate as per the AppoTech, but software version is v5.0.2.1. A copy of the software can be found here
  • Screenshot of the DPFMate Software "About..." dialog box
  • Dump of StartInfoUnicode.ini:
Titlename=DPFMate v5.0.2.1
CopyRightTips=Copyright (C) 2007 AppoTech Corporation

Hardware Details

  • Photos of the circuitry are here, here and here.
  • Following the StartInfoUnicode.ini file, if the information in the file is correct, the flash chip's datasheet should be this
  • It seems to be using the AX 206 chip. Datasheets here and information here.
  • I have two keychains, because the first unit had a "quirk" - unit only powers on 4 or 5 times after being charged. Not sure if this problem is related to the number of times turned on, or after 5 to 10 minutes of it being turned off (or even on). However, I suspect a full battery discharge would allow me to charge the unit up, making it usable again.

Firmware and Processor Details

The firmware basically knows several operation modes:

  • Boot Loader (hold MENU button while pushing the RESET button). The device will then register as HID device and create a /dev/hidraw0 device under Linux. Technical details of this mode came from:[24]

When the DPF goes into Bootloader mode (showing USB ID 1908:3318), it expects max. 64 byte size USB interrupt messages with a header and payload data. The header implements a simple Remote Procedure Call format through the bootload handler. Its format is as follows:

typedef struct {
	unsigned char len;
	unsigned char chk;
	unsigned char jmp[2];
	union {
		// Structures for various backends
		// The default memory loader:
		struct {
			unsigned char offset[2];
			unsigned char buf[BUFSIZE];
		} loader;
		struct {
			unsigned char opcode;
			unsigned char n;
			unsigned char buf[16];
		} spi;
	} u;
} UsbMsg;


The ‘len’ byte specifies the full length of the USB packet. ‘chk’ is a checksum that is consecutively updated with every packet sent. The ‘jmp’ field contains the jump address of the handler that takes care of the attached data payload. For simple memory writing, the address of the internal ROM memory write routine is used. Once a program (for example flashing routines) is loaded into memory, it can be jumped into using this RPC scheme.

  • Standard photo frame mode: The unit will display images and not register as USB device when plugged in
  • USB operation, triggered via the menu entry: The device will register as CDROM with the USB details provided below. The flash access occurs via the SCSI generic device by specific vendor commands 0xCA, 0xCB and 0xCD. This is covered in various code fragments, see Talk:DPF_with_AppoTech_AX206

Memory map

The AX206 has internal SRAM where code from external memory is loaded to. The internal SRAM bank is mapped to external memory as well as code memory, so it is internally mirrored.

XDATA (movx)             CODE (movc)
0x0000-0x00ff            0x1a00-0x1aff    USB FIFO
0x0200-0x02ff            0x1b00-0x1bff    DATA memory (8 bit addressable)
0x0800-0x11ff            0x1000-0x19ff    CODE/DATA memory

                         0x0000-0x0fff    Mask ROM

IRQ handlers             0x1003

Apparently, a part of the USB FIFO area can be used as data memory as well, since only 144 bytes are used (2*64 + 2*8 for USB EP0 and EP1).

Firmware internals

When in standard mode, the device is booting from the SPI flash. The 'boot sector' consists of a data block with some boot information plus a jump table (see more below) and the boot code.

The loading of the code from SPI flash occurs via XDATA, but the loaded code is actually located at instruction SRAM (CODE) with offset +0x800.

Here are the most important offsets and record lengths. BE stands for Big Endian, LE for Little Endian order.

0x00[2] (BE): Code destination in XMEM
0x02[2] (BE): Code position in IMEM
0x05[3] (BE): Start of code in Flash, normally 0x220
0x23[2] (LE): Screen resolution X
0x25[2] (LE): Screen resolution Y
0x80[8]     : Magic ID 'ProcTbl1' or similar
0x88[..]    : Module procedure jump table

The jump table ends with the magic '-EndTbl-'

The boot code loads a few common code modules from SPI flash. These are merely three code segments at the following (CODE) addresses:

0x1003: IRQ handler
0x1280: common LCD addressing routine
0x1934: common dynamic module loader (see below)

Please speak up if the addresses vary on your DPF.

Other code segments are dynamically loaded by some modules, depending on the operation mode of the DPF.

Jump Table

Since the AX206 has only 3k of internal SRAM which is obviously used by the USB FIFO and JPEG quantization tables, mechanisms are implemented to dynamically load code modules from SPI. The jump table entries are descriptors of length 8 for each module and decode as follows:

0x00[2] (BE) : Destination load START address in XMEM
0x02[2] (BE) : Destination load END address in XMEM
0x04[3] (LE) : Source offset in flash
0x07[1]      : Fill byte, unused.

Jumps to those modules within the coded are implemented using trampoline functions. For example, when a function from another module is called, the code sequence looks like:

	mov	a,#bank_no             ; module index in table
	mov	dptr,#target_function  ; Address of function in module
	ljmp	tramp_jmp              ; Jump into dynamic loader trampoline

The number of modules varies depending on DPF model and firmware version.

Code download

Code downloading is supported with the tools from the dpf-ax distribution. The necessary patches to get lcd4linux running are included in the distribution tar files found at [25]. They might be updated regularly, therefore please check the up to date .tgz files from the link above.

When you modify the code:

It's easy to brick your frame by overwriting the original firmware. This used to be a problem. However, the ProgSPI from [26] restores the original flash content - if you saved it! Therefore, before messing around, make a dump of the flash. Another alternative is restore.py from [27] to backup or flash the firmware.

USB Details

  • lsusb log:
Bus 005 Device 002: ID 1908:0102  
Device Descriptor:
  bLength                18
  bDescriptorType         1
  bcdUSB               1.10
  bDeviceClass            0 (Defined at Interface level)
  bDeviceSubClass         0 
  bDeviceProtocol         0 
  bMaxPacketSize0         8
  idVendor           0x1908 
  idProduct          0x0102 
  bcdDevice            2.00
  iManufacturer           2 BUILDWIN
  iProduct                3 Digital Photo Frame
  iSerial                 1 200807101900000000
  bNumConfigurations      1
  Configuration Descriptor:
    bLength                 9
    bDescriptorType         2
    wTotalLength           32
    bNumInterfaces          1
    bConfigurationValue     1
    iConfiguration          0 
    bmAttributes         0x80
      (Bus Powered)
    MaxPower              200mA
    Interface Descriptor:
      bLength                 9
      bDescriptorType         4
      bInterfaceNumber        0
      bAlternateSetting       0
      bNumEndpoints           2
      bInterfaceClass         8 Mass Storage
      bInterfaceSubClass      6 SCSI
      bInterfaceProtocol     80 Bulk (Zip)
      iInterface              4 DPF Mate
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x81  EP 1 IN
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
      Endpoint Descriptor:
        bLength                 7
        bDescriptorType         5
        bEndpointAddress     0x01  EP 1 OUT
        bmAttributes            2
          Transfer Type            Bulk
          Synch Type               None
          Usage Type               Data
        wMaxPacketSize     0x0040  1x 64 bytes
        bInterval               0
Device Status:     0x0000
  (Bus Powered)
  • dmesg log:
usb 5-1: new full speed USB device using uhci_hcd and address 2
usb 5-1: New USB device found, idVendor=1908, idProduct=0102
usb 5-1: New USB device strings: Mfr=2, Product=3, SerialNumber=1
usb 5-1: Product: Digital Photo Frame
usb 5-1: Manufacturer: BUILDWIN
usb 5-1: SerialNumber: 200807101900000000
usb 5-1: configuration #1 chosen from 1 choice
Initializing USB Mass Storage driver...
scsi5 : SCSI emulation for USB Mass Storage devices
usbcore: registered new interface driver usb-storage
USB Mass Storage support registered.
usb-storage: device found at 2
usb-storage: waiting for device to settle before scanning
usb-storage: device scan complete
scsi 5:0:0:0: CD-ROM            buildwin  Photo Frame     1.01 PQ: 0 ANSI: 2
sr1: scsi3-mmc drive: 40x/40x writer cd/rw xa/form2 cdda tray
sr 5:0:0:0: Attached scsi CD-ROM sr1
sr 5:0:0:0: Attached scsi generic sg2 type 5
ISO 9660 Extensions: Microsoft Joliet Level 3
usb 5-1: reset full speed USB device using uhci_hcd and address 2
Personal tools