Tuesday, March 26, 2019

YAALI 40 CW TCVR Using SI5351 DDS VFO and ATtiny13 Assembly Language NOT ARDUINO

This project is to show the efficiency of ASM aka assembly language to control SI5351. The Source code can be found at the bottom.

Yaali / Yali : The meaning is a mythical creature seen in many South Indian sculptures. It may be portrayed as part lion, part elephant and part horse. Source: wikipedia


    V U 3 X V R
    Si5351 Clock Generator using ATtiny13
    Programmed By : Ram Sankar Pillai
    Date : 25-June-2018
    Version : 1.0
    Microcontroller Clock Speed = 1.2MHz using internal oscillator 9.6MHz/8 = 1.2MHz
    8bit Timer0 overflow interrupt set to occur every 0.012Secons = 12millis
    I2C data transfer using BIT-BANG method.
.include "tn13def.inc"

;**** Ports ****

.equ    SDAPORT     = PORTB
.equ    SDABIT      = PORTB0
.equ    SDADDR      = DDRB
.equ    SDAPIN      = PINB

.equ    SCLPORT     = PORTB
.equ    SCLBIT      = PORTB1
.equ    SCLDDR      = DDRB
.equ    SCLPIN      = PINB

.equ    txPORT    = PORTB
.equ    txBIT        = PORTB2
.equ    txDDR        = DDRB
.equ    txPIN        = PINB

.equ    keyPORT    = PORTB
.equ    keyBIT    = PORTB4
.equ    keyDDR    = DDRB
.equ    keyPIN    = PINB

.equ    b_dir        = 0            ; transfer direction bit in i2cadr
.equ    txFlagBit    = 0        ; BIT0 of flagRegister SRAM # 128
.equ    txDelayTimeFlagBit = 1 ; BIT1 of RX/TX switching delay time
;****  Registers  ****
.def    i2cdata    = r17            ; I2C data transfer register
.def    i2cadr    = r18            ; I2C address and direction register

.def    regNum    = r20
.def    regVal    = r21

.def    A            = r16
;.def    lastFreqVal     = r17
;.def    currentFreqVal     = r18
;.def    adcFreqByte1     = r19
;.def    adcFreqByte2     = r20
;.def    adcFreqByte3     = r21
.def    btnCount         = r22
.def    currentBtnAdcVal     = R23

.def    tempFreqByte1    = R25
.def    tempFreqByte2    = R26
.def    tempFreqByte3    = R27   

.def    counter            = R30
;********** Division def *****************
.def    remainder1     = R0
.def    remainder2     = R1
.def    remainder3     = R2
.def    remainder4     = R3
.def    remainder5     = R4
.def    remainder6     = R5

.def    dividend1      = r16
.def    dividend2      = r17
.def    dividend3      = r18
.def    dividend4      = r19
.def    dividend5      = r20
.def    dividend6      = r21

.def    divisor1       = r24
.def    divisor2       = r25
.def    divisor3       = r26
.def    divisor4       = r27
.def    divisor5       = r28
.def    divisor6       = r29

;********** Multiply def ******************
.def    ANS1 = R0           ;64-Bit Answer
.def    ANS2 = R1           ;
.def  ANS3 = R2           ;
.def  ANS4 = R3           ;
.def  ANS5 = R4           ;
.def  ANS6 = R5           ;
.def  ANS7 = R6           ;
.def  ANS8 = R7           ;

.def    A1 = R16          ;Multiplicand
.def  A2 = R17          ;
.def  A3 = R18          ;
.def  A4 = R19          ;
.def  B1 = R20          ;Multiplier
.def  B2 = R21          ;
.def  B3 = R22          ;
.def  B4 = R23          ;

.def  C = R24          ;Loop Counter  
.def    freqByte1 = R8 ; do not change as it is not deleted by CLEAR ALL
.def    freqByte2 = R9
.def    freqByte3 = R10
;.def    freqByte4 = R11

;___________________ START OF SRAM ADDRESS  _____________________________________
aByte1:    .byte 1
aByte2:    .byte 1

bByte1:    .byte 1
bByte2:    .byte 1
bByte3:    .byte 1
bByte4:    .byte 1
b48bit1:    .byte 1
b48bit2:    .byte 1
b48bit3:    .byte 1
b48bit4:    .byte 1
b48bit5:    .byte 1
b48bit6:    .byte 1
p1Byte1:    .byte 1
p1Byte2:    .byte 1

p2Byte1:    .byte 1
p2Byte2:    .byte 1
p2Byte3:    .byte 1

aTimes128B1:    .byte 1
aTimes128B2:    .byte 1

bTimes128b1:    .byte 1
bTimes128b2:    .byte 1
bTimes128b3:    .byte 1
bTimes128b4:    .byte 1

bTimes128byC:    .byte 1

cTimes128bbyC1:    .byte 1
cTimes128bbyC2:    .byte 1
cTimes128bbyC3:    .byte 1
cTimes128bbyC4:    .byte 1

synth:        .byte 1
flagRegister:    .byte 1
lastFreqVal:        .byte 1
currentFreqVal:    .byte 1

temp1: .byte 1
temp2: .byte 1

.equ    pllFreq    = 810000000
.equ    fr1    = 2970000+700
.equ    fr2    = 7022300


.ORG    0x000    RJMP onReset ;RESET VECTOR
.ORG    0x003 RJMP    TIMER0_OVF

TIMER0_OVF: ;  0.012 seconds; @1.2MHz clk; 12 milli second
    PUSH    A
    INC    counter
    LDI    A, 0b0010_0011 ; select ADC 03 = Tunning
    RCALL    readADC
    STS    currentFreqVal, A
    OUT    TCNT0,A
    POP    A

    OUT    SPL, A   

;    LDI    A,0b0000_0011 ; CLK 1/64
    LDI    A,0b0000_0101 ; CLK 1/1024
    OUT    TCCR0B, A
    LDI    A,0b0000_0010 ;ENABLE TIMER1 OVF, TIMER0_OVF
    OUT    TIMSK0, A
    OUT    TCNT0, A

    LDI    A, 0b1000_0011    ; ADC clock should be 100 to 200KHz,     Processor Clock Speed / 100k = x(round up to next division factor)
    OUT    ADCSRA, A        ; ADC enable, ADC prescaler division factor 10

    SBI    txDDR, txBIT
    CBI    keyDDR, keyBIT
    SBI    keyPORT, keyBIT
;************ I2C INIT *********************
    SBI    SDADDR, SDABIT ; as output
    SBI    SCLDDR, SCLBIT ; as output

;************ PLL SETTINGS *******************       
; Except PLL parameter #29, 32 all are ZERO only.
; 810MHZ DIV 27 MHz, then a=30; b=0; c=0
; becomes P1 = 3328 0b0000_1101_0000_0000
    LDI    regNum, 29
    LDI    regVal, 0b0000_1101
    RCALL    i2cSend

;    LDI    regNum, 32
;    LDI    regVal, 0b0000_1101
;    RCALL    i2cSend

; ******* One Time Settings *****************
    LDI    regNum, 16 ; CLK0 enable
    LDI    regVal, 0b0100_1101
    RCALL    i2cSend

;    LDI    regNum, 17 ; CLK1 disable
;    LDI    regVal, 0b0100_1101
;    RCALL    i2cSend

    LDI    regNum, 18 ; CLK2 enable
    LDI    regVal, 0b0100_1101
    RCALL    i2cSend

    LDI    regNum, 177 ; PLL Reset
    LDI    regVal, 0xAC
    RCALL    i2cSend

    LDI    regNum, 183 ; capacitor value
    LDI    regVal, 0b1101_0010
    RCALL    i2cSend

    LDI    regNum, 03 ; clock disable
    LDI    regVal, 0b1111_1110
    RCALL    i2cSend
;___________________ MAIN PROGRAM STARTS HERE ________________________________
    SBIS    keyPIN, keyBIT
    RJMP    keyPressed
    RJMP    keyNotPressed

    LDS    A,  flagRegister
    SBRC    A,  txFlagBIT ; skip next if txFlagBIT is 0. ie was in RX mode
    RJMP    checkFreqChange    ; Do nothin, go to main loop
    SBI    txPORT, txBIT
    LDI    regNum, 03 ; clock enable
    LDI    regVal, 0b1111_1010
    RCALL    i2cSend
    LDS    A,  flagRegister
    SBR    A,  (1<<txFLagBIT) | (1<<txDelayTimeFlagBit)
    STS    flagRegister, A
    RJMP    checkFreqChange

    LDS    A,  flagRegister
    SBRS    A,  txFlagBIT ; skip next if txFlagBIT is 1. ie was in TX mode
    RJMP    checkDelayTimeFlag    ; Do nothing, go to main loop
    LDI    regNum, 03 ; clock enable
    LDI    regVal, 0b1111_1110
    RCALL    i2cSend
    LDS    A,  flagRegister
    CBR    A,  1<<txFLagBIT
    STS    flagRegister, A
    CLR    counter
    RJMP    checkFreqChange

    LDS    A,  flagRegister
    SBRS    A,  txDelayTimeFlagBit
    RJMP    checkFreqChange
    CPI    counter, 4 ; 350 millis delay
    BRLO    main ; keyChecked
    CBI    txPORT, txBIT
    LDS    A,  flagRegister
    CBR    A,  1<<txDelayTimeFlagBit
    STS    flagRegister, A
;    RJMP    main

    LDS    A, currentFreqVal
    LDS    R17, lastFreqVal
    CP    R17, A
    BREQ    main
    STS    lastFreqVal, A   
    LDS    R17, currentFreqVal
    CLR    XL
    CLR    XH
    INC    XH
    SUBI    XL, -10
    CPI    XH, 25
    BRLT    ok
    RJMP    mapEnd
    CP    R17, XL
    BRSH    mapStart

.def    ansL    =    R0
.def    ansH    =    R1
.def    multiply8a = R26 ; A
.def    multiply8b = R27 ; B
    MOV    multiply8a, XL ;currentFreqVal
    LDI    multiply8b, 100
    LDI    R28, 8 ; counter for multiply ; C
    CLR    ansH
    MOV    ansL, multiply8b
    LSR    ANSL
    BRCC    skipMul
    ADD    ANSH, multiply8a
    ROR    ANSH
    ROR    ANSL
    DEC    R28
    BRNE    loopMul
;************************ CLK 1 **************************   
    LDI    tempFreqByte1,   LOW(fr1)
    LDI    tempFreqByte2, byte2(fr1)
    LDI    tempFreqByte3, byte3(fr1)

    MOV    freqByte1, tempFreqByte1
    MOV    freqByte2, tempFreqByte2
    MOV    freqByte3, tempFreqByte3

    PUSH    ansL
    PUSH    ansH

    ADD    freqByte1, ansL
    ADC    freqByte2, ansH
    LDI    A, 0
    ADC    freqByte3, A

    LDI    A, 42    ; setting frequency on CLK0
    STS    synth, A
    RCALL    arithmatic

;********************* CLK 2 *******************************
    POP    ansH
    POP    ansL
    LDI    tempFreqByte1,   LOW(fr2)
    LDI    tempFreqByte2, byte2(fr2)
    LDI    tempFreqByte3, byte3(fr2)

    MOV    freqByte1, tempFreqByte1
    MOV    freqByte2, tempFreqByte2
    MOV    freqByte3, tempFreqByte3

    SUB    freqByte1, ansL
    SBC    freqByte2, ansH
    LDI    A, 0
    SBC    freqByte3, A

    LDI    A, 58 ; ; setting frequency on CLK2
    STS    synth, A
    RCALL     arithmatic

    rjmp    main

;______________________ ENF OF MAIN PROGRAM ____________________________
;             Subprogram  delay        *
;    CLR    counter
;    CP    counter, A
;    BRLO    delayNotFinished
    OUT    ADMUX, A     ; AVcc, left adjust( we need just ADCH only), ADC0
    SBI    ADCSRA, ADSC ; start ADC conversion
    SBIS    ADCSRA, ADIF ; look for ADC conversion finish flag ADIF
    RJMP    keep_pooling
    SBI    ADCSRA, ADIF   
    IN    A, ADCH    ; load ADCH into A
;        Set Frequencey subroutines        *

; P1 Registers
;    #46          #45           #44
; MS0_P1[0:7], MS0_P1[15:8], MS0_P1[17:16]
; p1Byte1         p1Byte2,      p1Byte3
; when freq is > 2MHz the P1 will be less than 16bit, hence
; bit 17:16 will become zero.
; #44 also contains R divider value, which is Zero in our case
;  P2 Registers
;    #49          #48           #47
; MS0_P2[0:7], MS0_P2[15:8], MS0_P2[19:16] [3:0]
; p2Byte1         p2Byte2,      p2Byte3

; P3 registers
;    #43          #42           #47
; MS0_P3[0:7], MS0_P3[15:8], MS0_P3[19:16] [7:4]
; p1Byte1         p1Byte2,      p1Byte3

    LDS    regNum, synth ; #42, #50, #58
    LDI    regVal, 0b1111_1111
    RCALL    i2cSend

    INC    regNum    ; #43
    LDI    regVal, 0b1111_1111
    RCALL    i2cSend

    INC regNum        ; #44 this parameter is always ZERO
;    LDI    regNum, 44
;    LDI    regVal, 0x00
;    RCALL    i2cSend

    INC    regNum    ; #45
    LDS    regVal, p1Byte2
    RCALL    i2cSend

    INC    regNum    ; #46
    LDS     regVal, p1Byte1
    RCALL    i2cSend

    INC    regNum    ; #47
    LDS    A, p2Byte3
    ORI    A, 0b1111_0000
    MOV    regVal, A
    RCALL    i2cSend

    INC    regNum    ; #48
    LDS    regVal, p2Byte2
    RCALL    i2cSend

    INC    regNum    ; #49
    LDS    regVal, p2Byte1
    RCALL    i2cSend
    ldi    i2cadr,0xc0;+i2cwr    ; Set device address and write
    rcall    i2c_start        ; Send start condition and address
    MOV    i2cdata,regNum        ; Write word address (0x00)
    rcall    i2c_do_transfer        ; Execute transfer
    MOV    i2cdata,regVal        ; Set write data to 01010101b
    rcall    i2c_do_transfer        ; Execute transfer
    rcall    i2c_stop        ; Send stop condition
    mov    i2cdata,i2cadr        ; copy address to transmitt register
    sbi    SDADDR,SDABIT        ; force SDA low
    rcall    i2cDelay        ; quarter period delay
    sec                ; set carry flag
    rol    i2cdata            ; shift in carry and out bit one
    rjmp    i2c_write_first
    lsl    i2cdata            ; if transmit register empty
    breq    i2c_get_ack        ;    goto get acknowledge
    sbi    SCLDDR,SCLBIT        ; force SCL low
    brcc    i2c_write_low        ; if bit high
    nop                ;    (equalize number of cycles)
    cbi    SDADDR,SDABIT        ;    release SDA
    rjmp    i2c_write_high
i2c_write_low:                ; else
    sbi    SDADDR,SDABIT        ;    force SDA low
    rjmp    i2c_write_high        ;    (equalize number of cycles)
    rcall    i2cDelay        ; half period delay
    cbi    SCLDDR,SCLBIT        ; release SCL
    rcall    i2cDelay        ; half period delay
    rjmp    i2c_write_bit
    sbi    SCLDDR,SCLBIT        ; force SCL low
    cbi    SDADDR,SDABIT        ; release SDA
    rcall    i2cDelay        ; half period delay
    cbi    SCLDDR,SCLBIT        ; release SCL
    sbis    SCLPIN,SCLBIT        ; wait SCL high
                        ;(In case wait states are inserted)
    rjmp    i2c_get_ack_wait
    clc                ; clear carry flag
    sbic    SDAPIN,SDABIT        ; if SDA is high
    sec                ;    set carry flag
    rcall    i2cDelay        ; half period delay
    sbrs    i2cadr,b_dir        ; if dir = write
    rjmp    i2c_write        ;    goto write data
    sbi    SCLDDR,SCLBIT        ; force SCL low
    sbi    SDADDR,SDABIT        ; force SDA low
    rcall    i2cDelay        ; half period delay
    cbi    SCLDDR,SCLBIT        ; release SCL
    rcall    i2cDelay        ; quarter period delay
    cbi    SDADDR,SDABIT        ; release SDA
    rcall    i2cDelay        ; half period delay

;        P1, P2, P3 Arithmatic Functions        *
    RCALL     clearAll
    ldi    dividend1,   low(pllFreq)    ;1 LS-Byte
    ldi    dividend2, byte2(pllFreq)    ;1
    ldi    dividend3, byte3(pllFreq)    ;1
    ldi    dividend4, byte4(pllFreq)    ;1 MS-Byte
    MOV    divisor1, freqByte1           ;1 LS-Byte
    MOV    divisor2, freqByte2           ;1
    MOV    divisor3, freqByte3           ;1
    CLR    divisor4;, freqByte4           ;1 MS-Byte
; this is a + b/c = PLLFreq / Freq
    rcall  divideU32byU32r                ;- result (dividend4-dividend1) should be 1000000 (1000000.49)
    STS    aByte1, dividend1 ; hold value of " a "
    STS    aByte2, dividend2
    MOV    r12, remainder1
    MOV    r13, remainder2
    MOV    r14, remainder3
    MOV    r15, remainder4

    RCALL    clearAll ; aByte & bByte both TESTED OK
; remainder multiply 0xFFFFF
    MOV    a1, r12
    MOV    a2, r13
    MOV    a3, r14
    MOV    a4, r15
    ldi    b1,   low(0xFFFFF)
    ldi    b2, byte2(0xFFFFF)
    ldi    b3, byte3(0xFFFFF)
    RCALL    multiply32x32
    MOV    r12, ans1
    MOV    r13, ans2
    MOV    r14, ans3
    MOV    r15, ans4
    STS    b48bit5, ans5
    STS    b48bit6, ans6
    RCALL    clearAll

; divide by frequency
    MOV    dividend1, r12
    MOV    dividend2, r13
    MOV    dividend3, r14
    MOV    dividend4, r15
    LDS    dividend5, b48bit5
    LDS    dividend6, b48bit6

    MOV    divisor1, freqByte1
    MOV    divisor2, freqByte2
    MOV    divisor3, freqByte3
    CLR    divisor4;, freqByte4

    rcall    divideU32byU32r

    STS    bByte1, dividend1 ; hold value of " b "
    STS    bByte2, dividend2
    STS    bByte3, dividend3
    STS    bByte4, dividend4 ; holds b final value
    RCALL    clearAll

; b times 128
    LDS    A1, bByte1
    LDS    A2, bByte2
    LDS    A3, bByte3
    LDS    A4, bByte4
    LDI   B1,  128;LOW(128)
    rcall    multiply32x32 ; this is = b * 128 ; 32bit answer
    STS    bTimes128b1, ANS1
    STS    bTimes128b2, ANS2
    STS    bTimes128b3, ANS3
    STS    bTimes128b4, ANS4
    RCALL    clearAll
    LDS    dividend1, bTimes128b1
    LDS    dividend2, bTimes128b2
    LDS    dividend3, bTimes128b3
    LDS    dividend4, bTimes128b4

    ldi    divisor1,   low(0xFFFFF)           ;1 LS-Byte
    ldi    divisor2, byte2(0xFFFFF)           ;1
    ldi    divisor3, byte3(0xFFFFF)           ;1
    rcall    divideU32byU32r  ; this result is = 128 * b / 1048575

    STS    bTimes128byC, dividend1
    RCALL    clearAll
; now it = 128 * a
    LDS    A1, aByte1
    LDS    A2, aByte2
    LDI   B1,  128;LOW(128)
    RCALL    multiply32x32 ; i'm getting 14720     ; we are interested in ans1 & ans2 only = 16bit
    MOV    r12, ans1
    MOV    r13, ans2
    RCALL    clearAll
    MOV    add1L, r12
    MOV    add1H, r13
    LDS    add2L, bTimes128byC
    CLR    add2H
    add    add1l, add2l        ;Add low bytes
    adc    add1h, add2h
    STS    temp1, add1L
    STS    temp2, add1H
    RCALL    clearAll
    LDS    sub1L, temp1
    LDS    sub1H, temp2
    LDI    sub2L,   LOW(512)
    LDI    sub2H, BYTE2(512)
    sub    sub1l,sub2l        ;Subtract low bytes
    sbc    sub1h,sub2h        ;Add high byte with carry
    STS    p1Byte1, sub1L
    STS    p1Byte2, sub1H ;  this hold P1 Value.
    RCALL    clearAll
; now it = 128 * b
    LDS    A1,     bByte1
    LDS    A2,    bByte2
    LDS    A3,    bByte3
    LDS    A4,    bByte4
    LDI   B1,  LOW(128)
;    LDI   B2, BYTE2(128)
    RCALL    multiply32x32
    STS    bTimes128b1, ANS1
    STS    bTimes128b2, ANS2
    STS    bTimes128b3, ANS3
    STS    bTimes128b4, ANS4
    RCALL    clearAll
; now it = C *( 128 * b/c )
    LDS    A1,     bTimes128byC
    LDI   B1,   LOW(0xFFFFF)
    LDI   B2, BYTE2(0xFFFFF)
    LDI   B3, BYTE3(0xFFFFF)
    RCALL    multiply32x32
    MOV    r12, ans1
    MOV    r13, ans2
    MOV    r14, ans3
    MOV    r15, ans4
    RCALL    clearAll
; Now subtraction of (128*b) - (c* 128*b/c)
    LDS    sub1byte1, bTimes128b1
    LDS    sub1byte2, bTimes128b2
    LDS    sub1byte3, bTimes128b3
    LDS    sub1byte4, bTimes128b4
    MOV    sub2Byte1, r12
    MOV    sub2Byte2, r13
    MOV    sub2Byte3, r14
    MOV    sub2Byte4, r15
    SUB    sub1byte1,sub2byte1         ;Add the lower bytes together
    SBC    sub1byte2,sub2byte2         ;Add the second bytes and include carry bit
    SBC    sub1byte3,sub2byte3         ;Add the third bytes and include carry bit
    SBC    sub1byte4,sub2byte4         ;Add the fourth bytes and include carry bit
    STS    p2Byte1, sub1byte1 ; this on holds P2 values.
    STS    p2Byte2, sub1byte2
    STS    p2Byte3, sub1byte3
    RCALL    setFrequency

;         CLEAR ALL REGISTERS                    *
clearAll: ; These are registers used in arithmatic functions.
    CLR    R0
    CLR    R1
    CLR    R2
    CLR    R3
    CLR    R4
    CLR    R5
    CLR    R6
    CLR    R7
    CLR    R16
    CLR    R17
    CLR    R18
    CLR    R19
    CLR    R20
    CLR    R21
    CLR    R22
    CLR    R23
    CLR    R24
    CLR    R25
    CLR    R26
    CLR    R27
    CLR    R28
    CLR    R29


;**** add16 Register Variables
.def add1l = r16
.def add1h = r17
.def add2l = r18
.def add2h = r19

;sub32 Register Variables
.DEF  sub1byte1 = R16         ;To hold low byte of value1
.DEF  sub1byte2 = R17         ;To hold second byte of value1
.DEF  sub1byte3 = R18         ;To hold third byte of value1
.DEF  sub1byte4 = R19         ;To hold fourth byte of value1
.DEF  sub2byte1 = R20         ;To hold low byte of value2
.DEF  sub2byte2 = R21         ;To hold second byte of value2
.DEF  sub2byte3 = R22         ;To hold third byte of value2
.DEF  sub2byte4 = R23         ;To hold fourth byte of value2

;* "sub16" - Subtracting 16-bit registers
.def sub1l = r16
.def sub1h = r17
.def sub2l = r18
.def sub2h = r19
;         Start of 32 % 32 bit division             *
;   http://www.avrfreaks.net/comment/4819#comment-4819    *
 ; Dividend will hold the integer result
    ldi    counter,49                      ;1   init loop counter
    sec                                    ;1   set carry
    rol    dividend1                       ;1   shift left dividend
    rol    dividend2                       ;1
    rol    dividend3                       ;1
    rol    dividend4                       ;1
    rol    dividend5
    rol    dividend6
    dec    counter                         ;1
    brne   divideU32byU32rc                ;1/2
    ret                                    ;4

    rol    remainder1                      ;1
    rol    remainder2                      ;1
    rol    remainder3                      ;1
    rol    remainder4                      ;1
    rol    remainder5
    rol    remainder6
    sub    remainder1,divisor1             ;1   rem -= divisor
    sbc    remainder2,divisor2             ;1
    sbc    remainder3,divisor3             ;1
    sbc    remainder4,divisor4             ;1
    sbc    remainder5,divisor5
    sbc    remainder6,divisor6
    brcc   divideU32byU32ra                ;1/2 if res < 0
    add    remainder1,divisor1             ;1   restore remainder
    adc    remainder2,divisor2             ;1
    adc    remainder3,divisor3             ;1
    adc    remainder4,divisor4             ;1
    adc    remainder5,divisor5
    adc    remainder6,divisor6
    clc                                    ;1   clear carry
    rjmp   divideU32byU32rb                ;2

;         Start of 32 x 32 bit multiplication        *
; https://sites.google.com/site/avrasmintro/home/2b-basic-math
    SUB   ANS8,ANS8    ;Clear ANS8 and Carry Flag
    MOV   ANS1,B1      ;Copy Multiplier to Answer
    MOV   ANS2,B2      ;
    MOV   ANS3,B3      ;
    MOV   ANS4,B4      ;
    LDI   C,33         ;Set Loop Counter to 33
    ROR   ANS4         ;Shift Multiplier to right
    ROR   ANS3         ;
    ROR   ANS2         ;
    ROR   ANS1         ;
    DEC   C            ;Decrement Loop Counter
    BREQ    DONE         ;Check if all bits processed
    BRCC    SKIP         ;If Carry Clear skip addition
    ADD   ANS5,A1      ;Add Multipicand into Answer
    ADC   ANS6,A2      ;
    ADC   ANS7,A3      ;
    ADC   ANS8,A4      ;
    ROR   ANS8         ;Shift high bytes of Answer
    ROR   ANS7         ;
    ROR   ANS6         ;
    ROR   ANS5         ;
;************************ END of 32 x 32 bit Multiplication ************************

Monday, October 8, 2018

Homebrew 5 Watts 40m CW Transceiver Using TIA Amplifiers. Si5351 Based Superhetrodyne Receiver

All design ideas from the EMRFD book. Thanks to W7ZOI, KK7B, W7PUA. And i'm blessed to get this book in India at a second hand book seller. I told him to reserve any radio related books, one fine eve he called me about this book. I also bought ARRL 2011 book. If i'm not using the design concept from this book, then its a shame on having the book. So, here is my QRP Project..

1st design requirement is, front facing 4" speaker. No compromise.

I wanted this to be a self powered, no need to search for DC adapter. The transformer salvaged from old HI-FI cassette player. 15V 2A. I used 12V regulated power supply for TIA chain. Rest using unregulated 17V. 

Close up view

From right >> RX/TX antenna relay >> 40m BPf >> 1st TIA amp >> VFO diode ring mixer >>10MHz ladder filter >> 2nd TIA amp >> 10MHz BFO >> 2nd diode ring mixer >> 2N2222 preamp >> audio power amp >
ULN2003 for all relay switching

Transmitter stage. >> 2N2222 >> BD139 >> 2SC1971 >> 5th order LPF . 2SC1971 gives spurr free 5 watts clean output with 17V 2A. I connect SI5351 clock output directly to 2N2222. All are TV balun cores. Cause thats what i have.

Side tone oscillator , Power supply and audio amplifier close up view

This is my own SI5351 clock generator board using ATMega8. ( I Hate arduino. ). I'm using C language in this project, but assembly version is in progress. You can find details about this PCB on this blog, look for SI5351 DDS board..

The speaker is from old National Panasonic cassette player. Excellent audio quality.

Etched TIA Amp board, i made about ten PCBs for future uses. Around 1" x 1" approx

Initial layout. Modular PCB system makes very easy to assemble and troubleshoot.

Sunday, July 1, 2018

Si5351 DDS Clock Generator Using ATtiny13 Microcontroller with assembly language


This is my project to demonstrate the simplicity of assembly language program. Usually we need lot of program size when we use Arduino compilers and its library. I'm much worried about the program size and coding efficiency. So i wanted to try my skill to make assembly language code to interface Si5351 DDS. After the introduction of mobile phones we lost our memory capacity to store the phone numbers in our brain. Similarly Arduino is spoiling our programming skills. It of-course opened up the creativity on hardware side, but on the software side most of the peoples copy-paste. The first place to look for Arduino code is google. Most of us just copy somebody's library and use it. Arduino made everybody to hesitate to study the datasheet and follow the instruction. I'm not an anti-arduino man, but i want to blow the whistle.

The challenge in this project is 1kB or less program size to interface Si5351 chip. I took the challenge myself. In arduino 1kB is just enough to blink LED with some sequence. Thats the beauty of Arduino ..LOL

 Project Specification:

  • Use the Si5351 as variable frequency oscillator to cover CW range
    • Ex : 7000 to 7050 KHz
    •        10100 to 10150 KHz
    •        14000 to 14050 KHz 
    •          3500 to 3550 KHz etc...
  • To change the frequency using potentiometer
  • CLK2 as beat frequency oscillator for required frequency
  • Control the VFO or ON/OFF the CLK0 output with morse key
  • 1 digital output for TX/RX relay
  • Operating voltage is 3.3V for ATTiny13 and Si5351

Circuit Diagram  

Source Code :

80m - 3500 to 3550 KHz
40m - 7000 to 7050 KHz
30m - 10100 to 10150 KHz
20m - 14000 to 14050 KHz 

Youtube Video


Wednesday, November 1, 2017

Valve Audio Amplifier

Magnetic Loop Antenna For Transmitting

After the success of my receiving magnetic loop, i wanted to give a try on transmitting loop. It has both good and bad results.

One fine evening my friend OM Prem VU2RPC and myself started fabricating the magnetic loop to transmit on 40meter.

Used 3/4" copper tube used for air conditioner with a length of 9 feet.
Wide spaced variable capacitor 30-300pF salvaged from old valve transmitter
2.5SQm wire for inner loop.
Construction is as simple as possible. Just used 3/4" PVC pipes.
Just maintained the outer loop dia as 3feet, and inner loop 0.5feet.

We had about 10 contacts within 15 mins, it was sunday. The tough part is to keep the SWR.
The loop is very narrow bandwidth, even 10KHz change is frequency will affect the SWR to 3:1. Really bad, so maintain power level not more than 50 watts.
The RF from the antenna was also very severe, we can feel the radiation.

Result :
The overall result is,
It is definitely compromised antenna for receiving. There is no doubt, we had no noise pick up, and very good gain also.

For transmitting it not a good antenna. Unless we want to use just for only one frequency, like beacon. Because the bandwidth is too narrow. We have to adjust the variable capacitor for every change on frequency.

Magnetic Loop for Shortwave Receiving

DRM AIR +6100 KHz Shortwave receiving Magnetic loop antenna for 80m to 20m band

This is my trial during year 2015 to receive All India Radio DRM signal from Delhi, India. I'm located south India which is 3600Km far. The actual DRM on 6100KHz is transmit to cover 80Km surrounding Delhi. I made a simple Magnetic loop to get signal from that far. It was a huge seccess. Since i'm using magnetic loop the noise level was very low, and i can null alomost to zero. Below you can find the pictures of my AIR DRM 6100KHz.

I used old Oats container filled with sand on it as a post support. 3/4" PVC pipe, inside is a house electric wiring wire (3-20swg wire). Its about 3feet diameter. The outer loop is connected with a 365pF broadcast set variable capacitor. Inner loop is 1/2 feet dia. I used the same wire.

The radio Redsun (Kaito) RP-2100 comes with a IF out. I made a small converter to convert the RF to AF. Its inside the small black color box.

Saturday, January 7, 2017

VU3XVR Software Defined Radio SDR Using Si5351 DDS VFO and ATMega8 Microcontroller

This is a demonstration on Software Defined Radio Using Si5351 DDS VFO. Original designer is Burkard Kainka, Author of Elektor  SDR-2007. I Just modified VFO by using my own Si5351 based VFO, For more details please chek my blog vu3xvr dot blogspot dot in

Specification :

Frequency Range : 3 to 30 MHz
Mode  : AM - SSB - CW - DRM
Hardware Used :  https://www.elektormagazine.de/magazine/elektor-201607/29066
Software Used : SDRadio by I2PHD available from this website http://digilander.libero.it/i2phd/sdradio/