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.

[参考译文] LAUNCHXL-F28379D:相移 SPI CLK 信号以消除1us 到 lt 的延迟

Guru**** 2536270 points


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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/1249866/launchxl-f28379d-phase-shifting-spi-clk-signal-to-remove-delay-to-1us

器件型号:LAUNCHXL-F28379D

大家好、我希望找到一种方法来对 SPI CLK 信号进行相移而不产生中断、以消除 CS 信号的下降沿与第一个 CLK 脉冲的上升沿之间的延迟。 由于此延迟、我似乎将丢失前几位。 我附上了一张示波器图片、上面显示了我正在处理的项目中的延迟和代码。 该代码基于 C2000中的 TI SPI 环回外部 FIFO 中断示例。 但是、不会使用中断、并且会为三线 SPI 手动配置 GPIO。 器件是一款 RLS LA11D01_12绝对磁性编码器、配置为 SPI 从器件。 我认为, 在 SPIEncoderRead ()函数的 for 循环中的写线 引入了这种延迟,然而,开始与编码器通信需要这条线。 如果有人能提供帮助、请告诉我。

 

以下是从 spi_ex3_external_loopback_fifo_interrupts.c 中修改的代码(对于混乱和大型注释部分表示抱歉):

//##########################################################################出################################出
//
//文件:spi_ex3_external_loopback_fifo_interrupt.c
//
//标题:具有 FIFO 中断的 SPI 数字环回
//
//! \addtogroup driver_example_list
//!

具有 FIFO 中断的 SPI 数字外部环回


//!
//! 这个程序使用两个 SPI 模块间的外部回路。 两者皆可
//! 使用 SPI FIFO 及其中断。 SPIA 配置为从机
//! 并从配置为主器件的 SPI B 接收数据。
//!
//! 发送一个数据流、然后与接收到的数据流进行比较。
//! 发送的数据如下所示:\n
//! 0000 0001 \n
//! 0001 0002 \n
//! 0002 0003 \n
//! …… \n
//! FFFE FFFF \n
//! FFFF 0000 \n
//! 等等 \n
//! 这种模式会永久重复。
//!
//! /b 外部连接\n
//! -GPIO25和 GPIO17 - SPISOMI
//! -GPIO24和 GPIO16 - SPISIMO
//! GPIO27和 GPIO19 - SPISTE
//! -GPIO26和 GPIO18 - SPICLK
//!
//! \b 监视\b 变量\n
//! -\b sData -要发送的数据
//! -/b RDATA -接收的数据
//! -\b rDataPoint -用于跟踪接收中的最后位置
//! 使用数据流进行错误检查
//!
//
//##########################################################################出################################出
//
//$Release Date:$
//$Copyright:
//版权所有(C)2013-2023 Texas Instruments Incorporated - http://www.ti.com/
//
//以源代码和二进制形式重新分发和使用,无论有无
//修改,前提是满足以下条件
//已满足:
//
//重新分发源代码必须保留以上版权
//通知,此条件列表和下述免责声明。
//
//以二进制形式重新分发必须复制上述版权
//通知,此条件列表和以下免责声明(位于
///文件和/或其他材料
//分布。
//
// TI 公司名称或公司名称
//其贡献者可用于认可或推广派生的产品。
//未经事先书面许可从本软件获得。
//
//此软件由版权持有者和贡献者提供
//"按原样"和任何明示或暗示的保证、包括但不限于
//仅限于对适销性和适用性的暗示保证
//不考虑特定目的。 在任何情况下、版权均不得
//所有者或贡献者对任何直接、间接、偶然、
//特殊、示例或后果性损害(包括但不包括
//仅限于采购替代货物或服务;不能使用、
///数据或利润;或业务中断)
//责任理论,无论是在合同,严格的责任,或侵权
//(包括疏忽或其他)以任何方式产生的使用
//本软件,即使已被告知此类损坏的可能性。
//$
//##########################################################################出################################出

//
//包含的文件
//
#include "driverlib.h"
#include "device.h"
#include "GPIO.h"

//
//全局变量
//
volatile uint16_t sData[2];//发送数据缓冲区
volatile uint16_t rdata 缓存[2];//接收数据缓冲区
volatile uint16_t rDataPoint = 0;//以跟踪我们在
//通过数据流检查接收的数据
uint16_t SPIRX[2];
int32_t 编码返回;


//
//函数原型
//
void initSPIBMaster (void);
void initSPIASlave (void);
void configGPIO (void);
int32_t SPIEncoderRead (void);
__interrupt void spibTxFIFOISR (void);
__interrupt void spiaRxFIFOISR (void);

//
//主菜单
//
空 main (void)
{

//
//初始化设备时钟和外设
//
device_init();

//
//禁用引脚锁定并启用内部上拉。
//
device_initGPIO();

//
//初始化 PIE 和清除 PIE 寄存器。 禁用 CPU 中断。
//
interrupt_initModule();

//
//使用指向 shell 中断的指针初始化 PIE 矢量表
//服务例程(ISR)。
//
interrupt_initVectorTable();

//
//此示例中使用的中断重新映射到 ISR 函数
//此文件中找到。
//
// Interrupt_register (INT_SPIB_TX、&spibTxFIFOISR);
// Interrupt_register (INT_SPIA_RX、&spiaRxFIFOISR);

//
//将 GPIO 配置为外部环回。
//
configGPIOs();

//
//将 SPI B 设置为主器件,将其初始化为 FIFO 模式
//
//initSPIBMaster();

//
//将 SPI A 设置为从器件,并针对 FIFO 模式进行初始化
//
initSPIASlave();

////
//初始化数据缓冲区
////
// for (I = 0;I < 2;I++)
//{
// sData[i]= i;
// RDATA[I]= 0;
//}
//
////
////启用此示例所需的中断
////
// Interrupt_enable (INT_SPIA_RX);
// Interrupt_enable (INT_SPIB_TX);

//
//启用全局中断(INTM)和实时中断(DBGM)
//
//EINT;
//ERTM;

//
//永久循环。 暂停或放置断点以观察缓冲区。
//
while (1)
{
encoderReturn = SPIEncoderRead ();


int32_t SPI 编码器 Read (void)
{
int16_t ENCODER_LEDER = 0;
uint8_t i;


GPIO_writePin (19、0);
for (I=0;I<2;I++)
{
SPI_writeDataBlockingNonFIFO (SPIA_BASE、0);
SPIRX[i]= SPI_readDataBlockingNonFIFO (SPIA_BASE);

GPIO_writePin (19、1);


int32_t ENCODER_RELED_SCALLED =(SPIRX[0]<<12U)+(SPIRX[1]>2U);
ENCODER_RELEDER =-(int16_t)(ENCODER_RELED_SCALED);
返回 ENCODER_RELEDS;

//
//此函数在启用 FIFO 的情况下将 SPI B 配置为主器件。
//
//void initSPIBMaster (void)
//{
////
////在配置 SPI 之前必须将其置位
////
// SPI_disableModule (SPIB_BASE);
//
////
// SPI 配置。 使用500kHz SPICLK 和16位字大小。
////
// SPI_setConfig (SPIB_BASE、DEVICE_LSPCLK_FREQ、SPI_PROT_POL0PHA0、
// SPI_MODE_MASTER、500000、16);
// SPI_disableLoopback (SPIB_BASE);
// SPI_setEmulationMode (SPIB_BASE、SPI_emulation_free_run);
//
////
//// FIFO 和中断配置
////
// SPI_enableFIFO (SPIB_BASE);
// SPI_clearInterruptStatus (SPIB_BASE、SPI_INT_TXFF);
// SPI_setFIFOInterruptLevel (SPIB_BASE、SPI_FIFO_TX2、SPI_FIFO_RX2);
// SPI_enableInterrupt (SPIB_BASE、SPI_INT_TXFF);
//
////
////配置完成。 启用模块。
////
// SPI_enableModule (SPIB_BASE);
//}

//
//此函数可在启用 FIFO 的情况下将 SPI A 配置为从器件。
//
void initSPIASlave (void)
{


SPI_disableModule (SPIA_BASE);

SPI_setConfig (SPIA_BASE、DEVICE_LSPCLK_FREQ、SPI_PROT_POL0PHA0、SPI_MODE_MASTER、4000000 14);

SPI_disableLoopback (SPIA_BASE);
SPI_setEmulationMode (SPIA_BASE、SPI_emulation_free_run);
SPI_enableTriWire (SPIA_BASE);
SPI_enableModule (SPIA_BASE);

//
//将 GPIO 配置为外部环回。
//
void configGPIO (void)
{
//
//该测试是为 SPIA 与 CPU 之间的外部回送
//和 SPIB。
//外部连接:
//-GPIO25和 GPIO17 - SPISOMI
//-GPIO24和 GPIO16 - SPISIMO
//-GPIO27和 GPIO19 - SPISTE
//-GPIO26和 GPIO18 - SPICLK
//
//

// GPIO59是 SPISOMIA。

//

GPIO_setMasterCore (59、GPIO_CORE_CPU1);

GPIO_setPinConfig (GPIO_59_SPISOMIA);

GPIO_setPadConfig (59、GPIO_PIN_TYPE_PULLUP);

GPIO_setQualificationMode (59、GPIO_QUAL_ASYNC);

//

// GPIO58是 SPISIMOA 时钟引脚。

//

GPIO_setMasterCore (58、GPIO_CORE_CPU1);

GPIO_setPinConfig (GPIO_58_SPISIMOA);

GPIO_setPadConfig (58、GPIO_PIN_TYPE_PULLUP);

GPIO_setQualificationMode (58、GPIO_QUAL_ASYNC);

//

// GPIO19是 SPISTEA。

//


GPIO_setMasterCore (19、GPIO_CORE_CPU1);
GPIO_setPinConfig (GPIO_19_GPIO19);
GPIO_setPadConfig (19、GPIO_PIN_TYPE_PULLUP);
GPIO_setQualificationMode (19、GPIO_QUAL_ASYNC);
GPIO_setDirectionMode (19、GPIO_DIR_MODE_OUT);

//

// GPIO60是 SPICLKA。

//

GPIO_setMasterCore (60、GPIO_CORE_CPU1);

GPIO_setPinConfig (GPIO_60_SPICLKA);

GPIO_setPadConfig (60、GPIO_PIN_TYPE_PULLUP);

GPIO_setQualificationMode (60、GPIO_QUAL_ASYNC);

////
//
//// GPIO25是 SPISOMIB。
//
////
//
// GPIO_setMasterCore (64、GPIO_CORE_CPU1);
//
// GPIO_setPinConfig (GPIO_64_SPISOMIB);
//
// GPIO_setPadConfig (64、GPIO_PIN_TYPE_PULLUP);
//
// GPIO_setQualificationMode (64、GPIO_QUAL_ASYNC);
//
//
//
////
//
// GPIO24是 SPISIMOB 时钟引脚。
//
////
//
// GPIO_setMasterCore (63、GPIO_CORE_CPU1);
//
// GPIO_setPinConfig (GPIO_63_SPISIMOB);
//
// GPIO_setPadConfig (63、GPIO_PIN_TYPE_PULLUP);
//
// GPIO_setQualificationMode (63、GPIO_QUAL_ASYNC);
//
//
//
////
//
// GPIO27是 SPISTEB。
//
////
//
// GPIO_setMasterCore (27、GPIO_CORE_CPU1);
//
// GPIO_setPinConfig (GPIO_27_SPISTEB);
//
// GPIO_setPadConfig (27、GPIO_PIN_TYPE_PULLUP);
//
// GPIO_setQualificationMode (27、GPIO_QUAL_ASYNC);
//
//
//
////
//
// GPIO26是 SPICLKB。
//
////
//
// GPIO_setMasterCore (65、GPIO_CORE_CPU1);
//
// GPIO_setPinConfig (GPIO_65_SPICLKB);
//
// GPIO_setPadConfig (65、GPIO_PIN_TYPE_PULLUP);
//
// GPIO_setQualificationMode (65、GPIO_QUAL_ASYNC);
//
//}

////
// SPI A 发送 FIFO ISR
////
//_interrupt void spibTxFIFOISR (void)
//{
// uint16_t i;
//
////
//发送数据
////
// for (I = 0;I < 2;I++)
//{
// SPI_writeDataNonBlocking (SPIB_BASE、sData[i]);
//}
//
////
//递增下一周期的数据
////
// for (I = 0;I < 2;I++)
//{
// sData[i]= sData[i]+ 1;
//}
//
////
////清除中断标志并发出 ACK
////
// SPI_clearInterruptStatus (SPIB_BASE、SPI_INT_TXFF);
// Interrupt_clearACKGroup (interrupt_ACK_group6);
//}
//
////
// SPI B 接收 FIFO ISR
////
//_interrupt void spiaRxFIFOISR (void)
//{
// uint16_t i;
//
////
//读取数据
////
// for (I = 0;I < 2;I++)
//{
// RDATA[i]= SPI_readDataNonBlocking (SPIA_BASE);
//}
//
////
////检查接收的数据
////
// for (I = 0;I < 2;I++)
//{
// if (RDATA[i]!=(rDataPoint + I))
//{
////出错了。 RDATA 不包含预期数据。
// Example_Fail = 1;
// ESTOP0;
//}
//}
//
// rDataPoint++;
//
////
////清除中断标志并发出 ACK
////
// SPI_clearInterruptStatus (SPIA_BASE、SPI_INT_RXFF);
// Interrupt_clearACKGroup (interrupt_ACK_group6);
//
// Example_PassCount++;
//}

//
//文件结束
//

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

    你好,Jonah,

    Unknown 说:
    我正在寻找一种方法、以便在没有中断的情况下对 SPI CLK 信号进行相移、从而消除 CS 信号的下降沿和第一个 CLK 脉冲的上升沿之间的延迟。

    延迟是由于 CPU 用于切换 CS 引脚(通过 GPIO 写入)、因此 CPU 必须启动对 SPI TX 寄存器的写入。 有两个选项可供您浏览:

    1.优化  GPIO_writePin()函数。 它的源包含在 driverlib 中。 我在下面粘贴了以便参考。 您可以看到、这里有很多开销。 您可以编写自己的优化 内联函数来修复偏移 和掩码而不是计算偏移和掩码。 注意:这会有所改进、但不会消除 CS 和第一个 SPI_CLK 之间的延迟。

    static inline void
    GPIO_writePin(uint32_t pin, uint32_t outVal)
    {
        volatile uint32_t *gpioDataReg;
        uint32_t pinMask;
    
        //
        // Check the arguments.
        //
        ASSERT(GPIO_isPinValid(pin));
    
        gpioDataReg = (uint32_t *)((uintptr_t)GPIODATA_BASE) +
                      ((pin / 32U) * GPIO_DATA_REGS_STEP);
    
        pinMask = (uint32_t)1U << (pin % 32U);
    
        if(outVal == 0U)
        {
            gpioDataReg[GPIO_GPxCLEAR_INDEX] = pinMask;
        }
        else
        {
            gpioDataReg[GPIO_GPxSET_INDEX] = pinMask;
        }
    }

    下面您可以找到少量的 GPIO 编写优化代码、您可以将其用作参考。 您将需要根据自己的使用进行调整。

    #define BUCK_GPIO_PROFILING1_SET_REG        GPIO_O_GPASET
    #define BUCK_GPIO_PROFILING1_CLEAR_REG      GPIO_O_GPACLEAR
    #define BUCK_GPIO_PROFILING1_SET            GPIO_GPASET_GPIO13
    #define BUCK_GPIO_PROFILING1_CLEAR          GPIO_GPACLEAR_GPIO13
    
    #pragma FUNC_ALWAYS_INLINE(BUCK_HAL_setProfilingGPIO1)
    static inline void BUCK_HAL_setProfilingGPIO1(void)
    {
        #pragma diag_suppress = 770
        #pragma diag_suppress = 173
        HWREG(GPIODATA_BASE + BUCK_GPIO_PROFILING1_SET_REG) =
                                                  BUCK_GPIO_PROFILING1_SET;
        #pragma diag_warning = 770
        #pragma diag_warning = 173
    }
    
    #pragma FUNC_ALWAYS_INLINE(BUCK_HAL_resetProfilingGPIO1)
    static inline void BUCK_HAL_resetProfilingGPIO1(void)
    {
        #pragma diag_suppress = 770
        #pragma diag_suppress = 173
        HWREG(GPIODATA_BASE + BUCK_GPIO_PROFILING1_CLEAR_REG) =
                                                      BUCK_GPIO_PROFILING1_CLEAR;
        #pragma diag_warning = 770
        #pragma diag_warning = 173
    }

    2.您可以将该引脚配置为 SPI_STE,而不是使用 GPIO 控制 CS 引脚。 这将允许 SPI 直接驱动该引脚、从而实现 CS 和 SPI_CLK 之间的最小延迟。 您需要启用 SPI FIFO 模式并使 FIFO 充满数据、从而确保 SPI_STE 引脚在编码器需要时保持低电平。 因此、大多数人更喜欢使用 GPIO。

    祝你好运!


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

    谢谢您的建议! 我已经将 GPIO 引脚重新配置为 STE、它消除了延迟! 但是、它仅在每16位 clk 周期存储数据。 我当时想、我可以每28个时钟周期使用 FIFO 中断来拉低 CS 引脚。 不确定我会具体实施 FIFO 中断、因为当我尝试为 FIFO 使用 SPI 读取和写入时、没有与 SPI 从器件的通信。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我当时想我可以使用 FIFO 中断每28个时钟周期拉低 CS 引脚。 [/报价]

    在 FIFO 模式下、只要 FIFO 中有数据、SPI 就会使 STE 线路保持低电平。 如果您已将字符长度配置为16位、那么如果您向 FIFO 写入两个16位字符、STE 线路将在32个 SPI 时钟内保持低电平。 在第28个 SPI 时钟上无法控制 STE 引脚。  

    不确定我实施 FIFO 中断的具体程度

    您正在使用的示例代码应在 FIFO 模式下配置 SPI。 不过、看看您提供的代码、您似乎将该代码删除了吗?  

    [/quote]