我有一个STM32L476RG的问题。我有两个相互关联的问题。我有一个可行的解决方案,我只是想知道它是如何工作的。
我有一个问题写数据到SPIx_DR寄存器。我的代码如下:
void SPI_SendData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint32_t Len)
{
while(Len > 0)
{
//1. wait until TXE is set
while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG) == FLAG_RESET);
//8 bit DS
//1. load the data in to the DR
*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer; //typecasting to uint8_t
Len--;
pTxBuffer++;
}
}
上面的代码是完美的工作。然而,我有问题,理解以下行:
*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer;
据我所知STM32L4系列不同于STM32F4系列。我有一个STM32F4工作代码,它是不同的:
pSPIx->DR = *pTxBuffer;
当我为STM32L4这样写时,无论如何它都会发送16位而不是8位。区别在于,SPIx_DR对写入它的数据的宽度很敏感。然而,我不知道如何理解它,并从参考手册(RM0351)阅读它。它是写在参考手册RM0351页1463(数据包装)?
我的问题是:
STM32L4对写入数据的宽度敏感,在哪里可以读到它(参考手册中的页面)是正确的吗?欢迎所有进一步的解释。我在参考手册里找不到。
这个问题是关于C语法的。如何理解以下转换(以SPI2为例):
*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer;
pSPIx->DR
= *(0x4000380C)
(SPI2_DR地址= 0x4000380C).
所以它应该等于:
*((volatile uint8_t *)0x4000380C) = *pTxBuffer;
如何理解第一部分*((volatile uint8_t *)0x4000380C)
?
希望有人能帮我澄清这个话题。谢谢你的宝贵时间。
编辑(添加逻辑分析仪图片使我的问题更清楚):
我试着再描述一遍我的问题。
当我使用STM32L476RG发送SPI数据时:
void SPI_SendData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint32_t Len)
{
while(Len > 0)
{
//1. wait until TXE is set
while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG) == FLAG_RESET);
//8 bit DS
//1. load the data in to the DR
*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer; //typecasting to uint8_t
Len--;
pTxBuffer++;
}
}
现在我发送"Hello World"为例。我一次发送8位。如你所见,*pTxBuffer被写成uint8_t。
输出如下(正确):
8 bits_1 8 bits_2现在当我使用这个函数发送SPI数据与STM32L476RG:
void SPI_SendData(SPI_RegDef_t *pSPIx, uint8_t *pTxBuffer, uint32_t Len)
{
while(Len > 0)
{
//1. wait until TXE is set
while(SPI_GetFlagStatus(pSPIx, SPI_TXE_FLAG) == FLAG_RESET);
//8 bit DS
//1. load the data in to the DR
pSPIx->DR = *pTxBuffer; //typecasting to uint8_t
Len--;
pTxBuffer++;
}
}
输出如下(错误):
16 bits_1 16 bits_2现在你可以看到区别了。问题是底层代码理论上应该可以工作。它在STM32F407上工作得很好。现在STM32F407和STM32L476在SPI方面有什么区别?我认为答案依赖于STM32L476参考手册RM0351页1463(数据打包)?
拆解
*((volatile uint8_t *)&pSPIx->DR) = *pTxBuffer;
为
uint8_t * temp1 = &pSPIx->DR;
然后 volatile uint8_t *temp2 = temp1;
然后 *temp2 = *pTxBuffer;
这些诡计的目的是强制执行写操作,它告诉编译器必须将该值写入指定的位置。编译器可以决定不这样做,例如,它已经在几行之前写了相同的值。'volatile'对编译器说——真的要写这个,因为它背后有特殊的硬件。
几乎和
一样 pSPIx->DR = *pTxBuffer;
但它没有'volatile'限定符,所以编译器可以选择不这样做(或移动顺序)