Inter-Processor Communication between ARM & DSP
I've been working on a MityDsp L138F board with Linux Ångström run by the ARM core. I'm expected to learn and implement various possible IPC methods to make the cores communicate with each other.
- I've successfully implemented the "DSP Hello World" example provided in the wiki, which uses DspLink as well as the ARM running Linux.
- I'm also able to reserve a region in the DDR2 memory as a shared field, and read and write this region with ARM and DSP without an OS running, in order to pass data between the cores.
I have a few questions on this:
- Documentation of DspLink states that the ARM core must be running a HLOS (e.g. Linux) and the DSP core an RTOS (e.g. DSP/BIOS). But in that example, I didn't have to install an RTOS on the DSP; I just built a DSP/BIOS project for C6748, and that's it. Isn't DSP/BIOS something I was supposed to install on the DSP (not just on the host PC)?
- TI says DSP/BIOS and DspLink are no longer up-to-date and recommends using SYS/BIOS (a.k.a. TI-RTOS Kernel), SysLink, and possibly IPC 1.x instead, in the IPC options page, but I still don't know if and how SYS/BIOS is supposed to be installed on the DSP.
Also, does MityDsp support SYS/BIOS, or should I stick with DSP/BIOS? (Because I tried to go with the TI-RTOS Workshop and I couldn't even manage the very first lab.)
- This article lists some DspLink modules including MSGQ, NOTIFY, and RINGIO, but the "DSP Hello World" tutorial mentions none of those. Are they available as well?
- Finally, are there any other ways you think I should be testing?
Thank you in advance.
Here is some feedback regarding your questions:
- DSP/BIOS is the RTOS that runs on the DSP. However, unlike an OS like Linux, which needs to be installed, DSP/BIOS does not. I believe it is simply compiled into the .out file created when you build a DSP project.
- Althought TI is no longer supporting it, we currently recommend using DspLink and DSP/BIOS. A portion of the functionality offered by our MDK is built around this ARM/DSP communicatios method.
- The MDK functions you used when going through the "DSP Hello World" example were wrappers around the MSGQ method of utilizing DspLink. The source is available in our MDK if you want to modify the communication method, but it is the only method we currently provide support for.
- I cannot think of anything else for you to be looking into at this point. If you do find the functionality provided by DspLink and our MDK to not be sufficient for your needs please let us know so we can provide advice, or at least give a rough estimate as to the effort required in going down a path such as switching to SysLink.
Thanks for your response. My first question was really confusing me, so thanks for the explanation.
Considering neither Critical Link nor TI technically supports DspLink anymore (you provide your own functions instead, and they urge to upgrade), I'll give SysLink a shot. If that turns out fruitless, then I'll have to switch back to DspLink.
Thank you again.
As a qualification I want to mention that DspLink is the communications and control method Critical Link supports and recommends using at this point. Our MDK provides wrappers around DspLink for loading the DSP via the ARM and communicating via DspLink MSGQs. We have not had any issues with DspLink being the core for our communications and control, evening though TI encourages users to upgrade.
Let us know if you have any questions, though our ability to help with SysLink related questions may be limited.
The communication method Critical Link provides is great; the code was easy to follow and I understood most of it.
The problem is that it supports only message buffers, but we may need to use "shared memory" communications as well (available as the "POOL module" in DspLink, and "Memory" in SysLink. I tried accessing a shared region in RAM by using pointers, but as expected, Linux doesn't allow me for safety. At work, I was told to test all possible means of IPC, so we could consider all our options once the project starts.
I tried configuring SysLink yesterday, but I got stuck in the first step and opened a thread in TI's E2E forum, and they haven't responded yet.By the way, I also noticed some time ago that there is a DSP Binary message template in your wiki, but I didn't quite understand the provided code because it is incomplete.
- Why should I use a
unionto combine message headers and content? (I thought
unioncouldn't hold more than one of its members at a time.)
- I suppose the inbound message handler at the end of the page must be inserted to both ARM and DSP codes; is that correct?
- I was using
sprintfto convert integers to strings and vice versa and sending numerical values as strings rather than binary messages. Would using this template be more sensible and efficient (since converting integers to char strings occupy more space)?
I consulted to my colleague. It turns out, we don't insist on using SysLink instead of DspLink. But we definitely need a shared memory mechanism where the DSP writes some data to the memory, send an interrupt to the ARM, and the ARM does the rest.
Regarding your need for the ARM to read memory written by the DSP there is a function call ReadMemory() in the ARM tcDspApp class. If you setup a structure where the DSP uses DspLink to communicate an address the ARM is to read from, the ARM can then use ReadMemory to access that data. One caveat to be careful of when sharing memory between the DSP and ARM is to make sure you cache flush appropriately (i.e. the DSP should flush its cache for the memory region it is going to share with the ARM so that the ARM is not potentially reading stale data).
Regarding your previous message:
- If you want to set aside a shared region in RAM and have the DSP and ARM both access it, that is possible. On the ARM side you would need to use /dev/mem to provide proper address/pointer translation (i.e. physical to virtual). (As mentioned above, appropriate cache flushing will be key to make sure you application runs as desired).
- Regarding your question on the union example given in the "DSP Binary message template" page, the union was created to allow for interpreting one chunk of data in multiple ways. Essentially you get a message, but you don't know what the message type is. You access the header information via the union to determine this (each message type must have the same header layout), and then based on that access the appropriate union entry is used to inteprete the payload appropriately.
- If your system needs bi-directional communication between the ARM and DSP, both the ARM and DSP will each need inbound message handlers.
- Unless your application gains a benefit or has a requirement that strings be transmitted, it is more efficient to communicate binary integer data.
Thanks for your reply.
dspapp.cpp in the MDK, and noticed
ReadMemory() is a simplified version of the
PROC_read() function of DspLink. About the function arguments:
void* DspAddr: What is the physical address of DSP that I should be reading from ARM? I've read the Cache and Memory page in the wiki, which says:
The Critical Link supplied .tci files include default sets of settings for these platforms. The L138 module sets the memory map to reserve 96MB for the ARM from 0xC0000000 to 0xC5FFFFFF, and 32MB for the DSP from 0xC6000000 to 0xC7FFFFFF.
Are these addresses the same ones I refer to in das U-Boot, such as "
bootm c0700000"? Should I assign this parameter something between 0xC6000000 and 0xC7FFFFFF?
void* DestAddr: Explained in the code as the "virtual address of destination". What does this mean?
ReadMemory() enables the ARM to read from the DSP's memory, but how am I supposed to fill this memory through the DSP? Should I simply declare pointers that point to the addresses from 0xC6000000 to 0xC7FFFFFF, and fill those values? Also, how should I flush the cache?
PROC_read() are pretty similar, I also examined the latter, which led me to the "READWRITE" example provided in TI's DspLink User Guide. They use
PROC_write() in order to read from and write to the DSP memory, but the syntax is too complicated, at least to me. Their ARM code is full of functions like "
NORMAL_API DSP_STATUS RDRW_Execute()" and the main function is somehow "
RDRW_Main", which I have no idea how the compiler knows to start from there. Anyways, it'll be better if I stick to the Critical Link's version.
I know I asked a lot, but I'm a newbie, so please be patient with me.
- Q: void* DspAddr: What is the physical address of DSP that I should be reading from ARM?
- A: This depends on how you structure your application. One example would be having the DSP allocate a chunk of heap data and filling it with something for the ARM the read. The ARM then supplies the pointer for this heap space (as seen by the DSP) as the DspAddr argument to ReadMemory()
- Q: Are these addresses the same ones I refer to in das U-Boot, such as "bootm c0700000"?
- A: Yes. These addresses are physical addresses. Physical addresses in the range 0xC0000000 to 0xDFFFFFFF correspond to RAM access. You will need to manage how RAM is utilized across your system and that there are no unwanted overlaps (i.e. the DSP BIOS should be assigned memory regions using the tcf/tci platform files, and this should not overlap the memory ARM Linux is using). Also, as a caveat, note that you should be aware of how much memory your L138 is configured with. 0xC0000000 to 0xDFFFFFFF allows you to address up to 512 MB of RAM, but if your chip is smaller than that (i.e. 128 MB or 256 MB) trying to address the upper regions of this space will cause you to loop back and potentially access data that is being used by DSP BIOS or ARM Linux.
- Q: void* DestAddr: Explained in the code as the "virtual address of destination". What does this mean?
- A: I recommend the following resources for gaining a better understanding of virtual addressing:
- Q: how am I supposed to fill this memory through the DSP?
- A: That is up to you. You can allocate heap pointers in the DSP and simply use that as the DspAddr argument (as mentioned above). You can also set aside a section of RAM that is not specified to be used by Linux or the DSP and have that be a shared memory space. Your example of using 0xC6000000 to 0xC7FFFFFF could be valid, but only if you can guarantee that this memory is not being used by the DSP BIOS or ARM Linux.
- Q: how should I flush the cache?
- A: Refer to the BCACHE_* instructions in the DSP BIOS 5.x API http://www.ti.com/lit/ug/spru403s/spru403s.pdf