NuttX RTOS for PinePhone: 4G LTE Modem

📝 12 Apr 2023

Quectel EG25-G LTE Modem inside PinePhone

Quectel EG25-G LTE Modem inside PinePhone

What makes Pine64 PinePhone a phone? It’s the 4G LTE Modem inside that makes Phone Calls and sends Text Messages!

Now we’re building a Feature Phone with Apache NuttX RTOS (Real-Time Operating System). To make things simpler, we’re writing down everything we know about the 4G LTE Modem, and how it works inside PinePhone…

Read on to learn all about PinePhone’s 4G LTE Modem…

Quectel EG25-G LTE Modem

Quectel EG25-G LTE Modem

§1 Quectel EG25-G LTE Modem

What’s this LTE Modem?

Inside PinePhone is the Quectel EG25-G LTE Modem for 4G LTE Voice Calls, SMS and Mobile Data, plus GPS (pic above)…

To control the LTE Modem, we send AT Commands

So to dial the number 1711, we send this AT Command…

ATD1711;

The LTE Modem has similar AT Commands for SMS and Mobile Data.

(EG25-G runs on Qualcomm MDM 9607 with a Cortex-A7 CPU inside)

How to send the AT Commands to LTE Modem?

The LTE Modem accepts AT Commands in two ways (pic below)…

So if we’re sending and receiving lots of 4G Mobile Data, USB is the better way.

(UART Interface is probably sufficient for a Feature Phone)

Let’s talk about the UART and USB Interfaces…

Data Interfaces for LTE Modem

§2 Data Interfaces for LTE Modem

There’s a band of bass players in my PinePhone?

Ahem the Baseband Processor inside the LTE Modem (pic above) is the hardware that handles the Radio Functions for 4G LTE and GPS.

According to the PinePhone Schematic (Page 15), the Baseband Processor talks to PinePhone (Allwinner A64) over the following Data Interfaces (pic above)…

UART is slower than USB, so we should probably use USB instead of UART.

(Unless we’re building a simple Feature Phone without GPS)

PinePhone also controls the LTE Modem with a bunch of GPIO Pins…

Control Pins for LTE Modem

§3 Control Pins for LTE Modem

PinePhone’s LTE Modem is controlled only by AT Commands?

There’s more! According to the PinePhone Schematic (Page 15), the LTE Modem is controlled by the following GPIO Pins (pic above)…

We’ll control the above GPIO Pins to power up the LTE Modem at startup. (More in the next section)

Also at startup, we’ll read this GPIO Pin to check if the LTE Modem is hunky dory

These GPIO Pins control the Airplane Mode and Sleep State

And the LTE Modem signals PinePhone on this GPIO Pin for Incoming Calls and SMS Messages

Let’s power up the LTE Modem…

LTE Modem Power

§4 LTE Modem Power

How will we power up the LTE Modem?

PinePhone Schematic (Page 15) says that PinePhone controls the power via GPIO Pin PL7 (pic above)…

GPIO Pin PL7 (bottom left) switches on the Battery Power 4G-BAT (top left)…

LTE Modem Power

PinePhone Schematic (Page 15)

Which powers the LTE Modem via VBAT_BB (top right).

Thus LTE Modem won’t power up without the Lithium-ion Battery.

(WPM1481 is a Power Controller)

What’s Switch SW1-A? (Bottom left)

Hardware Privacy Switch 1 (Modem) should be set to “On”.

Or the LTE Modem won’t power on!

(Indeed that’s a Hardware Switch, not a Soft Switch)

So we set GPIO Pin PL7 and the modem powers on?

There’s a Soft Switch inside the LTE Modem that we need to toggle…

Sounds complicated, but we’ll explain the complete Power Up Sequence in a while.

(Power Key works like the press-and-hold Power Button on vintage Nokia Phones)

Anything else to power up the LTE Modem?

In a while we’ll set the Reset Pin and check the Status Pin

We need to program PinePhone’s Power Management Integrated Circuit (PMIC) to supply 3.3 V on DCDC1. Here’s why…

LTE Modem Power Output

§5 Power Output

Wait there’s a Power Output for the LTE Modem?

Yeah it gets confusing. The LTE Modem outputs 1.8 Volts to PinePhone (pic above)…

Which goes into PinePhone’s Voltage Translators as VDD_EXT (top left)…

LTE Modem Power Output

PinePhone Schematic (Page 15)

(TXB0104 is a Voltage Translator)

The circuit above converts the UART Signals (TX / RX / CTS / RTS)…

Voltage Translators are also used for the LTE Modem Control Pins.

What’s DCDC1? (Top right)

We need to program PinePhone’s Power Management Integrated Circuit (PMIC) to supply 3.3 V on DCDC1.

Otherwise the UART Port (and the Control Pins) will get blocked by the Voltage Translators.

Why 1.8 V for the LTE Modem?

Most parts of the LTE Modem run on 3.3 V… Just that it needs to power up the SIM Card at 1.8 V. (See this)

(Remember that the SIM Card is actually a microcontroller)

This Low Voltage Signaling is probably meant for newer, power-efficient gadgets. (Like this)

LTE Modem inside PinePhone

§6 Power On LTE Modem

Whoa LTE Modem has more pins than a Bowling Alley! (Pic above)

How exactly do we power up the LTE Modem?

Earlier we spoke about PinePhone’s GPIO Pins that control the LTE Modem…

LTE Modem PinA64 GPIO Pin
RF PowerPL7
Baseband PowerPL7
ResetPC4
Power KeyPB3
DisablePH8
StatusPH9

This is how we control the GPIO Pins to power up the LTE Modem

  1. Program PinePhone’s Power Management Integrated Circuit (PMIC) to supply 3.3 V on DCDC1 (Like this)

    We skip this because DCDC1 is already powered on.

  2. Set PL7 to High to power on the RF Transceiver and Baseband Processor

  3. Set PC4 to Low to deassert LTE Modem Reset

  4. Set PH7 (AP-READY) to Low to wake up the modem

  5. Set PB2 (DTR) to Low to wake up the modem

  6. Wait 30 milliseconds for VBAT Power Supply to be stable

  7. Toggle PB3 (Power Key) to start the LTE Modem, like this:

    Set PB3 to High

    And wait 600 milliseconds

    Then set PB3 to Low.

  8. Set PH8 to High to disable Airplane Mode

  9. Read PH9 to check the LTE Modem Status:

    PH9 goes from High to Low when the LTE Modem is ready, in 2.5 seconds.

  10. UART and USB Interfaces will be operational in 13 seconds

EG25-G Hardware Design (Page 41) beautifully illustrates the Power On Sequence

LTE Modem Power

Note that Power Key and Reset are High-Low Inverted when accessed via GPIO Pins PC4 and PB3.

(High becomes Low and vice versa)

Power Key looks funky: High → Low → High…

Yeah the Power Key is probably inspired by the press-and-hold Power Button on vintage Nokia Phones.

(Power Key works differently on pre-production PinePhones)

Let’s implement the steps with Apache NuttX RTOS…

(Kudos to Genode OS for the Power On Sequence)

§7 Power Up wth NuttX

We’ve seen the Power On Sequence for LTE Modem…

How will we implement it in Apache NuttX RTOS?

This is how we implement the LTE Modem’s Power On Sequence in NuttX: pinephone_modem.c

// Read PH9 to check LTE Modem Status
#define STATUS (PIO_INPUT | PIO_PORT_PIOH | PIO_PIN9)
ret = a64_pio_config(STATUS);
DEBUGASSERT(ret == OK);
_info("Status=%d\n", a64_pio_read(STATUS));

(a64_pio_config comes from A64 PIO Driver)

(a64_pio_read too)

We begin by reading PH9 for the LTE Modem Status.

Then we set PL7 to High to power up the RF Transceiver and Baseband Processor: pinephone_modem.c

// Set PL7 to High to Power On LTE Modem (4G-PWR-BAT)
// Configure PWR_BAT (PL7) for Output
#define P_OUTPUT (PIO_OUTPUT | PIO_PULL_NONE | PIO_DRIVE_MEDLOW | \
                  PIO_INT_NONE | PIO_OUTPUT_SET)
#define PWR_BAT (P_OUTPUT | PIO_PORT_PIOL | PIO_PIN7)
a64_pio_config(PWR_BAT);  // TODO: Check result

// Set PWR_BAT (PL7) to High
a64_pio_write(PWR_BAT, true);
// Omitted: Print the status

(a64_pio_write comes from A64 PIO Driver)

(pinephone_modem_init is called by pinephone_bringup)

We set PC4 to Low to deassert the LTE Modem Reset

// Set PC4 to Low to Deassert LTE Modem Reset (BB-RESET / RESET_N)
// Configure RESET_N (PC4) for Output
#define RESET_N (P_OUTPUT | PIO_PORT_PIOC | PIO_PIN4)
a64_pio_config(RESET_N);  // TODO: Check result

// Set RESET_N (PC4) to Low
a64_pio_write(RESET_N, false);
// Omitted: Print the status

Set PH7 (AP-READY) and PB2 (DTR) to Low to wake up the modem

// Set AP-READY (PH7) to Low to wake up modem
// Configure AP-READY (PH7) for Output and set to Low
#define AP_READY (P_OUTPUT | PIO_PORT_PIOH | PIO_PIN7)
a64_pio_config(AP_READY);  // TODO: Check result
a64_pio_write(AP_READY, false);

// Set DTR (PB2) to Low to wake up modem
// Configure DTR (PB2) for Output and set to Low
#define DTR (P_OUTPUT | PIO_PORT_PIOB | PIO_PIN2)
a64_pio_config(DTR);  // TODO: Check result
a64_pio_write(DTR, false);

Wait 30 milliseconds for the power to be stable

// Wait 30 ms
up_mdelay(30);

Now we toggle PB3 for the Power Key: High → 600 milliseconds → Low…

// Set PB3 to Power On LTE Modem (BB-PWRKEY / PWRKEY).
// PWRKEY should be pulled down at least 500 ms, then pulled up.
// Configure PWRKEY (PB3) for Output
#define PWRKEY (P_OUTPUT | PIO_PORT_PIOB | PIO_PIN3)
a64_pio_config(PWRKEY);  // TODO: Check result

// Set PWRKEY (PB3) to High
a64_pio_write(PWRKEY, true);
// Omitted: Print the status

// Wait 600 ms for PWRKEY
up_mdelay(600);
// Omitted: Print the status

// Set PWRKEY (PB3) to Low
a64_pio_write(PWRKEY, false);
// Omitted: Print the status

Finally we set PH8 to High to disable Airplane Mode

// Set PH8 to High to Disable Airplane Mode (BB-DISABLE / W_DISABLE#)
// Configure W_DISABLE (PH8) for Output
#define W_DISABLE (P_OUTPUT | PIO_PORT_PIOH | PIO_PIN8)
a64_pio_config(W_DISABLE);  // TODO: Check result

// Set W_DISABLE (PH8) to High
a64_pio_write(W_DISABLE, true);
// Omitted: Print the status

To wrap up, we wait for LTE Modem Status to turn Low: pinephone_modem.c

// Poll for Modem Status until it becomes Low
for (int i = 0; i < 30; i++) {  // Max 1 minute

  // Read the Modem Status
  uint32_t status = a64_pio_read(STATUS);
  // Omitted: Print the status

  // Stop if Modem Status is Low
  if (status == 0) { break; }

  // Wait 2 seconds
  up_mdelay(2000);
}

Let’s run this!

NuttX starts LTE Modem

NuttX starts LTE Modem

§8 Is LTE Modem Up?

We’ve implemented the Power On Sequence for LTE Modem…

Does it work on Apache NuttX RTOS?

Yes it works! NuttX reads the Modem Status and switches on the power (PL7)…

Configure STATUS (PH9) for Input
Status=0

Set PWR_BAT (PL7) to High
Status=1

(See the Complete Log)

Then it deasserts the reset (PC4) and wakes up the modem (PH7 and PB2)…

Set RESET_N (PC4) to Low
Set AP-READY (PH7) to Low to wake up modem
Set DTR (PB2) to Low to wake up modem

Wait 30 ms
Status=1

NuttX toggles the Power Key (PB3): High → 600 milliseconds → Low…

Set PWRKEY (PB3) to High
Wait 600 ms

Set PWRKEY (PB3) to Low
Status=1

And it disables Airplane Mode (PH8)…

Set W_DISABLE (PH8) to High
Status=1

Finally it waits for the LTE Modem Status (PH9) to turn Low…

pinephone_modem_init: Status=1
pinephone_modem_init: Status=1
pinephone_modem_init: Status=1
pinephone_modem_init: Status=0

And the LTE Modem is up! (Roughly 6 seconds)

(See the Complete Log)

This matches the Power Up Sequence that we saw earlier…

LTE Modem Power

(EG25-G Hardware Design, Page 41)

(Power Key and Reset are High-Low Inverted)

Will the LTE Modem accept AT Commands now?

Not yet. The LTE Modem might take 30 seconds to be fully operational!

Let’s observe the UART Port…

PinePhone Schematic (Page 15)

PinePhone Schematic (Page 15)

(TXB0104 is a Voltage Translator)

§9 Test UART with NuttX

LTE Modem has started successfully on NuttX…

How will we send AT Commands to the modem?

The LTE Modem is connected to PinePhone (Allwinner A64) at these UART Ports (pic above)…

Thus we may check UART3 to see if the LTE Modem responds to AT Commands: hello_main.c

// Open /dev/ttyS1 (UART3)
int fd = open("/dev/ttyS1", O_RDWR);
printf("Open /dev/ttyS1: fd=%d\n", fd);
assert(fd > 0);

// Repeat 5 times: Write command and read response
for (int i = 0; i < 5; i++) {

  // Write command
  const char cmd[] = "AT\r";
  ssize_t nbytes = write(fd, cmd, strlen(cmd));
  printf("Write command: nbytes=%ld\n%s\n", nbytes, cmd);
  assert(nbytes == strlen(cmd));

  // Read response
  static char buf[1024];
  nbytes = read(fd, buf, sizeof(buf) - 1);
  if (nbytes >= 0) { buf[nbytes] = 0; }
  else { buf[0] = 0; }
  printf("Response: nbytes=%ld\n%s\n", nbytes, buf);

  // Wait a while
  sleep(2);
}

// Close the device
close(fd);

The NuttX App above sends the command “AT” to the LTE Modem over UART3. (5 times)

Watch what happens when we run it…

Testing LTE Modem over UART

(See the Complete Log)

Our NuttX App sends command “AT” to the LTE Modem over UART3…

Open /dev/ttyS1
Write command: AT\r

But it hangs there. No response!

Remember that the LTE Modem might take 30 seconds to become operational. Be patient, the response appears in a while…

Response:
RDY

RDY” means that the LTE Modem is ready for AT Commands!

(EG25-G AT Commands, Page 297)

Our NuttX App sends command “AT” again…

Write command: AT\r
Response:
+CFUN: 1
+CPIN: NOT INSERTED

LTE Modem replies…

Our NuttX App sends command “AT” once more…

Write command: AT\r
Response:
AT
OK

LTE Modem echoes our command “AT”…

And responds to our command with “OK”.

Which means that our LTE Modem is running AT Commands all OK!

(See the Complete Log)

UART3 works with NuttX?

We modified the Allwinner A64 UART Driver to support UART3. The changes will be upstreamed to NuttX Mainline later…

TODO: Disable UART2 and /dev/ttyS2 so that UART3 maps neatly to /dev/ttyS3. (See this)

There’s another way to test the LTE Modem: Via USB…

USB Controller Block Diagram from Allwinner A64 User Manual

USB Controller Block Diagram from Allwinner A64 User Manual

§10 Test USB with NuttX

We talked about testing the LTE Modem the UART way…

What about the USB way?

Yep the USB Interface should work for testing the LTE Modem…

How’s that coming along?

We fixed the NuttX USB EHCI Driver (pic above) to handle USB Interrupts…

But somehow the LTE Modem isn’t triggering any USB Interrupts (13 seconds after startup)…

Which fails the enumeration of USB Devices (like the LTE Modem). And we can’t connect to the USB Interface of the LTE Modem.

But then we discovered that the GPIO Pins for Power Key and Reset are High-Low Inverted. So we need to retest.

Stay tuned for updates on the USB Testing!

(This crash needs to be fixed when USB Hub Support is enabled)

Quectel EG25-G LTE Modem inside PinePhone

Quectel EG25-G LTE Modem inside PinePhone

§11 What’s Next

I hope this article was helpful for learning about PinePhone’s 4G LTE Modem…

Up Next: Find out how we make phone calls and send text messages with PinePhone’s 4G LTE Modem…

Also check out the other articles on NuttX for PinePhone…

Many Thanks to my GitHub Sponsors for supporting my work! This article wouldn’t have been possible without your support.

Got a question, comment or suggestion? Create an Issue or submit a Pull Request here…

lupyuen.github.io/src/lte.md

§12 Notes

  1. There’s plenty more inside PinePhone’s LTE Modem. Check out these articles…

    “Genode: PinePhone Telephony”

    “PinePhone Power Management”

    “Modem on PinePhone”

    “Audio on PinePhone”

    “EG25-G Reverse Engineering”

    “OSDev: PinePhone”

  2. Take note of these Limitations and Design Decisions

    “Modem UART flow control is broken”

    “Modem PWR_KEY signal resistor population”

  3. LTE Modem Pinout is different for pre-production editions of PinePhone! (Like Braveheart 1.1)

    I’m using PinePhone Hardware Revision 1.2 (Ubports Edition)…

    “PinePhone Hardware Revisions”

  4. Why are we experimenting with BOTH UART and USB for the LTE Modem?

    Here’s the long story

LTE Modem inside PinePhone

§13 Appendix: LTE Modem Pins

What’s the purpose of the above LTE Modem pins?

This section describes the purpose of every LTE Modem pin connected to PinePhone…

§13.1 Power Supply

From EG25-G Hardware Design (Page 22)…

Pin NamePin No.I/ODescription
VDD_EXT7POProvide 1.8 V for external circuit

(PO is Power Output)

§13.2 Power On / Off

From EG25-G Hardware Design (Page 22)…

Pin NamePin No.I/ODescription
PWRKEY21DITurn on / off the module
RESET_N20DIReset signal of the module

(DI is Digital Input)

§13.3 Status Indication

From EG25-G Hardware Design (Page 22)…

Pin NamePin No.I/ODescription
STATUS61ODIndicate the module operating status

(OD is Open Drain)

§13.4 USB Interface

From EG25-G Hardware Design (Page 22)…

Pin NamePin No.I/ODescription
USB_VBUS71PIUSB connection detection

(PI is Power Input)

§13.5 Main UART Interface

From EG25-G Hardware Design (Page 24)…

Pin NamePin No.I/ODescription
RI62DORing indicator
CTS64DOClear to send
RTS65DIRequest to send
DTR66DIData terminal ready, sleep mode control
TXD67DOTransmit data
RXD68DIReceive data

(DO is Digital Output)

(DI is Digital Input)

§13.6 Other Interface Pins

From EG25-G Hardware Design (Page 32)…

Pin NamePin No.I/ODescription
W_DISABLE#4DIAirplane mode control
AP_READY2DIApplication processor sleep state detection

(DI is Digital Input)

§13.7 I/O Parameters Definition

From EG25-G Hardware Design (Page 21)…

TypeDescription
AIAnalog Input
AOAnalog Output
DIDigital Input
DODigital Output
IOBidirectional
ODOpen Drain
PIPower Input
POPower Output