STM32F7与Telit GL865间LWIP PPPoS的LCP协商无法启动问题排查
STM32F7 Nucleo + Telit GL865 GSM PPPoS 问题排查
问题背景
我正在用STM32F7 Nucleo开发板搭配Telit GL865 GSM模块,通过USART1进行通信。原本的流程是先通过AT命令配置模块,之后模块会发送LCP包,但目前模块最终返回NO CARRIER提示,看起来无法处理PPP协商流程。现在有两个核心问题困扰我:
- 不确定当前使用的AT命令是否正确(和我参考的ESP-IDF示例中的命令不一样);
- 调用
pppos_create(&ppp_netif, output_cb, status_cb, 0)之后,status_cb回调函数完全没有被触发。
相关代码(部分截断)
/////////////////////////// Includes #include "main.h" #include "stm32f7xx_hal.h" #include "lwip.h" #include "usart.h" #include "gpio.h" #include <stdio.h> #include <stdarg.h> #include <time.h> #include "string.h" #include "lwip/opt.h" #include "lwip/sys.h" #include "lwip/timeouts.h" #include "lwip/debug.h" #include "lwip/stats.h" #include "lwip/init.h" #include "lwip/tcpip.h" #include "lwip/netif.h" #include "lwip/api.h" #include "lwip/tcp.h" #include "lwip/udp.h" #include "lwip/dns.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" #include "lwip/etharp.h" #include "netif/ethernet.h" #include "lwip/apps/netbiosns.h" #include "lwip/apps/httpd.h" #include "netif/ppp/pppos.h" #include "ppp/ppp.h" #include "lwip/sio.h" #include "netif/ppp/pppapi.h" #include "netif/ppp/pppos.h" #include "netif/ppp/pppoe.h" #include "netif/ppp/ppp_opts.h" /////////////////////////////////////////////End of Includes void SystemClock_Config(void); #define RX_SIZE 64 ///////////////////////////////////////////////////////Variables uint32_t sysTickCounter = 0; uint8_t sendData[50] = " \n"; uint8_t recData; uint8_t receivedValue, connected = 0; uint32_t recIndex = 0; uint8_t recBuffer[RX_SIZE]; uint8_t pppLinkStatusCallbackArray[RX_SIZE]; uint8_t sent,sendMeToPPPoS = 0; ppp_pcb *ppp; struct netif ppp_netif; u8_t sio_idx = 0; sio_fd_t ppp_sio; uint8_t ATconnected,lcpCame,length = 0; uint8_t lcpStartIndex, lcpStopIndex,lcpStartOld,lcpStart,lcpStop = 0; ////////////////////////////////////////////////////////////End of Variables ////////////////////////////////////////////////////////////PPP Functions static void status_cb(ppp_pcb *pcb, int err_code, void *ctx) { //this function is never called; however, it must have been called in the main with ppp = pppos_create(&ppp_netif, output_cb, status_cb, 0); struct netif *pppif = ppp_netif(pcb); LWIP_UNUSED_ARG(ctx); switch(err_code) { case PPPERR_NONE: { printf("status_cb: Connected\n"); printf(" our_ipaddr = %s\r\n", ipaddr_ntoa(&pppif->ip_addr)); printf(" his_ipaddr = %s\r\n", ipaddr_ntoa(&pppif->gw)); printf(" netmask = %s\r\n", ipaddr_ntoa(&pppif->netmask)); connected = 1; // break; } case PPPERR_PARAM: { printf("status_cb: Invalid parameter\r\n"); break; } case PPPERR_OPEN: { printf("status_cb: Unable to open PPP session\r\n"); break; } case PPPERR_DEVICE: { printf("status_cb: Invalid I/O device for PPP\r\n"); break; } case PPPERR_ALLOC: { printf("status_cb: Unable to allocate resources\r\n"); break; } case PPPERR_USER: { ppp_free(); printf("status_cb: User interrupt\r\n"); break; } case PPPERR_CONNECT: { printf("status_cb: Connection lost\r\n"); break; } case PPPERR_AUTHFAIL: { printf("status_cb: Failed authentication challenge\r\n"); break; } case PPPERR_PROTOCOL: { printf("status_cb: Failed to meet protocol\r\n"); break; } case PPPERR_PEERDEAD: { printf("status_cb: Connection timeout\r\n"); break; } case PPPERR_IDLETIMEOUT: { printf("status_cb: Idle Timeout\r\n"); break; } case PPPERR_CONNECTTIME: { printf("status_cb: Max connect time reached\r\n"); break; } case PPPERR_LOOPBACK: { printf("status_cb: Loopback detected\r\n"); break; } default: { printf("status_cb: Unknown error code %d\r\n", err_code); break; } } ppp_connect(pcb, 30);//Try to reconnect in 30 seconds } static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { //UART output callback for PPPoS return HAL_UART_Transmit_IT(&huart1, data, sizeof(data)); } /////////////////////////////////////////////////////////End of PPP Functions /////////////////////////////////////////////////////////////////////////Main int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_USART1_UART_Init(); MX_LWIP_Init(); HAL_UART_Receive_IT(&huart1, &recData, 1); SysTick_Config(SystemCoreClock/1000); HAL_Delay(300);//delay 300ms memset(recBuffer, 0, sizeof(recBuffer));//UART receive buffer HAL_UART_Transmit_IT(&huart1, (uint8_t*)"AT\r\n", strlen("AT\r\n"));//send this AT command over UART to GSM module HAL_Delay(300); HAL_Delay(300); memset(rec
排查与解决建议
1. 先搞定AT命令配置的正确性
Telit GL865的PPP配置逻辑和ESP-IDF里的模块差异很大,别直接照搬ESP的命令,得严格参考GL865的 datasheet:
- 先确认网络注册状态:发送
AT+CREG?,如果返回+CREG: 0,1(本地注册)或+CREG: 0,5(漫游注册)才说明模块连上网了,这是PPP协商的前提; - 启动PPP会话的正确命令:GL865用
AT#PPP=1来开启PPP模式,而不是ESP里可能用到的AT+CGDCONT之后直接触发的逻辑,发送这个命令后模块才会开始发送LCP包; - 串口参数必须匹配:GL865默认是115200波特率、8位数据位、无校验、1停止位,你得确保
MX_USART1_UART_Init()里的配置和这个完全一致; - 别用HAL_Delay等响应:用
HAL_Delay()来等模块响应太不靠谱,应该在串口接收中断里判断模块返回的OK或其他响应,确认上一条AT命令执行成功后,再发送下一条,避免命令发送时机错误导致配置失败。
2. 修复PPPoS回调未触发的核心问题
status_cb没触发,本质是PPP栈根本没进入协商流程,先查这几个关键点:
- output_cb的致命错误:你现在返回
HAL_UART_Transmit_IT(&huart1, data, sizeof(data)),sizeof(data)是指针的大小(32位机是4字节),不是实际要发送的len!这会导致PPP发送的帧被截断,模块收不到完整的PPP数据,自然不会响应。改成:static u32_t output_cb(ppp_pcb *pcb, u8_t *data, u32_t len, void *ctx) { //UART output callback for PPPoS return HAL_UART_Transmit_IT(&huart1, data, len); } - 必须把串口接收的数据喂给PPP栈:你现在用
HAL_UART_Receive_IT接收单个字节,但收到后要调用pppos_input(&ppp_netif, &recData, 1)把数据传给PPP栈,否则PPP栈收不到模块发来的LCP包,根本不会启动协商,status_cb当然不会触发; - 检查LWIP配置宏:在
lwipopts.h里必须开启:
如果这些宏没开,PPP功能是禁用的,调用#define PPP_SUPPORT 1 #define PPPOS_SUPPORT 1 #define PPP_DEBUG 1 // 开启调试方便看日志pppos_create也不会有效果; - 检查pppos_create的返回值:代码里要判断
ppp是否为NULL,如果创建失败,后续流程都不会执行:ppp = pppos_create(&ppp_netif, output_cb, status_cb, 0); if (ppp == NULL) { printf("Failed to create PPPoS PCB!\r\n"); // 处理错误 } - 确认tcpip线程正常运行:
MX_LWIP_Init()应该已经启动了tcpip线程,你可以加个日志或者断点确认线程是否在运行。
3. 解决LCP包无法处理和NO CARRIER的问题
模块发送LCP包后返回NO CARRIER,本质是PPP栈没收到或者没回复LCP帧,解决上面的串口数据喂入和output_cb的问题后,PPP栈就能正常和模块进行LCP协商了,这个问题应该会随之解决。
内容的提问来源于stack exchange,提问作者Sarp Engin Daltaban
相关产品推荐
相关产品推荐

