//指定宽度向上对齐
#define RT_ALIGN(size,align) (((size) + (align) -1) & ~((align) - 1)
//指定宽度向下对齐
#define RT_ALIGN_DOWN(size,align) ((size)&~((align)-1))
1. 指定宽度向上对齐
#define RT_ALIGN(size,align) (((size) + (align) -1) & ~((align) - 1)
作用为将字节数size向上提升为align的整数倍, 就是以align为上界对齐的意思。
需要注意的是align要为2的幂次方。
- (size) + (align) - 1:align-1为size除以align的最大余数,用size去加它是为了便于向上取align的整数倍数值。
- ~((align) - 1):为余数的掩码,将其&上(size) + (align) - 1即可清除其余数,得到align的整数倍数值。
举个 4k页面边界的例子,即align=4096: 如果size = 3888;那么以上界对齐,执行结果就是4096。 如果size = 4096;结果是4096. 如果size = 4222; 则结果为8192.
2. 指定宽度向下对齐
#define RT_ALIGN_DOWN(size,align) ((size)&~((align)-1))
将字节数size向下提升到align的整数倍的, 就是以align为下界对齐的方式的意思。
举个 4k页面边界的例子,若size = 3888; 结果为0. 如果size = 4096;结果是4096. 如果size = 4222; 则结果为4096。
3. 计算示例
- RT_ALIGN(17,4)= 20
(size) + (align) - 1 = 17 + 3 = 0001 0101
~((align) - 1) = ~(3) = ~(0000 0011)
0001 0101 & ~(0000 0011) = 0001 0100 = 20 // 将后两位清0,后两位即为最大余数3
上面说过align必须为2的n次幂,下面测试其不为2的n次幂时的错误用法:
-
RT_ALIGN(17,3)
正确结果:18
实际运算结果:17
(size) + (align) - 1 = 17 + 2 = 0001 0011
~((align) - 1) = ~(2) = ~(0000 0010)
0001 0011 & ~(0000 0010) = 0001 0001 = 17
很明显,并没有完成三字节对齐,也就是说这个宏定义不能进行任意字节的对齐。不过我们一般都是四字节对齐八字节对齐,所以不能进行三字节对齐,七字节对齐,并没有什么影响。
应该是只有 1,2,4,8,16这种2的n次方才能用这个进行字节对齐。
4. 使用示例
在擦除flash函数中,由于stm32f103c8是按页擦除的,整个1k byte。当输入擦除地址时,要先判断出这个擦除的地址是属于哪一个页的,然后把整页擦除。
这个判断当前擦除地址是哪一个的时候,用的就是指定宽度对齐。
#define FLASH_PAGE_SIZE (0x400U)
/**
* Erase data on flash with bank.
* @note This operation is irreversible.
* @note This operation's units is different which on many chips.
*
* @param bank flash bank
* @param addr flash address
* @param size erase bytes size
*
* @return result
*/
int stm32_flash_erase_bank(uint32_t bank, rt_uint32_t addr, size_t size)
{
rt_err_t result = RT_EOK;
uint32_t PAGEError = 0;
/*Variable used for Erase procedure*/
FLASH_EraseInitTypeDef EraseInitStruct;
if ((addr + size) > STM32_FLASH_END_ADDRESS)
{
LOG_E("ERROR: erase outrange flash size! addr is (0x%p)\n", (void *)(addr + size));
return -RT_EINVAL;
}
HAL_FLASH_Unlock();
/* Fill EraseInit structure*/
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
EraseInitStruct.PageAddress = GetPage(addr);
EraseInitStruct.NbPages = (size + FLASH_PAGE_SIZE - 1) / FLASH_PAGE_SIZE;
EraseInitStruct.Banks = bank;
if (HAL_FLASHEx_Erase(&EraseInitStruct, &PAGEError) != HAL_OK)
{
result = -RT_ERROR;
goto __exit;
}
__exit:
HAL_FLASH_Lock();
if (result != RT_EOK)
{
return result;
}
LOG_D("erase done: addr (0x%p), size %d", (void *)addr, size);
return size;
}
/**
* @brief Gets the page of a given address
* @param Addr: Address of the FLASH Memory
* @retval The page of a given address
*/
static uint32_t GetPage(uint32_t addr)
{
uint32_t page = 0;
page = RT_ALIGN_DOWN(addr, FLASH_PAGE_SIZE);
return page;
}
/**
* @ingroup BasicDef
*
* @def RT_ALIGN(size, align)
* Return the most contiguous size aligned at specified width. RT_ALIGN(13, 4)
* would return 16.
*/
#define RT_ALIGN(size, align) (((size) + (align) - 1) & ~((align) - 1))
/**
* @ingroup BasicDef
*
* @def RT_ALIGN_DOWN(size, align)
* Return the down number of aligned at specified width. RT_ALIGN_DOWN(13, 4)
* would return 12.
*/
#define RT_ALIGN_DOWN(size, align) ((size) & ~((align) - 1))