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()