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.

[参考译文] RTOS/CC3200:使用 TI-RTOS SPI/DMA 时、是否可以缩短 SPI 传输之间的时间?

Guru**** 2551760 points
Other Parts Discussed in Thread: CC3200

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

https://e2e.ti.com/support/wireless-connectivity/wi-fi-group/wifi/f/wi-fi-forum/615236/rtos-cc3200-is-it-possible-to-reduce-time-between-spi-transfers-when-using-ti-rtos-spi-dma

器件型号:CC3200

工具/软件:TI-RTOS

我将 TI-RTOS 与 SPI/DMA 驱动程序配合使用、以便与外部器件进行通信。  我已经设置了一个计时器来启动重复性 SPI_TRANSF()。  SPI 传输之间的最短时间似乎约为40微秒(传输约为35微秒)。  无论我将计时器周期设置为多低、都有一个最小的 SPI 重新传输周期。

1)是否有更快速地重新发送的好方法(即减少40微秒)?

2) 2)或者、使用 TI-RTOS 时、是否可以实现 SPI DMA Ping Pong 传输?

谢谢、

Alex

以下测试代码:

/* XDCtools 头文件*/
#include 
#include 
#include 

/* BIOS 头文件*/
#include 
#include 

/* TI-RTOS 头文件*/
#include 
#include 

/*示例/板头文件*/
#include "Board.h"

#define BUFSIZE32

SPI_Transaction spiTransaction spiTransaction;
SPI_HandleSPI;
SPI_ParamsspiParams;
uint16_t transmitBuffer[BUFSIZE];
uint16_t receiveBuffer[BUFSIZE];



空 UserCallbackFxn (SPI_Handle SPI、SPI_Transaction * spiTransaction)
{
无符号静态 int callback_cnt=0;
Log_Info1 ("Callback #%u"、callback_cnt);
}



int main (void)
{
/*呼叫板初始化函数*/
Board_initGeneral();
Board_initSPI();

SPI_Params_init (&spiParams);
spiParams.transferMode = SPI_MODE_CALLACK;
spiParams.transferCallbackFxn =用户 CallbackFxn;
spiParams.bitrate = 20000000;
spiParams.dataSize = 16;
SPI = SPI_OPEN (Board_SPI0、&spiParams);
spiTransaction.count = 32;
spiTransaction.txBuf = transmitBuffer;
receivTransaction.rxBuf = spieBuffer;

/*启动 BIOS */
BIOS_start();

返回(0);
}



void sample_period_timer_fxn (void)
{
spi_transfer (SPI、&spiTransaction);
//Log_info0 ("SPI transfer started");
} 

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

    尊敬的 Alex:

    您可以将 TI-RTOS 与 SPI 乒乓功能结合使用、并将 其与您在此处先前文章中编写的代码结合使用。 您不必使用 TI-RTOS 中提供的 SPI 驱动程序 API。 您只需包含适当的 SPI driverlib 头文件、并使用直接 driverlib 调用来执行 SPI 传输。  

    TI-RTOS SPI API (通常用于 TI-RTOS 外设 API 的 TI 驱动程序)只是一个抽象层、实现了与您已经编写的代码相同的功能。 但是、这些 SPI 驱动器存在一些限制、对于为 CC3200构建的 TI 驱动程序版本尤其明显。 您可能已经注意到、TI 驱动程序 API 可能的最大传输大小为1024字。 此外,它不支持 DMA 交替缓冲,这意味着由于驱动程序必须关闭 SPI 接口,重新打开 SPI 接口,然后为每个 SPI_TRANSFERT()调用再次设置 DMA 传输,因此将有一个最小的 SPI 非活动周期。

    虽然确实可以修改 SPI 驱动程序以支持 DMA 交替缓冲、因为我已经对 CC3220 SPI 驱动程序进行了个人修改以支持它、 将之前的工作复制到支持 TI-RTOS 的新项目中、比尝试处理和修改 CC3200 SPI 驱动程序要简单得多。

    如果您仍想将更抽象的 TI 驱动程序用于 SPI 传输、请告诉我、我将为您提供一些有关修改 CC3200 SPI 驱动程序的更具体的指导。

    此致、

    Michael

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

    Michael、

    感谢您的解释、我现在对此有更深入的了解。  实际上、昨天我尝试将 TI-RTOS 代码与低级 driverlib 代码合并、但遇到了一个问题。  当我合并代码以使用 TI-RTOS 运行 SPI 交替时、SPI 函数将不再运行、但我的计时器函数将不再运行。  我想使用计时器重新启用 SPI DMA 传输、使其以设置的频率运行。  该计时器在 RTOS cfg 脚本中设置、无需 SPI 代码即可工作。

    以下是我的测试代码:

    谢谢、

    Alex

    /* XDCtools 头文件*/
    #include 
    #include 
    #include 
    
    /* BIOS 头文件*/
    #include 
    #include 
    
    /* TI-RTOS 头文件*//#include
    
    //#include 
    
    /*示例/板头文件*/
    #include "Board.h"
    
    /* Driverlib 头文件*/
    #include "hw_types.h"
    #include "hw_memmap.h"
    #include "hw_mcspi.h"
    #include "spi.h"
    #include "Udma.h"
    #include "prcm.h"
    #include "rom_bong/fp
    
    
    
    
    缓冲区大小为每个缓冲区定义一个缓冲区。
    unsigned long g_ulg_usRxBufACount = 0;
    unsigned long g_ulg_usRxBufBCount = 0;
    unsigned long g_ulTxCount = 0;
    
    uint16_t g_usTxBuf[BUF_SIZE];
    uint16_t g_usRxBufA[BUF_SIZE];
    
    
    
    
    
    void t Uint16_t UxBuxF_Size]
    ;t Uint_Uint_UxBuxF_size;t Uint_Uint_UxBuxF[unt UxF_Is]
    unsigned long ulStatus;
    无符号超长整型;
    
    //
    //读取 SPI 的中断状态。
    //
    ulStatus = MAP_SPIIntStatus (GSPI_BASE、1);
    LOG_Info1 ("SPI 状态%x"、ulStatus);
    
    //
    //清除任何暂挂的 SPI 状态中断。
    //
    MAP_SPIIntClear (GSPI_base、ulStatus);
    
    
    //
    //检查 DMA 控制表以查看乒乓"A"传输是否为
    //完成。 "A"传输使用接收缓冲器"A"和主缓冲器
    //控制结构。
    //
    ulMode = MAP_uDMAChannelModeGet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
    
    //
    //如果主控制结构体指示停止,则表示"A"
    //接收缓冲完成。 UDMA 控制器仍应接收
    //将数据输入"B"缓冲区。
    //
    if (ulMode = UDMA_MODE_STOP)
    {
    //
    //递增计数器以指示数据已被接收到缓冲区 A 中
    //
    G_ulg_usRxBufACount++;
    
    //
    //使用主缓冲区为"A"缓冲区设置下一个传输
    //控制结构。 进入"B"缓冲器的持续接收为时
    //完成,UDMA 控制器将切换回这个。
    //
    //为 Rx bufA 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH6_GSPI_RX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_MODE_Pingpong、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufA、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
    }
    
    //
    //检查 DMA 控制表以查看乒乓"B"传输是否为
    //完成。 "B"传输使用接收缓冲器"B"和副缓冲器
    //控制结构。
    //
    ulMode = MAP_uDMAChannelModeGet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
    
    //
    //如果副控制结构体指示停止,则表示"B"
    //接收缓冲完成。 UDMA 控制器仍应接收
    //将数据输入到"A"缓冲区中。
    //
    if (ulMode = UDMA_MODE_STOP)
    {
    //
    //递增计数器以指示数据已被接收到缓冲区 A 中
    //
    G_ulg_usRxBufBCount++;
    
    //
    //使用替代设置"B"缓冲区的下一个传输
    //控制结构。 接收到"A"缓冲器的时间
    //完成,UDMA 控制器将切换回这个。
    //
    //为 Rx bufB 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH6_GSPI_RX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufB、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
    }
    
    //
    //如果禁用 SPI DMA TX 通道,则表示 TX DMA 传输
    //完成。
    //
    if (!map_uDMAChannelIsEnabled (UDMA_CH7_GSPI_TX))
    {
    G_ulTxCount++;
    //
    //开始另一个到 SPI TX 的 DMA 传输。
    //
    MAP_uDMAChannelControlSet (UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH7_GSPI_TX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT、UDMA_MODE_BASIC、g_usTxBuf、(void *)(GSPI_base + MCSPI_O_TX0)、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT);
    
    }
    
    log_info2 ("a =%u、B =%u"、g_ulg_usRxBufACount、g_ulg_usRxBufBCount);
    }
    
    
    
    
    
    int main (void)
    {
    Board_initGeneral();
    
    MAP_PRCMPeripheralClkEnable (PRCM_GSPI、PRCM_RUN_MODE_CLK);
    MAP_PRCMPeripheralReset (PRCM_GSPI);
    MAP_SPIReset (GSPI_base);
    Board_initSPI();
    UDMAInit();
    
    MAP_SPIConfigSetExpClk (GSPI_base、MAP_PRCMPeripheralClockGet (PRCM_GSPI)、
    20000000、SPI_MODE_MASTER、SPI_SUB_MODE_0、
    (SPI_HW_CTRL_CS |
    SPI_4PIN_MODE |
    SPI_Turbo_off |
    SPI_CS_ACTIVELOW |
    SPI_WL_16));
    
    MAP_SPIIntRegister (GSPI_base、SPIIntHandler);
    
    MAP_SPIFIFOLVELSet (GSPI_BASE、1、1);
    MAP_SPIFOEnable (GSPI_base、SPI_RX_FIFO | SPI_TX_FIFO);
    
    MAP_SPIDmaEnable (GSPI_base、SPI_RX_DMA);
    MAP_SPIDmaEnable (GSPI_base、SPI_TX_DMA);
    MAP_SPIIntEnable (GSPI_base、SPI_INT_DMATX | SPI_INT_DMARX);
    
    MAP_uDMAChannelAssign (UDMA_CH6_GSPI_RX);
    MAP_uDMAChannelAssign (UDMA_CH7_GSPI_TX);
    
    //为 Rx bufA 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH6_GSPI_RX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_MODE_Pingpong、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufA、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
    
    //为 Rx bufB 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH6_GSPI_RX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufB、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
    
    MAP_SPIEnable (GSPI_BASE);
    
    /*启动 BIOS */
    BIOS_start();
    
    返回(0);
    }
    
    
    
    void sample_period_timer_fxn (void)
    {
    Log_info0 ("要在此启动 SPI 传输");
    }
    

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

    添加更多信息。  如果我注释掉"MAP_SPIEnable (GSPI_base);"、则计时器会再次工作、因此它与 SPI 活动直接相关。

    我还添加了一个心跳任务函数(来自 TI-RTOS "empty"示例)、该函数使 LED 闪烁、以验证它不仅是计时器、而且在启用 SPI 时也不起作用。

    有什么想法或最佳调试途径?

    谢谢、

    Alex

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

    我不确定您在这里的用例是什么。 如何在配置脚本中设置计时器? 是否可以改用硬件计时器? 此外、使用计时器的目的是什么? 您是否尝试对相同的值执行重复 SPI 传输、但两者之间等待一小会? 或者、您是否正在尝试获得连续设置、以便无需等待即可发送相同的32个字?

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

    您好、Michael、

    我正在致力于一个系统、该系统能够以可选的固定周期连续对模数转换器进行采样。 最大采样率受限于20MHz 的 SPI 总线最大速度、因此我尝试尽可能快地接收数据、同时保持固定的采样周期。 我还想使用 TI-RTOS、这是因为操作系统为系统的其余处理提供了额外的功能。

    定时器的目的是保持一个可选的固定采样频率。 要回答您的问题、是的、传输过程是重复的、需要等待很短的时间才能保持固定的可选频率。 除了更改 A/D 寄存器设置时、对 A/D 转换器数据的请求总是相同的、这种情况很少见。 我可以使用硬件计时器、但决定使用 TI-RTOS 计时器、因为它易于设置。

    感谢您的帮助!

    Alex

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

    尊敬的 Alex:

    我会尝试使用硬件计时器、看看它是否有用。

    下面是一些代码、您可以使用这些代码来设置中断和执行 ISR 的硬件计时器:

    /*确保所有定时器中断被禁用、并且定时器被停止*/
    MAP_TimerIntDisable (TIMERERA1_BASE、TIMER_CAPB_EVENT|TIMER_CAPB_MATCH | TIMER_TIMB_TIMEOUT|TIMER_CAPA_EVENT|TIMER_CAPA_MATTIMA_TIMEOUT);
    MAP_TimerDisable (TIMERERA1_BASE、TIMER_M两者);
    MAP_TimerIntClear (TIMERERA1_BASE、TIMER_CAPB_EVENT|TIMER_CAPB_MATC|TIMER_TIMB_TIMEOUT|TIMER_CAPA_EVENT|TIMER_CAPA_MATC|TIMER_TIMA_TIMEOUT);
    /*确定计时器设置*/
    uint32_t timerPeriod =(800000/samplpleRate)- 1;
    
    
    /*确保定时器停止并被清除*/
    MAP_TimerValueSet (TIMERERA1_BASE、TIMER_A、0xFFFF);
    
    /*将定时器从周期减至0 */
    MAP_TimerConfigure (TIMERERA1_BASE、0x4000002);
    MAP_TimerLoadSet (TIMERERA1_BASE、TIMER_A、timerPeriod);
    MAP_TimerIntRegister (TIMERERA1_BASE、TIMER_A、TA1_0_ISR);
    MAP_TimerEnable (TIMERERA1_BASE、TIMER_A);
    MAP_TimerIntEnable (TIMERERA1_BASE、TIMER_TINA_TIMEOUT); 

        

    void TA1_0_ISR (void){
    /*获取中断状态并清除*/
    int_fast16_t ta1iv;
    无符号超长整型 ulSample;
    ta1iv = map_TimerIntStatus (TIMERRA1_base、1);
    MAP_TimerIntClear (TIMERERA1_BASE、TA1iv);
    /*如果计时器已达到0*/
    if (ta1iv=timer_TINA_TIMEOUT){
    /*从 ADC 读取当前值*/
    ulSample = MAP_ADCFIFORead (ADC_base、ADC_CH_3)
    
    }
    } 

    此致、

    Michael

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

    我在代码中添加了硬件计时器。  我在计时器 ISR 中重新启用 DMA Tx。  尽管存在一些意外行为、但这确实起作用。  DMA 传输的平均输出速率为正确的速率、但 DMA 传输之间的时间非常不一致、有时甚至在最后一次传输后立即发送。  我本来希望这些传输几乎完全按照计时器中断速率发生。  整体操作是可以接受的、但意外行为有点令人担忧。  有什么想法为什么会发生这种情况?  定时器优先级与 DMA?

    仍然存在一个问题、添加 SPI 和计时器代码后、RTOS 任务(LED 心跳)不再运行。  我在论坛上看到过将 driverlib 代码添加到 TI-RTOS 代码时需要注意的参考资料。  这是否是任务未运行的原因?

    谢谢、

    Alex

    下面的测试代码:

    /* XDCtools 头文件*/
    #include 
    #include 
    #include 
    
    /* BIOS 头文件*/
    #include 
    #include 
    
    /* TI-RTOS 头文件*//#include
    
    //#include 
    #include 
    
    /*示例/板头文件*/
    #include "Board.h"
    
    /* Driverlib 头文件*/
    #include "hw_types.h"
    #include "hw_memmap.h"
    #include "hw_mcspi.h"
    #include "spi.h"
    #include "Udma.h"
    #include "prcm.h"
    #include "task_stackns"
    
    
    #define #task_stackn_stackn.tsp?#define #define #task_timer #tasktask.stack_timer #define #define #tasktasktask.stackn_timer #define #define #task.stackn_timers #taskt
    
    
    
    
    
    timer #task.stack_timer #task.stack_
    unsigned long g_ulg_usRxBufACount = 0;
    unsigned long g_ulg_usRxBufBCount = 0;
    unsigned long g_ulTxCount = 0;
    
    uint16_t g_usTxBuf[BUF_SIZE];
    uint16_t g_usRxBufA[BUF_SIZE];
    UintxBuxF_0
    
    
    ;UintxBuxF_VIT_Uintn_size;uintxBu UARg arg1)
    {
    while (1){
    Task_sleep ((UINT) arg0);
    GPIO_TOGGLE (Board_LED);
    }
    }
    
    
    void SPIIntHandler (void)
    {
    unsigned long ulStatus;
    无符号超长整型;
    
    //
    //读取 SPI 的中断状态。
    //
    ulStatus = MAP_SPIIntStatus (GSPI_BASE、1);
    //Log_Info1 ("SPI 状态%x"、ulStatus);
    
    //
    //清除任何暂挂的 SPI 状态中断。
    //
    MAP_SPIIntClear (GSPI_base、ulStatus);
    
    
    //
    //检查 DMA 控制表以查看乒乓"A"传输是否为
    //完成。 "A"传输使用接收缓冲器"A"和主缓冲器
    //控制结构。
    //
    ulMode = MAP_uDMAChannelModeGet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
    
    //
    //如果主控制结构体指示停止,则表示"A"
    //接收缓冲完成。 UDMA 控制器仍应接收
    //将数据输入"B"缓冲区。
    //
    if (ulMode = UDMA_MODE_STOP)
    {
    //
    //递增计数器以指示数据已被接收到缓冲区 A 中
    //
    G_ulg_usRxBufACount++;
    log_info0 ("SPI Rx A");
    //
    //使用主缓冲区为"A"缓冲区设置下一个传输
    //控制结构。 进入"B"缓冲器的持续接收为时
    //完成,UDMA 控制器将切换回这个。
    //
    //为 Rx bufA 设置 uDMA
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_MODE_Pingpong、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufA、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
    }
    
    //
    //检查 DMA 控制表以查看乒乓"B"传输是否为
    //完成。 "B"传输使用接收缓冲器"B"和副缓冲器
    //控制结构。
    //
    ulMode = MAP_uDMAChannelModeGet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
    
    //
    //如果副控制结构体指示停止,则表示"B"
    //接收缓冲完成。 UDMA 控制器仍应接收
    //将数据输入到"A"缓冲区中。
    //
    if (ulMode = UDMA_MODE_STOP)
    {
    //
    //递增计数器以指示数据已被接收到缓冲区 A 中
    //
    G_ulg_usRxBufBCount++;
    LOG_info0 ("SPI Rx B");
    //
    //使用替代设置"B"缓冲区的下一个传输
    //控制结构。 接收到"A"缓冲器的时间
    //完成,UDMA 控制器将切换回这个。
    //
    //为 Rx bufB 设置 uDMA
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufB、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
    }
    
    
    }
    
    
    
    void TA1_0_ISR (void){
    //Log_info0 ("计时器 ISR");
    /*获取中断状态并清除*/
    int_fast16_t ta1iv;
    unsigned int ulStatus;
    
    无符号超长整型 ulSample;
    ta1iv = map_TimerIntStatus (TIMERRA1_base、1);
    MAP_TimerIntClear (TIMERERA1_BASE、TA1iv);
    /*如果计时器已达到0*/
    if (ta1iv=timer_TINA_TIMEOUT){
    MAP_uDMAChannelTransferSet (UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT、UDMA_MODE_BASIC、g_usTxBuf、(void *)(GSPI_base + MCSPI_O_TX0)、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT);
    log_info0 ("SPI Tx");
    }
    }
    
    
    
    int main (void)
    {
    Task_Params taskParams;
    
    
    unsigned int uIdx;
    for (uIdx = 0;uIdx < BUF_SIZE;uIdx++)
    {
    G_usTxBuf[uIdx]= uIdx;
    }
    
    /*呼叫板初始化函数*/
    Board_initGeneral();
    Board_initGPIO();
    
    /*构造心跳任务线程*/
    Task_Params_init (&taskParams);
    taskParams.arg0 = 1000;
    taskParams.STACKSIZE = TASKSTACKSIZE;
    taskParams.stack =_task0Stack;
    Task_construct(&task0Struct,(Task_FuncPtr)心跳 BeatFxn、&taskParams、NULL);
    
    MAP_PRCMPeripheralClkEnable (PRCM_TIMERA1、PRCM_RUN_MODE_CLK);
    MAP_PRCMPeripheralReset (PRCM_TIMERA1);
    
    /*确保所有定时器中断被禁用、并且定时器被停止*/
    MAP_TimerIntDisable (TIMERERA1_BASE、TIMER_CAPB_EVENT|TIMER_CAPB_MATCH | TIMER_TIMB_TIMEOUT|TIMER_CAPA_EVENT|TIMER_CAPA_MATTIMA_TIMEOUT);
    MAP_TimerDisable (TIMERERA1_BASE、TIMER_M两者);
    MAP_TimerIntClear (TIMERERA1_BASE、TIMER_CAPB_EVENT|TIMER_CAPB_MATC|TIMER_TIMB_TIMEOUT|TIMER_CAPA_EVENT|TIMER_CAPA_MATC|TIMER_TIMA_TIMEOUT);
    /*确定计时器设置*/
    uint32_t timerPeriod =(80000000/26000)- 1;
    
    /*确保定时器停止并被清除*/
    TimerValueSet (TIMERERA1_BASE、TIMER_A、0xFFFF);
    
    /*将定时器从周期减至0 */
    MAP_TimerConfigure (TIMERERA1_BASE、0x4000002);
    MAP_TimerLoadSet (TIMERERA1_BASE、TIMER_A、timerPeriod);
    MAP_TimerIntRegister (TIMERERA1_BASE、TIMER_A、TA1_0_ISR);
    MAP_TimerEnable (TIMERERA1_BASE、TIMER_A);
    MAP_TimerIntEnable (TIMERERA1_BASE、TIMER_TINA_TIMEOUT);
    
    
    MAP_PRCMPeripheralClkEnable (PRCM_GSPI、PRCM_RUN_MODE_CLK);
    MAP_PRCMPeripheralReset (PRCM_GSPI);
    
    MAP_SPIReset (GSPI_base);
    Board_initSPI();
    
    UDMAInit();
    
    MAP_SPIConfigSetExpClk (GSPI_base、MAP_PRCMPeripheralClockGet (PRCM_GSPI)、
    20000000、SPI_MODE_MASTER、SPI_SUB_MODE_0、
    (SPI_HW_CTRL_CS |
    SPI_4PIN_MODE |
    SPI_Turbo_off |
    SPI_CS_ACTIVELOW |
    SPI_WL_16));
    
    MAP_SPIIntRegister (GSPI_base、SPIIntHandler);
    
    MAP_SPIFIFOLevelSet (GSPI_base、1、1);
    MAP_SPIFOEnable (GSPI_base、 SPI_RX_FIFO | SPI_TX_FIFO);
    
    MAP_SPIDmaEnable (GSPI_base、SPI_RX_DMA);
    MAP_SPIDmaEnable (GSPI_base、SPI_TX_DMA);
    MAP_SPIIntEnable (GSPI_base、SPI_INT_DMATX | SPI_INT_DMARX);
    
    MAP_uDMAChannelAssign (UDMA_CH6_GSPI_RX);
    MAP_uDMAChannelAssign (UDMA_CH7_GSPI_TX);
    // MAP_uDMAChannelAssign (UDMA1_UCH1);
    
    //为 Rx bufA 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH6_GSPI_RX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT、UDMA_MODE_Pingpong、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufA、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_PRI_SELECT);
    
    //为 Rx bufB 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_NONE | UDMA_DST_INC_16 | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH6_GSPI_RX、UDMA_ATTR_USEBURST);
    MAP_uDMAChannelTransferSet (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT、UDMA_MODE_PINGONG、(void *)(GSPI_base + MCSPI_O_RX0)、G_usRxBufB、BUF_SIZE);
    MAP_uDMAChannelEnable (UDMA_CH6_GSPI_RX | UDMA_ALT_SELECT);
    
    //为 Tx 设置 uDMA
    MAP_uDMAChannelControlSet (UDMA_CH7_GSPI_TX | UDMA_PRI_SELECT、UDMA_SIZE_16 | UDMA_SRC_INC_16 | UDMA_DST_INC_NONE | UDMA_ARB_1);
    MAP_uDMAChannelAttributeEnable (UDMA_CH7_GSPI_TX、UDMA_ATTR_USEBURST);
    MAP_SPIEnable (GSPI_BASE);
    
    /*启动 BIOS */
    BIOS_start();
    
    返回(0);
    }
    

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

    在某些情况下、driverlib 和 TI 驱动程序可能相互冲突。 这种情况最常见于 GPIO、而使用 SPI 时的几率要小得多、而使用计时器时几乎没有。 发生冲突的原因是 TI 驱动程序执行的设置和初始化。 使用 GPIO_init(),除了通常使用 driverlib GPIO API 设置的一些其他选项外,TI 驱动程序还会执行通常必须在 pinmux.c 中执行的所有设置。 但是对于 SPI,只要您不使用任何 TI 驱动程序 SPI API 调用,就不会遇到任何问题,因为 TI 驱动程序中的所有 SPI 设置都是通过 SPI_Open ()完成的。 借助这些计时器、TI CC3200驱动程序构建中没有计时器模块 API、因此没有任何冲突。

    关于 BeatBeatFxn()没有执行,原因很可能是它被抢先了。 也就是说,还有一些其他优先级更高的任务正在运行,而不是运行 BEBEBEBEBEARFxn()。 假设您没有在 CC3200上运行其他任务、因为设置 DMA 后似乎您的主任务返回、这意味着您的中断将占用您的所有处理器周期。 硬件中断的优先级高于所有任务。

    计时器中断每3076个周期只会触发一次、因此不会占用您的所有处理器时间。 我想知道您的 SPI 中断处理程序是否持续触发、从而导致了问题。 尝试在 ISR 中输入一些 GPIO 切换(例如切换 LED)、并查看它们的触发频率以及使用逻辑分析仪执行它们所需的时间。 此外,由于中断处理程序只处理 RX DMA,因此请尝试只使用 SPIIntEnable()启用 SPI_INT_DMARX 中断。

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

    我根据您的建议添加了一些诊断:

    我禁用了 SPI_INT_DMATX 中断(当然,谢谢),并将 Log_Info1()状态放入我的 ISR 中,以便从 SPIIntStatus()输出中断状态。 结果表明、每个超时/DMA SPI Tx ISR 正在运行两次。 通过 ISR 的两次都由 SPI_INT_DMARX 触发。 第一次执行该操作时不会清除中断(I log 前和后清除)。 第二次清除中断、同时 Rx DMA 模式为 UDMA_MODE_STOP、指示交替模式下的 Rx 缓冲器完成。

    为什么我获得两个 SPI_INT_DMARX 中断? 此外、当我请求清除时、为什么不能第一次清除?

    我显著降低了计时器的速度(低至10kHz)、并且能够看到检测信号任务在 LED 输出上运行。 由于我的 SPI 正在通过 DMA 传输运行、除非我将其降低至10kHz、否则为什么没有剩余的任务周期?

    感谢您的帮助!

    谢谢、
    Alex

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

    也就是说、虽然 DMA 显著降低了 SPI 传输的处理器开销、但并不能完全消除它。 您仍然需要花费处理器时间执行 ISR 并重新加载 DMA 传输。 此外、将上下文切换到 ISR 并执行其中的各种函数也需要时间。

    我不确定您为什么会一目了然地获得两个 SPI_INT_DMARX 中断。 我必须更深入地考虑它。

    再想一想、您的 SPI 外设是如何工作的? 在我看来、您只是从 g_usTXbuf 发送一些虚拟数据(您可能应该顺便将其初始化为某个值)、同时读取33个字节的数据。 这是为了测试 SPI 接口、还是不必向器件发送某些命令?

    在这种情况下、只需修改所使用的 SPI 时钟、以便发送33字节所需的时间等于所需的采样周期。 您将无法选择任何任意 SPI 时钟/采样率、因为 SPI 时钟来自具有简单整数分频器的40MHz 晶体。 但是、如果使用这种方法、您将能够使用1024字 DMA 传输、从而消除了由于处理器开销而导致的重新加载 DMA 传输的任何问题。

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

    我使用的 SPI 外设是一个多通道 A/D 转换器。 我需要重复发送每个通道的请求。 我在这里列出的代码针对测试/优化 SPI 性能进行了简化。 我的完整应用代码具有缓冲器初始化等

    感谢您的建议。 修改 SPI 时钟以匹配采样速率并延长 DMA 传输时间的想法是非常好的。 我尝试了一下、但您正是 SPI 时钟的整数分频器。 在给定 SPI 速率时钟选项的情况下、很难匹配时序并保持无磁采样率。 我还探讨了一个高速率计时器中断、用于直接写入/读取 SPI Tx/Rx 寄存器。

    我得出的结论是、在以全总线速率为 SPI (TX 和 Rx)提供服务时、整个通信负载和 UDMA 使用大量/关键的 CPU 周期。 我想我将从另一个角度来解决这个问题、因为我无法获得所需的性能。

    感谢你的所有帮助。

    谢谢、
    Alex