LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Serial Comms interrupt

With a typical event driven architecture one can implement a while loop in main:

Main()
{
    Init code();
   While(1)
   {
       If (timer_tick)
             Process serial comms data;
             Process state_machine;
             Do other stuff;
             Clear timer tick;
   }
}

 

Interrupt service routine to receive serial data
Interrupt service routine to set timer tick
Of course the code must be finished before the next time interval.

 

1. With LabWindows is the preferred method to call all the timer_tick routines from a timer?
       (Usually interrupts have a bare minimum of overhead.)
2. If data is received while the timer code is executing will it interrupt the timer code?

3. Can the comms be disabled while the buffers are accessed during the timer_tick?.

0 Kudos
Message 1 of 15
(3,931 Views)

Hi Nubie,

 

I suppose timers are the best way to generate timer events. You can try the async timer library for a more precise timing performance rather than the UIR timer control.

 

As far as I know, the timer routine continues to run uninterrupted if a timer event is generated during the timer routine. But it gets queued up. So it will execute whenever the current routine finishes. 

 

Comms are not disabled automatically, you can manually close and reopen but I do not recommend that. The incoming bytes are buffered anyway. If you want a clean start each time just flush (use FlushInQ) them at the beginning of the timer routine.

 

Hope this helps, 

S. Eren BALCI
IMESTEK
0 Kudos
Message 2 of 15
(3,905 Views)

My main concern is with the incomming comms.

My comm routine shoves the new data into a fixed size listbox FIFO.

The timer routine updates the list box if required but I can't have the receive comms  modifying the listbox during this time.

I have used

SuspendTimerCallbacks();

ResumeTimerCallbacks();

to wrap the receive comms interrupt.

 

Is there a way I can block the receive comms or not loose any received data while I am in the timer interrupt?

0 Kudos
Message 3 of 15
(3,903 Views)

Suspend/ResumeTimerCallbacks functions are for UIR timers.

Why don't you use the async timers?

Their callbacks are called in a separate thread, so you do not have to interrupt your com read operation.

S. Eren BALCI
IMESTEK
0 Kudos
Message 4 of 15
(3,896 Views)

I will definitely check that out.

 

Thanks.

0 Kudos
Message 5 of 15
(3,893 Views)

Eren.

 

I have 16 RS232 serial comm ports that put the incomming data into their respective circular comm buffers for later processing. Here the comm buffer head pointer updates accordingly.

 

In a timer routine I will take the data out of the circular comm buffers and update their comm buffer tail pointers accordingly.

 

How can I make sure that while timer routine is processing and checking the pointers that the serial comm routine will not modify them?

 

If the timer is called in a separate thread how is the data protected? I do not want to loose any received data even when processing the comm buffers.

The RxData interrupts put the data into the following buffers:

 

typedef struct
{
char data[COMM_BUF_SIZE];
int headPtr;
int tailPtr;
Prompt token;
}CommBuf;

static CommBuf commBuf[NUM_OF_COMM_BUFS];

0 Kudos
Message 6 of 15
(3,836 Views)

You can use callbacks too, the serial library will "watch" the incoming frames and call a routine of your choosing when any of several configurable events occurs, such as buffer full to some percentage, incoming byte, incoming byte of a certain type (e.g. crg rtn), etc.etc.

 

Menchar

0 Kudos
Message 7 of 15
(3,823 Views)

Hi Menchar.

 

The serial comms callbacks are ok and work fine. They put the data into a global buffer for parsing at a later time.

What I don't quite know is if at a later time when the data is being parsed the comms callback gets called and puts more data into the global buffer at the same time the parser is pulling data out of it.

I can't loose any comms data.

 

I don't quite understand who blocks who. If it is mulithreaded how is the global buffer protected?

 

I am sure this has been done a million times before.

I checked a source code example  but it doesn't explain these details.

0 Kudos
Message 8 of 15
(3,819 Views)

NI nubie -

 

An aync timer runs on its own thread (all async timers are on this same thread), different from the main thread, and your callback should be running on the main thread.

 

Threads don't sequence access to common resources themselves, you have to manage it.  So if you indeed have two or more threads reading / writing the same queue / file / resource , you need to explicitly serialize access using OS components such as semaphores or mutexes or critical sections.    All of the CVI libraries are supposed to be thread safe, meaning you don't have to serialize the library function calls, the libraries a written to do that for you.  But that just means two threads can't conflict each other within the same library function - it's still possible to write erroneous code with a threadsafe library.

 

This is known as the "reader writer problem" and is something of a classic problem in computer science.

 

You don't want one thread pulling data from the queue at the same instant that another thread is adding to it.

 

Some languages (Java) offer standard libraries / classes that have thread safe data structs, but C doesn't.  NI has thread safe libraries in CVI for much of this that are built on top of OS primitives.

 

I wrote (as does everybody sooner or later it seems) a set of thread safe data struct functions in C to solve this type of problem, in my case using circular buffers and Win32 critical sections.

 

Menchar

Message 9 of 15
(3,817 Views)

Hi Menchar.

 

The help is very limited. 

 

One or two sentence explanation without too many details.

A coded sample with stubbed functions indicating what the initial starting point for the code would be would help dramatically but I never find anything like that in the help.

I will have 22 com ports with 22 global buffers that will be parsed peridically with a timer intrrupt. I need to prevent double access to the buffers.

 

I think I have to set up all the commcallbacks in main and then create the timer in a new thread but will that protect the global buffers?

 Something like this: Main{ if (InitCVIRTE (0, argv, 0) == 0) return -1;
 
if ((gPanelHandle = LoadPanel (0, "CCUTest.uir", PANEL)) < 0) return -1;

 Init (); OpenCommPorts ();  /* Multitreading stuff here */
  

 cmtStatus = CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE,ThreadFunction, NULL,&threadID);

 DisplayPanel (gPanelHandle);
 RunUserInterface ();
   
 CloseCommPorts ();

 DiscardPanel (gPanelHandle);
   
 
return 0;

} 

commCallBacks();  etc.

 

int CVICALLBACK ThreadFunction (void *functionData)
{

 //parse global buffers for all 22 com ports here
return
0;
}

 

 

0 Kudos
Message 10 of 15
(3,811 Views)