Thursday, December 28, 2017

Zeta FX-79 Buffalo Build - Wiring plan

Zeta FX-79 Buffalo Build - Wiring plan


The stock configurations for the FX-79 seem to recommend running with 3s lipos, so that's what I'm planning to do.  I'll be using two 5000 mah batteries in parallel.    My Flight Controller is rated up to 5s, as far as I can tell on the forums, so I have the option of upgrading later if I wish.

The Omnibus F4 Pro V2 comes with an onboard 3 amp BEC.  However, as I read the forums, I understand that it can get rather warm.  As a precaution, I'm planning to run very little through the onboard BEC.

Power Plan

  • Direct from batteries
    • Flight controller - rated to 5s (I think).
    • Runcam and VTX (through a filter).  Both are rated up to 6s.
    • ESC (via the Flight Controller for current measuring)
  • BEC on Flight Controller
    • GPS
    • Uart inverter
  • External BEC
    • Servos
    • Receiver
  • External BEC (auxiliary port)
    • Lights or special effects
I roughed out a wire plan on my office whiteboard.



About Club24A


There are known problems with this board with regards to reporting accurate current if VCC is jumpered into the Camera or VTX pins.  It's known as "Club24A" in the forums.  I'm avoiding that problem entirely by not using the onboard jumper to apply power to the RAM pins.  I'm actually hijacking the RAM pins for another purpose (RSSI).  I'm providing the power to the camera and VTX via the wiring harness, apart from the Omnibus board, so I do not expect any of the Club24A issues.

Riser pins


Since I'm providing power to most of the external devices via the external BEC rather than through the FC, it's led to a rather convoluted wiring harness.  While the FC provides 3 pins in most places, for powered servo cables, I'm generally using just the signal wire, and drawing power from my external BEC.  I decided to solder wires directly onto the Flight Controller and terminate with female servo connectors.  This makes the flight controller a bit of a hassle to wire up, but with care, it should be alright. 

I'm planning to use extension cables everywhere, so that the FC can be removed for calibration or reprogramming if necessary.  Also, being the most convoluted part of the build, it should be fairly easy to transplant, if the plane crashes badly enough that I need to replace the foam.

Here's the flight controller wiring, about 3/4 done.  I'll update this picture when it's complete.  Note the heavy cables which lead to the batteries and ESC.  The servo cables patch into other cables to provide power.



Monday, December 25, 2017

Zeta FX-79 Buffalo Build - Preliminaries

Zeta FX-79 Buffalo Build



My wife bought me a Zeta FX-79 Buffalo flying wing for Christmas.  I'll be chronicling the build in this blog post.  My motivation for this plane was to have an FPV platform to use for balloon "Search and Rescue" operations.  I'd like to have an FPV camera, and a higher resolution camera for post-flight analysis.  I'd also like to be able to fly my Kenwood TH-D72A radio as an airborne APRS digipeater platform.  Since my trackers are very low power (10mw or so), the hope is that an airborne digipeater might be helpful in recovery operations.

I purchased the fittings from a variety of sources.  The Bill of Materials follows. 


I'll be doing the build with the Omnibus F4 Pro V2 flight controller, which includes an OSD and can relay Smartport Telemetry back to my Tanaris Plus transmitter.

In future posts, I'll document the build process and initial flights.

Sunday, August 20, 2017

AFSK modulation experiments - success!

AFSK modulation experiments - success!


So, in the previous blog entry, I confirmed that I had come up with some numbers and timer values to make the frequencies I needed.  For posterity, I'll document them here.

DAC configration

I'm running my DAC with 24 data points.  I generated my sinewave table using the script that I blogged previously.  Based on the results from AFSK modulation experiments - part 4, I set the PPM on the Si5351b to 30, and the DAC_PCT to 35 to achieve about 3000hz deviation.  It looks as follows:

#define DAC_PCT 35          // Percentage of DAC output#define SINE_RES        24const uint16_t sinewave[SINE_RES] = {        (0 * DAC_PCT / 100) + 2048, (530 * DAC_PCT / 100) + 2048, (1023 * DAC_PCT / 100) + 2048,        (1448 * DAC_PCT / 100) + 2048, (1773 * DAC_PCT / 100) + 2048, (1978 * DAC_PCT / 100) + 2048,        (2047 * DAC_PCT / 100) + 2048, (1978 * DAC_PCT / 100) + 2048, (1773 * DAC_PCT / 100) + 2048,        (1448 * DAC_PCT / 100) + 2048, (1024 * DAC_PCT / 100) + 2048, (530 * DAC_PCT / 100) + 2048,        (0 * DAC_PCT / 100) + 2048, (-530 * DAC_PCT / 100) + 2048, (-1023 * DAC_PCT / 100) + 2048,        (-1448 * DAC_PCT / 100) + 2048, (-1773 * DAC_PCT / 100) + 2048, (-1978 * DAC_PCT / 100) + 2048,        (-2047 * DAC_PCT / 100) + 2048, (-1978 * DAC_PCT / 100) + 2048, (-1773 * DAC_PCT / 100) + 2048,        (-1448 * DAC_PCT / 100) + 2048, (-1024 * DAC_PCT / 100) + 2048, (-530 * DAC_PCT / 100) + 2048,};

Clock speed


I'm testing on the Nucleo-L152RE, which has a STM32L152RET6 processor.  My flght board uses an STM32L152CB, which is quite similar.  I'm running it at a clock speed of 32 MHZ, and the prescalars set such that the APB1 clock speed is also 32mhz.

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;  RCC_OscInitStruct.HSIState = RCC_HSI_ON;  RCC_OscInitStruct.HSICalibrationValue = 16;  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4; // 32mhz  RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV2;  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)


Timer calculations


Based on the 32mhz clock, I calculated timers as follows.  The goal for the DAC timer was to be able to simply toggle the "counter" value back and forth, in order to change the tone between 1200hz and 2200hz.  You can calculate the Clock Ticks yourself by dividing:

Clock_Ticks_Hz = 32000000 / (DAC Datapoints * Prescaler * Counter)


Function Timer DAC sinewave
data points
Prescaler Counter Clock ticks (hz)
Baud Timer
1200hz
TIM2 n/a13,333 2 1200.03001
DAC timer
1200 hz
TIM6 24 101 11 1200.120012
DAC timer
2200 hz
TIM6 24101 6 2200.220022

  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 13333 - 1;
  htim2.Init.Period = 2 - 1; // 1200 hz
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;

  if (HAL_TIM_Base_Init(&htim2) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }

  htim6.Instance = TIM6;
  htim6.Init.Prescaler = 101 - 1;
  htim6.Init.Period = 11 - 1;
// 1200 hz

  htim6.Init.CounterMode = TIM_COUNTERMODE_UP;


  if (HAL_TIM_Base_Init(&htim6) != HAL_OK)
  {
    Error_Handler(__FILE__, __LINE__);
  }
  // We turn on the ARPE register so that the counter is only updated AFTER a clean
  // count completes.  Otherwise, we run the risk of overcounting an interval.
  htim6.Instance->CR1  |= TIM_CR1_ARPE; // Turn on auto-preload register

The ARPE bit


Note that on the DAC timer (TIM6) we set the ARPE bit in the Control Register.   This causes any changes to the counter to take effect AFTER the next timer pop.  This assures that each timer cycle is complete, so that the DAC data points are properly spaced.


Switching between 1200hz and 2200hz

Because I'm using the DAC to make the sine wave, and just adjusting the TIM6 timer to change the frequency, I am able to greatly simplify the code that most APRS implementations use.  Rather than using a 512 element phase array, I'm simply using a 24 element sine array for the DAC.  I no longer need to track the phase position when switching.  Rather, I just adjust the timer counter.

The code is simple, but it confused me at first, because AX.25 is using NRZI encoding.  So, here's a bit about that, before showing the code.

From Wikipedia:
At the datalink level, AX.25 specifies HDLC (ISO 3309)[3] frames transmitted with NRZI encoding.   
In NRZI encoding, you're not sending the actual bits, but rather toggling whatever bit you are sending, based on the next data value.  I borrowed a few lines from the Tracksoar code, and modified them to my purposes:

if ((current_byte & 1) == 0) {
// Toggle tone (1200 <> 2200)
current_timer_counter ^= (COUNTER_1200 ^ COUNTER_2200); // Switch to the opposite counter value
__HAL_TIM_SET_AUTORELOAD(&htim6,current_timer_counter); // Set frequency
}

That's it.  No math about phase arrays and accmulators!  Yay!

Initial test failures


I only had 3 tiny bugs in my code which prevented APRS from working.


  1. I actually FORGOT the HAL_TIM_SET_AUTORELOAD command after setting the current_timer_counter.  lol.  
  2. The more subtle one was that I had misread the manual, and thought that the ARPE bit was set by default.  When I tested without it, there were hesitations in the middle of the transmission. It was obvious what was going on when I heard it, and simple to fix.
  3. I contrived the test by hard-coding GPS values into the strings that the aprssend() call uses.  I used the wrong number of digits in the Longitude, and so my Kenwood D72 caught my callsign, it wouldn't decode it until I fixed that coordinate.  Along the way, I noticed that my APRS comment was also too long.  I wanted it to read "Mr. Watson, come here, I want you." Unfortunately, that's too many characters.  So, I changed it to "Mr. Watson, Come here!..."

Successful test







Saturday, August 12, 2017

AFSK modulation experiments - part 4

AFSK modulation experiments - part 4


I left off the last time with some concerns that the deviation might be too wide on the VCXO, and also that when using the VCXO, the Si5351 was somewhat off frequency (about 5 khz).  I set out to work on both of those issues tonight.

I began by setting up my scope and service monitor so that I could measure the P2P value of the modulating sine wave, and the deviation of the resulting signal.


Here, we see a 1200hz sine wave the VCXO signal should be ve being generated by the DAC.  The P2P value is 0.980 volts.  This is from setting the sine wave at 30% amplitude.  We also see that the wave is centered at (2.18 + 1.20) / 2 = 1.69 volts. That's just fine, since it should be centered around 1.65 volts.



The resulting deviation for the wave above (on the 0-6 scale) is coming in at about 2.7 khz.  That's a touch low.

So, I ran the tests over and over gathering data. I also varied the PPM value to see the effect.


PPM value Sine wave % P2P voltage (volts) Deviation (hz)
30 50 1.52 3,500
30 30 0.982,700
30 40 1.243,300
40 40 1.243,700
40 30 0.983,200

Deviation Results

The PPM value definitely has an impact on the deviation.  Assuming that we would want the capability of 5 khz deviation for an FM signal, but then we would only want to modulate the signal to 3 khz, the ppm should be (5000 hz / 144.390) = 35 PPM.   In a previous post, I came up with the number 24, but that was when I was considering modulating to 3.2 khz, not 5 khz.

So, it appears that for flight use, I should be setting my PPM to 35 ppm, and setting my sinewave appropriately to get about a 3khz deviation.  That should be at about 30% or so.   I noticed a bit of variability when I was testing this evening, due to the fact that I was using breakout boards and jumpers all over.  I suspect this is a process I'll need to repeat when I have the production boards spun up.

Correcting for the incorrect frequency


I dabbled with the "Correction" call to fix the frequency of the VCXO this evening.

  MySi5351.set_correction(-12940);

In the end, the value above was sufficient to center up the frequency where I was testing, at 144.330 mhz.  According to the documentation, I can expect to do this with every board I build.

Conclusions



  1. I'll build my flight code with a PPM of 35.
  2. I'll build my flight code with a Calibration option.  When set, the tracker will generate a fixed tone (or maybe alternated between 1200 and 2200) so that I can confirm that the deviation is correct, and also so that I can diddle the "correction" value to assure the tracker is on frequency.





Friday, August 11, 2017

AFSK modulation experiments - part 3

AFSK modulation experiments - part 3


So, Part 2 of this little journey featured our hero barking up the wrong tree a bit.  I made two mistakes.
  1. I assumed that I had to modulate the VC pin on the Si5351b with values from -3v3 .. 3v3.  That is incorrect.  The proper values for the VC pin on the Si5351b are from 0 .. 3v3.  The "typical" value is listed as VDD / 2 (IE: 1.65 volts).  I presume (see below) that this means that any modulation should be centered at 1.65 volts.
  2. I assumed that the output of my signal generator was making an AC signal.  Of course, it wasn't, as I had things wired up.  It was a DC signal.
The mistakes above led to some seriously confusing results, and some pretty bad sounding signals.

Taking a step back


I decided to do some Science, and assure that I wasn't making any more bad assumptions.  I set up a test environment on my bench so that I could try moving the VC pin between 0 .. 3v3, and see the resulting impact on the signal being generated.

I wired up my Si5351b breakout board to my STM Nucleo-L152RE.  I ran the output into my spectrum analyzer so that I could get a good look at what was happening.  I wired the VC pin to a variable DC power supply so that I could vary it carefully, and see where the signal wound up.



Test 1: Baseline without VCXO


For the first test, I wanted to just set the frequency of the Si5351b to 144.330 without using the VCXO. This test was intended to see where the Si5351b was centered, without using the VC, so I had an idea of how well calibrated it was.

Here are the relevant lines which initialized the Si5351.  I am using the Etherkit Si5351 library.

    MySi5351.set_freq(14433000000ULL, SI5351_CLK0);
    MySi5351.output_enable(SI5351_CLK0, ENABLE);

This is the result.


My spectrum analyzer is reasonably well calibrated.  The center frequency of the Si5351b came in at 144.330004 mhz.  Dang.  Not bad at all!  My little breakout board actually uses a TCXO for the oscillator, and I think that helps with the accuracy.

Test 2: VC at 0 volts

  MySi5351.set_vcxo(86598000000ULL, 40);
  // Set CLK0 to be locked to VCXO
  MySi5351.set_ms_source(SI5351_CLK0, SI5351_PLLB);
  // Tune to 144.330 MHz center frequency
  MySi5351.set_freq_manual(14433000000ULL, 86598000000ULL, SI5351_CLK0);
  MySi5351.update_status();
  MySi5351.output_enable(SI5351_CLK0, ENABLE);



OK, that did just what one would expect.  It pulled the signal down to 144.323462 mhz.  That's 6.538 khz down.  Note, I set the PPM value to "40" in the initial tests, which is the value that was in the samples in the Etherkit Si5351 library I'm using.  Diddling with the PPM value will follow.

Test 3: VC at 3.3 volts


Great, OK, that set the top end of the swing.  It's at 144.332962.  I was a little surprised that it seemed a little asymmetric.   It's only 2.962 khz above the center (vs the 6,538 below we saw).

Test 4: VC at 1.65 volts


OK, this one, I would expect should show the signal centered up again.


Ruh Roh.  We should be at 144.330.  We're at 144.327212.   That's about 5khz off where I expected. Not cool.  If I split the difference between the low and high values, I should have been at 144.328212, which would still have been 1.788 khz off.

Test 5: What voltage do I need for Center frequency?




OK, I was able to get it centered up.  Rather than being at 1.65 volts, I had to apply 2.43 volts. Curious.

Test 6: How does modulation look at 1.65 volts with the DAC?


So, my DAC was all set up to make about 1 volt P2P, centered at 1.65 volts.  I put that 1200 hz modulation into the VC pin to see what it would look like,


Sure enough, it looks symmetric around 133.327 mhz, the same as when the VC pin is just held at 1.65 volts.



Other thoughts on the frequency error

In a later test, I had the VCXO set at 146.000 mhz.  When set up that way, the frequency was dead nuts on at 1.65 volts.  Modulating the frequency looked just fine, too.

I suspect that the frequency error has something to do with an error introduced by the multisynth multipliers and dividers.  I'm not too concerned, as I may be able to address it either by using the calibration subroutines, or different multipliers.

Deviation and the PPM value

OK, so I had set the PPM value in all of these tests to 40.  At 144.330 mhz, that should make for a deviation of  3.608 khz.  My observed deviation was 144.332962 - 144.323462 = 9.500 khz,  

Hmm...   Is that how you measure deviation?  If so, mine's WAY too big.

Test 7:  Different PPM values



PPM value 0 volt reading 3.3 volt reading Delta
30 144.325164 mhz 144.332289 mhz 7,127 hz
40 144.323462 mhz 144.332962 mhz 9,500 hz

I also tried a test with 20 PPM (which isn't supported according to the documentation), and it seemed to show the same readings as 30 PPM.

If I understand "deviation" in this context, I think these numbers are too big.  I need to understand this better.

Next steps


Strictly speaking, the frequency being off isn't too much of a problem.  The Si5351 has a calibration routine which I can use to center this up.  It's just odd that the center frequency is different when using the VCXO.  I'm a little more concerned about the deviation right now.  The lowest deviation setting still seems to be too wide, unless I'm misunderstanding what to expect with regard to this kind of experiment.

Things to do:
  1. Call the calibration routine to see if I can get it centered up.
  2. Experiment with the amplitude of the VC signal to see the effect on the signal, and received modulation.
  3. See if different multipliers work to improve the frequency accuracy of the VCXO.  I used 6 for these tests.   I could try 4 or 8




Generating a sinewave table for my DAC

Generating a sinewave table for my DAC


Unlike other AFSK implementations, I don't actually need a sinewave table with a lot (like 512) of values in it.  In fact, I'll be using just 24 values in my sinewave table for my DAC.

I decided to write a program to generate my table.  While I was at it, I decided that I would have it build in a scaling factor as a "#define".  By changing that one #define, I can change the amplitude of the sinewave with a recompile, rather than having to re-generate a whole new table.

Sinewave.pl

#!/usr/bin/perl
# Usage: sinewave.pl samples
# Generates a sinewave table containing the specified number of samples.
# For example, "sinewave.pl 36" yields:
#       #DEFINE DAC_PCT 100
#       #DEFINE SINE_RES        36
#       const uint16_t sinewave[SIN_RES] = { .... }
# The DAC_PCTxx define is a percentage multipler against all of the values in the table.  Useful if your DAC output is too high.
# By changing this one DEFINE in your code, you can scale the sinewave table at compile time.  Note, that the DAC values will remain
# centered on the sine(0) value, and will scale "inward" toward that number.  For example, on a 12 bit DAC, sin(0) is going to be at 2048.
# Even if you scale up and down, the sine wave will be centered around 2048.
#
# The output of this program is actually a C program which an be compiled to confirm the table is built properly.  When satisfied,
# you can just copy/paste the sinewave table and the few necessary defines into your own program.
use strict;
my $DACBITS = 12;                       # Number of bits the DAC (or pwm) is using
my $COLUMNS_PER_LINE = 3;               # Number of values per row
if ($#ARGV != 0) {
        print STDERR "Usage: $0 samples\n";
        exit 4;
}
my $center_value = 2 ** $DACBITS / 2;   # The peak 2 peak of the sine wave is twice $center_value, so we divide by two.
my $PI = 3.1415926;
my $samples = $ARGV[0];
my $degrees = 0;
my $column;
my $value;
my $row;
print("\#include \"stdint.h\"\n");
print("\#include <stdio.h>\n");
print("main()\n");
print("{\n");

print("\#define DAC_PCT 100             // Percentage of DAC output\n");
print("\#define SINE_RES        $samples\n");
print("const uint16_t sinewave\[SINE_RES\] = {\n");
for ($row = 0; $row < ($samples / $COLUMNS_PER_LINE); $row++) {
        print("\t");
        for ($column = 0; (($degrees < 360) &&  ($column < $COLUMNS_PER_LINE)); $degrees += 360/$samples) {
                $value = int($center_value * sin($degrees/180.0 * $PI));                # Perl sin() is in Radians.  Convert.
                print("(${value} * DAC_PCT / 100) + $center_value, ");
                $column++;
        }
        print("\n");
}
print("};\n");
print("int      i;\n\n");
print("for (i = 0; i < SINE_RES; i++) {\n");
print("\t");
print("printf(\"\%d\\n\", sinewave[i]);");
print("\n"); print("\t}\n"); print("}\n");

What it does

Rather than just creating the sinewave table, it actually generates a short C program which can be compiled in Unix to confirm that the table is properly formed, and that the values look correct.


Sample run for 24 data points

mqh1@debian:~/wisp2$ ./sinewave.pl 24
#include "stdint.h"
#include <stdio.h>
main()
{
#define DAC_PCT 100             // Percentage of DAC output
#define SINE_RES        24
const uint16_t sinewave[SINE_RES] = {
        (0 * DAC_PCT / 100) + 2048, (530 * DAC_PCT / 100) + 2048, (1023 * DAC_PCT / 100) + 2048,
        (1448 * DAC_PCT / 100) + 2048, (1773 * DAC_PCT / 100) + 2048, (1978 * DAC_PCT / 100) + 2048,
        (2047 * DAC_PCT / 100) + 2048, (1978 * DAC_PCT / 100) + 2048, (1773 * DAC_PCT / 100) + 2048,
        (1448 * DAC_PCT / 100) + 2048, (1024 * DAC_PCT / 100) + 2048, (530 * DAC_PCT / 100) + 2048,
        (0 * DAC_PCT / 100) + 2048, (-530 * DAC_PCT / 100) + 2048, (-1023 * DAC_PCT / 100) + 2048,
        (-1448 * DAC_PCT / 100) + 2048, (-1773 * DAC_PCT / 100) + 2048, (-1978 * DAC_PCT / 100) + 2048,
        (-2047 * DAC_PCT / 100) + 2048, (-1978 * DAC_PCT / 100) + 2048, (-1773 * DAC_PCT / 100) + 2048,
        (-1448 * DAC_PCT / 100) + 2048, (-1024 * DAC_PCT / 100) + 2048, (-530 * DAC_PCT / 100) + 2048,
};
int     i;
for (i = 0; i < SINE_RES; i++) {
        printf("%d\n", sinewave[i]);
        }
}
mqh1@debian:~/wisp2$

Compile and run the output


mqh1@debian:~/wisp2$ ./sinewave.pl 24 > t.c
mqh1@debian:~/wisp2$ cc t.c
mqh1@debian:~/wisp2$ ./a.out
2048
2578
3071
3496
3821
4026
4095
4026
3821
3496
3072
2578
2048
1518
1025
600
275
70
1
70
275
600
1024
1518
mqh1@debian:~/wisp2$

In the output above, you can see that it's got a sinewave centered at 2048, with values ranging from (almost) 0 to 4095.

Re-scaling the sine wave

To change the scale out the sinewave, I simply modify the #define

#define DAC_PCT 50              // Percentage of DAC output

This will set the DAC amplitude at 50%

mqh1@debian:~/wisp2$ vi t.c
mqh1@debian:~/wisp2$ cc t.c
mqh1@debian:~/wisp2$ ./a.out
2048
2313
2559
2772
2934
3037
3071
3037
2934
2772
2560
2313
2048
1783
1537
1324
1162
1059
1025
1059
1162
1324
1536
1783
Note that the center is still around 2048, but the amplitude only goes up and down by about 1024.



Wednesday, August 2, 2017

Plotting a maidenhead grid square in aprsisce

Plotting a maidenhead grid square in aprsisce


The WSPR protocol uses Maidenhead grid squares to plot location.  The granularity of a 6-character grid square is approximate 3x4 miles, which is fine for WSPR balloons in the air.  Unfortunately, if a payload crashes on the ground, it's not as useful.  Twice, now, I've tried to locate a WSPR payload on the ground by driving around and trying to hear the signal.  I find it useful to have Aprsisce running in my car, and plotting the grid square on the map, so that I know when I'm reaching the borders of the search area.  Unfortunately, I can never remember how I did it.  This blog entry is a "note to self" for the next time this comes up.

Convert grid square to KML

Visit this site, and enter the 6 character grid square.  It outputs a .kml file.

Convert the KML file to a GPX file

Visit this site and conver the kml to gpx.

Load the GPX file as an overlay in aprsisce

Inside aprsisce:  Configure / Overlay / Add GPX file...

Set the opacity and color so that it shows nicely on the map.


AFSK modulation experiments - Part 2

AFSK modulation experiments - Part 2

Prelude

The experiments below were an initial attempt at modulation.  After posting this blog, I discovered I made an error.  the VC pin should take values between 0 .. 3v3.  I was attempting to modulate with an AC voltage, which was broken in several different ways.  Live and learn.

The erroneous post follows, for posterity.  However, corrections will be evident in blog posts made after this one.

Read below at your own peril.  I made lots of mistakes!!!

Test code

So, I'm using the Etherkit Library to generate my signals.  I used a little test code this evening to configure the VCXO and generate a signal at 144.330.  I then attached my signal generator to the VC pin and adjusted the frequency and amplitude to see if I could modulate my signal.  It worked!

The code is mostly just the example code available on his site.
// ASTXR-12-26.000MHz-512545 TCXO is 26 MHZ.  We use 0PF, since it's a TCXO and not a crystal.
MySi5351.init(SI5351_CRYSTAL_LOAD_0PF, 26000000UL, 0UL);
// power down the unused clocks
MySi5351.set_clock_pwr(SI5351_CLK1, DISABLE);
MySi5351.set_clock_pwr(SI5351_CLK2, DISABLE);
// Turn off transmit on unused clocks
XMITOFF(SI5351_CLK1);
XMITOFF(SI5351_CLK2);
MySi5351.set_clock_pwr(SI5351_CLK0, ENABLE);
XMITOFF(SI5351_CLK0);
MySi5351.drive_strength(SI5351_CLK0,SI5351_DRIVE_8MA); // Max power
MySi5351.set_vcxo(86598000000ULL, 40);
// Set CLK0 to be locked to VCXO
MySi5351.set_ms_source(SI5351_CLK0, SI5351_PLLB);
// Tune to 144.390 MHz center frequency
MySi5351.set_freq_manual(14433000000ULL, 86598000000ULL, SI5351_CLK0);
MySi5351.update_status();
MySi5351.output_enable(SI5351_CLK0, ENABLE);

Note, I have not yet fiddled with the PPM parameter as discussed in the previous blog.  I left it at "40" from the example.

Amplitude fiddling

I noticed that the amplitude of the signal generator output changed significantly when plugged into the VC pin.  I dialed the amplitude up and down until I reached a reasonable level, without distortion. I noted that under load, the P2P amplitude was about 1.16v.  When attached to the VC pin, the amplitude went down to about 0.6v p2p.


DAC fiddling

Knowing the amplitude, I was curious what output level the DAC would generate with the sine wave tables I was using for maximum amplitude.  Not surprisingly, it was about 3v p2p.  Not a shocker, since the Si5351 is operating at 3v3.  I needed to lower the amplitude of the DAC output to match what I was getting from the signal generator (1.16v).

The RC filter, tested in the Part 1 blog for this project, cleaned up the signal significantly, and also reduces the amplitude.  That's a start.

DC Blocking Cap


The signal generator makes an AC signal, swinging positive and negative.  The DAC makes a sine wave that is strictly positive.  I introduced a DC blocking cap into the circuit to convert it to AC, and clean it up a bit.

Test circuit



This circuit was sufficient to convert the DAC output to filtered AC.  The P2P voltage was about 1.5 volts, but it was sufficient for testing.  Sure 'nuff, it worked.  Putting the "AC Signal Out" from this filter into the VC pin on the Si5351b modulated the signal, and the tone created on the Nucleo DAC was readable on an FM receiver.

Progress!

Afterword


So, upon further examination, I discovered that I was in error.  The VC pin on the Si5351 requires 0 .. 3v3, all positive.  The experiments I was doing were generating an AC signal, but the modulation was faulty.  I'll have more on this in a future blog post.


Saturday, July 29, 2017

Choosing "pull" value for the Si5351 VCXO for APRS

Choosing "pull" value for the Si5351 VCXO for APRS


When configuring the VCXO frequency on the Si5351b, there is a register setting for the "Pull range".  It is described as follows in Silicon Labs publication AN619 "Manually Generating an Si5351 Register Map":

Set VCXO_Param register value according to the equation below. Note that 1.03 is a margining factor to ensure the full desired pull range is achieved. For a desired pull-range of +/– 30 ppm, the value APR in the equation below is 30, for +/– 60 ppm APR is 60, and so on.
This sounds a lot like the FM Deviation to me, though I wish they used those words.

For APRS, the deviation for the 2200hz tone should be about 3.5khz.  The 1200hz tone will be proportionally lower.  So, I need to do some math:

Desired pull: 3,500 hz.
APRS frequency: 144.390 Mhz.

PPM = 3,500 / 144.390 = 24.2 .  Rounded to an integer, it's "24".

The Etherkit Si5351Arduino library, which I've ported to the STM32CubeMX environment, claims that the PPM value must be in the range of 30 .. 240.  I guess I'll set it to "30" and see how it goes.

Since the library does all the number crunching to calculate the register values, I don't need to calculate them myself..

Correction

Subsequent to posting this blog, I realized that I really want to set the PPM for 5 khz deviation (standard FM), but only modulate my signal to 3-3.5 khz.  Redoing the math:  PPM = 5000 / 144.390 = 34.6, rounded to 35.


Monday, July 10, 2017

AFSK modulation experiments - Part 1

AFSK modulation experiments - Part 1


So, on the next version of my Wisp tracker, I would like to attempt AFSK (APRS) modulation in addition to the WSPR modulation.  The Si5351b clock generator chip provides a VC input pin, which allows for FM modulation.  By using the DAC on the Microcontroller to make the appropriate sine waves, I should be able to achieve the proper 1200 and 2200hz tones necessary to modulate AFSK.

Step 0 of this project is to make a sine wave on an ARM Cortex processor similar to the one I will use in flight. The STM Nucleo L152RE fits the bill nicely.  I use the L151 processor on my Wisp tracker.  I did a fair bit of prototyping for the Wisp1 with this Nucleo.



Using STM32CubeMx, I was able to build some skeleton code to drive the DAC.  I found a Sinewave table online that someone had built that fit the bill nicely.  It had 128 points.

I ran the code, and it generated an absolutely beautiful Sine wave.  Sorry I forgot to take a picture. Unfortunately, when I tried to increase the frequency of the sine wave, I couldn't get above about 1500hz before the microcontroller failed to make a signal.  I didn't look into it deeply, but I suspect there simply wasn't time for the DAC to process the values between interrupts.

I reduced the number of samples from 128 to 36.  It made a respectable sine wave.


Having done that, I was curious how it would look with 12 samples.  As expected, it was rather lumpy.


So, I wondered whether I could throw a simple RC filter into the mix to smooth out the sine wave.  I built one with a 330 ohm resistor and 0.1uF cap.  



According to an online calculator, with those values, the filter cutoff frequency should be about 4825 hz, which is well above the 2200hz I was experimenting with.  Voila.  This is the sine wave with just 12 data points, run through the RC filter.


About attenuation


Note that the signal before filtering was about 3.3v peak to peak.  After the filter, it was about 2.7v peak to peak.  I didn't expect this much attenuation from the filter, but still, it's not bad.  It could simply be due to the breadboard and cheezy connections I was using.  Still, provided that 2.7v is sufficient to swing the signal on the Si5351b to achieve the proper deviation, I should be fine.

Alternatives


Should the attenuation prove too much to make a good signal on the Si5351, I have the option of running without a filter, and just fooling with the number of samples in the sine wave until I strike a good compromise.  Still, I'd really like to use the filter if I can.  I figure the GIGO (Garbage In, Garbage Out) philosophy applies here.  The cleaner the signal I put into the Si5351, the nicer the output should be.

Watch future blog posts for more experiments.


Tuesday, June 6, 2017

High Altitude Balloon flight - 6/3/17 from Rochester, NY Hamfest

High Altitude Balloon flight


Having modified a camera and built a controller, I wanted to fly it to see how the camera worked.  I assembled the payload into a foam box and rigged it up with a parachute.

Photos of the launch


Are available in this album

Payload parameters



Parameter Value
Payload mass 650 g
Parachute 30" octagonal (corner to corner)
Estimated Descent Rate 5.91 m/s (using Hexaagonal)


Flight prediction input


Parameter Value
Location Set with map to the Hamfest venue
Launch Altitude Unset (0)
Launch Time 15:00
Launch Date 6/3/2017
Ascent Rate Initially set to 5.5 m/sec.  Predictor overwrote it to 6.3.
Burst Altitude Left to default at 30,000.  Predictor over wrote it
Descent Rate 6.0 m/sec
Burst Calculator
Payload Mass 650g
Balloon Kaymont 1200
Target Ascent Rate 5.5 m/sec
Advanced
Gas Hydrogen

Flight prediction Output and Actuals


Parameter Predicted Value Actual Value
Burst Altitude 34315 m 33880
Time to burst 93 m 88 m
Ascent Rate 6.12 m/sec 6.388 m/sec
Launch Volume 103.8 cu ft 103.8 cu ft (est)
Descent Rate 5.91 m/sec 10.12 overall
 3.2 m/sec last 2000 feet
Descent Time 133 m 143 m


Flight path comparison


The flight followed the prediction almost exactly!  It landed 10.24 miles further SSE than predicted. The parachute performed very well.  I need to re-measure it to assure it's a 30" (and not 36") chute. That might explain the discrepancy.  NB: I measured it.  Yup, it was a 36" chute.  That explains a lot!


Temperature data


Charts in aprs.fi showed the internal tracker bottoming out about -39 degrees celsius, and the external tracker at -42c.  I didn't work really hard on taping up the box, but it seems that such a large open box with a still camera really doesn't have much thermal mass.  It'll be interesting to see how that changes when I have a video camera in there on the next flight.

Lessons Learned


  • Using a time profile for scheduling the snapshot frequency worked just fine.  It was a good way to get more picture density during interesting periods of the flight.
  • I need to work on sealing the payload box better to see if I can stabilize the temperatures some. Everything functioned, but I would have preferred the cameras stayed warmer.
  • Using the "Landscape" mode on the Kodak Pixpro yielded blurry pictures.  I got some great images, but more than 50% were blurry.  I'm going to try "Sport" mode next time.
  • The camera performed well enough that I have purchased a second one to use as a video mode camera in the payload, and run two at once.
  • I need to remeasure the parachute to see if I can sort out the discrepancy in descent rate.

Sunday, June 4, 2017

Modifying a Kodak Pixpro FZ43 for external shutter control

Modifying a Kodak Pixpro FZ43 for external shutter control


I've been using REALLY cheap 808 Keychain cameras for video on my flights.  I decided I wanted to upgrade to something a little nicer, to get better video and still quality.  There are some cameras out there with open firmware that people are using, but they're on the used market, and won't be available forever.  I figured I'd try to venture off on my own and see what I could do.

Design points:

  • Relatively inexpensive (sub-$100) camera that has decent resolution for video and stills.
  • External microcontroller to run the shutter.  I targetted the Atmel ATTINY13, since I have about 5 of them in my junk box.
  • AA powered camera, so that I can use Energizer Ultimate Lithiums (good in cold weather)
  • Depending on battery life when testing, I might want to wire in more batteries in parallel to allow for more pictures.
After trolling around on Amazon, I settled on the Kodak Pixpro FZ43.  I scored it on Amazon Prime for $64.  


The specs for the camera indicated that it could take about 120 pictures on a pair of batteries.  I would definitely want to wire in more. 

Modification


I opened up the camera, and it was a simple matter to find a little semi-riser where traces led from the shutter.  As expected, pressing the shutter shorts a connection to ground.   I connected two tiny wire-wrap wires to do some testing.



I whacked together a little circuit diagram to control the shutter from my ATTINY13 chip.  I was unsure how much current the shutter might sink, so rather than wiring it directly to the chip, which can only handle about 20ma, I elected to control the shutter via a transistor switch.  A 2N3904 served nicely, and I had a about 8 of 'em in my parts box.



I confirmed that I could trigger the shutter by holding the pin (PB3 in my setup) high for 1/2 second. I assumed there would be some button de-bouncing done by the camera, so I started with 1/2 second, and it worked, so I left it.  It worked like a champ.

First Test


With the camera working by microcontroller, I decided to do a duration test to see how the batteries held up.  I turned off the flash, and left the camera running, taking one picture per minute, overnight with just a pair of internal batteries.  The documentation stated about 120 pictures.  I got 460!  Those Ultimate Lithium batteries really rock!  Also, there was no flash, and we were operating at room temperature, so in flight, I'm SURE there would be less capacity.  I settled on wiring in two additional batteries in parallel with the camera, for flight, assuming that I could do 400-500 still shots in flight without difficulty.

For balloon operations, I also like to have a beeper on the payload.  I decided to put that under microcontroller as well, since hell, I'm a geek and idle hands are the devil's playground!  The final schematic looked like this.



Again, I used a transistor for the beeper.  In testing, it was drawing well under 20ma, but I wasn't sure what the surge current was, so rather than take a chance, I tossed in another transistor.

Here are the final mods to the camera.  I found a third pin that had the VCC rail on it.  I put a wire to that, and secured it down with a little kapton tape.  The wires are strain-relieved by knots on the inside of the case, which are too big to pass through the holes I drilled.



I decided I would attach the camera to my controller and external batteries via a connector with some riser pins on it.  Here's the finished product.


Having tested all functions on breadboard, I just needed to whack together a little board for the payload.  Here's the finished product, sitting on top of the breadboard mock-up.  Subsequent to this picture, I wired in a few LEDs which fire when the transistors do.  This just gives some visual indication that things are working, even if the camera or beeper aren't attached.

I set up the board to be powered from a bus which consists of the two external batteries wired in parallel to the internal camera batteries.  The circuit, therefore, runs on 3.0 volts, which is well within spec of the ATTINY13.  I did reset a "brownout" software fuse on the chip to make sure that it didn't reboot if it had a bit of voltage drop.

I built the board with an 8-DIP socket on it, so that I could externally program the chip, test it on my breadboard, and then just pop it off, and transfer it to the flight board.  That way I didn't need to put programming risers on the flight board.


I ran predictions for my first flight.  It estimated 93 minutes to burst, and 135 minutes to landing.  So, I wrote code for the ATTINY such that it took 6 pictures per minute in a 15 minute around burst time, and around landing time.  I scaled back the picture rate during "boring" times for the flight.

Final flight configuration

Here's a picture of all the "guts" of my first flight payload.    The green thing on the left is the tracker, which runs on one AAA battery.  Then, I have the camera, flight board, beeper, and the two batteries that supplement the camera.  The two batteries in the upper left are for the camera itself.



The first flight showed that this system worked like a champ!  I was getting 6 pictures per minute at burst, and at landing time.  This allowed me balance battery power (and weight) against the desire to get interesting pictures.

First flight.  Two minutes after apogee, on the descent.  That's Lake Ontario in the background.


Next Steps


While the shutter mechanism worked great, I was disappointed in the focus of the pictures.  The camera does auto-focus on the center of the screen,  An unfortunate number of the photos were out of focus.  I'm going to mess with the settings to see if I can do better, or perhaps have it hard-code to "focus on infinity".

Also, this worked very nicely.  I'm getting a second camera which I will wire similarly.  I'd like to have one taking stills and another taking video.  I'll wire up the video record shutter (a different button) on the second camera, in addition to the shutter, so I'll have a 4-wire configuration.  The microcontroller will then be able to switch between video and stills, should I choose.



Thursday, January 19, 2017

Hojo and the case of the faulty FT-2800M

Hojo and the case of the faulty FT-2800M


Background

A friend, Joe / W2IFB mentioned that he had a Yaesu FT-2800M fail on him.  He had been keyed in a long QSO for more than 10 minutes when the radio failed, catastrophically.  Thinking that he had blown the final, he tried replacing the final transistor.  Unfortunately, it didn't work.  He reported that the radio was basically in a "short" when plugged in.

He gave me the radio and said "It's yours!  If you fix it, maybe I'll buy it back!"  I accepted the challenge.

Initial testing


I took the radio and set the current limiting on my power supply to 300ma, figuring that would be sufficient to demonstrate a problem.  I plugged the radio in, and sure enough, it was drawing current HARD.  Placing my ohm meter across the power leads, it showed 0 ohms.  It's in a dead short.

Investigation


I opened up the radio and snooped around the board a little.  I saw the power transistor that had been replaced, but didn't see any shorts nearby.  It also seemed unlikely that a problem in the final would cause a dead short when the radio was still powered off.   I also observed what appears to be a two-turn inductor coil that may have gotten a bit smushed.  None of this looked like the cause of the short, however.



I pulled out the schematics and took a look at the routing of the power.  I assume the short must be very early in the circuit, since the unit uses a soft power switch, and it hasn't even been powered on. Glancing at the schematic, and board, I saw a few voltage regulators, and a protection diode.




The protection diode was right near the edge of the board, and an obvious first thing to check.  It's a clamping diode, so a surge of some kind may have caused it to fail.


I removed the diode from the board, and sure enough!  It's a dead short.  0 ohms in both directions. Further, I hooked it to the power supply and confirmed that the diode was permitting full voltage rom the supply through it in both directions.  It's blown.



Yaesu is kind enough to list the manufacturers part number in their service manual.  Digi-key has the part for $0.48.  I'll tuck one onto my next order.

Further testing


With the diode removed, the power leads no longer showed a short.  Encouraged, I decided to simply hook power to the board and see if the current draw was reasonable. The head was still detached, so I didn't expect the radio to power on. Sure enough,  the current draw was down in the 10s of milliamps. I think that's reasonable.

Hooking up a more beefy power supply, I was able to run through a full suite of tests, and confirm that it was simply the diode at fault.  The radio was working just fine.

Repair and Alignment

I ordered up the diode and got it in from Digi-Key.  The installation was trivial.

I went ahead and did a few tests prior to aligning the radio.  It was transmitting about -650 hz off frequency at 146.000.  Most other metrics seemed good, though it was only making about 50 watts on high power (should be 65).

The Jig

The perform the alignment, I needed to inject signals into the microphone port.  I decided to make a jig that I could use for this project, and in the future.  

 I built a 6-pin cable to use for the project, and sorted out the pinout.  Yaesu uses a common ground for the Mic and PTT.  The Mic inputs go to the BNC port.  The PTT goes to the toggle switch.


The finished product.  Now I can pump signals right from my service monitor into the mic port on the radio.  The toggle switch makes it easy to engage the PTT without holding a button,



Alignment Details

I followed the alignment procedure from the manual.  Notes here for posterity.


Adjustment Original Value Adjusted Value
PLL Reference -645 hz -15 hz
TP-TVC 1.547 v 1.502
TP-TVC 0.925 v Not adjusted.  Broken Trim Pot.
Target value was 1.3 v.
TUN 137 1.987 v 2.009 v
TUN 146  2.050 v 2.051 v
TUN 160 2.026 v 2.026 v
TUN 173 2.018 v 2.018 v
TXPW H 50 w 65 w

All other setting values were already optimal when measured, and were left alone.  Current readings on transmit were all well under published maximums.



Sunday, January 15, 2017

RCA WV988 VTVM recap and repair

The purchase


I found an RCA WV988 VTVM at a hamfest.  It was labeled "Works - $10".  I figured it would be a fun project to learn a little about recapping and tube based equipment.  It has a minor crack in the face, but I don't really care.  I'm more interested in this VTVM for the "puttering" aspects than for usability.  Still, it'll be nice to have an analog meter on my bench if I get it working well.  It's got a nice big display, and the crack doesn't impede use.

I managed to find a manual for it online.  It's one one electrolytic cap, which I'll replace.  It's also got a selenium rectifier, which can release toxic "magic smoke" at failure.  The interwebz recommend replacing that with a diode and series resistor.

A peek inside


A previous owner had soldered in a D-cell battery to operate the Ohm meter.  I'll pull that out, and put in a battery holder.  Also, clearly in view are the electrolytic capacitor and the selenium rectifier that will need to go.


Checking it out


I went through and tried all the basic functions.  They were all pretty good, though it was slightly out of calibration.  I'll go through and attempt a recalibration after repairing it.

Installing a battery holder


Easy enough.  I desoldered the D-cell, and put in a AA battery holder.  I drilled a small hole in the plastic holder, and countersunk it a little. I used the existing screw to install the new holder.  I soldered in the wires and used a bit of heat shrink to insulate.

The Old Battery, Soldered in.

Battery removed.  I'll reuse that screw in the center of the old holder.

Hole drilled in AA holder, and countersunk a little, so the screw isn't in the way of the battery.

Installed, with a little shrink-wrap on the wiring.

Now the battery is easily replaced.


Replacing the cap and rectifier


The cap was a 20uF 200v.  That was easily replaced.  The rectifier is rated tat 20mA.  It's easily replaced with a 1N4004 diode and a 2 Watt, 820 ohm series resistor.   I followed the basic recipe in Rich Bonkowski's (W3HWJ) excellent article.  I tried a few different resistors until I got a voltage that matched what I was reading prior to the replacement.

Since I was installing one additional component (the resistor) in series, I drilled two new holes in the board, and ran the diode to one of the new holes, and then connected the resistor from the adjoining hole to the other rectifier pin.  Since there was no trace on the board for that connection, I simply extended the leads to one another, twisted them once, and soldered them together.  The result looked nice and tidy.

The old rectifier and cap.


The PCB from the back side.  The two new holes (bottom box) have leads through them from the diode and resistor.  I simply twisted together and soldered them.  The existing pads from the rectifier and cap are marked.



The final installation of the diode, resistor and new cap.

Testing

Upon testing, it appears that the DC voltage calibration was off, and it is at the limit of the variable resistor for tuning.  It's off by around 1 volt.  More follows as I sort out the issue.