Couple questions about RLP, and (hopefully) some code review

I’ve got a couple questions about RLP on my FEZ (Panda II).

First, the documentation states that 10KB of memory is reserved when you enable RLP. Is this 10KB the maximum size of the ELF image that can be loaded? The documentation also states that the only way to reclaim this memory is to “erase the firmware” from the bootloader. Does this mean using the “E” command from bootloader mode, or does it mean that reloading the firmware (using the XMODEM upload procedure) restore the original memory configuration?

Second, I’ve written (included below) a simple “driver” for writing bytes out to a shift register. I’ve done this in the hopes that I can achieve better performance using RLP than I can by “bit-banging” from managed code. What sort of performance improvement am I likely to see? Is this the sort of thing that RLP is appropriate for?

Finally, I’ve included below the code for my shift register bit-banger. I was hoping someone could look over it and tell me if I’ve got the general idea right. It’s the first bit of RLP code I’ve written, and my C is fairly rusty. I’ll be posting this code on code.tinyclr.com when it’s done, if it’s actually useful.


 #include "RLP.h"

unsigned int port_clock = 0;
unsigned int port_latch = 0;
unsigned int port_data  = 0;
unsigned int port_clear = 0;

// I'm way too ghetto for a real header file...
int Release(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize);

int Initialize(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	port_clock = *(unsigned int*)args[0];
	port_latch = *(unsigned int*)args[1];
	port_data  = *(unsigned int*)args[2];
	port_clear = *(unsigned int*)args[3];

	// make sure the ports aren't already reserved (latch and clear are optional)
	if( RLPext->GPIO.IsReserved(port_clock) == RLP_TRUE )
		return -1;
	if( RLPext->GPIO.IsReserved(port_data) == RLP_TRUE )
		return -2;
	if( port_latch > 0 && RLPext->GPIO.IsReserved(port_latch) == RLP_TRUE )
		return -3;
	if( port_clear > 0 && RLPext->GPIO.IsReserved(port_clear) == RLP_TRUE )
		return -4;

	// reserve the clock port
	if( RLPext->GPIO.ReservePin(port_clock, RLP_TRUE) != RLP_TRUE )
	{
		Release(0, 0, 0, 0);
		return -1;
	}

	// reserve the data port
	if( RLPext->GPIO.ReservePin(port_data, RLP_TRUE) != RLP_TRUE )
	{
		Release(0, 0, 0, 0);
		return -2;
	}

	// reserve the latch port
	if( port_latch > 0 && RLPext->GPIO.ReservePin(port_latch, RLP_TRUE) != RLP_TRUE )
	{
		Release(0, 0, 0, 0);
		return -3;
	}

	// reserve the clear port
	if( port_clear > 0 && RLPext->GPIO.ReservePin(port_clear, RLP_TRUE) != RLP_TRUE )
	{
		Release(0, 0, 0, 0);
		return -4;
	}

	// enable output mode on the pins, all low initially
	RLPext->GPIO.EnableOutputMode(port_clock, RLP_FALSE);
	RLPext->GPIO.EnableOutputMode(port_latch, RLP_FALSE);
	RLPext->GPIO.EnableOutputMode(port_data,  RLP_FALSE);
	RLPext->GPIO.EnableOutputMode(port_clear, RLP_FALSE);

	// we're done
	return 0;
}

int Release(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	if( port_clock != 0 )
	{
		RLPext->GPIO.ReservePin(port_clock, RLP_FALSE);
		port_clock = 0;
	}

	if( port_latch != 0 )
	{
		RLPext->GPIO.ReservePin(port_latch, RLP_FALSE);
		port_latch = 0;
	}

	if( port_data != 0 )
	{
		RLPext->GPIO.ReservePin(port_data, RLP_FALSE);
		port_data = 0;
	}

	if( port_clear != 0 )
	{
		RLPext->GPIO.ReservePin(port_clear, RLP_FALSE);
		port_clear = 0;
	}

	return 0;
}

int WriteByte(unsigned int *generalArray, void **args, unsigned int argsCount, unsigned int *argSize)
{
	unsigned char data  = *(unsigned char*)args[0];
	unsigned int  clear = *(unsigned int*)args[1];
	unsigned int  lsbf  = *(unsigned int*)args[2];
	int           i     = 0;

	// clear (if we're clearing, and we have a clear pin)
	if( clear == RLP_TRUE && port_clear > 0 )
	{
		RLPext->GPIO.WritePin(port_clear, RLP_FALSE);
		RLPext->GPIO.WritePin(port_clear, RLP_TRUE);
	}

	// latch false (if we're latching data)
	if( port_latch > 0 )
		RLPext->GPIO.WritePin(port_latch, RLP_FALSE);

	if( lsbf == RLP_TRUE )
	{
		// write the data, least significant bit first
		for( i = 0; i < 8; i++ )
		{
			// first, bring the clock low
			RLPext->GPIO.WritePin(port_clock, RLP_FALSE);

			// then, write the data
			RLPext->GPIO.WritePin(port_data, data % 2 == 1);

			// finally, bring the clock high
			RLPext->GPIO.WritePin(port_clock, RLP_TRUE);

			// shift right
			data = data >> 1;
		}
	}
	else
	{
		// write the data, most significant bit first
		for( i = 0; i < 8; i++ )
		{
			// first, bring the clock low
			RLPext->GPIO.WritePin(port_clock, RLP_FALSE);

			// then, write the data
			RLPext->GPIO.WritePin(port_data, data >= 128);

			// finally, bring the clock high
			RLPext->GPIO.WritePin(port_clock, RLP_TRUE);

			// shift left
			data = data << 1;
		}
	}

	// latch true (if we're latching data)
	if( port_latch > 0 )
		RLPext->GPIO.WritePin(port_latch, RLP_TRUE);

	return 0;
}

No, that is all static resources of your RLP object, including code and data.

[quote]The documentation also states that the only way to reclaim this memory is to “erase the firmware” from the bootloader. Does this mean using the “E” command from bootloader mode, or does it mean that reloading the firmware (using the XMODEM upload procedure) restore the original memory configuration?
[/quote]

Yes E

Have you tried it yet? Yet is will be much much faster than doing it in C# :slight_smile:

Is there any way to tell how close to the limit I am? Maybe there’s information in the .map file that can help me out?

This command simply erases any user data in the flash, correct? The actual firmware itself won’t be erased?

I haven’t done it yet, because the board’s at home, and I’m at work. I’ll try it when I have a chance, however, and I’ll post some info on the performance improvement.

You can tell by using map file yes

The E erases everything