试图弄清楚这个#define

时间:2019-04-16 13:52:48

标签: c sample stm32f4 stm32f7

我正在尝试将适用于stm32fxxx的16位音频记录器应用程序调整为24位,但我偶然发现了#define,这使我感到困惑。

我已经将16位DMA更改为32位DMA,并将某些缓冲区uint16_t更改为uint32_t等。不知道为什么uint32_t并没有签名int,但我稍后会介绍。无法通过DMA传递24位,因此我将发送32位并在以后丢弃一个字节。

HAL_SAI_Transmit_DMA()的第三个输入实际上期望在uint16_t中有一个大小值。

#define AUDIO_OUT_BUFFER_SIZE       16384 
#define AUDIODATA_SIZE 2
#define DMA_MAX_SZE    0xFFFF
#define DMA_MAX(x)  (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE)

uint8_t BSP_AUDIO_OUT_Play(uint16_t* pBuffer, uint16_t Size)
{
    // send audio samples over DMA from buffer to audio port 
    HAL_SAI_Transmit_DMA(&haudio_out_sai, (uint8_t*) pBuffer, 
        DMA_MAX(AUDIO_OUT_BUFFER_SIZE / AUDIODATA_SIZE));

    return AUDIO_OK;
}

我猜我需要更改为

AUDIODATA_SIZE 4
#define DMA_MAX_SZE    0xFFFFFFFF // 32bit

但是我想知道#define DMA_MAX(x) (((x) <= DMA_MAX_SZE)? (x):DMA_MAX_SZE)应该做什么,甚至如何工作!它几乎写成好像它是一个函数吗?其中x是IO值?

AUDIODATA_SIZE是每个样本中的字节数:

我很抱歉成为C语言的初学者,但是我从未见过这样的事情,只能假定它掩盖了缓冲区的大小。但为什么?

pBuffer是指向传递到函数中的uint16_t*指针的指针,并根据需要将其(uint8_t*)pBuffer强制转换为HAL_SAI_Transmit_DMA。 我也从未见过这样的指针强制转换,但是它可以正常工作。

2 个答案:

答案 0 :(得分:2)

  

我想知道这个定义应该在做什么以及它是如何工作的!它几乎写成好像它是一个函数吗?其中x是IO值?

我认为您是在询问DMA_MAX宏。是的,它的编写几乎就像是一个函数一样,并且在概念上也有点像。这就是为什么将这样的宏称为“函数式宏”。另一种是“类似对象的宏”。

类似函数的宏仍然是宏。它的外观将替换为给定的替换文本,并且其任何参数的标识符内的所有外观都将被(完全宏扩展的)宏参数所替代,但在这里我将忽略一些例外。因此,这...

DMA_MAX(BufferSize / AUDIODATA_SIZE)

...扩展为:

(((BufferSize / AUDIODATA_SIZE) <= DMA_MAX_SZE)? (BufferSize / AUDIODATA_SIZE):DMA_MAX_SZE)

它使用三元运算符求和BufferSize / AUDIODATA_SIZEDMA_MAX_SZE中的较小者。从所提供的代码中看不出为什么以及如何(以及是否)正确的做法。

  

pBuffer是指向uint16_t *指针的指针,该指针传递给   函数并将其强制转换为HAL_SAI_Transmit_DMA的(uint8_t *)pBuffer   根据需要。我也从未见过这样的指针   可以。

允许从一种对象指针类型转换为另一种对象指针类型,有时这样做甚至是明智的。特别是,强制转换为诸如uint8_t *之类的字符指针是一种提供对对象表示形式的原始字节的访问的明确定义的方法。

答案 1 :(得分:1)

0xFFFF似乎不是位掩码,但最大大小为65535。

DMA_MAX(x)仅检查所传递的参数是否小于最大值,如果没有,则将值限制为所允许的最大值。也许是某种形式的溢出检查?

在逻辑上等效于此伪代码:

if( (BufferSize / AUDIODATA_SIZE) <= DMA_MAX_SZE)
{
  HAL_SAI_Transmit_DMA(... , BufferSize / AUDIODATA_SIZE);
}
else
{
  HAL_SAI_Transmit_DMA(... , DMA_MAX_SZE);
}

请注意,最好不要写这样的icky宏,而是使用一个临时变量:

uint16_t size; 
if(BufferSize / AUDIODATA_SIZE <= DMA_MAX_SZE)
{
  size = BufferSize / AUDIODATA_SIZE;
}
else
{
  size = DMA_MAX_SZE;
}

HAL_SAI_Transmit_DMA(... , size);

这将编译为与您当前拥有的机器代码相同的机器代码,但可读性更高。