MOD54415 sending UDP packet from IRQ7 ISR routine

for everything else
Post Reply
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

MOD54415 sending UDP packet from IRQ7 ISR routine

Post by jediengineer »

I'm trying to do the impossible, the forbidden. I'm trying to send a tiny UDP packet from an IRQ7 interrupt function. I've created a circuit that raises the IRQ7 pin high when the circuit board voltage drops below a certain level (Undervoltage Lockout or UVLO). What I've been able to do in the interrupt function (just experimentation) is actually get out 1-2 printf statements and call the assembly "HALT" prior to the filter capacitors on the board actually draining too low that the DC converters shut off. To test this I've just unplugged the power cord at the board. Works every time. What I'd like to do is send a UDP packet out instead of a printf statement. Considering that printf is notoriously slow, I figured a UDP packet would be much faster and I should have enough power to pull off sending just one packet with a 4 byte payload. That being said, I'm not extremely well versed in network protocols so I'm reaching out to the community.

Currently, I have declared a global UDP packet in my namespace, and a function is called from the namespace at bootup that sets up the UDP packet:

Code: Select all

// GLOBAL - for reference:
UDPPacket IRQ7packet;
 
void IRQ7_packet_setup()
{
     IRQ7packet.SetSourcePort(source_port);
     IRQ7packet.SetDestinationPort(destination_port);
     IRQ7packet.AddDataWord(IDENTIFICATION);
     IRQ7packet.AddDataWord(IRQ7_FAULT);
}

That being said, I know I run into a privelage violation by calling "IRQ7packet.Send(ipaddr);" from the IRQ function. I tried setting up a task with a priority of "MAIN_PRIORITY - 10" and posting a semaphore, but that doesn't work. Is there a way to manually create and send a packet from within the IRQ7 ISR? My other concern with using a an OS task is that I'll ahve to wait for the current task to complete before the pending semaphore is answered. Anyone got any better ideas? Thanks!
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: MOD54415 sending UDP packet from IRQ7 ISR routine

Post by rnixon »

How about setting up the packet ahead of time, so the irq7 only posts the semaphore, and your highest priority task is only a pend and send udp packet? An interrupt will call the scheduler, so after the irq7 returns, the highest task ready to run will run, so you do not have to wait for the task that was running before the irq7 to complete. This is a point I think is very easy to miss. I see posts about increasing the time ticks because they "want their tasks to switch faster". That's not true. In fact, it will slow things down a bit since you can't switch tasks while inside an isr, and if you increase time ticks you increase the amount of time your are in the timer isr.

There is probably a better solution to your issue than what I describe here, because even if you start executing your high priority task to send the packet, timing will vary because other interrupts can occur and preempt that task. I don't think you can wrap the send in a critical section, since the ethernet processing needs interrupts. Probably need to experiment a bit. Maybe toggle some an unused gpio signal in your task that pends and sends to see how consistent it is in time.
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

Re: MOD54415 sending UDP packet from IRQ7 ISR routine

Post by jediengineer »

rnixon wrote:How about setting up the packet ahead of time, so the irq7 only posts the semaphore, and your highest priority task is only a pend and send udp packet? An interrupt will call the scheduler, so after the irq7 returns, the highest task ready to run will run, so you do not have to wait for the task that was running before the irq7 to complete. This is a point I think is very easy to miss. I see posts about increasing the time ticks because they "want their tasks to switch faster". That's not true. In fact, it will slow things down a bit since you can't switch tasks while inside an isr, and if you increase time ticks you increase the amount of time your are in the timer isr.

There is probably a better solution to your issue than what I describe here, because even if you start executing your high priority task to send the packet, timing will vary because other interrupts can occur and preempt that task. I don't think you can wrap the send in a critical section, since the ethernet processing needs interrupts. Probably need to experiment a bit. Maybe toggle some an unused gpio signal in your task that pends and sends to see how consistent it is in time.
I've already done that - It didn't work. This is called from UserMain at startup:

Code: Select all

void IRQ7_packet_setup()
{
	using namespace squirrel;
	/// IRQ 7 UVLO protection will send the following packet.
	IRQ7packet.SetSourcePort(source_port);
	IRQ7packet.SetDestinationPort(destination_port);
	IRQ7packet.AddDataByte(ID_NUM);
	IRQ7packet.AddDataWord(0x1427);
}
This was my task setup:

Code: Select all

	OSSemInit( &IRQ7_SEM, 0 );
	OSSimpleTaskCreatewName(IRQ7_packet_sender, MAIN_PRIO - 10, "IRQ7 Packet Sender");
And that would call a function that comprised of:

Code: Select all

IRQ7packet.Send(ipaddr);
asm("HALT");
which never gets called. I'm assuming that this is because the scheduler allows the current interrupted task to finish running before it addresses the IRQ7 semaphore? Unless MAIN_PRIO -10 is insufficient? Is there a way to kill all tasks before returning from the interrupt routine? Or some way to get the scheduler to immediately switch to this task of sending? Maybe encasing the "Send" function with "USER_ENTER_CRITICAL" could prevent other interrupts or tasks from switching?
rnixon
Posts: 833
Joined: Thu Apr 24, 2008 3:59 pm

Re: MOD54415 sending UDP packet from IRQ7 ISR routine

Post by rnixon »

>I've already done that - It didn't work. This is called from UserMain at startup:

Make it simpler. Write a totally new app, then start small and build on it.
- UserMain only with a global packet declaration, function to setup packet parameters, function to send and halt. Note that you probably need to add a delay before the halt to give the packet time to go out.

- Now modify to use multiple tasks and a semaphore. Trigger the semaphore with something like stdin getchar() in the posting task.

- Now add interrupts

Code: Select all

IRQ7packet.Send(ipaddr);
asm("HALT");
>which never gets called.
How do you know? Just because you don's see the packet doesn't mean it isn't getting called. Toggle a gpio or led to verify.

>I'm assuming that this is because the scheduler allows the current interrupted task to finish running before it addresses the IRQ7 semaphore?

Absolutely not, unless the current interrupted task is a higher priority

>Unless MAIN_PRIO -10 is insufficient? Is there a way to kill all tasks before returning from the interrupt routine?

Then the system will not be able to do anything

>Or some way to get the scheduler to immediately switch to this task of sending?

If your priorities are set correctly, that is exactly what will happen as far as user created tasks go. Not sure what other higher priority tasks will get called to actually send the packet. They are listed in constants.h. At a minimum it looks like these two need to run in order to send your packet:
#define IP_PRIO (39)
#define ETHER_SEND_PRIO (38)

>Maybe encasing the "Send" function with "USER_ENTER_CRITICAL" could prevent other interrupts or tasks from switching?

If the tasks that are necessary for the network stack to operate cannot run, your packet will never go out. This isn't like sending something out a serial port. A lot of stuff needs to occur to get the packet out.
User avatar
dciliske
Posts: 624
Joined: Mon Feb 06, 2012 9:37 am
Location: San Diego, CA
Contact:

Re: MOD54415 sending UDP packet from IRQ7 ISR routine

Post by dciliske »

Ok, I've got a few questions:
  1. Do you know the destination IP address when you create the IRQ7 packet?
  2. If you know the destination IP, do you also know the hardware MAC address?
The problem with trying to just send a packet from your level 7 IRQ is that when it gets down to the bottom of the world, it's possible that the ethernet hardware is saturated. The driver would normally block at this point and wait until resources are available, but since this is a level 7, I think that the transmit function will just blow through the section to load the packet into the send queue as there is no space and ends up dumping it on the floor. This is, of course, assuming that your destination is in the ARP cache. If it's not, then the stack would need to transmit and receive an ARP message to determine where to send the packet.

Basically, my thought on the matter is that if you *really* want to get this packet out the Ethernet, you will need to construct the complete raw frame and manually insert it into the Ethernet driver (not even using TransmitBuffer). This is an entirely doable thing; I'm just not sure whether this is a reasonable thing given the time cost involved. Hell, I think even for Paul or I, this would be a bit of a challenge and we wrote the damn thing!
Dan Ciliske
Project Engineer
Netburner, Inc
jediengineer
Posts: 192
Joined: Mon Dec 17, 2012 6:24 am

Re: MOD54415 sending UDP packet from IRQ7 ISR routine

Post by jediengineer »

dciliske wrote:Ok, I've got a few questions:
  1. Do you know the destination IP address when you create the IRQ7 packet?
  2. If you know the destination IP, do you also know the hardware MAC address?
The problem with trying to just send a packet from your level 7 IRQ is that when it gets down to the bottom of the world, it's possible that the ethernet hardware is saturated. The driver would normally block at this point and wait until resources are available, but since this is a level 7, I think that the transmit function will just blow through the section to load the packet into the send queue as there is no space and ends up dumping it on the floor. This is, of course, assuming that your destination is in the ARP cache. If it's not, then the stack would need to transmit and receive an ARP message to determine where to send the packet.

Basically, my thought on the matter is that if you *really* want to get this packet out the Ethernet, you will need to construct the complete raw frame and manually insert it into the Ethernet driver (not even using TransmitBuffer). This is an entirely doable thing; I'm just not sure whether this is a reasonable thing given the time cost involved. Hell, I think even for Paul or I, this would be a bit of a challenge and we wrote the damn thing!

rnixon, I'll try the delay and see if it helps, and I'll change the priority a little higher on the task creation. But I'll have to give up if that doesn't work.

Dan, it was requested of me that I at least try to get a simple 4 byte payload out the door before the power falls off. I managed to get a printf out, which tells me that there's a chance I could possibly get a packet out. But if not, it's not the end of the world. I'm going to try what rnixon suggested, and if it doesn't work, I'll pass the info to the boss that it won't happen. If they insist, I'll seek your guidance for sure.

The destination doesn't change - all my transmissions are to a static IP address. I could understand the driver blocking while in an IRQ7 routine... I guess my question is to find the fastest way to dump the packet I made onto the network. Will the system delete the packet if I create it at startup as I did, and not send it until power-down? And for that matter, if I call ForceReboot - will it free the memory of that packet or will it just create another at startup?
Post Reply