I require 8 PWM Topic is solved

If you have a simple question and just want an answer.
Post Reply
lexicon1
Newbie
Posts: 1
Joined: Fri Oct 10, 2014 3:08 pm

I require 8 PWM

Post by lexicon1 »

Is it possible to have 8 PWM outputs at 10KHZ using the xCore. If yes how is this implemented 



View Solution
User avatar
larry
Respected Member
Posts: 275
Joined: Fri Mar 12, 2010 6:03 pm

Post by larry »

That should definitely be possible. Have a look at the PWM code available at https://github.com/xcore/sc_pwm.

User avatar
infiniteimprobability
XCore Legend
Posts: 1126
Joined: Thu May 27, 2010 10:08 am
Contact:

Post by infiniteimprobability »

Here's a configurable n-channel PWM module. How many bits resolution do you need?

Using 8 x 1b ports, it will give you 10.28bits of resolution at 10.016KHz using all 8 cores (ie. 62.5MIPS for PWM). It provides reset synchnronised, buffered PWM which can go from 0 to 100% duty with no gaps. 

It contains a test program ran on the simulator (althoguh I tested and it is fine on hardware too)

PWM freq=10016Hz, resolution=1248 steps, at 80ns each

Resolution = 10.285402bits

xsim: error: C51188: maximum cycles reached (1000000)
Screen Shot 2014-10-16 at 09.28.32.png
(45.93 KiB) Not downloaded yet
Screen Shot 2014-10-16 at 09.28.32.png
(45.93 KiB) Not downloaded yet
Attachments
pwm.zip
(3.19 KiB) Downloaded 318 times
pwm.zip
(3.19 KiB) Downloaded 318 times
Schorsch
Member
Posts: 12
Joined: Sun Feb 16, 2014 8:36 am

Post by Schorsch »

Hi lexicon1,

here is a very simple way with less resource usage. For many of application it is enough. You can
configure each bit ( of a port ) you want. I think, you searched for that way.

Code: Select all

/*
 * xCORE200_multiPWM.xc
 *
 *  Created on: 25.04.2016
 *      Author: Schorsch
 *
 *      A very simple way!
 *      You can expand this on a 8 bit port, too!
 *      Whithout a need of a timer!
 *      For many application it works fine!
 *      If you need less frequency, your resolution is getting better.
 */


#include <xs1.h>
#include <platform.h>
#include <stdio.h>

#define FLASH_PERIOD 100000000  // for testing

on tile[1]: out port PWM = XS1_PORT_4B;

interface my_pwm_interface
{
    void setPWM0( int impulsWidth );    //
    void setPWM1( int impulsWidth );
    void setPWM2( int impulsWidth );
    void setPWM3( int impulsWidth );
};

void app( interface my_pwm_interface server c )
{
    int pwm0Period, pwm0ON, pwm0Counter;
    int pwm1Period, pwm1ON, pwm1Counter;
    int pwm2Period, pwm2ON, pwm2Counter;
    int pwm3Period, pwm3ON, pwm3Counter;
    unsigned int containerPort;

    pwm0Period  = 250;      // Periodtime -> correlates 10,7 kHz
    pwm0ON      =  100;     // Pulsetime
    pwm1Period  = 250;
    pwm1ON      =  50;
    pwm2Period  = 250;
    pwm2ON      =  200;
    pwm3Period  = 250;
    pwm3ON      =  50;

    while(1)
    {
        select
        {
            case c.setPWM0( int impulsWidth ):
            {
                  pwm0ON = impulsWidth;
            }
               break;
            case c.setPWM1( int impulsWidth ):
            {
                  pwm1ON = impulsWidth;
            }
               break;
            case c.setPWM2( int impulsWidth ):
            {
                  pwm2ON = impulsWidth;
            }
               break;
            case c.setPWM3( int impulsWidth ):
            {
                  pwm3ON = impulsWidth;
            }
               break;
            default:
            {
              // set alway on ( Don't worry! ) -> if clauses clear the respective bit
              containerPort = 0xF;

              pwm0Counter++;
              pwm1Counter++;
              pwm2Counter++;
              pwm3Counter++;

              // is Counter greater than "Pulsetime"
              if ( pwm0Counter >= pwm0ON )
              {
                  // clear Bit
                  containerPort &= ~( 1 << 0 );
              }
              // is Counter greater than "Periodtime"
              if ( pwm0Counter >= pwm0Period )
              {
                  // restart Counter
                  pwm0Counter = 0;
              }

              if ( pwm1Counter >= pwm1ON )
              {
                  containerPort &= ~( 1 << 1 );
              }
              if ( pwm1Counter >= pwm1Period )
              {
                  pwm1Counter = 0;
              }

              if ( pwm2Counter >= pwm2ON )
              {
                  containerPort &= ~( 1 << 2 );
              }
              if ( pwm2Counter >= pwm2Period )
              {
                  pwm2Counter = 0;
              }

              if ( pwm3Counter >= pwm3ON )
              {
                  containerPort &= ~( 1 << 3 );
              }
              if ( pwm3Counter >= pwm3Period )
              {
                  pwm3Counter = 0;
              }

              // send Value on 4-bit Port
              PWM <: containerPort;
            }
              break;

          } // ENDE select

    } // ENDE while(1)

} // ENDE app()

// wait loop for testing
void wait(void)
{
    timer tmr;
    unsigned t;
    tmr :> t;
    t+=FLASH_PERIOD;
    tmr when timerafter (t) :> void;
}

// testapplication
void app2( interface my_pwm_interface client c )
{
    wait();
    wait();
    c.setPWM0( 100 );
    c.setPWM3( 200 );
    wait();

    c.setPWM0( 200 );
    wait();

    c.setPWM0( 40 );
    wait();

    c.setPWM0( 50 );
    wait();

    c.setPWM0( 60 );
    c.setPWM2( 100 );
    wait();

    c.setPWM0( 100 );
    wait();

    c.setPWM0( 200 );
    wait();

    c.setPWM0( 69 );
    wait();

    c.setPWM0( 100 );
    wait();
}


int main( void )
{
    interface my_pwm_interface c;
    par
    {
        on tile[1]: app( c );
        on tile[1]: app2( c );
    }
    return 0;
}
Have fun!

Greatings

Schorsch
Schatz143
Member++
Posts: 31
Joined: Mon Jan 20, 2020 9:54 am

Post by Schatz143 »

Code: Select all


#include <xs1.h>
#include <string.h>
#include <stdlib.h>
#include "debug_print.h"
#include "pwm.h"

extern buffered out port:32 p_pwm[PWM_CHANNELS];
extern clock clk_pwm;

//Externally callable set duty. Puts a few calculations on client side to ease timing on server side
#if USE_INTERFACE == 1
void set_duty(unsigned channel, unsigned duty, client pwm_if_t i_pwm){
  pwm_duty_t new_pwm;

#ifdef MAX_DUTY
  if (duty > MAX_DUTY) duty = MAX_DUTY;
#else
  if (duty > N_BITS_RESO) duty = N_BITS_RESO;
#endif
#ifdef MIN_DUTY
  if (duty < MIN_DUTY) duty = MIN_DUTY;
#endif

  new_pwm.transition_cnt = N_FRAMES - (duty >> 5);  //Integer number of 32b frames
  new_pwm.transition_idx = duty & 0x1f;             //Remainder - how many 1s per 32b frame

  i_pwm.set_duty(channel, new_pwm);

#else //use channels
void set_duty(unsigned channel, unsigned duty, streaming chanend c_pwm){
  unsigned transition_cnt;
  unsigned transition_idx;

#ifdef MAX_DUTY
  if (duty > MAX_DUTY) duty = MAX_DUTY;
#else
  if (duty > N_BITS_RESO) duty = N_BITS_RESO;
#endif
#ifdef MIN_DUTY
  if (duty < MIN_DUTY) duty = MIN_DUTY;
#endif

  if (duty >= N_BITS_RESO) duty = N_BITS_RESO;

  transition_cnt = N_FRAMES - (duty >> 5);  //Integer number of 32b frames
  transition_idx = duty & 0x1f;             //Remaidner - how many 1s per 32b frame
  c_pwm <: channel;
  c_pwm <: transition_cnt;
  c_pwm <: transition_idx;
#endif
}

#pragma unsafe arrays
static inline unsigned get_transition_frame(unsigned index){ //Fast
  const unsigned lookup[33]={
      0x00000000,
      0x80000000,
      0xc0000000,
      0xe0000000,
      0xf0000000,
      0xf8000000,
      0xfc000000,
      0xfe000000,
      0xff000000,
      0xff800000,
      0xffc00000,
      0xffe00000,
      0xfff00000,
      0xfff80000,
      0xfffc0000,
      0xfffe0000,
      0xffff0000,
      0xffff8000,
      0xffffc000,
      0xffffe000,
      0xfffff000,
      0xfffff800,
      0xfffffc00,
      0xfffffe00,
      0xffffff00,
      0xffffff80,
      0xffffffc0,
      0xffffffe0,
      0xfffffff0,
      0xfffffff8,
      0xfffffffc,
      0xfffffffe,
      0xffffffff};

  return (lookup[index]);
}

//The PWM task. Uses 32b serialised (buffered) ports to output pwm frames.
#pragma unsafe arrays
#if USE_INTERFACE == 1
void pwm_task(server pwm_if_t i_pwm){
#else
void pwm_task(streaming chanend c_pwm){
  unsigned pwm_channel;
#endif

  int i = 0, j = 0;
  const unsigned port_initial = 0;
  unsigned update[PWM_CHANNELS] = {0};
  pwm_duty_t pwm_duty[2][PWM_CHANNELS] = {{{0}}}; //double buffered array of pwm structs
  unsigned pwm_indx[PWM_CHANNELS] = {0};

  set_clock_on(clk_pwm);
  configure_clock_rate_at_least(clk_pwm, 100, PWM_CLK_DIV);
  stop_clock(clk_pwm);
  for (i=0; i<PWM_CHANNELS; i++){

    partout(p_pwm[i], 1, port_initial); //Tried to force low - doesn't seem to work
    configure_out_port(p_pwm[i], clk_pwm, port_initial);
    p_pwm[i] <: port_initial;
  }
  start_clock(clk_pwm);

  while(1){
#pragma loop unroll
    for (i=1; i<N_FRAMES+1; i++){ //Output N 32b frames
#pragma loop unroll
      for(j=0; j<PWM_CHANNELS; j++){ //Output a frame for each PWM channel

        if (i == pwm_duty[pwm_indx[j]][j].transition_cnt){
          p_pwm[j] <: get_transition_frame(pwm_duty[pwm_indx[j]][j].transition_idx);
        }
        else if (i < pwm_duty[pwm_indx[j]][j].transition_cnt){
          p_pwm[j] <: get_transition_frame(0); //All zeros
        }
        else {   //(i  pwm_duty[j].transition_cnt)
          p_pwm[j] <: get_transition_frame(32); //All ones
        }
      }//for j (pwm chans)

      select {  //Check to see if new duty has been requested, if so buffer
#if USE_INTERFACE == 1
        case i_pwm.set_duty(unsigned channel, pwm_duty_t new_duty):
          unsigned next_buf = pwm_indx[pwm_channel] ^ 1;
          memcpy(&pwm_duty[next_buf][channel], &new_duty, sizeof(new_duty));
          update[channel] = 1;
        break;
#else
        case c_pwm :> pwm_channel:
          unsigned next_buf = pwm_indx[pwm_channel] ^ 1;

          c_pwm :> pwm_duty[next_buf][pwm_channel].transition_cnt;
          c_pwm :> pwm_duty[next_buf][pwm_channel].transition_idx;
          update[pwm_channel] = 1;
        break;
#endif
        default: //Drop through if no new PWM duty to buffer
        break;
      }// select
    }//for i (nframes)

#pragma loop unroll
    for(j=0; j<PWM_CHANNELS; j++){ //Check to see if new duty is in buffer, if so, switch buffer
      if (update[j]){
        pwm_indx[j] ^= 1; //swap buffer
        update[j] = 0;    //clear update request flag
      }
    } //for j
//    debug_printf("Iterations to go = %d\n", running);
  }//while 1
}



i get to run the code given by "infiniteimprobability " on xcore 200 explorer kit.I get the followiing error
which i attch below
Attachments
Error.png
Error.png (17.36 KiB) Viewed 69790 times
Error.png
Error.png (17.36 KiB) Viewed 69790 times
User avatar
mon2
XCore Legend
Posts: 1913
Joined: Thu Jun 10, 2010 11:43 am
Contact:

Post by mon2 »

@Schatz143, try a CLEAN before Build All for this project and post your results.
Post Reply