Это мой код для вывода этой платы на 16 МГц с использованием PLL и внешних часов.
static int clock_init ( void )
{
unsigned int ra;
//switch to external clock.
ra=GET32(RCC_CR);
ra|=1<<16;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<17)) break;
if(1)
{
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=1;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==1) break;
}
//HSE ready
//PLLM aim for 2mhz so 8/4=2
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLP 16Mhz*8 = 128, 16MHz*6 = 96, not enough
//so PLLP is 8 VCO 128 so PLLN is 64
//dont really care about PLLQ but have to have something so 8
PUT32(RCC_PLLCFGR,0x20000000|(8<<24)|(1<<22)|(3<<16)|(64<<6)|(4<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
PUT32 / GET32 - это функции абстракции для выполнения str / ldr. Я попробую либо 48 HSE, либо 48 МГц HSI, и выложу то, что нахожу.
static int clock_init ( void )
{
unsigned int ra;
//PLLM aim for 2mhx so 16/8 = 2;
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLN = 144, VCO 288
//PLLP = 6, output 288/6 = 48MHz
//dont really care about PLLQ but have to have something so 6
PUT32(RCC_PLLCFGR,0x20000000|(6<<24)|(0<<22)|(2<<16)|(144<<6)|(8<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
Uart работает, но это не говорит о многом.
При использовании масштаба 1 по умолчанию я вижу это немного быстро. но если я использую 8 МГц HSE, то это выглядит лучше. Я использую Systick, чтобы считать 120 секунд. установите systick так, чтобы он переворачивал каждые 1 миллион отсчетов, затем ждите 120 опрокидываний, сравните с секундомером / таймером.
Затем используйте 16000000 в палитре и подсчитайте 900 опрокидываний, которые должны составлять 5 минут, с точностью до секунды с момента сравнения визуально к таймеру это только то, что точно. При использовании HSE, масштабирование 1 (по умолчанию)
При использовании HSI, масштабирование 1 отключается на несколько секунд, чтобы получить 19,7 нс, хотя это будет много секунд, и я не вижу такого количества.
Теперь с использованием шкалы HSI 3:
static int clock_init ( void )
{
unsigned int ra;
ra=GET32(RCC_APB1ENR);
ra|=1<<28; //PWR enable
PUT32(RCC_APB1ENR,ra);
PUT32(FLASH_ACR,0x00000001);
PUT32(PWR_CR1,0x4000);
GET32(PWR_CR1);
//PLLM aim for 2mhx so 16/8 = 2;
//PLLN input is 2, want >=100 and <=432 so between 50 and 216
//PLLN = 144, VCO 288
//PLLP = 6, output 288/6 = 48MHz
//dont really care about PLLQ but have to have something so 6
PUT32(RCC_PLLCFGR,0x20000000|(6<<24)|(0<<22)|(2<<16)|(144<<6)|(8<<0));
ra=GET32(RCC_CR);
ra|=1<<24;
PUT32(RCC_CR,ra);
while(1) if(GET32(RCC_CR)&(1<<25)) break;
ra=GET32(RCC_CFGR);
ra&=~3;
ra|=2;
PUT32(RCC_CFGR,ra);
while(1) if(((GET32(RCC_CFGR)>>2)&3)==2) break;
return(0);
}
Похоже, более точный. 5 минут измеряется как 5 минут до второго. Таким образом, возможно, что документация неверна в отношении точности HSI (поскольку существует это исключение при использовании масштабирования по умолчанию).
48 МГц -> 20,83 нс
20,62 - 21,04 с документированным ошибка.
Существует причина для использования внешних часов. Если вы заинтересованы в большей точности, поскольку у вас есть плата NUCLEO, используйте внешнюю синхронизацию HSE, а не внутреннюю HSI.
Хммм, фактически 1% для 16 МГц, что составляет 3% при умножении на 3 для получения 48 МГц. Я думаю, что использование делителя в ФАПЧ ухудшает ситуацию, но я должен подумать об этом еще немного.
20.21 - 21.46 - это диапазон, который вы должны видеть при температуре калибровки, а затем отличаться от диапазона, основанного на d ie темп.