This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320C6748: SPI Flash程序一直卡在忙判断

Part Number: TMS320C6748

运行例程TMS320C6748的SPI Flash,发现程序一直卡在忙判断中,循环执行读状态寄存器的指令,读取到的数据全为0xff。例程仅将SPI1改为了SPI0,然后用的flash芯片为W25Q128JW,请问这种情况应如何调试

  • 下面的我的主函数,基本上对原始例程没有修改

    /****************************************************************************/
    /* */
    /* SPI FLASH 读写测试 */
    /* */
    /* 2024年12月05日 */
    /* */
    /****************************************************************************/

    /****************************************************************************/
    /* */
    /* 头文件声明(硬件抽象层HAL) */
    /* */
    /****************************************************************************/
    #include "TL6748.h" // TL6748芯片 ,函数声明
    #include "soc_C6748.h" // 系统级芯片SoC ———— C6748 SOC的外设信息
    #include "hw_psc_C6748.h" // 电源系统控制器PSC ———— 硬件寄存器和字段
    #include "uart.h" // 异步收发传输器UART————宏定义
    #include "spi.h" // 串行外设接口SPI————宏定义
    #include "psc.h" // 电源系统控制器PSC————宏定义
    #include "uartStdio.h" // 函数原型
    #include "interrupt.h" // DSP中断相关的API声明和系统中断
    #include <string.h> // C标准库中的字符串处理函数

    /****************************************************************************/
    /* */
    /* 宏定义 */
    /* */
    /****************************************************************************/
    // SPI 管脚配置
    #define SIMO_SOMI_CLK_CS 0x00000E01 // SPI接口的引脚配置值
    #define CHAR_LENGTH 0x8 // 数据长度 或 缓冲区大小

    // FLASH 地址
    #define SPI_FLASH_ADDR_MSB1 0x0A // 这三行定义了访问SPI Flash时的地址 0A0000
    #define SPI_FLASH_ADDR_MSB0 0x00
    #define SPI_FLASH_ADDR_LSB 0x00

    // SPI Flash 操作指令码
    #define SPI_FLASH_SECTOR_ERASE 0xD8 // 扇区擦除命令 0xD8
    #define SPI_FLASH_PAGE_WRITE 0x02 // 页写入命令 0x02
    #define SPI_FLASH_STATUS_RX 0x05 // 读状态寄存器命令 0x05
    #define SPI_FLASH_WRITE_EN 0x06 // 写使能命令 0x06
    #define SPI_FLASH_READ 0x03 // 读命令 0x03

    // 写操作执行中
    #define WRITE_IN_PROGRESS 0x01 // 表示写操作正在进行的标志位

    /****************************************************************************/
    /* */
    /* 全局变量 */
    /* */
    /****************************************************************************/
    // 同步操作的标志
    volatile unsigned int flag = 1; // volatile确保编译器不会缓存该变量的值

    // 发送和接收数据的长度
    unsigned int tx_len;
    unsigned int rx_len;

    // 用于存放发送、接收、验证数据的数组
    unsigned char vrf_data[260];
    unsigned char tx_data[260];
    unsigned char rx_data[260];

    // 指针————指向发送和接收的数据缓冲区
    unsigned char *p_tx;
    unsigned char *p_rx;

    /****************************************************************************/
    /* */
    /* 函数声明 */
    /* */
    /****************************************************************************/
    void PSCInit(void); // 初始化电源系统控制器PSC
    void GPIOBankPinMuxSet(void); // 配置GPIO引脚复用
    void SPIDataFormatConfig(unsigned int dataFormat); //配置SPI数据格式

    void ReadFromFlash(void); // 从Flash读取数据
    void IsFlashBusy(void); // 检查Flash是否忙
    void WritetoFlash(void); // 向Flash写入数据
    void WriteEnable(void); // 启用写操作
    void SpiTransfer(void); // 进行SPI数据传输
    void SectorErase(void); // 擦除Flash
    int VerifyData(void); // 校验数据
    void StatusGet(void); // 获取Flash的状态
    void InterruptInit(void); // 初始化中断系统
    void SPIInterruptInit(void); // 初始化SPI中断
    void SPIInit(void); // 初始化SPI接口
    void SPIIsr(void); // SPI中断服务例程

    /****************************************************************************/
    /* */
    /* 主函数 */
    /* */
    /****************************************************************************/
    int main(void)
    {
    PSCInit(); // 初始化PSC
    GPIOBankPinMuxSet(); // GPIO管脚复用
    UARTStdioInit(); // 初始化UART,使用串口2
    UARTPuts("SPI Flash实验\r\n", -1);
    GPIOBankPinMuxSet(); // 初始化GPIO管脚复用,再次调用,保证GPIO配置正确
    InterruptInit(); // 初始化DSP中断
    SPIInterruptInit(); // 初始化SPI中断
    SPIInit(); // 初始化SPI接口
    WriteEnable(); // 写使能启用对Flash的写操作(擦除前需要写使能)
    SectorErase(); // 擦除 Flash ——————————————————目前程序问题出现在这里

    // 向Flash写入数据并验证是否正确
    WriteEnable(); // 写使能
    WritetoFlash(); // 写入Flash数据
    ReadFromFlash(); // 读取Flash数据
    VerifyData(); // 验证数据一致性
    UARTPuts("已验证Flash数据\r\n", -1);

    // 进入无限循环,等待下一步处理或退出程序
    for(;;)
    {
    }
    }

    // ———————————————————————————————————————— 其他子函数 ————————————————————————————————————————

    /****************************************************************************/
    /* */
    /* 初始化 */
    /* */
    /****************************************************************************/

    // PSC初始化
    void PSCInit(void)
    {
    PSCModuleControl(SOC_PSC_0_REGS, HW_PSC_SPI0, PSC_POWERDOMAIN_ALWAYS_ON, PSC_MDCTL_NEXT_ENABLE);
    // 指定PSC0基地址、指定硬件模块SPI0、电源开启、模块使能
    // 确保SPI0模块有电且随时可用(SPI0模块由PCS0管理)
    }

    // GPIO 管脚复用配置
    void GPIOBankPinMuxSet(void)
    {
    SPIPinMuxSetup(0); // 启用SPI0通道————参数为0表示设置PINMUX3的15_0位(对应SPI0),参数为1表示设置PINMUX5的23_8位(对应SPI1)
    SPI1CSPinMuxSetup(0); // 设置SPI0_SCS0引脚————为SPI0通道设置片选引脚SPI0_SCS0
    }

    // 初始化DSP中断
    void InterruptInit(void)
    {
    IntDSPINTCInit(); // 初始化DSP中断控制器
    IntGlobalEnable(); // 使能DSP全局中断
    }

    // 初始化SPI中断
    void SPIInterruptInit(void)
    {
    IntRegister(C674X_MASK_INT4, SPIIsr); // 注册中断服务函数————注册INT4中断函数为SPIIsr,将c674xISRtbI[4]指向SPIIsr
    IntEventMap(C674X_MASK_INT4, SYS_INT_SPI0_INT); // 映射中断事件————将SPI0中断源映射到INT4
    IntEnable(C674X_MASK_INT4); // 使能可屏蔽中断————使能INT4
    }

    // 初始化SPI接口
    void SPIInit(void)
    {
    unsigned char cs = 0x01; // 配置SPI片选信号
    unsigned char dcs = 0x01;
    unsigned int val = SIMO_SOMI_CLK_CS; // 用于存储SPI引脚配置
    SPIReset(SOC_SPI_0_REGS); // SPI0复位,确保处于已知状态,其中SOC_SPI_0_REGS 表示SPI0寄存器的基地址
    SPIOutOfReset(SOC_SPI_0_REGS); // 取消SPI0复位,SPI0开始工作
    SPIModeConfigure(SOC_SPI_0_REGS, SPI_MASTER_MODE); // 配置SPI0为主模式
    SPIClkConfigure(SOC_SPI_0_REGS, 228000000, 20000000, SPI_DATA_FORMAT0); // 配置时钟,SPI工作时钟频率为20MHz,模块时钟为228MHz (228000000, 20000000)
    SPIPinControl(SOC_SPI_0_REGS, 0, 0, &val); // 配置SPI引脚控制器————这里是写SPIPC0,配置SPI模块的引脚功能(而不是GPIO功能)
    SPIDefaultCSSet(SOC_SPI_0_REGS, dcs); // 配置CS脚的缺省值,无数据传输时CS电平为缺省值(此处设为高电平)
    SPIDataFormatConfig(SPI_DATA_FORMAT0); // 配置SPI数据格式————配置为DATA_FORMAT0寄存器中的格式值
    SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), cs); // 配置SPI数据格式及片选信号
    SPIIntLevelSet(SOC_SPI_0_REGS, SPI_RECV_INTLVL | SPI_TRANSMIT_INTLVL); // 配置SPI中断级别(分别配置接收中断级别、发送中断级别)
    SPIEnable(SOC_SPI_0_REGS); // 使能 SPI0
    }

    /****************************************************************************/
    /* */
    /* SPI Flash读写验证 */
    /* */
    /****************************************************************************/

    // SPI Flash写使能
    void WriteEnable(void)
    {
    tx_data[0] = SPI_FLASH_WRITE_EN; // SPI写使能
    tx_len = rx_len = 1; // 数据长度为1
    SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
    SpiTransfer();
    }

    // 擦除SPI Flash
    void SectorErase(void)
    {
    tx_data[0] = SPI_FLASH_SECTOR_ERASE;
    tx_data[1] = SPI_FLASH_ADDR_MSB1;
    tx_data[2] = SPI_FLASH_ADDR_MSB0;
    tx_data[3] = SPI_FLASH_ADDR_LSB;
    tx_len = rx_len = 4;
    SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
    SpiTransfer();
    UARTPuts("程序停止在忙判断(完成数据传输,未完成忙判断)\r\n", -1);
    IsFlashBusy(); // 忙判断——————————————————————————————————目前程序停止在这
    }

    // 写SPI Flash
    void WritetoFlash(void)
    {
    unsigned int index;
    tx_data[0] = SPI_FLASH_PAGE_WRITE;
    tx_data[1] = SPI_FLASH_ADDR_MSB1;
    tx_data[2] = SPI_FLASH_ADDR_MSB0;
    tx_data[3] = SPI_FLASH_ADDR_LSB;

    for (index = 4; index < 260; index++)
    {
    tx_data[index] = index;
    }

    for(index = 4; index < 260; index++)
    {
    vrf_data[index] = index;
    }

    tx_len = rx_len = index;

    SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
    SpiTransfer();
    IsFlashBusy();
    }

    // 读SPI Flash
    void ReadFromFlash(void)
    {
    unsigned int index;
    tx_data[0] = SPI_FLASH_READ;
    tx_data[1] = SPI_FLASH_ADDR_MSB1;
    tx_data[2] = SPI_FLASH_ADDR_MSB0;
    tx_data[3] = SPI_FLASH_ADDR_LSB;

    for (index = 4; index < 260; index++)
    {
    tx_data[index] = 0;
    }

    tx_len = rx_len = index;
    SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
    SpiTransfer();
    }

    // 数据校验
    int VerifyData(void)
    {
    unsigned int index;
    UARTPuts(" 数据校验: ", -1);
    UARTPuts("\r\n", -1);
    for(index = 4; index < 260; index++)
    {
    if(vrf_data[index] != rx_data[index])
    {
    UARTPuts("\r\n", -1);
    UARTPuts(" 数据不匹配的位置: ", -1);
    UARTPutNum((int)index - 3);
    UARTPuts("\r\n", -1);
    UARTPuts("验证失败\r\n", -1);
    return 0;
    }
    }

    if (index == 260)
    {
    UARTPuts("\r\n", -1);
    UARTPuts("读写数据相同\r\n", -1);
    UARTPuts("验证成功\r\n", -1);
    return 1;
    }

    return 0;
    }

    /****************************************************************************/
    /* */
    /* 其他函数 */
    /* */
    /****************************************************************************/

    // SPI Flash忙判断
    void IsFlashBusy(void)
    {
    do{
    StatusGet();
    }while(rx_data[1] & WRITE_IN_PROGRESS); // 退出循环的条件为rx_data[1] = 0
    }

    // 读状态寄存器
    void StatusGet(void)
    {
    tx_data[0] = SPI_FLASH_STATUS_RX;
    tx_len = rx_len = 2;
    SPIDat1Config(SOC_SPI_0_REGS, (SPI_CSHOLD | SPI_DATA_FORMAT0), 0x1);
    SpiTransfer();
    }

    // 配置 SPI 数据格式
    void SPIDataFormatConfig(unsigned int dataFormat)
    {
    // 配置 SPI 时钟(极性和相位,SPI时钟空闲时为高电平,数据在第一个边沿被采样(下降沿采样))
    SPIConfigClkFormat(SOC_SPI_0_REGS,
    (SPI_CLK_POL_HIGH | SPI_CLK_INPHASE),
    dataFormat);

    // 配置 SPI 发送时 MSB 优先,MSB表示最高有效位
    SPIShiftMsbFirst(SOC_SPI_0_REGS, dataFormat);

    // 设置字符长度,设定每个字符的位数(数据字长度为8位,即一个字符8位)
    SPICharLengthSet(SOC_SPI_0_REGS, CHAR_LENGTH, dataFormat);
    }

    // SPI数据传输
    void SpiTransfer(void)
    {
    p_tx = &tx_data[0]; // 将指针p_tx指向tx_data的第一个元素
    p_rx = &rx_data[0]; // 将指针p_rx指向rx_data的第一个元素
    SPIIntEnable(SOC_SPI_0_REGS, (SPI_RECV_INT | SPI_TRANSMIT_INT));
    // 使能发送中断和接收中断,产生SPI0中断,转入SPIIsr中断服务函数
    while(flag);
    flag = 1;
    SPIDat1Config(SOC_SPI_0_REGS, SPI_DATA_FORMAT0, 0x1); // 配置SPI数据格式及片选信号
    }

    // SPI 中断服务函数
    void SPIIsr(void)
    {
    unsigned int intCode = 0; // 清除CPU中断标志,intCode用于存储中断向量码
    IntEventClear(SYS_INT_SPI0_INT); // 清除SPI0中断标志,确保中断已经被处理
    intCode = SPIInterruptVectorGet(SOC_SPI_0_REGS); // 读取SPI0中断向量码,确定引起中断的事件类型

    while (intCode) // 判断是发送中断还是接收中断
    {
    if(intCode == SPI_TX_BUF_EMPTY) // 发送缓冲区空引起的中断
    {
    tx_len--; // tx_len减1,用于后面if条件判断
    SPITransmitData1(SOC_SPI_0_REGS, *p_tx); // 发送当前指向的数据
    p_tx++; // 移动指针到下一个待发送数据
    if (!tx_len) // 如果所有数据都发送完毕(tx_len=0),禁用发送中断
    {
    SPIIntDisable(SOC_SPI_0_REGS, SPI_TRANSMIT_INT);
    }
    }

    if(intCode == SPI_RECV_FULL) // 接收缓冲区满引起的中断
    {
    rx_len--; // rx_len减1,用于后面if条件判断
    *p_rx = (char)SPIDataReceive(SOC_SPI_0_REGS); // 读取接收到的数据,类型转为char,存储到*p_rx指向的位置
    p_rx++; // 移动指针到下一个待接收的数据
    if (!rx_len) // 如果所有数据都接收完毕(rx_len=0),禁用接收中断,设置标志位flag=0
    {
    flag = 0;
    SPIIntDisable(SOC_SPI_0_REGS, SPI_RECV_INT);
    }
    }
    intCode = SPIInterruptVectorGet(SOC_SPI_0_REGS); // 重新读取中断向量码,确保没有新的中断发生(intCode=0),退出ISR
    }
    }

  • 您好

    您用的是什么例程?

  • 您好

    由于长时间未收到回复,本贴关闭。

    如果仍有问题,请随时重新发帖咨询。