ATtiny10 用プログラム (4)

ATtiny10 用のサイン波発生プログラムを作りました。
(12/27 追記: 「sin_tn10.c」で USE_ADC 未定義の場合にコンパイル・エラーになる問題と、「stab128.S」の 2 の補数計算のバグを修正したプログラムに差し替えました)
フェーズ・アキュムレータとサイン波テーブルを使っており、任意の周波数を発生できます。
Timer1 の 8 ビット phase correct PWM を DAC として利用しており、数 kHz のカットオフ周波数の LPF を接続してアナログ波形を得ます。
内部クロック、外部クロックどちらにも対応しており、サンプリング周波数は 8 MHz 内部/外部クロックで 16.525 kHz、12 MHz 外部クロックで 23.4375 kHz です。
最大で 2 波を独立に発生可能で、PB0 (ピン 1) 側の周波数は固定あるいは PB2 (ピン 4) に加える外部電圧で可変の、どちらかを選択可能で、PB1 (ピン 3) 側の周波数は固定です。 (外部クロックではPB0 (ピン 1) 側のみ有効)
Arduino とつないだまま使用する場合の回路図を下に示します。

PB2 (ピン 4) は周波数可変のための AD 入力専用とし、外部から電圧を与えるだけで、負荷となるものは付けないようにします。
PB0 (ピン 1)、PB1 (ピン 3) は書き込みに使われるので、「重い」負荷を付けると書き込みに失敗するようになります。 図のアクティブ・フィルタによる LPF のように、数十 kΩ 以上のインピーダンスにします。

外部クロックを設ける場合には、図のように、抵抗を介して Arduino 側に接続します。
本来のアプリケーション回路ではクロック・ジェネレータ出力と ATtiny10 の 3 番ピンは直結すべきですが、Arduino と接続したままプログラム書き込み/実行を行うために、このようにしています。
書き込みのために Arduino がディジタル 13 番ピンを低インピーダンスでドライブすると、クロック・ジェネレータ出力は抵抗を介して接続されているので、クロック・ジェネレータ側は「負け」、Arduino の出力側が「勝ち」、ATtiny10 の 3 番ピン側には書き込み信号だけが伝わります。
プログラムのソースを下に示します。
AVR Studio 4.19 で新規の C プロジェクトを立ち上げ、プロジェクト名を「sin_tn10」とし、自動生成された中身が空白の「sin_tn10.c」に下の内容をコピー・アンド・ペーストします。
「sin_tn10.c」

/*************************************************/
/* sin_tn10.c : sine wave generator for ATtiny10 */
/*              using phase accumulator          */
/*              and sine wave table              */
/*                                               */
/* 2011/12/27 : bug fixed                        */
/* 2011/12/24 : Created by pcm1723               */
/*************************************************/
  
#include <avr/io.h>
#include <avr/interrupt.h>

//
// mode selection defines
//
#define USE_SIGMADM // 1st order Sigma-DM PWM
#define USE_ADC // PB2 (pin 4) = freq control AD input
//
// PB1 (pin 3) function select
//
//#define USE_EXTCLK // PB1 = ext clock in
//#define USE_BUSY   // PB1 = busy indicator out
#define USE_OC0B    // PB1 = echo of ADCL / freq2 out
#define USE_FOUT2   // PB1 = fixed freq sine out2

// external clock input is top priority
#if defined(USE_EXTCLK)
  #undef USE_BUSY
  #undef USE_OC0B
  #undef USE_FOUT2
#endif

// busy output is second priority
#if defined(USE_BUSY)
  #undef USE_OC0B
  #undef USE_FOUT2
#endif

// f-number table has 72 entries per octave
#define STEPS_PER_OCTAVE (72)

// phase increment for 440 Hz @ fs = 15.625 kHz
//
// PHASE_INC = 440.0 * (2 ** 24) / fs
//           = 440.0 * (2 ** 24) * 512 / F_CPU
//           = 440.0 * (2 ** 24) / 15.625e3
//           = 440.0 * 1073.742
//           = 472446.4
//
#define CALC_PHASE_INC(f) ((uint32_t)(0.5+((f)*0x1000000UL*512.0/F_CPU)))

#if defined(F_CPU)
  #define PHASE_INC  CALC_PHASE_INC(440.0)
  #define PHASE_INC2 CALC_PHASE_INC(440.0)
#endif // #if defined(F_CPU)

#if !defined(PHASE_INC)
#define PHASE_INC  (472446UL) // for F_CPU = 8 MHz
#define PHASE_INC2 (472446UL) // for F_CPU = 8 MHz
#endif

// pitch index offset
#define PITCH_OFS  (27)

//
// OSCCAL byte adjustment value
//
#define OSCCAL_ADJ (0)

typedef union tag_u16_u8_union_t {
  uint16_t u16;
  uint8_t  u8[2];
} u16_u8_union_t;

extern int16_t  get_sin(uint16_t ind);  // sine wave gerarator
extern uint16_t get_fnum(uint16_t ind); // get f-number for the index

uint32_t ph_acc; // phase accumulator
uint8_t  da8_val; // 8 bit DA value

#if defined(USE_ADC)
uint32_t ph_inc; // phase increment
uint16_t idx; // pitch index
uint8_t  oct; // octave code
uint16_t ad_ave;  // averaged AD value
#endif

#if defined(USE_SIGMADM)
u16_u8_union_t sdm_work; // for 1st order Sigma-DM
#endif

#if defined(USE_FOUT2)
uint32_t ph_acc2;
uint8_t  da8_val2;
#endif

void attiny10_port_setup( void )
{
#if defined(USE_EXTCLK)
  CCP    = 0xD8; // set protection signature
// CLocK Main Settings Register CLKMS1:CLKMS0 = 10
  CLKMSR = _BV(CLKMS1); // select external clock
#endif
// set clock prescaler to 1/1 (8 MHz clock)
  CCP    = 0xD8; // set protection signature
  CLKPSR = 0;    // clock prescale = 1/1 (8 MHz clock)
// add OSCCAL offset
  CCP    = 0xD8; // set protection signature
  OSCCAL += OSCCAL_ADJ; // add OSCCAL offset
// setup PWM
// timer mode = 8 bit ph_acc correct PWM (WGM0[3:0] = 0001)
  TCCR0A  = _BV(WGM00); // WGM01:WGM00 = 01
  TCCR0B  = _BV(CS00);  // WGM03:WGM02 = 00, CS00 = 1 (clk/1)
// set compare output mode to clear at up, set at down
  TCCR0A |= _BV(COM0A1); // COM0A1:COM0A0 = 10 
#if defined(USE_OC0B)
  TCCR0A |= _BV(COM0B1); // COM0B1:COM0B0 = 10 
  DDRB   |= _BV(DDB1);  // set OC0B (pin 3) to output
  OCR0BL  = 0x80;
#endif
  DDRB   |= _BV(DDB0);  // set OC0A (pin 1) to output
#if defined(USE_BUSY)   // BUSY (IDLE) indicator
  DDRB   |= _BV(DDB1);  // set PB1 to output
#endif
  OCR0AL  = 0x80;
#if defined(USE_ADC)
  DIDR0  = _BV(ADC2D);     // Digital Input Disable for PB2
  DDRB  &= ~(_BV(DDB2));   // set PB2 (pin 4) to input
  PORTB &= ~(_BV(PORTB2)); // disable PB2 pullup
  ADMUX  = 2; // ADC input from PB2 (pin 4)
  ADCSRB = _BV(ADTS2); // ADC Auto Trigger Source = Timer0 OVF             
// ADC clock = 125.0 kHz @ 8  MHz CPU clock
//             187.5 kHz @ 12 MHz CPU clock
// ADC conversion rate = 1/2 fs = 7.8125 kHz @ 8 MHz CPU clock
  ADCSRA = (  _BV(ADEN)  // ADc ENable
            | _BV(ADATE) // ADc Auto Trigger Enable
            | 6  );       // prescaler = 1/32
#endif // #if defined(USE_ADC)
} // void attiny10_port_setup()

int main() 
{
  attiny10_port_setup(); 
  for (;;) { // infinite loop
    if (_BV(TOV0) & TIFR0) {// Timer0 OVerflow occurred?
      TIFR0 |= _BV(TOV0); // clear Timer OVerflow flag
      OCR0AL = da8_val; // output to PWM DAC
#if defined(USE_FOUT2)
      OCR0BL = da8_val2; // output to PWM DAC
#endif // #if defined(USE_FOUT2)
#if defined(USE_BUSY)
      PORTB |= _BV(PORTB1); // indicate BUSY
#endif // #if defined(USE_BUSY)
#if defined(USE_ADC) // variable frequency
      if (_BV(ADIF) & ADCSRA) { // ADC data ready
        ADCSRA |= _BV(ADIF); // clear ADc Interrupt Flag
// averaging AD value using IIR leaky integrator
// X(z) = (1/256) / (1 - (255/256) * z**(-1))
// Time constant = 256/f_adconv = 32.8 ms
// DC gain = 1
        ad_ave -= (ad_ave >> 8); // decay
        ad_ave += ADCL;      // add new AD value
  #if (!defined(USE_BUSY) & defined(USE_OC0B) & !defined(USE_FOUT2))
        OCR0BL = ADCL; // echo ADC data (8 bit) to OC0B
  #endif // #if !defined(USE_BUSY)
// form averaged ADC data to (1/3) seminote step index
        idx = (uint8_t)(ad_ave >> 8); // 0..255
        idx = (idx << 1) + PITCH_OFS;
        oct  = 0; // assume octave 0 at first
// calc octave (oct = idx / STEPS_PER_OCTAVE)
//      index  (idx = idx % STEPS_PER_OCTAVE)   
        while (STEPS_PER_OCTAVE <= idx) { // division loop
          idx -= STEPS_PER_OCTAVE; // subtract index
          oct++; // next octave
        } // while ()
// get f-number from index and apply octave shift
        ph_inc  = ((uint32_t)get_fnum(idx) << oct);
      } // if (_BV(ADIF) ...
      ph_acc += ph_inc; // update phase accumulator
#else // fixed frequency
      ph_acc += PHASE_INC; // update phase accumulator
#endif // #if defined(USE_ADC) 
#if defined(USE_FOUT2)
      ph_acc2 += PHASE_INC2; // update phase accumulator2
#endif // #if defined(USE_FOUT2)
#if defined(USE_SIGMADM) // 1st order Sigma-DM calculation
      sdm_work.u16 = sdm_work.u8[0] + get_sin(ph_acc >> 8);
      da8_val      = 0x80 ^ sdm_work.u8[1];
#else // ordinal PWM
      da8_val = 0x80 ^ ((uint16_t) get_sin(ph_acc >> 8) >> 8);
#endif // #if defined(USE_SIGMADM)1
#if defined(USE_FOUT2)
      da8_val2 = 0x80 ^ ((uint16_t) get_sin(ph_acc2 >> 8) >> 8);
#endif // #if defined(USE_FOUT2)
#if defined(USE_BUSY)
      PORTB &= ~(_BV(PORTB1)); // indicate IDLE
#endif // #if defined(USE_BUSY)
    } // if (_BV(TOV0) & TIFR0) { ...
  } // for (;;)
} // int main()

プロジェクト・フォルダに下のふたつの (gas で使用する) アセンブラ・ソースファイル (拡張子が「.S」 英大文字の「エス」) を作成し、プロジェクトに追加します。
「stab128.S」

; 512 point sine table
; only first 128 points (0..pi) for symmetry
; (even symmetry table)

#include <avr/io.h>

    .global stab128

stab128:
;                   ; index/total_points
	.dc.w	0x00c7	;   0.5/512
	.dc.w	0x0256	;   1.5/512
	.dc.w	0x03e5	;   2.5/512
	.dc.w	0x0574	;   3.5/512
	.dc.w	0x0702	;   4.5/512
	.dc.w	0x0891	;   5.5/512
	.dc.w	0x0a1f	;   6.5/512
	.dc.w	0x0bac	;   7.5/512
	.dc.w	0x0d39	;   8.5/512
	.dc.w	0x0ec6	;   9.5/512
	.dc.w	0x1052	;  10.5/512
	.dc.w	0x11dd	;  11.5/512
	.dc.w	0x1368	;  12.5/512
	.dc.w	0x14f1	;  13.5/512
	.dc.w	0x167b	;  14.5/512
	.dc.w	0x1803	;  15.5/512
	.dc.w	0x198a	;  16.5/512
	.dc.w	0x1b10	;  17.5/512
	.dc.w	0x1c96	;  18.5/512
	.dc.w	0x1e1a	;  19.5/512
	.dc.w	0x1f9d	;  20.5/512
	.dc.w	0x211f	;  21.5/512
	.dc.w	0x229f	;  22.5/512
	.dc.w	0x241e	;  23.5/512
	.dc.w	0x259c	;  24.5/512
	.dc.w	0x2718	;  25.5/512
	.dc.w	0x2893	;  26.5/512
	.dc.w	0x2a0d	;  27.5/512
	.dc.w	0x2b84	;  28.5/512
	.dc.w	0x2cfa	;  29.5/512
	.dc.w	0x2e6e	;  30.5/512
	.dc.w	0x2fe1	;  31.5/512
	.dc.w	0x3151	;  32.5/512
	.dc.w	0x32c0	;  33.5/512
	.dc.w	0x342d	;  34.5/512
	.dc.w	0x3598	;  35.5/512
	.dc.w	0x3700	;  36.5/512
	.dc.w	0x3867	;  37.5/512
	.dc.w	0x39cb	;  38.5/512
	.dc.w	0x3b2d	;  39.5/512
	.dc.w	0x3c8d	;  40.5/512
	.dc.w	0x3deb	;  41.5/512
	.dc.w	0x3f46	;  42.5/512
	.dc.w	0x409f	;  43.5/512
	.dc.w	0x41f5	;  44.5/512
	.dc.w	0x4348	;  45.5/512
	.dc.w	0x449a	;  46.5/512
	.dc.w	0x45e8	;  47.5/512
	.dc.w	0x4734	;  48.5/512
	.dc.w	0x487d	;  49.5/512
	.dc.w	0x49c3	;  50.5/512
	.dc.w	0x4b06	;  51.5/512
	.dc.w	0x4c47	;  52.5/512
	.dc.w	0x4d84	;  53.5/512
	.dc.w	0x4ebf	;  54.5/512
	.dc.w	0x4ff6	;  55.5/512
	.dc.w	0x512b	;  56.5/512
	.dc.w	0x525c	;  57.5/512
	.dc.w	0x538a	;  58.5/512
	.dc.w	0x54b5	;  59.5/512
	.dc.w	0x55dc	;  60.5/512
	.dc.w	0x5701	;  61.5/512
	.dc.w	0x5822	;  62.5/512
	.dc.w	0x593f	;  63.5/512
	.dc.w	0x5a59	;  64.5/512
	.dc.w	0x5b70	;  65.5/512
	.dc.w	0x5c83	;  66.5/512
	.dc.w	0x5d93	;  67.5/512
	.dc.w	0x5e9f	;  68.5/512
	.dc.w	0x5fa7	;  69.5/512
	.dc.w	0x60ab	;  70.5/512
	.dc.w	0x61ac	;  71.5/512
	.dc.w	0x62a9	;  72.5/512
	.dc.w	0x63a3	;  73.5/512
	.dc.w	0x6498	;  74.5/512
	.dc.w	0x658a	;  75.5/512
	.dc.w	0x6677	;  76.5/512
	.dc.w	0x6761	;  77.5/512
	.dc.w	0x6847	;  78.5/512
	.dc.w	0x6929	;  79.5/512
	.dc.w	0x6a06	;  80.5/512
	.dc.w	0x6ae0	;  81.5/512
	.dc.w	0x6bb5	;  82.5/512
	.dc.w	0x6c87	;  83.5/512
	.dc.w	0x6d54	;  84.5/512
	.dc.w	0x6e1d	;  85.5/512
	.dc.w	0x6ee1	;  86.5/512
	.dc.w	0x6fa2	;  87.5/512
	.dc.w	0x705e	;  88.5/512
	.dc.w	0x7115	;  89.5/512
	.dc.w	0x71c9	;  90.5/512
	.dc.w	0x7278	;  91.5/512
	.dc.w	0x7322	;  92.5/512
	.dc.w	0x73c8	;  93.5/512
	.dc.w	0x746a	;  94.5/512
	.dc.w	0x7507	;  95.5/512
	.dc.w	0x75a0	;  96.5/512
	.dc.w	0x7634	;  97.5/512
	.dc.w	0x76c4	;  98.5/512
	.dc.w	0x774f	;  99.5/512
	.dc.w	0x77d5	; 100.5/512
	.dc.w	0x7857	; 101.5/512
	.dc.w	0x78d4	; 102.5/512
	.dc.w	0x794d	; 103.5/512
	.dc.w	0x79c0	; 104.5/512
	.dc.w	0x7a30	; 105.5/512
	.dc.w	0x7a9a	; 106.5/512
	.dc.w	0x7b00	; 107.5/512
	.dc.w	0x7b61	; 108.5/512
	.dc.w	0x7bbd	; 109.5/512
	.dc.w	0x7c14	; 110.5/512
	.dc.w	0x7c67	; 111.5/512
	.dc.w	0x7cb5	; 112.5/512
	.dc.w	0x7cfe	; 113.5/512
	.dc.w	0x7d42	; 114.5/512
	.dc.w	0x7d81	; 115.5/512
	.dc.w	0x7dbc	; 116.5/512
	.dc.w	0x7df1	; 117.5/512
	.dc.w	0x7e22	; 118.5/512
	.dc.w	0x7e4e	; 119.5/512
	.dc.w	0x7e75	; 120.5/512
	.dc.w	0x7e98	; 121.5/512
	.dc.w	0x7eb5	; 122.5/512
	.dc.w	0x7ecd	; 123.5/512
	.dc.w	0x7ee1	; 124.5/512
	.dc.w	0x7ef0	; 125.5/512
	.dc.w	0x7ef9	; 126.5/512
	.dc.w	0x7efe	; 127.5/512

;
; uint16_t get_sin(uint16_t ind);
;
; input parameter :
;    uint16_t ind  = R25:R24
;
; function result :  R25:R24
;    
; volatile register : R16, Z (R31:R30)
;
; R17 == 0 assumed (AVR C convention)
;

        .global get_sin
        .func   get_sin

FL_START =      0x4000 ; mapped address of FLASH memory

get_sin:
; Z (R31:R30) <- stab128 mapped address
        ldi     ZL,lo8(stab128+FL_START)  
        ldi     ZH,hi8(stab128+FL_START) 
        lsl     r24     ; 
        rol     r25     ; C <-- R25:R24 <-- 0
        ror     r16     ; MSB of R16 <-- C (MSB of R25)
        sbrc    r25,7   ; skip if b7 of R25 cleared (2SB of R25 on entry)
        com     r25     ; 1's complement (bitwise NOT)
        add     ZL,r25
        adc     ZH,r17  ; add offset
        add     ZL,r25
        adc     ZH,r17  ; add offset for 2byte data
        ld      r24,Z+
        ld      r25,Z   ; get sine value in R25:R24
        sbrs    r16,7   ; skip if b7 of R16 set (MSB of R25 on ertry)
        ret             ; positive number
;
        com     r25
        neg     r24
        sbci    r25,0xff ; 2's complement of R25:R24
        ret             ; negative number
        .endfunc

「fnum6.S」

; 16-bit precision f-number table 
; 6 steps per semitone          
; 100/6 = 16.66667 cent step     

#include <avr/io.h>

        .global fnum6
        .global get_fnum

FL_START    =   0x4000  ; mapped address of FLASH memory

fnum6:
;/***  C   ***/
        .dc.w   0x8000	;    0.0 cent
        .dc.w   0x813d	;   16.7 cent
        .dc.w   0x827d	;   33.3 cent
        .dc.w   0x83c0	;   50.0 cent
        .dc.w   0x8506	;   66.7 cent
        .dc.w   0x8650	;   83.3 cent
;/***  C#  ***/
        .dc.w   0x879c	;  100.0 cent
        .dc.w   0x88ec	;  116.7 cent
        .dc.w   0x8a3f	;  133.3 cent
        .dc.w   0x8b96	;  150.0 cent
        .dc.w   0x8cef	;  166.7 cent
        .dc.w   0x8e4c	;  183.3 cent
;/***  D   ***/
        .dc.w   0x8fad	;  200.0 cent
        .dc.w   0x9111	;  216.7 cent
        .dc.w   0x9278	;  233.3 cent
        .dc.w   0x93e3	;  250.0 cent
        .dc.w   0x9551	;  266.7 cent
        .dc.w   0x96c3	;  283.3 cent
;/***  D#  ***/
        .dc.w   0x9838	;  300.0 cent
        .dc.w   0x99b1	;  316.7 cent
        .dc.w   0x9b2e	;  333.3 cent
        .dc.w   0x9cae	;  350.0 cent
        .dc.w   0x9e32	;  366.7 cent
        .dc.w   0x9fba	;  383.3 cent
;/***  E   ***/
        .dc.w   0xa145	;  400.0 cent
        .dc.w   0xa2d4	;  416.7 cent
        .dc.w   0xa468	;  433.3 cent
        .dc.w   0xa5ff	;  450.0 cent
        .dc.w   0xa79a	;  466.7 cent
        .dc.w   0xa939	;  483.3 cent
;/***  F   ***/
        .dc.w   0xaadc	;  500.0 cent
        .dc.w   0xac83	;  516.7 cent
        .dc.w   0xae2e	;  533.3 cent
        .dc.w   0xafde	;  550.0 cent
        .dc.w   0xb191	;  566.7 cent
        .dc.w   0xb349	;  583.3 cent
;/***  F#  ***/
        .dc.w   0xb505	;  600.0 cent
        .dc.w   0xb6c5	;  616.7 cent
        .dc.w   0xb88a	;  633.3 cent
        .dc.w   0xba53	;  650.0 cent
        .dc.w   0xbc20	;  666.7 cent
        .dc.w   0xbdf2	;  683.3 cent
;/***  G   ***/
        .dc.w   0xbfc9	;  700.0 cent
        .dc.w   0xc1a3	;  716.7 cent
        .dc.w   0xc383	;  733.3 cent
        .dc.w   0xc567	;  750.0 cent
        .dc.w   0xc750	;  766.7 cent
        .dc.w   0xc93e	;  783.3 cent
;/***  G#  ***/
        .dc.w   0xcb30	;  800.0 cent
        .dc.w   0xcd27	;  816.7 cent
        .dc.w   0xcf23	;  833.3 cent
        .dc.w   0xd124	;  850.0 cent
        .dc.w   0xd32a	;  866.7 cent
        .dc.w   0xd535	;  883.3 cent
;/***  A   ***/
        .dc.w   0xd745	;  900.0 cent
        .dc.w   0xd95a	;  916.7 cent
        .dc.w   0xdb74	;  933.3 cent
        .dc.w   0xdd94	;  950.0 cent
        .dc.w   0xdfb9	;  966.7 cent
        .dc.w   0xe1e3	;  983.3 cent
;/***  A#  ***/
        .dc.w   0xe412	; 1000.0 cent
        .dc.w   0xe647	; 1016.7 cent
        .dc.w   0xe881	; 1033.3 cent
        .dc.w   0xeac1	; 1050.0 cent
        .dc.w   0xed06	; 1066.7 cent
        .dc.w   0xef51	; 1083.3 cent
;/***  B   ***/
        .dc.w   0xf1a2	; 1100.0 cent
        .dc.w   0xf3f8	; 1116.7 cent
        .dc.w   0xf654	; 1133.3 cent
        .dc.w   0xf8b6	; 1150.0 cent
        .dc.w   0xfb1e	; 1166.7 cent
        .dc.w   0xfd8c	; 1183.3 cent
;
; uint16_t get_fnum(uint16_t ind);
;
; input parameter :
;    uint16_t ind  = R25:R24
;
; function result  : R25:R24
;    
; volatile register :  Z (R31:R30)
;
        .func   get_fnum
get_fnum:
; Z (R31:R30) <- fnum6 mapped address
        ldi     ZL,lo8(fnum6+FL_START)  
        ldi     ZH,hi8(fnum6+FL_START) 
        add     ZL,r24
        adc     ZH,r25  ; add offset
        add     ZL,r24
        adc     ZH,r25  ; add offset for 2byte data
        ld      r24,Z+
        ld      r25,Z   ; get f-number value in R25:R24
        ret             ; 
;

これを最適化オプション「-Os」でコンパイルすると、プログラム・サイズ 906 バイト、データ・サイズ 21 バイトになります。
sin_tn10.c のソース中の #define で各種の設定ができますが、上のソースでの設定は、

  • 内部クロック使用 (USE_EXTCLK 未定義)
  • シグマーデルタ変調使用 (USE_SIGMADM 定義)
  • 電圧入力による周波数可変 (USE_ADC 定義)
  • 2 出力モード (USE_FOUT2 定義)

になっています。
PB0 (ピン 1) から出力されるサイン波の周波数は PB2 (ピン 4) への電圧入力を AD 変換した数値でコントロールされています。
AD 変換後の数値 0 〜 255 に対して、88 鍵ピアノの音域程度 (40 Hz 〜 4 kHz 程度) を割り当てており、数値が 1 変化すると周波数は 1/3 半音 (1.944 %) 変化します。
PB2 (ピン 4) から出力される第二のサイン波の周波数はソースファイル上の定数で決まり、実行時に可変はできません。
上のソースファイルでは、440 Hz に設定してあります。 (正確には 8 MHz クロックで 439.99963 Hz)
もちろん、内部クロックの精度は ±10 % 程度なので、正確な周波数が必要ならば、クロックの周波数を測定して、設定する数値を修正する必要があります。
長くなってきたので、#define による設定の詳細は次回にまわします。
最後にコンパイル結果を fix_lds プログラムに通して lds/sts を書き換えて正常に動作するようにした HEX ファイルを下に示します。 これを ATiny10 に書き込めば動作します。
「sin_tn10_fixed.hex」

:100000000AC019C018C017C016C015C014C013C04C
:1000100012C011C010C011271FBFCFE5D0E0DEBF56
:10002000CDBF10E0A0E4B0E001C01D93A535B1073D
:10003000E1F720D0A8C1E4CF88ED8CBF16BF8CBFFC
:1000400089B789BF81E08EBD8DBD8EB580688EBDBC
:100050008EB580628EBD099A80E884BD089A86BDFF
:1000600084E087BB0A98129892E09BBB8CBB86EA1F
:100070008DBB0895CF93DF93DFDF0AB500FFFDCF7F
:100080008AB581608ABD89A1000086BD88A1000073
:1000900084BD8DB384FF3EC0EC9A81A3000092A37F
:1000A0000000292F3327821B930B92AB000081ABFA
:1000B000000029B3820F911F92AB000081AB0000BA
:1000C000892F90E0880F991F855E9F4F20E003C025
:1000D00088549040232F322F3F5F88349107C0F718
:1000E0008EA900009FA9000020AB000043D1A0E032
:1000F000B0E000A3000004C0880F991FAA1FBB1F17
:100100000A95D2F780A9000091A90000A2A90000D9
:10011000B3A9000020A1000031A1000042A100000D
:1001200053A1000084A1000095A10000A6A1000039
:10013000B7A10000280F391F4A1F5B1F24A9000028
:1001400035A9000046A9000057A900008AA10000B7
:100150009BA10000ACA10000BDA1000082589A4CF8
:10016000A84FBF4F8AA900009BA90000ACA90000BE
:10017000BDA9000083A30000C82FD0E0BB27A52F96
:10018000942F832F9CD0C80FD91FD4AB0000C3ABD2
:10019000000084A30000805889A900008AA1000003
:1001A0009BA10000ACA10000BDA10000892F9A2FE7
:1001B000AB2FBB2784D0905898A900005ECFC70012
:1001C0005602E5037405020791081F0AAC0B390DAE
:1001D000C60E5210DD116813F1147B1603188A192C
:1001E000101B961C1A1E9D1F1F219F221E249C253A
:1001F000182793280D2A842BFA2C6E2EE12F5131CB
:10020000C0322D34983500376738CB392D3B8D3CC3
:10021000EB3D463F9F40F54148439A44E84534470B
:100220007D48C349064B474C844DBF4EF64F2B517A
:100230005C528A53B554DC55015722583F59595ADC
:10024000705B835C935D9F5EA75FAB60AC61A962EE
:10025000A36398648A657766616747682969066A57
:10026000E06AB56B876C546D1D6EE16EA26F5E70B7
:100270001571C97178722273C8736A740775A07595
:100280003476C4764F77D5775778D4784D79C0795E
:10029000307A9A7A007B617BBD7B147C677CB57C6D
:1002A000FE7C427D817DBC7DF17D227E4E7E757E11
:1002B000987EB57ECD7EE17EF07EF97EFE7EEEEB11
:1002C000F1E4880F991F079597FD9095E90FF11FAD
:1002D000E90FF11F8191908107FF08959095819515
:1002E0009F4F089500803D817D82C08306855086A2
:1002F0009C87EC883F8A968BEF8C4C8EAD8F11914A
:100300007892E3935195C3963898B1992E9BAE9C01
:10031000329EBA9F45A1D4A268A4FFA59AA739A985
:10032000DCAA83AC2EAEDEAF91B149B305B5C5B63C
:100330008AB853BA20BCF2BDC9BFA3C183C367C585
:1003400050C73EC930CB27CD23CF24D12AD335D5B2
:1003500045D75AD974DB94DDB9DFE3E112E447E60F
:1003600081E8C1EA06ED51EFA2F1F8F354F6B6F8D0
:100370001EFB8CFDE4EEF2E4E80FF91FE80FF91F15
:0A038000819190810895F894FFCF59
:00000001FF