ФАПЧ Напряжение СКАЛ STM32 - PullRequest
1 голос
/ 19 января 2020

Я работаю с платой STM32F767 Nucleo и в настоящее время пытаюсь установить PLL в качестве системных часов. Хотя я смог, благодаря примеру, сгенерированному CubeMX, я действительно не понимаю, почему это нужно сделать. Настройка:

  • HSI = 16 МГц
  • PLLM = 8
  • VCO_Input_Frequency = 16/8 = 2 МГц
  • PLLN = 144
  • Частота = 144 * 2 = 288 МГц
  • PLLP = 6
  • PLL_Output_Frequency = 288/6 = 48 МГц

  • PPRE1 = 2
  • APB1_Frequency = 24 МГц
  • APB1_Frequency_Timer = 2 * 24 МГц = 48 МГц

Следующая строка кода вызывает у меня беспокойство:

//Sets the voltage scaling mode to 3, VOS = 0x1 = b1
PWR->CR1 |= PWR_CR1_VOS_0;
a = PWR->CR1;       //Small delay

Когда эта строка прокомментирована, период составляет 19,7 мс, а когда активен, период составляет 20 мс, как и ожидалось. Это очень странно, именно так поступает сгенерированный код из CubeMX. Делает масштабирование напряжения до 1 (низкая производительность). Я не понимаю, как установка масштабирования напряжения, равного 1, заставляет PLL работать правильно.

Ниже приведен код, который настраивает PLL:

void sys_clock_init(void){
int a;

//Sets the wait states to 1
FLASH->ACR |= 0x01;
a = FLASH->ACR;         //Small delay

//Enables the power interface (for the power controller)
RCC->APB1ENR |= RCC_APB1ENR_PWREN;
a = RCC->APB1ENR;       //Small delay

//Clears the bits for the voltage scaling
PWR->CR1 &= ~(PWR_CR1_VOS);

//Sets the voltage scaling mode to 3, VOS = 0x1 = b1
PWR->CR1 |= PWR_CR1_VOS_0;
a = PWR->CR1;       //Small delay

//Makes HSI the source of the PLL
RCC->PLLCFGR &= ~(0x400000);

//Clears the bits for the different factors
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLM);

//Sets the PLLM = 0x08 = b100
RCC->PLLCFGR |= (RCC_PLLCFGR_PLLM_3);

//Clears the PLLN bits
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLN);

//Sets PLLN = 0x90 = b10010000
RCC->PLLCFGR |=(RCC_PLLCFGR_PLLN_7 | RCC_PLLCFGR_PLLN_4);

//Clears the PLLP bits
RCC->PLLCFGR &= ~(RCC_PLLCFGR_PLLP);

//Sets the PLLP = 0x02 = b10
RCC->PLLCFGR |=(RCC_PLLCFGR_PLLP_1);.

//Clears the PPRE1 bits
RCC->CFGR &= ~(RCC_CFGR_PPRE1_2 | RCC_CFGR_PPRE1_1 | RCC_CFGR_PPRE1_0);

//Set bit PPRE1 = 0x02 = b100
RCC->CFGR |= (RCC_CFGR_PPRE1_2);// | RCC_CFGR_PPRE1_0);

//Turns the PLL ON
RCC->CR |= RCC_CR_PLLON;

//Waits for the PLL to be ready
while(!((RCC->CR & RCC_CR_PLLRDY) == RCC_CR_PLLRDY));

//Clears the switch bits
RCC->CFGR &= ~(RCC_CFGR_SW);

//Set the PLL as the System Clock
RCC->CFGR |= (RCC_CFGR_SW_1);}

Я также протестировал комментирование строк, которые устанавливают биты VOS в коде CubeMX, и период равен 19,75 мс, как у меня.

1 Ответ

2 голосов
/ 19 января 2020

Это мой код для вывода этой платы на 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 темп.

...