Redesigned Arduino Based Buck Converter : N-Channel vs. P-Channel Buck Converter:

 I wrote about how N-channel MOSFET on the high side in buck converter design and why it will not work in my previous note Why High-Side N-Channel Buck Converters Fail. Although there is advantage to using n-channel on the side which is that the n-channel are fasters and cheaper than p-channel MOSFET, with additional circuit such as using charge pump or bootstrap circuit, it won't work as expected. 

The main hurdle with n-channel MOSFET on the high side (connected between the source and load) is that, to to fully turn on an N-channel MOSFET, the Gate voltage ($V_G$) must be significantly higher than the Source voltage ($V_S$). So, when the MOSFET turns on, the Source voltage rises to nearly the supply voltage ($V_{CC}$). And to stay "on," we required that the gate voltage be higher than the power supply voltage plus the gate to source voltage threshold:$$V_G > V_{CC} + V_{GS(th)}$$The result is that we can't just use the supply voltage to toggle the gate; you need a voltage higher than the supply itself. 

The following shows the circuit diagram of buck converter with N-channel MOSFET on the high side that will not work.

buck converter circuit with n-channel mosfet on high side
The detailed reasons why N-channel MOSFET on high side in buck converter is not suitable is explained in detail in my previous blog post Why High-Side N-Channel Buck Converters Fail.

There are couples of solutions we could use here to fix the problem. These solutions are:

  1. Charge Pumps: Small circuits that "pump up" a voltage higher than the rail.

  2. Bootstrap Circuits: Frequently used in PWM applications (like motor drivers or buck converters). It uses a capacitor and a diode to "lift" the gate voltage above the rail every time the MOSFET switches.

  3. High-Side Gate Driver ICs: Dedicated chips (like the IR2110 or similar) that handle all this headache for you.

  4. P-channel MOSFET: Replace the n-channel MOSFE with p-channel MOSFET.

I used the 4th solution; I replaced the n-channel MOSFET with p-channel MOSFET. This is the most direct way to simplify a high-side switch because it eliminates the need for voltages higher than the supply rail.

Circuit Schematic

The circuit diagram below shows n-channel MOSFET replaced by p-channel MOSFET on the high side of the Arduino based buck converter.

buck converter using Arduino circuit diagram

This circuit is a DC-to-DC Buck Converter designed to step down a higher DC voltage (12V) to a lower, regulated DC voltage (like 5V). It uses PWM (Pulse Width Modulation) from an Arduino to control a high-speed electronic switch.

Here is the step-by-step breakdown of how the hardware works together:


1. The Switching Stage (Control)

The Arduino (at Pin 9) generates a PWM signal. However, an Arduino pin cannot handle 12V or the high current needed for the MOSFET.

  • Q1 (2N2222A Transistor): Acts as a level-shifter. When Pin 9 goes HIGH, Q1 turns on and pulls the Gate of the MOSFET to Ground.

  • Q2 (IRF4905 P-Channel MOSFET): This is the main "Power Switch." Because it’s a P-Channel, it turns ON when its gate is pulled low (0V) and OFF when the gate is pulled high (12V via resistor R2).

  • Result: The 12V input is "chopped" into high-frequency square pulses.

2. The Power Stage (Conversion)

The chopped 12V signal is not usable DC yet. This is where the filter components come in:

  • L1 (Inductor): When the MOSFET is ON, current flows through the inductor, storing energy in a magnetic field. When the MOSFET turns OFF, the magnetic field collapses, and the inductor continues to push current toward the load.

  • D1 (1N5822 Schottky Diode): This is the "Flyback" or "Freewheeling" diode. When the MOSFET turns off, the inductor needs a path to pull current from Ground to keep the loop complete.

  • C1 (Output Capacitor): This acts as a reservoir. It charges during the "ON" cycle and discharges during the "OFF" cycle, smoothing out the voltage pulses into a steady DC line.

3. The Feedback Stage (Monitoring)

To ensure the output is correct, the Arduino needs to measure the voltage, but its pins can only handle up to 5V.

  • R3 & R4 (Voltage Divider): These resistors (14k and 10k) scale the output voltage down. For example, if the output is 12V, the Arduino sees roughly 5V at Pin A1.

  • C2 (Feedback Filter): This small capacitor filters out high-frequency switching noise from the divider, ensuring the Arduino gets a clean, "rock-solid" reading for its calculations.

  • RV1 (Potentiometer): This allows the user to manually set the target voltage. The Arduino reads this value and adjusts the PWM duty cycle accordingly to reach the desired output.


Summary Table: Component Roles

ComponentFunction
MOSFET (Q2)The high-speed switch that "chops" the 12V input.
Inductor (L1)Smooths current and stores energy during the "OFF" cycle.
Capacitor (C1)Smooths voltage ripple to provide steady DC.
Diode (D1)Provides a return path for current when the switch is open.
Resistors (R3/R4)Protect the Arduino by scaling the voltage down for measurement.
Some additional notes on the resistors $R_1$ and $R_2$.
  • Base Resistor ($R1$): In the previous buck converter design I used base resistor of $1 k\Omega$. Here I increased to something to $2.2 k\Omega$. Increasing the base resistor reduces the strain on the Arduino pin while still providing plenty of switching speed.
  • Pull-Up Resistor ($R2$): To achieve the high-speed 31.25 kHz switching rates I lowered Gate pull-up resistor from 10k from previous buck converter design down to $1 k\Omega$. This helps the MOSFET turn OFF faster, which reduces heat
Tip: Use the online Buck Converter Calculator to calculate the inductor and capacitors value for given switching frequency. Also see the Arduino Interactive Pinout Web Tool for planning pins. Both are free web tools on my blog.

Program Code

/*
 * BUCK CONVERTER MANUAL CONTROL (32.25kHz)
 * Developed for: ee-diary.net
 * Schematic: P-Channel IRF4905 with NPN Driver
 */

const int pwmPin = 9;      
const int potPin = A0;     
const int feedbackPin = A1; 

// Resistor values matching your Proteus Schematic (1.png)
const float R3 = 14000.0; // 14k Top Resistor
const float R4 = 10000.0; // 10k Bottom Resistor
const float dividerRatio = (R3 + R4) / R4; 

void setup() {
  Serial.begin(115200);
  pinMode(pwmPin, OUTPUT);

  // Set Timer 1 to 31.25kHz (Prescaler 1)
  TCCR1B = (TCCR1B & 0b11111000) | 0x01;

  Serial.println("--- BUCK CONVERTER: ee-diary.net ---");
  Serial.println("Adjust Potentiometer to reach target voltage");
  Serial.println("-----------------------------------------");
}

void loop() {
  // Read the potentiometer (0 to 1023)
  int potValue = analogRead(potPin);

  // Map to standard 8-bit PWM range (0 to 255)
  // At 1kHz, 255 = 100% Duty Cycle (Full Battery Voltage)
  int pwmValue = map(potValue, 0, 1023, 0, 255); 

  // Output the PWM to the MOSFET driver
  analogWrite(pwmPin, pwmValue);

  // Non-blocking timer for Serial monitoring
  static unsigned long lastPrint = 0;
  if (millis() - lastPrint > 400) { 
    
    // Read output voltage via the voltage divider
    float vRaw = analogRead(feedbackPin) * (5.0 / 1023.0);
    float actualVolts = vRaw * dividerRatio;

    // Display data for debugging
    Serial.print("POT: ");     Serial.print(potValue);
    Serial.print(" | PWM: ");  Serial.print(pwmValue);
    Serial.print(" | OUTPUT Voltage: "); Serial.print(actualVolts, 2);
    Serial.println("V");
    
    lastPrint = millis();
  }
}
The code is a bridge between the physical hardware and the logic needed to regulate power. It handles three main tasks: High-speed switching, User Input handling, and Real-time Voltage Math.

Here is the breakdown of the code:


1. Configuration & Calibration

const float R3 = 14000.0; 
const float R4 = 10000.0; 
const float dividerRatio = (R3 + R4) / R4; 
  • The Math: Since the Arduino cannot "read" 12V directly, your schematic uses a voltage divider. This dividerRatio (which is 2.4) tells the code how to "magnify" the small 0-5V signal back up to the real 0-12V value for the Serial Monitor.

2. The High-Speed Heart (Timer Setup)

TCCR1B = (TCCR1B & 0b11111000) | 0x01;
  • The "Overclock": By default, Arduino PWM is very slow (about 490Hz). This line modifies the Timer 1 hardware register.

  • By setting the prescaler to 0x01, you are pushing the frequency to 31.25kHz. This high speed is what allows you to use that small 155µH inductor instead of a massive one.

3. The Control Loop (The "Brain")

int potValue = analogRead(potPin);
int pwmValue = map(potValue, 0, 1023, 0, 255); 
analogWrite(pwmPin, pwmValue);
  • Input: It reads the 10k Potentiometer position.

  • Translation: It maps that position to a 0-255 "Duty Cycle" value.

  • Action: analogWrite tells the MOSFET how long to stay open.

    • PWM 0: MOSFET always OFF (0V Output).

    • PWM 255: MOSFET always ON (12V Output).

    • PWM 127: MOSFET ON 50% of the time (~6V Output).

4. Serial Monitor

if (millis() - lastPrint > 400) { 
    float vRaw = analogRead(feedbackPin) * (5.0 / 1023.0);
    float actualVolts = vRaw * dividerRatio;
}
  • Non-Blocking Delay: Using millis() instead of delay() is crucial. It allows the Arduino to keep switching the MOSFET perfectly while only pausing to print text to your screen every 400 milliseconds.

  • Precision Math: It converts the raw binary data (0-1023) back into Volts, then applies the dividerRatio so you see the actual output voltage on your Serial Monitor.

Video

The following video shows how the Arduino buck converter woks, explains the circuit and circuit components in details.


Related

Post a Comment

Previous Post Next Post