Semtech SX1231 FIFO读取异常求助:仅能读取首字节0x04
SX1231 FIFO读取异常排查:仅能获取消息长度字节,无法读取后续内容
我使用基于8051架构的Megawin MG82F6D64单片机,通过SPI连接Semtech SX1231射频芯片,目前遇到FIFO读取异常问题:仅能读取到代表消息长度为4字节的首字节0x04,无法读取后续4字节的消息内容。现有一台搭载同款SX1231的平板与开关控制设备可正常通信,但我无法获取完整消息。以下是当前的C代码及可正常工作的汇编代码,请求排查解决该问题。
问题代码(C语言)
#include <stdint.h> #include <stdbool.h> #include <reg_mg82f6d64.h> #define RegFifo 0x00 #define RegIrqFlags1 0x27 #define RegIrqFlags2 0x28 void wrb(uint8_t dat); void read_single(uint8_t reg); void w_f_rc(void); void rlc1(void); void w_f_fs(void); uint8_t masterInput; void main() { INITs(); w_f_fs();// 0x04 ->0x90 //;---set receiver mode w_f_rc();// 0x08 ->0xD8 while (1) { read_single(RegIrqFlags2); if ((masterInput == 0x40)) //check if there is any byte in FIFO { read_single(RegFifo);// I should read 0x04 means the message 4 byte long read_single(RegFifo);// Then I should read rest of the message with following lines below read_single(RegFifo);//But I still gets from SPI 0x04 read_single(RegFifo);// and here 0x04 read_single(RegFifo);// and here 0x04 read_single(RegFifo);// and here 0x04 } } } //*************************************************************** //; this function only reads 1Byte from SX1231 void read_single(uint8_t reg) { EA = 0; P14 = 0; // nSS -> LOW (SPI ON) EA = 1; wrb((reg & 0x7F)); wrb(reg); EA = 0; P14 = 1; // nSS -> HIGH (SPI OFF) EA = 1; } //;******************************************************************************************** //; this function write to MOSI from the "dat" parameter, // also write to masterInput variable from the MISO void wrb(uint8_t dat) // (write read byte) { while ((SPSTAT & 0x80) != 0); // wrb0: //(A != 0); SPDAT = dat; while ((SPSTAT & 0x80) == 0); // herebe: //(A == 0); masterInput = SPDAT; } void w_f_fs(void) { wrt_single(RegOpMode, 0x08);//0x04 // ;frequency synthesiser mode read_single(RegIrqFlags1);//0x90 while ((masterInput & 0x10) == 0) //;pll locked? { // sinR: read_single(RegIrqFlags1); } } void rlc1(void) { read_single(RegIrqFlags1);//0xD8 while ((masterInput & 0x80) == 0) // rlc1: { read_single(RegIrqFlags1); } } //-------------------------------------- // wait for sx1231's change mode to receive void w_f_rc(void) { wrt_single(RegOpMode, 0x10);//0x08 //;receive mode rlc1(); }
可正常工作的汇编代码
Received_RF: DS 5 NODE: DS 4 PRELST: DS 2 ; incoming message writes to Received_RF buffer ;if overflow occurs or length is not 4, exits with no ; Format of RF message from tablet: ; 4 ; id1 ; id2 ; device ; operation rf_rec_to_main: MOV B,#RegFifo ;message length LCALL read_single MOV Received_RF,A CJNE A,#4,rrtm0 MOV B,#RegFifo ;id1 LCALL read_single MOV NODE,A MOV B,#RegFifo ;id2 LCALL read_single MOV NODE+1,A MOV B,#RegFifo ;device id LCALL read_single MOV NODE+2,A MOV B,#RegFifo ;useful info (80,81) LCALL read_single MOV NODE+3,A CJNE A,#20h,same1 JMP rrtm5 ;promotion? read_single: ANL IE,#7Fh ANL PRELST+0,#0EFh ;cs MOV P1,PRELST+0 ORL IE,#80h MOV A,B LCALL wrb LCALL wrb ANL IE,#7Fh ORL PRELST+0,#10h ;remove cs MOV P1,PRELST+0 ORL IE,#80h RET wrt_single: ANL IE,#7Fh ANL PRELST+0,#0EFh ;slave select MOV P1,PRELST+0 ORL IE,#80h PUSH ACC MOV A,B ORL A,#80h LCALL wrb POP ACC LCALL wrb ANL IE,#7Fh ORL PRELST+0, #10h ;remove slave select MOV P1, PRELST+0 ORL IE,#80h RET wrb: PUSH ACC wrb0: MOV A,SPSTAT ANL A,#80h JNZ wrb0 POP ACC MOV SPDAT,A herebe: MOV A,SPSTAT ANL A,#80h JZ herebe MOV A,SPDAT RET
问题排查与修复方案
1. 核心问题:read_single函数逻辑错误
C代码中read_single的第二次wrb传递了reg参数,导致重复发送寄存器读命令,干扰了SX1231的FIFO指针递增逻辑。正确的SPI读寄存器流程应为:发送读地址后,发送任意填充字节触发时钟,接收真正的寄存器数据。
修复后的read_single和wrb函数:
// 修改wrb为返回读取值,避免全局变量覆盖 uint8_t wrb(uint8_t dat) { while ((SPSTAT & 0x80) != 0); // 等待上一次传输完成 SPDAT = dat; while ((SPSTAT & 0x80) == 0); // 等待本次传输完成 return SPDAT; } // 读取单个寄存器,返回结果 uint8_t read_single(uint8_t reg) { uint8_t result; EA = 0; P14 = 0; // nSS拉低 wrb(reg & 0x7F); // 发送读命令 result = wrb(0x00); // 发送空字节,接收目标数据 P14 = 1; // nSS拉高 EA = 1; return result; }
2. 中断标志判断错误
当前代码判断RegIrqFlags2 == 0x40(FIFO非空),但应等待整包接收完成的RxReady中断(RegIrqFlags1的bit7,即0x80),避免在接收过程中提前读取FIFO导致数据不完整。
修复后主循环:
void main() { uint8_t msg_len; uint8_t msg_buf[4]; INITs(); w_f_fs(); w_f_rc(); while (1) { // 等待整包接收完成(RxReady中断) if (read_single(RegIrqFlags1) & 0x80) { msg_len = read_single(RegFifo); if (msg_len == 4) { msg_buf[0] = read_single(RegFifo); msg_buf[1] = read_single(RegFifo); msg_buf[2] = read_single(RegFifo); msg_buf[3] = read_single(RegFifo); // 此处添加消息处理逻辑 } // 读取RegIrqFlags1已自动清除中断标志 } } }
3. 初始化配置缺失
C代码中INITs()函数未提供,需补充SX1231的关键配置(需与汇编代码一致),包括:
- FIFO基地址配置(
RegFifoTxBaseAddr、RegFifoRxBaseAddr) - 调制参数配置(
RegModemConfig1、RegModemConfig2) - 同步字配置(
RegSyncConfig、RegSyncValue) - 数据包格式配置(
RegPacketConfig1、RegPacketConfig2) - FIFO阈值配置(
RegFifoThreshold)
内容的提问来源于stack exchange,提问作者osLIII
相关产品推荐
相关产品推荐

