Weird interaction between SPI and TIMER3

Post here first, or if you can't find a relevant section!
Post Reply
profdc9
Posts: 5
Joined: Mon Mar 25, 2019 1:01 am
OS: Linux & Windows 10
IDE: Arduino
Core: Roger & Official
Board: Bluepill mostly

Weird interaction between SPI and TIMER3

Post by profdc9 » Fri Nov 08, 2019 7:04 am

I was working on my VNA project which uses a Bluepill, and I encountered a strange problem. To acquire a waveform, I use a combination of an interrupt triggered on a pin and TIMER3, where the pin triggers the beginning of acquisition and sets up TIMER3 to fire periodically, and then the ADC is read periodically in the interrupt on TIMER3. The trigger signal has some jitter so that the interrupt on the trigger pin continuously readjusts the interrupt rate on TIMER3 to follow the (almost) periodic triggering.

I have a routine outside of the interrupts that uses volatile variables to communicate with the interrupts, and when a particular count is reached, the acquisition is done. While waiting for the acquisition to finish, SPI commands are executed that update the display with the progress in the waiting loop. The display is a ILI9341/XPT2046 combination of LCD and touchscreen. I am using the libraries from Roger's distribution as well as the stm32duino libraries to control the timers and SPI.

The problem is that when a SPI command is issued, TIMER3 stops interrupting. I changed the code to use TIMER2 and it works ok. This is a bit baffling to me but if there's anyone who has ever encountered such a strange thing, perhaps they could enlighten me. Is there some interaction between the SPI code and the Timer?

Thanks,
Dan

stevestrong
Posts: 75
Joined: Tue Mar 05, 2019 7:49 am
Location: Munich
OS: Win7 & 10
IDE: Arduino 1.8.8, Sloeber
Core: Libmaple
Board: Bluepill, Generic F4VET6 black & mini
Contact:

Re: Weird interaction between SPI and TIMER3

Post by stevestrong » Fri Nov 08, 2019 10:29 am

SPI 1 pins MISO/MOSI (PA6/PA7) overlap with Timer3 channels 1 and 2.
https://os.mbed.com/media/uploads/hudak ... tage01.png

profdc9
Posts: 5
Joined: Mon Mar 25, 2019 1:01 am
OS: Linux & Windows 10
IDE: Arduino
Core: Roger & Official
Board: Bluepill mostly

Re: Weird interaction between SPI and TIMER3

Post by profdc9 » Fri Nov 08, 2019 3:32 pm

Thanks for the response.

I guess one thing that confuses me is that I am actually trying to trigger TIMER3 just on an internally generated clock signal, not the external pin trigger on the SPI pins. The external trigger pin I am using is another pin, PB15 which is associated with TIMER 1. Does the TIMER3 pay attention to the external pins when the pins are set up for the SPI device? If so, I will have to use pins for the external trigger and SPI that are not associated with any timer I want to use as an internal clock.

Thanks, Dan

profdc9
Posts: 5
Joined: Mon Mar 25, 2019 1:01 am
OS: Linux & Windows 10
IDE: Arduino
Core: Roger & Official
Board: Bluepill mostly

Re: Weird interaction between SPI and TIMER3

Post by profdc9 » Fri Nov 08, 2019 3:47 pm

To show in detail what I am trying to accomplish, I have two interrupt routines below. The interrupt routine ifClockInterrupt is triggered by a rising edge on the IFCLOCK_PIN (PB15). This signal is generated by an intermediate frequency from a mixer that is run through a zero-crossing comparator detector. Because there is clock jitter due to the SI5351A fractional divider, each period of the IF signal is not exactly the same length. So what I do is measure the time of the last period using the Cortex M3 cycle counter to estimate the time of the next clock cycle. I then set up the timer3 to generate equally spaced interrupts, over that clock cycle for the timerContInterrupt. The timer3 fires, and each time it measures three ADC inputs and then adds these to an accumulated signal to measure the quadrature (real and imaginary) part of the IF signal. After 4 or 12 timer3 clocks have passed (which depends on whether or not we are capturing the first or third harmonic of the IF), the timer3 stops accumulating and when the next edge of the trigger signal on PB15 occurs this cycle repeats until a certain number of periods of the IF signal have been averaged to accumulate a signal without clock jitter. I need the TIMER3 because it is the way I can time acquiring the quadrature samples of the IF inside a single period of the IF signal. The IF signal is set up to be about 10 kHz if measuring the first harmonic and 3.333 kHz for the third harmonic, and so the ADC is sampled at approximately 40 kHz.

Code: Select all

#define IFCLOCK_PIN PB15

void setup_if_clock(void)
{
  nvic_irq_set_priority(NVIC_EXTI_15_10, 2);
  attachInterrupt(IFCLOCK_PIN, ifClockInterrupt, RISING);

  nvic_irq_set_priority(NVIC_TIMER3, 2);
  timer_init(TIMER3);
  timer_attach_interrupt(TIMER3, 1, timerContInterrupt);
}

void ifClockInterrupt(void)
{
  unsigned int timerval = CPU_CYCLES;

  diftick = ((unsigned int)(timerval - lasttick));
  lasttick = timerval;

  if (current_summed < number_to_sum)
  {
    if (current_summed == 0)
    {
      sampCURI = 0; sampCURQ = 0;
      sampVOLTI = 0; sampVOLTQ = 0;
      sampCUR2I = 0; sampCUR2Q = 0;
      sampPWR = 0;
    }
    current_summed++;
    timer_pause(TIMER3);
    timer_set_count(TIMER3, 0);
    timerval = diftick / numphases;
    if (timerval > (F_CPU / 200000u))
    {
      timer_set_reload(TIMER3, timerval);
      timer_generate_update(TIMER3);
      curphase = 0;
      timer_resume(TIMER3);
    }
  }
}

void timerContInterrupt(void)
{
  //unsigned int timerval = CPU_CYCLES;

  if (curphase < numphases)
  {
    analogReadPins();
    switch (curphase & 0x03)
    {
      case 0: sampCURI += sampCUR;
        sampVOLTI += sampVOLT;
        sampCUR2I += sampCUR2;
        break;
      case 1: sampCURQ -= sampCUR;
        sampVOLTQ -= sampVOLT;
        sampCUR2Q -= sampCUR2;
        break;
      case 2: sampCURI -= sampCUR;
        sampVOLTI -= sampVOLT;
        sampCUR2I -= sampCUR2;
        break;
      case 3: sampCURQ += sampCUR;
        sampVOLTQ += sampVOLT;
        sampCUR2Q += sampCUR2;
        break;
    }
    sampPWR += sampCUR2;
    curphase++;
  }
}

int acquire_sample(unsigned int averages, unsigned int timeout)
{
  bool timedout = false;
  unsigned int inittime, curtime;

  //timer_init(TIMER3);
  timer_pause(TIMER3);
  timer_attach_interrupt(TIMER3, 1, timerContInterrupt);
  timer_set_prescaler(TIMER3, 0);
  timer_set_mode(TIMER3, 1, TIMER_OUTPUT_COMPARE);
  timer_set_count(TIMER3, 0);
  timer_set_reload(TIMER3,65535);
  timer_set_compare(TIMER3, 1, 0);
  timer_generate_update(TIMER3);

  timeout = timeout * (F_CPU / 1000u);
  /* wait for previous acquisition to stop */
  inittime = CPU_CYCLES;
  timedout = false;
  current_summed = 0;
  while (current_summed < number_to_sum)
  {
    curtime = CPU_CYCLES;
    if (((unsigned int)(curtime - inittime)) > timeout)
    {
      timedout = true;
      break;
    }
    if (vif != NULL) vif(vif_data);
  }
  if (timedout) return -1;
  number_to_sum = averages;
  current_summed = 0;
  /* wait for previous acquisition to stop */
  inittime = CPU_CYCLES;
  timedout = false;
  while (current_summed < number_to_sum)
  {
    curtime = CPU_CYCLES;
    if (((unsigned int)(curtime - inittime)) > timeout)
    {
      timedout = true;
      break;
    }
    if (vif != NULL) vif(vif_data);
  }
  if (timedout) return -1;
  return 0;
}

bool vna_acquire_dataset(vna_acquisition_state *vs, vna_acquire_dataset_operation vado, void *v)
{
  int n,c;
  unsigned int freqstep;
  vna_acquire_dataset_state vads;

  vna_initialize_si5351();
  freqstep = (vs->endfreq - vs->startfreq) / vs->nfreqs;
  for (n = 0; n < vs->nfreqs; n++)
  {
    unsigned int freq = vs->startfreq + freqstep * n;
    setup_frequency_acquire(freq);
    if (n == 0)
    {
      if (acquire_sample(12, vs->timeout) < 0)
        return false;
    }
    if (acquire_sample(vs->num_averages, vs->timeout) < 0)
      return false;
    vads.n = n;
    vads.total = vs->nfreqs;
    vads.freq = freq;
    vads.volti = sampVOLTI;
    vads.voltq = sampVOLTQ;
    vads.curi = sampCURI;
    vads.curq = sampCURQ;
    vads.cur2i = sampCUR2I;
    vads.cur2q = sampCUR2Q; 
    vado(&vads, v);
	  if (console_inchar() == '!')
        return false;
#ifdef VNA_TOUCHSCREEN
    if (touchscreen_enabled && touchscreen_abort())
       return false;
#endif
  }
  return true;
}

stevestrong
Posts: 75
Joined: Tue Mar 05, 2019 7:49 am
Location: Munich
OS: Win7 & 10
IDE: Arduino 1.8.8, Sloeber
Core: Libmaple
Board: Bluepill, Generic F4VET6 black & mini
Contact:

Re: Weird interaction between SPI and TIMER3

Post by stevestrong » Mon Nov 11, 2019 8:50 am


Post Reply