Offline
CA
Jazzmarazz wrote:
friendofmegaman wrote:

Theoretically... could we leverage some parallel interface for that? It should be feasible to clock it from GB clock and get all the data as needed. In fact we only need VSYNC, CLOCK, DATA0, DATA1... some 4 pin parallel interface anyone?

Yeah, possibly. The only problem I see is that very few people are going to have access to a parallel interface at home, let alone "on the road."


How bout this? http://www.amazon.com/Printer-25-Pin-Pa … B005HBKOH6

Dismantle the fucker and shove into a GB?

Offline
Michigan

Those cables are for printer connections only. They cannot fully emulate a full DB25 connection over USB.

Offline
CA

So the good thing is this parallel port has 8 data bits (more than we even need) and its speed is 12 000 kbps (and we need 4 000 kbps). Two questions:
1. How do we put data there without a uC (since I doubt we can solve lacking clocks problem there for we must consider non-uC variants)?
2. How do we read the data at the PC side?

Offline
CA
Jazzmarazz wrote:

Those cables are for printer connections only. They cannot fully emulate a full DB25 connection over USB.

Bummer... sad

Offline
Michigan

Still considering the parallel port, lets look at something:
http://www.reocities.com/SiliconValley/ … gb2pp7.gif

This is the Madcatz cable for transferring images from the GB camera to PC. Lets say we removed the link port connection and connected it to a 74HC165.

74HC165's Parallel connection connected to D0, D1, V and CLK, which leaves four free bits which could be used as a natural break in the data sent.
74HC165's Sout connected to Parallel pin 12 (or through the diode and transistor)
74HC165's enable connected to ground, or something.
etc...

Offline
Michigan

Here is some good information, schamtic and software for talking over a parallel port.
http://www.maximintegrated.com/en/app-n … vp/id/3230
Scrolling down I see a parallel-to-I2C diagram. I2C has an SCL and an SDA pin. Clock and data.
If the PC clocks our shift register, you would need a clock rate at least 8 times that of the GB's clock rate to make sure all 8-bits are shifted before the next GB clock cycle.

'your' software would have to take into account multiple data bytes with an unchanged GB-clock.

umm... Still seems complicated. I want to see composite video, and not just a picture on my PC. tongue

Offline
friendofmegaman wrote:

Theoretically... could we leverage some parallel interface for that?

I had the idea of using a parallel port (IEEE 1284) interface a while ago but abandoned it because it seems the port isn't fast enough, even in EPP/ECP mode.  But having another think, could we use two four-bit serial-parallel shift registers (one for each pixel bit) connected to the data lines?  We would then connect the clock to a status line through a /4 clock divider, and the VS and HS signals to status lines, possibly with some circuitry to increase the pulse width.  We would still have to blindly sample on the PC and would end up with raw, unclocked data, but so far this sounds feasible to me.

Offline
Michigan

Some timing documentation of the 16MHz arduino:
http://jeelabs.org/2010/01/06/pin-io-performance/

good read. Take special not of:

With these results we get: one digitalRead() takes 4134 ns, one direct port read takes 83 ns (again correcting for 819 ns loop overhead). The conclusion being that digitalRead() is 50x as slow as direct port reads.

Which one is correct? I don’t know for sure. I retried the direct port read with 16 entries per loop, and got 67 ns, which seems to indicate that a direct port read takes one processor cycle (62.5 ns), as I would indeed expect.

Conclusion: if performance is the goal, then we may need to ditch the Arduino approach.

Update – Based on JimS’s timing code (see comments): digitalRead() = 58 cycles and direct pin read = 1 cycle.

Update #2 – The “1 cycle” mentioned above is indeed what I measured, but incorrect. The bit extraction was probably optimized away. So it looks like direct pin access can’t be more than 29x faster than digitalRead(). As pointed out by WestfW in the comments, digitalRead() and digitalWrite() have predictable performance across all use cases, including when the pin number is variable. In some cases that may matter more than raw speed.

Update #3 – Another caveat – Lies, damn lies, and statistics! – is that the register allocations for the above loops make it extremely difficult to draw exact conclusions. Let me just conclude with: there are order-of-magnitude performance implications, depending on how you do things. As long as you keep that in mind, you’ll be fine.

Last edited by Jazzmarazz (Jun 3, 2014 11:20 pm)

Offline
Michigan

Something I mentioned before:
http://www.batsocks.co.uk/products/Othe … t.htm#nogo
Sadly I just read the details: "38x25 characters"

hmm...

Offline
Michigan

Rvan! Can you comment your pygame code for me? I need to modify it to accomadate whatever data I send, but I don't know all of what is going on. Comment it for the laymen, k? wink

Offline
Jazzmarazz wrote:

Rvan! Can you comment your pygame code for me?

Here it is.

#!/usr/bin/python
#author: friendofmegaman, rvan
#Display captured frame data on the PC.  Expects a 0x1E00 header and four
#pixels per byte.  Uses pygame, which is faster than pylab's scatter.

import pygame
from pygame.locals import *

#Set upscale factor, so the image can be made larger on the PC.
#This is configurable.
upscale = 2

width = 160
height = 144

#Set default palette.  We use the same colors as BGB.
grey = []
grey.append((224,248,208))
grey.append((136,192,112))
grey.append((52, 104, 86))
grey.append((8, 24, 32))

#Load the captured binary file.
fd = open('/path/to/screen.bin', 'rb')
data = fd.read()
fd.close()

#Split the data into frames at the frame header.  This will need to be changed
#if using a headerless or 3 pixels per byte format.
frames = data.split('\x1E\x00')
print len(frames), 'frames'

class Pixel:
    """Self-incrementing pixel class. When called with a two-bit color value, an
    instance of this class will set the appropriate color at that pixel and
    then automatically increment the x and y values."""
    x = 0;
    y = 0;
    def __call__(self, col):
        #Iterate over the PC pixels which represent one GB pixel and set the
        #color for each.
        for upy in range(upscale):
            for upx in range(upscale):
                window.set_at(((self.x)*upscale+upx,
                               (self.y)*upscale+upy), grey[col])
    
        #Increment the x and y values as necessary.
        self.x +=1
        if self.x==160:
            self.x = 0
            self.y +=1

#Instantiate Pixel.
pixel = Pixel()

#Initialize the pygame window.
window = pygame.display.set_mode((width*upscale, height*upscale))

#(friendofmegaman wrote this loop.  These are rvan's comments and may not be
#entirely accurate.)
for frame in frames:
    #Find the first complete frame.
    if len(frame)!=5760:
        continue

    #Iterate over each pixel.
    for y in range(144):
        for x in range(160):
            """This section is what will need to be changed to accommodate a
            different pixel format.  The important part is the call to pixel(),
            which needs to simply be called once for each pixel, in order."""

            #Convert the two-dimensional pixel address into a one-dimensional
            #global (i.e., whole screen) bit address.
            bit_offset = y*320+x*2

            #Convert the global bit address into a byte address and a
            #within-byte bit address.
            array_offset = bit_offset/8
            byte_offset = bit_offset%8

            #Load the relevant byte from the array and the relevant two bits
            #into px.
            byte = ord(frame[array_offset])
            px = (byte>>byte_offset)&0b11

            #Set the color.  Remember that Pixel increments automatically.
            pixel(px)

#Update the display to show the pixels.
pygame.display.update()

#Leave the display up until the window is closed or escape is pressed.
quit = False
while not quit:
    event = pygame.event.wait()
    if event.type == pygame.QUIT or event.type == KEYDOWN and \
    event.key == K_ESCAPE:
        quit = True
Offline
Michigan

Thanks so much. I'll have a look asap...

edit:

#Iterate over each pixel.
    for y in range(144):
        for x in range(160):

Did you mean to replace 144 and 160 with the height and width variables to keep thing consistent?

Last edited by Jazzmarazz (Jun 5, 2014 3:03 am)

Offline
Jazzmarazz wrote:

Thanks so much. I'll have a look asap...

edit:

#Iterate over each pixel.
    for y in range(144):
        for x in range(160):

Did you mean to replace 144 and 160 with the height and width variables to keep thing consistent?

You're welcome.

The hardcoded values come from friendofmegaman's version, and the variables come from some Pygame code I had written which I adapted for this, hence the discrepancy.  You're entirely right that the variables should be used here.  I'm sure there is much other tidying up which could be done, too.

Offline
Michigan

Still haven't had time to sit down with this myself, but I gotta thank you guys for introducing me to Dualport SRAM. I have another project and it may alone be my savior considering the limitations of 16MHz microcontrollers.

Dualport RAM does seem to be more expensive than I had hoped, but I have few other options. I will try to get back onto this project asap.
Cheers

Offline
Jazzmarazz wrote:

Still haven't had time to sit down with this myself, but I gotta thank you guys for introducing me to Dualport SRAM. I have another project and it may alone be my savior considering the limitations of 16MHz microcontrollers.

I'm now curious what your other project entails.

Offline
Michigan

Bump.
Its been ages since we last spoke about this, but I think I can set aside some testing time tomorrow. I got the day off and am waiting on some PCBs (unrelated) so I need to fill the time.