sw_uart_rx.h、sw_uart_rx.c

/*************************************************/
/* sw_uart_rx.h : Software UART (Rx only)        */
/*                for ATtiny10                   */
/*                using PCINT0 and ADC interrupt */
/*                                               */
/* 2012/01/12 : Created by pcm1723               */
/*************************************************/
#ifndef _SW_UART_RX_H_
#define _SW_UART_RX_H_

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "m2c_tn10.h"

// number of Rx data bits
#define UART_DATABITS (8)
// Rx transfer Complete flag bit
#define sw_RXC (7)

// Synth GATE ON
#define GATE_ON  (PORTB |=   _BV(GATE_BIT) )
// Synth GATE OFF
#define GATE_OFF (PORTB &= ~(_BV(GATE_BIT)))
// stop ADC free running mode
#define tn10_sw_uart_stop_adc()    (ADCSRA &= ~(_BV(ADEN)))
// start ADC free running mode
#define tn10_sw_uart_start_adc()   (ADCSRA |=  (_BV(ADSC) | _BV(ADEN)))
// disable Pin Change Interrupt
#define tn10_sw_uart_disable_pci() (PCICR  &= ~(_BV(PCIE0)))
// enable Pin Change Interrupt (and clear pending interrupt)
#define tn10_sw_uart_enable_pci() \
  do { \
    PCIFR |= _BV(PCIF0); \
    PCICR |= _BV(PCIE0); \
  } while (0)

// software UART setup
extern void tn10_sw_uart_setup( void );

extern volatile uint8_t uart_flag;   // Rx Data ready flag
extern volatile uint8_t uart_rx_buf; // Rx Data buffer

#endif // #ifndef
/*************************************************/
/* sw_uart_rx.c : Software UART (Rx only)        */
/*                for ATtiny10                   */
/*                using PCINT0 and ADC interrupt */
/*                                               */
/* 2012/01/12 : Created by pcm1723               */
/*************************************************/

#include <inttypes.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "sw_uart_rx.h"

volatile        uint8_t uart_flag;   // Rx Data ready flag
volatile        uint8_t uart_rx_buf; // Rx Data register
volatile static uint8_t uart_stat;   // (private) state counter
volatile static uint8_t uart_rx_sr;  // (private) Rx shift register

//
// ADC conversion complete interrupt
//
ISR(ADC_vect)
{
#if defined(UART_DEBUG)
    GATE_ON;
#endif 
  if (0x01 & (++uart_stat)) { // data sampling timing?
// read data bit and shift in
    uart_rx_sr >>= 1; 
    if (_BV(RXD_BIT) & PINB) { // test RxD value
      uart_rx_sr |= (1 << (UART_DATABITS-1)); // RxD = 'H'
    } // if (_BV(RXD_BIT) & PINB) { ...
    if ((2*(UART_DATABITS-1)) <= uart_stat) { // MSB found
      tn10_sw_uart_stop_adc(); // stop Baud clock
      uart_rx_buf = uart_rx_sr; // copy to buffer
      uart_flag |= _BV(sw_RXC);// Rx receive complete flag
      uart_rx_sr = 0;
      uart_stat = 0; // start bit hunt mode
      tn10_sw_uart_enable_pci(); // hunt start bit
    } // if ((2*(UART_DATABITS-1)) < uart_stat) ...
  } // if (0 == (0x01 & ...
#if defined(UART_DEBUG)
  GATE_OFF;
#endif
} // ISR(ADC_vect)

//
// Pin Change Interrupt Service Routine
//
ISR(PCINT0_vect)
{
#if defined(UART_DEBUG)
  GATE_ON;
#endif
    if (0 == (_BV(RXD_BIT) & PINB)) { // RxD == 'L' ?
// start bit edge ('H' --> 'L') found, wait before next check
      __asm__ __volatile__ // delay loop
        ( "\n\t"
          "ldi r24,15\n"
          "dly_L1:\n\t"
          "dec r24\n\t"
          "brne dly_L1\n\t"
          : : );
// check RxD level again (still 'L' ?)
      if (0 == (_BV(RXD_BIT) & PINB)) { // RxD == 'L' confirmed
        tn10_sw_uart_disable_pci(); // disable Pin Change Interrupt
        tn10_sw_uart_start_adc(); // start Baud rate interrupt
      } // if (0 == ...
// if (RxD != 'L'), NOISE detected, hunt start bit edge again
    } // if (0 == ...
#if defined(UART_DEBUG)
  GATE_OFF;
#endif
} // ISR(PCINT0_vect)

//
// software UART (Rx only) setup
//
void tn10_sw_uart_setup( void )
{
// ADC setup for Baudrate interrupt generation
  ADMUX  = 3; // ADC dummy input from PB3 (pin 6)
  ADCSRB = 0; // ADC free running mode             
//
// for (legacy) MIDI (31.25 kbps)
// ADC clock = 812.5 kHz @ 6.5  MHz CPU clock
// ADC interrupt rate = 812.5 kHz / 13 = 62.5 kHz @ 6.5 MHz CPU clock
//
// for serial MIDI (38.4 kbps)
// ADC clock = 997.4 kHz @ 7.9872 MHz CPU clock
// ADC interrupt rate = 997.2 kHz / 13 = 76.8 kHz @ 7.9872 MHz CPU clock
  ADCSRA = (  _BV(ADATE) // ADc Auto Trigger Enable
            | _BV(ADIE)  // ADc Interrupt Enable
            | 3);        // prescaler = 1/8
//
// Pin Change interrupt setup for soft UART Rx
//
  DDRB  &= ~(_BV(RXD_BIT));  // set RxD bit to INPUT
  PUEB  |= _BV(RXD_BIT);     // enable pullup
  PCMSK  = _BV(RXD_BIT);     // enable Rx bit Pin Change Interrupt
  tn10_sw_uart_stop_adc();   // stop ADC free running mode
  tn10_sw_uart_enable_pci(); // enable Pin Change Interrupt
  uart_stat  = 0;            // set start bit hunt mode
  uart_flag &= ~(_BV(sw_RXC)); // clear Rx ready flag
} // void tn10_sw_uart_setup()