The RAM is shared, therefore the method of access and communications is up to your specifications.
What you can do is find a way to protect that memory from other use by making sure that the heap and stack are never placed in that region; really by defining that region in your build process as a DATA segment which is not usable for heap, stack, or program memory.
Next as far as communications go. Having interrupts is helpful you just need to agree on the terms, which interrupt overrules, and so forth. I've never used interrupts. Instead that region was memory mapped where both sides built their software using the same reference file. Actually in my case it's typically always been a bank of DSP's having shared memory and Linux or other OS on the other side. However the concepts are still the same. The mapping of the region was generally driven by the technology side which was closest to the requirements, however it was a negotiated mapping in that either side could request that a set of bytes be declared in a certain way.
The main parts of these concepts are the following:
- Each side had a section it could only write too
- Each side had a section it could on read from
- The Read section for one side corresponds to the write section for the other side, and vice versa
- ADVANCED: If there was a section where both sides could read and write too, ownership of that segment was done via a set of rules involving the write-only and read-only sections
By that last point I mean that there was a set of rules. If one side wished to attain ownership of the common read-write section; it would assert a location in it's write-only section; which in turn would be a read-only section for the other side. The side receiving the request would acknowledge, or not that request. One of the two sides would be considered the master, and both sides would time-out on requests and either have to retry or cause a fault because they'd been forced to wait too long.
Say the following exists:
Side A WRONLY region is 0x4000-0x7FFF and this is RDONLY for Side B
Side B WRONLY region is 0x8000-0xBFFF and this is RDONLY for Side A
Common RW region starts at 0xC000.
First byte is "other region common write request"
Second byte is "grant request to other region"
Side A writes 1 to first byte @WRONLY=0x4000
Side B reads 1 at first byte @RDONLY=0x4000
Side B write 1 to second byte @WRONLY=0x8001
Side A reads 1 at second byte @RDONLY=0x8001
Side A now can write to the common RW region freely. Once A is done it should de-assert the first byte to close it's request.
I actually recommend that you stay away from common RW segments if you can. The implementations I've done have always been defined such that one segment is WRONLY for Side A and RDONLY for Side B and another segment is the reverse. The segments don't have to be the same size; they just have to be defined commonly for both code implementations. And then one can always only write to one segment and always only read from another segment. Many times one location is used to indicate "new data".