其他分享
首页 > 其他分享> > flash_acr_latency

flash_acr_latency

作者:互联网

关于flash_acr_latency的理解

这个问题网上查了很多资料,但是我感觉都写的不是很清楚。下面我就结合我个人搜集到的资料,再结合个人的理解来认识一下这个参数,但是可能我所的完全是错的,如果说有更多的看法,欢迎指出,我的目的就是为了引出最正确的理解,对这个参数。

首先来看看关于内部flash所涉及的时钟树部分:

image-20210731172345468

在官方手册中有关latency的理解如下:

image-20210731172654218

image-20210731172824261

在配置系统时钟之前,通常需要先调整latency,然后再改变系统时钟,不然可能会出现flash读写问题。

个人想到一个问题是:

如果在改变系统时钟之前,调整了这个latency,那么出现的问题是什么呢?

这个调整了的latency与原先的系统时钟不匹配了,难道不会出现flash读写问题吗?

后面还要执行设置系统时钟的语句,肯定要访问flash,这不就矛盾了吗?

所以说到底怎么回事:

官方文件的意思是为了维持读flash的控制信号,所以需要设置。

控制信号无非就是高低电平,由若干个时钟周期组成,当你系统的时钟改变了。比如频率变高,控制信号按照我的理解应该是 维持一定的电平长度,那么需要的时钟周期数变多。

所以产生控制信号读flash的中,有一个等待完成的电平,也是由若干个时钟周期组成。

那么当频率变高时,就需要增加等待的状态,来维持那个电平信号。

按照这个思路推测,等待时间长一点是没关系的。等待时间短就可能时序产生错误,等待时间长一点,无非就浪费一点时间。

还是能保证时序的正确。

如果以上推测成立,那么得出的结论如下:

1)0<时钟频率=<24M HZ 时,三个等待状态都可以选择。

2)24<时钟频率=<48HZ时,二个状态可以选择,即one wait state或者two wait state

3) 48<时钟频率=<72HZ时,只能是two wait state

4) 如果时钟频率是从大往小了 调,那么就是必须先调整时钟频率,然后再调latency。

一句话总结就是,如果时钟频率较低,可以容忍较大latency,如果时钟频率较高,绝不能容忍较低是latency。

以上就是个人的猜测,可能就是完全是胡说八道,如果知道更好的理解的,十分欢迎指出来。

如何证明这个结论呢?

1)做实验,我暂时没去做,实验的过程想大致就是,配置一个系统时钟,然后设置不同的latency,然后看程序是否能正常运行。

如果能正常运行,那么读flash是没问题的。

2)第二个就是官方的HAL库的配置例程,他的代码时如何写的呢?这也是我想法的来源,当时看这个代码时就思考为什么其这么写。

没有比ST官方自己更了解自己芯片的了。

我们来看一下其代码:(直接跳到最后面看)

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)
{
  uint32_t tickstart;

  /* Check Null pointer */
  if (RCC_ClkInitStruct == NULL)
  {
    return HAL_ERROR;
  }

  /* To correctly read data from FLASH memory, the number of wait states (LATENCY)
  must be correctly programmed according to the frequency of the CPU clock
    (HCLK) of the device.
    为了能正确的阅读数据从FLASH内存,等待状态的数量(延迟)必须被正确编程,根据设备的CPU时钟频率(HCLK)
    */
//如果在工具链中定义了该宏
#if defined(FLASH_ACR_LATENCY)
  /* Increasing the number of wait states because of higher CPU frequency
  如果延迟大于当前寄存器的延迟
  */
  if (FLatency > __HAL_FLASH_GET_LATENCY())
  {
    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register
    设置FLASH_ACR寄存器的内容,根据FLatency
    */
    __HAL_FLASH_SET_LATENCY(FLatency);

    /* Check that the new number of wait states is taken into account to access the Flash
    memory by reading the FLASH_ACR register
    检测是否写入
    */
    if (__HAL_FLASH_GET_LATENCY() != FLatency)
  {
    return HAL_ERROR;
  }
}

#endif /* FLASH_ACR_LATENCY */
/*-------------------------- HCLK Configuration 
如果时钟类型是HCLK
--------------------------*/
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)
  {
    /* Set the highest APBx dividers in order to ensure that we do not go through
    a non-spec phase whatever we decrease or increase HCLK.
    这里为什么呢?因为当HCLK改变时,但是APB1、APB2的分频因子不变,导致APB1、APB2总线时钟改变了
    为了防止超过最大的时钟频率,设置为最大的分频因子
    修改寄存器CFGR的APB1预分频器为16分频
    修改寄存器CFGR的APB2预分频器为16分频
    最后根据时钟结构体的分频因子设置AHB的分频
    */
    if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
    {
      MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV16);
    }

    if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
    {
      MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, (RCC_HCLK_DIV16 << 3));
    }

    /* Set the new HCLK clock divider */
    MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);
  }

  /*------------------------- SYSCLK Configuration
  系统时钟的配置
  ---------------------------*/
  if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK)
  {

    /* HSE is selected as System Clock Source */
    if (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE)
    {
      /* Check the HSE ready flag */
      if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY) == RESET)
      {
        return HAL_ERROR;
      }
    }
    /* PLL is selected as System Clock Source */
    else if (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK)
    {
      /* Check the PLL ready flag */
      if (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY) == RESET)
      {
        return HAL_ERROR;
      }
    }
    /* HSI is selected as System Clock Source */
    else
    {
      /* Check the HSI ready flag */
      if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY) == RESET)
      {
        return HAL_ERROR;
      }
    }
      //该宏主要用于控制CFGR的SW位来控制系统时钟的来源,这里有个疑问,一旦修改了时钟的来源没那么不就是改变了systick的时钟频率,那么导致的问题就是如果flash_latency不改变的话,后面的语句就可能不能访问,所以要先修改flatency,
    __HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);

    /* Get Start Tick
    下面是通过读取cfgr寄存器的sws位来判断是都就绪,该位代表的含义是:
    软件置位SW后,SWS会由硬件置位指示哪个作为疫苗
    */
    tickstart = HAL_GetTick();

    while (__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos))
    {
      if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)
      {
        return HAL_TIMEOUT;
      }
    }
  }

#if defined(FLASH_ACR_LATENCY)
  /* Decreasing the number of wait states because of lower CPU frequency
  FLatency小于当前寄存器的FLatency
  */
  if (FLatency < __HAL_FLASH_GET_LATENCY())
  {
    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */
    __HAL_FLASH_SET_LATENCY(FLatency);

    /* Check that the new number of wait states is taken into account to access the Flash
    memory by reading the FLASH_ACR register */
    if (__HAL_FLASH_GET_LATENCY() != FLatency)
  {
    return HAL_ERROR;
  }
}
#endif /* FLASH_ACR_LATENCY */

/*-------------------------- PCLK1 Configuration ---------------------------*/
if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)
  {
    //根据结构体的内容修改CFGE寄存器的APB1分频因子
    MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider);
  }

  /*-------------------------- PCLK2 Configuration ---------------------------*/
  if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)
  {
      //根据结构体的内容,修改APB2分频因子
    MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3));
  }
//在前面已经根据需求打开各个开关,这里配置完分频因子
  /* SystemCoreClock为系统时钟频率 */
  SystemCoreClock = HAL_RCC_GetSysClockFreq() >> AHBPrescTable[(RCC->CFGR & RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos];

  /* Configure the source of time base considering new system clocks settings*/
  HAL_InitTick(uwTickPrio);

  return HAL_OK;
}

这里只说明latency与系统时钟配置之间的关系。同时我们定义了宏FLASH_ACR_LATENCY

那么这里的关系为

 if (FLatency > __HAL_FLASH_GET_LATENCY())//如果要配置的latency大于当前寄存器指定的latency
      __HAL_FLASH_SET_LATENCY(FLatency);    //就配置当前的latency
     //如果没有大于,后续就会先配置系统时钟
//   下面这条语句一旦设置完成,系统时钟就改变了
    __HAL_RCC_SYSCLK_CONFIG(RCC_ClkInitStruct->SYSCLKSource);
//然后再次判断了
    if (FLatency < __HAL_FLASH_GET_LATENCY())
         __HAL_FLASH_SET_LATENCY(FLatency);
/*得出的结论是什么,
   1)如果增加latency那么你的正常目的是提高系统时钟频率,
  就先设置latency,这样不仅原来的时钟匹配一个较高的latency,然后提高系统时钟,这样过渡就很自然,不能先设置时钟频率
    如果先设置时钟频率,那么出现较高的时钟频率匹配一个低的latency,这是不符合前面的结论
   2)如果是减少latency,那么你的正常目的是降低系统频率,
   就先设置系统频率,再设置latency,这样同样是较低的系统频率匹配一个较高的latency,如果是先设置latency,这样原来的时钟匹配  一个低的latency,也是不符合前面的结论。
*/

上面的内容只是分享的内容,只是提供一个参考,可能完全是胡说八道。希望有更多懂的人来解答该问题,共同进步。

标签:latency,FLASH,HAL,LATENCY,flash,acr,时钟,RCC
来源: https://blog.csdn.net/xiaoqa11/article/details/119281886