Is it possible to have 8 PWM outputs at 10KHZ using the xCore. If yes how is this implemented
I require 8 PWM Topic is solved
-
- Newbie
- Posts: 1
- Joined: Fri Oct 10, 2014 3:08 pm
-
- Respected Member
- Posts: 275
- Joined: Fri Mar 12, 2010 6:03 pm
That should definitely be possible. Have a look at the PWM code available at https://github.com/xcore/sc_pwm.
-
Verified
- XCore Legend
- Posts: 1153
- Joined: Thu May 27, 2010 10:08 am
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)
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)
You do not have the required permissions to view the files attached to this post.
-
- Member
- Posts: 12
- Joined: Sun Feb 16, 2014 8:36 am
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.
Have fun!
Greatings
Schorsch
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;
}
Greatings
Schorsch
-
- Member++
- Posts: 31
- Joined: Mon Jan 20, 2020 9:54 am
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
You do not have the required permissions to view the files attached to this post.
-
- XCore Legend
- Posts: 1913
- Joined: Thu Jun 10, 2010 11:43 am
@Schatz143, try a CLEAN before Build All for this project and post your results.