Trying to implement PLL in code - Page 1
Forum section: electronics / projects

author: Raj
author_rank: Frequent Contributor
timestamp: October 24, 2021, 09:48:19 am
content: I want to make a code that allows a microcontroller(preferably avr isp compatible) to read a square wave of frequency range 6.25Hz to 900hz and output squarewave 1.75, 3.5 or 7 times what was fed in. 5% is the accuracy needed.I can't seem think of a solution to the problem, is it even possible or do I have to do it using plain old PLL?I was thinking of using 2 microcontrollers for this. One to read input frequency then the output frequency, then it commands the other microcontroller to raise or lower it's frequency.The frequency generating micro, has a loop with simple delay and a check for what the other microcontroller is telling it to do.

author: RoGeorge
author_rank: Super Contributor
timestamp: October 24, 2021, 09:54:29 am
content: Seems easier without emulating a PLL.Measure the duration of the input signal (using a hardware timer and timer interrupts), then at each edge divide the duration you measured by 1.75, 3.5 or 7 and playback the divided numbers with a second hardware timer.

author: Raj
author_rank: Frequent Contributor
timestamp: October 24, 2021, 09:56:24 am
content: Quote from: RoGeorge on October 24, 2021, 09:54:29 amThought about it, but hardware timer math is just something i cant seem to be able to do. 8bit timer has too much error and 16 bit is something i haven't learnt yet (on attiny microcontrollers)I know it's more of a 'me' problem.I also thought of using a table to store the values needed for every input frequency with x amount of accuracy

author: AndrewBCN
author_rank: Frequent Contributor
timestamp: October 24, 2021, 03:49:02 pm
content: I would second the method outlined by RoGeorge.If you would consider using a more powerful STM32 MCU instead of an AVR, this would be a relatively simple thing to program. The STM32F411CEU6 for example has 1 x 16-bit complex timer, 2 x 16-bit and 2 x 32-bit general purpose timers, and a number of other less powerful timers as well as three dedicated system timers, plus - very important - the libraries to make use of them.

author: Raj
author_rank: Frequent Contributor
timestamp: October 24, 2021, 04:54:45 pm
content: Quote from: AndrewBCN on October 24, 2021, 03:49:02 pmI guess, it's time to switch to another chip then.Is someone with experience of pic16f628a reading this? how easy is it relatively? cause I already own those chips.

author: harerod
author_rank: Frequent Contributor
timestamp: October 24, 2021, 05:00:34 pm
content: On a 16MHz AVR 5% of 6300Hz would mean about 126 machine cycles. So as an exercise, write this firmware PLL in any programming language that you are familiar with. In assembly that exercise would yield quite nice results, but even C is more than adequate for the required accuracy.After you have that implementation running, I'd recommend a rewrite for a timer with prescaler, just as an exercise.This can be done - have fun!

author: BrianHG
author_rank: Super Contributor
timestamp: October 24, 2021, 05:10:51 pm
content: I dont know about AVR, but with a cheap 40Mhz 8 bit/16 bit PIC with a timer input + a PWM output set to 50%, with the right fraction for it's length will generate a perfect 1.75, 3.5 or 7 times the input, 0 error, so long as you reset/realign the PWM duty cycle to the edge of the source input. I assume the AVR can do the same.To avoid output +/- 1clk jitter, this re-alignment should only be done once every 4 cycles for the lower 1.75 output generating the perfect multiple integer of 7.

author: Raj
author_rank: Frequent Contributor
timestamp: October 24, 2021, 05:48:42 pm
content: Quote from: BrianHG on October 24, 2021, 05:10:51 pmread the datasheet. you mean "CAPTURE/COMPARE/PWM (CCP) MODULE"?

author: BrianHG
author_rank: Super Contributor
timestamp: October 24, 2021, 05:50:14 pm
content: Another way to look at this, time your input.Divide by 14 and set a second timer to that figure.A)Every time timer 2 loops, toggle 1 output to give you the x7 output.Ever second time, toggle output number 2 giving you the x3.5 output.Every fourth time, toggle a third output for the x1.75 output.B)Every time timer 2 loops, increment an IO port output.Bit 0 on that IO port will have the x7 output.Bit 1 on that IO port will have the x3.5 output.Bit 2 on that IO port will have the x1.75 output.Remember to reset timer 2 on the trigger of the input timer 1 so that the first count of the x7 is toggled there and locked in. Using system B) makes everything else stupid simple.This would also be the way I would also approach this with an FPGA using 2 high speed counters and a single divide by 14 for calculating the loop length of timer #2 which increments the 3 bit output counter for the x7...x1.75.

author: BrianHG
author_rank: Super Contributor
timestamp: October 24, 2021, 05:53:27 pm
content: Quote from: Raj on October 24, 2021, 05:48:42 pmYes. This is the module which can achieve a timer, then you divide by 14 to run timer number 2 to generate an interrupt to where you increment a 3 bit IO port using my option B) making all your output fractions.

author: Raj
author_rank: Frequent Contributor
timestamp: October 24, 2021, 06:52:23 pm
content: Quote from: BrianHG on October 24, 2021, 05:50:14 pmOh I forgot to mention that only one output frequency was needed not all three at the same time. But since there all differ by a factor of 2, simply adding 1 to a byte, everytime first loop gets done and ignoring all but the first 3 bits could do the job of needed.

author: AndrewBCN
author_rank: Frequent Contributor
timestamp: October 24, 2021, 07:12:39 pm
content: All the above are just variations on the method RoGeorge suggested first.I would again suggest using an STM32 and programming it in C.Here you can find the code to measure the frequency/period and duty cycle of an input signal on an STM32 chip, thanks to the hardware timer library.https://github.com/stm32duino/STM32Examples/blob/main/examples/Peripherals/HardwareTimer/Frequency_Dutycycle_measurement/Frequency_Dutycycle_measurement.inoAnd to generate any frequency, it's a single line of code.https://github.com/stm32duino/STM32Examples/blob/main/examples/Peripherals/HardwareTimer/All-in-one_setPWM/All-in-one_setPWM.inoI would think it doesn't get much simpler than that.

author: Raj
author_rank: Frequent Contributor
timestamp: October 24, 2021, 07:17:43 pm
content: Quote from: AndrewBCN on October 24, 2021, 07:12:39 pmIndeed. I don't even know what compiler to use for pic chips :pThe only ones I've written code for, until now, were atstudio compatible.I guess stm world be similar unlike pic, which doesn't even have a free of cost c compiler (I think)