This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Interrupt mechanism from ARM to DSP

Hi!

I'm working with the EVMK2H board (Rev 4.0), MCSDK v3.1.4.7 and IPC v3.36.02.13. I would like to implement a simple interrupt mechanism between the ARM and a DSP. What I have in mind is an equivalent of the Notify module but for IPC v3, that is to say that I'd like to be able to send an interrupt (or a message or anything) to a DSP so that its workflow is interrupted and it can handle the request before eventually returning to its previous work.

I read the IPC documentation and so far I didn't see anything close to this for all communications mechanisms seem to be blocking (like MessageQ_get). I believe I saw someone on this forum mentionning the mailbox process (I assume he was refering to the mpm mailbox) but I think it's also blocking.

I don't necesseraly need a high-level API to do so, if there's a way to trigger an interrupt by setting a bit in a register that would also be perfect. I just need the ARM -> DSP side.

So please if somebody could tell me if I missed something and/or point me to some relevant documentation on the subject it would be great!

Thanks in advance,

Thomas.

  • Here's an update: As far as I understand, I will be able to create custom interruptions on the DSPs by either using the CSL API or the HWI module of SYS/BIOS. What I can't find yet is how is it possible to trigger those interrupts from the ARM?

    Thanks!
  • K2H has IPC registers (Look at http://www.ti.com/lit/ds/symlink/66ak2h12.pdf at table 8-30, the IPC registers address start at 0x02620240) 

    To write to the physical address use mmap.  Look at the source code of devmem2 and see how to write (and read) to physical addresses

    Ran

  • Hi Ran!

    Thank you very much for the information, that looks exactly like what I need, I'll try this as soon as possible (before end of monday) and keep you posted!

    Thanks again,


    Thomas.

  • Hi!


    I read and tried a lot of things during the week-end and I think I'm getting pretty close to my goal. However it's still not working completely and I'm running out of ideas on the 'why'. Besides, I have a few questions remaining regarding the global interrupt mechanism:

    1. Based on Configuring interrupts on Keystone devices and this thread (and several others from this forum), I understand that the CSL module is used to configure the CIC, which is the chip interrupt controller and the HWI module is in charge of the INTC which is the DSP's own interrupt controller and the code snippets given are sufficiently explicit to use those modules.

    What I can only assume however, is the fact that the IPCGR directly triggers an event (id 105 on the 66AK2H according to the manual) and not a system interrupt, meaning that setting the first bit of this register to '1' will directly trigger the interrupt on the INTC (HWI module). Is that correct?

    If this is indeed true, the example provided by the above thread is not relevant since it's using the CSL module to catch the CSL_GEM_IPC_LOCAL interrupt. Moreover I've not been able to find the definition of this macro anywhere in the sdk nor have I been able to find a list of all system interrupts possible on the device.

    Based on the above, the following code should catch the interrupt raised by the IPC register:

    Hwi_Handle ipcgr_hwi;
    
    Hwi_Params hwi_params;
    Error_Block error_block;
    
    Hwi_Params_init(&hwi_params);
    Error_init(&error_block);
    
    hwi_params.arg = 1;
    
    // Set the event id of the peripheral assigned to this interrupt.
    hwi_params.eventId = 105;
    
    // Disable the interrupt for now.
    hwi_params.enableInt = FALSE;
    
    

    Are the above assumptions and code correct?

    2. On the ARM side, as you suggested, I should be able to write the IPGRN register accordingly to trigger the event. Here's the code I use:

    #define REG_BASE (0x02620000) // mmap requires offset to be aligned on a page frontier.
    #define KICK0 (0x38)
    #define KICK1 (0x3C)
    #define IPCGR_BASE (0x240)
    #define IPCGR(x) ((IPCGR_BASE + (x*4)))
    
    #define PAGE_SIZE 4096
    
    #define READ32_REG(x) (*((volatile uint32_t *)(x)))
    #define WRITE32_REG(x, n) (*((volatile uint32_t *)(x)) = n)
    
    int main(void) {
    
    	int dev_mem_fd = -1;
    	void *reg_base = (void *)-1;
    	
    	if ((dev_mem_fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0) {
    		perror("descriptor opening error:");
    		return -1;
    	}
    	
    	reg_base = mmap(0, PAGE_SIZE, PROT_WRITE | PROT_READ, MAP_SHARED, dev_mem_fd, (off_t)REG_BASE); 
    	if(!reg_base || reg_base == MAP_FAILED) {
    		perror("mmap failed:");
    		return -1;
    	}
    	
    	fprintf(stdout, "* Initial IPCGR(i) values:\n");
    	for (uint8_t i = 0; i < 8; ++i) {
    		fprintf(stdout, "  * %u 0x%x\n", i, READ32_REG(reg_base+IPCGR(i)));
    	}
    	
    	// Send interrupt to DSPs:
    	
    	/* 1. Unlock the Bootcfg MMR (memory mapped registers) in which
    	 * IPGR belongs. By default those registers are locked after boot time,
    	 * to unlock them two specific registers must be set with very specific
    	 * data :
    	 * see section 8.2.3.4 66AK2H specification.
    	 */
    	WRITE32_REG(reg_base+KICK0, 0x83e70b13);
    	WRITE32_REG(reg_base+KICK1, 0x95a4f1e0);
    	
    	/* 2. Send the interrupt. */
    	for (uint8_t i = 0; i < 8; ++i) {
    		WRITE32_REG(reg_base+IPCGR(i), 0x11); // HERE THE BIT SHOULD BE SET
    	}
    	// Commit changes to the mapped file.
    	msync(reg_base, PAGE_SIZE, MS_SYNC);
    	
    	/* 3. Relock MMR registers by writting anything else than the previous
    	 * sequences in the KICK0-1 registers.
    	 */
    	WRITE32_REG(reg_base+KICK0, 0x42);
    	WRITE32_REG(reg_base+KICK1, 0x1337);
    
    	fprintf(stdout, "* Final IPCGR(i) values:\n");
    	for (uint8_t i = 0; i < 8; ++i) {
    		fprintf(stdout, "  * %u 0x%x\n", i, READ32_REG(reg_base+IPCGR(i)));
    	}
    	
    	munmap(reg_base, PAGE_SIZE);
    }
    

    The problem is that the above code will produce the following result:

    * Initial IPCGR(i) values:
      * 0 0x0
      * 1 0x0
      * 2 0x0
      * 3 0x0
      * 4 0x0
      * 5 0x0
      * 6 0x0
      * 7 0x0
    * Final IPCGR(i) values: // Should have been 0x11
      * 0 0x10
      * 1 0x10
      * 2 0x10
      * 3 0x10
      * 4 0x10
      * 5 0x10
      * 6 0x10
      * 7 0x10
    

    Meaning that the one bit I want to set is not set. Moreover, the KICK0 and KICK1 registers don't seem to be written in the first place... Do you have any idea what I might be missing?

    3. Is the IPC register used by modules system (such as the IPC one)? I know it's also used at boot time, which is why I had to mask the interrupt in the first place. If that's the case, how can one use the SRCN bits of the register on the DSP to know where/why the interrupt is coming from?

    4. I've seen a lot of references to the GEM interrupt controller but I've not been able to find the definition of the GEM acronym.

    Thank you,


    Thomas.

  • Start from the end

    The name of the DSP core was changed during different versions of the DSP. It used to be called GEM, then when more hardware was added it changed the name to MEGA_MODULE, and finally with the introduction of C66 DSP the name was changed to CorePac, to illustrate that there is lots of hardware inside the DSP core.

    Now about the interrupts, this is somewhat a generic answer

    The first thing that I would do is to allocate the IPC register that generate event to Core 0, use CCS to toggle this registers to one and then use the acknowledge register to set it back to zero. (You can find the registers' address in the device data sheet)

    After this works for me will look at the DSP registers and the CIC0 registers and see what bit is set when the IPC register is on. This will tell if the interrupt is a primary interrupt to the DSP Core 0 or it goes through the CIC (or both). In the first case only local DSP events should be map into an interrupt line (and then ISR) in the second case the CIC should map system event to host channel (I think that this is what we call the output of the CIC, but I may be wrong, you will figure it out)

    If you understand how the mechanism is working, finding the csl function will be easier.

    Ran
  • Hi Ran!

    Thank you very much for the answers, I think I have a good insight on the global mechanism by now. I'll try what you suggest to very if setting the IPCGR bit triggers an event or a system interrupt. In the latter, I will be using the CSL functions described in the "configuring Interrupts on Keystone devices" guide.

    However, could you please clarify the following points:

    1. Is the IPC register used by modules system (such as the IPC one)?

    2. Do you have an idea why the IPCGR bit is not set by the ARM code I provided?

    Thanks again!

    Thomas.

  • Hi!

    Sorry for the delay of my answer...

    Here are the conclusions I've come to:

    • Setting the first bit of the IPC register trigers an event on the DSP's own interrupt controller (which means that the above code for catching it using only HWI is correct).
    • It obviously can be used to trigger interrupt from ARM to DSP and from DSP to DSP.
    • The unlocking of KICK0 and KICK1 registers doesn't seem necessary (the interrupt seems to be sent whether or not they are unlocked).
    • The IPC and MessageQ modules do use that register (especially the MessageQ_open/create/get functions). A quick workaround could be to only enable the interrupt after having creating/opening the queues and having a custom MessageQ_get function disabling the interrupt beforehand and re-enabling it after. MessageQ_put doesn't seem to trigger the event.
    • In the above code the IPC register is rightly set, the problem came from the interrupt not being correctly enabled. It seems like reading the IPC register always returns 0 for the first bit?

    Hope it can help other people! Thanks for your help,

    Thomas.

  • Can you close the thread please