How to sense feedback voltage using C8051F120 Development Kit

Thread Starter

gdylp2004

Joined Dec 2, 2011
101
Hi,

I am currently using the C8051F120 development kit (see attached) in attempt to sense the o/p voltage from my Buck convertor and adjust the PWM signal, which is also generated from the 8051 chip.

However my question is how should I connect point A (see another attachment) and interface it with the development kit?

I've read somewhere from the datasheet that there is an internal reference voltage of 1.2V and therefore I've stepped down the 28V output with a set of appropriate resistors (R1 & R2).

Assuming I would like to make about 30 samples before I made one adjustment to the PWM duty cycle, would what I've drawn in the attached been feasible?

Also, I got a hunch that I might as well omit the comparator and DAC, that is, connecting the register output directly to the processor.

Any comments would be appreciated.

Thanks in advance.

- Michael
 

Attachments

Thread Starter

gdylp2004

Joined Dec 2, 2011
101
Ok, my objective is to get an as accurate 28V output voltage as possible. Right now, my open-loop Buck converter output is only at about 26.67V DC while "pumping" 28% duty cycle, 100kHz 3.3V PWM into my Buck.

As seen in my attached with a red circle, the input coming into the ADC0 seems like in pairs. So my question is would a single-ended input be better or a differential input to this ADC0 be more appropriate for me to obtain an as accurate 28V output as possible?

Let's say if I do not want the output voltage to exceed +/- 0.1% away from my ideal 28V, that is, assuming after stepping down to 1.2V at point A, the voltage sensed by the ADC0 must be able to detect a tiny difference of about 1.2mV (0.1% of 1.2V), would the single-ended input or the differential input configuration allow me to achieve this?

Next, I understand be it which configuration I used in the end, there would be a 8-bit register storing the ADC0 digital output after converting the analog signal. I would like to know (assuming I am using the single-ended sensing configuration, which is sensing the 1.2V directly from point A) what would the 8 bits data looks like? And also, what type of variable should I declare to capture this 8-bit data that actually represents my 1.2V for example?

Attached is my Buck converter schematic and the real photo, just in case you're interested to know what do I mean of the 28V output voltage.
 

Attachments

Thread Starter

gdylp2004

Joined Dec 2, 2011
101
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.

Rich (BB code):
Rich (BB code):
//-----------------------------------------------------------------------------
// Includes
//-----------------------------------------------------------------------------
 
#include <c8051f120.h> // SFR declarations
#include <stdio.h> 
 
//-----------------------------------------------------------------------------
// Global Constants
//-----------------------------------------------------------------------------
 
#define INTCLK 24500000 // Internal oscillator frequency in Hz
#define SYSCLK 49000000 // Output of PLL derived from (INTCLK*2)
#define BAUDRATE 115200 // Baud rate of UART in bps
#define SYSCLK 49000000 // Output of PLL derived from (INTCLK*2)
#define SAMPLE_RATE 50000 // Sample frequency in Hz
#define INT_DEC 256 // Integrate and decimate ratio
#define SAR_CLK 2500000 // Desired SAR clock speed
 
#define SAMPLE_DELAY 50 // Delay in ms before taking sample
 
sbit LED = P1^6; // LED='1' means ON
sbit SW1 = P3^7; // SW1='0' means switch pressed
 
//-----------------------------------------------------------------------------
// 16-bit SFR Definitions for 'F12x
//-----------------------------------------------------------------------------
 
sfr16 ADC0 = 0xbe; // ADC0 data
sfr16 RCAP2 = 0xca; // Timer2 capture/reload
sfr16 RCAP3 = 0xca; // Timer3 capture/reload
sfr16 TMR2 = 0xcc; // Timer2
sfr16 TMR3 = 0xcc; // Timer3
 
//-----------------------------------------------------------------------------
// Function Prototypes
//-----------------------------------------------------------------------------
 
void OSCILLATOR_Init (void);
void PORT_Init (void);
void PCA0_Init (void);
void Set_PCA0_Duty_Cycle(unsigned short l_us_duty_cycle);
void UART1_Init (void);
void ADC0_Init (void);
void TIMER3_Init (int counts);
void ADC0_ISR (void);
void Wait_MS (unsigned int ms);
 
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
 
long Result; // ADC0 decimated value
 

Thread Starter

gdylp2004

Joined Dec 2, 2011
101
Rich (BB code):
//-----------------------------------------------------------------------------
// main() Routine
//-----------------------------------------------------------------------------
 
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);
}
 
// SFRPAGE = PCA0_PAGE; // Change to PCA0 page
//
// while (1)
// {
// Set_PCA0_Duty_Cycle(74);
// // Wait a little while
// for (delay_count = 30000; delay_count > 0; delay_count--);
//
// if (duty_direction == 1) // Direction = Increase
// {
// // First, check the ECOM0 bit
// if ((PCA0CPM0 & 0x40) == 0x00)
// {
// PCA0CPM0 |= 0x40; // Set ECOM0 if it is '0'
// }
// else // Increase duty cycle otherwise
// {
// PCA0CPH0--; // Increase duty cycle
//
// if (PCA0CPH0 == 0x00)
// {
// duty_direction = 0; // Change direction for next time
// }
// }
// }
// else // Direction = Decrease
// {
// if (PCA0CPH0 == 0xFF)
// {
// PCA0CPM0 &= ~0x40; // Clear ECOM0
// duty_direction = 1; // Change direction for next time
// }
// else
// {
// PCA0CPH0++; // Decrease duty cycle
// }
// }
//
// };
}
 
 
 
 
 
//-----------------------------------------------------------------------------
// OSCILLATOR_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// This function initializes the system clock to use the internal oscillator
// at 24.5 MHz multiplied by two using the PLL.
//
//-----------------------------------------------------------------------------
 

Thread Starter

gdylp2004

Joined Dec 2, 2011
101
Rich (BB code):
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 [COLOR=#397a44 !important]system clock by a factor of M/N = 2[/COLOR]
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
}
 
//-----------------------------------------------------------------------------
// PORT_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// This function configures the crossbar and GPIO ports.
//
// P0.0 digital push-pull PCA0 CEX0
//
//-----------------------------------------------------------------------------
void PORT_Init (void)
{
char SFRPAGE_save = SFRPAGE; // Save Current SFR page
 
SFRPAGE = CONFIG_PAGE; // set SFR page
 
P0MDOUT = 0x07;
XBR0 = 0x08;
XBR2 = 0xC4;
 
// Enable UART1
P0MDOUT |= 0x01; // Set TX1 pin to push-pull
P1MDOUT |= 0x40; // Set P1.6(LED) to push-pull
 
SFRPAGE = SFRPAGE_save; // Restore SFR page
}
 
//-----------------------------------------------------------------------------
// PCA0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// This function configures the PCA time base, and sets up 8-bit PWM output
// mode for Module 0 (CEX0 pin).
//
// The frequency of the PWM signal generated at the CEX0 pin is equal to the
// PCA main timebase frequency divided by 256.
//
// The PCA time base in this example is configured to use SYSCLK, and SYSCLK
// is set up to use the internal PLL running at 49 MHz. Therefore,
// the frequency of the PWM signal will be 49 MHz / 256 = 191.4 kHz.
// Using different PCA clock sources or a different processor clock will
// result in a different frequency for the PWM signal.
//
// -------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
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 UART1_Init (void)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
 
SFRPAGE = UART1_PAGE;
SCON1 = 0x10; // SCON1: mode 0, 8-bit UART, enable RX
 
SFRPAGE = TIMER01_PAGE;
TMOD &= ~0xF0;
TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit reload
 
 
if (SYSCLK/BAUDRATE/2/256 < 1) {
TH1 = -(SYSCLK/BAUDRATE/2);
CKCON |= 0x10; // T1M = 1; SCA1:0 = xx
} else if (SYSCLK/BAUDRATE/2/256 < 4) {
TH1 = -(SYSCLK/BAUDRATE/2/4);
CKCON &= ~0x13; // Clear all T1 related bits
CKCON |= 0x01; // T1M = 0; SCA1:0 = 01
} else if (SYSCLK/BAUDRATE/2/256 < 12) {
TH1 = -(SYSCLK/BAUDRATE/2/12);
CKCON &= ~0x13; // T1M = 0; SCA1:0 = 00
} else {
TH1 = -(SYSCLK/BAUDRATE/2/48);
CKCON &= ~0x13; // Clear all T1 related bits
CKCON |= 0x02; // T1M = 0; SCA1:0 = 10
}
 
TL1 = TH1; // Initialize Timer1
TR1 = 1; // Start Timer1
 
SFRPAGE = UART1_PAGE;
TI1 = 1; // Indicate TX1 ready
 
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page
 
}
 
//-----------------------------------------------------------------------------
// ADC0_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters : None
//
// Configure ADC0 to use Timer3 overflows as conversion source, to
// generate an interrupt on conversion complete, and to use right-justified
// output mode. Enables ADC end of conversion interrupt. Leaves ADC disabled.
//
//-----------------------------------------------------------------------------
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
}
 
//-----------------------------------------------------------------------------
// TIMER3_Init
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters :
// 1) int counts - calculated Timer overflow rate
// range is postive range of integer: 0 to 32767
//
// Configure Timer3 to auto-reload at interval specified by <counts> (no
// interrupt generated) using SYSCLK as its time base.
//
//-----------------------------------------------------------------------------
void TIMER3_Init (int counts)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
 
SFRPAGE = TMR3_PAGE;
 
TMR3CN = 0x00; // Stop Timer3; Clear TF3;
TMR3CF = 0x08; // use SYSCLK as timebase
 
RCAP3 = -counts; // Init reload values
TMR3 = RCAP3; // Set to reload immediately
EIE2 &= ~0x01; // Disable Timer3 interrupts
TR3 = 1; // start Timer3
 
SFRPAGE = SFRPAGE_SAVE; // Restore SFR page
}
 
//-----------------------------------------------------------------------------
// Interrupt Service Routines
//-----------------------------------------------------------------------------
 
//-----------------------------------------------------------------------------
// ADC0_ISR
//-----------------------------------------------------------------------------
//
// Here we take the ADC0 sample, add it to a running total <accumulator>, and
// decrement our local decimation counter <int_dec>. When <int_dec> reaches
// zero, we post the decimated result in the global variable <Result>.
//
//-----------------------------------------------------------------------------
void ADC0_ISR (void) interrupt 15
{
static unsigned int_dec=INT_DEC; // Integrate/decimate counter
// we post a new result when
// int_dec = 0
static long accumulator=0L; // Here's where we integrate the
// ADC samples
 
AD0INT = 0; // Clear ADC conversion complete
// indicator
 
accumulator += ADC0; // Read ADC value and add to running
// total
int_dec--; // Update decimation counter
 
if (int_dec == 0) // If zero, then post result
{
int_dec = INT_DEC; // Reset counter
Result = accumulator >> 8;
accumulator = 0L; // Reset accumulator
}
}
 
//-----------------------------------------------------------------------------
// Support Subroutines
//-----------------------------------------------------------------------------
 
//-----------------------------------------------------------------------------
// Wait_MS
//-----------------------------------------------------------------------------
//
// Return Value : None
// Parameters:
// 1) unsigned int ms - number of milliseconds of delay
// range is full range of integer: 0 to 65335
//
// This routine inserts a delay of <ms> milliseconds.
//
//-----------------------------------------------------------------------------
void Wait_MS(unsigned int ms)
{
char SFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
 
SFRPAGE = TMR2_PAGE;
 
TMR2CN = 0x00; // Stop Timer3; Clear TF3;
TMR2CF = 0x00; // use SYSCLK/12 as timebase
 
RCAP2 = -(SYSCLK/1000/12); // Timer 2 overflows at 1 kHz
TMR2 = RCAP2;
 
ET2 = 0; // Disable Timer 2 interrupts
 
TR2 = 1; // Start Timer 2
 
while(ms)
{
TF2 = 0; // Clear flag to initialize
while(!TF2); // Wait until timer overflows
ms--; // Decrement ms
}
 
TR2 = 0; // Stop Timer 2
 
SFRPAGE = SFRPAGE_SAVE; // Restore SFRPAGE
}
 
//-----------------------------------------------------------------------------
// End Of File
//-----------------------------------------------------------------------------
 
Top