This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Adjusting PWM freq from example code

Hi guys,

Recently, I've been trying to use the sample codes of C8051F120 DK: ADC and PCA (for PWM) in attempt to 1) produce a 100kHz, 28% duty cycle 3.3V PWM & 2) read an analog voltage signal in the range of 0-2.43V and display it on Hyperterminal via UART1.

Had realised that in order to create a 100kHz PWM, the CLK divider should be 0x20 and CLK multiplier should be about 0x21 to get that 100kHz, but if I change PLL0DIV = 0x20 and PLL0MUL = 0x21 accordingly, the display at the hyperterminal could not display the sensed mV properly. And if I used the default settings for PLL0DIV & PLL0MUL, the PWM will be 194kHz instead of 100kHz. So, it is really a chicken or egg problem.

Could anyone know how to do it in order for me to achieve both 1) 100kHz PWM and 2) displaying the sensed voltage correctly?

My partial codes are as below (since it is too long to be posted).

Recently, I've been trying to use the sample codes: ADC and PCA (for PWM) in attempt to 1) produce a 100kHz, 28% duty cycle 3.3V PWM & 2) read an analog voltage signal in the range of 0-2.43V and display it on Hyperterminal via UART1.

Had realised that in order to create a 100kHz PWM, the CLK divider should be 0x20 and CLK multiplier should be about 0x21 to get that 100kHz, but if I change PLL0DIV = 0x20 and PLL0MUL = 0x21 accordingly, the display at the hyperterminal could not display the sensed mV properly. And if I used the default settings for PLL0DIV & PLL0MUL, the PWM will be 194kHz instead of 100kHz. So, it is really a chicken or egg problem.

Could anyone know how to do it in order for me to achieve both 1) 100kHz PWM and 2) displaying the sensed voltage correctly?

My codes are as below.

void main (void)
{
 long measurement; // Measured voltage in mV
 unsigned int delay_count; // Used to implement a delay
 bit duty_direction = 0; // 0 = Decrease; 1 = Increase

 // Disable watchdog timer
 WDTCN = 0xde;
 WDTCN = 0xad;

 PORT_Init (); // Initialize crossbar and GPIO
 OSCILLATOR_Init (); // Initialize oscillator
 PCA0_Init (); // Initialize PCA0
 UART1_Init (); // Initialize UART1
 TIMER3_Init (SYSCLK/SAMPLE_RATE); // Initialize Timer3 to overflow at sample rate

 ADC0_Init (); // Init ADC

 SFRPAGE = ADC0_PAGE;
 AD0EN = 1; // Enable ADC

 EA = 1; // Enable global interrupts

 while (1)
 {
 EA = 0; // Disable interrupts

 // The 12-bit ADC value is averaged across INT_DEC measurements. The result is
// then stored in Result, and is right-justified
// The measured voltage applied to AIN 0.1 is then:
 //
 // Vref (mV)
 // measurement (mV) = --------------- * Result (bits)
// (2^12)-1 (bits)

 measurement = Result * 2430 / 4095;

 EA = 1; // Re-enable interrupts

 SFRPAGE = UART1_PAGE;

 printf("AIN0.1 voltage: %ld mV\n",measurement);

 SFRPAGE = CONFIG_PAGE;
 LED = ~SW1; // LED reflects state of switch

 Wait_MS(SAMPLE_DELAY); // Wait 50 milliseconds before taking another sample
 Set_PCA0_Duty_Cycle(74);
 }

void OSCILLATOR_Init (void)
{
 int loop; // Software timer

 char SFRPAGE_save = SFRPAGE; // Save Current SFR page

 SFRPAGE = CONFIG_PAGE; // Set SFR page

 OSCICN = 0x83; // Set internal oscillator to run
 // at its maximum frequency

 CLKSEL = 0x00; // Select the internal osc. as
 // the SYSCLK source

 //Turn on the PLL and increase the system clock by a factor of M/N = 2
 SFRPAGE = CONFIG_PAGE;

 PLL0CN = 0x00; // Set internal osc. as PLL source
 SFRPAGE = LEGACY_PAGE;
 FLSCL = 0x10; // Set FLASH read time for 50MHz clk
 // or less
 SFRPAGE = CONFIG_PAGE;
 PLL0CN |= 0x01; // Enable Power to PLL
 PLL0DIV = 0x01; // Set Pre-divide value to N (N = 1)
 PLL0FLT = 0x01; // Set the PLL filter register for
 // a reference clock from 19 - 30 MHz
 // and an output clock from 45 - 80 MHz
 PLL0MUL = 0x02; // Multiply SYSCLK by M (M = 2)

 for (loop=0; loop < 256; loop++); // Wait at least 5us
 PLL0CN |= 0x02; // Enable the PLL
 while(!(PLL0CN & 0x10)); // Wait until PLL frequency is locked
 CLKSEL = 0x02; // Select PLL as SYSCLK source

 SFRPAGE = SFRPAGE_save; // Restore SFR page
}

void PCA0_Init (void)
{
 char SFRPAGE_save = SFRPAGE; // Save current SFR Page

 SFRPAGE = PCA0_PAGE;
 // configure PCA time base; overflow interrupt disabled
 PCA0CN = 0x00; // Stop counter; clear all flags
 PCA0MD = 0x08; // Use SYSCLK as time base

 PCA0CPM0 = 0x42; // Module 0 = 8-bit PWM mode

 // Configure initial PWM duty cycle = 50%
 PCA0CPH0 = 256 - (256 * 0.5);

 // Start PCA counter
 CR = 1;
 SFRPAGE = SFRPAGE_save;
}

void Set_PCA0_Duty_Cycle(unsigned short l_us_duty_cycle)
{
 //Save current SFR Page
 char SFRPAGE_SAVE = SFRPAGE;

 SFRPAGE = PCA0_PAGE;

 if (l_us_duty_cycle == 0)
 {
 //For 0% duty cycle, clear ECOM0
 //PCA0CPM0 &= 0xBF;

 //lsl : 02 Jun 2011 : 1744hrs
 //For 0% duty cycle, clear ECOM0 (bit 6) & PWM0 (bit 1)
 PCA0CPM0 &= 0xBD;
 }
 else if (l_us_duty_cycle > 255)
 {
 //For 100% duty cycle
 //a. Set ECOM0 (bit 6) & PWM0 (bit 1)
 //b. Load 0x00 into PCA0CPH0

 PCA0CPM0 |= 0x42; //0x40;

 PCA0CPH0 = 0;
 }
 else
 {
 PCA0CPM0 |= 0x42; //0x40;

 PCA0CPH0 = 256 - (unsigned char)(l_us_duty_cycle & 0xFF);
 }

 //Restore the SFRPAGE
 SFRPAGE = SFRPAGE_SAVE;
}

void ADC0_Init (void)
{
 char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page

 SFRPAGE = ADC0_PAGE;

 ADC0CN = 0x04; // ADC0 disabled; normal tracking
 // mode; ADC0 conversions are initiated
 // on overflow of Timer3; ADC0 data is
 // right-justified

 REF0CN = 0x07; // Enable temp sensor, on-chip VREF,
 // and VREF output buffer

 AMX0CF = 0x00; // AIN inputs are single-ended (default)

 AMX0SL = 0x01; // Select AIN0.1 pin as ADC mux input

 ADC0CF = (SYSCLK/SAR_CLK) << 3; // ADC conversion clock = 2.5MHz
 ADC0CF |= 0x00; // PGA gain = 1 (default)

 EIE2 |= 0x02; // enable ADC interrupts

 SFRPAGE = SFRPAGE_SAVE; // Restore SFR page
}

0