AnsweredAssumed Answered

MQX is blocking task after enabling interrupts

Question asked by Michael Schwager on Sep 23, 2014
Latest reply on Sep 26, 2014 by Michael Schwager

Running MQX 4.1.2 on Kinetis K60, and latest IAR v7 or something.

 

I have a setup where I'm reading values from a sensor, then displaying them on the UART, but the display eventually locks up at random times while the sensor continues to run.

The sensor's DRDY output interrupts the K60 at around 400Hz (2.5ms period), and the UART updates every 50ms, showing the last value from the sensor.  So there are multiple interrupts from the sensor for every time the display task runs.  This is so not to overload the terminal software.

 

The tasks, interrupts, and other things are set up as follows:

1. One task which first blocks on a lightweight event, then prints some stuff on stderr UART, then does a time_delay(50), then repeats loop.  I suspect MQX's handling of time_delay().

2. One task which waits on a semaphore, then reads sensor value from SPI port (using MQX 4.1 dma-and-interrupt driver as SPI master), then posts lightweight event for above task, then starts over.

3.  An interrupt routing which triggers on the sensor's DRDY line, then posts semaphore for second task.

 

What happens is the display runs fine for a while, then stops in the middle of a printf statement.  Ie the text only goes part way, or sometimes it locks up between lines.  The oscilloscope shows the interrupt line and following SPI read is still going at 400Hz.  When I pause the controller and examine tasks summary with IAR, it says the display task is queue-blocked.  It's not event blocked.

 

The problem goes away if I remove time_delay at the bottom of the first task, but then there is too much data on the UART.  I've commented out much stuff, so I'm pretty sure there is some weird interaction between the interrupt routine and the time_delay() function.

 

Prior to enabling hardware interrupts to run the sensors, I was using internal MQX lightweight timer to post the semaphore for the second task.  This did not pose a problem.

 

A quick and incomplete copy of the code is here:

void device_read_task(uint32_t param) {

  // Reads device values on its own time or on the event, whichever is slower

  MQX_FILE_PTR err = fopen("ittyc:", (const char *) IO_SERIAL_TRANSLATION);

  _io_set_handle(IO_STDERR, err);

  fprintf(stderr, "Starting device_read_task\n");

 

// .. a bunch of setup stuff, variable declarations, etc.

  while(1) {

  result = _lwevent_wait_ticks(ldev->parent->event, ldev->event_mask, TRUE, 0);

  if (result == LWEVENT_WAIT_TIMEOUT) {

  volatile uint8_t a = 5; // test to see whether the problem is due to event not being sent... this is usually not the case

  }

 

// ... a bunch of stuff to copy existing values from global location to here...

 

  fprintf(stderr,"% 5d,   %6hd, %6hd, %6hd,    ", counter++, adc_data[0], adc_data[1], adc_data[2]);

  fprintf(stderr,"% 5.6f, % 5.6f, % 5.6f,    ", xval, yval, zval);

  fprintf(stderr,"% 5.6f, % 5.6f, % 5.6f", xvalcal, yvalcal, zvalcal);

  fprintf(stderr,"\n");

  fflush(stderr);

  _time_delay(p->period);  // When this is removed the lockup problem goes away, but the UART goes too fast

  }

}

 

 

void device_run_task(uint32_t param) {

//... bunch of setup stuff

 

  while(1) { // put something here about enabling or disabling this loop.

  // Wait until the next timer or interrupt...

  _lwsem_wait(ldev->period_semaphore);

 

  MQX_TICK_STRUCT ticks;

  _time_get_ticks(&ticks);

  async_report.timestamp = ticks.TICKS[0];

 

// Here we run the SPI bus and read the sensor data, and place in some global variable

 

  // Post the event which triggers the display/uart task

  result = _lwevent_set(ldev->parent->event, ldev->event_mask);

 

  }

 

 

}

Outcomes