Monday, August 11, 2014

Si570 Arduino Shield PCB is off to be manufactured

I finished up the Si570 shield for the Arduino today and sent the gerber files off the the fab house today.  They will be on the panel to be produced on 13 Aug, so hopefully I will have some prototype PCBs back soon.


Sunday, August 10, 2014

Si570 shield progress

I have spent some time today working on my Si570 Arduino shield.  A few changes:
  1. Added a 3.3V regulator on the board with a separate power input (9-12v) as with dual Si570 devices on the board, I don't want to draw that current from the Arduino regulator.
  2. Increased the trace size for the 3V3 power rail off the regulator.
  3. Changed the SMA connector footprint to be appropriate for a much more narrow connector.
  4. I2C multiplexor chip used to drive multiple (up to 4) I2C buses optionally at different logic levels.  I drive the multiplexor at 5V from the Arduino.  Each Si570 is on its own 3V3 bus and two extra busses are available.  I included the 3V3 OLED display on the first Si570 bus.
  5. Hand routing of the mess made by the Eagle auto-router.
To be done:
  1. Replace reset button with one that is actually available.
  2. Rework the SMA connector footprint a little more as it is still marginally too wide.
A lot of discussion was passed back and forth regarding the use of separate connections for the various periphery that will connect this shield to the Minima board.  Most folks suggested that I just use the normal Arduino connectors along the edges for all off-board connections.  I have provided those connections for those that choose to connect in this way or decide to stack another shield on top of the Si570 shield.

I however also included individual connections for individual periphery (encoder, paddles, buttons, PTT, etc.) so that a cable with a ground and signal lines can be connected as a single connector without having to worry about multiplexing ground lines, etc.

Using the I2C multiplexor will require a change to my Si570 driver and OLED driver.  5V I2C displays will not require any code changes as they will be connected directly to the 5V Arduino I2C bus.

Here is a quick screen shot of the board.  It is pretty close to being ready to send off the be manufactured.



I am hoping to get these off to be created this week.

Monday, August 4, 2014

Bug found in Si570 code for Minima

A problem has been discovered in my Si570 code that implements 1Hz tuning.  The code was unnecessarily resetting the DCO on every update when tuning down in frequency.  While setting the frequency correctly, the error was causing the DCO to restart on every increment in frequency producing an audible click in the Minima.  The frequency was being set correctly, just clicking the receiver when it was not necessary.

The error was two-fold.  Firstly, I failed to reserve sufficient bits for the 3500 ppm calculation.  Secondarily, the Arduino absolute value function (abs()) is very quirky and it was just simpler to remove the function from my code.

Lastly, I modified the Si570 code to only calculate the 3500 ppm offset whenever the DCO centre frequency was changed rather than on every frequency change in order to gain a slight performance improvement.

The changes will be posted to my GitHub Si570 repository as soon as I am able.  Meanwhile, here are the changes for the adventurous among us that want to take on the change manually.

In Si570.h, I added a member variable to the Si570 class to hold the calculated 3500 ppm value for the current center frequency.

class Si570
{
public:
  Si570(uint8_t i2c_address, uint32_t calibration_frequency);
  Si570_Status setFrequency(uint32_t newfreq);
  void debugSi570();

  Si570_Status status;

private:
  uint8_t i2c_address;
  uint8_t dco_reg[13];
  uint32_t f_center;
  uint32_t frequency;
  uint16_t hs, n1;
  uint32_t freq_xtal;
  uint64_t fdco;
  uint64_t rfreq;
  uint32_t max_delta;

  uint8_t i2c_read(uint8_t reg_address);
  int i2c_read(uint8_t reg_address, uint8_t *output, uint8_t length);

  void i2c_write(uint8_t reg_address, uint8_t data);
  int i2c_write(uint8_t reg_address, uint8_t *data, uint8_t length);

  bool read_si570();
  void write_si570();
  void qwrite_si570();

  uint8_t getHSDIV();
  uint8_t getN1();
  uint64_t getRFREQ();

  void setRFREQ(uint32_t fnew);
  int findDivisors(uint32_t f);

};

Secondarily, I modified Si570.cpp to initialize max_delta when the Si570 object is constructed in Si570::Si570.

  // We are about the reset the Si570, so set the current and center frequency to the calibration frequency.
  f_center = frequency = calibration_frequency;

  max_delta = ((uint64_t) f_center * 10035LL / 10000LL) - f_center;

Lastly,  I modified the setFrequency function to remove the quirky Arduino abs() function and to set the max_delta value only when it changes.

// Set the Si570 frequency
Si570_Status Si570::setFrequency(uint32_t newfreq) 
{
  // If the current frequency has not changed, we are done
  if (frequency == newfreq)
    return status;

  // Check how far we have moved the frequency
  uint32_t delta_freq = newfreq < f_center ? f_center - newfreq : newfreq - f_center;

  // If the jump is small enough, we don't have to fiddle with the dividers
  if (delta_freq < max_delta) 
  {
    setRFREQ(newfreq);
    frequency = newfreq;
    qwrite_si570();
  }
  else 
  {
    // otherwise it is a big jump and we need a new set of divisors and reset center frequency
    int err = findDivisors(newfreq);
    setRFREQ(newfreq);
    // Set the new center frequency
    f_center = frequency = newfreq;
    // Calculate the new 3500 ppm delta
    max_delta = ((uint64_t) f_center * 10035LL / 10000LL) - f_center;
    write_si570();
  }
  
  return status;

}

My apologies for not catching this bug before the code was made available.  Many thanks to one of the many Minima users "John - MI0DFG" for finding and reporting this issue so that I can get it fixed.

Tuesday, July 29, 2014

Added 60 metre support to Minima tuning

I have updated my Minima code to support channelized 60 metre frequency allocations.  If you select 60 metres through the band up/down buttons, the rotary encoder will now select the next/previous channel frequency and ensure that USB is set.

If on the other hand you tune the VFO to the 5Mhz frequency range without selecting 60 metres with the band switches, you may set any frequency you like or either sideband.

I do not yet support the CW+PSK 1.5 kHz offset from the normal SSB frequencies but plan to add this support soon.

I am pleased with how this is coming together.  I am diverging a bit from the original Minima code, but intend to keep backwards compatibility as long as possible for those that are interested in that.  I use conditional compile options to enable or disable functionality as desired.  For example I can build for the original 6 wire LCD displays (16x2 or 20x4), for I2C displays of the same geometry as the 6 wire displays or for OLED displays.  I can build for the original pot tuning or for a rotary encoder.  I have a special build for Freetronics versions of the Arduino LCD shield. I can also build to support displays that have no notion of a display cursor.

Eventually however, my build will fork completely and become specialized to my needs/desires.  I will maintain the last compatible build as a separate fork from Eldon, WA0UWH's fine work.

My code will soon be available from my github to anyone that would benefit from these changes.

Monday, July 28, 2014

Minima controller breadboard

I spent a little time this evening customizing the Minima controller code a little for my little OLED display.  I will be bringing my breadboard to the pQRP pie and coffee evening this week on Wednesday for people to poke at and give some feedback.  Come join us at Bob's Brew and Burgers in Everett at 19:00, grab a burger and visit.

Sunday, July 27, 2014

Minima breadboard of Controller

I have integrated my keyer code that was originally developed for the Propeller hardware and ported to the Arduino with the Minima firmware.  My Si570 driver enabling 1 Hz tuning, AdaFruit's encoder driver and my latest OLED display have all been integrated with the Minima firmware.

The lash-up I have for tested can be seen below.  This implements a working Minima controller with rotary encoder tuning and an OLED display.  The keyer paddles and sidetone speaker are enabled by the freeing up of LCD display pins by converting the display to I2C.



Rather than build a controller board, I am laying out an Arduino shield board that will contain the Minima's Si570 and connectors for all the other components such as the encoder, display, CW speed control, paddles, PTT and a  myriad of buttons.  I have adopted the button logic pioneered by Eldon, WA0UWH.  The shield will contain solder pads for an optional second Si570 that could be used for a BFO signal, easily set to be optimum for USB, LSB or CW.  Both Si570 devices will have solder pads for a resistive pad to allow easy setting of output level down from the 13 dbm of the Si570.  This would allow experimenting with different mixers for example.  If no attenuation is desired, a 0 ohm resistor or solder jumper may be installed instead.  This also allows for a load resistor to be installed if desired.  Here is a quick screenshot of my current (incomplete) state of things:




I am also laying out a PCB for the Minima transceiver module.  I have gone back and forth on making it SMT or thru-hole and have decided to use SMT as much as possible.  Some of the components will need be thru-hole, but to the degree possible, I will use SMT components.  My build will be pretty generic, though I am contemplating using a different crystal filter as I have a module that has been rattling around in my junque box for a number of years that might be fun to use rather than the discrete crystal filter of the Minima.  If I do use the filter module, I will attempt to lay it out such that it could be built either way.

Meanwhile, I am collecting parts for the build.  



Sunday, July 20, 2014

MicroLCD issues

I have just started investigating why both of my new OLED displays require a 2 pixel offset to the right in order to prevent truncating the display.  Starting out easy, we go with the simplest bit of code to turn on the LCD.

#include <Wire.h>
#include <MicroLCD.h>

LCD_SSD1306 lcd;

void setup()
{
  lcd.begin();
}

void loop()
{
  // put your main code here, to run repeatedly:

}

This code results in the following display.  Notice the white bar on the right side.  The display clear code is already suspect.  Unplugging the display and re-running the code moves the white bar to the left side of the display running the entire way from top to bottom.



This is the code in the LCD initialization function that clears the display.

    ssd1306_command(SSD1306_SETLOWCOLUMN | 0x0);  // low col = 0
    ssd1306_command(SSD1306_SETHIGHCOLUMN | 0x0); // hi col = 0
    ssd1306_command(SSD1306_SETSTARTLINE | 0x0);  // line #0

    for (byte i = 0; i < SSD1306_LCDHEIGHT / 8; i++) {
      // send a bunch of data in one xmission
        ssd1306_command(0xB0 + i);//set page address
        ssd1306_command(0);//set lower column address
        ssd1306_command(0x10);//set higher column address

        for(byte j = 0; j < 8; j++){
            Wire.beginTransmission(_i2caddr);
            Wire.write(0x40);
            for (byte k = 0; k < SSD1306_LCDWIDTH / 8; k++) {
                Wire.write(0);
            }
            Wire.endTransmission();
        }

    }

If I change k < SSD1306_LCDWIDTH to k <= SSD1306_LCDWIDTH then I can get the entire display to clear.  However, this is suspect because as written, it should work logically speaking.

When the device is initialized, if no cursor setting operations are performed, the first text will be displayed in the lower left corner without any truncation.  Once any cursor setting is done, The truncation is present from that point forward.

I will dig into the driver further, but for now I have fixed this by moving the inter-character spacing to the front of a character rather than the end and additionally provide two additional inter-character spaces at the beginning of a line of text.

#include <Wire.h>
#include <MicroLCD.h>


LCD_SSD1306 lcd;
uint8_t invert = 0;

void setup()
{
  lcd.begin();
  lcd.clear();
  for (int i = 0; i < 8; i++)
  {
    lcd.print("A");
    lcd.print(i);
    lcd.print("-----------------");
    lcd.print(i);
    lcd.println("B");
  }

}

loop()
{
}

The code above now displays correctly with no truncation.  This provides for 21 colums by 8 rows of text using the 5x8 font.  When I have time to dig into this further, I will post further updates on this topic.