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.

[参考译文] CCS/CC2640R2F:两个 CC2640 LaunchPad 之间的 SPI 通信

Guru**** 3003130 points

Other Parts Discussed in Thread: CC2640

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

https://e2e.ti.com/support/tools/code-composer-studio-group/ccs/f/code-composer-studio-forum/921396/ccs-cc2640r2f-spi-communication-between-two-cc2640-launchpads

器件型号:CC2640R2F
主题中讨论的其他器件:CC2640

工具/软件:Code Composer Studio

尊敬的 TI 支持团队

您好!

我的项目有问题、希望您能帮我解决。 我的项目是在一个 CC2640 Launchpad 和一个 C2000系列 Launchpad (例如 F28379d)之间的 SPI 的帮助下发送和接收数据。

遗憾的是、我是一名初学者、我正在做一些小步骤来学习如何使用微控制器。 为了达到最终目标、我从 spislave_CC2640R2_LAUNCHXL_tirtos_ccs 和 spimaster_CC2640R2_LAUNCHXL_tirtos_ccs 示例开始、在两个 CC2640微控制器之间进行通信、该示例运行得很好。 下一步是用两个简单的数字(该数字应在 ADC 值范围内、例如、我希望发送此对[3000、3001])替换字符串(从器件的 Hello、msg#:")。 第一个问题是如何以最小变化量修改代码?  (请向我展示我需要如何更改代码的哪一部分以及需要更改的代码。 我尝试自己更改它,但结果不是我所期望的,毕竟我是一个初学者)。

第二个问题是、在下一步中、如果我想在 CC2640和 F28379d 之间进行通信、是否可能由于 RTOS 和裸机之间的差异而面临问题?

这是原始示例代码。 如果您向我展示如何更改它、我们将不胜感激。

%%%%%%%%%%%%%%%%%%

SPI 主器件:  

%%%%%%%%%%%%%%%%%%

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

#define THREADSTACKSIZE (1024)

#define SPI_MSG_LENGTH (30)
#define MASTER_MSG ("Hello from master、msg#:")

#define MAX_LOOP (10)

静态 Display_Handle 显示;

unsigned char masterRxBuffer[SPI_MSG_LENG];
unsigned char masterTxBuffer[SPI_MSG_LENG];

//在从器件准备好传输之前阻止主器件的信号量*/
SEM_t masterSem;

/*
*=== slaveReadyFxn ===
* Board_SPI_SLAVE_READY 上 GPIO 中断的回调函数。
*/
void slaveReadyFxn (uint_least8_t index)
{
SEM_post (&masterSem);
}

/*
=== masterThread ======
*主器件 SPI 在向从器件发送消息的同时从
从器件接收*消息。
//
void * masterThread (void * arg0)
{
SPI_Handle 主 Spi;
SPI_Params Parspiams;
SPI_Transaction 事务;
uint32_t 一;
布尔 转让;
内部32_t 状态;

/*
* Board_SPI_MASTER_READY 和 Board_SPI_SLAVE_READY 是连接的 GPIO 引脚
主器件和从器件之间的*。 这些引脚用于同步
*通过一个小的"握手"来控制主器件和从器件应用。 引脚
*稍后用于同步传输并确保主设备不会
*开始传输、直至从设备就绪。 这些引脚的行为
*不同的 spimaster 和 spislave 示例:
*
* spimaster 示例:
* * Board_SPI_MASTER_READY 配置为输出引脚。 期间
* "握手"此引脚从低电平更改为高电平输出。 这种情况
* 通知从器件主器件已准备好运行应用程序。
* 之后、主器件使用该引脚通知从器件
* 已打开 Board_SPI_master。 当 BOARD_SPI_MASTER 打开时、即会执行此操作
* 引脚将被拉低。
*
* * Board_SPI_SLAVE_READY 配置为输入引脚。 期间
* "握手"读取此引脚、高电平值将指示从器件
* 已准备好运行应用程序。 然后、一个下降沿中断
* 将在该引脚上配置。 当从设备准备好执行时
* 传输、它会将该引脚拉低。
*
*下面我们设置 Board_SPI_MASTER_READY 和 Board_SPI_SLAVE_READY 初始值
*"握手"的条件。
*
GPIO_setConfig (Board_SPI_MASTER_READY、GPIO_CFG_OUTPUT | GPIO_CFG_OUT_LOW);
GPIO_setConfig (Board_SPI_SLAVE_READY、GPIO_CFG_INPUT);

/*
*握手-将 Board_SPI_MASTER_READY 设置为高电平以指示主器件已就绪
*以运行。 等待 Board_SPI_SLAVE_READY 变为高电平。
*
GPIO_WRITE (Board_SPI_MASTER_READY、1);
while (GPIO_Read (Board_SPI_SLAVE_READY)= 0){}

//握手完成;现在在 Board_SPI_SLAVE_READY 上配置中断*/
GPIO_setConfig (Board_SPI_SLAVE_READY、GPIO_CFG_IN_pu | GPIO_CFG_IN_INT_INT_FALLING);
GPIO_setCallback (Board_SPI_SLAVE_READY、slaveReadyFxn);
GPIO_enableInt (Board_SPI_SLAVE_READY);

/*
*创建同步信标;主器件将在此信标上等待
*直到从设备就绪。
*
状态= SEM_INIT (&masterSem、0、0);
if (status!= 0){
display_printf (display、0、0、"创建 masterSem\n"error creating masterSem\n");

while (1);
}

/*将 SPI 作为主器件打开(默认)*/
SPI_Params_init (&spiParams);
spiParams.frameFormat = SPI_POL0_PHA1;
spiParams.bitrate = 4000000;
masterSpi = SPI_open (Board_SPI_master、&spiParams);
if (masterSpi == NULL){
Display_printf (display、0、0、"初始化主器件 SPI\n"时出错);
while (1);
}
否则{
display_printf (display、0、0、"Master SPI initialized");
}

/*
*主器件已打开 Board_SPI_MASTER;将 Board_SPI_MASTER_READY 设置为高电平
*通知从属方。
*
GPIO_WRITE (Board_SPI_MASTER_READY、0);

/*将消息复制到发送缓冲区*/
strncpy ((char *) masterTxBuffer、master_MSG、SPI_MSG_LENGTH);

对于(I = 0;I < MAX_LOOP;I++){
/*
*等待从器件准备好传输;从器件将拉取
* Board_SPI_SLAVE_READY 低电平。
*
SEM_WAIT (masterSem);

/*初始化主 SPI 事务结构*/
masterTxBuffer[sizeof (master_MSG)- 1]=(i % 10)+'0';
memset ((void *) masterRxBuffer、0、SPI_MSG_LENGTH);
transaction.count = SPI_MSG_length;
transaction.txBuf =(void *) masterTxBuffer;
transaction.rxBuf =(void *) masterRxBuffer;

/*切换用户 LED、指示正在进行 SPI 传输*/
GPIO_TOGGLE (Board_GPIO_LED1);

/*执行 SPI 传输*/
transferOK = SPI_transfer (masterSpi、事务);
if (transferOK){
Display_printf (display、0、0、"主设备已接收:%s"、masterRxBuffer);
}
否则{
display_printf (display、0、0、"主 SPI 传输失败");
}

/*在开始下一个 SPI 传输前睡眠一位*/
睡眠(3);
}

SPI_CLOSE (masterSpi);

/*示例完成-将引脚设置为已知状态*/
GPIO_DisableInt (Board_SPI_SLAVE_READY);
GPIO_setConfig (Board_SPI_SLAVE_READY、GPIO_CFG_OUTPUT | GPIO_CFG_OUT_LOW);
GPIO_WRITE (Board_SPI_MASTER_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、masterThread、NULL);
如果(retc!= 0){
/* pthread_create()失败*/
while (1);
}

返回(NULL);
}

%%%%%%%%%%%%%%%%%%

SPI 从器件:  

%%%%%%%%%%%%%%%%%%

#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);
}

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

    masterTxBuffer 是一个字符数组、这意味着如果您需要将 ADC 值放入 TX 缓冲区、则需要将 ADC 值转换为 char 并将其插入缓冲区。 这是 C 字符串操作。

    只要您在两侧使用相同的 SPI 模式、芯片运行裸机或操作系统等无关紧要   

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

    感谢您的回答。 还有一个问题。 当我运行示例时、当微控制器连接到 USB 时、它不会开始传输数据。 我必须先刷写它、然后断开并重新连接它以开始传输。 此问题是否与握手有关? 如何纠正它? 我想在表达式窗口中观察传输的值。 这就是我需要保持连接的原因。

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

    为了使代码在刷写器件后启动、器件必须接收复位信号。