View previous topic :: View next topic |
Author |
Message |
fly28
Joined: 11 Feb 2017 Posts: 9
|
stopping process in PIC18F4550 |
Posted: Sat Feb 11, 2017 11:47 am |
|
|
I have a data acquisition project with 18F4550. Everything is going well, it's connected to the PC via USB.
The problem is that sometimes data acquisition process lasts several minutes and I want to stop it with a command from computer but the computer is locked until the 18F4550 finished. I thought about using an interrupt but I do not know how to transmit the interrupt to the circuit via USB and how 18F4550 to manage interrupt. Any suggestion is welcome and I want to thank those who read (and respond) to my topic. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19494
|
|
Posted: Sat Feb 11, 2017 1:12 pm |
|
|
This is down to badly written code....
There is no reason for the PC to be 'locked' just because the PIC is performing data acquisition. Think how everything on your PC would be if this was the case for all the things it normally does?. |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Sun Feb 12, 2017 1:37 am |
|
|
My apologies for the incorrect expression. The program is blocked when it receives data via USB. If 18F4550 need to take 600 samples for 5 minutes then, this time, I can not stop sampling unless I disconnect the USB cable. The same thing happens when 18F4550 should order something (LED, other devices) for a long time and I want to stop earlier order. Other PC applications go smoothly all time. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19494
|
|
Posted: Sun Feb 12, 2017 3:25 am |
|
|
Just have your program have an option to send a 'stop' command.
Seriously the USB, even if you are just running as a CDC device, can happily send/receive many hundreds of kB/sec. It's not exactly rocket science to have the receive code, do a test for some unused character (commonly something like ETX), and have the code stop if this is received. |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Mon Feb 13, 2017 11:49 am |
|
|
The program uses the HID driver (I use Microchip's VID and have a sublicense for PID ). To send a command to the chip the program creates a package that contains a byte for command's code (let's say 15 for setting output port) and other bytes for parameters or data . My program had already an instruction "Reset All" that works OK when the chip is in condition "static" (outputs are ON or OFF but do not change, does not read inputs). Reset All instruction calls "reset_cpu ()" according to the instructions set CCS. If the chip does something (read input data, take samples or send data to the outputs) then it does not accept any command (even reset_cpu () ) until ends what it has to do. After finishing previous order then takes the new order , even reset_cpu (). This is not a project like "click button and light the LED ." I thought I would use an interrupt but have not found an example of how to send an interrupt via USB and how to process 18F4550 the interrupt . |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 13, 2017 12:35 pm |
|
|
The CCS HID example program, ex_usb_hid.c, shows that in the main
loop of your program, you could put a test for usb_kbhit() and check if
you have a packet. Then if you have a packet, get it, and act on the
contents. Why can't you put something like this in your program ?
Why does your program have to "go away" for 5 minutes on a data
sampling mission ? Can't you call the following type of code periodically
in your data sampling code ? Then exit the data sampling iroutine
if you get a command to do so. You could return a status code from
the data sampling function telling your main() code that an abort has
occured.
The following code is from ex_usb_hid.c:
Code: |
if(usb_kbhit(USB_HID_ENDPOINT))
{
usb_get_packet(USB_HID_ENDPOINT, in_data, USB_CONFIG_HID_RX_SIZE);
if(in_data[0] && in_data[1])
{
LEDS_RED();
} |
If you believe you can't do this within your sampling routines, then post
or describe your sampling routines. Explain why no checking of usb_kbhit
can be tolerated within the routines. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19494
|
|
Posted: Mon Feb 13, 2017 1:37 pm |
|
|
It's worth perhaps realising that the USB driver _will_ be calling it's interrupt. Worst case no slower than about 100* per second. This is happening all the time (required for USB to be correctly handled). As PCM Programmer says, just test for a command arriving to say 'stop'. If your host system never sends anything while it is waiting, then the kbhit itself can be your interrupt.
Understand that an 'interrupt', does not allow you to go somewhere else in your main code. An interrupt handler always returns you to where it was called from. If your code needs to break out of an operation, then you code needs to have the routine(s) in it to allow it to exit when something happens, testing a flag or something similar. This can be kbhit as easily as anything else.
Every single serious programmer here will have written many routines to do exactly this, coming out to setup menus, or exiting operations, when a trigger is seen. |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Mon Feb 13, 2017 2:33 pm |
|
|
@ PCM programmer , thank you for your response.
So, I inserted two lines of code in the program:
Code: | if (usb_kbhit (1)) {
usb_get_packet (1 in_data, 64);
if (in_data [0] == 25) { // this
reset_cpu (); } // and this |
and I wiped out the line below which reset the CPU. I tested the program with this modification and is Ok, it resets the CPU in static conditions. But if the CPU does something (as I wrote above) then it doesn't reset, it keeps his job until the end. I entered into debug mode of the PC program, including the HID module and all instructions of sending data via the USB are executed, reset command is sent but unexecuted.
About "sampling mission" - is just one example of many. The question remains why can not stop the processor when it is in a procedure ? |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Mon Feb 13, 2017 2:44 pm |
|
|
@ Ttelmah Thank you for your responses
I do not need to jump somewhere else in the program (to "goto" ). I need to "break" the program somehow. I was thinking about interrupts because as another way to stop the CPU, since the above procedure does not work. I have no way to test a flag, the idea is to stop the CPU from the PC program. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 13, 2017 2:53 pm |
|
|
Quote: | The question remains why can not stop the processor when it is in a procedure ? |
Maybe because you are not calling usb_task() ? Which you should do. |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Mon Feb 13, 2017 2:57 pm |
|
|
a bigger portion of the code:
Code: |
while (TRUE) {
usb_task();
usb_debug_task();
if (usb_enumerated()) {
if (usb_kbhit(1)) {
usb_get_packet(1, in_data, 64);
if(in_data[0] == 25){ // this
reset_cpu(); } // and this
.
.
. |
|
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Mon Feb 13, 2017 3:01 pm |
|
|
Your approach to the issue is very "brutish"; sort of like shooting the transformer on the power pole because you want to turn off the lights in your house. That will certainly accomplish your goal, but it's not the best way.
You need to very carefully think about how you have structured your program. You say that your processor has some sort of measurement task that can take a long time. The way you've coded it now is obviously in the "blocking" style, and is something that most experienced embedded programmers avoid like the plague. That is, keep doing "this" until it's done, and then make yourself available to do something else.
This is how I would structure what you're doing. Most measurements aren't one-after-the-other rapid-fire format. There's usually some delay between them. Whatever that delay is, I'd set up a timer to interrupt (fire) at whatever this interval is. If the timer fires, and it's also okay to get a measurement, then get that measurement. Once a measurement is taken, see how many measurements you've performed so far - if you've hit whatever your target number is, then "it's now not okay to get a measurement". You can also disable the timer too, if you haven't "overloaded" the timer to take care of other things.
So you'll have a timer interrupt and in the main loop of your code, you'll have a test to see if the timer has fired, and another test to see if it's okay to do a measurement. If both conditions are true, go ahead and perform a measurement, and then see if your running tally of measurements has hit your magic number that you require.
In addition, your main loop would also have another test to see if any incoming serial traffic has arrived (in your case via the USB link to a PC). That loop can also do work. In your case you want to test to see if the PC has sent the ALL STOP command. If you receive this command, then "it's now not okay to get a measurement" and your program will stop taking measurements.
Again, very carefully consider what you want to do and start to think about how you can accomplish this via non-blocking code. |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Mon Feb 13, 2017 3:30 pm |
|
|
@ newguy
It is indeed a brutish style and somehow you understood a part of the problem, namely the data acquisition. But my program can also generate signals ( acts as functions generator or , another example, can command four stepper motors, or other cases). These commands can be for microseconds, seconds, minutes or even days. The idea with the timer (for small times) is interesting and I will study. On the other hand a timer introduces some errors; now the program can generate a pulse of 11 microseconds followed by a break, let's say 377 ms and this in a cycle repeated of 47563 times (it's a stupid example, but I tested the project with laboratory instruments and do these ). However, the 18F4550 program memory is used at 90%, I do not have much space for changes. |
|
|
newguy
Joined: 24 Jun 2004 Posts: 1907
|
|
Posted: Mon Feb 13, 2017 3:46 pm |
|
|
What you're doing can be refactored into an interrupt-driven format. Almost all PICs have multiple timers - you can use one to generate your output pulses, and this really isn't difficult. If timing on the pulses is absolutely critical, then you'll have to investigate high priority interrupts and whether your PIC is capable of handling them. dsPICs have, by default, programmable priority interrupts and they're easily capable of doing what you're now doing but in an interrupt driven format, and not in a blocking format.
Even if you don't have high priority interrupts on the processor you're using, you can still get round this problem by testing for the critical interrupt flag in the other interrupts. |
|
|
fly28
Joined: 11 Feb 2017 Posts: 9
|
|
Posted: Mon Feb 13, 2017 4:12 pm |
|
|
I can generate 16 functions, no PIC or dsPIC has so many timers. However, this is not the main aim of my project, it's one of many. My code is not blocking, it's working perfectly; only if I try to stop him earlier via USB I can't until it finishes. |
|
|
|