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.

[参考译文] CC2650:回调模式下的 CC2650 SPI DMA

Guru**** 2553420 points


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

https://e2e.ti.com/support/wireless-connectivity/bluetooth-group/bluetooth/f/bluetooth-forum/836319/cc2650-cc2650-spi-dma-in-callback-mode

器件型号:CC2650

你好  

TI 是否有在回调模式下使用 SPI DMA 的任何示例?  

下面是我的问题的说明-

我必须依次检测两个 ADC 引脚并将数据存储到板载闪存中。 为此、我了解必须打开 ADC 通道->读取并存储在闪存中->关闭通道->打开新通道并重复该过程。 以下命令示例  

ADC = ADC_open (Board_ADCBufChannel0、&params);

RES = ADC_convert (ADC、&adcValue1[1]);

ExtFlash_write (flash_addr+ 2*i、2、(uint8_t*)&adcValue1[1]);

ADC_Close (ADC);

遗憾 的是,ADC 通道的打开和关闭以及闪存写入需要很长时间,我只能获得5kHz 的采样频率。 我意识到闪存写入在阻断模式下使用 SPI DMA。 我将其更改为回调模式、输入回调函数、但无法使代码顺利执行... 主要是因为我的固件体验有限:)  

这里有几个问题。  

我的算法高于完成任务的最佳方法。 我应该将一个块的 ADC 数据从两个通道保存到 RAM、然后从 RAM 传输到闪存。 但是、即使这样、在 CPU 继续读取 ADC 通道时、也需要在回调模式下由 SPI DMA 处理 RAM 到闪存的传输。  

是否有 SPI DMA 的示例是回调模式、这将帮助我入门。  

谢谢

Raghu

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

    您好!

    1 -我不知道您的应用程序的所有限制、因此很难为您提供一个好的答案。 是的、写入闪存会占用时间、但它还可以防止您在意外重启时丢失数据。 因此、必须在限制之间找到平衡点、并做出最佳决策。

    2-您可以查看 SDK 中提供的示例。

    此致、

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

    嗯... 好的。 我的任何问题都没有得到真正的回答:)。 我想我可以尝试更具体一些。 那么、这里开始了

    1.当前 ADC 通道的打开和关闭是否是移动到下一个通道的唯一方式? 是否有方法一次性打开两个 ADC 通道并从两个通道依次获取 ADC 读数?

    2.我查看了 SDK 中的示例、然后才发布了问题。 我在 SPI 中找到的任何示例都使用阻塞模式。  因此、我希望 TI 的某个人已经知道、因为我认为收集数据并将其存储在闪存中是一个非常常见的用例。 也许我错过了一些东西、因为有这么多示例。

    谢谢

    Raghu

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

    您好!

    1-您描述的对多个 ADC 通道进行采样的解决方案不是唯一的解决方案。 此问题通常在我们的论坛上提出:例如、在 https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/486753https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/794816。

    2-示例 spislave (在 examples\rtos\中) \drivers\spislave)在回调模式下使用 SPI。 此外、您还可以在论坛上找到与此问题相关的一些主题:[edit:link updated] https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/683421

    此致、

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

    您好 Clement

    1.感谢您提供链接。 我将处理这些问题。

    2.我不确定此路径的位置 examples\rtos\ \drivers\spislave。  

    这是在我的 BLE SDK 目录还是 tirtos_cc13xx_cc26xx_2_21_01_08目录中? 在任何安装中、我都没有名为 RTOS 的文件夹。  

    第3个链接似乎已断开。 单击时出现访问被拒绝错误。  

    https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/68342。 

    另外,我想我可以更改一个 spislave 示例,将其转换为 spamaster 示例吗?  

    谢谢

    Raghu

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

    您好!

    我在给您的链接中犯了一个错误。 很抱歉。 正确的链接如下: https://e2e.ti.com/support/wireless-connectivity/bluetooth/f/538/t/683421 (我已更新我之前的消息)

    如果需要,您可以在 TI 云上找到 spislave 示例: http://dev.ti.com/tirex/explore/node?node=AEyFXH-qFUs4SoXlGQpF.w__krol.2c__LATEST 。 我还粘贴了下面的 spisave.c 文件。 当然、您可以修改示例以获得主模式。

    我希望这将有所帮助、

    此致、

    /*
    版权所有(c) 2018-2019、德州仪器(TI)公司
    *保留所有权利。
    *
    *
    只要
    符合以下条件*、允许以源代码和二进制形式重新分发和使用:
    *
    **源代码的重新分发必须保留上述版权
    * 声明、此条件列表和以下免责声明。
    *
    ***二进制形式的再发行必须复制上述版权
    * 请注意
    、*中的此条件列表和以下免责声明 分发时提供的文档和/或其他材料。
    *
    **德州仪器公司的名称和
    *的名称均不相同 其贡献者可用于认可或推广衍生产品
    * 未经特定的事先书面许可。
    *
    *本软件由版权所有者和贡献者"按原样"提供
    *、
    
    不承担任何明示或暗示的保证、包括但不限于*适销性和特定用途适用性的暗示保证*。 在任何情况下、版权所有者或
    *贡献者都不对任何直接、间接、偶然、特殊、
    *模范、 或相应的损害(包括但不限于
    *采购替代产品或服务;丧失使用、数据或利润;
    *或业务中断)、但出于任何责任理论
    、*无论是在合同中、严格责任还是由于
    使用本软件而以任何方式产生的侵权行为(包括疏忽或*其他)
    、*即使已获悉可能会发生此类损坏。
    //
    
    /*
    === spislave.c =====
    */
    #include 
    #include 
    #include 
    
    /* POSIX 头文件*/
    #include 
    #include 
    #include 
    
    /*驱动程序头文件*/
    #include 
    #include 
    #include 
    
    /*示例/板头文件*/
    #include "Board.h"
    
    #define THREADSTACKSIZE (1024)
    
    #define SPI_MSG_LENGTH (30)
    #define SLAVE_MSG ("Hello from slave、msg#:")
    
    #define MAX_LOOP (10)
    
    静态 Display_Handle 显示;
    
    unsigned char slaveRxBuffer[SPI_MSG_length];
    unsigned char slaveTxBuffer[SPI_MSG_length];
    
    //在传输完成前阻止从站的信号量*/sem_t
    slaveSem;
    
    /*
    *=== transferCompleteFxn ===
    * SPI_TRANSFCTION ()的回调函数。
    //
    void transferCompleteFxn (SPI_Handle handle、SPI_Transaction *事务)
    {
    SEM_post (&slaveSem);
    }
    
    /*
    === slaveThread ====
    *从器件 SPI 在同时接收
    来自主器件的*消息的同时向主器件发送消息。
    //
    void * slaveThread (void * arg0)
    {
    SPI_Handle slaveSpi;
    SPI_Params Parspiams;
    SPI_Transaction 事务;
    uint32_t 一;
    布尔 转让;
    内部32_t 状态;
    
    /*
    * Board_SPI_MASTER_READY 和 Board_SPI_SLAVE_READY 是连接的 GPIO 引脚
    主器件和从器件之间的*。 这些引脚用于同步
    *通过一个小的"握手"来控制主器件和从器件应用。 引脚
    *稍后用于同步传输并确保主设备不会
    *开始传输、直至从设备就绪。 这些引脚的行为
    *不同的 spimaster 和 spislave 示例:
    *
    * spislave 示例:
    * * Board_SPI_MASTER_READY 配置为输入引脚。 期间
    * "握手"读取此引脚、高电平值将指示
    * 主设备已准备好运行应用程序。 之后、引脚为
    * 读取以确定主器件是否已打开其 SPI 引脚。
    * 当主器件打开其 SPI 时、它将把这个引脚拉低。
    *
    * * Board_SPI_SLAVE_READY 配置为输出引脚。 期间
    * "握手"此引脚从低电平更改为高电平输出。 这种情况
    * 通知主器件从器件已准备好运行应用程序。
    * 之后、从器件使用该引脚向主器件发出通知
    * 已准备好进行传输。 当准备好进行传输时、该引脚将会
    * 下拉至低电平。
    *
    *下面我们设置 Board_SPI_MASTER_READY 和 Board_SPI_SLAVE_READY 初始值
    *"握手"的条件。
    *
    GPIO_setConfig (Board_SPI_SLAVE_READY、GPIO_CFG_OUTPUT | GPIO_CFG_OUT_LOW);
    GPIO_setConfig (Board_SPI_MASTER_READY、GPIO_CFG_INPUT);
    
    /*
    *握手-将 Board_SPI_SLAVE_READY 设置为高电平以指示从器件就绪
    *以运行。 等待 Board_SPI_MASTER_READY 变为高电平。
    *
    GPIO_WRITE (Board_SPI_SLAVE_READY、1);
    while (GPIO_Read (Board_SPI_MASTER_READY)=0){}
    
    /*
    *创建同步信标;该信标将阻止从器件
    *直到传输完成。 从机配置为回调模式
    *以便我们配置 SPI 传输、然后通知主器件
    *从设备已准备就绪。 但是、我们仍然必须等待电流传输
    *在设置下一个之前完成。 因此、我们等待 slaveSem;
    *一旦传输完成、回调函数将解除阻止
    *从属设备。
    *
    状态= SEM_INIT (&slaveSem、0、0);
    if (status!= 0){
    display_printf (display、0、0、"创建 slaveSem\n"error creating slaveSem\n");
    
    while (1);
    }
    
    /*
    *等待主器件 SPI 打开。 配置 SPI 引脚时、将会发生这种情况
    *时钟可以从低电平切换到高电平(或从高电平切换到低电平、具体取决于
    *极性)。 如果使用3引脚 SPI 且从器件在之前已打开
    *假设主器件、时钟转换可能会导致从器件移出位
    *这是一个实际的传输。 我们可以通过打开来防止这种行为
    *首先主设备,然后打开从设备。
    *
    while (GPIO_Read (Board_SPI_MASTER_READY)){}
    
    /*
    *在回调模式下以从器件身份打开 SPI;回调模式用于允许我们这样做
    *配置传输、然后将 Board_SPI_SLAVE_READY 设置为高电平。
    *
    SPI_Params_init (&spiParams);
    spiParams.frameFormat = SPI_POL0_PHA1;
    spiParams.mode = SPI_SLAVE;
    spiParams.transferCallbackFxn = transferCompleteFxn;
    spiParams.transferMode = SPI_MODE_CALLACK;
    slaveSpi = SPI_open (Board_SPI_slave、&spiParams);
    if (slaveSpi == NULL){
    Display_printf (display、0、0、"初始化从器件 SPI\n"时出错);
    while (1);
    }
    否则{
    display_printf (display、0、0、"已初始化从属 SPI \n");
    }
    
    /*将消息复制到发送缓冲区*/
    strncpy ((char *) slaveTxBuffer、SLAVE_MSG、SPI_MSG_LENGTH);
    
    对于(I = 0;I < MAX_LOOP;I++){
    /*初始化从属 SPI 事务结构*/
    slaveTxBuffer[sizeof (slave_MSG)- 1]=(I % 10)+'0';
    memset ((void *) slaveRxBuffer、0、SPI_MSG_LENGTH);
    transaction.count = SPI_MSG_length;
    transaction.txBuf =(void *) slaveTxBuffer;
    transaction.rxBuf =(void *) slaveRxBuffer;
    
    /*打开用户 LED 指示灯,指示正在进行 SPI 传输*/
    GPIO_TOGGLE (Board_GPIO_LED1);
    
    /*
    *设置 SPI 传输;Board_SPI_SLAVE_READY 将设置为通知
    *主设备从设备就绪。
    *
    transferOK = SPI_transfer (slaveSpi、事务);
    if (transferOK){
    GPIO_WRITE (Board_SPI_SLAVE_READY、0);
    
    /*等待传输完成*/
    SEM_WAIT (slaveSem);
    
    /*
    *驱动 Board_SPI_SLAVE_READY 高电平以指示从器件未就绪
    *用于另一个传输。
    *
    GPIO_WRITE (Board_SPI_SLAVE_READY、1);
    
    
    display_printf (display、0、0、"从机接收到:%s"、slaveRxBuffer);
    }
    否则{
    display_printf (display、0、0、"从器件 SPI 传输失败");
    }
    }
    
    SPI_Close (slaveSpi);
    
    /*示例完成-将引脚设置为已知状态*/
    GPIO_setConfig (Board_SPI_MASTER_READY、GPIO_CFG_OUTPUT | GPIO_CFG_OUT_LOW);
    GPIO_WRITE (Board_SPI_SLAVE_READY、0);
    
    display_printf (display、0、0、"\nDone");
    
    返回(NULL);
    }
    
    /*
    ==== mainThread ====
    //
    void * mainThread (void * arg0)
    {
    pthread_t 线程0;
    pthread_attr_t attrs;
    struct sched_param primParam;
    内部 REC;
    内部 detachState;
    
    /*调用驱动程序初始化函数。 *
    display_init();
    GPIO_init();
    spi_init();
    
    /*配置 LED 引脚*/
    GPIO_setConfig (Board_GPIO_LED0、GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    GPIO_setConfig (Board_GPIO_LED1、GPIO_CFG_OUT_STD | GPIO_CFG_OUT_LOW);
    
    /*打开输出的显示屏*/
    Display = Display_open (Display_Type_UART、NULL);
    if (display =NULL){
    /*无法打开显示驱动程序*/
    while (1);
    }
    
    /*打开用户 LED */
    GPIO_WRITE (Board_GPIO_LED0、Board_GPIO_LED_ON);
    
    display_printf (display、0、0、"启动 SPI 从设备示例");
    display_printf (display、0、0、"此示例要求外部电线为"
    "已连接至接头引脚。 有关详细信息、请参阅 Board.html。\n");
    
    /*创建应用程序线程*/
    pthread_attr_init (atttrs);
    
    detachState = pthread_create_detached;
    /*设置优先级和堆栈大小属性*/
    retc = pthread_attr_setdetachstate (&attrs、detachState);
    如果(retc!= 0){
    /* pthread_attr_setdetachstate()失败*/
    while (1);
    }
    
    retc |= pthread_attr_setstacksize (&attrs、THREADSTACKSIZE);
    如果(retc!= 0){
    /* pthread_attr_setstacksize()失败*/
    while (1);
    }
    
    /*创建从线程*/
    priParam.sched_priority = 1;
    pthread_attr_setschedparam (&attrs、&priParam);
    
    retc = pthread_create (&thread0、&attrs、slaveThread、NULL);
    如果(retc!= 0){
    /* pthread_create()失败*/
    while (1);
    }
    
    返回(NULL);
    }
    

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

    您好 Clement。

    感谢您的回复和链接。 这对我来说是很好的尝试。 如果弹出任何其他内容、我将打开一个新线程。 现在、我感谢您的所有帮助。  

    Raghu