A bit late in the process, but you should do the actual frequency increment in the interrupt handler. Then have a tight main loop with fake multitasking. Every iteration you count the frequency, every 4th loop you output the frequency on i2c, every 16th loop you update the display, etc.
Thanks for the video series, they help keep me motivated as I am sure is the case for very many other people. Perhaps the following is an option for getting the most out if the AVR that you are using. However do consider the following as sudo code, because I have not compiled it nor checked the frequencies that are involved (CPU clock and signal being measured). The intention here is to sample only as often as you need to update the display and and then resume user interface activities. unsigned long samplePeriod; unsigned long sampleStart = 0; uint8_t sampleCount = 0; ISR(INT0_vect) { if (sampleCount == 0) { sampleStart = micros(); // on the first interrupt store the microseconds } if (sampleCount >= 10) { // the sample count of 10 is quite arbitrary and most likely needs to be tweaked based on the CPU frequency samplePeriod = micros() - sampleStart; // calculate the difference between the start and end microseconds EIMSK &= ~(1
The timers in the Nano can be set up to generate interrupts so that the frequency counter function can operate in the background. If you do this the frequency counter function would barely be noticed when decoding the rotary dial and vice versa. The Arduino library has the ability to store data into non-volatile memory on chip. You could store your calibration parameters into NVRAM without hard coding it into code. It is actually very easy to do. The advantage would be if it drifts over time you don't need to reprogram the device. Just recalibrate. I had an IC 22a I purchased in early 1970s. I already had a GLB Channelizer to provide multiple channels to this rock bound transceiver. I added a Nano circuit to generate CTCSS tones now needed to hit repeaters. It stores the CTCSS tone in NVRAM for each repeater frequency I have programmed. A board fits inside the GLB Channelizer and determines the frequency from the GLB switches. I actually synthesize the tones with three digital outputs that cycle through using a timer. The tones are very accurate in frequency and low distortion sine waves. I had almost the same motivations you did. I hope you continue your project with great success. I don't have an IMSAI but do have an ALTAIR that I built in 1975. W5PZT
Thanks for the fascinating journey - it's fun to lurk as you explore an interesting alternative to frequency synthesis and I'm looking forward to seeing if you can make the multiprocessor I2C counter option work. I'm curious if you've considered using a dedicated external PLL chip like the LMX2331UTM? This isn't much beyond the prescaler approach you've already tried, but would allow you to get true phase lock on your existing VCO without loading down the Arduino with a heavy real-time requirement. These chips are in stock at the usual distributors, not too expensive, run on 5V and should interface with rest of your system without requiring much support circuitry. The downside is you'd have to do the loop filter design and dual-modulus calculations, but that could be an interesting journey in itself.
Would be interesting to know the reasons behind not time slicing the frequency count (I presume hardware limitation), also will be interesting to see how you get 2 arduinos to communicate and behave :-) Great series so far, thanks.
Very nice project. I have learned so much about HF measurement from your videos. Thanks. I think the Arduino library uses the 16bit Hardware counter to count an generates the needed time window in software. Any interrupt during counting would influence the window time and therefore the result, so interrupts might be disabled by the library. Even if the library would relay on a second timer with additional interrupts, it would be a problem if any other interrupt wold delay your final windowing interrupt. Maybe interrupt priorities could help but I think nested interrupts are not suppoted by the underlying ATmega. So doing the window in software seems to be a good idea - but anyhow this blocks all other tasks. One option would be an external window, for instance a TCXO devided down to 100ms and than CMOS AND with the 2.5 Mhz. Plus some controlling anyhow. I think even the two Arduino solution is not bad at all. Maybe the new Arduino could have a simple loop: 1. Count, 2. Tell the result as I2C master. The existing Arduino should than be the slave since this one is interruptable. I tried a similar thing with an ATMega8, trying to generate a clock for a shortwave receiver. (3.8Mhz). But I did not use a DAC. Instead I had some PWM. I ended up with much undesired FM modulation so I gave up. But maybe I should try again with a DAC. This seems promising. So I'm really interested how this story will go on. Thanks!
Why not use a counter chip to count the amount of oscillations and add a simple code that would trigger timer interrupts for Nano to read from the counters? It would decrease the number of interrupts needed by a factor of 256.
After some thought another option popped up in my mind: you can trigger interrupts by the overflow bit and just add 256 to the sum. Then once in a while in the main loop you may check the timing against amount of oscillations vs expected and make a correction to the voltage. That would not require use of any additional data pins.
at the end you explain about the fact you need to think about the pins you use and yes i agree but thats also the reason why i dont use arduino based boards, now a days i use the teensy which has more feature like more uart ports, more i2c ports, more spi ports, all pin can be interrupt, more pwm, more analog pins, so if you F it up you can easy use other pins, and dont forget 32bit, fast cpu, fpu
You now only have a flag in the encoder interrupt routine. You don't know if it triggered once or more. Try changing that interrupt to have a counter to know how many times it triggered before your loop handles it. Fix the bounce in the hardware.
I think you may be making the solution too difficult. Likely you do not need to dedicate 100% of processor to do the freq-counter. Try including another count which immediately exits the _ir_sub by some % so that the cpu has time for your base functions. IE - time share,...
I2C can give clocking noise in your rx(sounds like a whine) ..some thing i have found when modding commercial ssb transceivers to the ham bands with dds si5351 and oled displays or led displays driven by tm1637 drivers
@@mr1enrollment they're...... is that what you are refering too? If not, you may want to check out both the official Mbed core for arduino and the Earle Philhower core. Both have strenghts and weaknesses. Both work well.
@@keithspainhour9067 Hi Keith, I am just noting that the Pico is NOT an Arduino processor. Rather an ARM Cortex. I don't know which uPC he is using but does not look like an ARM. The Pico IS supported by the Arduino IDE though. But you need to properly configure the IDE. It would be interesting to compare the pin outs because the form factor looks the same. Pico is a nice little device, and the PIO is a bit complicated to dig thru and understand. (Ah the Nano is a ATmega328,....) cheers
Hmm, I do not know why the Arduino's frequency counter library would kill your other interrupts.. which library are you using? I would have thought it would only generate interrupts at the "gate" frequency, where its sampling the counter, then resetting it. For an I2C sensor, like a frequency counter, its should generate an interrupt to let the MCU know when it has something to read. Handling multiple interrupt sources with only one pin can get fun as well.. usually its handled by having level sensitive (eg. active low) INT sources wire-or then together then the ISR has to round-robin go to each potential source and check it. Once all pending INTs are cleared then the line de-asserts and normal processing continues. Cheers,
Maybe the arduino has not enough resources availability to do all the stuff. Using another divider before the counter input would be a solution since you have to sample less often. Accuracy would be less though
Hello. I think that the idea of a separate arduino for the counter is ok. Is what I would do, but I think that you don´t need I2c comm between them. You only need data one way, from the counter arduino to the UI arduino. So, you could use some serial data from the counter to the UI arduino at a convenient time. Also, is your counter accuracy based on the arduino's own crystal/clock? Or do you have a better timebase somewhere?
Does anybody know where to find the actual service manual for Icom IC-245, not the user manual. Was one ever produced? I tried mods(dot)dk, no luck. I have the US model, not the euro model. I ordered a capacitor kit from fleabay, supposedly nichicon/rubicon 85 deg C caps and some 7447 BCD to 7 segment decoder/drivers to fix front panel digit that had permanent BCD input C, stuck high - displayed '4' when should display '0'. I took the front panel off to verify if 7447 was bad or bad output from PLL chip. Damned thing came clear. - digit in question displays properly now. No amount of board flexing will change it - neither did it change with board flexing before I disassembled front panel. I did find a 27 ohm 1/8 watt resistor hanging from simplex/duplex switch - I'm wondering if this was touching display board on 7447 'C' input? I can't find this resistor any where on the schematics I have. Also my PLL unit is different from one shown in this series - mine has no connectors with a row of disc caps - all connections are bulkhead feedthru caps. Can any body help a brutha out? Thanks!
Surprised about the processing time. What method are you using to measure the frequency input? You mention pin 5 being used which is associated with the timers, another option is to use pulsein() which can use any pin (I think), but the key is that is will measure one pulse then return a value. It also has an optional timeout (default one sec) the docs say this method is good for 10uS to 3mins.. Andy
You should write your own counter routine. You could probably get away with just doing a sample every few tenths of a second or more. Your VCO drift shouldn't be that fast or that much so slow your sample rate down. And you should be able to do a minimal interrupt route that just copies the value of the counter to memory and then do the math later. You might still miss a click or two but it would be a lot less. And/or bake in a disable in so when the encoder is in use you just disable your counter.
There is no reason why the Arduino cannot count 2.5 MHz on its hardware timer. Set the timer to interrupt on overflow and increment a volatile uint16_t variable in the service routine. It can EASILY do this 40 times per second. Pessimistically this 100 us/s duty cycle. Once per second in loop (), read the memory and the hardware timer to form a uint32_t count for display. (Shift left 6b = x64 first...) You can fabricate a union to store the variable, to hold a place to store the hardware count, and to be read as 32 bits. Don't forget to zero the count in preparation for the next second (or store the 32 bits for subtraction from the next read). But, the accuracy of the count is directly affected by the accuracy of the Arduino's oscillator (definition of '1 s') and calibration is only effective until that rate drifts.
@@IMSAIGuy There should be only a few of those each second also. Check for switch bounce -- a lp filter and Schmidt trigger might be needed -- each bounce generates an interrupt. Otherwise, some code optimization might be needed. Be sure BOTH interrupts are generated reliably from the dial.
I've learned a TON from you. Not the least of which is you're a very smart yet humble guy that is inspiring me to fail more at this stuff. Thanks!
Thanks for posting this project!!! I know it is making me motivated to try some projects!
A bit late in the process, but you should do the actual frequency increment in the interrupt handler. Then have a tight main loop with fake multitasking. Every iteration you count the frequency, every 4th loop you output the frequency on i2c, every 16th loop you update the display, etc.
Exactly, curiosity and learning stimulus, Thanks
Thanks for the video series, they help keep me motivated as I am sure is the case for very many other people.
Perhaps the following is an option for getting the most out if the AVR that you are using.
However do consider the following as sudo code, because I have not compiled it nor checked the frequencies that are involved (CPU clock and signal being measured).
The intention here is to sample only as often as you need to update the display and and then resume user interface activities.
unsigned long samplePeriod;
unsigned long sampleStart = 0;
uint8_t sampleCount = 0;
ISR(INT0_vect) {
if (sampleCount == 0) {
sampleStart = micros(); // on the first interrupt store the microseconds
}
if (sampleCount >= 10) { // the sample count of 10 is quite arbitrary and most likely needs to be tweaked based on the CPU frequency
samplePeriod = micros() - sampleStart; // calculate the difference between the start and end microseconds
EIMSK &= ~(1
It is a nice project for university students by learning to handle a problem.
The timers in the Nano can be set up to generate interrupts so that the frequency counter function can operate in the background. If you do this the frequency counter function would barely be noticed when decoding the rotary dial and vice versa. The Arduino library has the ability to store data into non-volatile memory on chip. You could store your calibration parameters into NVRAM without hard coding it into code. It is actually very easy to do. The advantage would be if it drifts over time you don't need to reprogram the device. Just recalibrate. I had an IC 22a I purchased in early 1970s. I already had a GLB Channelizer to provide multiple channels to this rock bound transceiver. I added a Nano circuit to generate CTCSS tones now needed to hit repeaters. It stores the CTCSS tone in NVRAM for each repeater frequency I have programmed. A board fits inside the GLB Channelizer and determines the frequency from the GLB switches. I actually synthesize the tones with three digital outputs that cycle through using a timer. The tones are very accurate in frequency and low distortion sine waves. I had almost the same motivations you did. I hope you continue your project with great success. I don't have an IMSAI but do have an ALTAIR that I built in 1975. W5PZT
I did that. But then the rotary encoder stops functioning as it uses interrupts too
Thanks for the fascinating journey - it's fun to lurk as you explore an interesting alternative to frequency synthesis and I'm looking forward to seeing if you can make the multiprocessor I2C counter option work.
I'm curious if you've considered using a dedicated external PLL chip like the LMX2331UTM? This isn't much beyond the prescaler approach you've already tried, but would allow you to get true phase lock on your existing VCO without loading down the Arduino with a heavy real-time requirement. These chips are in stock at the usual distributors, not too expensive, run on 5V and should interface with rest of your system without requiring much support circuitry. The downside is you'd have to do the loop filter design and dual-modulus calculations, but that could be an interesting journey in itself.
Would be interesting to know the reasons behind not time slicing the frequency count (I presume hardware limitation), also will be interesting to see how you get 2 arduinos to communicate and behave :-) Great series so far, thanks.
Probably the accuracy
Very nice project. I have learned so much about HF measurement from your videos. Thanks.
I think the Arduino library uses the 16bit Hardware counter to count an generates the needed time window in software. Any interrupt during counting would influence the window time and therefore the result, so interrupts might be disabled by the library. Even if the library would relay on a second timer with additional interrupts, it would be a problem if any other interrupt wold delay your final windowing interrupt. Maybe interrupt priorities could help but I think nested interrupts are not suppoted by the underlying ATmega. So doing the window in software seems to be a good idea - but anyhow this blocks all other tasks.
One option would be an external window, for instance a TCXO devided down to 100ms and than CMOS AND with the 2.5 Mhz. Plus some controlling anyhow.
I think even the two Arduino solution is not bad at all. Maybe the new Arduino could have a simple loop: 1. Count, 2. Tell the result as I2C master. The existing Arduino should than be the slave since this one is interruptable.
I tried a similar thing with an ATMega8, trying to generate a clock for a shortwave receiver. (3.8Mhz). But I did not use a DAC. Instead I had some PWM. I ended up with much undesired FM modulation so I gave up. But maybe I should try again with a DAC. This seems promising.
So I'm really interested how this story will go on.
Thanks!
Yes, I have thought of adding an external gate. Maybe sometime in the future.
Some sound advice there, just have fun!
Why not just use a latching buffer on the freq counter
and read it with an I2C to parallel port?
When you get this working I'll be excited, it appears it uses the same unit as my ic211.
Why not use a counter chip to count the amount of oscillations and add a simple code that would trigger timer interrupts for Nano to read from the counters? It would decrease the number of interrupts needed by a factor of 256.
After some thought another option popped up in my mind: you can trigger interrupts by the overflow bit and just add 256 to the sum. Then once in a while in the main loop you may check the timing against amount of oscillations vs expected and make a correction to the voltage. That would not require use of any additional data pins.
at the end you explain about the fact you need to think about the pins you use and yes i agree but thats also the reason why i dont use arduino based boards, now a days i use the teensy which has more feature like more uart ports, more i2c ports, more spi ports, all pin can be interrupt, more pwm, more analog pins, so if you F it up you can easy use other pins, and dont forget 32bit, fast cpu, fpu
You now only have a flag in the encoder interrupt routine. You don't know if it triggered once or more. Try changing that interrupt to have a counter to know how many times it triggered before your loop handles it. Fix the bounce in the hardware.
Nice video clip, keep it up, thank you for sharing it :)
I think you may be making the solution too difficult.
Likely you do not need to dedicate 100% of processor to do the freq-counter.
Try including another count which immediately exits the _ir_sub by some % so that the cpu has time for your base functions. IE - time share,...
I2C can give clocking noise in your rx(sounds like a whine) ..some thing i have found when modding commercial ssb transceivers to the ham bands with dds si5351 and oled displays or led displays driven by tm1637 drivers
Note the Rpi Pico has two cores and plenty of pins. Also 125mHz! AND if you really want to learn - the Pico PIO has plenty of reason for learning.
And they're are two Arduino "cores" for the pico to choose from.
@@keithspainhour9067 best check your comment.
@@mr1enrollment they're...... is that what you are refering too? If not, you may want to check out both the official Mbed core for arduino and the Earle Philhower core. Both have strenghts and weaknesses. Both work well.
@@keithspainhour9067 Hi Keith, I am just noting that the Pico is NOT an Arduino processor. Rather an ARM Cortex. I don't know which uPC he is using but does not look like an ARM. The Pico IS supported by the Arduino IDE though. But you need to properly configure the IDE. It would be interesting to compare the pin outs because the form factor looks the same. Pico is a nice little device, and the PIO is a bit complicated to dig thru and understand. (Ah the Nano is a ATmega328,....)
cheers
@@keithspainhour9067 agreed, Ive been using Earle's.
Cool thanks for the post.
Best way to emulate a PLL is to use a PLL, use a serial controlled PLL and do away with the complications.
Hmm, I do not know why the Arduino's frequency counter library would kill your other interrupts.. which library are you using?
I would have thought it would only generate interrupts at the "gate" frequency, where its sampling the counter, then resetting it.
For an I2C sensor, like a frequency counter, its should generate an interrupt to let the MCU know when it has something to read.
Handling multiple interrupt sources with only one pin can get fun as well.. usually its handled by having level sensitive (eg. active low) INT sources wire-or then together then the ISR has to round-robin go to each potential source and check it. Once all pending INTs are cleared then the line de-asserts and normal processing continues.
Cheers,
Maybe the arduino has not enough resources availability to do all the stuff. Using another divider before the counter input would be a solution since you have to sample less often. Accuracy would be less though
Just hook up the dial signals to an input pin and add this routine to be run before or after the frequency counting.
Hello. I think that the idea of a separate arduino for the counter is ok. Is what I would do, but I think that you don´t need I2c comm between them. You only need data one way, from the counter arduino to the UI arduino. So, you could use some serial data from the counter to the UI arduino at a convenient time. Also, is your counter accuracy based on the arduino's own crystal/clock? Or do you have a better timebase somewhere?
for now just the xtal on the Arduino. the radio did not have anything fancy so it might be about the same.
Does anybody know where to find the actual service manual for Icom IC-245, not the user manual. Was one ever produced? I tried mods(dot)dk, no luck. I have the US model, not the euro model. I ordered a capacitor kit from fleabay, supposedly nichicon/rubicon 85 deg C caps and some 7447 BCD to 7 segment decoder/drivers to fix front panel digit that had permanent BCD input C, stuck high - displayed '4' when should display '0'. I took the front panel off to verify if 7447 was bad or bad output from PLL chip. Damned thing came clear. - digit in question displays properly now. No amount of board flexing will change it - neither did it change with board flexing before I disassembled front panel. I did find a 27 ohm 1/8 watt resistor hanging from simplex/duplex switch - I'm wondering if this was touching display board on 7447 'C' input? I can't find this resistor any where on the schematics I have. Also my PLL unit is different from one shown in this series - mine has no connectors with a row of disc caps - all connections are bulkhead feedthru caps. Can any body help a brutha out? Thanks!
Surprised about the processing time. What method are you using to measure the frequency input?
You mention pin 5 being used which is associated with the timers, another option is to use pulsein() which can use any pin (I think), but the key is that is will measure one pulse then return a value. It also has an optional timeout (default one sec) the docs say this method is good for 10uS to 3mins..
Andy
1/2.5 MHz = 400 ns
You should write your own counter routine. You could probably get away with just doing a sample every few tenths of a second or more. Your VCO drift shouldn't be that fast or that much so slow your sample rate down. And you should be able to do a minimal interrupt route that just copies the value of the counter to memory and then do the math later. You might still miss a click or two but it would be a lot less. And/or bake in a disable in so when the encoder is in use you just disable your counter.
I think you are right.
Why not simply suspend frequency counting while changing frequencies?
There is no reason why the Arduino cannot count 2.5 MHz on its hardware timer. Set the timer to interrupt on overflow and increment a volatile uint16_t variable in the service routine. It can EASILY do this 40 times per second. Pessimistically this 100 us/s duty cycle. Once per second in loop (), read the memory and the hardware timer to form a uint32_t count for display. (Shift left 6b = x64 first...) You can fabricate a union to store the variable, to hold a place to store the hardware count, and to be read as 32 bits. Don't forget to zero the count in preparation for the next second (or store the 32 bits for subtraction from the next read). But, the accuracy of the count is directly affected by the accuracy of the Arduino's oscillator (definition of '1 s') and calibration is only effective until that rate drifts.
yes, it does this just fine, it just cannot handle the interrupts from the front panel at the same time.
@@IMSAIGuy There should be only a few of those each second also. Check for switch bounce -- a lp filter and Schmidt trigger might be needed -- each bounce generates an interrupt. Otherwise, some code optimization might be needed. Be sure BOTH interrupts are generated reliably from the dial.
Investigate replacing the Arduino with a Teensy 4.0