005-指定宽度对齐宏(RT_ALIGN_DOWN)

 //指定宽度向上对齐
#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))
  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值