2 Replies Latest reply on Mar 3, 2017 10:50 AM by Intel Corporation

    Quark D2000 PWM Signal Offset

    cartejac

      Hello all,

       

      As part of my senior capstone for an Electrical Computer Engineering degree I am trying to use a Quark D2000 microcontroller to generate some PWM signals with fairly precise time offsets from one another (90 degrees of an 800kHz waveform, for example)

       

      I have been struggling to get the PWM module to behave as I expect it to. I am trying to configure one of the PWM/Timers to generate an interrupt after a certain period and then reconfigure itself as a PWM signal generator. At the same time, I am delaying the start of the other PWM timer using a system wait function call. I understand that I might not be able to get the waveforms to start at precisely the same time given the single-threaded nature of this processor, but I cannot get nearly the accuracy that I expect. Using the code below:

       

      void pwm_delay_cb(void* pwm_config, uint32_t timer_status)

      {

        send_string_log_pkt("Timer1 cb fired.");

        qm_pwm_stop(QM_PWM_0, QM_PWM_ID_1); //TODO: Is this necessary? The timer might stop on overflow

        qm_pwm_config_t* p = (qm_pwm_config_t *) pwm_config;

        if (qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_1, p) != 0){

             return;

        }

       

       

        qm_pwm_start(QM_PWM_0, QM_PWM_ID_1);

        qm_pmux_select(QM_PIN_ID_24, QM_PMUX_FN_2);

        free(pwm_config);

      }

       

       

       

       

      /* There's just one space for interrupt callbacks, for some reason.

      * and setting a configuration without interrupts or a callback clears

      * previously set interrupts. BEWARE

      * The delay appears to be controllable at scales larger than 15us,

      * but when you try to compress the offset to less than that, the

      * waveforms do not shift....

      */

      uint8_t enable_pwm(uint32_t high_ticks, uint32_t low_ticks, uint32_t delay_ticks)

      {

        // Go for PWM enabled, no interrupt

        qm_pwm_config_t delay_config;

        qm_pwm_config_t *pwm_config = malloc(sizeof(qm_pwm_config_t));

        pwm_config->hi_count = high_ticks;

        pwm_config->lo_count = low_ticks;

        pwm_config->mask_interrupt = true;

        pwm_config->mode = QM_PWM_MODE_PWM;

       

       

        // Set the configuration for PWM0

        if (qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_0, pwm_config) != 0){

             return -1;

        }

       

       

        // Set it off!

        // Set up the delay for the second PWM signal

        delay_ticks = delay_ticks + 50; // Tack on additional delay for the pulses to start at the same time. //75 to 63, huge jump

        /* Somewhere between 500 and 600, there's a huge jump... */

        delay_config.hi_count = delay_ticks;

        delay_config.lo_count = delay_ticks;

        delay_config.mask_interrupt = false;

        delay_config.callback = pwm_delay_cb;

        delay_config.callback_data = pwm_config;

        delay_config.mode = QM_PWM_MODE_TIMER_FREE_RUNNING;

        if (qm_pwm_set_config(QM_PWM_0, QM_PWM_ID_1, &delay_config) != 0){

        return -1;

        }

       

       

        /*qm_pwm_reg_t* r = QM_PWM;

        r->timer[QM_PWM_ID_1].loadcount = delay_ticks;

        QM_PWM->timer[QM_PWM_ID_1].controlreg |= 1; // Force delay_ticks into currentvalue field

        QM_PWM->timer[QM_PWM_ID_1].controlreg &= ~1;

        QM_PWM->timer[QM_PWM_ID_1].controlreg |= 1; // Force delay_ticks into currentvalue field

        QM_PWM->timer[QM_PWM_ID_1].controlreg &= ~1;

        QM_PWM->timer[QM_PWM_ID_1].controlreg |= 1; // Force delay_ticks into currentvalue field

        QM_PWM->timer[QM_PWM_ID_1].controlreg &= ~1;*/

       

       

        // Request the routing of the timer interrupt signal

        qm_irq_request(QM_IRQ_PWM_0, qm_pwm_isr_0);

       

       

        // Turn on Timer 1

        qm_pwm_start(QM_PWM_0, QM_PWM_ID_1);

        clk_sys_udelay(1);

       

       

        qm_pwm_start(QM_PWM_0, QM_PWM_ID_0);

        clk_sys_udelay(1000);

       

       

        // Change the pin multiplexing to put the signal on the physical pin

        qm_pmux_select(QM_PIN_ID_19, QM_PMUX_FN_2);

       

       

        return 0;

      }

        • 1. Re: Quark D2000 PWM Signal Offset
          cartejac

          I pressed Ctrl-s and it posted before I could fully format the code and remove comments.

           

          But that is it. called using enable_pwm(20, 20, 20).

           

          This starts PWM0 1ms after PWM1 on my machine. Changing the 50 added to delay_ticks to 500, however, pushes PWM0 to start just 15us after PWM1, but increasing it small amounts after that does not change the time difference of the start of the waveforms. Not only is that change in delay far too large for the change in timer ticks (450 * 1/32MHz ~ 14us), but I cannot control it to a finer granularity after that.

           

          I've been playing with adding delays at all points along these functions and moving around when I change the pin multiplexing and timer starting, but I cannot seem to get the microcontroller to respond in a way that I understand, let alone predictably.

           

          My questions then:

          Is this method a valid way to configure the PWM on the Quark? Are there better ways with finer granularity?

          Why does the system not allow me to achieve a closer start between the waveforms?

          Why so much variance between PWM start times for the given delay_tick values?

          • 2. Re: Quark D2000 PWM Signal Offset
            Intel Corporation
            This message was posted on behalf of Intel Corporation

            Hi Cartejac,

            Thank you for contacting us.

            Let us investigate more about your issue and we'll let you know when we have updates.

            Have a nice day.

            Regards,
            Leonardo R.