flash_acr_latency
作者:互联网
关于flash_acr_latency
的理解
这个问题网上查了很多资料,但是我感觉都写的不是很清楚。下面我就结合我个人搜集到的资料,再结合个人的理解来认识一下这个参数,但是可能我所的完全是错的,如果说有更多的看法,欢迎指出,我的目的就是为了引出最正确的理解,对这个参数。
首先来看看关于内部flash所涉及的时钟树部分:
在官方手册中有关latency的理解如下:
在配置系统时钟之前,通常需要先调整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