Default master clock source

Post here first, or if you can't find a relevant section!
Post Reply
timdf911
Posts: 5
Joined: Thu Dec 01, 2022 5:32 pm

Default master clock source

Post by timdf911 »

Hi guys

I little while back I started a thread about how to measure frequencies up to 30MHz with 1kHz resolution using a STM32F401 Nucleo board.

After a lot of experimentation I was successful, but have now run into another problem.

I suspect by default I'm using the internal 16MHz RC oscillator which is marginal in terms of stability.

A better reference would be to use the 8MHz xtal drived MCO signal coming from the ST link section.

Below is my code where I've tried to select an external 16MHz xtal, but despite the xtal running ok it always uses the internal 16MHz RC osc.

The code itself works fine - just has an issue with reference selection. Input signal is applied to PD2.

Apologies in advance for my primitive coding style and not using register defines etc.

There's a reason why I'm using only a 16 bit counter - hardware limitations elsewhere.

Here's hoping the code displays ok and makes sense !

Regards Tim

Code: Select all


void setup() {

Serial2.begin (115200);   // Initialise the serial interface
Serial.println("start") ;

//RCC->CR &= ~(1<<0); // turn off hsi

RCC->CR |= 1<<16;   // start xtal osc and wait for it to settle
while (!(RCC->CR & (1<<17)));

RCC->APB1ENR |= 1<<28; // turn on power clock

PWR->CR |= 3<<14; // power mode 2

FLASH->ACR = (1<<8) | (1<<9)| (1<<10)| (5<<0);

// set up prescalers

RCC->CFGR &= ~(1<<4); // bits 7:4 all 0s

RCC->CFGR |= (4<<10); // bits 12:10  100 or 4 into 10th position means /2

RCC->CFGR &= ~(4<<13); // set bit 14 to zero for no divide

// configure main PLL

#define PLL_M   16
#define PLL_N   336
#define PLL_P   4  

RCC->PLLCFGR = (PLL_M <<0) | (PLL_N << 6) | (PLL_P <<16) | (1<<22);

// enable PLL and wait for it to become ready

RCC->CR |= (1<<24); // ok
while (!(RCC->CR & (1<<25))); // ok

// select PLL clock source and  wait for it to be set
RCC->CFGR |= (2<<0);
//RCC->CFGR |= (3<<0); // not allowed
while (!(RCC->CFGR & (2<<2)));

setup_freq_timers() ;

}

void loop() {

 Serial.println(measure_freq());

 delay(300) ;

}


void setup_freq_timers (void) // generates timebase signal signal on CH1
{

 //   set up Timer 2 for gating signal
 //   Enable clock access to tim2
  RCC->APB1ENR |=  (1U<<0);

//  Enable clock access to GPIOA for time gate debug
  RCC->AHB1ENR |=  (1U<<0) ;

//Set prescaler value
  TIM2->PSC =  84 - 1 ; // 84MHz clock done to 1MHz
    
//Set auto-reload value
  TIM2->ARR =  8000 - 1;  // 8ms Gate  
  
//Set output compare toggle mode
  TIM2->CCMR1 = ((1U<<4) | (1U<<5));

//Enable tim2 ch1 in compare mode 
  TIM2->CCER |= (1U<<0);
  
// MMS=010  bit 5 evnt on TRG01 on each event
  TIM2->CR2 |=  (1U<<5 ) ; 

//Clear counter
  TIM2->CNT = 0;
 
///////////////////////////////////////////
//set up timer 2 PD2 input
//////////////////////////////////////////

//Enable clock access to GPIOD
  RCC->AHB1ENR |= (1U<<3);

//Set PD2 mode into alternate function mode
  GPIOD->MODER &=~(1U<<0); 
  GPIOD->MODER |=(1U<<5);

//Set PD2 alternate function type to TIM3_CH3 (AF02)
  GPIOD->AFR[0]|= (1U<<9)  ; // 0b0010 = AF2

//Enable clock access to tim3
  RCC->APB1ENR |= (1U<<1);

/*Set Prescaler*/
  TIM3->PSC = 0 ; 

 //Set CH3 to input capture from ITR1 via TRC
  TIM3->CCMR2  |= (1U<<0) | (1U<<1 ) ; // mapped to TRC to trigger, needs TS bit in SMCR
  TIM3->SMCR |=  (1U<<4)    ; // slecting ITR1 in TS bit 4 

// set slave mode reset
  TIM3->SMCR |=  (1U<<2)    ;  // set sms reset mode
  TIM3->ARR = 0xffff ;
  
  TIM3->CCER  = 0x0100 ;  // cap compare 3 output enable

  TIM3->SMCR |= TIM_SMCR_ECE; // switch to ETR2 input on PD2
  TIM3->SMCR |= TIM_SMCR_ETPS; // divide by 8

}


int measure_freq () //  returns int of freq in kHz
{

        int i = 0 ;
        int freq_temp = 0 ;

        TIM3->CCR3 = 0 ;
        TIM3->CR1 =   (1U<<0); // start tim3   
        TIM2->CR1 = (1U<<0);  // start tim2
    
        while(!(TIM3->SR & (1U<<3))){}  // dummy read to clear junk  ch3 capture compare irq         
              freq_temp =   (TIM3->CCR3);
     
          freq_temp = 0 ;  
                     
          i = 0 ;
           while (i <=7)      //  average over 4 readings // was 3 
              {       
                  while(!(TIM3->SR & (1U<<3))){}  // (1U<<3) ch3 capture compare irq     
                  freq_temp = freq_temp  +  (TIM3->CCR3);    
                  i++ ;
              }      
    
        TIM3->CR1 = 0 ; //  stop timers
        TIM2->CR1 = 0 ; 
     return  freq_temp / 8 ;
      
        
}

timdf911
Posts: 5
Joined: Thu Dec 01, 2022 5:32 pm

Re: Default master clock source

Post by timdf911 »

Ok,

I've made some progress and now have my Nucleo board running with a 16MHz external xtal. I used Cubemex to generate the clock tree numbers but for some reason it's running twice as fast as it should.

EG if I set a baud rate of 57600 it actually generates 115200

Any ideas as to where I've gone wrong ?

Regards Tim

EDIT - fixed it I had to delete #include <Arduino.h> from my sketch


Code: Select all

  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Configure the main internal regulator output voltage
  */
  __HAL_RCC_PWR_CLK_ENABLE();
  __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLM = 16;
  RCC_OscInitStruct.PLL.PLLN = 336;
  RCC_OscInitStruct.PLL.PLLP = 4;
  
  RCC_OscInitStruct.PLL.PLLQ = 7;


  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }
  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}


dannyf
Posts: 447
Joined: Sat Jul 04, 2020 7:46 pm

Re: Default master clock source

Post by dannyf »

a few things:
1. you want to set up the clock first;
2. once the clock is switched over, you want to update SystemCoreClock - assuming you are using CMSIS;
3. you want the uart baud rate set-up to be dependent on the clock setting. I usually derive F_PHB from SystemCoreClock in my uart setup code.

I don't have a F4 but here is how I switch to HSEPLL on a F1:
//switch to HSExPLL
//Predivx makes sure that PLL output frequency is less than 24Mhz
void SystemCoreClockHSEPLL(uint32_t PLLMul_x, uint32_t PREDIV_x) {
SystemCoreClockHSI(); //switch to HSI - so PLL can be disabled

RCC->CR |= RCC_CR_HSEON; //turn on HSE
//wait for HSI to be ready
while ((RCC->CR & RCC_CR_HSERDY) == 0) continue; //1->HSI ready, 0->HSI not ready
//HSE is ready now
//switch the clock to HS
//RCC->CFGR = (RCC->CFGR &~RCC_CFGR_SW) | (RCC_CFGR_SW & RCC_CFGR_SW_HSE);

//turn off PLL - doable only if PLL is NOT the system clock
RCC->CR &=~RCC_CR_PLLON; //1->pll on, 0->pll off
//configure predivider
//RCC->CFGR = (RCC->CFGR &~RCC_CFGR2_PREDIV1) | (RCC_CFGR2_PREDIV1 & PREDIV_x);
//configure PLL multiplier
RCC->CFGR = (RCC->CFGR &~RCC_CFGR_PLLMULL) | (RCC_CFGR_PLLMULL & PLLMul_x); //set the pll multiplier
RCC->CFGR = (RCC->CFGR &~RCC_CFGR_PLLSRC) | (RCC_CFGR_PLLSRC & (1<<16)); //0->HSI selected as pll source (pll input = HSI/2); 1->prediv1 as pll source
RCC->CR |= RCC_CR_PLLON; //1->pll on, 0->pll off
while ((RCC->CR & RCC_CR_PLLRDY) == 0) continue; //1->PLL ready, 0->pll not ready
//switch the clock to PLL
RCC->CFGR = (RCC->CFGR &~RCC_CFGR_SW) | (RCC_CFGR_SW & RCC_CFGR_SW_PLL);
//now hsi/2pll is the clock source
}
you will need to check it against your datasheet.
Post Reply

Return to “General discussion”