Jump to content
philexile

Jaguar Dev System

Recommended Posts

Well, I knew things working on the first try was too good to be true.  For whatever reason, that first time was the only time I've ever gotten this to work.  I was able to upload programs of various sizes many, many times on that first night, but then I yanked out all the debug LEDs, moved the level adjusters closer together, etc. just to clean the board up, added some minor teardown code to the GPIO path of lo_inp.c, and... nothing works 😞  I've tried everything I can think of to recreate the working state, from restoring the breadboard to its exact prior layout based on the pictures above, dangling LEDs and all, reverting the code to its prior state (to the best of my knowledge.  The changes were very minor and didn't touch any of the core functionality, but I of course neglected to make a snapshot in git of the exact working code), and even put together two fresh level adjuster modules in case I messed them up somehow when I pried them off the breadboard to move them.  No joy.  I was getting occasional success with 4-bit mode on the trivial "hello world" program on the first few tries, but at this point nothing will upload successfully.  I tried uploading using the new source code (The parallel port code was mostly unchanged) for lo_inp.c on the x86 path from my old parallel port system, and that still works fine, so nothing's gone wrong with the Jag or the general algorithm, just the new GPIO path.  I hacked up the code to just send random long words every 3 seconds, printing them on the console on the PC/Pi side, and I can see that every so often on the GPIO path, the data is just not latched correctly.  Random bytes skew to the left or right, or bits "stick" across nibbles, bytes, or even entire words occasionally.  Something is just off with the timing somehow now, even though I know changed nothing there from the working runs, and I tried all kinds of timing tweaks from zero delay up to 1 second delays everywhere.  I'm stumped.

 

At this point, all I can figure is that the RockPi board's GPIO behavior somehow went bad between the attempts, and continued to degrade a bit as I made subsequent attempts.  I'm going to try again with my other board (A Libre Computer Board AML-S805X-AC) if I can get that set up, but in the meantime I've posted the GPIO-based code to github in case anyone wants to take a look at it:

 

https://github.com/cubanismo/lo_inp/blob/master/lo_inp.c

 

Specifically, these functions that implement all the actual GPIO support:

static void waitGPIO(void)
{
	/*
	 * XXX I have no idea if a GPIO read takes an equivalent amount of time
	 * to an x86 I/O op.  We'll see.
	 */
	int a;
	for (a = gWait; a; a--) mraa_gpio_read(gpio_busy);
}

static void SendNibbleGPIO(uint8_t c)
{
	/* Pins are initialized low -> high */
	int outbits[8] = {
		c & 0x01,
		(c & 0x02) >> 1,
		(c & 0x04) >> 2,
		(c & 0x08) >> 3,
		(c & 0x10) >> 4,
		(c & 0x20) >> 5,
		(c & 0x40) >> 6,
		(c & 0x80) >> 7,
	};

	/* Wait for busy to go low */
	while (mraa_gpio_read(gpio_busy));
	waitGPIO();

	/* Write the data lines */
	mraa_gpio_write_multi(gpio_data, outbits);
	waitGPIO();

	/* Write strobe low */
	mraa_gpio_write(gpio_strobe, 0);
	waitGPIO();

	/* Wait for busy to go high */
	while (!mraa_gpio_read(gpio_busy));
	waitGPIO();

	/* Write strobe high */
	mraa_gpio_write(gpio_strobe, 1);
	waitGPIO();
}

static void SendWordGPIO(uint16_t w)
{
	unsigned int i, j;
	int outbits[8] = {0};

	for (j = 1; j <= 3; j++) w = ((w << 1) & 0xFFFF) | (w >> 15);

	for (i = 1; i <= 8; i++)
	{
		/* Wait for busy to go high */
		while (!mraa_gpio_read(gpio_busy));
		waitGPIO();

		/*      Write some data... ??? */
		/* Pins are initialized low -> high */
		outbits[1] = (w & 0x02) >> 1;
		outbits[2] = (w & 0x04) >> 2;
		mraa_gpio_write_multi(gpio_data, outbits);
		waitGPIO();

		/* Set strobe high */
		mraa_gpio_write(gpio_strobe, 1);
		waitGPIO();

		for (j = 1; j <= 2; j++) w = ((w << 1) & 0xFFFF) | (w >> 15);

		/* Wait for busy to go low */
		while (mraa_gpio_read(gpio_busy));
		waitGPIO();

		/* Set strobe low */
		mraa_gpio_write(gpio_strobe, 0);
		waitGPIO();
	}
}

static void InitPortNormalGPIO()
{
	int outbits[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };

	/* Init data low */
	mraa_gpio_write_multi(gpio_data, outbits);

	/* Init strobe low... Twice? */
	mraa_gpio_write(gpio_strobe, 0);
	mraa_gpio_write(gpio_strobe, 0);

	Delay(100);
}

static void InitPortHyperGPIO()
{
	int outbits[8] = { 0, 0, 0, 0, 0, 0, 0, 0, };

	/* Init data low */
	mraa_gpio_write_multi(gpio_data, outbits);

	/* Init strobe low */
	mraa_gpio_write(gpio_strobe, 0);

	Delay(100);
}

 

Share this post


Link to post
Share on other sites

Oh, and a couple side notes:

 

I also did get that shorter 6ft/2m parallel cable before I started working on the Pi-based experiments, and it did not improve things on the x86/PC side at all.  Both the 15ft cables I had actually work better.  Go figure 🙂

 

I am sourcing the reference 5v signal for the voltage level adjusters from the Jaguar controller port's 5v line.  I assume that's the better than using the RockPi's 5v line as a reference level.  I accidentally wired that line all the way through to the 5v power line on the RockPi once while testing, and everything was still working fine (or as well as it had been by that point anyway), but when I tried to power off the Jag, it wouldn't turn off.  The power coming in through the controller port seemed to be enough to override the power switch, maybe even power the whole system.  I didn't wait around to experiment once I realized the mistake and quickly pulled the power off the Pi board.  I hope I wasn't damaging anything there, but this was well into my unsuccessful experiments, so I don't think it's the cause of the failures.

Share this post


Link to post
Share on other sites

I came back to this after working on other projects for a while, and was able to coax it back to life somewhat.  Switching to the other Pi board didn't help anything.  The key, as far as I can tell anyway, is having all the signals going through the same level-shifter IC.  There must be some variance between the propagation delay or something.  I'd tried messing with this before, but without the knowledge that 4-bit mode uses the "upper" 4-bits (speaking in terms of the lines on a parallel port in the BJL wiring diagram), rather than the lower 4-bits of data.  Wiring things up such that the upper 4 bits and the strobe + busy lines are all going through one level-shifter IC allowed me to successfully upload the jag "hello world" and "Hot Chicks"/256 color C demos from the Belboz SDK.  I'm still not able to replicate my initial success uploading larger files such as Gem Race.  I did successfully upload tube2020 once, which is about 350KB.  I messed around with CPU governors, locking the CPU frequencies, using taskset to schedule on particular cores, and everything, but nothing really seems to affect the reliability that much.

 

I also rewrote my SendLong/SendWord commands to use something more like @42bs posted, rather than mirroring the existing lo_inp.c X86 routines into GPIO methods exactly, but that didn't seem to affect things one way or the other much either.

 

What I do notice, is that the more I experiment, the worse it works.  I think something just overheats or something and throws everything off.

Share this post


Link to post
Share on other sites

I suggest you try to make some demo files with defined patterns. For example alternating 0xFF and 0x00, or 0xAA and 0x55 to see if this could cause the problem.

 

Share this post


Link to post
Share on other sites

BJL is definitely finicky about propagation delays ; I remember tweaking the timings to get things to work reliably. And even with dedicated hardware and precise timings, large transfers still fail from time to time.

 

One thing you can do to improve reliability is to first upload and run a small and more resilient custom loader using BJL, then use that custom loader to actually transfer the data.

That's what I use to program the Jagtopus cartridge, and it works very reliably. Let me know if you're interested.

  • Thanks 1

Share this post


Link to post
Share on other sites

At one point, I hacked up the uploader code to generate these types of patterns, sleep 3 seconds between dwords, and print them out locally as they're transmitted, then spent several hours swiveling my head around trying to make sense of the patterns.  The main thing I did was march a pattern across the dword (0x0000000f, 0x000000f0, 0x00000f00..., substituting various values for 'f', using larger patterns when testing 8-bit mode)  There was no rhyme or reason to it.  I think I found that bits "stick" in the next nibble/byte sometimes, but there wasn't anything deterministic about when it happened.  Sometimes it worked, sometimes it didn't.  Wasn't specific to a particular byte/nibble/bit or anything.  It seemed pretty random.

 

What's weird is it really does seem like things just degrade over time.  I unplugged everything after my tests earlier today, and plugged it all back in tonight to run a few more tests, and it seems no more reliable than when I left off earlier.  It's like I'm burning out the components somehow as I test, but I don't know why that would be happening.  It's a little disturbing that the behavior would persist like this, and I'm worried I'm imagining it since I don't have any real objective data to prove it.

 

Regardless, I'm probably going to put this project on hold again for a while, but my next steps were:

 

-Write a kernel module to do the low-level GPIO twiddling (Implement SendWord/SendLong in the kernel basically) to see if that would eliminate some variance.  I could block interrupts, lock out CPU frequency changes during an entire BJL upload, use high-precision timing methods directly to implement delays, and do super-rude things like hold a spin lock on all CPUs around each individual SendByte/SendNibble op, for example.

 

-I could also try using memory-mapped GPIO from userspace, as it looks like you've done, rather than gpiod, which I think mraa is using behind the scenes (I also have a version of lo_inp that uses gpiod directly, but it didn't fare any better), but then I'd end up with very board-specific code.  Hence, I lost interest in pursuing this.

 

-Break down and try implementing the whole thing on an Arduino Nano.  I was really hoping for some general-ish solution that anyone with a Pi-like board could replicate though 😕  If I go this route, I kind of want to go all-in and work up a PCB based on the Arduino Nano with just enough stuff for BJL, so I can make something that's an all-in-one solution like the never-released Catnip USB cable that I can just release the design files for.

 

Anyway, I don't think I'll attempt any of this anytime soon.  I still have my old motherboard with a parallel port on it wired up sitting on an anti-static bag in its box on the floor with my 15ft parallel cable and a regular BJL adapter attached to it, and that works just fine when I feel like being a masochist and not using my skunkboard.  Plenty of other projects to pursue, but if anyone else genuinely is interested in using something like this, I could be convinced to come back to it.

Share this post


Link to post
Share on other sites
5 minutes ago, cubanismo said:

Write a kernel module to do the low-level GPIO twiddling

I think, user mode GPIO on Linux could be the root cause of the problem. You simply can't be sure that the kernel won't interfere between accesses.

Next could be the edges of the Pi's GPIOs. If these are not steep enough the Jaguar might mis-interpret it.

  • Thanks 1

Share this post


Link to post
Share on other sites
9 minutes ago, cubanismo said:

Break down and try implementing the whole thing on an Arduino Nano

I used an old Cortex-M3 eval-board which has Ethernet and nice 5V levels. This worked very well. Just RTOS, TCP/IP and no Linux. ;-)

  • Thanks 1

Share this post


Link to post
Share on other sites
1 minute ago, Zerosquare said:

One thing you can do to improve reliability is to first upload and run a small and more resilient custom loader using BJL, then use that custom loader to actually transfer the data.

That's what I use to program the Jagtopus cartridge, and it works very reliably. Let me know if you're interested.

Yeah, if you have some resilient loader code to share, I'll take a look at it.  I was mildly interested in coding up something like the packet loader referenced here:

 

https://web.archive.org/web/20090316204047/http://www.freewebs.com/swapd0/tools.html#PacketLoader

 

(What became of your website @swapd0?)

 

As an aside, I'm also personally curious what happened to the JagCF project and the Catnip.  I keep coming across mentions of them (Stumbled upon

this the other day), and other mentions that the projects didn't come to fruition, but no real explanation as to why.

Share this post


Link to post
Share on other sites
8 minutes ago, 42bs said:

Next could be the edges of the Pi's GPIOs. If these are not steep enough the Jaguar might mis-interpret it.

 Yeah, and I did see mention on the amazon reviews of those level adjusters that their edges weren't the cleanest, but I didn't see any better ones on offer anywhere either.  On most of my hardware-ish projects, the correct next step really seems to be getting a good oscilloscope 😕 I haven't touched one since college/university.

Share this post


Link to post
Share on other sites
Posted (edited)
On 7/21/2020 at 7:19 AM, cubanismo said:

Yeah, if you have some resilient loader code to share, I'll take a look at it.

I'd need to extract the communication code from the rest and clean it up a bit, but here's how it works:

 

On the PC (or microcontroller, etc.) side, set the parallel port (D0~D7) to output mode, all outputs low (data=0x00). Then:

- To send a "0" bit, toggle D6 ; to send a "1" bit, toggle D7.

- Wait until BUSY toggles.

- Repeat for the next bit to send, etc.

 

On the Jaguar side, set the joypad port to output mode, all outputs low (JOYSTICK=$8000). Then:

- Wait until either bit 14 ("0" bit received) or bit 15 ("1" bit received) toggles.

- Toggle the state of bit 7 of JOYSTICK.

- Repeat for the next bit to receive, etc.

 

That's all there is to it.

 

Note the complete lack of timings in the definition of the protocol, and . This means that timeouts and race conditions can never occur: both sides are always in lockstep, and if one side is slower, the other will simply wait for it to be ready. In fact, the communication will automatically run at the fastest speed that's possible

Also, since there's only a single signal changing state at the same time, propagation delays are irrelevant: even if different pins have different delays, it will not cause problems. Crosstalk between signals can also be detected and rejected: if more than one signal appears to have toggled, read the inputs again until it is no longer the case.

 

Once that works, you can speed things up by sending two bits at the same time: toggle D4 for 00, D5 for 01, D6 for 10, and D7 for 11. On the Jaguar side, simply XOR the current and previous state of the inputs, shift the result 12 bit right, and use it as an index into a look-up table to get the value of the bits (or an "invalid" value if more than one signal toggled).

 

On 7/21/2020 at 7:19 AM, cubanismo said:

As an aside, I'm also personally curious what happened to the JagCF project and the Catnip.  I keep coming across mentions of them (Stumbled upon

this the other day), and other mentions that the projects didn't come to fruition, but no real explanation as to why.

Basically, the Skunkboard happened. After it was released and widely adopted by the community, interest for BJL pretty much waned, and so did the purpose of the Catnip: using the Skunkboard's USB connection was faster and most reliable. The Skunkboard also provided a way to play cartridge games, which was one of the major features of the JagCF. Even if both projects had different goals, there was significant overlap between the two (and even more overlap with SainT's SD cart).

 

The Catnip itself has been completed: I still use it with my Jaguar, and it can also be used to program Jagtopus carts. There's just little point in releasing it now.

Edited by Zerosquare
  • Thanks 1

Share this post


Link to post
Share on other sites
4 minutes ago, Zerosquare said:

I'd need to extract the communication code from the rest and clean it up a bit, but here's how it works:

Thanks.  If it's work to get the code factored out, don't do it on my account.  I probably won't get back to this soon, and the explanation here is plenty of info to go on when I do.

 

5 minutes ago, Zerosquare said:

The Skunkboard also provided a way to play cartridge games, which was one of the major features of the JagCF.

Yeah, but it didn't sneak in a coprocessor and whanot.  Would have been cool to see that. 🙂 Thanks for sharing!

Share this post


Link to post
Share on other sites
Posted (edited)
53 minutes ago, cubanismo said:

Would have been cool to see that. 🙂

I don't have any demo of the coprocessor part, but there's this old video showing running various homebrews, displaying high-resolution pictures (unfortunately, the video compression spoils the result), and video streaming:

http://zerosquare.free.fr/demo_jagcf.avi

Edited by Zerosquare
  • Like 1

Share this post


Link to post
Share on other sites
On 7/21/2020 at 7:19 AM, cubanismo said:

Yeah, if you have some resilient loader code to share, I'll take a look at it.  I was mildly interested in coding up something like the packet loader referenced here:

 

https://web.archive.org/web/20090316204047/http://www.freewebs.com/swapd0/tools.html#PacketLoader

 

(What became of your website @swapd0?)

 

As an aside, I'm also personally curious what happened to the JagCF project and the Catnip.  I keep coming across mentions of them (Stumbled upon

this the other day), and other mentions that the projects didn't come to fruition, but no real explanation as to why.

Yeah, that was long time ago...

 

Try to get a skunk board, it saves a lot of headaches and the upload speed it's a lot faster.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...