Agatsuma TV Tuner Technical Documentation 0.1
April 30th, 2024
Shonumi aka D.S. Baxter


***************************************************
1. Introduction
***************************************************

The Agatsuma TV Tuner (ATVT) is a cartridge for the Game Boy Advance that allowed users to watch analog broadcast TV. It was released exclusively in Japan on April 29, 2006. Created by Agatsuma Entertainment Inc., it was the only officially licensed TV tuner for the GBA. It also allows for composite A/V input.


***************************************************
2. General Hardware Information
***************************************************

- Comes in a very large, bulky, black cartridge (about the size of an original DS folded).
- Has an adjustable antenna on the upper left side that extends and rotates.
- Requires 6 AA batteries to work.
- Features dual-speakers on the front to bypass the GBA's audio system.
- Features a volume dial on the lower left side.
- Has a composite A/V input port on the lower right side.
- Has a 3.5mm headphone jack on the lower right side.
- Has a port on the back side for an external antenna connection.
- Comes with at least 256 bytes of flash memory to save configuration data.
- Only compatible with analog broadcasts (NTSC-J).
- Tunes into 62 channels.
- Capable of receiving signals from 55.25MHz to 801.25MHz.
- Uses a Philips FQ1236/P H-3 as the actual TV tuner.


***************************************************
3. I/O Registers
***************************************************

The ATVT has several memory-mapped registers that deal with TV operations as well as writing to its internal flash memory.

-----------------------------------------------------------
Address				| I/O Name
-----------------------------------------------------------
0x8000000			| TV_FLASH_INIT
0x8000AAA			| TV_FLASH_CMD0
0x8000554			| TV_FLASH_CMD1
0x8020000 - 0x80200FF		| TV_FLASH_DATA
0xA800000 - 0xA812BFF		| TV_FRAME_BUFFER
0xE000000			| TV_CNT_A
0xE000001			| TV_CNT_B
0xE000002			| TV_CNT_C
0xE000003			| TV_CNT_D
-----------------------------------------------------------

TV_FLASH_INIT deals specifically with two standard flash commands, 0x90 (Enter ID Mode) and 0xFF (Reset). All other flash commands have to write to TV_FLASH_CMD0 and TV_FLASH_CMD1. A small section of what is normally cartridge ROM is instead reserved for 256 bytes of flash memory.

The ATVT provides video as full 240x160 frames, in the form of a 15bpp bitmap image. The frame buffer is available to read directly.

4 separate control registers are used to issue TV-related commands. The bulk of the work falls on TV_CNT_A and TV_CNT_B. TV_CNT_C and TV_CNT_D have lesser roles; writing to these locations overwrites the values in their counterparts. That is to say, writing to TV_CNT_C overwrites TV_CNT_A, and writing to TV_CNT_D overwrites TV_CNT_B. This is often done to zero out and reset those registers (presumably without affecting something about their operations).


***************************************************
4. Data Transfer Protocol
***************************************************

In order to send commands or read data from commands, the CPU writes bytes serially to using TV_CNT_A or TV_CNT_B. The register used depends on which commands are being issued. Here, only Bit 0 and Bit 1 are used to clock the transfer and represent I/O data. 

-----------------------------------------------------------
Bit 0	| I/O Data
Bit 1	| Clock (0 = LOW, 1 = HIGH)
-----------------------------------------------------------

The ATVT uses the I2C protocol for data transfers, but the specifics of how it is implemented on the GBA are detailed in this section. Depending on the command, TV_CNT_A must have Bits 2, 6, and 7 set HIGH (essentially OR'ed 0xC4), while TV_CNT_B must have Bit 6 set HIGH (essentially OR'ed by 0x40). The high-level protocol for issuing commands looks something like this:

-----------------------------------------------------------
START SIGNAL

TRANSFER BYTE 
ACKNOWLEDGE SIGNAL

TRANSFER BYTE
ACKNOWLEDGE SIGNAL

...

READ BYTE (only used for some read commands)
ACKNOWLEDGE SIGNAL (only used for read commands)

STOP SIGNAL
-----------------------------------------------------------

The Start Signal involves setting the clock HIGH twice, while sending 1 then 0 as data:

-----------------------------------------------------------
Start Signal
-----------------------------------------------------------
1) Set Clock High and set I/O Data to 1
2) Set Clock High and set I/O Data to 0
-----------------------------------------------------------

The Start Signal always follows a Stop Signal, or is the first signal sent to the ATVT at all post-boot. After the Start Signal, individualy bytes can be transferred bit-by-bit. Bytes are sent MSB-first. Each bit requires 4 writes to TV_CNT_A or TV_CNT_B. The process is described below:

-----------------------------------------------------------
Transfer Bit
-----------------------------------------------------------
1) Set Clock LOW
2) Set I/O Data to transfer bit
3) Set Clock HIGH
4) Set Clock LOW
-----------------------------------------------------------

After repeating those steps 8 times, a full byte has been transferred to the ATVT. Once the transfer is complete, an Acknowledgement Signal must be sent as well. This signal consists of 4 writes to TV_CNT_A or TV_CNT_B as such:

-----------------------------------------------------------
Acknowledgement Signal
-----------------------------------------------------------
1) Set Clock LOW and set I/O Data to 0
2) Set I/O Data 1
3) Set Clock HIGH
4) Set Clock LOW and set I/O Data to 1
-----------------------------------------------------------

If there is more incoming data for a command, the process for transferring bytes begins immediately. However, if there is no more data, a Stop Signal must be sent:

-----------------------------------------------------------
Stop Signal
-----------------------------------------------------------
1) Set Clock LOW and set I/O Data to 0
2) Set Clock HIGH
3) Set Clock HIGH and set I/O Data to 1
-----------------------------------------------------------

Some commands return 8-bit data from the ATVT. After the last byte of the command has been transferred and acknowledged, this 8-bit data is read immediately (i.e., the read occurs before a Stop Signal). As with transferring bytes, reading bytes is done serially. The process for that is as follows:

-----------------------------------------------------------
Read Bit
-----------------------------------------------------------
1) Set Clock LOW and set I/O Data to 1
2) Set Clock HIGH
3) Read Bit 0 of TV_CNT_A or TV_CNT_B
-----------------------------------------------------------

This is done a total of 8 times until the byte is fully read out.


***************************************************
5. Commands
***************************************************

By writing certain bytes to the ATVT (using the protocol described above) the CPU can send several commands to the device. The first byte is the address frame. The last two bytes of a command are 16-bit parameters. As is typical of I2C, Bit 0 of the address frame determines whether the command will read or write values. In the case of read commands, no parameter bytes are used. A list of known commands is shown in the table below along with whether the command uses TV_CNT_A or TV_CNT_B:

----------------------------------------------------------------------------------------------------------------------
Command Name		| Address Frame		|Command Pattern	|Register
----------------------------------------------------------------------------------------------------------------------
Unknown Command		| 86 			| xx xx			| TV_CNT_B
Read Channel Status	| 87			|			| TV_CNT_B
Change Channel		| C0			| xx xx			| TV_CNT_B
Unknown Command		| D8			| 00			| TV_CNT_A
Switch to AV Input Mode	| D8			| 02 E0			| TV_CNT_A
Switch to TV Mode	| D8			| 02 E1			| TV_CNT_A
Set Video Contrast	| D8			| 10 xx			| TV_CNT_A
Set Video Brightness	| D8			| 11 xx			| TV_CNT_A
Unknown Command		| D8			| 14			| TV_CNT_A
Set Video Hue		| D8			| 15 xx			| TV_CNT_A
Unknown Command		| D8			| 1E xx			| TV_CNT_A
Clear Video Frame	| D8			| 0D 80			| TV_CNT_A
Render Video Frame	| D8			| 0D 00			| TV_CNT_A
Read Command Data	| D9			| 			| TV_CNT_A
----------------------------------------------------------------------------------------------------------------------


[[Command 86 xx xx - Unknown Command]]

This command appears related to changing the channel. It is called 3 times before reading the channel status or changing the channel frequency. The 16-bit parameters always follow this pattern:

-----------------------------------------------------------
Byte	1		| Byte 2
-----------------------------------------------------------
0x00			| 0x56
0x01			| 0x30
0x02			| 0x44
-----------------------------------------------------------





[[Command 87 - Read Channel Status]]

This command returns an 8-bit value representing the status of the current channel's reception. If the ATVT detects a valid TV signal, it will return the value 0xC0. Any other value seems to indicate that no proper reception was found for that channel, at least on the frequency assigned for it.





[[Command C0 xx xx - Change Channel]]

This command changes the current channel. This command is called twice. For the first call, its parameters form a 16-bit value that represents the channel's frequency in MHz. The lowest frequency possible is 55.25MHz and is representing by the hex value 0x0650. The highest possible frequency is 801.25MHz and is represented by the hex value 0x34F0. Essentially, increasing/decreasing the 16-bit value by 1 changes the frequency by 0.0625MHz.

For the second call, the 16-bit parameter uses 3 values depending on the channel frequency. If the frequency is between 55.25MHz and 159.9375MHz inclusive, the value is 0x8641. If the frequency is between 160MHz and 441.9375MHz inclusive, the value is 0x8642. If the frequency is greater than 442MHz, the value is 0x8644.

The Change Channel command is called when the user manually switches between saved channels, when scanning for available channels, and when manually tuning channels.




[[Command D8 00 - Unknown Command]]

This command is used right after the Render Video Frame command. It returns a single byte.





[[Command D8 02 E0 - Switch to AV Input Mode]]

This command is used to switch video input from TV signals to composite A/V input whenever the user presses the Select button.





[[Command D8 02 E1 - Switch to TV Mode]]

This command is used to switch video input from composite A/V input to TV signals whenever the user presses the Select button.





[[Command D8 10 xx - Set Video Contrast]]

This command sets the contrast of all video output. It accepts a single signed 8-bit value (2's complement), where the lowest value (-128) represents the minimum contrast and the highest value (127) represents the maximum contrast.





[[Command D8 11 xx - Set Video Brightness]]

This command sets the brightness of all video output. It accepts a single signed 8-bit value (2's complement), where the lowest value (-128) represents the minimum brightness and the highest value (127) represents the maximum brightness.





[[Command D8 14 - Unknown Command]]

This command is used after the Render Video Frame command and right after the command D8 00. It returns a single byte.





[[Command D8 15 xx - Set Video Hue]]

This command sets the hue of all video output. It accepts a single signed 8-bit value (2's complement), where the lowest value (-128) represents the minimum hue and the highest value (127) represents the maximum hue. Although this feature is labeled as hue by the ATVT itself, functionally it manipulates the saturation, with lower values skewing video more towards grayscale, but never completely so.





[[Command D8 1E xx - Unknown Command]]

This command is used right before the Render Video Frame and Clear Video Frame commands. It accepts an 8-bit parameter. The ATVT appears to set this to a constant value of either 0x06 when rendering a frame or 0x26 when clearing a frame.





[[Command D8 0D 80 - Clear Video Frame]]

This command appears to clear the internal video frame, or at least prepare the hardware to render the next video frame.





[[Command D8 0D 00 - Render Video Frame]]

This command renders any video frame from TV signals or the A/V input source. After issuing this command, 15bpp image data is available to read at the address range 0xA800000 - 0xA812BFF.





[[Command D9 - Read Command Data]]

This command reads a single byte that represents the result of several unidentified commands. Specifically, it is used in conjection with the D8 00 and D8 14 commands.


***************************************************
6. Flash Memory
***************************************************

The ATVT uses a very small amount of flash memory to store data such as brightness, contrast, and hue preferences, as well as a list of favorited channels and their frequencies. Below is a chart of known flash commands used by the ATVT:

-----------------------------------------------------------
0x80, 0x30	| Erase Sector
0x90		| Enter ID Mode
0xA0		| Write 16-bit Value
0xF0		| Terminate Command (force end of write)
0xFF		| Reset
-----------------------------------------------------------

To issue either the Enter ID Mode or Reset commands, the CPU writes directly to TV_FLASH_INIT. Although the ATVT supports grabbing the manufacturer ID, this value isn't used by the device, and the software doesn't bother even reading it. The other 2 flash commands, Erase Sector and Write Data work as follows:

-----------------------------------------------------------
Erase Sector
-----------------------------------------------------------
1) Write 0xAA to TV_FLASH_CMD0
2) Write 0x55 to TV_FLASH_CMD1
3) Write 0x80 to TV_FLASH_CMD0

4) Write 0xAA to TV_FLASH_CMD0
5) Write 0x55 to TV_FLASH_CMD1
6) Write 0x30 to TV_FLASH_DATA
-----------------------------------------------------------

Typically for a sector erase command, the sector number would be part of the address when writing 0x30 (e.g. flash memory working on 4KB sector would do use a format like 0x802-000 for the ATVT). However, since only a very small and limited amount of flash memory is available on the ATVT, the software is hardcoded to use only the first sector, thus it always defaults to 0x8020000. After erasing a sector, Terminate Command is called to make sure the write is finished. That command is executed by simply writing 0xF0 to TV_FLASH_CMD0.

-----------------------------------------------------------
Write 16-bit Value
-----------------------------------------------------------
1) Write 0xAA to TV_FLASH_CMD0
2) Write 0x55 to TV_FLASH_CMD1
3) Write 0xA0 to TV_FLASH_CMD0
4) Write MSB to TV_FLASH_DATA + INDEX
5) Write LSB to TV_FLASH_DATA + INDEX + 1
-----------------------------------------------------------

It should be noted that all I/O for the ATVT's flash memory is 16-bit, however, most registers only expect 8-bit values. Writing data is the only known area where all 16-bits are used. Like most flash memory, simply reading directly from the address range assigned to flash will pull its data. No special commands are necessary to read TV_FLASH_DATA.


***************************************************
7. Audio
***************************************************

Audio output appears to be handled by the ATVT itself. Given the complexities of trying to convert live over-the-air audio to GBA compatible samples, as well as the quality of the GBA audio system, Agatsuma likely chose to bypass that all and have the ATVT directly handle audio. It may have been a technologically simpler approach too. At any rate, there doesn't seem to be any audio handling code in the ATVT's ROM at all either.


***************************************************
8. AGB-P-ZTVJ
***************************************************

Prior to its release, news reports circa 2006 noted that the ATVT was to have a GBA game code of "AGB-P-ZTVJ". The "Z" would have indicated a special media cartridge in the same category of the GBA Jukebox and Play-Yan. Strangely enough, however, the ATVT itself has no external markings bearing this game code. Neither its box nor instruction pamplet have this information either. Generally the last 4 characters of the game code match data in the ROM header, but the ATVT uses "dtv0". Although the ATVT was marketed as a DS accessory, it is physically a GBA cartridge. Despite being officially licensed by Nintendo themselves, the ATVT appears somewhat anamalous in this regard compared to nearly every other GBA cartridge. The only similar case is the Campho Advance, which did not receive an official game code despite being licensed as well.