Jump to content
IGNORED

Vorticon's Blog - Image Capture on the TI 99/4A Computer


RSS Bot

Recommended Posts

This not a new project which was initially started in 2015, but it was never well documented and I was not very happy with the end result at that time. I picked it up again last month and made significant improvements with some guidance from Tursi, so here it is.

Image capture has not been attempted previously on the TI 99/4A computer even though most other contemporary computers did have such a facility developed for them. While I realize that nowadays it's not really necessary since one could snap any picture with a digital camera, process it using Tursi's Convert9918 program (http://www.harmlesslion.com/cgi-bin/onesoft.cgi?2) and transfer it to the computer, there is still something special about doing this directly on the TI.

The first challenge was figuring out which capture camera to use, with the major requirement being ease of interfacing and good documentation as well as low cost, and I ended up settling on the Raspberry Pi camera. It has a large amount of support available online and is very easy to work with. Of course this entailed using a Raspberry Pi SBC as well, but I already had a couple of spare ones, namely model B, lying around, and they are dirt cheap anyway.



A standard bitmap image on the TI has a resolution of 256x192 pixels, or a total of just over 49,000 pixels. With that many data points to transmit to the TI, I opted to use the TI's parallel port (PIO) for ease of access and processing. One of the issues encountered at this point was the fact that the Raspberry Pi does not have a parallel port, so the solution was to simulate one by commissioning 8 GPIO pins on the board to act as a bidirectional 8-bit parallel port via software. Another issue related to the fact that the Raspberry Pi operates at 3.3V whereas the TI operates at 5V, therefore requiring the use of an interface between the two in order to convert the voltages back and forth and avoid frying the Raspberry Pi. The interface also allowed the gating of information to and from the TI.
Here's the schematic:



The idea here is that the Rpi camera will capture a raw RGB image at a resolution of 256x192 pixels, which produces 3 bytes of information per pixel, one for each red, green and blue colors. Obviously that's a massive amount of information, and so I had the Rpi compress the three bytes into one, taking advantage of the fact that the blue color is poorly perceived by the human eye. In the final scheme, one byte per pixel was produced, with 3 bits for red, 3 bits for green and 2 bits for blue, which was then transmitted to the TI one byte at a time.

Here's the initial breadboarded prototype:



I experienced a significant amount of noise with that prototype, likely related to the mass of wires required, but I was confident that the design was sound, so I bit the bullet and decided to create a double sided PCB for the project. This was the first time I had attempted to create a double sided PCB, and the end result was barely satisfactory, although is did require a lot of nursing to correct for missed vias and broken traces.


Top


Bottom


Populated

The general protocol for data transmission from the Raspberry Pi to the TI was as follows:

-Both handshake output lines start LOW
-TI polls the RPI handshake line, waiting for HIGH
-RPI sets the data port pins with valid data
-RPI then sets its handshake output HIGH to indicate data is available on the port
-RPI then polls the TI's handshake output, waiting for HIGH
-When TI see the RPI handshake high, it reads the data byte from the data pins
-TI then sets its output HIGH as an acknowledge
-TI then polls the RPI handshake line, waiting for LOW
-RPI sees the TI pin go HIGH, and releases its handshake (sets it LOW). RPI is now free to go process the next byte
-TI see the RPI line go LOW, and sets it's handshake LOW. TI is now free to process the byte.
-This process resumes at the top.


Here's the python code on the Raspberry Pi end:

Spoiler
:		if b[i] == '0':			GPIO.output(data_ports[i], GPIO.LOW)		else:			GPIO.output(data_ports[i], GPIO.HIGH)# Read the command code sent from the TI to the GPIO data linesdef read_command():	for i in range(:		GPIO.setup(data_ports[i], GPIO.IN)	byte_value = ''	global command	for i in range(:		if GPIO.input(data_ports[i]) == True:			byte_value = byte_value + '1'		else:			byte_value = byte_value + '0'	command = int(byte_value,2)	for i in range(:		GPIO.setup(data_ports[i], GPIO.OUT)# Main program looptry:    while True:	control_out()        # Wait for SPAREOUT line to go high        # Command code present on the data lines	GPIO.wait_for_edge(24, GPIO.RISING)	data_in()	read_command()	# Disable interrupt	GPIO.remove_event_detect(24)	GPIO.setup(24, GPIO.IN)	if command == 1:        # Command code 1: capture still image		# Capture one image frame		with picamera.PiCamera() as camera:			camera.resolution = (256, 192)			camera.start_preview()			camera.iso = 100			time.sleep(2)			camera.capture('image.data', 'rgb')		picture = open('image.data', 'rb')			# Acknowledge command receipt		HSK_pulse()	                # Send image byte by byte over the data lines		picture.seek(0)		byte_counter = 0		data_out()		print('Sending image data')		while True:			# Set up data lines with next byte			# Prepare byte from file			color_count = 1			# pack RGB values			while color_count < 4:				raw_byte = picture.read(1)				byte_value = struct.unpack('<B',raw_byte)				if color_count == 1:					R = (int(byte_value[0]) >> 5) & 7				else:					if color_count == 2:						G = (int(byte_value[0]) >> 5) & 7					else:						B = (int(byte_value[0]) >> 6) & 3				color_count += 1			R = R << 5			G = G << 2			comp_byte = 0			comp_byte = R | G | B				byte = bin(comp_byte)[2:].zfill(					send_byte(byte)			byte_counter += 1			# Signal the TI that a byte is available on the data line and wait for acknowledgement			HSK_high()			while GPIO.input(23) == False:				pass			HSK_low()			if byte_counter == 49152:				print('Image transfer done!')				break			# Wait for the TI to finish processing the byte			while GPIO.input(23) == True:				pass		picture.close()	GPIO.cleanup()	GPIO.setup(24, GPIO.IN, pull_up_down = GPIO.PUD_DOWN)	GPIO.setup(25, GPIO.OUT)	GPIO.setup(23, GPIO.IN)	GPIO.setup(8, GPIO.OUT)	GPIO.setup(7, GPIO.OUT)	GPIO.setup(11, GPIO.OUT)except KeyboardInterrupt:	picture.close()	GPIO.cleanup() 


On the TI side, I initially used an extremely primitive method of processing the image where I averaged the values of the RGB colors for each row of 8 pixels after decompressing the received bytes and chose the closest color from the TI's palette to assign to that entire row. If you recall, the TI can only assign a single foreground and a single background color to each row of 8 pixels due to the limitations of the 9918 video display processor. For black and white, I used the same method of RGB averaging, but then selected a threshold between white and black that gave the best image. Needless to say that the results were less than stellar...





And this was where things stood for the next 3 years, until I decided recently to revisit the project. I contacted Tursi regarding the algorithms he used for his Convert9918 PC program, and he was kind enough to give me all the information needed for me to revamp the image processing program on the TI. I decided to skip color processing at this time given that it would have been very intensive from a processing and memory standpoint and would make for a very long image display time, although I might re-visit this at some point in the future.


Black and white


Half-tone

Obviously a major improvement! The whole image transfer process takes about 45 seconds, which is pretty reasonable.

Here's a video of the entire project. Another fun one :)

Attached thumbnail(s)
  • blogentry-25753-0-24382400-1542825627_th
  • blogentry-25753-0-13877900-1542826296_th
  • blogentry-25753-0-55075000-1542826545_th
  • blogentry-25753-0-20884000-1542826727_th
  • blogentry-25753-0-32933200-1542826733_th
  • blogentry-25753-0-17080800-1542826795_th
  • blogentry-25753-0-53207200-1542827466_th
  • blogentry-25753-0-95101700-1542827473_th
  • blogentry-25753-0-00853900-1542827922_th
  • blogentry-25753-0-13248200-1542828018_th
  • blogentry-25753-0-24552800-1542828261_th


http://atariage.com/forums/blog/659/entry-15260-image-capture-on-the-ti-994a-computer/
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...