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.

[参考译文] TMS320F28377S:TMS320F28377S SPI 通信问题

Guru**** 2330840 points
Other Parts Discussed in Thread: TMS320F28377S
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1511640/tms320f28377s-tms320f28377s-spi-communication-problem

器件型号:TMS320F28377S

工具/软件:

TI 团队大家好、

我正在使用 TMS320F28377S 并尝试使用建立通信 SPI 模块 。 我已经处理了两天、但一直无法让它正常工作。

SPI 通信函数时被重用 而不对配置进行任何更改 、我可以成功写入和读取数据。

我尝试与之通信的器件是 EEPROM 芯片:25LC640A-E/SN 。 请帮我解决这个问题。

以下是 引脚分配 工程 我已经准备好了。

(无法正常工作)

void SPI_GPIO_Init(void)
{
EALLOW;

// === MOSI: GPIO24 → SPISIMOB ===
GpioCtrlRegs.GPAGMUX2.bit.GPIO24 = 1; // Set GPIO24 to use GMUX option 1
GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 2; // Set MUX to 2 for SPISIMOB function
GpioCtrlRegs.GPAQSEL2.bit.GPIO24 = 3;

// === MISO: GPIO25 → SPISOMIB ===
GpioCtrlRegs.GPAGMUX2.bit.GPIO25 = 1; // Set GPIO25 to use GMUX option 1
GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 2; // Set MUX to 2 for SPISOMIB function
GpioCtrlRegs.GPAQSEL2.bit.GPIO25 = 3;

// === CLK: GPIO26 → SPICLKB ===
GpioCtrlRegs.GPAGMUX2.bit.GPIO26 = 1; // Set GPIO26 to use GMUX option 1
GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 2; // Set MUX to 2 for SPICLKB function
GpioCtrlRegs.GPAQSEL2.bit.GPIO26 = 3;

// === Set GPIO directions ===
GpioCtrlRegs.GPADIR.bit.GPIO24 = 1; // MOSI: output
GpioCtrlRegs.GPADIR.bit.GPIO25 = 0; // MISO: input
GpioCtrlRegs.GPADIR.bit.GPIO26 = 1; // CLK: output

// === Enable internal pull-up resistors ===
GpioCtrlRegs.GPAPUD.bit.GPIO24 = 0; // Enable pull-up for MOSI
GpioCtrlRegs.GPAPUD.bit.GPIO25 = 0; // Enable pull-up for MISO
GpioCtrlRegs.GPAPUD.bit.GPIO26 = 0; // Enable pull-up for CLK

GpioCtrlRegs.GPBMUX1.bit.GPIO38 = 0; // Set GPIO38 to GPIO function
GpioCtrlRegs.GPBDIR.bit.GPIO38 = 1; // Set as output
GpioCtrlRegs.GPBPUD.bit.GPIO38 = 0; // Enable pull-up resistor
GpioDataRegs.GPBSET.bit.GPIO38 = 1; // Set HIGH initially (inactive)

EDIS;
}



void SPI_INIT()
{

EALLOW;
GpioDataRegs.GPBSET.bit.GPIO38 = 1; // nCS HIGH




CpuSysRegs.PCLKCR8.bit.SPI_B = 1;
SpibRegs.SPICCR.bit.SPISWRESET = 0; // Reset SPI
SpibRegs.SPICCR.bit.CLKPOLARITY = 0; // Clock polarity 0
SpibRegs.SPICTL.bit.CLK_PHASE = 0 ;
SpibRegs.SPICCR.bit.SPICHAR = 7; // 8-bit data
SpibRegs.SPICTL.bit.MASTER_SLAVE = 1; // Master mode
SpibRegs.SPICTL.bit.TALK = 1; // TX enable
SpibRegs.SPIBRR.bit.SPI_BIT_RATE = 21; // Baud Rate
SpibRegs.SPICCR.bit.SPISWRESET = 1; // Release SPI from reset

EDIS;

}

void EEPROM_WriteByte(Uint16 address, Uint8 data)
{
// Write Enable
GpioDataRegs.GPBCLEAR.bit.GPIO38 = 1; // nCS LOW
SPIB_SendByte(0x06); // Write Enable opcode
GpioDataRegs.GPBSET.bit.GPIO38 = 1; // nCS HIGH

// Write Command
SPI_Delay(); 
GpioDataRegs.GPBCLEAR.bit.GPIO38 = 1;

SPIB_SendByte(0x02); // WRITE opcode
SPIB_SendByte((address >> 8) & 0xFF); // Address High Byte
SPIB_SendByte(address & 0xFF); // Address Low Byte
SPIB_SendByte(data); // Data byte

GpioDataRegs.GPBSET.bit.GPIO38 = 1;

DELAY_US(5000); // Wait write cycle (max 5ms)
}

Uint8 EEPROM_ReadByte(Uint16 address)
{
Uint8 value;

GpioDataRegs.GPBCLEAR.bit.GPIO38 = 1;

SPIB_SendByte(0x03); // READ opcode
SPIB_SendByte((address >> 8) & 0xFF); // Address High Byte
SPIB_SendByte(address & 0xFF); // Address Low Byte
value = SPIB_SendByte(0x00); // Dummy write to receive data


DELAY_US(5);
GpioDataRegs.GPBSET.bit.GPIO38 = 1;

return value;
}

Uint16 SPIB_SendByte(Uint16 data)
{
while (SpibRegs.SPISTS.bit.BUFFULL_FLAG == 1); // Wait if TX buffer full
SpibRegs.SPITXBUF = data << 8;

while (SpibRegs.SPISTS.bit.INT_FLAG == 0); // Wait for RX
return SpibRegs.SPIRXBUF & 0x00FF;
}

void SPI_Delay(void)
{
asm(" RPT #50 || NOP"); 
}

在主环路中进行测试

void main(void)
{
    for(;;)
    {
        if(spi_write_test==1)
        {
            EEPROM_WriteByte(0x1234, 0xAA);
            spi_write_test=0;
        }

        if(spi_read_test==1)
        {
            EEPROM_ReadByte(0x1234);
            spi_read_test=0;
        }
    }
}

时钟频率--> 750kHz

写入序列

  

读取序列

(功能)

void SPI_GPIO_Init(void)
{
    EALLOW;

    // MOSI (Master Out, Slave In) -> GPIO24
    GpioCtrlRegs.GPAMUX2.bit.GPIO24 = 0; // Set as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO24 = 1;  // Configure as output

    // MISO (Master In, Slave Out) -> GPIO25
    GpioCtrlRegs.GPAMUX2.bit.GPIO25 = 0; // Set as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO25 = 0;  // Configure as input

    // CLK (Clock) -> GPIO26
    GpioCtrlRegs.GPAMUX2.bit.GPIO26 = 0; // Set as GPIO
    GpioCtrlRegs.GPADIR.bit.GPIO26 = 1;  // Configure as output

    // CS (Chip Select) -> GPIO38
    GpioCtrlRegs.GPBMUX1.bit.GPIO38 = 0; // Set as GPIO
    GpioCtrlRegs.GPBDIR.bit.GPIO38 = 1;  // Configure as output

    EDIS;
}


void SPI_Delay(void)
{
    asm(" RPT #50 || NOP"); // Short delay between clock transitions
}


void SPI_SendByte(uint8_t data)
{
    int i;

    for (i = 7; i >= 0; i--)
    {
        if ((data >> i) & 0x01)
            GpioDataRegs.GPASET.bit.GPIO24 = 1; // MOSI high
        else
            GpioDataRegs.GPACLEAR.bit.GPIO24 = 1; // MOSI low

        SPI_Delay();

        GpioDataRegs.GPASET.bit.GPIO26 = 1; // CLK high
        SPI_Delay();

        GpioDataRegs.GPACLEAR.bit.GPIO26 = 1; // CLK low
        SPI_Delay();
    }
}



uint8_t SPI_ReadByte(void)
{
    int i;
    uint8_t received = 0;

    for (i = 7; i >= 0; i--)
    {
        // Dummy 0 bit on MOSI
        GpioDataRegs.GPACLEAR.bit.GPIO24 = 1;

        SPI_Delay();

        GpioDataRegs.GPASET.bit.GPIO26 = 1; // CLK high
        SPI_Delay();

        // Sample MISO
        if (GpioDataRegs.GPADAT.bit.GPIO25)
            received |= (1 << i);

        GpioDataRegs.GPACLEAR.bit.GPIO26 = 1; // CLK low
        SPI_Delay();
    }

    return received;
}





void EEPROM_Write_0x1234_0x10(void)
{
    // Step 1: Send WREN command (Write Enable)
    GpioDataRegs.GPBCLEAR.bit.GPIO38 = 1; // CS low
    SPI_SendByte(0x06); // WREN command
    GpioDataRegs.GPBSET.bit.GPIO38 = 1;   // CS high
    SPI_Delay(); // Small delay if needed

    // Step 2: Send WRITE command + Address + Data
    GpioDataRegs.GPBCLEAR.bit.GPIO38 = 1; // CS low

    SPI_SendByte(0x02);   // WRITE command
    SPI_SendByte(0x12);   // Address MSB (0x12 for 0x1234)
    SPI_SendByte(0x34);   // Address LSB (0x34 for 0x1234)
    SPI_SendByte(0xAA);   // Data byte (0x10)

    GpioDataRegs.GPBSET.bit.GPIO38 = 1;   // CS high

    // Step 3: Wait for write cycle to complete (typical 5ms)
    DELAY_US(5000); // 5 milliseconds wait
}



uint8_t EEPROM_Read_0x1234(void)
{
    uint8_t read_data;

    GpioDataRegs.GPBCLEAR.bit.GPIO38 = 1; // CS low - start communication

    SPI_SendByte(0x03);   // READ command
    SPI_SendByte(0x12);   // Address MSB
    SPI_SendByte(0x40);   // Address LSB

    read_data = SPI_ReadByte(); // Read one byte

    GpioDataRegs.GPBSET.bit.GPIO38 = 1;   // CS high - end communication

    return read_data;
}

主环路

void main(void)
{
    for(;;)
    {
        if(spi_write_test==1)
        {
            EEPROM_Write_0x1234_0x10();
            spi_write_test=0;
        }

        if(spi_read_test==1)
        {
            EEPROM_Read_0x1234();
            spi_read_test=0;
        }
    }
}

写入  

读取

EEPROM 器件命令表

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好:

    抱歉、为了清晰起见、我有几个即时跟进问题。

    1. 所提供的代码是功能代码还是非功能代码?
    2. 功能代码与非功能代码有何不同?
    3. 使用非功能代码时、失败状态是什么? 即是否没有任何通信、是否是垃圾数据、格式错误等?

    此外、请注意、我们不建议在消息正文中发布大型代码块。 请尝试使用附件功能、否则、如果某个页面上的内容过多、我们会发现 e2e 过去遇到性能问题。

    此致、
    Jason Osborn

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的答复。
    首先、初始代码块中的行对应于我尝试与 EEPROM 器件通信但无法建立通信的那一刻。 第二个代码块表示我在调试模式下测试的结构。 我分享的最后一个代码块显示了版本中的行、在使用 SPI 模块的情况下、我能够与 EEPROM 器件成功通信。

    至于示波器捕获:

    • 前两个图像对应于失败的通信尝试、即它们反映了第一个代码块执行期间发生的情况。

    • 最后一组映像表示在不使用 SPI 模块的情况下与 EEPROM 器件成功建立通信的时刻。

    尝试 EEPROM 通信时、我首先发送0x06以发出"写入使能"命令。
    然后我发送0x02、表示随后将执行写入操作。
    该地址0x1234是我要写入的目标位置。 在第一个示例中、我尝试将值写入0xAA此地址;在第二个示例中、我尝试写入0x10

    对于读取、我发送0x03后跟目标地址、以指示读取操作。 因此,在一个示例中,我无法从地址读取任何数据0x1234,而在另一个示例中,我成功读回0x10

    我希望这一解释能澄清问题。
    此致、
    Omer Arslan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    再次大家好:

    在观察示波器波形后、我注意到时钟信号的上升几乎与数据同时发生。 由于 EEPROM 在时钟的上升沿使用样本数据、我怀疑在时钟略早推进数据可能会解决问题。

    为了进行测试、我移除了 MISO 和 MOSI 线路上的串联电阻器(将其设置为0Ω)、并将 CLK 线路上的串联电阻增加到200Ω。 通过这种配置、通信开始可靠地工作。

    现在、我的问题是:
    是否有办法在不修改硬件的情况下、使用 SPI 模块在 TMS320F28377S 上实现此相同的时序调整? 具体来说、我是否可以延迟时钟信号或通过寄存器设置推进数据输出?

    我担心、基于电阻器的延迟可能会在不同的温度条件(低温和高温环境)下导致问题、因此我更希望使用更稳健的基于软件或硬件支持的解决方案。

    此外、您能否建议 SPI 线路上的串联电阻和下拉电阻的理想值以确保信号完整性?

    谢谢!

    此致、
    Omer Arslan

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Omer

    查看 F28377S 器件 TRM 中的下表和图表:

    通过调整 SPI 配置的 CLKPOLARITY 和 CLK_PHASE 位、您可以调整时钟方案。 听起来您当前有方案[x、0]、而您想要[x、1]吗? 调整该值后应消除对任何外部电阻器延迟的需求。

    对于电阻器、有时建议在 CS 引脚上添加一个上拉电阻器(也称为 STE 或 PTE)、但一般来说、SPI 不需要外部上拉/下拉电阻器- C2000内部上拉通常就足够了。 如果您的应用噪声特别大、添加外部上拉电阻可能会有所帮助-我无法为您提供特定的值、因为这取决于您的应用的要求。

    此致、
    Jason Osborn