I am trying to make a midi clock output (24PPQN) using the UART on an ATMEGA328
I want to use a 32 bit phase accumulator for this.
I am ticking the accumulator at a rate of 8Khz using a 16 bit timer.
to calculate the phase increment values i am using the following formula with python:
i then tick the phase inside the ISR, check for a rising edge and add a midi timing tick to a ring buffer.
when the uart is ready i pull some data from the buffer and send it.
121 bpm = 121 / 60 beats per second = 24 * 121 / 60 pulses per second.
So 60 / 24 / 121 = 2.5 / 121 seconds between pulses.
Your timer is at 8kHz, so 2.5 / 121 * 8000 = 165.28 clock ticks between pulses. This is not a round number. Either you round it and get an inaccurate bpm without jitter, or you leave it as is and you get the correct average tempo with jitter (roughly 3 out of 4 pulses will be distant by 165 clock ticks, and 1 out of 4 pulses will be distant by 166 clock ticks).
thanks for taking the time to explain this, i think i have better understanding of it now.
but i’m starting to realize my mental math skills are on a pathetic level, which i’m a bit embaressed about
i’m really enjoying learning embedded programming but the thing that is really slowing me down is a basic calculation like this, which i feel i should be able to grasp quite quickly.
Where should i improve?
basic algebra?
i don’t mind taking large steps back if thats what it takes, i just want to know what i should focus on.
If i understand correctly 125BPM should give a tempo without jitter.
2.5 / 125 * 8000 = 160
this is a round number so i should be able to get a stable clock.
This is not case with me.
No matter how i measure the BPM, it is always jumping up and down from 125.0 to 125.1 quite rapitly
Is there perhaps something wrong with my phase increment calculation?
If your code was such that a clock pulse is sent every 160th call to the ISR, you would get a jitter-free clock with a tempo of 125 BPM and an ISR rate of 8kHz. To get a clock pulse sent every 160th call to the ISR, you can naively increment a counter and send a pulse every time the counter reaches 160; or use an accurate phase accumulator.
But you’re not using an accurate phase accumulator here because it uses integer maths and things are rounded up! So you have to consider the rounding errors too! This is because 160 does not divide (1<<32), so the “wrap arounds” won’t occur neatly every 160th ISR call - there will be the occasional interval where the wraparound occurs every 159th or 161th call (depending on whether you round up or down). It’s a rare event, though.
In other words, with your present implementation, the conditions for an absolutely jitter-free clock is that:
isr_freq / hertz is an integer (so that the clock pulses are aligned on an 8kHz grid).
This integer divides (1<<32) (or equivalently is a power of 2 under 32 - so that rounding errors do not occur).
These conditions are met for 156.25 BPM and 78.125 BPM.
You should consider handling the special case where isr_freq / hertz is an integer with an extra piece of code.
I would also advise you to investigate if the code actually sending the 0xf8 introduces additional delays, and if your MIDI clock measuring device does not introduce jitter from its own timing measurements. Have you checked the actual MIDI signal with a scope?
thanks for the reply.
just measured the midi signal with a scope.
with 125 bpm i get a signal that alternates between 50hz and 50.13hz.
i will check if my code causes any delays.
Maybe another ISR is occasionally invoked and interrupts the other one? Try to build the most minimalist code (direct UART write with a timer ISR at 160 Hz…) and add one by one all the layers of complexity.
I’m only using timer 1 interrupts.
Maybe i am initializing another one somewhere in my code.
Going to build the minimalist code and build it up as you advised tomorrow.
Really hoping i can solve this thing then.
Ok so after hours testing i finally found the problem (sort of).
After a long time of testing i eventually decided to see if the actual micro controller was the problem, and it turns it was.
The identical code including ringbuffers, serial class, etc, gave me a stable clock on a fresh micro controller.
I’m still not sure what went wrong though.
Thanks so much for your help and patience.
Oh and happy birthday
Oh wow that’s really strange! Maybe it was set to run on an internal RC oscillator instead of an accurate, external crystal? (Thinking of an AVR whose fuses have not been properly set).