You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 08:57:02