SI5351 PLL-Steuerung mit dem Tiny85    

Elektronik-Labor   Projekte   AVR  Tiny85



Das Franzis Lernpaket Mikrocontroller


Auf der Suche nach einer Bascom-Ansteuerung für den SI5351 bin ich auf die Seite von Andrew Woodfield, ZL2PD gestoßen: https://www.zl2pd.com/tiny85_si5351_VFO.html.  Mit seinem Code kann man zwei der PLL-Ausgänge  des SI5351 gleichzeitig nutzen, indem beide interne PLLs angesteuert werden. Bei einem geringen Wechsel der Frequenz wird die eigentliche PLL nachgeführt, während die nachfolgenden Teiler konstant bleiben und nur mit ungebrochenen Teilerverhältnissen arbeiten. Dieses Verfahren verspricht ein geringes Phasenrauschen.

Das Programm habe ich auf das Wesentliche gekürzt und mit einer seriellen Ansteuerung versehen. Man kann nun zwei Kanäle mit 9600 Baud in ganzen Kilohertz  ansteuern:

x7000     gibt 7 MHz an Clk0 aus
y14000   gibt  14 MHz an Clk1aus

Beim Start und ohne weitere serielle Steuerung wird eine Frequenz von  
14296 kHz an Clk 1 erzeugt, die ich für meinen FT8-Sender nach der Dritten Methode brauche.

'------------------------------------------------------------------
' si5351a DDS Oscillator with I2C LCD display
' Author: Andrew Woodfield ZL2PD
' Date: March 2016
' File Name: si85vfoxx.bas (where xx is version number)
'
' Released under the terms and conditions of the
' Creative Commons Public License ("CCPL")
' See creativecommons.org for details
'
' Commercial use is prohibited without written permission
' from the author
'
'------------------------------------------------------------------
' Adapted from boardtest11.bas:
'
' V01: initial code
'
'------------------------------------------------------------------
' Credits:
'
' I2C LCD code adapted from www.ne.jp/asahi/shared/o-family/ElecRoom/ElecMAIN.htm
' si5351 code is adapted from OE1CGS and Jason Milldrum C code
'

'
'------------------------------------------------------------------
' Strpped down for basic operation and control over RS232
' by Burkhard Kainka, DK7JD, March 2019

'------------------------------------------------------------------

'------------------------------------------------------------------
' Compiler Directives (some fundamental hardware issues)

$regfile = "attiny85.dat"
$crystal = 8000000
$hwstack = 128
$swstack = 64
$framesize = 128

Open "comb.2:9600,8,n,1" For Input As #1
Config Portb = Output
Config Sda = Portb.4
Config Scl = Portb.3
I2cinit
Waitms 50
Si5351init
Waitms 500
Gfreq = 14296000 '14296 kHz an Ckl 1
Clk = 1
Setfreq
Waitms 500

Do
Dat = Ischarwaiting(#1)
If Dat > 0 Then
Input #1 , Zeile
Komm = Left(zeile , 1)
L = Len(zeile)
L = L - 1
Zeile = Right(zeile , L)

If Komm = "x" Then 'Frequenz 0
Freq = Val(zeile)
Gfreq = Freq * 1000
Clk = 0
Setfreq
End If

If Komm = "y" Then 'Frequenz 1
Freq = Val(zeile)
Gfreq = Freq * 1000 '
Clk = 1
Setfreq
End If
End If
Loop
(Software gekürzt)

Download:
si5351_Tiny85.zip


Verwendung der Arduino-IDE

Die meisten bisherigen Versuche mit dem SI5351 habe ich mit dem Arduino Uno durchgeführt. Dabei sind auch so schöne Sachen wie Stehwellenmessbrücken, CW-Sender und WSPR-Baken herausgekommen. Es macht daher Sinn, auch den Tiny85 in Arduino-C zu programmieren, um weitere Ressourcen nutzen zu können. Aber es gibt zwei Probleme. Zum einen sind die meisten Programme zu groß für den Tiny85. Und sie verwenden die I2C-Handware und den Hardware-UART. Beides fehlt dem ATtiny. Meist wird die Wire Bibliothek verwendet, die eine ATmega voraussetzt.

Als Ersatz gibt es die Library SoftI2CMaster (https://github.com/felias-fogg/SoftI2CMaster), die auch mit einem ATtiny einsetzbar ist. Das funktioniert dann nach dem selben Muster, wie es auch Bascom macht. Und für den SI5351 habe ich in Github das Projekt si5351mcu von Pavel Milanes  gefunden (https://github.com/pavelmc/Si5351mcu). Er hatte das Ziel, den Code besonders kompakt zu schreiben und alle Umschalt-Geräusche bei einer neuen Frequenzwahl zu vermeiden. Das gelingt ihm, indem er ebenfalls wie in dem obigen Bascom-Programm die PLL verstellt, aber die Nachteiler konstant lässt. Damit verbunden ist auch hier die Einschränkung, dass nur zwei Kanäle gleichzeitig genutzt werden können. Allerdings verwendet er ebenfalls die Wire-Bibliothek. Im ersten Ansatz habe ich sein Beispiel si5351_mcu_simple mit einem Arduino Uno und dem Elektor SDR-Shield getestet. Dabei wurde noch die I2C Hardware-Schnittstelle verwendet.


/*
* si5351mcu - Si5351 library for Arduino, MCU tuned for size and click-less
*
* This is the packed simplest example.
*
* Copyright (C) 2017 Pavel Milanes <pavelmc@gmail.com>
*
* Many chunk of codes are derived-from/copied from other libs
* all GNU GPL licenced:
* - Linux Kernel (www.kernel.org)
* - Hans Summers libs and demo code (qrp-labs.com)
* - Etherkit (NT7S) Si5351 libs on github
* - DK7IH example.
* - Jerry Gaffke integer routines for the bitx20 group
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/


/***************************************************************************
* Just put two frequencies out in clk0 and clk1 at different power levels
*
* Take into account your XTAL error, see Si.correction(###) below
***************************************************************************/


#include "si5351mcu.h"

// lib instantiation as "Si"
Si5351mcu Si;

// some variables
long F1 = 14296000; // 14.0 MHz to CLK0

void setup() {
Si.init(25000000);
// set max power to both outputs
Si.setPower(0, SIOUT_8mA);
Si.setPower(2, SIOUT_8mA);
Si.setFreq(0, F1);
Si.setFreq(2, F1);
Si.reset();
Si.enable(0);
Si.enable(2);
}

void loop() {
// do nothing
}
Im nächsten Schritt sollte versucht werden, dem Projekt den SoftI2CMaster unterzuschieben. Ohne Änderung der Hardware würden dann die Port C.4 als SDA und C.5 als SCL angesteuert. Der Umbau war aber nicht ganz einfach, weil der WIRE innerhalb der Bibliothek  si5351mcu eingebunden wurde und weil außerdem die Funktionsaufrufe etwas anders heißen und etwas anders genutzt werden. Ich musste also den Quelltext der Bibliothek selbst verändern.  Aus der Datei si5351mcu.h wurde die Wire.h entfernt

//#include "Wire.h"

und statt dessen wurde in si5351mcu.cpp die Software-Version eingefügt, zusammen mit den Pin-Deklarationen noch für den ATmega:


#define SDA_PORT PORTC
#define SDA_PIN 4
#define SCL_PORT PORTC
#define SCL_PIN 5
#include "Arduino.h"
#include "si5351mcu.h"
#include "SoftI2CMaster.h"
}

Die eigentlichen  Datenzugriffe finden sich sehr kompakt an Ende in der Funktion i2cWrite, die jeweils ein Byte in ein Register schreibt.  Hier konnten die Software-Kommandos leicht ausgetaucht werden.



/****************************************************************************
* Private function to send the register data to the Si5351, arduino way.
***************************************************************************/
void Si5351mcu::i2cWrite(byte regist, byte value){
i2c_start(SIADDR << 1);
i2c_write(regist);
i2c_write(value);
i2c_stop();

// Wire.beginTransmission(SIADDR);
// Wire.write(regist);
// Wire.write(value);
// Wire.endTransmission();
}

Beim ersten Versuch wollte das noch nicht funktionieren. Ich konnte zwar mit dem Oszilloskop die SDA-Daten und die SCL-Impulspakete deutlich sehen, aber der PLL-Baustein zeigte keine Reaktion. Dann ist mit ein Problem wieder eingefallen, das beim I2C-Bus häufiger auftaucht. Es ist nicht ganz eindeutig, ob das R/Wr-Bit mit zu Adresse gehört oder nicht. Wire geht von einer 7-Bit-Adresse aus und fügt bei einem Schreibvorgang selbst die 0 als achtes Bit an. SoftI2CMaster dagegen verwendet eine 8-Bit-Schreibadresse und eine um 1 erhöhte 8-Bit-Leseadresse. Ich musste daher die Slave-Adresse SIADR um ein Bit nach links shiften, also praktisch mit 2 multiplizieren. Damit funktionierte alles auf dem Arduino Uno.

Der nächste Schritt ist, es für den Tiny85 einzurichten. Dazu muss ich nur noch die I2C-Busleitungen an den Port B des Tiny85 anpassen.

#define SDA_PORT PORTB
#define SDA_PIN 4
#define SCL_PORT PORTB
#define SCL_PIN 3
#include "Arduino.h"
#include "si5351mcu.h"
#include "SoftI2CMaster.h"
Download (ino, hex und Library-src):  si5351_mcu_85.zip

Am Ende musste noch das kompilierte hex-File aus seinem temp-Verzeichnis abgefangen werden. Mit der Software aus dem Lernpaket Mikrocontroller konnte es dann in den Tiny85 gebrannt werden. Das hat auch sofort funktioniert. Inzwischen verrichtet der Generator seinen Dienst in meinem FT8-Transceiver. Bei dem Vergleich Bascom/Arduino ist mir übrigens wieder aufgefallen, dass Bascom sehr viel sparsamer mit dem Flash umgeht.  Die Arduino-IDE erzeugt dagegen besonders große Hex-Files.



Elektronik-Labor   Projekte   AVR  Tiny85