M4/M0 communication

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

M4/M0 communication

1,774 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by JohnR on Tue Oct 01 18:47:14 MST 2013
Hi,

In my project using the LPC4350, M0 is used to get and integrate data over SGPIO from two ADCs. M4 is used to process and display the results.

Until today I have been using in the M4 code the statement LPC_CREG->M4TXEVENT = 0x1 to signal the M0_M4CORE_IRQHandler() in M0 to start a batch of measurements.

When this is complete M0 calls LPC_CREG->M0TXEVENT = 0x1; to signal the M0CORE_IRQHandler() in M4 that in turn starts the calculations on the received data.

In the manual, setting either of these two registers to 0x1 is supposed to have no effect, but it does certainly seem to work OK for me.

Today I replaced the LPC_CREG->M4TXEVENT and LPC_CREG->M0TXEVENT calls with __SEV() and the system still  works fine.

Could somebody please explain in the context of the LPC4350 what SEV, WFE, WFI, DMB and DSB instructions do and how they are used. Or point me to some documentation.

I have looked at the ARM site and not come away wiser so any help would be appreciated.

Thanks in advance,

John.
Labels (1)
0 Kudos
13 Replies

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by JohnR on Fri Oct 17 06:38:34 MST 2014
Hi Bavarian,

Such honesty is refreshing!

The LPC4370 chips are really amazing in their capabilities and my quibble was more of a question that you have now answered.

Thanks for the reply,

JohnR.
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bavarian on Fri Oct 17 04:21:59 MST 2014
Well, it just happened.  0:)

In early times of the development we planned the LPC4300 with 2 cores M4 and M0.
The second M0 slipped in a little bit "by accident". If we had clearly planned for the 3 cores then we would have implemented this in a more elegant way.
But at least you profit from this "accident" by now having a standard microcontroller with 3 ARM cores in it.

Regards,
NXP Support Team.
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by JohnR on Tue Oct 14 15:09:24 MST 2014
Hi,

While we are on the subject.

It does seem a pity that there are no specific separate interrupt numbers for M0App and M0Sub, instead of the common INT#1 raised by M4 through TXEV.

Going the other way, TXEV raised by M0App and M0Sub, do invoke specific responses.

In the first case, it seems that both M0App and M0Sub get woken up and any specific request has to guarded by a global variable. This works but seems clumsy.

Was there a reason for this?

JohnR.

0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArriaLive on Tue Oct 14 08:35:54 MST 2014

Quote: TheFallGuy
Because This is an NXP chip and not a bit of IP from ARM. ARM do not sell a dual core m4+m0 device, so NXP have created their own. The way NXP have chosen to do this is as described in the documentation - they have wired it to an IRQ.



Aha!  That's what I suspected.  To be precise, however, the __WFE() and __SEV() instructions were specifically created by ARM as part of the ARM architecture for multi-processor systems.  The NXP implementation is actually not precisely to the ARM spec.  That's ok, as long as we're all clear on that decision by NXP and as long as the NXP documentation is clear enough about the fact that WFE does not work as specified by ARM (that could be clearer...).


Quote:
The main difference is that for WFE even interrupts before the WFE set the event flag, so WFE doesn't wait.
With WFI if the interrupt occurs before the WFI the WFI doesn't wake up.



Starblue, that is an excellent point of differentiation, and is probably the best reason to use WFE instead of WFI in my particular case.

Thanks to both of you for your help and clarifications!
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by starblue on Tue Oct 14 01:06:57 MST 2014
The Definitive Guide to ARM Cortex -M3 and Cortex-M4 Processors contains a discussion of the fine points of WFI vs WFE.

The main difference is that for WFE even interrupts before the WFE set the event flag, so WFE doesn't wait.
With WFI if the interrupt occurs before the WFI the WFI doesn't wake up.
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Mon Oct 13 12:31:33 MST 2014
Because This is an NXP chip and not a bit of IP from ARM. ARM do not sell a dual core m4+m0 device, so NXP have created their own. The way NXP have chosen to do this is as described in the documentation - they have wired it to an IRQ.
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArriaLive on Mon Oct 13 11:48:21 MST 2014
Thank you for your response.


Quote:
Quote:  Does this not answer your question?



Well, yes, sort of.  I've read that before, but it raises one more question.  According to ARM documentation, the difference between the __WFE() and the __WFI() instructions are that the __WFE() suspends operation of the core until the same things happen on the __WFI(), OR the __SEV() instruction is sent from another core:


Quote:
From the ARM documentation: 
If the event register is 0, WFE suspends execution until one of the following events occurs:
[list]
  [*]an exception, unless masked by the exception mask registers or the current priority level
  [*]an exception enters the Pending state, if SEVONPEND in the System Control Register is set
  [*]a Debug Entry request, if debug is enabled
  [*]an event signaled by a peripheral or another processor in a multiprocessor system using the SEV instruction.
[/list]
If the event register is 1, WFE clears it to 0 and completes immediately.



Compare with the __WFI() instruction:

Quote:
From the ARM documentation:  WFI suspends execution until one of the following events occurs:
[list]
  [*]an exception
  [*]an interrupt becomes pending, which would preempt if PRIMASK was clear
  [*]a Debug Entry request, regardless of whether debug is enabled.


[/list]

So, here's the question:  if __WFE() requires an interrupt to wake up the M0, why is that instruction even necessary?

I can, of course, implement an interrupt, but the ARM documentation suggests that may not be necessary.  With the __WFE() instruction shouldn't I be able to just build a simple main() loop like this one (no interrupt required)?:

int main() {
  while (1) {
    while (!bufferempty()) {
      dostuffwithbuffer();
    }
    __WFE;     //Wait for next __SEV() event from M4.
  }
}
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by TheFallGuy on Mon Oct 13 00:27:10 MST 2014

Quote:
This bit in turn is hardwired to the interrupt logic of the other core IP and will generate an IRQ.


and

Quote:
Does the NVIC or the Event Router have to be configured somehow (no, I have not yet enabled interrupts).


Does this not answer your question?
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by ArriaLive on Sat Oct 11 23:10:08 MST 2014
I know this thread is a couple years old, but I'm having a little trouble with the __SEV() and __WFE() instructions:  The LPC43xx documentation, the ARM website, and this conversation suggest that when using a __WFE() instruction on the M0, the M0 goes to sleep (default is sleep mode), and is awakened by an __SEV() instruction from the M4.  John's implementation seems to work, but mine doesn't.  Am I missing a setting?

More info:  In my application, the M0 runs a simple loop that checks a queue for a new entry.  New entries are placed in the queue by the M4.  This handshake works just fine.  But since the queue is empty more than it is full, I'd like to just put the processor to sleep in the loop, then wake up when a new entry is in the queue.  So, in the M0 loop I include the __WFE() instruction to let it nap, and then in the M4, when something is placed in the queue, I call the __SEV() instruction.  That __SEV() should wake up the M0 and continue the loop, right?

But for some reason the M0 doesn't wake up on the __SEV() instruction.  If I use the debugger to pause and continue the M0 processor, that wakes the M0 up, runs the loop once for any existing queue entry, then goes back to sleep again and won't wake up unless I create a debug event again.  The __SEV() instruction on the M4 is not waking up the M0 on its own.

Does the NVIC or the Event Router have to be configured somehow (no, I have not yet enabled interrupts).

Thanks,
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bavarian on Wed Oct 02 08:19:41 MST 2013
Hello John,

well, in terms of "event clear" writing a '1' has indeed no effect  0:)
The event flag is still there and the IRQ appears again after leaving the ISR.

But you're right. We need to mention it somewhere in a clear way.

Regards,
NXP Support
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by JohnR on Wed Oct 02 06:36:42 MST 2013
Sorry for a second post.


Quote:

As you have already experienced, the interrupt on the M0 is caused by an event from the M4, latched into the register M4TXEVENT.



What I meant to say is that the manual is wrong when it says that writing a 1 to the register has no effect.

Maybe the entry should say that it does cause an interrupt but that its use is deprecated in favour of SEV?

John.
0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by JohnR on Wed Oct 02 06:30:14 MST 2013
Thanks so much for the fast and useful reply.

I ran into this problem trying to debug my dual M4/M0 system when M4 is running FreeRTOS and lwip_1.4.0, using some stripped down httpserver-netconn code. The idea is that massaged data from M0 will be sent to a remote site but right now netconn just sends some hard coded strings.

If I turn off MO by not calling __SEV(), the lwip code works fine. If M0 is running the function, tcp_input() in the lwip code, seems not to be able to find a PCB and so then returns RST.

Any thoughts again are most welcome.

John.


0 Kudos

1,299 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by bavarian on Wed Oct 02 05:05:35 MST 2013
The Wait-for-Interrupt or Wait-for-Event instructions put the Cortex-Mx into stop mode (ARM core is stopped, not the LPC4350!).
As this causes an immediate stop there might be the wish to finish bus transfers which were initiated with the last instruction (e.g. read from external memory). This can be achieved with a DSB instruction. See explanation of DMB and DSB at http://www.keil.com/support/man/docs/armasmref/armasmref_CIHGHHIE.htm.

The SEV instruction triggers a hardware signal from the Cortex-Mx IP to '1'. In the LPC43xx this signal is routed to an event logic in the CREG domain, causing MxTXEVENT set to '1'.
This bit in turn is hardwired to the interrupt logic of the other core IP and will generate an IRQ.

As you have already experienced, the interrupt on the M0 is caused by an event from the M4, latched into the register M4TXEVENT. Writing a '1' into this register is effectively doing the same thing, but the mechanism with SEV is doing things a little bit more synchronized to the system clocks. I think it's possible to run into race conditions if you do it by writing to the register directly.

However, it's doing the same thing, we recommend to use the SEV instruction.

Hope this clarifies you question,
NXP Support





0 Kudos