Magic Lantern Forum

Developing Magic Lantern => Reverse Engineering => Topic started by: a1ex on June 24, 2018, 04:46:30 PM

Title: Low-level image capture
Post by: a1ex on June 24, 2018, 04:46:30 PM
Goal: capture raw images (both photo and LiveView) without executing any of the image processing paths. Just get the raw data.

Why? To understand how it works and to have fewer variables for experimenting with crop modes, high frame rates, readout settings etc.

Idea: log all MMIO activity and replay only what's done from the Evf task and associated interrupts.

Current status: able to get periodic HEAD timer interrupts!

Log: 5D3-mv1080p25.log (https://a1ex.magiclantern.fm/bleeding-edge/capture/5D3-mv1080p25.log)

Rough overview:
- image capture is controlled from the main CPU (maybe with the help of Eeko; I hope it's not the case)
- all the interactions between the CPU and its peripherals are done via MMIO and interrupts (lowest level)
- high-level interactions are done via ADTG, CMOS and ENGIO registers; on top of ENGIO we've got EDMAC, image processing modules etc
- Canon's image capture code is too complex to understand what it does, but we can trace its actions (messages, functions called, MMIO activity)
- stuff is happening in Canon's EvfState (https://a1ex.bitbucket.io/ML/states/60D-alt/sm10.htm) (look for state transitions in the log file)

Step by step:

1) evfInit: runs at startup, no interesting MMIO activity

2) evfActive: this starts LiveView, creates resource locks 0x50000 (STARTUP), 0x40000 (HEAD) and 0x250000 (CARTRIDGE) and powers on the image capture device:

- before using a hardware device in an embedded system, we usually have to enable some clocks; best guess:

    MEM(0xC0400008) |= 0x400000;
    MEM(0xC0202000) = 0xD3;
    MEM(0xC0243800) = 0x40;


- then we may have to power it on (SDRV_PowerOnDevice, InitializePcfgPort):

    EngDrvOut(0xC0F01008, 0x1);
    register_interrupt("IMGPOWDET", 0x52, imgpowdet_cbr, 0);
    MEM(0xC0400028) = 0x100;

    /* InitializePcfgPort */
    EngDrvOut(0xC0F18000, 0x2);
    EngDrvOut(0xC0F1800C, 0x7C7F00);
    EngDrvOut(0xC0F01010, 0x200000);

    /* probably some GPIO */
    MEM(0xC0220020) = 0x46;

    /* IMGPOWDET interrupt triggers shortly after this */

    /* these seem to be related, not sure what they do */
    msleep(10);
    MEM(0xC0220024) = 0x46;
    msleep(10);


At this point you'll get an IMGPOWDET interrupt, showing that some image capture stuff was successfully powered on.

3) evfStart: bunch of initializations, including FPS timers, raw capture resolution, ADTG, CMOS; enables HEAD1 timer

4) when HEAD1 fires -> evfPrepareChangeVdInterrupt[FrameNo:0]; runs RamClear (guess: zeroing out the image buffer); enables HEAD3

5) when HEAD3 fires -> evfChangeHdInterrupt: stops RamClear, SetLvTgNextState(0x2) (lots of ADTG and CMOS regs)

6) when HEAD1 fires again -> evfChangeVdInterrupt: re-programs HEAD3

7) when HEAD3 fires again -> evfChangeHdInterrupt: SetLvTgNextState(0x4) -> PowerSaveTiming, SetReadOutTiming, SetLiveViewHeadFor1stSR, enables HEAD2, SensorDriveModeChangeCompleteCBR

8 ) evfModeChangeComplete (happens right after the above)

9) when HEAD2 fires -> evfPrepareCaptureVdInterrupt[FrameNo:1], LVx1_SetPreproPath, first raw frame should be available?

To be continued. Unable to get an image yet.