RLP function completes but does not return to managed code

I’m trying to control a s1d13700 display controller chip. I found a arduino example on the net and tested it using a arduino and it worked. I reworked that into c# code and it works, but it is very slow. Enter RLP. I converted the original code to something that should work as RLP.

As yagarto seems to be unmaintained I took my toolchain from Prebuilt GNU toolchain for ARM (legacy). I also tried keil compiler but it’s results crashed on init bss en procedure loading.

If I compare the action on the display from native code to the managed version I can determine that it completes the native code initialization function fine. However the next break point in c# code is never hit and the debugger looses communication. Luckily I build in the suggested disable rlp trick from the documentation, so I can reflash and try again.

initS1D13700.invokeex never returns. I did not include everything as that might make thing unreadable. If you want to see something more/else ask me,
The code:

struct pin_type {
		unsigned char d0;
		unsigned char d1;
		unsigned char d2;
		unsigned char d3;
		unsigned char d4;
		unsigned char d5;
		unsigned char d6;
		unsigned char d7;
		unsigned char a0;
		unsigned char wr;
		unsigned char rd;
		unsigned char cs;
		unsigned char rst;
	} pins;

int InitS1D13700(unsigned char *generalArray, void **args, unsigned int argsCount, unsigned int *argSize) {
	pins.d0 = generalArray[0];
	pins.d1 = generalArray[1];
	pins.d2 = generalArray[2];
	pins.d3 = generalArray[3];
	pins.d4 = generalArray[4];
	pins.d5 = generalArray[5];
	pins.d6 = generalArray[6];
	pins.d7 = generalArray[7];
	pins.rd = generalArray[8];
	pins.wr = generalArray[9];
	pins.a0 = generalArray[10];
	pins.cs = generalArray[11];
	pins.rst = generalArray[12];
	/*Set all data pins as 
	output and then set them low*/
	RLPext->GPIO.EnableOutputMode(pins.d0, 0);
	RLPext->GPIO.EnableOutputMode(pins.d1, 0);
	RLPext->GPIO.EnableOutputMode(pins.d2, 0);
	RLPext->GPIO.EnableOutputMode(pins.d3, 0);
	RLPext->GPIO.EnableOutputMode(pins.d4, 0);
	RLPext->GPIO.EnableOutputMode(pins.d5, 0);
	RLPext->GPIO.EnableOutputMode(pins.d6, 0);
	RLPext->GPIO.EnableOutputMode(pins.d7, 0);
	/*Set all control pins as 
	output and then set them high*/
	RLPext->GPIO.EnableOutputMode(pins.rd, 1);
	RLPext->GPIO.EnableOutputMode(pins.wr, 1);
	RLPext->GPIO.EnableOutputMode(pins.a0, 1);
	RLPext->GPIO.EnableOutputMode(pins.cs, 1);
	RLPext->GPIO.EnableOutputMode(pins.rst, 1);
	/* Now we are going to issue the system set command
		and specify operating paramters. If these need to
		change for your application, you must study the
		S1D13700 datasheet and change the values in
		S1D13700.h */


	return 0;

/* This function is specified inline for speed reasons*/
inline void __attribute__ ((always_inline)) setData(unsigned char data)
	RLPext->GPIO.EnableOutputMode(pins.d0, (data & 1));
	RLPext->GPIO.EnableOutputMode(pins.d1, ((data & (1 << 1)) >> 1));
	RLPext->GPIO.EnableOutputMode(pins.d2, ((data & (1 << 2)) >> 2));
	RLPext->GPIO.EnableOutputMode(pins.d3, ((data & (1 << 3)) >> 3));
	RLPext->GPIO.EnableOutputMode(pins.d4, ((data & (1 << 4)) >> 4));
	RLPext->GPIO.EnableOutputMode(pins.d5, ((data & (1 << 5)) >> 5));
	RLPext->GPIO.EnableOutputMode(pins.d6, ((data & (1 << 6)) >> 6));
	RLPext->GPIO.EnableOutputMode(pins.d7, ((data & (1 << 7)) >> 7));

void writeCommand(unsigned char command)
	RLPext->GPIO.WritePin(pins.wr, 0);
	RLPext->GPIO.WritePin(pins.cs, 0);
	RLPext->GPIO.WritePin(pins.wr, 1);
	RLPext->GPIO.WritePin(pins.cs, 1);


void writeData(unsigned char data)
	RLPext->GPIO.WritePin(pins.a0, 0);
	RLPext->GPIO.WritePin(pins.cs, 0);
	RLPext->GPIO.WritePin(pins.wr, 0);
	RLPext->GPIO.WritePin(pins.cs, 1);
	RLPext->GPIO.WritePin(pins.wr, 1);
	RLPext->GPIO.WritePin(pins.a0, 1);

c# code

 #region Definition
        RLP.Procedure initS1D13700;
        RLP.Procedure writeText;
        RLP.Procedure textGoTo;
        RLP.Procedure graphicGoTo;
        RLP.Procedure clearText;
        RLP.Procedure clearGraphic;
        RLP.Procedure drawLine;
        RLP.Procedure drawBox;
        RLP.Procedure drawCircle;
        RLP.Procedure drawByteBuffer;


        #region Low level control and init

        public S1D13700(byte RD, byte WR, byte A0, byte CS, byte RST, byte D0, byte D1, byte D2, byte D3, byte D4, byte D5, byte D6, byte D7)
            byte[] elf_file = Resources.GetBytes(Resources.BinaryResources.RLP_S1D13700);

            initS1D13700 = RLP.GetProcedure(elf_file, "InitS1D13700");
            writeText = RLP.GetProcedure(elf_file, "WriteText");
            textGoTo = RLP.GetProcedure(elf_file, "TextGoTo");
            graphicGoTo = RLP.GetProcedure(elf_file, "GraphicGoTo");
            clearText = RLP.GetProcedure(elf_file, "ClearText");
            clearGraphic = RLP.GetProcedure(elf_file, "ClearGraphic");
            drawLine = RLP.GetProcedure(elf_file, "DrawLine");
            drawBox = RLP.GetProcedure(elf_file, "DrawBox");
            drawCircle = RLP.GetProcedure(elf_file, "DrawCircle");
            drawByteBuffer = RLP.GetProcedure(elf_file, "DrawByteBuffer");

            Debug.Print("elfSize = " + elf_file.Length.ToString());
            elf_file = null;
            initS1D13700.InvokeEx(new byte[] { D0, D1, D2, D3, D4, D5, D6, D7, RD, WR, A0, CS, RST});

I’m trying this on an old usbizi-devsys as that is the only free module I have at the moment. However old should not mean non working:)

There is a special note regarding BSS region in RLP documentation:


Make sure you are good there.

I suggest (unless you already done this) to make sure RLP is working with very simple function first and then start building from there.

@ bzuidgeest - What does hardReset do?

I would try with yagarto just to be sure it’s not the toolchain causing trouble.

And also what Architect said - create simple test method which returns some integer and see if that works.

Hi all.

Let my try to answer the questions and sugestions.

@ jasdev

Hardreset resets the s1d13700 controller. I’m however quite sure the problem is not there. The last command in the init function is dispon (display on) and the display does turn on. Then it has to return and that does not happen…

void hardReset(void)
	RLPext->GPIO.WritePin(pins.rst, 0);
	RLPext->GPIO.WritePin(pins.rst, 1);

@ architect

There are quite a lot of notes in there… but f you mean the one about the linkerscript needing to be similar to the one in the example than i think that is true.
Also as I had not tried it, I made a simple function that just returns 1 nothing else. And that function works and returns.

@ Hyperlisk
I made a test method as above and it works. Let me see if I can start adding things until it fails…

How big is your elf file?

That’s quite a long delay. I hope you waited that long :slight_smile:

@ Hyperlisk - It’s in microseconds, so not that long!

Ah sorry. Thought it was in milliseconds :slight_smile:

@ architect
The elf file is about 8kb. so it’s should not exceed the 10kb limit on this old device.

@ andre.m
I believe it get’s to the end of the function as I can see the the display turns on and that only happens with the dispon command at the end. I verified that with my managed version of the code.

However following using the dummy function test method I now know the function refuses to return as soon as I include the first RLPext->GPIO.EnableOutputMode(pins.d0, 0); line.

int DummyFunction(unsigned char *generalArray, void **args, unsigned int argsCount, unsigned int *argSize) {

	pins.d0 = generalArray[0];
	pins.d1 = generalArray[1];
	pins.d2 = generalArray[2];
	pins.d3 = generalArray[3];
	pins.d4 = generalArray[4];
	pins.d5 = generalArray[5];
	pins.d6 = generalArray[6];
	pins.d7 = generalArray[7];
	pins.rd = generalArray[8];
	pins.wr = generalArray[9];
	pins.a0 = generalArray[10];
	pins.cs = generalArray[11];
	pins.rst = generalArray[12];
	/*Set all data pins as 
	output and then set them low*/
       //including this line prevents dummy from returning.
	RLPext->GPIO.EnableOutputMode(pins.d0, 0);
//without the enableoutputline this return the expected byte value.
        return generalArray[5];

C/C++ is not something I program much in. I can read it well enough for when I do conversions to managed code. So did i use the enableoutputmode function wrong? copied something that should be referenced or the other way?

Does it matter if it is just that pin or any other pin blocks the execution as well?

EnableOutputMode expects unsigned int for both parameters:

void EnableOutputMode(unsigned int Pin, unsigned int InitialState)

@ architect
No pin does not matter, I tried different ones.

@ jasdev
I look in to casting the value, The code from the ks0108 example on this site was used as a example and it uses usingned char as a parameter. Giving me the assumption it would not matter.