Re: Loop problem: CPU usage
Just as a follow up, if I don't carry out the analysis (ie return instead) then the structure that receives, sends and unblocks the analysis threads uses negligeable CPU time. I can run at pretty much any speed I like with no problems at all.
It's when the CPU usage gets above 95% that things start to fall down.
The point is, though, that my QueryPerformanceTimers tell me that the analysis is taking 25ms which at 12 / s should be about 300ms total... Even with the other overheads, I shouldn't be at more than 50% CPU usage.
Could it be context changes? I don't know how fast the windows scheduler is...
Ben.
Re: Loop problem: CPU usage
Ben,
I just looked at post #56 as well as your most recent contribution in post #61. It is surprising that CPU load is even an issue here and it points to design rather than the limitations of the mighty giga-flop desktop PC.
The send and recv of serial characters should be no stress whatsoever to the PC given the right driver architecture.
You need to design or acquire from internet a suitable RS232 driver within the Win32-API domain.
I almost get the impression that you might be polling for individual characters on the PC side. This is not necessary. You can use a buffer and read this periodically with a timeout.
We need to re-open this thread and talk about the design of your serial driver on the PC side. You need to use buffers and timeouts in your console application.
Well if you can believe it, I'm actually on vacation now so who knows if I can really get into this. Nevertheless, I am disturbed by your troubles on the PC-side and think that these need to be smoothed out.
I can send some sample RS232 codes, but there are also many examples on the net at CodeGuru as well as CodeProject.
Sincerely, Chris.
Re: Loop problem: CPU usage
There should be no probelm using a console application.
Please post your PC code. Naturally, we do not need to see the actual processing, which you can replace with a call to some place-holder function like DoLengthyProcessing(). Just show us the framework: how does the PC know that the micro has sent an object's number, how are the threads implemented (i.e, pool of persistent threads (better) vs. creation of new thread for each new number (less good)), how many threads are there, etc.
Mike
Re: Loop problem: CPU usage
Hi Chris,
I hope you're having a good vacation. I'm using the CSerial class for my serial communications. Details below.
Mike, I'll post below the simplified code. I think this is actually related to another post I made in the multithreading forum because after testing with just one analyse thread running I'm starting to get the performance results I expected to see.
http://www.codeguru.com/forum/showth...91#post1613791
Anyway, the inits are here:
Code:
//inits
for (int k = 0; k<NUM_THREADS; k++) //=2
{
interface[k] = CDataInterface::create(0,Buffer[0]->GetSize(),3,300);
}
for (int k=0; k<NUM_THREADS; k++)
{
thread_num = k;
hThread_Analyse[k] =::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread_Analyse,this,0,&ThreadId__Analyse[k]);
//SetThreadPriority(hThread_Analyse[k],THREAD_PRIORITY_BELOW_NORMAL );
Sleep(100);
}
hThread_RxCommsRS232 =::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread_RxCommsRS232,this,0,&ThreadId__RxCommsRS232);
SetThreadPriority(hThread_RxCommsRS232,THREAD_PRIORITY_HIGHEST );
and the threads:
Code:
long WINAPI Thread_RxCommsRS232(LPVOID lpParam)
{
CAnalyser* the_analyser=(CAnalyser*)lpParam;
//CSerial serial;
LONG lLastError = ERROR_SUCCESS;
LARGE_INTEGER date_courante;
DWORD pdwWritten = 0;
// Attempt to open the serial port (COM1)
lLastError = the_analyser->serial.Open(_T("COM4"),0,0,true);
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to open COM-port"));
// Setup the serial port (9600,8N1, which is the default setting)
lLastError = the_analyser->serial.Setup(CSerial::EBaud115200,CSerial::EData8,CSerial::EParNone,CSerial::EStop1);
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to set COM-port setting"));
lLastError = the_analyser->serial.SetupHandshaking(CSerial::EHandshakeOff);
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to set COM-port handshaking"));
// Register only for the receive event
lLastError = the_analyser->serial.SetMask(CSerial::EEventBreak |
CSerial::EEventError |
CSerial::EEventRecv);
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to set COM-port event mask"));
// Use 'non-blocking' reads, because we don't know how many bytes
// will be received. This is normally the most convenient mode
// (and also the default mode for reading data).
lLastError = the_analyser->serial.SetupReadTimeouts(CSerial::EReadTimeoutNonblocking);
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to set COM-port read timeout."));
lLastError = the_analyser->serial.Purge();
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Couldn't Purge."));
// Create a handle for the overlapped operations
HANDLE hevtOverlapped = ::CreateEvent(0,TRUE,FALSE,0);;
if (hevtOverlapped == 0)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to create manual-reset event for overlapped I/O."));
// Setup the overlapped structure
OVERLAPPED ov = {0};
ov.hEvent = hevtOverlapped;
// Open the "STOP" handle
HANDLE hevtStop = ::CreateEvent(0,TRUE,FALSE,_T("Overlapped_Stop_Event"));
if (hevtStop == 0)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to create manual-reset event for stop event."));
// Keep reading data, until an EOF (CTRL-Z) has been received
bool fContinue = true;
//do
while ( fContinue)
{
// Wait for an event
//lLastError = the_analyser->serial.WaitEvent();
lLastError = the_analyser->serial.WaitEvent(&ov);
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to wait for a COM-port event."));
// Setup array of handles in which we are interested
HANDLE ahWait[2];
ahWait[0] = hevtOverlapped;
ahWait[1] = hevtStop;
// Wait until something happens
switch (::WaitForMultipleObjects(sizeof(ahWait)/sizeof(*ahWait),ahWait,FALSE,INFINITE))
{
case WAIT_OBJECT_0:
{
// Save event
const CSerial::EEvent eEvent = the_analyser->serial.GetEventType();
// Handle error event
if (eEvent & CSerial::EEventError)
{
ALERT;
printf("\n### ERROR: ");
switch (the_analyser->serial.GetError())
{
case CSerial::EErrorBreak: printf("Break condition"); break;
case CSerial::EErrorFrame: printf("Framing error"); break;
case CSerial::EErrorIOE: printf("IO device error"); break;
case CSerial::EErrorMode: printf("Unsupported mode"); break;
case CSerial::EErrorOverrun: printf("Buffer overrun"); break;
case CSerial::EErrorRxOver: printf("Input buffer overflow"); break;
case CSerial::EErrorParity: printf("Input parity error"); break;
case CSerial::EErrorTxFull: printf("Output buffer full"); break;
default: printf("Unknown"); break;
}
printf(" ###\n");
}
// Handle data receive event
if (eEvent & CSerial::EEventRecv)
{
//printf("serial event \n");
QueryPerformanceCounter(&date_courante);
// Read data, until there is nothing left
DWORD dwBytesRead = 0;
char szBuffer[101];
//do
//{
// Read data from the COM-port
//printf("Reading buffer\n");
//EnterCriticalSection(&the_analyser->SerialPortAccess);
the_analyser->serial.Read(szBuffer,3/*sizeof(szBuffer)-1*/,&dwBytesRead);
//LeaveCriticalSection(&the_analyser->SerialPortAccess);
//printf("Finished Reading buffer '%s' bytes read %d\n", szBuffer, dwBytesRead );
if (lLastError != ERROR_SUCCESS)
return the_analyser->ShowError(the_analyser->serial.GetLastError(), _T("Unable to read from COM-port."));
//printf("serial : nb_bytes read: %d\n",dwBytesRead);
if (dwBytesRead == 3)
{
//printf("serial : nb_bytes read: %d\n",dwBytesRead);
szBuffer[3] = 0x00;
//printf("THREAD RxCommsRS232 '%s' received at: %I64d\n", szBuffer, date_courante.QuadPart);
if (szBuffer[0]==1)
{
byte object_number;
char xxx,yyy;
sscanf(szBuffer,"%c%c%c",&xxx,&object_number,&yyy);
the_analyser->object_no_recd = object_number -48;
//the_analyser->object_no_recd = (unsigned int)(szBuffer[1] - 48);
the_analyser->lastRxTime[0] = date_courante.QuadPart;
int event_ok = 0;
event_ok = SetEvent(the_analyser->hRS232RxEvent);
if (!event_ok)
{
...
}
}
if (szBuffer[0]==3) //Status message received from µC
{
the_analyser->last_message_uC = (byte)szBuffer[1];
SetEvent(the_analyser->hStatusRx_uC);
}
}
the_analyser->serial.Purge();
//}
//while (dwBytesRead == sizeof(szBuffer)-1);
//while (dwBytesRead > 0);
}
}
break;
void CAnalyser::CallBackFunction2()
{
CObjecttiming* local_object = new CObjecttiming();
int at_least_one_buffer_found = 0;
int buffer_to_use = 0;
if (WaitForSingleObject(hRS232RxEvent), INFINITE) == WAIT_OBJECT_0)
{
ResetEvent(hRS232RxEvent);
local_object->object_number = object_no_recd;
at_least_one_buffer_found = 0;
for (int j=0; j<BUFFER_SIZE; j++)
{
if (at_least_one_buffer_found)
continue;
if (BufferCready[j])
{
at_least_one_buffer_found++;
local_object->Num_circ_buffer = j;
BufferCready[j] = false;
}
}
if (at_least_one_buffer_found)
{
if ( (buffer_to_use >=0)&&(buffer_to_use < BUFFER_SIZE) )
{
pBuffer->Copy(Buffer);
bool found_a_thread = false;
bool no_thread_available = false;
int thread_to_call = -1;
thread_to_call = 0;
while ((!found_a_thread) && (!no_thread_available))
{
EnterCriticalSection(&AnalyseThreadStatus[thread_to_call]);
if (AnalyseThreadBusy[thread_to_call]==false)
{
found_a_thread = true;
local_object->ready_for_analysis = true;
object_to_analyse[thread_to_call] = local_object;
QueryPerformanceCounter(&stop);
SetEvent(hObjectReady[thread_to_call]);
INFO;
printf("Time up to setevent = %f\n", (( (float)stop.QuadPart - (float)start.QuadPart )/ (float)the_analyser->freq.QuadPart) *1000.0f );
}
else
{
TRACE;
printf("thread[%d] is busy\n",thread_to_call);
}
LeaveCriticalSection(&AnalyseThreadStatus[thread_to_call]);
if (thread_to_call > NUM_THREADS)
{
no_thread_available = true;
ALERT;
printf("!!!No threads available \n");
}
else
{
thread_to_call++;
}
}
if (!found_a_thread)
{
...
delete local_object;
}
}
}
else
{
nb_not_enough_buffers++;
ALERT;
printf("CALLBACK FUNCTION: Not enough buffers %d", nb_not_enough_buffers);
}
}
long WINAPI Thread_Analyse(LPVOID lpParam)
{
CAnalyser* the_analyser=(CAnalyser*)lpParam;
int this_thread_number = the_analyser->thread_num;
CObjecttiming* local_object = NULL;
while (Keep_thread_alive)
{
WaitForSingleObject(the_analyser->hObjectReady[this_thread_number], INFINITE);
local_object = the_analyser->object_to_analyse[this_thread_number];
EnterCriticalSection(&the_analyser->AnalyseThreadStatus[this_thread_number]);
the_analyser->AnalyseThreadBusy[this_thread_number] = true;
LeaveCriticalSection(&the_analyser->AnalyseThreadStatus[this_thread_number]);
ResetEvent(the_analyser->hObjectReady[this_thread_number]);
assert(local_object != NULL);
if ( (local_object->ready_for_analysis == true) && (local_object->is_analysing == false) )
{
local_object->is_analysing = true;
//Analyse object
local_object->analysis_result = the_analyser->Analyse_Object(local_object, this_thread_number);
local_object->is_analysing = false;
the_analyser->BufferCready[local_object->Num_circ_buffer] = true;
local_object->Num_circ_buffer = -1;
local_object->finished_analysing = true;
}
EnterCriticalSection(&the_analyser->AnalyseThreadStatus[this_thread_number]);
the_analyser->AnalyseThreadBusy[this_thread_number] = false;
LeaveCriticalSection(&the_analyser->AnalyseThreadStatus[this_thread_number]);
}
Re: Loop problem: CPU usage
I am not certain that the following would explain the behavior you are seeing (although it might explain the behavior at your related thread at http://www.codeguru.com/forum/showth...91#post1613791, in which you state tht the threads are using the wrong information), but the following code is wrong and should be changed:
Code:
// thread starting code
for (int k=0; k<NUM_THREADS; k++)
{
thread_num = k;
hThread_Analyse[k] =::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread_Analyse,this,0,&ThreadId__Analyse[k]);
Sleep(100);
}
// then, in the thread code
long WINAPI Thread_Analyse(LPVOID lpParam)
{
CAnalyser* the_analyser=(CAnalyser*)lpParam;
int this_thread_number = the_analyser->thread_num;
// etc, which uses this_thread_number as an index into shared data
}
The code is wrong because you can't guarantee that a newly-started thread will start up and read the this_thread_number member variable, before the thread-starting code changes the variable. I see that you tried to guarantee it, by insertion of the Sleep(100) call, but that's no guarantee. For example, even after the Sleep(100) call, the thread scheduler might not yet have scheduled the newly-created thread for execution, or maybe the scheduler will schedule your newly-created threads for out-of-order execution, such that both threads get exactly the same value for this_thread_number.
Here's one way to do it better, without the race condition:
Code:
class ThreadCookie
{
public:
CAnalyser* pThis;
int thread_num;
};
// thread starting code
for (int k=0; k<NUM_THREADS; k++)
{
ThreadCookie* pCookie = new ThreadCookie;
pCookie->pThis = this;
pCookie->thread_num = k;
hThread_Analyse[k] =::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread_Analyse, pCookie, 0,&ThreadId__Analyse[k]);
// no need for Sleep(100);
}
// then, in the thread code
long WINAPI Thread_Analyse(LPVOID lpParam)
{
ThreadCookie* pCookie = (ThreadCookie*)lpParam;
CAnalyser* the_analyser=pCookie->pThis;
int this_thread_number = pCookie->thread_num;
delete pCookie;
// etc, which uses this_thread_number as an index into shared data
}
Mike
Re: Loop problem: CPU usage
Hi Mike,
That seems a much better way of doing it. Thanks for that. Although, using the same name for the various instances of ThreadCookie worries me. I could be wrong about that. Wouldn't it be safer to do it this way:
Code:
for (int k=0; k<NUM_THREADS; k++)
{
ThreadCookie* pCookie[k] = new ThreadCookie();
pCookie[k]->pThis = this;
pCookie[k]->thread_num = k;
hThread_Analyse[k] =::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread_Analyse, pCookie[k], 0,&ThreadId__Analyse[k]);
// no need for Sleep(100);
}
Thanks.
Ben.
Re: Loop problem: CPU usage
Hi Ben,
I just took a look at the larger portion of your code sample in thread #64. I am a little bit concerned about the length of the code and the mixture of various functions within the thread. In addition, it is hard for me to recognize any kind of RS232 protocol which you may have implemented. Finally, there is a mixture of old-school C-idioms combined with some elements of C++.
This might not be what you want to hear but your code seems a bit compressed yet simultaneously over-dimensioned and somewhat disorganized for the modest assignment at hand (RS232 communication with a simple protocol with a microcontroller RS232). Now I am only going in this direction with you because I know that you have been working very hard on this project for quite some time. I have also followed your work with the microcontroller side. But we have to work on the PC side now. Please do not confuse my bluntness with any kind of criticism. Far from it, I want to make sure that you are programming to the best of your abitilies also on the PC side.
If you worked with me, then I would tell you to redesign this work. Take some time and think about the design goals. Choose one language (C or C++) and use it consistently. But more important than the language choice is the architecture. You should design some kind of an object oriented architecture in which all of the serial operations (open, send, receive, timestamp, etc.) are encapsulated in one class.
I think that you should use a dedicated, separate worker-thread for you receive loop.
Your protocol, in so far as one is present for your communications with the microcontroller, should be in a different class. And it should be present in some recognizable form.
You need to minimize your use of pointers and operator new. Also, your code is screaming for assistance through the sensible use of STL.
I need to re-establish my orientation with the PC-side of your communications software.
Could you please describe very briefly the main goals of your PC-side software in combination with the microcontroller as well as any kind of protocol which you are using?
Sincerely, Chris.
Re: Loop problem: CPU usage
Hi Chris,
Thanks for the constructive criticism... sadly I'm not a natural born coder, but rather a nuts and bolts guy that's found himself having to code! That and the fact that most of the programming experience i have is C and not C++ / object. I'm making progress though, largely thanks to you guys. One of the reasons I like the micro is the simplicity of the programming (C). If I had to do this in DOS then it would probably be done and dusted months ago :)
Concerning the RS232 comms, that was always a concern of mine and I pretty much lifted the CSerial class (from codeproject.com) and put it in a worker thread. Right now that thread is just waiting for an event and reacting to it. When you say that I should use a dedicated, separate worker thread, I thought this was what I was doing :s
My goal, in terms of the serial communication, is uniquely to receive a 3 byte message from the micro and deal with it. The first byte of which is an identifier for the kind of message, the 2nd is the number of the object and the 3rd is redundant for the time being.
I also need to send a 3 byte message to the micro where the 1st byte is the message identifier, the 2nd is the number of the object and the 3rd is the action to take.
There is no other serial communication going on. I wanted to keep the messages as short as possible to avoid too much traffic on the serial port.
In light of your post, I'm a bit embarassed by the quality of my code :( but this represents the best of my abilities.
When you say use STL, where / how exactly would you recommend doing this?
Thanks for all this. I realise you're on vacation and should be sitting in the sun with a martini, not trudging through my code!
Ben.
Re: Loop problem: CPU usage
Quote:
Originally Posted by shoppinit
Hi Mike,
That seems a much better way of doing it. Thanks for that. Although, using the same name for the various instances of ThreadCookie worries me. I could be wrong about that. Wouldn't it be safer to do it this way:
Code:
for (int k=0; k<NUM_THREADS; k++)
{
ThreadCookie* pCookie[k] = new ThreadCookie();
pCookie[k]->pThis = this;
pCookie[k]->thread_num = k;
hThread_Analyse[k] =::CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Thread_Analyse, pCookie[k], 0,&ThreadId__Analyse[k]);
// no need for Sleep(100);
}
Thanks.
Ben.
Not necessary because of "pass by value" semantics. In each iteration of the loop, an new ThreadCookie object is created, and the value of a pointer to it is stored in pCookie (my original code). When CreateThread is called, its value is eventually passed to the thread, which leaves the pCookie variable free to store a new pointer to a new ThreadCookie object in the next iteration of the loop.
The difference from your original code is that you were sharing the variable itself, which of course can hold only one single value at a time.
But in light of comments from dude_1967 (Chris), all that might be irrelevant:
Quote:
Originally Posted by shoppinit
When you say that I should use a dedicated, separate worker thread, I thought this was what I was doing :s
I'm not completely certain, but what I think Chris is telling you is that there is no need for more than a single worker thread. The thread should wait for a comm event from the micro, quickly do all processing that it needs to, including sending the answer back to the micro, and then wait for the next event. You would need more than a single worker thread only if the processing required for each message took a remarkably long time, such that it might overlap significantly with receipt of a subsequent comm event.
Mike
Re: Loop problem: CPU usage
Quote:
Originally Posted by shoppinit
... I pretty much lifted the CSerial class (from codeproject.com) and put it in a worker thread.
If you are referring to CSerialPort, then the version at Codeproject is several years old now. You should go directly to PJ Naughter's site and get the lastest and greatest: http://www.naughter.com/serialport.html
Mike
Re: Loop problem: CPU usage
Quote:
Originally Posted by shoppinit
...rather a nuts and bolts guy that's found himself having to code!
A lot of good programmers have this kind of background.
Quote:
Originally Posted by shoppinit
My goal, in terms of the serial communication, is uniquely to receive a 3 byte message from the micro and deal with it. The first byte of which is an identifier for the kind of message, the 2nd is the number of the object and the 3rd is redundant for the time being.
I also need to send a 3 byte message to the micro where the 1st byte is the message identifier, the 2nd is the number of the object and the 3rd is the action to take.
This sounds very straight forward. I do like the MFC-based serial driver which you have been using. However, I believe that your design requirements are so simple that this thing is over dimensioned for yuor design requirements. However, you can definitely use this class if you want to. This would save time but also cut down on your learning as well as the lean-ness of your final implementation.
In general, you are talking about a classic and simple architecture involving the OSI communications layers 1-3 and 7 (http://en.wikipedia.org/wiki/OSI_model). I will suggest an architecture below.
Quote:
Originally Posted by shoppinit
In light of your post, I'm a bit embarassed by the quality of my code :( but this represents the best of my abilities.
Don't be embarassed. Everyone needs help every now and then. I also ask a lot of questins here at CodeGuru.
Quote:
Originally Posted by shoppinit
When you say use STL, where / how exactly would you recommend doing this?
.Here is one possible way to approach this problem...
The following will seem like quite a lot and it is a hard way to go over the internet. But I am sure we can work through the points one at a time. And at the end of it all you might have really good results.
I assume you are writing a console application. Is this correct?
First of all you need OSI layers 1-3. Design a serial driver class which is capable of sending and receiving raw byte arrays. Let's call is ComSerial. This class needs to support such functions as open, close, send, recv, etc. The use of an STL container such as vector is recommended for the send and recv interface. The raw-byte send and recv fucntions can remain private at this point.
Parallel to this class, design a single frame protocol object (a class or structure) which encapsulates the three byte messages. Let's call this class Message_3uc. It would be advisable to replace the third redundant byte with a CRC8 checksum which can be implemented in the uc as well as the PC with the same algorithm. I can provide you with an algorithm. This class needs an internal 3-byte array (possibly an STL vector). In addition, there should be support for command creation as well as response parsing including service-ID checks and validity checks with the CRC8.
Armed with the above mentioned two classes, you can create the public interface to OSI layer 1-3 including most importantly the send and recv functions. These can either be implemented as an extension of your serial class ComSerial or as a derived class ComSerialMsg. For the actual send and receive functions now the interface could be a queue of Message_3uc objects. In exact terms, then this can be a std deque of message objects.
Now you are done with OSI layers 1-3.
The application layer (OSI layer 7) can be implemented through the use of a higher level object or even a simple functional interface. Basically this class or interface needs to be responsible for creating single messages or message queus and receiving them as well as dispatching any kinds of services or actions needed (such as control, logging and error reaction). I do not know enough abut the application to be able to talk about this yet.
I can generate some sample codes, including sample interfaces with STL for all of this junk if you need a hand getting started. But that's about all I can do based on the time constraints I have. So you would have to finish it yourself.
One final question: How much RS232 communication are you talking about? How many messages, what frequencies and total amounts (bursts) of data are involved here? Also what kinds of PC response times do you need? We need this information for the lower OSI layers.
Give me a feedback if you want to take it on with this kind of design.
Sincerely, Chris.
Re: Loop problem: CPU usage
Hi Chris,
Thanks very much for that. Sorry I haven't got back to you, but I've been extremely busy getting the other bits of the project sorted - mechanical, electrical, etc, which has turned into a nightmare of its own.
I've discovered the downside of using a micro for this kind of thing: interfacing it with everything else. I've been dogged by EMI noise problems and other difficult to resolve electrical problems. My electronics knowlegde is worse than my coding ;)
Coming back to your post, I confirm that I am using a console application. The comms layer information was interesting.
In terms of the amount of RS232 communication going on, there could be up to 50 messages / sec one way, or 100 both ways.
I appreciate your offer for help with the serialcom classes. I'm aware, though, that you've surely got better things to be doing!
Many thanks.
Ben.
Re: Loop problem: CPU usage
Hi Ben,
Quote:
Originally Posted by shoppinit
I've discovered the downside of using a micro for this kind of thing: interfacing it with everything else. I've been dogged by EMI noise problems and other difficult to resolve electrical problems.
What kind of EMC problems have you encountered? There are several types of problems: radiative emissions, wire-based interference, supply line instability, etc. It's a bit beyond the scope of this forum, but it might be interesting to discuss this aspect of the design. Sometimes it can be very important to have a clean grounding design for your µC board (important for the radiative stuff).
Quote:
Originally Posted by shoppinit
In terms of the amount of RS232 communication going on, there could be up to 50 messages / sec one way, or 100 both ways.
Sounds like less than 1kB data / sec. With the right design this should not be a problem for the PC host system.
We can discuss the software design further if you would like.
Sincerely, Chris.
Re: Loop problem: CPU usage
Quote:
Originally Posted by dude_1967
What kind of EMC problems have you encountered? There are several types of problems: radiative emissions, wire-based interference, supply line instability, etc.
Hi Chris,
The micro has 2 external interrupts that are driven (via industrial optos) by 2 inductive sensors (24v PNP). The EINTs proved extremely sensitive to line noise, EMI emissions, etc. I'm getting a lot of false activations - exactly as if the EINT inputs were floating, but they're pulled high. I tried shielding everything (and I mean everything!) and this helps slightly.
I don't think it's a supply line problem since, out of desperation, I tried running the micro off batteries (right now it's powered by the PC it's connected to for RS232).
I think the problem is impedance matching between the opto and the micro since I've got about 6ft of wire connecting them. This is way beyond my abilities in electronics, having only a vague idea about impedance matching.
The only solution I can think of is to get rid of the industrial optos, solder some 4n37 optos onto the micro PCB as close to the micro as possible and have the +24v coming into the box where I've mounted the micro. I might put an RC circuit on there while I'm at it to be doubly sure.
I can see this being a big problem once I've got everything in a noisy industrial environment with power relays going on and off nearby and it worries me.
Quote:
Originally Posted by dude_1967
Sounds like less than 1kB data / sec. With the right design this should not be a problem for the PC host system.
Yes, the amount of actual data is small, but the frequency of the transmissions is relatively high. I'd very much appreciate some input on how best to make the communications as robust as possible.
Thanks.
Ben.
Re: Loop problem: CPU usage
Incidentally, I resolved the multithreading problem. It turns out that a function that I was calling in Intel's IPP library wasn't thread safe. Or at least, not the way I was implementing it. I've since dumped the IPP library since it didn't bring any performance improvements (quite the opposite sometimes).
Now I'm getting the kind of CPU usage I expected to see.
Ben.