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...
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.
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));
}
}