5k-100kHz software controlled clock output

I have a pretty simple need for a clock output from one of the Giga pins (D15 would be ideal) with a software controlled frequency of 5kHz to 100kHz.

What's the simplest code or library to do this?

I've been looking at the STM32 PWM modes but they seem pretty complicated and way overkill for my simple clock signal needs.

I saw one post that mentioned using the Mbed PWMout library, but I've been getting errors: 'PwmOut' is not a member of 'mbed'

I'd appreciate any tips, pointers or ideas to avoid reinventing this wheel.

1 Like

The PWM is ideal for it. But if you don't want to dive in learning, just to setup a toggle a pin by timer interrupt with giving period

Thanks, that's a great alternative idea. I studied the STM32 timer docs in more detail last night and I may give the CompareOutput approach a try... In any case it was a lot simpler to get a clock out of a MEGA pin for the earlier version of this project...

This is the simplest example I've found so far for the STM32 on the GIGA...

I don't remember a timer settings in detail.
Did you try it?
Do you have an oscilloscope or logic analyzer to test the output?

The link below also may helps:

Thanks for the extra info. I do have scopes and a logic analyzer, but I've been away from home recently. I've created an Arduino function with that code and I hope to be able to test it within the next week or so.

My main project involves trying to read 38 photodiodes to measure the velocity and acceleration of a spring loaded rod. This timer is part of a 38 bit shift register test circuit to see how fast I can read and time stamp the 38 digital inputs with a tight loop.

The previous MEGA based version had only 8 phototransistors and used interrupts on the digital inputs and could achieve a 40 kHz pulse rate. I'm hoping the much faster GIGA can achieve 100kHz.

I laid out a PCB using Easy EDA and fabricated by JLCPCB (only $4 for 5 boards) My first boards are waiting for me at home too, so I'm quite anxious to get back, get out the scope and test everything ASAP. :wink:

3 Likes

I was able to fix and modify the timer code from that stackoverflow post to create a configurable clock output signal on the Arduino GIGA. By passing in the right prescaler and counter values you can achieve a clock rate over a very wide range of less than 1 HZ to many MHz.

It uses Timer14 and outputs the clock signal on Arduino GIGA PinD5, which is STM32 pin PA7.

Here's the code in case it's useful to others.

void InitTimer14(int PrescaleRatio, int PeriodCount) {

  Serial.print("RCC->APB1LENR ");
  Serial.println(String(RCC->APB1LENR, BIN));
  Serial.print("RCC->AHB4ENR ");
  Serial.println(String(RCC->AHB4ENR, BIN));
  Serial.print("GPIOA->MODER ");
  Serial.println(String(GPIOA->MODER, BIN));
  Serial.print("GPIOA->OSPEEDR ");
  Serial.println(String(GPIOA->OSPEEDR, BIN));
  Serial.print("GPIOA->AFR[0] ");
  Serial.println(String(GPIOA->AFR[0], BIN));
  Serial.print("TIM14->PSC ");
  Serial.println(String(TIM14->PSC, BIN));
  Serial.print("TIM14->ARR ");
  Serial.println(String(TIM14->ARR, BIN));
  Serial.print("TIM14->CCR1 ");
  Serial.println(String(TIM14->CCR1, BIN));
  Serial.print("TIM14->CCMR1 ");
  Serial.println(String(TIM14->CCMR1, BIN));
  Serial.print("TIM14->CR1 ");
  Serial.println(String(TIM14->CR1, BIN));
  Serial.print("TIM14->CCER ");
  Serial.println(String(TIM14->CCER, BIN));
  Serial.print("TIM14->EGR ");
  Serial.println(String(TIM14->EGR, BIN));

  //HAL_Init();
  // 1. Enabling The Clock Sources
  RCC->APB1LENR |= RCC_APB1LENR_TIM14EN;  // Enable TIM14 peripheral clock source
  RCC->AHB4ENR |= RCC_AHB4ENR_GPIOAEN;    // Enable GPIOA peripheral clock source
  // 2. GPIO Setup
  GPIOA->MODER |= (0x2UL << 14);   // PA7 Alternate function AF9
  GPIOA->MODER &= ~(0x1UL << 14);  // PA7 Alternate function AF9 Default after reset has this bit set, so be sure to clear it
  //GPIOA->OSPEEDR |= (0x2UL << 14);      // PA7 very high speed
  GPIOA->OSPEEDR &= ~(0x3UL << 14);  // PA7 Low speed, reduces ringing. Works great at over 1 MHz
  GPIOA->AFR[0] |= (0x9UL << 28);    // AF9 for TIM14 AFR[7]
  // 3. Counter Mode
  //    As the TIM14 peripheral only supports counting up there is nothing to be configured.
  // 4. Timer Timing Parameters
  TIM14->PSC = PrescaleRatio - 1;  //Prescale 120MHz clock, Prescaler ratio is PSC value +1
  TIM14->ARR = PeriodCount - 1;    //Counter counts up from 0 to ARR, then starts from 0 again
  TIM14->CCR1 = 1;                 //Output toggles when counter matches this value, controls phase of output clock relative to counter's cycle
  // 5. Configure Toggle (Clock) Mode
  TIM14->CCMR1 |= (0x3UL << TIM_CCMR1_OC1M_Pos);  // Toggle (Clock) mode 3<<4
  TIM14->CCMR1 |= TIM_CCMR1_OC1PE;                // Enable preload of CCR1 1<<3
  // 6. Enable Auto Reload Preload
  TIM14->CR1 |= TIM_CR1_ARPE;  // Enable preload of ARR 1<<7
  // 7. Signal Polarity, CC Output
  TIM14->CCER &= ~TIM_CCER_CC1P;  // Set signal polarity - 0
  TIM14->CCER |= TIM_CCER_CC1E;   // Enable CC - On - OC1 signal is output on the corresponding output pin 1<<0
  // 8. Set Interrupt Source
  TIM14->CR1 |= TIM_CR1_URS;  // Setting UG bit does not gen. int.  Only counter overflow generates an UEV if enabled 1<<2
  // 9. Reload The Registers
  TIM14->EGR |= TIM_EGR_UG;  // Generate an update event 1<<0
  // 10. Enable timer
  TIM14->CR1 |= 1 << 0;  // enable timer 1<<0

  {
    Serial.print("RCC->APB1LENR ");
    Serial.println(String(RCC->APB1LENR, BIN));
    Serial.print("RCC->AHB4ENR ");
    Serial.println(String(RCC->AHB4ENR, BIN));
    Serial.print("GPIOA->MODER ");
    Serial.println(String(GPIOA->MODER, BIN));
    Serial.print("GPIOA->OSPEEDR ");
    Serial.println(String(GPIOA->OSPEEDR, BIN));
    Serial.print("GPIOA->AFR[0] ");
    Serial.println(String(GPIOA->AFR[0], BIN));
    Serial.print("TIM14->PSC ");
    Serial.println(String(TIM14->PSC, BIN));
    Serial.print("TIM14->ARR ");
    Serial.println(String(TIM14->ARR, BIN));
    Serial.print("TIM14->CCR1 ");
    Serial.println(String(TIM14->CCR1, BIN));
    Serial.print("TIM14->CCMR1 ");
    Serial.println(String(TIM14->CCMR1, BIN));
    Serial.print("TIM14->CR1 ");
    Serial.println(String(TIM14->CR1, BIN));
    Serial.print("TIM14->CCER ");
    Serial.println(String(TIM14->CCER, BIN));
    Serial.print("TIM14->EGR ");
    Serial.println(String(TIM14->EGR, BIN));
  }
}
3 Likes