提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
随着电机控制领域的不断发展,通讯方式也越来越重要,选择合适的通讯方式对获取电机实时的电机参数有着重要的意义,而我们今天介绍的SPI通讯是电机与as5047p编码器之间进行数据传输的关键。
一、SPI通讯原理
SPI是串行外设接口(Serial Peripheral Interface)的缩写,是一种高速、全双工、同步通信总线,所以可以在同一时间发送和接收数据,SPI没有定义速度限制,通常能达到甚至超过10M/bps。
SPI有主、从两种模式,通常由一个主模块和一个或多个从模块组成(SPI不支持多主机),今天我们介绍的是单主机从机通讯即TC275芯片作为主机与从机as5047p编码器之间进行数据交换,如图所示。

SPI通信至少需要四根线,它们是MISO(主设备数据输入)、MOSI(主设备)、SCLK(时钟)、和CS/SS(片选):
- MISO(Master Input Slave Output):主设备数据输入,从设备数据输出;
- MOSI(Master Output Slave Input):主设备数据输出,从设备数据输入;
- SCLK(Serial Clock):时钟信号,由主设备产生;
- CS/SS(Chip Select/Slave Select):从设备使能信号,由主设备控制,一主多从时,CS/SS是从芯片是否被主芯片选中的控制信号,只有片选信号为预先规定的使能信号时(高低位或低电位),主芯片对此从芯片的操作才有效。

这里简单介绍了SPI通信基本的工作原理,如果想要深入了解SPI通讯可以参考下面这篇文章:深入了解SPI通讯
二、相关代码配置
先在英飞凌的IDE中导入有关SPI通信的代码,这里我以TC275芯片为例导入SPI通信例程,如图所示:

主要在引脚,时钟参数,数据交换代码这三方面来介绍代码的配置方式。
1.引脚及片选相关配置
代码如下:
#define CSPin &MODULE_P33,10
void initQSPI3Master(void)
{
IfxQspi_SpiMaster_Config spiMasterConfig; /* Define a Master configuration */
// IfxQspi_SpiMaster_initModuleConfig(&spiMasterConfig, QSPI1_MASTER); /* Initialize it with default values */
IfxQspi_SpiMaster_initModuleConfig(&spiMasterConfig, QSPI3_MASTER);
spiMasterConfig.base.mode = SpiIf_Mode_master; /* Configure the mode */
/* Select the port pins for communication */
const IfxQspi_SpiMaster_Pins qspi3MasterPins = {
// &IfxQspi1_SCLK_P10_2_OUT, IfxPort_OutputMode_pushPull, /* SCLK Pin (CLK) */
// &IfxQspi1_MTSR_P10_3_OUT, IfxPort_OutputMode_pushPull, /* MasterTransmitSlaveReceive pin (MOSI) */
// &IfxQspi1_MRSTA_P10_1_IN, IfxPort_InputMode_pullDown, /* MasterReceiveSlaveTransmit pin (MISO) */
&IfxQspi3_SCLK_P33_11_OUT, IfxPort_OutputMode_pushPull, /* SCLK Pin (CLK) */
&IfxQspi3_MTSR_P33_12_OUT, IfxPort_OutputMode_pushPull, /* MasterTransmitSlaveReceive pin (MOSI) */
&IfxQspi3_MRSTD_P33_13_IN, IfxPort_InputMode_pullDown, /* MasterReceiveSlaveTransmit pin (MISO) */
IfxPort_PadDriver_cmosAutomotiveSpeed3 /* Pad driver mode */
};
spiMasterConfig.pins = &qspi3MasterPins; /* Assign the Master's port pins */
/* Set the ISR priorities and the service provider */
spiMasterConfig.base.txPriority = ISR_PRIORITY_MASTER_TX;
spiMasterConfig.base.rxPriority = ISR_PRIORITY_MASTER_RX;
spiMasterConfig.base.erPriority = ISR_PRIORITY_MASTER_ER;
spiMasterConfig.base.isrProvider = IfxSrc_Tos_cpu0;
/* Initialize the QSPI Master module */
IfxQspi_SpiMaster_initModule(&g_qspi.spiMaster, &spiMasterConfig);
}
这里按照自己所需配置SPI的四根引脚,MISO,MOSI,SCLK以及CS,其中尤其要注意的是需要自己配置片选的引脚:#define CSPin &MODULE_P33,10.
2.时钟参数的配置
代码如下:
void initQSPI3MasterChannel(void)
{
IfxQspi_SpiMaster_ChannelConfig spiMasterChannelConfig; /* Define a Master Channel configuration */
/* Initialize the configuration with default values */
IfxQspi_SpiMaster_initChannelConfig(&spiMasterChannelConfig, &g_qspi.spiMaster);
spiMasterChannelConfig.base.baudrate = MASTER_CHANNEL_BAUDRATE; /* Set SCLK frequency to 1 MHz */
spiMasterChannelConfig.base.mode.dataHeading = SpiIf_DataHeading_msbFirst;
spiMasterChannelConfig.base.mode.dataWidth = 16;
spiMasterChannelConfig.base.mode.shiftClock = 1;// 相位
spiMasterChannelConfig.base.mode.clockPolarity = 0; //极性
spiMasterChannelConfig.base.mode.autoCS=0;
/* Select the port pin for the Chip Select signal */
const IfxQspi_SpiMaster_Output qspi3SlaveSelect = { /* QSPI1 Master selects the QSPI3 Slave */
// &IfxQspi1_SLSO9_P10_5_OUT, IfxPort_OutputMode_pushPull, /* Slave Select port pin (CS) */
&IfxQspi3_SLSO11_P33_10_OUT, IfxPort_OutputMode_pushPull,
IfxPort_PadDriver_cmosAutomotiveSpeed1 /* Pad driver mode */
};
spiMasterChannelConfig.sls.output = qspi3SlaveSelect;
/* Initialize the QSPI Master channel */
IfxQspi_SpiMaster_initChannel(&g_qspi.spiMasterChannel, &spiMasterChannelConfig);
}
- 根据as5147p芯片手册,设置时钟极性为0,即时钟空闲的默认状态为低电平,设置时钟相位为1,即在时钟信号SCK的第二个跳变沿采样,所以数据采样时机是在一个波形下降沿如图所示。
- 如图所示,需要发送16bits的数据,因此设置数据大小为16位,同时由于数据传输顺序为最高位优先,因此设置
dataHeading为SpiIf_DataHeading_msbFirst。 - 如下图所示,由于需要满足特殊的时序要求,因此令
autoCS=0,选择软件手动控制片选信号,在后面的发送函数会有代码实现。 - SPI通讯频率可以需求设置,受限于每个系统能提供多大的系统时钟频率,以及最大的SPI传输速率,这里的波特率我设置为800KHZ。

3.数据交换
void transferData(void)
{
IfxPort_setPinModeOutput(CSPin, IfxPort_OutputMode_pushPull, IfxPort_OutputIdx_general);
IfxPort_setPinLow(CSPin);
uint32 ticks = IfxStm_getTicksFromMilliseconds(&MODULE_STM0, 10);
IfxStm_waitTicks(&MODULE_STM0, ticks);
g_qspi.spiBuffers.spiMasterTxBuffer[0] = 0xFFFF;
//g_qspi.spiBuffers.spiMasterTxBuffer[1] = 0xFF;
// for(int i = 0; i < 1; i++)
{
while(IfxQspi_SpiMaster_getStatus(&g_qspi.spiMasterChannel) == SpiIf_Status_busy);
IfxQspi_SpiMaster_exchange(&g_qspi.spiMasterChannel, &g_qspi.spiBuffers.spiMasterTxBuffer[0], &g_qspi.spiBuffers.spiSlaveRxBuffer[0], 1);
while(IfxQspi_SpiMaster_getStatus(&g_qspi.spiMasterChannel) == SpiIf_Status_busy);
}
IfxPort_setPinModeOutput(CSPin, IfxPort_OutputMode_pushPull, IfxPort_OutputIdx_general);
IfxPort_setPinHigh(CSPin);
//
// ticks = IfxStm_getTicksFromMilliseconds(&MODULE_STM0, 10);
// IfxStm_waitTicks(&MODULE_STM0, ticks);
}
这里我通过SPI通信对as5047p编码器发送0xFFFF获取电机绝对位置信息(有时间我会更一篇关于as5047p编码器SPI通信获取位置的文章),这里和例程不一样的是:
- 在发送信息前后都手动拉高和拉低了片选信号,拉低数据开始传输,拉高数据传输结束;
- 第一个Busy状态,等待SPI通道准备好,第二个Busy状态,等待数据传输完成;
- 同时自己修改了发送数组
spiBuffers.spiSlaveRxBuffer[0],从8位修改为16位,以及下面这个交换函数:
IfxQspi_SpiMaster_exchange(&g_qspi.spiMasterChannel, &g_qspi.spiBuffers.spiMasterTxBuffer[0], &g_qspi.spiBuffers.spiSlaveRxBuffer[0], 1);
g_qspi.spiBuffers.spiMasterTxBuffer[0]指向发送缓冲区的指针,表示要发送的数据的起始地址,g_qspi.spiBuffers.spiSlaveRxBuffer[0]是一个指向接收缓冲区的指针,表示存储接收到的数据的位置,1表示发送Buffer数组个数。
最终成功实现了SPI通讯获取了电机位置(这些都是自己查资料和不断调试最终试出来的,都是泪啊),大家如果发现SPI通信未通,可以尝试一下我这种方式。下面看看我出来的波形吧,蓝色为时钟信号,绿色为MOSI信号:

总结
TC275芯片的SPI配置无非就是一些引脚配置,以及与SPI相关的特定参数配置例如片选,时钟参数等,其中最关键就是要读懂芯片提供的例程中SPI通信实现的逻辑,这个是最重要的,引脚等配置是提供了一个好的平台,而如何使用则在于你对一些函数API的调用。

1076

被折叠的 条评论
为什么被折叠?



