A tiny sdr prototype based on FST3253 mixer driven by a quadrature signal from Si5351 and controlled by Attiny13 |
Setting up the correct values in the devices registers are needed to output a required frequency by this device and most of the currently available libraries uses at least a few kilobytes. After seeing an interesting post from Ram (vu3xvr), where he uses attiny13 with limited flash size, thought of doing the same with avr-gcc and building a simple library for rapid prototyping. I borrowed the math routines for division and multiplications available among the avr-communities in assembly for
doing 32bit math on the 8bit avr. In addition parts of i2c library by Peter Fleury is used to communicate with the chip.
Hans Summers from qrplab has several examples and details on the pll settings (esp, the application note needs reading in betwen the lines). Jason (NT7S) has an excellent library which is recommended if you have enough flash size to spare as my library has some limitations at the expense of reduced flash usage.
The wiring for Si5351 is very simple and is mentioned else where (See here)
- simple library to use with avr / arduino to set frequency on Si5351
- uses a mix of assembly and c to achieve the register settings
- takes less than 1000 bytes, so useful with attiny13
- If you want to use Arduino platform, just install a microcore for attiny with link time optimisation (LTO) Link
- It use a bitbang i2c, So use PB1 (SCL) & PB2 (SDA)on attiny13 (can be changed to any pin in i2cmaster.S file in the library)
- There is an example sketch (tinypll - takes around 960 bytes of flash), just upload it via an isp programmer (usbasp, or use an arduino uno as isp) and it generates a signal at 10MHZ and can be adjusted a few kHz upward by applying a voltage (0-vcc) on ADC3 of the attiny13
- For testing it on an arduino uno, you can use the same test sketch and see the enclosed pinout diagram to locate PB1 (Digital pin 9) , PB2 (pin 10) and ADC3 (A3) on the uno.
- For sdr application, to generate a quadrature output and to reduce the jitter, i used a different approach (slightly larger code size-200bytes more) where PLL frequency is changed and an integral divider is used in the multi-synth (will update later )
The entire code is available for download on github
If interested only in the avr-gcc version - download
To vary the frequency in the test program, connect a potentiometer (wiper)to the ADC input and connect the the other ends to the vcc and ground to get a variable voltage from 0-vcc
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | #include <avr/io.h> #include "tiny5351.h" void InitADC() { ADMUX |= (1<<REFS0); //set prescaller to 128 and enable ADC ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN); } #if defined(__AVR_ATmega328P__) uint16_t ReadADC(uint8_t ADCchannel) { //select ADC channel with safety mask ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F); //single conversion mode ADCSRA |= (1<<ADSC); // wait until ADC conversion is complete while( ADCSRA & (1<<ADSC) ); return ADC; } #else //ADC on ATTINY13 #define REF_AVCC (0<<REFS0) // reference = AVCC // select the corresponding channel 0~N and set reference uint16_t ReadADC(uint8_t ADCchannel) { ADMUX = REF_AVCC | ADCchannel; // set reference and channel ADMUX |= _BV(ADLAR); // left adjust of ADC result ADCSRA |= (1<<ADSC); // start conversion while(ADCSRA & (1<<ADSC)){} // wait for conversion complete return ADC; } #endif void setup() { // put your setup code here, to run once: #if defined(__AVR_ATmega328P__) //set adc input pin DDRC &=~(1<<PC3); //input onPC3 ie A3 on Arduino Uno with Atmega328p #else DDRB &=~(1<<PB3); // For attiny it is PB3 for adc input #endif uint32_t frequency=10000000UL; uint16_t t; uint16_t prv_t = 0; InitADC(); sei(); } void loop() { // put your main code here, to run repeatedly: t = ReadADC(3); if (prv_t != t) { si5351_freq(frequency+(t<<7), 0); //multiply adc value with 128 0-1023 becomes 0-(1023*128) prv_t = t; } } |
For avr-gcc users, there is a zip file in the package with make files
Just edit to change your programmer and the microcontroller. For e.g to test with an arduino uno,
just use the Makefile.uno (make -f Makefile.uno & make flash)
To use with arduino ide, just download and keep the folder inside the libraries folder and there is an example sketch in the tinypll
The library has routine to set the frequency which is very minimal and uses a fixed pll frequency and available divider to get the target frequency. To improve the phase noise /jitter , an alternative routine can be made where the divider can be kept as a fixed integer and vary the pll frequency (multiplier)
I2C pins are controlled by bitbanging and can be changed by editing the assembly files (inside the library). By default PB1 and PB2 is used.
Riyas, You have done good job in putting the things for avr-gcc. Even I had once tried decoding Yaali Transceiver from VU3XVR)assembly code. Ramsankar's assembly knowledge to be applauded. Thanks a lot again..
ReplyDeleteDE, VU3UJW, PRAVEEN