# A patch for the Bus Pirate firmware to enable specifying PWM # frequencies with 1 Hz precision (works at least down to 2 Hz). # To avoid breaking existing scripts, the old syntax for KHz # PWM (command "g") is kept and the new Hz variant is a new # command "G". # # Apply the patch in the Bus Pirate firmware source directory with: # patch -p0 , 2012-02-04, 2012-02-07 # Copyright waived on this code. # Index: AUXpin.c =================================================================== --- AUXpin.c (revision 1716) +++ AUXpin.c (working copy) @@ -16,7 +16,11 @@ #include "base.h" #include "procMenu.h" - //TRISDbits.TRISD5 +#ifndef CLOCK_FREQ +#define CLOCK_FREQ 32000000 +#endif + +//TRISDbits.TRISD5 #define AUXPIN_DIR BP_AUX_DIR // 20 @@ -36,72 +40,83 @@ unsigned long bpFreq_count(void); +static void bpPWM(const unsigned int hz_mult); + int PWMfreq; int PWMduty; +#define PWM_MAX_FREQ 4000000L + +static void PWMstart(const long freq_hz, unsigned int PWM_pd) { + unsigned int PWM_period; + float pf = (2.0f / CLOCK_FREQ); + + // Choose the prescaler according to frequency + if(freq_hz<4000){ + pf *= 256; + T2CONbits.TCKPS1=1; + T2CONbits.TCKPS0=1; + }else if(freq_hz<31000){ + pf *= 64; + T2CONbits.TCKPS1=1; + T2CONbits.TCKPS0=0; + }else if(freq_hz<245000L){ + pf *= 8; + T2CONbits.TCKPS1=0; + T2CONbits.TCKPS0=1; + }else{ + T2CONbits.TCKPS1=0; + T2CONbits.TCKPS0=0; + } + pf = (1.0f / freq_hz) / pf - 1; + // Adding 0.5f would round properly but makes the code larger + PWM_period = (unsigned int)(pf /*+ 0.5f*/); + pf *= PWM_pd / 100.0f; + PWM_pd = (unsigned int)(pf /*+ 0.5f*/); + + //assign pin with PPS + AUXPIN_RPOUT = OC5_IO; + // should be fine on bpv4 + + OC5R = PWM_pd; + OC5RS = PWM_pd; + OC5CON = 0x6; + PR2 = PWM_period; + T2CONbits.TON = 1; + + AUXmode=AUX_PWM; +} + //setup PWM frequency using user values in global variables void updatePWM(void) -{ unsigned int PWM_period, PWM_dutycycle, PWM_div; - +{ //cleanup timers T2CON=0; // clear settings T4CON=0; OC5CON =0; //#BPV4 - should be OC5CON1/2 - if(PWMfreq==0) - { AUXPIN_RPOUT = 0; //remove output from AUX pin + if(PWMfreq==0) { + AUXPIN_RPOUT = 0; //remove output from AUX pin AUXmode=AUX_IO; return; } + PWMstart((long)PWMfreq * 1000, PWMduty); +} - if(PWMfreq<4) - { //use 256 //actual max is 62500hz - PWM_div=62;//actually 62500 - T2CONbits.TCKPS1=1; - T2CONbits.TCKPS0=1; - } - else if(PWMfreq<31) - { //use 64 - PWM_div=250; - T2CONbits.TCKPS1=1; - T2CONbits.TCKPS0=0; - } - else if(PWMfreq<245) - { //use 8 - PWM_div=2000; - T2CONbits.TCKPS1=0; - T2CONbits.TCKPS0=1; - } - else - { //use 1 - PWM_div=16000; - T2CONbits.TCKPS1=0; - T2CONbits.TCKPS0=0; - } - PWM_period=(PWM_div/PWMfreq)-1; - PR2 = PWM_period; +//setup the PWM/frequency generator (in KHz) +void bpPWMKHz(void){ + bpPWM(1000); +} - PWM_dutycycle=(PWM_period*PWMduty)/100; - - - //assign pin with PPS - AUXPIN_RPOUT = OC5_IO; - // Should be fine on bpv4 - - OC5R = PWM_dutycycle; - OC5RS = PWM_dutycycle; - OC5CON = 0x6; - T2CONbits.TON = 1; - - AUXmode=AUX_PWM; - +//setup the PWM/frequency generator (in Hz) +void bpPWMHz(void){ + bpPWM(1); } //setup the PWM/frequency generator -void bpPWM(void){ - unsigned int PWM_period, PWM_dutycycle, PWM_freq, PWM_div; - int done; - float PWM_pd; +static void bpPWM(const unsigned int hz_mult) { + long PWM_freq; + unsigned int PWM_pd; //cleanup timers T2CON=0; // clear settings @@ -117,88 +132,39 @@ if(cmdbuf[((cmdstart+1)&CMDLENMSK)]==0x00) return; // return if no arguments to function } - done=0; - cmdstart=(cmdstart+1)&CMDLENMSK; //cmdstart&=CMDLENMSK; //get any compound commandline variables consumewhitechars(); - PWM_freq=getint(); + PWM_freq=getint(); // TODO: range of int insufficient in Hz for > 32KHz (use KHz version) + PWM_freq *= hz_mult; consumewhitechars(); PWM_pd=getint(); //sanity check values - if((PWM_freq>0)&&(PWM_freq<4000)) done++; - if((PWM_pd>0)&&(PWM_pd<100)) done++; - - - //calculate frequency: - if(done!=2)//no command line variables, prompt for PWM frequency - { cmderror=0; - - //bpWline(OUMSG_AUX_PWM_NOTE); + if ((PWM_freq<=0)||(PWM_freq>PWM_MAX_FREQ)|| + (PWM_pd<=0)||(PWM_pd>=100)) { + //no command line variables, prompt for PWM frequency + cmderror=0; + if (hz_mult == 1000) { + // KHz BPMSG1029; - //bpWstring(OUMSG_AUX_PWM_FREQ); BPMSG1030; - PWM_freq=getnumber(50,1, 4000, 0); + PWM_freq=getnumber(50,1,(int)(PWM_MAX_FREQ/1000), 0); + } else { + // TODO: Convert to BPMSG? + bpWstring("1-"); + bpWlongdec(PWM_MAX_FREQ); + bpWstring("Hz PWM\r\nFrequency in Hz"); + PWM_freq=getlong(500,1,PWM_MAX_FREQ,0); + } + PWM_freq *= hz_mult; + BPMSG1033; + PWM_pd=getnumber(50,0,99,0); } - - //choose proper multiplier for whole range - //bpWstring(OUMSG_AUX_PWM_PRESCALE); - //BPMSG1031; - if(PWM_freq<4){//use 256 //actual max is 62500hz - //bpWline("256"); - PWM_div=62;//actually 62500 - T2CONbits.TCKPS1=1; - T2CONbits.TCKPS0=1; - }else if(PWM_freq<31){//use 64 - //bpWline("64"); - PWM_div=250; - T2CONbits.TCKPS1=1; - T2CONbits.TCKPS0=0; - }else if(PWM_freq<245){//use 8 - //bpWline("8"); - PWM_div=2000; - T2CONbits.TCKPS1=0; - T2CONbits.TCKPS0=1; - }else{//use 1 - //bpWline("1"); - PWM_div=16000; - T2CONbits.TCKPS1=0; - T2CONbits.TCKPS0=0; - } - PWM_period=(PWM_div/PWM_freq)-1; - //bpWstring("PR2:"); - //BPMSG1032; - //bpWintdec(PWM_period); //echo the calculated value - //bpBR; - - if(done!=2)//if no commandline vairable, prompt for duty cycle - { //bpWstring(OUMSG_AUX_PWM_DUTY); - BPMSG1033; - // PWM_pd=bpUserNumberPrompt(2, 99, 50); - PWM_pd=getnumber(50,0,99,0); - } - - PWM_pd/=100; - PWM_dutycycle=PWM_period * PWM_pd; - //bpWdec(PWM_dutycycle); - - //assign pin with PPS - AUXPIN_RPOUT = OC5_IO; - // should be fine on bpv4 - - OC5R = PWM_dutycycle; - OC5RS = PWM_dutycycle; - OC5CON = 0x6; - PR2 = PWM_period; - T2CONbits.TON = 1; - - //bpWline(OUMSG_AUX_PWM_ON); BPMSG1034; - AUXmode=AUX_PWM; - + PWMstart(PWM_freq, PWM_pd); } //frequency measurement Index: procMenu.c =================================================================== --- procMenu.c (revision 1716) +++ procMenu.c (working copy) @@ -520,9 +520,16 @@ if (bpConfig.busMode == HIZ) { //bpWmessage(MSG_ERROR_MODE); BPMSG1088; } else { - bpPWM(); + bpPWMKHz(); } break; + case 'G': + if (bpConfig.busMode == HIZ) { //bpWmessage(MSG_ERROR_MODE); + BPMSG1088; + } else { + bpPWMHz(); + } + break; case 'c': //bpWline("-aux pin assigment"); modeConfig.altAUX = 0; //bpWmessage(MSG_OPT_AUXPIN_AUX); @@ -1342,7 +1349,7 @@ } //getnumber(int def, int min, int max, int x) -#if defined(BUSPIRATEV4) +//#if defined(BUSPIRATEV4) // gets number from input // -1 = abort (x) // -2 = input to much @@ -1443,7 +1450,7 @@ } return temp; // we dont get here, but keep compiler happy } -#endif +//#endif Index: AUXpin.h =================================================================== --- AUXpin.h (revision 1716) +++ AUXpin.h (working copy) @@ -15,7 +15,8 @@ */ void bpFreq(void); unsigned long bpBinFreq(void); -void bpPWM(void); +void bpPWMKHz(void); +void bpPWMHz(void); void updatePWM(void); void bpAuxHiZ(void); Index: procMenu.h =================================================================== --- procMenu.h (revision 1716) +++ procMenu.h (working copy) @@ -42,7 +42,7 @@ int cmdhistory(void); #endif int getnumber(int def, int min, int max, int x); -#if defined(BUSPIRATEV4) +//#if defined(BUSPIRATEV4) long getlong(long def, int min, long max, int x); -#endif +//#endif