I promised that my new shield could be "used as a general-purpose board with any system", so I thought I better put my money where my mouth is. I also thought it would be nice to re-visit the Raspberry Pi...
A quick search turned up this "library" (actually it is in Python, where such things properly are called "Modules") for driving the Si5351 from a Pi. I decided to give it a spin - so I (literally) dusted off my Pi.
First, I had to learn how to use I2C - which I'd never done before on this platform. Actually - that's a lie: first I had to remember how to log in to the Pi, but we won't embarrass ourselves by revealing that truth!
Firing up I2C in Raspberry-land involves a few easy steps, which are reasonably well covered in (e.g.) this instructable. If, like me, you have a 512MB Pi, note that the I2C channel is number 1 (not 0, as given in the instructable referenced here - and many other "how to" resources on the net).
Once you get all the soft resources in place on your Pi, you're in a position to make the hardware connections to the GPIO pins (SDA is pin 3 and SCL is pin 5 on my RPi model B). I used my fancy GPIO breakout, of course.
My first experiment used the Si5351 on the Adafruit breakout board - which you can see in the photo below...
With this hardware in place, I was able to test the I2C connection with the "I2CDETECT" command, which showed the Si5351 reporting for duty in her correct place (at 0x60)...
In the screen grab above, you can also see my call to the little program I wrote to set up the Si5351, using the resources in the "library" - man, was that a pain! This "library" is is re-work of the Adafruit (Arduino) library for the Si5351 (the quality of which I've commented upon before) and this resource is even weaker. There is pretty much zero documentation - so the little program below is just my very poor attempt to get something to run - which it manages to do...
Having satisfied myself that I could drive an Si5351 from the RPi, I hooked up the new prototype board. I emphasize there was NO ADDITIONAL INTERFACE HARDWARE USED - the new board can interface directly to the Pi or any other system - even with 3v3 logic (such as the Arduino DUE).
Here's the system on the bench - the Arduino UNO at top left of the photo was used to source the 3V3 and 12V to power the new board (the RPi's 3v3 output is only rated to supply up to 50 milliAmps and - of course - there's no 12V supply).
The screen grabs from the RPi desktop were made using the (comically named) "SCROT" and emailed to the computer on which I'm writing this drivel. Whilst this method works, it does seem awfully inefficient (having the image take a long detour through the internet when the two computers are only inches from one another). So - I took the opportunity to learn about installing a Windows-compatible network "share" on my Raspberry Pi. This is made possible through a program called Samba, which works very well.
The morals of this story are:
1) The new (prototype) Kanga / m0xpd / n6qw board works FB with the Raspberry Pi
2) Thank God for Jason, nt7s' EXCELLENT Si5351 (Arduino) library
3) There is (as far as I know) a gap in the market for an equivalent library / module for the RPi
4) Maybe - just maybe - I'll order that Model B Plus and/or a Model A Plus
...-.- de m0xpd
Tuesday 30 December 2014
Sunday 28 December 2014
Si5351 Shield
I'm excited to bring news of a new board - a flexible RF Generator, based upon the Si5351, including two channels of amplification and a quadrature generator...
The board is served up in an Arduino Shield format - but it can be used as a general-purpose board with any system. I've been playing with the design for a few weeks now and I'm delighted to tell that it is a real team effort. As before, all this is made possible by Dennis, g6ybc, of Kanga Products but this time we have been joined by Pete Juliano, n6qw.
The prototype PCBs were delivered to Dennis just before Christmas and it gave us just the excuse we needed to meet up (in a pub, of course) to exchange greetings and components...
I soon had the digital side of things checked and working (but I must give credit where it is due - Dennis soldered the tiny Si5351 onto the board) and I was able to confirm operation two days before Christmas.
You can see the part-built system in its test configuration atop an Arduino UNO here...
The system in this state is, in fact, pretty much a functional duplicate of the experimental Arduino shield I've described before.
The 2*6 header at top left of the photo above is an expanded version of the "RF Bus" on the Kanga / m0xpd DDS Shield, to give backward compatibility between this new RF Generator and the old DDS Shield (along with the other shields that interfaced to it). The expansion allows for the fact that there are now three independent frequencies on the bus - and I've made not only the Q and I available on the header (as on the DDS Shield) but also their complements, Not Q and Not I.
The red jumpers (bottom right in the photo above) select the I2C source - putting the jumpers in place connects the I2C signals to pins A4 and A5 on the Arduino shield (as is appropriate to e.g. an Arduino UNO) whilst leaving them off makes the I2C available on header pins, to be allocated as the user wishes.
I finished stuffing the rest of the board yesterday and winding the coils, as seen in the photo below, in which I'm making an analog test from one of the n6qw output amplifiers...
The shield has all three outputs of the Si5351 accessible on the header, as I've already explained, but two of them are further buffered by amplifiers designed by my friend Pete - aptly described as "afterburners" by Bill, n2cqr. Readers will understand why I'm interested in having two channels so buffered, given my interest in Dual DDS schemes etc..
The outputs of these amplifiers are isolated by transformers and are available on 0.1 inch headers - or on the mandatory SMA connectors if you're feeling flush!
The whole shebang is explained in this annotated picture...
We need a few minor board revisions before we're ready to go public (they really are revisions, rather than corrections) and then you will be in a position to try it for yourself.
2015 looks like being an exciting year.
...-.- de m0xpd
The board is served up in an Arduino Shield format - but it can be used as a general-purpose board with any system. I've been playing with the design for a few weeks now and I'm delighted to tell that it is a real team effort. As before, all this is made possible by Dennis, g6ybc, of Kanga Products but this time we have been joined by Pete Juliano, n6qw.
The prototype PCBs were delivered to Dennis just before Christmas and it gave us just the excuse we needed to meet up (in a pub, of course) to exchange greetings and components...
I soon had the digital side of things checked and working (but I must give credit where it is due - Dennis soldered the tiny Si5351 onto the board) and I was able to confirm operation two days before Christmas.
You can see the part-built system in its test configuration atop an Arduino UNO here...
The system in this state is, in fact, pretty much a functional duplicate of the experimental Arduino shield I've described before.
The 2*6 header at top left of the photo above is an expanded version of the "RF Bus" on the Kanga / m0xpd DDS Shield, to give backward compatibility between this new RF Generator and the old DDS Shield (along with the other shields that interfaced to it). The expansion allows for the fact that there are now three independent frequencies on the bus - and I've made not only the Q and I available on the header (as on the DDS Shield) but also their complements, Not Q and Not I.
The red jumpers (bottom right in the photo above) select the I2C source - putting the jumpers in place connects the I2C signals to pins A4 and A5 on the Arduino shield (as is appropriate to e.g. an Arduino UNO) whilst leaving them off makes the I2C available on header pins, to be allocated as the user wishes.
I finished stuffing the rest of the board yesterday and winding the coils, as seen in the photo below, in which I'm making an analog test from one of the n6qw output amplifiers...
The shield has all three outputs of the Si5351 accessible on the header, as I've already explained, but two of them are further buffered by amplifiers designed by my friend Pete - aptly described as "afterburners" by Bill, n2cqr. Readers will understand why I'm interested in having two channels so buffered, given my interest in Dual DDS schemes etc..
The outputs of these amplifiers are isolated by transformers and are available on 0.1 inch headers - or on the mandatory SMA connectors if you're feeling flush!
The whole shebang is explained in this annotated picture...
We need a few minor board revisions before we're ready to go public (they really are revisions, rather than corrections) and then you will be in a position to try it for yourself.
2015 looks like being an exciting year.
...-.- de m0xpd
Sunday 21 December 2014
Arduino SDR IV
Time to try once again to squeeze a quart into a pint pot...
One of the failings of my Arduino SDR, with its limited (12-bit) input stage, is the tendency to be swamped by big guns. The resulting distortion is of the particularly ugly "digital" variety that takes no prisoners.
At present, I'm dealing with this by knocking my ATU way off tune whenever a strong station comes on - but this is hardly an elegant solution.
Sure - I could add a simple potentiometer on the RF input - but that would never be addressable by anything other than my hand - barely an improvement over the ATU approach. I thought about adding a digital potentiometer at the RF input - but a quick look at the data sheets reveals that this approach is a non-starter.
Accordingly, I decided to play with a digital potentiometer in the "IF" of my software-defined radio which (of course) is actually in the high audio frequency range.
I happened to have an AD5242 in the "junk box" - as used in the experiments with the Digital Tube Screamer. This is a two-channel device (I needed a two-channel device to scale both the In-phase and Quadrature components of my system). The particular AD5242 in my collection was the 1MOhm variant.
The device features an I2C digital interface - which was a bit of a concern, as I'd never had much joy with I2C and the Arduino DUE.
Fortunately, Rob Tillaart's library seemed to compile fine for the DUE and worked pretty much first time (once I had figured which of the two available I2C interfaces on the DUE was being used, with the help of my Ripoff logic analyser). I soon had the DUE talking to the AD5242 and implementing various resistances, tracking d.c. voltages read from a potentiometer...
Having confirmed I could control resistor values at will from the DUE, I thought about building a twin-channel, variable gain amplifier. It uses another Analog Devices chip from the "junk box", this time a quad OpAmp, which will run on a 3v3 supply - the AD8608...
Now, the physical potentiometer generates a voltage which is read into the DUE and then generates a control code to set the GAIN of the amplifiers. This gain varies between 6.5 dB and -41.5 dB. The (partial) schematic below gives you an idea of what I'm up to...
So - now the variable gain amplifier is added into the SDR receiver's input path...
It is, as you can see, very much a temporary "lash-up" at this stage. But it works fine. I have the ability to take shelter when the big guns open up. I also have a little more gain available to increase overall sensitivity. Plus, I've retained the variable receive bandwidth control from before.
But what - you might ask - is the advantage over putting the potentiometer on the RF input, just as I mentioned at the top of this post? Well...
One day soon, I will be able to allow the DUE to take over control of the AD5242 - to give automatic level control.
For the moment, I'll satisfy myself with manual control and focus on those other distractions the next few days have to offer.
...-.- de m0xpd
One of the failings of my Arduino SDR, with its limited (12-bit) input stage, is the tendency to be swamped by big guns. The resulting distortion is of the particularly ugly "digital" variety that takes no prisoners.
At present, I'm dealing with this by knocking my ATU way off tune whenever a strong station comes on - but this is hardly an elegant solution.
Sure - I could add a simple potentiometer on the RF input - but that would never be addressable by anything other than my hand - barely an improvement over the ATU approach. I thought about adding a digital potentiometer at the RF input - but a quick look at the data sheets reveals that this approach is a non-starter.
Accordingly, I decided to play with a digital potentiometer in the "IF" of my software-defined radio which (of course) is actually in the high audio frequency range.
I happened to have an AD5242 in the "junk box" - as used in the experiments with the Digital Tube Screamer. This is a two-channel device (I needed a two-channel device to scale both the In-phase and Quadrature components of my system). The particular AD5242 in my collection was the 1MOhm variant.
The device features an I2C digital interface - which was a bit of a concern, as I'd never had much joy with I2C and the Arduino DUE.
Fortunately, Rob Tillaart's library seemed to compile fine for the DUE and worked pretty much first time (once I had figured which of the two available I2C interfaces on the DUE was being used, with the help of my Ripoff logic analyser). I soon had the DUE talking to the AD5242 and implementing various resistances, tracking d.c. voltages read from a potentiometer...
Having confirmed I could control resistor values at will from the DUE, I thought about building a twin-channel, variable gain amplifier. It uses another Analog Devices chip from the "junk box", this time a quad OpAmp, which will run on a 3v3 supply - the AD8608...
Now, the physical potentiometer generates a voltage which is read into the DUE and then generates a control code to set the GAIN of the amplifiers. This gain varies between 6.5 dB and -41.5 dB. The (partial) schematic below gives you an idea of what I'm up to...
So - now the variable gain amplifier is added into the SDR receiver's input path...
It is, as you can see, very much a temporary "lash-up" at this stage. But it works fine. I have the ability to take shelter when the big guns open up. I also have a little more gain available to increase overall sensitivity. Plus, I've retained the variable receive bandwidth control from before.
But what - you might ask - is the advantage over putting the potentiometer on the RF input, just as I mentioned at the top of this post? Well...
One day soon, I will be able to allow the DUE to take over control of the AD5242 - to give automatic level control.
For the moment, I'll satisfy myself with manual control and focus on those other distractions the next few days have to offer.
...-.- de m0xpd
Sunday 14 December 2014
R(F)duino DUE
An idle moment this weekend gave me opportunity to upgrade the R(F)duino to include the Si5351...
You've seen the original R(F)duino with its brace of AD9850 DDS modules, doing fine service in the Parallel IF rig. That system, being first, now should be called R(F)duino "UNO" (not that we're being influenced here).
Readers will know that I'm keen on the little Si5351 device, which offers a number of advantages over the AD9850s. Having already used the Si5351 in my RF generator scheme in the Breadboard BITX, I was keen to make a custom system - thus was born the second R(F)duino - the "DUE"...
As you see, I took very much a "minimum effort" approach to development of the DUE, simply plagiarising my design for the greater part of the UNO and swapping out the left hand side (as seen in the orientation above). The board has stayed at its rather large size for two reasons - first to accommodate all the connectors and second to make an easy retro-fit into the Parallel IF rig!
The features of the R(F)duino DUE are highlighted in the following annotated picture...
The schematic is here...
The code is essentially the Si5351 code that already has been published (but with extensions to support the Parallel IF functions, band change and SSB / CW transmit, which are some of the extra features of my transceiver). I couldn't resist differentiating it with a childish change of the banner line, just for this photo, taken during testing...
Now I need another idle moment or two to swap out the old R(F)duino in the Parallel IF rig for this new, improved, DUE version. I've just looked at the Christmas double issue of the Radio Times - doesn't look like there will be any trouble finding idle moments!
...-.- de m0xpd
You've seen the original R(F)duino with its brace of AD9850 DDS modules, doing fine service in the Parallel IF rig. That system, being first, now should be called R(F)duino "UNO" (not that we're being influenced here).
Readers will know that I'm keen on the little Si5351 device, which offers a number of advantages over the AD9850s. Having already used the Si5351 in my RF generator scheme in the Breadboard BITX, I was keen to make a custom system - thus was born the second R(F)duino - the "DUE"...
As you see, I took very much a "minimum effort" approach to development of the DUE, simply plagiarising my design for the greater part of the UNO and swapping out the left hand side (as seen in the orientation above). The board has stayed at its rather large size for two reasons - first to accommodate all the connectors and second to make an easy retro-fit into the Parallel IF rig!
The features of the R(F)duino DUE are highlighted in the following annotated picture...
The schematic is here...
The code is essentially the Si5351 code that already has been published (but with extensions to support the Parallel IF functions, band change and SSB / CW transmit, which are some of the extra features of my transceiver). I couldn't resist differentiating it with a childish change of the banner line, just for this photo, taken during testing...
Now I need another idle moment or two to swap out the old R(F)duino in the Parallel IF rig for this new, improved, DUE version. I've just looked at the Christmas double issue of the Radio Times - doesn't look like there will be any trouble finding idle moments!
...-.- de m0xpd
Thursday 11 December 2014
Parallel IF
Now that the January 2015 number of RadCom has started hitting the newsstands (even though I'm still looking forward to Christmas), I guess the cat is out of the bag...
The journal contains my article "A parallel filter architecture for flexible IF processing" (page 78) which - in turn - prompts me to reveal the true identity of the rig which I have been struggling to conceal in these pages for the past year.
What I have been clumsily calling the "multi-band rig" or (worse still) the "multi-band, BITX-inspired development platform" is, in fact, the Parallel IF rig...
I explain in the RadCom article how and why two ordinary crystal filters with disjoint pass-bands can sit next to each other - in parallel - quite comfortably. If these filters have different bandwidths, the whole rig can change receiving bandwidth simply by using the appropriate IF frequency required to select one or other of the filters. NO SWITCHING of any kind is required - just a change of oscillator frequencies.
You can imagine how easy this change of oscillator frequencies is to achieve with the RF Generator scheme that Pete Juliano and I already have published in SPRAT 158 and described in many blog posts, as summarised on this page.
The Parallel IF rig pictured above has two such crystal filters, between two of the ordinary bidirectional amplifiers familiar to builders of the BITX...
You can see my embodiments of these filters in the following photo, in which you'll note the absence of switches, relays and the like...
The software of the Parallel IF rig is a super-set of the m0xpd "Dual DDS" code - it includes an additional menu option to switch between the two IF frequencies required to operate one or other of the IF filters.
It is presented (of course) simply as a choice between the two receiving bandwidths...
The scheme works - very well.
Two weeks ago I presented a method for directly visualising overall receiving response - from RF to audio (magnitude) frequency response. Now you understand why!
With the disclosure of my new Parallel IF architecture, it is now time to use the new measurement method in anger...
Here's the measured response of the Parallel IF rig in SSB mode (a result you've already seen)...
Here's what happens if you keep the tuning the same but "switch" to the alternative IF path, giving a tighter overall response, appropriate to CW...
Formally, this is what might usually be called CW(R) mode as it is in lower side band; CW is more usually received in USB - this is just a convenience associated with the technique I've used to send CW from my rig, as described in SPRAT 159. The method works just as well with CW in USB - but would not allow a direct comparison with LSB reception in 40m, as above.
RSGB members can learn more about the method from the article in their copy of RadCom - other readers will be hearing very much more about the method over the coming months.
I am honoured to be working with Pete Juliano, n6qw, on the development of a new rig - a project specifically to showcase this "Parallel IF" principle. We will be publishing construction details of this new rig in 2015, hopefully in QRP Quarterly (subject to confirmation).
I am further honoured to have been invited to speak at QRP ARCI's Four Days in May 2015 - "the biggest and best QRP event in the World" (at least it was, before they invited me along HI HI).
You will not be surprised to hear that my subject will be this new method of achieving variable receive bandwidth in simple superhet rigs at very low cost.
I'm excited about it!
...-.- de m0xpd
The journal contains my article "A parallel filter architecture for flexible IF processing" (page 78) which - in turn - prompts me to reveal the true identity of the rig which I have been struggling to conceal in these pages for the past year.
What I have been clumsily calling the "multi-band rig" or (worse still) the "multi-band, BITX-inspired development platform" is, in fact, the Parallel IF rig...
I explain in the RadCom article how and why two ordinary crystal filters with disjoint pass-bands can sit next to each other - in parallel - quite comfortably. If these filters have different bandwidths, the whole rig can change receiving bandwidth simply by using the appropriate IF frequency required to select one or other of the filters. NO SWITCHING of any kind is required - just a change of oscillator frequencies.
You can imagine how easy this change of oscillator frequencies is to achieve with the RF Generator scheme that Pete Juliano and I already have published in SPRAT 158 and described in many blog posts, as summarised on this page.
The Parallel IF rig pictured above has two such crystal filters, between two of the ordinary bidirectional amplifiers familiar to builders of the BITX...
You can see my embodiments of these filters in the following photo, in which you'll note the absence of switches, relays and the like...
The software of the Parallel IF rig is a super-set of the m0xpd "Dual DDS" code - it includes an additional menu option to switch between the two IF frequencies required to operate one or other of the IF filters.
It is presented (of course) simply as a choice between the two receiving bandwidths...
The scheme works - very well.
Two weeks ago I presented a method for directly visualising overall receiving response - from RF to audio (magnitude) frequency response. Now you understand why!
With the disclosure of my new Parallel IF architecture, it is now time to use the new measurement method in anger...
Here's the measured response of the Parallel IF rig in SSB mode (a result you've already seen)...
Here's what happens if you keep the tuning the same but "switch" to the alternative IF path, giving a tighter overall response, appropriate to CW...
Formally, this is what might usually be called CW(R) mode as it is in lower side band; CW is more usually received in USB - this is just a convenience associated with the technique I've used to send CW from my rig, as described in SPRAT 159. The method works just as well with CW in USB - but would not allow a direct comparison with LSB reception in 40m, as above.
RSGB members can learn more about the method from the article in their copy of RadCom - other readers will be hearing very much more about the method over the coming months.
I am honoured to be working with Pete Juliano, n6qw, on the development of a new rig - a project specifically to showcase this "Parallel IF" principle. We will be publishing construction details of this new rig in 2015, hopefully in QRP Quarterly (subject to confirmation).
I am further honoured to have been invited to speak at QRP ARCI's Four Days in May 2015 - "the biggest and best QRP event in the World" (at least it was, before they invited me along HI HI).
You will not be surprised to hear that my subject will be this new method of achieving variable receive bandwidth in simple superhet rigs at very low cost.
I'm excited about it!
...-.- de m0xpd
Sunday 7 December 2014
Continual Interruptions
This is the story of doing the job properly: tracking the rotation of rotary encoders using an interrupt-based approach. The story leads to updated versions of the m0xpd VFO code for AD9850 and Si5351 systems.
I have explained how a desire for simplicity kept the early designs published on this blog based on a simple "polled" rotary encoder architecture. In truth, there was a little more to it than just a "desire for simplicity"...
The Kanga / m0xpd DDS shield has a user-configurable pin assignment for the DDS module pins. However, it is biased towards the use of pins D2:D5 - these are the easiest pin allocations to make, as you see in the photo above. This will use up the pins D2 and D3 on the Arduino UNO which are the only two which support hardware interrupts. Accordingly, the systems which used the DDS shield tended to occupy pins D2 and D3, making interrupts inaccessible.
Ever since the appearance of the Dual DDS scheme and, specifically, its embodiment in the R(F)duino, I have intentionally freed up pins 2 and 3 for the Rotary encoder in my own builds, with the intention of - one day - moving to an interrupt-driven interface.
That day has arrived.
Its arrival was ushered in by two additional factors. First was the appearance of the Si5351, which sits on the I2C interface and completely frees up all the digital pins originally squandered on the DDS module. Second - and most important - was inspiration from Tom Hall, ak2b's beautiful receiver, which I saw on Tom's You Tube video. Correspondence with Tom finally persuaded me I HAD to act...
The problem with the original "polling" interface is one of visibility - the encoder is largely invisible to the code.
It is as if the encoder is obscured behind a brick wall, glimpsed only for an instant within the course of each execution of the main program loop, through a gap in the wall...
The code executing in the continuous "loop" function passes this "gap" in the wall only once per cycle and has to look for a change in the encoder's state since the last time the device was polled. It is seen that there is a rather precarious dependence upon the time it takes for the other tasks which the code has to perform in the one pass around the loop (and, hence the sample rate) and the speed of rotation. This explains my recent preoccupation with capacitors on the encoder output!
The code associated with this polling approach is not elegant, dealing - as it must - with the consequences of the two possible changes in observed state...
By contrast, the interrupt approach allows a complete brick wall between loop( ) and the encoder, but establishes a second process - the Interrupt Service Routine ('ISR')- to count the pulses from the encoder.
The ISR has 20:20 vision of the encoder.
In my implementation, I've arranged for the Interrupt Service Routine to maintain a variable, "Turns", which counts the number of "clicks" from a start time until reset. Clockwise rotation adds to the count, whilst counter-clockwise subtracts...
In the new code, the main program loop (which, in the user-friendly world of the Arduino, is called "loop( )") has vision of the count variable, "Turns", AND can reset it back to zero.
The frequency adjustment routine, equivalent to the one above, now becomes...
Notice that if more than one "Turn" event occurs in one pass through the loop( ) it is is now handled correctly, rather than just counted as one (or missed altogether). Accordingly, the frequency adjustment (etc) is very much smoother.
The new interface to the rotary encoder depends upon an Arduino library, Rotary, which can be downloaded from Przemek, sq9nje's Github repository.
I have used the new interrupt handling approach to produce a revised version of the Dual DDS VFO code and the Si5351 VFO Code, both of which can be found here. Reports, please, from anybody who tries them (I've tested "personal" versions of these new interrupt-driven programs with great results in my own rigs, including the Breadboard BITX and the Multi-band rig).
The same methods can be used by readers who wish to modify any of the previous m0xpd systems (such as the Occam's projects or the Kanga VFO systems) but this will require re-allocation of pins 2 and 3 which presently are assigned to the DDS - a simple enough task.
...-.- de m0xpd
I have explained how a desire for simplicity kept the early designs published on this blog based on a simple "polled" rotary encoder architecture. In truth, there was a little more to it than just a "desire for simplicity"...
The Kanga / m0xpd DDS shield has a user-configurable pin assignment for the DDS module pins. However, it is biased towards the use of pins D2:D5 - these are the easiest pin allocations to make, as you see in the photo above. This will use up the pins D2 and D3 on the Arduino UNO which are the only two which support hardware interrupts. Accordingly, the systems which used the DDS shield tended to occupy pins D2 and D3, making interrupts inaccessible.
Ever since the appearance of the Dual DDS scheme and, specifically, its embodiment in the R(F)duino, I have intentionally freed up pins 2 and 3 for the Rotary encoder in my own builds, with the intention of - one day - moving to an interrupt-driven interface.
That day has arrived.
Its arrival was ushered in by two additional factors. First was the appearance of the Si5351, which sits on the I2C interface and completely frees up all the digital pins originally squandered on the DDS module. Second - and most important - was inspiration from Tom Hall, ak2b's beautiful receiver, which I saw on Tom's You Tube video. Correspondence with Tom finally persuaded me I HAD to act...
The problem with the original "polling" interface is one of visibility - the encoder is largely invisible to the code.
It is as if the encoder is obscured behind a brick wall, glimpsed only for an instant within the course of each execution of the main program loop, through a gap in the wall...
The code executing in the continuous "loop" function passes this "gap" in the wall only once per cycle and has to look for a change in the encoder's state since the last time the device was polled. It is seen that there is a rather precarious dependence upon the time it takes for the other tasks which the code has to perform in the one pass around the loop (and, hence the sample rate) and the speed of rotation. This explains my recent preoccupation with capacitors on the encoder output!
The code associated with this polling approach is not elegant, dealing - as it must - with the consequences of the two possible changes in observed state...
By contrast, the interrupt approach allows a complete brick wall between loop( ) and the encoder, but establishes a second process - the Interrupt Service Routine ('ISR')- to count the pulses from the encoder.
The ISR has 20:20 vision of the encoder.
In my implementation, I've arranged for the Interrupt Service Routine to maintain a variable, "Turns", which counts the number of "clicks" from a start time until reset. Clockwise rotation adds to the count, whilst counter-clockwise subtracts...
In the new code, the main program loop (which, in the user-friendly world of the Arduino, is called "loop( )") has vision of the count variable, "Turns", AND can reset it back to zero.
The frequency adjustment routine, equivalent to the one above, now becomes...
Notice that if more than one "Turn" event occurs in one pass through the loop( ) it is is now handled correctly, rather than just counted as one (or missed altogether). Accordingly, the frequency adjustment (etc) is very much smoother.
The new interface to the rotary encoder depends upon an Arduino library, Rotary, which can be downloaded from Przemek, sq9nje's Github repository.
I have used the new interrupt handling approach to produce a revised version of the Dual DDS VFO code and the Si5351 VFO Code, both of which can be found here. Reports, please, from anybody who tries them (I've tested "personal" versions of these new interrupt-driven programs with great results in my own rigs, including the Breadboard BITX and the Multi-band rig).
The same methods can be used by readers who wish to modify any of the previous m0xpd systems (such as the Occam's projects or the Kanga VFO systems) but this will require re-allocation of pins 2 and 3 which presently are assigned to the DDS - a simple enough task.
...-.- de m0xpd
Subscribe to:
Posts (Atom)