Views: 27,992,236 Homepage | Main | Rules/FAQ | Memberlist | Active users | Last posts | Calendar | Stats | Online users | Search 11-17-25 04:21 AM
Guest:

Main - Posts by kuratius


kuratius
Posted on 04-24-25 02:42 PM, in GBAtek addendum/errata (rev. 4 of 04-24-25 07:20 PM) Link | #7653
Posted by PoroCYon

Aptina MT9V113 internal MCU stuff


The Aptina cameras have an internal 68HC11-based MCU. Parts of its address space can be accessed through the XDMA registers (0x98c, 0x990, reachable over I2C)
There's a "physical" address range (0x0000..0x1fff) and a "virtual"/"logical" one (0x2000..0x3fff). The former can be used to access "system" and "user RAM" (resp. 0x0000..0x03ff and 0x0400..0x7ff), as well as "Special Function Registers" (SFRs), basically just MMIO regs of the HC11. The latter allows access to the variable spaces of several "firmwares"/"services" running on the MCU, used for autofocus, autowhitebalance, etc. Each camera has a separate HC11.

The above is already kinda known, but now for the new stuff. (Keep this section of GBATEK at hand while reading this, as I guess only a handful people ever looked at the cameras to begin with.)

(NOTE: as the HC11 is an 8/16-bit MCU, pointers etc. are 16-bit (its address space is 16 bits wide). Also, it's a big-endian architecture, keep that in mind.)

SFRs

  • 0x1040: watchdog reset: write 0 to this address to calm down the watchdog timer.
  • 0x1048: "high-precision timer": 32-bit timer value that probaly increases by 1 every 16 MHz tick.
  • 0x1050: "pagetable" pointer: pointer to a list of 16 addresses used to determine to which physical addresses the virtual ones will resolve.
  • 0x1060..0x1066: "ring bus access" or so, not too sure what this is, but it looks like it gives you some sort of DMA access. Sadly, I don't know which registers in this range are address ones, and which ones are used for data.
  • 0x1070: GPIO (already documented on GBATEK, didn't touch it myself.)

Address translation


As alluded to in the previous part, SFR 0x1050 is used to set the mapping. Its value is 0x0100, which means we can access and modify the "pagetable mapping" over I2C. (I'm using quotes here because it's far from anything like a real MMU.)

At 0x0100, a list of 16 pointes can be found: 0x0140 (MONITOR), 0x0000 (SEQ), 0x005d (AF), 0x0165 (AWB), 0x01d4 (FD), 0, 0, 0x282 (MODE), 0, 0, 0, 0x0220 (HG), and then more zeros.

This matches what you'll find when dumping the 0x2000..0x2fff area. While system RAM has space for 16 more pointers (starting at 0x0120) for addresses 0x3000..0x3fff, in practice these are mirrors of the 0x2*** range.

Setting a pagetable entry to an address of 0x2000 or higher seems to return 0 values, maybe there's a carveout, or maybe there's just nothing behind those addresses. Additionally, it does seem to mirror the upper half of memory (0x8000 and up) to the lower half, which is *quite* suspicious as a datasheet says there's 32 kilobytes of firmware ROM, and the exception vectors of the HC11 are at 0xfffe etc. (6502-style) So I'm betting the firmware ROM is in the upper half of MCU memory.

System RAM layout


With the above, we can start building a map of the system RAM space. As one datasheet (links at the end of this post) alludes to the stack of the HC11 firmware also being in system RAM and being 128 bytes in size, it's not too hard to guess where it is.
  • 0x000..0x047: SEQ
  • 0x05d..0x0c0: AF
  • 0x100..0x11f: page table
  • 0x120..0x13f: unused shadow pagetable? idk
  • 0x140..0x168: MONITOR
  • 0x165..0x1d2: AWB
  • 0x1d4..0x1f4: FD
  • 0x220..0x286: HG
  • 0x282..0x2ea: MODE (yes this overlaps with HG)
  • 0x300..0x37f: ??? (maybe stack but I doubt it)
  • 0x380..0x3ff: stack
The 0x380 region seems to be 0xdeadbeef (big-endian)-filled and grows from high addresses to low ones. Additionally, it's one of the RAM regions that seems to get reset regularly (see below). This gives me a relatively high conficence to say it is the stack of the HC11.

User RAM (0x0400 and on) doesn't seem to be writable, sadly. Or maybe I'm missing some kind of magic switch.

Running code on the HC11


A datasheet alludes to using the MONITOR variables to run code: arg1 is the pointer of the code to run, arg2 an optional argument (where is this put in? the accumulators?), and then set cmd to 0x01 to start the code.

Sadly, this did not work for me: it resets the MCU, while doing not much else. Maybe it needs some kind of CRC (which the datasheet also alludes to), or maybe the feature is just locked away. (EDIT: maybe the resetting thing would be added to have the XDMA thing avoid messing with internal state. But does using the virtual addressing mode bypass it? Would chaining using another peripheral (the "ring bus access" maybe?) be able to be used as a bypass? I haven't tested.)

Then I tried putting some shellcode in low system RAM and filling the stack with bad addresses (that is at the same time a NOP sled). Sadly this didn't work either, as the MCU also got reset before it got to execute my code. Maybe I'm triggering some kind of (bad) crash, or maybe there's a safety mechanism that automatically resets everything. (I hope it's not the latter.)

(MCU resets seem to clear/reset the pagetable, stack (0x0380 and up), and some of the "logical variable" spaces in system RAM. 0x300..0x37f seems to be preserved, as well as some other small places in low system RAM.)

Maybe this is a fun challenge for someone else here? :P

P.S. I used Pk11's dsi-camera proof-of-concept as a base to mess with the cameras. Not really publishing my code because it's mostly just a spaghetti of I2C accesses and FIFO ugliness. I used vasm as HC11 assembler, though be aware that it gets some opcodes wrong, check with A09 (which doesn't seem to be able to process "org" directives) and this and this opcode listing I found. For more info on the HC11, see this (original DIP CPU info) and this (more modern microcontroller impl, only gave it a cursory glance, idk how useful it is outside of the instruction set info).

Datasheets

Also a neat link: https://files.niemo.de/aptina_pdfs/



Some additions to this:
The MCU getting reset might be due the homebrew driver you used as a base sending a reset command every frame.
The 1ADC, 2ADC referred to on some row speed settings on gbatek refers to low power mode in the readmode setting. 1ADC is low power mode.
The pixel output clock can be calculated as
16.76 MHz *M/(N+1)/8/2

And correspondingly the frame rate should be pixel clock/(frame_length_lines*line_length_pck).
There's another way to calculate it based on coarse and fine integration time
integration_fps=pixel_clock/(coarse_int_time*line_length_pck+fine_int_time);
Usually this this is more accurate for the actual camera FPS with auto exposure if you read out the current values in the registers.


Here's some logs of the I2Cs Comms in FaceTraining's DSi version in melonDS if you force the arm7 to jump to the function that changes frame rate. Preset12 and above appear to be invalid; it does a bounds check on the contents of R1 if you jump to the function.
The function is at address 037dec10
and expects R0 to contain some sort of camera model id, I recommend just setting all the bits to 1, and R1 to contain the number of the preset.
FrameRatePresetRegisterWrites.zip


Main - Posts by kuratius

Page rendered in 0.054 seconds. (2048KB of memory used)
MySQL - queries: 22, rows: 67/67, time: 0.019 seconds.
[powered by Acmlm] Acmlmboard 2.064 (2018-07-20)
© 2005-2008 Acmlm, Xkeeper, blackhole89 et al.