To connect PuTTY to a Raspberry Pi, you have two primary paths: SSH over the network (using the Pi's IP address and port 22) or a direct Serial UART connection (using GPIO 14/15 at 115200 baud). While SSH is convenient, the serial UART method is mandatory for embedded debugging, bootloop recovery, and headless setups where WiFi or Ethernet is unavailable. This guide covers the exact hardware wiring, OS configuration, and a Python sensor project to test your headless serial console.

Difficulty Rating and Parts List

  • Difficulty: 2/5 (Beginner-Intermediate)
  • Time Required: 25 minutes
  • Target Board: Raspberry Pi 4 Model B (4GB, Rev 1.5) running Raspberry Pi OS (Bookworm 64-bit)

Before you start stripping wires, ensure you have the exact components listed below. Using a 5V logic serial adapter on the Pi's 3.3V GPIO pins is the most common way hobbyists permanently destroy their boards.

Component Exact Variant / Specification Estimated Cost (2026)
Microcontroller Raspberry Pi 4 Model B (4GB RAM, Rev 1.5) $55.00
Serial Adapter FTDI FT232RL USB-to-TTL Cable (Strictly 3.3V logic, e.g., TTL-232R-3V3) $22.00
Sensor (for testing) BME280 I2C Temperature/Humidity/Pressure Module (3.3V) $8.00
Wiring Female-to-Female Dupont Jumper Wires (20cm) $5.00
Software PuTTY (Windows) or native screen/minicom (Linux/macOS) Free

Hardware Wiring and Pin Mapping

We are wiring two separate interfaces here: the UART serial console for PuTTY, and the I2C bus for our test sensor. The Raspberry Pi 4's primary UART (/dev/serial0) maps to GPIO 14 (TX) and GPIO 15 (RX) on the 40-pin header.

CRITICAL SAFETY WARNING: The FTDI cable linked above outputs 3.3V logic. If you are using a generic, unbranded USB-to-serial adapter from a bulk pack, verify the TX/RX voltage with a multimeter before connecting. Feeding 5V into GPIO 15 will fry the Pi's UART controller and potentially the main SoC.

UART to FTDI Pin Mapping (PuTTY Console)

FTDI Cable Wire (Color) Signal Raspberry Pi 4 GPIO Physical Pin #
Black GND GND 6
Yellow (or Green) RX (Receive) GPIO 14 (TXD) 8
Orange (or White) TX (Transmit) GPIO 15 (RXD) 10

Note: TX always connects to RX, and RX connects to TX. Do not connect the red 5V VCC wire from the FTDI cable to the Pi; power the Pi via its USB-C port.

BME280 Sensor to Pi I2C Pin Mapping

BME280 Pin Signal Raspberry Pi 4 GPIO Physical Pin #
VIN / VCC 3.3V Power 3V3 Power 1
GND Ground GND 9
SCL I2C Clock GPIO 3 (SCL) 5
SDA I2C Data GPIO 2 (SDA) 3

Enabling the Serial Console in Raspberry Pi OS

By default, the serial port on modern Raspberry Pi OS is either disabled or reserved for Bluetooth. We need to reassign it to the GPIO header and enable the serial login shell so PuTTY can authenticate.

  1. Boot the Pi with a monitor and keyboard attached (or via SSH if WiFi is already configured).
  2. Open the terminal and run: sudo raspi-config
  3. Navigate to Interface Options > Serial Port.
  4. When asked 'Would you like a login shell to be accessible over serial?', select Yes.
  5. When asked 'Would you like the serial port hardware to be enabled?', select Yes.
  6. Exit raspi-config and reboot the Pi (sudo reboot).

Once rebooted, plug your FTDI USB adapter into your PC. Open Windows Device Manager to find your COM port number (e.g., COM3). Open PuTTY, select the Serial radio button, enter your COM port, set the speed to 115200, and click Open. Press Enter twice, and you will see the raspberrypi login: prompt.

Python Project: I2C Sensor Logging Over Headless Serial

Now that your PuTTY serial console is active, let's verify the system can run embedded tasks simultaneously. We will write a Python script using the smbus2 library to read the BME280 sensor over I2C. This proves that reserving the UART for PuTTY does not block other sensor operations.

First, install the required I2C tools and Python library via your PuTTY terminal:

sudo apt update
sudo apt install python3-smbus i2c-tools -y
sudo i2cdetect -y 1

You should see 76 or 77 in the grid output, confirming the BME280 is wired correctly.

Create a new file sensor_logger.py and paste the following complete, error-handled code:

#!/usr/bin/env python3
"""
BME280 I2C Sensor Logger
Target: Raspberry Pi 4 Model B (I2C Bus 1)
Dependencies: smbus2
"""

import smbus2
import time
import sys

# BME280 I2C Address (usually 0x76 or 0x77 depending on module jumper)
BME280_ADDR = 0x76
I2C_BUS = 1

def read_bme280_data(bus):
    """Reads raw compensation data and calculates temp/pressure/humidity."""
    # Simplified read for demonstration: reading raw temp msb/lsb/xsb
    # In production, use the adafruit-circuitpython-bme280 library for full compensation
    data = bus.read_i2c_block_data(BME280_ADDR, 0xF7, 8)
    
    # Raw Temperature calculation (simplified approximation for demo)
    raw_temp = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
    # Note: Real implementation requires applying factory calibration registers
    # We will just output the raw ADC value to prove I2C communication is working
    return raw_temp

def main():
    print(f"Initializing I2C Bus {I2C_BUS} for BME280 at address {hex(BME280_ADDR)}...")
    
    try:
        bus = smbus2.SMBus(I2C_BUS)
        # Check if device responds
        bus.read_byte_data(BME280_ADDR, 0xD0) # Read Chip ID register
    except FileNotFoundError:
        print("ERROR: I2C interface not enabled. Run 'sudo raspi-config' to enable I2C.")
        sys.exit(1)
    except OSError as e:
        print(f"ERROR: Cannot connect to BME280 at {hex(BME280_ADDR)}. Check wiring. Details: {e}")
        sys.exit(1)

    print("Sensor online. Logging data every 5 seconds. Press Ctrl+C to stop.")
    
    try:
        while True:
            raw_adc = read_bme280_data(bus)
            timestamp = time.strftime('%Y-%m-%d %H:%M:%S')
            print(f"[{timestamp}] BME280 Raw Temp ADC: {raw_adc}")
            time.sleep(5)
    except KeyboardInterrupt:
        print("\nLogging stopped by user.")
    except OSError as e:
        print(f"\nI2C Bus communication error during read: {e}")
    finally:
        bus.close()
        print("I2C Bus closed safely.")

if __name__ == '__main__':
    main()

Run the script via your PuTTY serial session: python3 sensor_logger.py. You will see live data printing to your terminal, confirming your headless embedded setup is fully operational.

Troubleshooting: COM Port Access Denied Errors

When working with serial adapters on Windows, you will inevitably encounter connection blocks. If PuTTY fails to connect, you will see this exact error string:

Exact Error String: Unable to open connection to COM3: Access is denied

Here are the first three things to check, ranked from most likely to least likely:

  1. The Port is Hijacked by Another Application (90% of cases): Windows only allows one process to hold a serial COM port at a time. If you have the Arduino IDE open (even in the background), a 3D printer slicer like Cura polling for printers, or another PuTTY window active, the OS will deny access. Close all other software and restart PuTTY.
  2. Incorrect COM Port Selection (8% of cases): Unplug the FTDI adapter, open Windows Device Manager, and expand 'Ports (COM & LPT)'. Plug the adapter back in and watch which COM port appears. If you selected COM3 in PuTTY but the device enumerated as COM4, the connection will fail.
  3. Missing or Corrupt FTDI Drivers (2% of cases): If the device shows up under 'Other Devices' with a yellow warning triangle in Device Manager, Windows hasn't loaded the driver. Download the official FTDI VCP (Virtual COM Port) drivers directly from FTDI Chip's official driver page.

FAQ: PuTTY Raspberry Pi Long-Tail Questions

How to connect PuTTY to Raspberry Pi without WiFi?

If your Pi has no network access, you must use the Serial UART method detailed in this guide. Wire the FTDI adapter to GPIO 14 and 15, set PuTTY to 'Serial' mode, enter your PC's COM port, and use a baud rate of 115200. This bypasses the network stack entirely and connects directly to the Pi's boot console via the SoC's hardware UART controller.

Why is my PuTTY Raspberry Pi serial output showing gibberish characters?

Gibberish (e.g., ÿÿÿÿ or random symbols) is almost always a baud rate mismatch. The Raspberry Pi's default serial console speed is 115200 baud. If your PuTTY session is set to 9600 baud (the default for many Arduino projects), the timing of the bits will be misinterpreted. Open PuTTY's configuration, navigate to Connection > Serial, and ensure 'Speed (baud)' is exactly 115200.

How do I extend this build to log data to a remote database?

To extend the Python script above for production use, replace the print() statement inside the while loop with an HTTP POST request using the requests library to send data to an InfluxDB or MQTT broker. To simplify the build for a standalone kiosk, remove the PuTTY serial requirement entirely and configure the script as a systemd service so it runs automatically on boot without requiring a terminal login.

For more information on configuring Raspberry Pi interfaces, refer to the official Raspberry Pi configuration documentation. For terminal emulation standards, see the PuTTY release archive.