I have been beating my head against this problem for over a week now and thought
I'd solicit some help from this group.  I have a system with the following two
functions, each of which needs to run as a seperate thread in RTLinux.  adcThread
is supposed to run at a rate of 100Hz and monitor the forces on a set of load
cells.  servo_thread runs at 50Hz and compares the currently recorded load cell
readings with the target readings and implements a PI servo loop to control the
forces.  The printk() statements were put in for debugging purposes to show what is
happening in the system.

Here are the symptoms I am seeing:

* Both threads appear to be successfully created, marked for periodic execution,
and started.

* servo_thread runs at 100Hz, as expected, until removed from the system with
rmmod.

* adcThread runs _one_ time, going to sleep and never again being awakened.

I have tried various re-arrangements of the code; putting servoTask ahead of
adcTask, decreasing the frequency of each and of both tasks, and having adcTask be
the _only_ task in the system.  In each case, the behavior is the same.

I apologize for the length of this note, but I couldn't think of any other way to
illustrate what is happening besides including the code in question.  Any
help/ideas/suggestions that anyone can provide would be greatly appreciated and
publically acknowledged.   :-)

Thanks.

Ken Ramey

void *adcThread(void *t)
{
  unsigned short int      adc_chan;
  unsigned short int      csr_temp, ctrl_reg;
  int                     sampleCnt;
  int                     adc_counts[ADC_CHANS];

  while (TRUE)
    {
      printk(KERN_INFO "adcThread active\n");
      csr_temp = IOSPACEW(adc_slot,ADC_CSR) & 0xe3f0;

      for (adc_chan = 0; adc_chan < ADC_CHANS; adc_chan++)
         adc_counts[adc_chan] = 0;

      sampleCnt = 0;
      while (sampleCnt < SAMPLE_SIZE)
         {
               for (adc_chan = 1; adc_chan <= ADC_CHANS; adc_chan++)
                 {
                       ctrl_reg = csr_temp | ((adc_chan - 1) >> 1);
                       if ((adc_chan % 2) == 0)
                          ctrl_reg |= 0x10;
                       else
                          ctrl_reg |= 0x08;

                       IOSPACEW(adc_slot,ADC_CSR) = ctrl_reg;
                       usleep(5);

                       IOSPACEW(adc_slot,ADC_CONVERT) = 0xffff;
                       usleep(11);

                       adc_counts[adc_chan - 1] += IOSPACEW(adc_slot,ADC_DATA);
                 }
           sampleCnt++;
     }

      for (adc_chan = 0; adc_chan < ADC_CHANS; adc_chan++)
           curCounts[adc_chan] = adc_counts[adc_chan] / SAMPLE_SIZE;

      IOSPACEW(adc_slot,ADC_CSR) = csr_temp;
      printk(KERN_INFO "adcThread going to sleep\n");
      pthread_wait_np();
    }
    printk(KERN_IN FO "adcThread exiting\n");
}

void *servo_thread(void *t)
{
  int          error;
  int          ival;
  int          dacout[AXIS];
  int          i;
  int          rawCount = 0;
  int          errSum[AXIS] = {0, 0};

  while (TRUE)
    {
      printk(KERN_INFO "servo_thread active\n");
      for (i = 0; i < AXIS; i++)
         {
               rawCount = curCounts[6 + i];  /* raw value from the adc     */
               error  = targetCount[i] - rawCount;
               ival   = errSum[i] + 0.015 * error;
               if (ival > DAC_MID + 1000)     /* +1000 from midpoint of DAC */
                 ival = DAC_MID + 1000;
               if (ival < DAC_MID - 1000)     /* -1000 from midpoint of DAC */
                 ival = DAC_MID - 1000;

               dacout[i] = (1 * error + errSum[i]);
               errSum[i] = ival;

               if (dacout[i] < 0)
                 dacout[i] = 0;
               else if (dacout[i] > 65535)
                 dacout[i] = 65535;
               IOSPACEW(dac_slot,i * 2) = (unsigned short) dacout[i];
             }
      /* Sleep until our next interval occurs */
      printk(KERN_INFO "servo_thread sleeping\n");
      pthread_wait_np();
    }
}

The two threads are started with the following code:

...
 pthread_attr_init(&attr);
  sched_param.sched_priority = 90;
  pthread_attr_setschedparam(&attr, &sched_param);

  retVal = pthread_create(&adcTask, &attr, adcThread, (void *)1);
  if (retVal != 0)
    printk(KERN_INFO "Unable to create ADC Thread. RC = %d\n", retVal);

  retVal = pthread_make_periodic_np(adcTask, gethrtime() , 10000000);
  if (retVal != 0)
    printk(KERN_INFO "Unable to start adcThread\n");

  sched_param.sched_priority = 100;
  pthread_attr_setschedparam(&attr, &sched_param);

 retVal = pthread_create(&servoTask, &attr, servo_thread, (void *)1);
 if (retVal != 0)
    printk(KERN_INFO "Unable to create Servo Thread. RC = %d\n", retVal);
  pthread_attr_setfp_np(servoTask, 1);

  retVal = pthread_make_periodic_np(servoTask, gethrtime() , 20000000);
  if (retVal != 0)
    printk(KERN_INFO "Unable to start servoTask\n");
...

----- End of forwarded message from [EMAIL PROTECTED] -----
-- [rtl] ---
To unsubscribe:
echo "unsubscribe rtl" | mail [EMAIL PROTECTED] OR
echo "unsubscribe rtl <Your_email>" | mail [EMAIL PROTECTED]
--
For more information on Real-Time Linux see:
http://www.rtlinux.org/

Reply via email to