XMEM2 - Now with real preemptive multitasking

For those of us who need more room...

XMEM2 @ GitHub - xxxajk/xmem2: Arduino Mega 1280/2560 and PJRC Teensy++2.0 xmem compatible library with auto-size features and real preemptive multitasking. Also provides ISR safe malloc for all AVR arduinos, and all Teensy products from PJRC.com.

xmem2 is an xmem compatible library with autosize features.

Supports both RuggedCircuits RAM expansions automatically. Supports Andy Brown's RAM expansion too.

Can support up to 255 banks of external memory, with minor sketch changes.

NEW: Supports moving the stack to external memory. You can even specify how much.

NEW: XMEM2 now supports real preemptive multitasking!

On the QuadRam, 16 tasks are possible.
Each task has it's own stack, and malloc arena.
Tasks are switched in round-robin order.
The shared stack/malloc arena area is 32KB and you can split it how ever you wish.
Best of all NO RTOS OVERHEAD

Multitasking Demo @ GitHub - xxxajk/testMultitask

NEW: CPU cycle friendly Sleep()
Lock_Acquire(), Lock_Release(), Yield()
Ability to determine parent task.
Ability to detect when a task is running or done.
Ability to determine if parent task owns child task.

More features coming as needed.

AJK,

Thanks for posting the Xmem2. I'm trying to make use of a Rugged Circuits QuadRam board to add memory to my mega 2560 project.

I've downloaded Xmem2 from github, and placed it in my (apple mac) Arduino/libraries folder.
Then I got testMultiTask and opened Arduino (1.5.2), but when I compile the sketch, I get a series of errors;

testMultitask.ino: In function 'void task_B()':
testMultitask:70: error: 'Sleep' is not a member of 'xmem'
testMultitask.ino: In function 'void setup()':
testMultitask:112: error: 'SetupTask' is not a member of 'xmem'
...

So, looking at the header file, I defined USE_MULTIPLE_APP_API
( I don't actually need Multi tasking in my project,just extra ram space). But then I get the following error about redefinition of malloc & free;
(BTW; I get this with Andy Browns Xmem too...)

/Applications/Arduino-152.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/lib/avr6/libc.a(malloc.o): In function malloc': /Users/cs/Developer/Hardware/AVR-USB/AVRMacPack/buildtmp.nobackup/avr-libc-1.6.4/avr/lib/avr6/../../../libc/stdlib/malloc.c:78: multiple definition of malloc'
core.a(malloc.c.o):/Applications/Arduino-152.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino/malloc.c:82: first defined here
/Applications/Arduino-152.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/bin/ld: Disabling relaxation: it will not work with multiple definitions
/Applications/Arduino-152.app/Contents/Resources/Java/hardware/tools/avr/bin/../lib/gcc/avr/4.3.2/../../../../avr/lib/avr6/libc.a(malloc.o): In function free': /Users/cs/Developer/Hardware/AVR-USB/AVRMacPack/buildtmp.nobackup/avr-libc-1.6.4/avr/lib/avr6/../../../libc/stdlib/malloc.c:195: multiple definition of free'
core.a(malloc.c.o):/Applications/Arduino-152.app/Contents/Resources/Java/hardware/arduino/avr/cores/arduino/malloc.c:194: first defined here
testMultitask.cpp.o: In function setup': /Applications/testMultitask.ino:112: undefined reference to xmem::SetupTask(void ()())'
/Applications/testMultitask.ino:113: undefined reference to xmem::StartTask(unsigned char)' /Applications/testMultitask.ino:114: undefined reference to xmem::SetupTask(void (
)())'
/Applications/testMultitask.ino:115: undefined reference to xmem::StartTask(unsigned char)' /Applications/testMultitask.ino:116: undefined reference to xmem::SetupTask(void (*)())'
/Applications/testMultitask.ino:117: undefined reference to xmem::StartTask(unsigned char)' testMultitask.cpp.o: In function task_B()':
/Applications/testMultitask.ino:70: undefined reference to `xmem::Sleep(unsigned long long)'

Have I missed something crucial in the docs somewhere? Any suggestions?

Mark B

I wanted to ask about all of the instances of 'reinterpret_cast' used for xmem:

...what is the reason that:

uint8_t *ptr;

ptr = reinterpret_cast<uint8_t *>(0x2200);

can not just be:

uint8_t *ptr;

ptr = 0x2200;

And to advance the pointer by 8 bytes for example, would "ptr = ptr + 8;" work, or is casting needed there too??

_uXe:
I wanted to ask about all of the instances of 'reinterpret_cast' used for xmem:

This must be my favourite C/C++ feature. It makes a complete nonsense of their prissy attempts at strict variable typing. Long live Python and Ruby

...R

Robin2:
This must be my favourite C/C++ feature.

Appreciate the sentiment - but doesn't get me any closer to an answer... is it because the addresses for Arduino pointers will always be 16 bits, but because the actual data value in this case is 8 bits it causes some conflict? So the 'reinterpret_cast' needs to be there as a workaround?

Robin2:
Two or three hours spent thinking and reading documentation solves most programming problems.

Words to live by! :slight_smile:

_uXe:
I wanted to ask about all of the instances of 'reinterpret_cast' used for xmem ... can not just be:

uint8_t *ptr;

ptr = 0x2200;

With the avr-gcc compiler either will work. Which is the point. That may not work with other compilers. Without the reinterpret_cast the compiler is free to do what it wants (within the bounds of still being C++). It is within the realm of possibility that a compiler could alter the value before the assignment.

The reinterpret_cast is essentially a contract between you and the compiler. You are saying "I want you, compiler, to treat this integer constant as a pointer to a byte without altering the value in any way. If you cannot do that you will inform me (warning or error)."

_uXe:
And to advance the pointer by 8 bytes for example, would "ptr = ptr + 8;" work, or is casting needed there too??

Good question. I believe adding an integer constant to a pointer results in a pointer in which case casting is superfluous.

That worked for me. It had not occurred to me that it might not.

This creates a byte pointer to the start of a struct

moveDataStruct moveData;
byte* ddata = reinterpret_cast<byte*>(&moveData);

and this iterates over the struct byte by byte to copy data into it

	for (byte n = 0; n < pcDataLen; n++) {
		inByte = Serial.read();
		*(ddata + n) = inByte;
		crcCheck = crcCheck ^ inByte;
	}

...R