Showing posts with label Minima. Show all posts
Showing posts with label Minima. Show all posts
Saturday, October 1, 2016
Updated Si570 code on GitHub
Well, I have finally updated my Si570 code on GitHub to reflect the changes to fix a bug found and blogged about over two years ago. I described the fix here, but failed to follow through and update the code on GitHub with the changes. Long past due, but glad to have that task off my TODO list.
Thursday, March 26, 2015
Minima - Again?
I have been back playing around a little bit with the Minima code the last couple of days. I have also been looking at TFT displays for my microcontroller projects. While not really a hobbyist price range, I stumbled over a nice group of displays from 4D Systems in Australia (www.4dsystems.com.au) that allow you to easily create some very nice displays without a lot of programming and simple serial interfaces to them that operate at high speeds and offload graphics drawing tasks to the display which sports its own processor.
You design the display layout on the desktop computer and save the user-interface elements to a micro-SD card that then plugs into the display. Interface to the micro-controller is transmit/receive data, ground, 5V and reset. Easy Peasy...
Here is an example display for the Minima that I have been tinkering with. Not bad for a first attempt. (I am not the best UI designer... Ok, I suck at it...)
So, it will be fun to see where this leads. Being a touch screen (they have both TFT and CAP Touch available) it can be used for input as well as output. I am using the simplified tools that have a selection of UI elements that can be placed, sized and programmed on the display as well as Arduino and Raspberry PI libraries to encapsulate the serial communications protocol. There is also the ability to talk to the lower level primitives, so we will have to scope that out as well.
More to come...
You design the display layout on the desktop computer and save the user-interface elements to a micro-SD card that then plugs into the display. Interface to the micro-controller is transmit/receive data, ground, 5V and reset. Easy Peasy...
Here is an example display for the Minima that I have been tinkering with. Not bad for a first attempt. (I am not the best UI designer... Ok, I suck at it...)
So, it will be fun to see where this leads. Being a touch screen (they have both TFT and CAP Touch available) it can be used for input as well as output. I am using the simplified tools that have a selection of UI elements that can be placed, sized and programmed on the display as well as Arduino and Raspberry PI libraries to encapsulate the serial communications protocol. There is also the ability to talk to the lower level primitives, so we will have to scope that out as well.
More to come...
Sunday, December 28, 2014
BPSK vs. FSK/MSK
In a previous post I pondered briefly about BPSK (used in PSK31) as compared to FSK. Instead of traditional frequency-shift keying, in BPSK information is transmitted by patterns of polarity-reversals (sometimes called 180-degree phase shifts). One way to think about this would be to swap antenna terminals on each phase reversal.
BPSK uses a 180 degree phase shift when encoding a zero bit in a varicode character. By way of review, BPSK uses a sinusoid of constant amplitude and a 180 degree phase shift to represent a binary 1 as opposed to a binary 0.
Now, the problem with this in radio circuits is the phase reversal if hard keyed will result in a lot of splatter and the accompanying bandwidth. So, in radio circuits as discussed in my series about PSK31 on the arduino, we typically ramp the sinusoid level down to zero at the phase change points to eliminate this splatter and shift the phase reversal to the middle of the bit time. PSK31 encodes a zero bit as a phase reversal and a one bit as no phase change. In other aspects however PSK31 is BPSK.
In thinking about BPSK vs. FSK or more accurately, MSK (Minimum Shift Keying) I found myself pondering whether they are functionally equivalent.
MSK is basically FSK with the shift set to ½ the baud rate. Realistically this is the smallest shift you can use without trading off transmission speed. PSK31 uses a 31.25 baud transmission speed. So, if we were going to encode a 31.25 baud data transmission using MSK, our keying shift would be 1/4 of the data rate either side of the transmit center frequency.
31.25 baud / 2 = 15.625 / 2 = 7.8125 Hz
If you think of the phase of a carrier that is 7.8125 Hz below the transmit center frequency, it will lag by 90 degrees after 32 mS, and at 7.8125 Hz above, it will lead by 90 degrees after 32 mS for a difference of 180 degrees.
So MSK appears to be functionally equivalent to BPSK while using +90 and -90 degree shifts instead of 0 and 180 degree shifts.
An advantage to this approach is that the resultant signal has no amplitude modulated component and so non-linear amplification techniques may be utilized greatly simplifying transmitter design. It does require the ability to do phase continuous frequency changes however.
Hmm...
Ok, so to give this concept a play around, I decided to use all the recent work I did on the Minima to implement 1 Hz tuning on the Si570 and see if I could implement a decode-able PSK31 varicode message using MSK techniques with the Si570.
The Si570 is technically capable of 0.42 Hz frequency precision, but for this experiment, I will use 8 Hz as the frequency shift above and below the transmit frequency instead of 7.8125 Hz.
At 7.8125 Hz, 360 degrees of phase change takes 128 ms. 90 degrees of phase change requires 128/4 = 32 ms.
At 8 Hz, 360 degrees of phase change takes 125 ms. 90 degrees of phase change requires 125/4 = 31.25 ms.
I suspect that most PSK31 decoding applications will be able to deal with this difference.
Having modified my recent PSK31 code to drive the Si570 oscillator rather than generate audio, I have run into a number of problems. I suspected that the i2c communications library that comes with the Arduino IDE would require interrupts to be enabled, which is true. If you try to call the Si570 code from within a timer interrupt, it will hang the device.
Enabling interrupts around the Si570 call within the timer ISR cures the hanging problem, but fails to communicate with the Si570 to set the frequency. I suspect that while the library is returning quickly, the i2c communications doesn't complete until sometime later.
Moving the setFrequency() call out of the ISR generates MSK, but it appears that there are bits being lost. The ISR is completing in 1.040 us, but is not accurately generating all of the frequency shifts. My suspicion is that the wire library is returning quickly, but that its own interrupt are not completing in a timely fashion to allow precise control over when frequency shifts are happening. I will have to do some measurements on the i2c communications and put some debugging pin toggles in the wire library to measure how long things are taking to complete.
More to come...
BPSK uses a 180 degree phase shift when encoding a zero bit in a varicode character. By way of review, BPSK uses a sinusoid of constant amplitude and a 180 degree phase shift to represent a binary 1 as opposed to a binary 0.
Now, the problem with this in radio circuits is the phase reversal if hard keyed will result in a lot of splatter and the accompanying bandwidth. So, in radio circuits as discussed in my series about PSK31 on the arduino, we typically ramp the sinusoid level down to zero at the phase change points to eliminate this splatter and shift the phase reversal to the middle of the bit time. PSK31 encodes a zero bit as a phase reversal and a one bit as no phase change. In other aspects however PSK31 is BPSK.
In thinking about BPSK vs. FSK or more accurately, MSK (Minimum Shift Keying) I found myself pondering whether they are functionally equivalent.
MSK is basically FSK with the shift set to ½ the baud rate. Realistically this is the smallest shift you can use without trading off transmission speed. PSK31 uses a 31.25 baud transmission speed. So, if we were going to encode a 31.25 baud data transmission using MSK, our keying shift would be 1/4 of the data rate either side of the transmit center frequency.
31.25 baud / 2 = 15.625 / 2 = 7.8125 Hz
If you think of the phase of a carrier that is 7.8125 Hz below the transmit center frequency, it will lag by 90 degrees after 32 mS, and at 7.8125 Hz above, it will lead by 90 degrees after 32 mS for a difference of 180 degrees.
So MSK appears to be functionally equivalent to BPSK while using +90 and -90 degree shifts instead of 0 and 180 degree shifts.
An advantage to this approach is that the resultant signal has no amplitude modulated component and so non-linear amplification techniques may be utilized greatly simplifying transmitter design. It does require the ability to do phase continuous frequency changes however.
Hmm...
Ok, so to give this concept a play around, I decided to use all the recent work I did on the Minima to implement 1 Hz tuning on the Si570 and see if I could implement a decode-able PSK31 varicode message using MSK techniques with the Si570.
The Si570 is technically capable of 0.42 Hz frequency precision, but for this experiment, I will use 8 Hz as the frequency shift above and below the transmit frequency instead of 7.8125 Hz.
At 7.8125 Hz, 360 degrees of phase change takes 128 ms. 90 degrees of phase change requires 128/4 = 32 ms.
At 8 Hz, 360 degrees of phase change takes 125 ms. 90 degrees of phase change requires 125/4 = 31.25 ms.
I suspect that most PSK31 decoding applications will be able to deal with this difference.
Having modified my recent PSK31 code to drive the Si570 oscillator rather than generate audio, I have run into a number of problems. I suspected that the i2c communications library that comes with the Arduino IDE would require interrupts to be enabled, which is true. If you try to call the Si570 code from within a timer interrupt, it will hang the device.
Enabling interrupts around the Si570 call within the timer ISR cures the hanging problem, but fails to communicate with the Si570 to set the frequency. I suspect that while the library is returning quickly, the i2c communications doesn't complete until sometime later.
Moving the setFrequency() call out of the ISR generates MSK, but it appears that there are bits being lost. The ISR is completing in 1.040 us, but is not accurately generating all of the frequency shifts. My suspicion is that the wire library is returning quickly, but that its own interrupt are not completing in a timely fashion to allow precise control over when frequency shifts are happening. I will have to do some measurements on the i2c communications and put some debugging pin toggles in the wire library to measure how long things are taking to complete.
More to come...
Thursday, November 6, 2014
New Minima-like build
My good friend Wayne NB6M has kindly loaned me his Minima-like build using my controller shield for the Arduino. His front panel is very similar to his original Minima build, but is now sporting a 20x4 display. He has removed the reset button from the front panel and added input for paddles in anticipation of me actually finishing the integration of my keyer code to the Minima code base.
Looking at the back of the panel, we can see the Arduino Uno and my controller shield mounted on the back of the display board. Wayne has used #12 bare copper wire soldered to the front panel to provide attach points for the Uno and shield. My shield will be modified to provide through-hole plating and solder pads so that it can be soldered in place.
The display board has been converted to i2c with a backpack board and the rotary encoder uses pins freed up by display being converted to i2c. The current shield design does not incorporate the proposed pins for the encoder from the discussion list, but will be modified in the final run to be compliant.
Wayne is using a pretty conventional IF strip from the Minima, but has chosen to replace the KISS mixer and BFO mixer with ADE-1 devices. His audio section is from a pre-existing project re-purposed for this project. The two SMA connectors connect to the VFO and BFO Si570 outputs from my controller shield. No low pass filter sections yet. The current configuration makes a pretty nice general coverage receiver.
I have handed off Wayne's other Minima build to Eldon so he will have a working radio to test with during his software development efforts.
Looking at the back of the panel, we can see the Arduino Uno and my controller shield mounted on the back of the display board. Wayne has used #12 bare copper wire soldered to the front panel to provide attach points for the Uno and shield. My shield will be modified to provide through-hole plating and solder pads so that it can be soldered in place.
The display board has been converted to i2c with a backpack board and the rotary encoder uses pins freed up by display being converted to i2c. The current shield design does not incorporate the proposed pins for the encoder from the discussion list, but will be modified in the final run to be compliant.
Wayne is using a pretty conventional IF strip from the Minima, but has chosen to replace the KISS mixer and BFO mixer with ADE-1 devices. His audio section is from a pre-existing project re-purposed for this project. The two SMA connectors connect to the VFO and BFO Si570 outputs from my controller shield. No low pass filter sections yet. The current configuration makes a pretty nice general coverage receiver.
I have handed off Wayne's other Minima build to Eldon so he will have a working radio to test with during his software development efforts.
Thursday, October 23, 2014
Minima controller shield - Using second Si570 as BFO.
I have implemented changes to the Minima controller code developed by Eldon Brown (WA0UWH) and others to use the second Si570 on my controller shield as the BFO oscillator. This change allows easy setting of your Minima BFO oscillator frequency to the desired point on your crystal filter passband curve, be that at the -3 dB point or further down the skirt.
The IF edit mode of the controller firmware will allow the adjustment of the BFO frequency. Separate frequencies are maintained for USB and LSB.
A separate issue is regarding the calibration of both of the Si570 devices on the shield against some frequency standard. For most folks that have a crystal oscillator for the BFO, the IF edit mode has probably been used to calibrate the dial to some frequency standard and this is fine. However adjusting the IF frequency offset from the displayed frequency only allows you to match the value that the controller uses to whatever frequency your crystal oscillator BFO is tuned to whereas with the second Si570, you can actually move the BFO frequency in software which is not the same thing as calibrating the dial.
The calibration of the Si570 devices as I see it is a separate matter from setting the desired BFO frequency as you certainly don't want to change where the BFO frequency sits on the IF passband just to calibrate the dial. So, I anticipate providing a different mechanism that will allow moving the VFO frequency (and BFO frequency for those using a second Si570 as the BFO oscillator) without changing the displayed frequency in order to determine the error offset for each Si570. This error offset can then be stored in eePROM and applied automatically from that point forward to the appropriate Si570.
More to come on this topic...
Sunday, October 19, 2014
Updated Minima Rotary Encoder Driver
The implementation uses pin-change interrupts for both the A and B inputs from the encoder. A side effect of this is that you cannot pick completely arbitrary pins for the A and B inputs to the Arduino. They must both be on the same port (PORTB, PORTC, PORTD). My minima shield uses digital pins 8 and 9 freed up by replacing the 6 wire LCD with an i2c display. Another option would be to use PD6 and PD7. PD7 is currently targeted to be used by the RF386 amplifier. However, the tuning control pot input A2 could be used freeing up PD6 and PD7 (both on PORTD) for use by the rotary encoder.
When an interrupt is received, the encoder is read and if it has changed, a 3ms debounce timer is reset. As long as the pins continue to interrupt, the debounce timeout continues to be reset. When the debounce timer expires, the encoder hasn't changed in the last 3ms and the value is processed.
I have provided integration to Eldon Brown's (WA0UWH) radiono code and completed initial testing. I have turned it over to him to release with his code if he wishes to do so.
In general there are three basic functions that need to be implemented to support rotary encoders.
- Set up pin change interrupts for encoder A and B inputs.
- Set up debounce timer
- Implement interrupt service routines (ISR) for pin change and timer
The following bunch of noise is to try to minimize the number of changes required in order to change the pins the encoder is connected to. The implementation represents a balance between providing pin change support for a Minima radio that can be configured as compared to a general purpose (large) library that can be configured in any way desired on any hardware platform. If you wish to use analogue aliases for encoder pin numbers (A0-A5) you should instead use 14-19 (the digital pin equivalent numbers).
It should be noted that all of this (currently) only works on the ATMega328 such as is found in the Minima, Arduino UNO, etc. Specifically support for the ATMega2560 is not yet implemented.
// Encoder pins
#define ENC_A_PIN 8 // Change these as desired, but both pins must be on
#define ENC_B_PIN 9 // the same port (PB, PC, PD)
// Pin change interrupts
// Digital pin PC Pin Vector Ctl Reg Port PCICR Bit Pin Mask Reg
// D0-D7 PCINT16-23 PCINT2_vect PCIR2 PD PCIE2 PCMSK2
// D8-D13 PCINT0-5 PCINT0_vect PCIR0 PB PCIE0 PCMSK0
// D14-D19 (A0-A5) PCINT8-13 PCINT1_vect PCIR1 PC PCIE1 PCMSK1
// Define the interrupt vector, interrupt enable bit, PCINTpin values
#if (ENC_A_PIN) >= 0 && (ENC_A_PIN) <= 7
#define VECTOR PCINT2_vect
#define PCMask PCMSK2
#define PCICRbit (1<<PCIE2)
#define PCINTpinA (1<<(ENC_A_PIN))
#define PCINTpinB (1<<(ENC_B_PIN))
#endif
#if (ENC_A_PIN) >= 8 && (ENC_A_PIN) <= 13
#define VECTOR PCINT0_vect
#define PCMask PCMSK0
#define PCICRbit (1<<PCIE0)
#define PCINTpinA (1<<(ENC_A_PIN-8))
#define PCINTpinB (1<<(ENC_B_PIN-8))
#endif
#if (ENC_A_PIN) >= 14 && (ENC_A_PIN) <= 19
#define VECTOR PCINT1_vect
#define PCMask PCMSK1
#define PCICRbit (1<<PCIE1)
#define PCINTpinA (1<<(ENC_A_PIN-14))
#define PCINTpinB (1<<(ENC_B_PIN-14))
#endif
Ok, so all that noise is defining a bunch of things that change when you change the encoder pin numbers. Specifically, you need to define the interrupt vector, the pin mask used and the pin change interrupt enable bit used.
The encoder returns a Gray code which I normalize to a 0..3 value. Specific patterns of values are compared to determine the encoder direction of rotation.
// Encoder patterns for clockwise and anti-clockwise rotation
static const int CCW_DIR[] = {0x01, 0x03, 0x00, 0x02};
static const int CW_DIR[] = {0x02, 0x00, 0x03, 0x01};
static int last_code; // Last stable encoder output
static int encoder_count; // tracks incremental rotation CW (+), CCW (-)
// Structure used to track encoder pin state in ISR
typedef struct
{
union
{
byte encoder;
struct
{
int enc_A:1;
int enc_B:1;
};
};
} PINSTATUS_t;
// Returns current encoder pin reading normalized to 0..3 value.
static inline int getEncoderValue(void)
{
int value = 0;
if (digitalRead(ENC_A_PIN)) value += 1;
if (digitalRead(ENC_B_PIN)) value += 2;
return value;
}
The pin change interrupt service routine (ISR) now needs to be defined. We only look at the current value of the encoder pins and compare it to the last value read. If it has changed, we just reset the 3ms debounce timer. We are not going to process the encoder value until it has not changed for 3 ms.
// Encoder pin change ISR - If a pin changed, reset debounce timer
ISR(VECTOR)
{
static PINSTATUS_t last;
byte prior;
prior = last.encoder;
last.enc_A = digitalRead(ENC_A_PIN); // Get encoder current pin values
last.enc_B = digitalRead(ENC_B_PIN);
if (prior != last.encoder)
{
TCNT1 = 0;
TIMSK1 |= (1 << OCIE1A);
}
}
The 3 ms timer is implemented using timer 1. I chose this timer because internal libraries for Arduino use timer 0 (the delay() function for example) and I plan to use timer 2 in my CW keyer code going forward. Timer 1 is a 16 bit timer and is set up to provide an interrupt after 3 ms.
Currently, I decode and debounce 4 edges per detent on the encoder. I could increment the encoder for each of these events which might make sense for an encoder without detents. However, getting an increment/decrement of 4 for every click of the encoder detent would be confusing, and not useful, so currently I only return an increment for every 4 encoder edges decoded resulting in incrementing by one per detent click. This could be used to speed up tuning when moving a long distance, but that is for another day...
// Timer ISR - We get here if the debounce timer times out. Compare the new
// code with the previous one to see which direction the encoder has turned.
// Update the rotation counter to reflect the change. The timer and interrupt
// are left disabled. I can get four counts per detent and effectively divide
// this by 4 to get one tick per detent.
ISR(TIMER1_COMPA_vect)
{
int new_code = getEncoderValue();
if (new_code != last_code)
{
if (new_code == CW_DIR[last_code]) {
if (0x00 == new_code) encoder_count++;
} else if (new_code == CCW_DIR[last_code]) {
if (0x00 == new_code) encoder_count--;
}
last_code = new_code;
}
TIMSK1 &= ~(1 << OCIE1A); // Disable Timer
}
The initialization code for the encoder sets up pin change interrupts and Timer 1. No magic here.
// Initialize the encoder
void initEncoder()
{
cli();
// Encoder pins
pinMode(ENC_A_PIN, INPUT_PULLUP);
pinMode(ENC_B_PIN, INPUT_PULLUP);
// Set pin change interrupt enable and pin mask for encoder pins
PCMask |= PCINTpinA; // Set pin mask for A and B inputs
PCMask |= PCINTpinB;
PCICR |= PCICRbit; // Enable interrupts on correct port
// Set timer 1 for 3 ms debounce timeout
TCCR1A = 0;// set entire TCCR1A register to 0
TCCR1B = 0;// same for TCCR1B
TCNT1 = 0;//initialize counter value to 0
// set compare match register 3 ms
OCR1A = 48000;
// turn on CTC mode
TCCR1B |= (1 << WGM12);
// Set bits for no prescaler
TCCR1B |= (1 << CS10);
// enable timer compare interrupt
TIMSK1 |= (1 << OCIE1A);
sei();
// Set the initial value from the encoder
last_code = getEncoderValue();
encoder_count = 0;
}
All that is left is to read and return a signed value indicating the direction and amount that the encoder has moved. If this is called in the main loop of your sketch, it will typically return a +/- 1 value depending on the latency of your main loop. In Eldon's Minima controller, it nicely returns a single increment or decrement per call. The only magic here is to disable interrupts while reading the multi-byte value of the encoder in order to prevent the value from being changed before all bytes can be read.
// Return encoder count. Negative - Anti-clockwise, positive - clockwise
int getEncoderDir()
{
uint8_t oldSREG = SREG;
cli();
int val = encoder_count;
encoder_count = 0;
SREG = oldSREG;
return val;
}
As always, your mileage may vary, but I hope you find this code useful. I am happy to help if anyone has problems with it. I will not be publishing this separately, but I expect that Eldon will use the integration in his Minima controller and publish it in due course after he has had a chance to review it.
I am happy to help with any problems. Drop me an email note at ko7m at arrl dot net and I will do my best to help you with any issues.
Wednesday, October 1, 2014
Minima working with rotary encoder
I have gotten Wayne, NB6M's Minima hardware working with a rotary encoder, thanks to the great work by Eldon, WA0UWH. Eldon has come up with a clever way to implement an encoder on top of his button structure that only requires a single input pin on the ATMega328 to handle all 7 buttons, plus the rotary encoder. Check out his blog for all the details.
I am sitting here listening to 75 meters tonight to the group that meets around 3.885 MHz on AM. Most of these guys are running old AM ham gear.
I have replaced the audio section with an LA4425 power amplifier chip. This is a 5W amplifier that typically is found in a automotive applications. It requires very few external parts and has sufficient drive to comfortably drive an unpowered speaker.
I have inserted this circuit between the volume control wiper and the speaker. Here is a shot of the ugly-style build in Wayne's Minima.
I like the end result, but it actually has a little more gain than it needs for this application. It is nice not needing to use amplified speakers just to hear the radio. I have not yet screwed down the component. It runs cool enough in this application, but the additional heat sink couldn't hurt.
I am sitting here listening to 75 meters tonight to the group that meets around 3.885 MHz on AM. Most of these guys are running old AM ham gear.
I have replaced the audio section with an LA4425 power amplifier chip. This is a 5W amplifier that typically is found in a automotive applications. It requires very few external parts and has sufficient drive to comfortably drive an unpowered speaker.
I have inserted this circuit between the volume control wiper and the speaker. Here is a shot of the ugly-style build in Wayne's Minima.
I like the end result, but it actually has a little more gain than it needs for this application. It is nice not needing to use amplified speakers just to hear the radio. I have not yet screwed down the component. It runs cool enough in this application, but the additional heat sink couldn't hurt.
Saturday, September 27, 2014
Fun with irDA
Recently, I picked up a fun little bit of kit that consists of a small irDA remote and an irDA receiver.
I did a bunch of reading about irDA remote controls and it is a bit mind boggling. It is clear that there is a bunch of legacy junque that has been drug along for years in the implementation of irDA remote controls. The little breakout board with the irDA receiver on it kindly includes a visible light LED that toggles in response to anything the sensor sees. This makes it easy to verify that it is seeing your remote control.
Taking at look at the output from the sensor on the scope we see this kind of information being transmitted for one of the buttons on the remote.
There are a bunch of different encodings for these remote controls and I had no interest in determining exactly what code format this remote uses. I did find an Arduino library or ten that would decode the data stream. With that in hand, I was able to find the codes for all the buttons on the remote, listed below top/left to bottom/right.
Power - 0xffa25d
Mode - 0xff629d
Mute - 0xffe21d
Play - 0xff22dd
Rewind - 0xff02fd
Fast Forward - 0xffc23d
EQ - 0xffe01f
Minus - 0xffa857
Plus - 0xff906f
0 - 0xff6897
Random - 0xff9867
U/SD - 0xffb04f
1 - 0xff30cf
2 - 0xff18e7
3 - 0xff7a85
4 - 0xff10ef
5 - 0xff38c7
6 - 0xff5aa5
7 - 0xff42bd
8 - 0xff4ab5
9 - 0xff52ad
I did a bunch of reading about irDA remote controls and it is a bit mind boggling. It is clear that there is a bunch of legacy junque that has been drug along for years in the implementation of irDA remote controls. The little breakout board with the irDA receiver on it kindly includes a visible light LED that toggles in response to anything the sensor sees. This makes it easy to verify that it is seeing your remote control.
Taking at look at the output from the sensor on the scope we see this kind of information being transmitted for one of the buttons on the remote.
There are a bunch of different encodings for these remote controls and I had no interest in determining exactly what code format this remote uses. I did find an Arduino library or ten that would decode the data stream. With that in hand, I was able to find the codes for all the buttons on the remote, listed below top/left to bottom/right.
Power - 0xffa25d
Mode - 0xff629d
Mute - 0xffe21d
Play - 0xff22dd
Rewind - 0xff02fd
Fast Forward - 0xffc23d
EQ - 0xffe01f
Minus - 0xffa857
Plus - 0xff906f
0 - 0xff6897
Random - 0xff9867
U/SD - 0xffb04f
1 - 0xff30cf
2 - 0xff18e7
3 - 0xff7a85
4 - 0xff10ef
5 - 0xff38c7
6 - 0xff5aa5
7 - 0xff42bd
8 - 0xff4ab5
9 - 0xff52ad
So, with all this fun in mind, I decided to set up the irDA remote to work with Minima. I added the code to initialize the irDA receiver and in the btnDown function added receiving the button codes above and mapping them to Minima's 7 button scheme implemented by Eldon, WA0UWH. For now, I just mapped the buttons as follows:
Mode -- FN (button 1)
Rewind - Left (button 2)
Fast Forward - Right (button 3)
Minus - Down (button 6)
Plus - Up (button 5)
So, with this simple change, I am able to move the cursor to select the frequency digit to change, move up and down through the ham band select and toggle RIT mode. It would be simple enough to add direct frequency entry and map the rest of the buttons.
This is just a proof of concept bit of fun on a Saturday afternoon when I should really be out playing in the sun before it runs away and hides for the rest of the year...
Here is the Minima controller shield mounted on an ATMega2560 with the irDA breakout board jumpered to digital pin 3. The display is an i2c 20x4 LCD on my Minima front panel.
Saturday, September 20, 2014
Minima Controller Shield - mounting options
Well, I am not certain yet how I am going to mount things in the long run, but for now I have stacked the display, Uno and Shield on the back of the panel. My wires are deliberately long until I make a final decision, but for now I have just coiled them up.
I will most likely fashion another panel a little bit larger that will have room for more buttons as well as the rotary encoder at which time the current tuning pot will become the speed control for a keyer. I have located some scrap aluminum, so I think it is the next best step.
Friday, September 19, 2014
Minima working with new shield
This evening, I hacked poor Wayne, NB6M's Minima to accept VFO energy from my Minima Controller shield. As a first hack, it worked fine and I was able to test drive the receiver from my controller.
I disconnected Wayne's Si570 output and brought the coax out to an SMA connector that I hooked up with a short SMA jumper cable to my VFO output. Other than being out of calibration, it seems to work fine.
So far so good... I want to try using the second Si570 as the BFO, but more surgery is necessary in order to replace the BFO oscillator. I think I will wait until I am more awake...
I disconnected Wayne's Si570 output and brought the coax out to an SMA connector that I hooked up with a short SMA jumper cable to my VFO output. Other than being out of calibration, it seems to work fine.
So far so good... I want to try using the second Si570 as the BFO, but more surgery is necessary in order to replace the BFO oscillator. I think I will wait until I am more awake...
Tuesday, September 16, 2014
Minima Displays
I have been playing around with a number of display options for the Minima. I found an interesting little board locally for about $12 in single quantities and on eBay for about $5 that has 8 digits of seven segment display, eight tri-colour LEDs and eight push buttons. It is based on the Titan Micro LED driver chip TM1638. Here is a good write-up on the device, I won't attempt to replicate it here.
I very quickly modified the Minima code to utilize this display. It could very easily be further adapted to support the various buttons. Some of the LCD second line indicators (RX/TX, LSB/USB, etc) could be indicated using tri-colour LEDs.
I thought folks might be interested in seeing this device and I wanted to get a feel for how difficult it would be to integrate into the Minima code. Out-of-box, it requires three of the scarce pins on the Arduino, but this can be easily resolved by expanding the I/O pins using a i2c device very similar to what is done with LCD backpacks for i2c.
Here is a photograph of my UNO running Minima version ko7m-AD with modifications for displaying the frequency. My Minima controller shield is in place but not currently powered.
Anyone interested in further details on this display board should see the links above. if you have trouble integrating this into your Minima code, drop me a note by email or by comment here and I will do my best to help you succeed.
ko7m at arrl dot net
I very quickly modified the Minima code to utilize this display. It could very easily be further adapted to support the various buttons. Some of the LCD second line indicators (RX/TX, LSB/USB, etc) could be indicated using tri-colour LEDs.
I thought folks might be interested in seeing this device and I wanted to get a feel for how difficult it would be to integrate into the Minima code. Out-of-box, it requires three of the scarce pins on the Arduino, but this can be easily resolved by expanding the I/O pins using a i2c device very similar to what is done with LCD backpacks for i2c.
Here is a photograph of my UNO running Minima version ko7m-AD with modifications for displaying the frequency. My Minima controller shield is in place but not currently powered.
Anyone interested in further details on this display board should see the links above. if you have trouble integrating this into your Minima code, drop me a note by email or by comment here and I will do my best to help you succeed.
ko7m at arrl dot net
Sunday, September 14, 2014
Crystal Filter
The post yesterday delivered my bag-o-rocks from China. I ordered on eBay 100, 20 Mhz surface mount crystals for building crystal filters.
I am going to have to convince my buddy Eldon, WA0UWH to help me categorize these using his AIM-4170B analyzer before I solder them into a circuit. $10 delivered from China is pretty good, but it remains to be seen how these crystals operate.
I am going to have to convince my buddy Eldon, WA0UWH to help me categorize these using his AIM-4170B analyzer before I solder them into a circuit. $10 delivered from China is pretty good, but it remains to be seen how these crystals operate.
Tuesday, September 9, 2014
Updated PCA9546 library
As mentioned in a previous post, I have updated the PCA9546 library in order to fix the problem of one of the methods of the class being implemented as private when it needs to be public. I also implemented a constructor that allows initialization of the class without selecting any channel as active. Lastly, I implemented a change to the selectChannel method to allow deselecting all channels.
As promised, I am posting the entirety of the update here for your convenience.
File: PCA9546.h
#ifndef PCA9546_H
#define PCA9546_h
#ifndef P
#define PBUFSIZE (66)
extern char buf[PBUFSIZE];
#define P(x) strcpy_P(buf, PSTR(x))
#endif
typedef enum
{
PCA9546_ERROR = 0,
PCA9546_SUCCESS
} PCA9546_Status;
#define PCA9546_NOCHANNEL (0) // No channel selected
#define PCA9546_CHANNEL_1 (1) // Bit 1
#define PCA9546_CHANNEL_2 (2) // Bit 2
#define PCA9546_CHANNEL_3 (4) // Bit 3
#define PCA9546_CHANNEL_4 (8) // Bit 4
class PCA9546
{
public:
PCA9546(uint8_t i2c_address);
PCA9546(uint8_t i2c_address, uint8_t channel);
bool selectChannel(uint8_t channel);
PCA9546_Status status;
uint8_t channel;
private:
uint8_t i2c_address;
uint8_t i2c_read();
void i2c_write(uint8_t data);
};
#endif
As promised, I am posting the entirety of the update here for your convenience.
File: PCA9546.h
#ifndef PCA9546_H
#define PCA9546_h
#ifndef P
#define PBUFSIZE (66)
extern char buf[PBUFSIZE];
#define P(x) strcpy_P(buf, PSTR(x))
#endif
typedef enum
{
PCA9546_ERROR = 0,
PCA9546_SUCCESS
} PCA9546_Status;
#define PCA9546_NOCHANNEL (0) // No channel selected
#define PCA9546_CHANNEL_1 (1) // Bit 1
#define PCA9546_CHANNEL_2 (2) // Bit 2
#define PCA9546_CHANNEL_3 (4) // Bit 3
#define PCA9546_CHANNEL_4 (8) // Bit 4
class PCA9546
{
public:
PCA9546(uint8_t i2c_address);
PCA9546(uint8_t i2c_address, uint8_t channel);
bool selectChannel(uint8_t channel);
PCA9546_Status status;
uint8_t channel;
private:
uint8_t i2c_address;
uint8_t i2c_read();
void i2c_write(uint8_t data);
};
#endif
File: PCA9546.cpp
/*
* PCA9546 Library for Arduino
*
* MIT License
*
* Copyright Jeff Whitlatch - ko7m - 2014
*/
#include <Arduino.h>
#include <Wire.h>
#include "PCA9546.h"
#include "debug.h"
#define DEBUG(x ...) // Default to NO debug
//#define DEBUG(x ...) debugUnique(x) // UnComment for Debug
// Initialize the PCA9546 and disable all channels
PCA9546::PCA9546(uint8_t PCA9546_address)
{
i2c_address = PCA9546_address;
Wire.begin();
selectChannel(PCA9546_NOCHANNEL);
}
// Initialize the PCA9546 and enable the channel(s) indicated
PCA9546::PCA9546(uint8_t PCA9546_address, uint8_t channel)
{
i2c_address = PCA9546_address;
Wire.begin();
selectChannel(channel);
}
// Send a channel selection word to the PCA9546
bool PCA9546::selectChannel(uint8_t channel)
{
// Sanity check value passed. Only least significant 4 bits valid
if (channel <= 0xf)
{
i2c_write(channel);
debug(P("Successfully selected PCA9546 channel"));
status = PCA9546_SUCCESS;
}
else
{
debug(P("PCA9546 channel selection failed"));
status = PCA9546_ERROR;
}
return (PCA9546_SUCCESS == status);
}
// Write a byte to I2C device. There is only a single register. If multiple bytes written, last one wins.
void PCA9546::i2c_write(uint8_t data)
{
Wire.beginTransmission(i2c_address);
Wire.write(data);
Wire.endTransmission();
}
// Read the one byte register from the I2C device
uint8_t PCA9546::i2c_read()
{
uint8_t rdata = 0xFF;
Wire.beginTransmission(i2c_address);
Wire.requestFrom(i2c_address, (uint8_t)1);
if (Wire.available()) rdata = Wire.read();
return rdata;
}
Minima Controller - 5V i2c LCD support
I have tested my Minima controller successfully for support of 16x2 or 20x4 LCD displays using a 5V i2c backpack. Here is a 20x4 display running my changes to WA0UWH's latest firmware for Minima.
Only two wires plus power and ground required to support these displays. The code is conditionally compiled with or without i2c display support as desired with the default to continue to support 6 wire displays. Converting to an i2c display will be required in order to free up I/O pins to support such things as rotary controllers, keyer paddles, etc. This change however will continue to work by default with the original Minima hardware configuration for the LCD display. In order to enable the functionality, please uncomment the following line near the top of the file "radiono.ino".
#define USE_I2C_LCD 1
You will also need to obtain the i2c library LiquidTWI and install in your Arduino environment in order to build with this support.
It should be noted that my Minima Controller shield is not required to support i2c displays.
Please contact me directly by email at ko7m at arrl.net or by commenting on this post if you have any problems and I will do my best to assist.
Only two wires plus power and ground required to support these displays. The code is conditionally compiled with or without i2c display support as desired with the default to continue to support 6 wire displays. Converting to an i2c display will be required in order to free up I/O pins to support such things as rotary controllers, keyer paddles, etc. This change however will continue to work by default with the original Minima hardware configuration for the LCD display. In order to enable the functionality, please uncomment the following line near the top of the file "radiono.ino".
#define USE_I2C_LCD 1
You will also need to obtain the i2c library LiquidTWI and install in your Arduino environment in order to build with this support.
It should be noted that my Minima Controller shield is not required to support i2c displays.
Please contact me directly by email at ko7m at arrl.net or by commenting on this post if you have any problems and I will do my best to assist.
Minima Controller - OLED Display
After some initial head scratching, I have my adaptation of the Minima sketch that supports my OLED display up and running on my controller shield.
I was initially not getting any joy out of the OLED display and it remained black despite my efforts. However, I had stupidly placed the initialization of the PCA9546 multiplexer after the initialization of the OLED display. Since the OLED cannot be addressed until the mux is set to channel 1, no joy.
I did write a somewhat useful utility that enumerates all i2c device id's that can be seen on the Arduino i2c bus as well as on each of the four channels of the mux which others may find useful.
Debugging this did point out to me an error in my PCA9546 code and a couple of changes I would like to make.
1. I have mistakenly made the selectChannel() method private, when it should be public.
2. The channel argument to selectChannel() is currently a bit field. The bottom 4 bits indicate which of the four channels should be enabled. I believe I will change this to just take a channel number rather than a bit field. I also need a way to deselect all channels.
3. I need to provide a constructor for the PCA9546 class that will allow initialization without selecting any channel.
I will provide an updated listing of PCA9546 class with these changes in a separate post.
Here is the code for scanning for devices connected to the i2c bus and all channels of the PCA9546.
// i2c_scanner
//
#include <Wire.h>
#include "PCA9546.h"
PCA9546 *mux;
char buf[66];
void setup()
{
Wire.begin();
Serial.begin(115200);
Serial.println("i2c Scanner");
mux = NULL;
}
void printAddress(byte address)
{
if (address<16) Serial.print("0");
Serial.println(address, HEX);
}
void loop()
{
uint8_t nChannel;
for (nChannel = 0; nChannel <= 4; nChannel++)
{
Serial.print("Channel ");
Serial.println(nChannel, DEC);
byte error, address;
int nDevices;
Serial.println("Scanning...");
nDevices = 0;
if (nChannel > 0)
{
if (mux == NULL)
{
mux = new PCA9546(0x70, 1 << (nChannel - 1));
}
else
{
bool fRc = mux->selectChannel(1 << (nChannel - 1));
}
}
for(address = 1; address < 127; address++ )
{
Wire.beginTransmission(address);
error = Wire.endTransmission();
// Just for good measure, try again
if (error != 0)
{
delay(10);
Wire.beginTransmission(address);
error = Wire.endTransmission();
}
if (error == 0)
{
Serial.print("i2c device found at address 0x");
printAddress(address);
nDevices++;
}
else if (error == 4)
{
Serial.print("Unknown error at address 0x");
printAddress(address);
}
}
if (nDevices == 0)
Serial.println("No i2c devices found\n");
else
Serial.println("");
}
// Hang the script
while (1==1);
}
Subscribe to:
Posts (Atom)


















