BLE-to-RS422 Bridge
This guide covers building a transparent BLE-to-RS422 bridge for the Winegard Carryout G2 satellite dish. The bridge replaces the USB-to-RS422 adapter with a wireless connection using Bluetooth Low Energy (BLE) via the Nordic UART Service (NUS). Optional IMU and barometric sensors add orientation feedback and atmospheric refraction correction for improved tracking accuracy.
Parts list
Section titled “Parts list”Bridge (required)
Section titled “Bridge (required)”- ESP32-S3-DevKitC-1-N16R8
- 2x MAX485 TTL-to-RS485 module
- 1x SparkFun Bidirectional Logic Level Converter (BOB-12009, BSS138-based)
- RJ-12 6P6C straight-wired cable with breakout
- Hookup wire / jumpers
Sensors (optional)
Section titled “Sensors (optional)”- 1x GY-9250 (MPU-9250) — 9-axis IMU (accelerometer + gyroscope + magnetometer)
- 1x BMP388 — barometric pressure + temperature
- 1x RYS352A GPS module — observer location + PPS timing
Build procedure
Section titled “Build procedure”-
Wire the power rails. The ESP32’s 5V output powers the level converter’s high side and both MAX485 modules. The 3.3V output powers the level converter’s low side. All grounds must be connected together.
-
Wire the level converter. Connect ESP32 GPIO17 (TX) to LV1 and ESP32 GPIO18 (RX) to LV2 on the SparkFun converter. Connect HV1 to MAX485 board 1 DI, and HV2 to MAX485 board 2 RO.
-
Lock the TX module (Board 1). Tie DE and RE on Board 1 to 5V. This permanently enables the driver and disables the receiver — the board only transmits.
-
Lock the RX module (Board 2). Tie DE and RE on Board 2 to GND. This permanently disables the driver and enables the receiver — the board only receives.
-
Wire the RJ-12 breakout. Connect Board 1’s A/B to pins 2/3 (TX pair) and Board 2’s A/B to pins 4/5 (RX pair). Connect pin 1 to common ground.
-
Wire the I2C sensors (optional). Connect MPU-9250 and BMP388 to GPIO8 (SDA) and GPIO9 (SCL) on the shared 3.3V I2C bus.
-
Wire the GPS module (optional). Connect RYS352A TX to GPIO5 (UART2 RX), RX to GPIO6 (UART2 TX), and PPS to GPIO7.
-
Flash the firmware. See
firmware/ble-bridge/in the project repository.
Schematic
Section titled “Schematic”Main bridge circuit
Section titled “Main bridge circuit” SparkFun Level Converter (BOB-12009) +--------------------------------------+ | |ESP32 3V3 --------------+| LV HV |+-- ESP32 5VESP32 GND --------------+| GND GND |+-- (shared) | |ESP32 GPIO17 (TX) ------+| LV1 HV1 |+-----> MAX485_1 DIESP32 GPIO18 (RX) +------| LV2 HV2 |+---- MAX485_2 RO | | | LV3 (spare) HV3 (spare) | | LV4 (spare) HV4 (spare) | +--------------------------------------+
MAX485 Board 1 (TX only) MAX485 Board 2 (RX only) +------------------------+ +------------------------+ | VCC <-- 5V | | VCC <-- 5V | | GND <-- GND | | GND <-- GND | | | | | | DI <-- HV1 | | RO --> HV2 | | RO (unused) | | DI (unused) | | | | | | DE <-- 5V | locked | | DE <-- GND | locked | | RE <-- 5V | TX mode | | RE <-- GND | RX mode | | | | | | A ---------------------+--> pin 2 | A <---------------------+-- pin 4 | B ---------------------+--> pin 3 | B <---------------------+-- pin 5 +------------------------+ +------------------------+
RJ-12 to Carryout G2 +---------------------------+ | Pin 1 (White) -- GND |<-- ESP32 GND | Pin 2 (Red) -- TX+/TA |<-- A_1 | Pin 3 (Black) -- TX-/TB |<-- B_1 | Pin 4 (Yellow) -- RX+/RA |--> A_2 | Pin 5 (Green) -- RX-/RB |--> B_2 | Pin 6 (Blue) -- N/C | +---------------------------+Power rails
Section titled “Power rails”ESP32 5V --+-- Level Converter HV +-- MAX485_1 VCC +-- MAX485_1 DE + RE (tied high = TX mode) +-- MAX485_2 VCC
ESP32 3V3 --- Level Converter LV
ESP32 GND -+-- Level Converter GND +-- MAX485_1 GND +-- MAX485_2 GND +-- MAX485_2 DE + RE (tied low = RX mode) +-- RJ-12 Pin 1How it works
Section titled “How it works”The Carryout G2 uses RS-422 full-duplex: two separate differential pairs, one for each direction. The MAX485 is a half-duplex RS-485 transceiver with a shared A/B pair and direction control pins (DE/RE). By hardwiring DE/RE, each board is locked into a single direction:
-
Board 1 (TX): DE=HIGH, RE=HIGH — driver always enabled, receiver disabled. ESP32 UART1 TX goes through the level shifter to DI, out as differential A/B to the G2 serial RX.
-
Board 2 (RX): DE=LOW, RE=LOW — driver disabled, receiver always enabled. G2 serial TX comes in on differential A/B, through RO and the level shifter to ESP32 UART1 RX.
The SparkFun level converter translates between 3.3V (ESP32) and 5V (MAX485) on both data lines. The two spare channels (LV3/HV3, LV4/HV4) are available if DE/RE ever need GPIO control for a half-duplex variant.
The firmware is the same regardless of whether the RS-422 transceiver is a MAX490 (single full-duplex chip) or two MAX485s (locked half-duplex pair). It only sees UART TX/RX on GPIO17/18.
RJ-12 cable notes
Section titled “RJ-12 cable notes”Straight-wired 6P6C. Pin 1 is leftmost when looking at the jack with the clip facing away from you (tab down).
| Pin | Color | Function | Connects to |
|---|---|---|---|
| 1 | White | GND | Common ground |
| 2 | Red | TX+ (TA) | MAX485 Board 1 A |
| 3 | Black | TX- (TB) | MAX485 Board 1 B |
| 4 | Yellow | RX+ (RA) | MAX485 Board 2 A |
| 5 | Green | RX- (RB) | MAX485 Board 2 B |
| 6 | Blue | N/C | — |
If crimping your own cable, verify pin-to-color with a multimeter before connecting to the dish. RJ-12 crimps are easy to get reversed (pins mirror if the connector is flipped). A wrong connection won’t damage anything (differential signals are current-limited) but communication won’t work.
Sensors — I2C bus
Section titled “Sensors — I2C bus”The MPU-9250 and BMP388 share a single I2C bus on GPIO8 (SDA) / GPIO9 (SCL). Both run at 3.3V directly from the ESP32, no level shifting needed.
I2C bus schematic
Section titled “I2C bus schematic” I2C Bus (3.3V, 400kHz) ----------------------
ESP32 3V3 --+------------------+--- MPU-9250 VCC | +--- BMP388 VCC | +-- 4.7K_ohm -- SDA bus --+-- MPU-9250 SDA | +-- BMP388 SDI | +-- 4.7K_ohm -- SCL bus --+-- MPU-9250 SCL +-- BMP388 SCK
ESP32 GPIO8 (SDA) ---- SDA busESP32 GPIO9 (SCL) ---- SCL bus
ESP32 GND --+-- MPU-9250 GND +-- BMP388 GND (SDO to GND = addr 0x76)
MPU-9250 AD0 -- GND (I2C address = 0x68)BMP388 SDO -- GND (I2C address = 0x76)The 4.7K-ohm pull-ups are shared — one pair for the whole bus. Many breakout boards include onboard pull-ups already; if both the GY-9250 and BMP388 boards have them, the combined parallel resistance (~2.3K-ohm) is still fine for 400kHz I2C at 3.3V. Only add external pull-ups if neither board has them.
MPU-9250 (GY-9250) — 9-axis IMU
Section titled “MPU-9250 (GY-9250) — 9-axis IMU”| Property | Value |
|---|---|
| I2C Address | 0x68 (AD0 to GND) |
| VCC | 3-5V (onboard LDO) |
| Interface | I2C (up to 400kHz) or SPI |
What it provides for satellite tracking:
- Magnetometer (AK8963): Compass heading for automatic north alignment. Eliminates manual alignment of dish base “BACK” marking to true north. Apply local magnetic declination to convert magnetic north to true north.
- Accelerometer: Gravity vector gives tilt angle = elevation. Independent verification of the dish firmware’s reported EL position.
- Gyroscope: Angular rate during slews. Detect oscillation, overshoot, and vibration for tuning the leapfrog overshoot compensation algorithm.
BMP388 — barometric pressure + temperature
Section titled “BMP388 — barometric pressure + temperature”| Property | Value |
|---|---|
| I2C Address | 0x76 (SDO to GND) |
| VCC | 3.3V |
| Pressure range | 300-1250 hPa |
| Pressure resolution | +/-0.01 hPa (+/-8 cm altitude) |
| Temperature accuracy | +/-0.5 degrees C |
| Interface | I2C (up to 3.4MHz) or SPI |
What it provides for satellite tracking:
- Atmospheric refraction correction. Radio signals bend as they pass through the atmosphere, especially at low elevation angles. The amount of bending depends on air pressure and temperature. At 15 degrees elevation (the Trav’ler’s minimum), refraction shifts apparent position by ~0.2 degrees. Standard refraction models (Bennett, Saemundsson) take pressure and temperature as inputs — the BMP388 provides both in real time.
- Temperature monitoring. Ambient temperature at the dish for thermal drift awareness and electronics health monitoring.
The simplified Bennett refraction formula:
R = 1/tan(el + 7.31/(el + 4.4)) * (P/1010) * (283/(273 + T))Where R is refraction in arcminutes, el is apparent elevation in degrees, P is pressure in hPa, T is temperature in degrees C. At el=15, P=1013, T=20: R is approximately 3.4 arcmin (0.057 degrees). Small but meaningful for narrow-beam antennas.
GPS — RYS352A
Section titled “GPS — RYS352A”The RYS352A is a compact GPS module with PPS output. It connects via UART2 and provides observer location for satellite pass prediction and a 1Hz PPS pulse for precise UTC time synchronization.
GPS wiring
Section titled “GPS wiring”ESP32 GPIO5 (UART2 RX) <-- RYS352A TX (NMEA sentences out)ESP32 GPIO6 (UART2 TX) --> RYS352A RX (config commands in, optional)ESP32 GPIO7 <-- RYS352A PPS (1Hz rising edge, ~100ns jitter)ESP32 3V3 --> RYS352A VCCESP32 GND --> RYS352A GND| Module Pin | ESP32 Pin | Function |
|---|---|---|
| VCC | 3V3 | 3.3V power (onboard LDO on most breakouts) |
| GND | GND | Ground |
| TX | GPIO5 (UART2 RX) | NMEA sentence output at 115200 baud |
| RX | GPIO6 (UART2 TX) | PAIR/NMEA config input (optional) |
| PPS | GPIO7 | 1Hz pulse synchronized to GPS time |
PPS (Pulse Per Second): The RYS352A outputs a precise 1Hz pulse on the rising edge, synchronized to UTC via GPS constellation. The firmware captures this edge via interrupt for correlating satellite events with sub-microsecond precision. The module’s RTC battery backup enables warm starts (~5s) after initial cold start fix (~30-60s).
UART notes: The RYS352A defaults to 115200 baud NMEA output with GN talker ID (multi-constellation). The TX line (GPIO6) sends $PAIR proprietary commands at boot to configure the GPS module for satellite tracking use:
- Only GGA (position/quality), GSA (fix mode/DOP), RMC (time/date/speed), and GSV (satellite visibility, every 5th fix) are enabled
- Redundant sentences (GLL, VTG, ZDA, GRS, GST, GNS) are disabled to reduce parser load and latency
- PPS is configured to pulse only on 2D/3D fix with 100ms pulse width
- Each command waits for
$PAIR001ACK; failures are logged but non-fatal
Full GPIO map
Section titled “Full GPIO map”| GPIO | Function | Interface | Notes |
|---|---|---|---|
| 5 | GPS RX | UART2 RX | From RYS352A TX (NMEA out) |
| 6 | GPS TX | UART2 TX | To RYS352A RX (config in) |
| 7 | GPS PPS | GPIO interrupt | 1Hz rising edge |
| 8 | I2C SDA | I2C | MPU-9250 + BMP388 (shared bus) |
| 9 | I2C SCL | I2C | MPU-9250 + BMP388 (shared bus) |
| 17 | RS-422 TX | UART1 TX | To level shifter to MAX485 Board 1 DI |
| 18 | RS-422 RX | UART1 RX | From level shifter from MAX485 Board 2 RO |
| 38 | RGB LED | WS2812 | Onboard NeoPixel (DevKitC V1.1) |
| 43 | USB Console TX | UART0 | CH343 USB-serial (untouched) |
| 44 | USB Console RX | UART0 | CH343 USB-serial (untouched) |