Loading

Paste #poi0ccvqr

  1. /************************************************************************/
  2. /*                                                                      */
  3. /*                      Software UART with FIFO, using T1               */
  4. /*                                                                      */
  5. /*              Author: P. Dannegger                                    */
  6. /*                                                                      */
  7. /************************************************************************/
  8. //              Target: ATtiny44
  9.  
  10. #include <avr/io.h>
  11. #include <avr/interrupt.h>
  12.  
  13.  
  14. #define BAUD        9600
  15. #define STX_SIZE    10
  16. #define SRX_SIZE    10
  17.  
  18. #define STXD        SBIT( PORTA, PA6 )  // = OC1A
  19. #define STXD_DDR    SBIT( DDRA,  PA6 )
  20.  
  21. #define SRXD_PIN    SBIT( PINA,  PA7 )  // = ICP
  22.  
  23. struct bits {
  24.   uint8_t b0:1;
  25.   uint8_t b1:1;
  26.   uint8_t b2:1;
  27.   uint8_t b3:1;
  28.   uint8_t b4:1;
  29.   uint8_t b5:1;
  30.   uint8_t b6:1;
  31.   uint8_t b7:1;
  32. } __attribute__((__packed__));
  33.  
  34. #define SBIT_(port,pin) ((*(volatile struct bits*)&port).b##pin)
  35. #define SBIT(x,y)   SBIT_(x,y)
  36.  
  37.  
  38. //          Optimization improvements
  39.  
  40. #define OPTR18 __asm__ volatile (""::);     // it helps, but why ?
  41.                         // remove useless R18/R19
  42.  
  43. // always inline function x:
  44.  
  45. #define AIL(x)   static x __attribute__ ((always_inline)); static x
  46.  
  47.  
  48. // never inline function x:
  49.  
  50. #define NIL(x)   x __attribute__ ((noinline)); x
  51.  
  52.  
  53. // volatile access (reject unwanted removing access):
  54.  
  55. #define vuint8_t(x)  (*(volatile uint8_t*)&(x))
  56. #define vint8_t(x)  (*(volatile int8_t*)&(x))
  57. #define vuint16_t(x) (*(volatile uint16_t*)&(x))
  58. #define vint16_t(x) (*(volatile int16_t*)&(x))
  59.  
  60. #define uputs(x)    uputs_((uint8_t*)(x))   // avoid char warning
  61.  
  62. #define BIT_TIME    (uint16_t)(F_CPU * 1.0 / BAUD + 0.5)
  63.  
  64. #define TX_HIGH     (1<<COM1A1^1<<COM1A0)
  65. #define TX_LOW      (TX_HIGH^1<<COM1A0)
  66. #define TX_OUT      TCCR1A      // use compare output mode
  67.  
  68. #define ROLLOVER( x, max )  x = ++x >= max ? 0 : x
  69.                     // count up and wrap around
  70.  
  71. static uint8_t stx_buff[STX_SIZE];
  72. static uint8_t stx_in;
  73. static uint8_t stx_out;
  74. static uint8_t stx_data;
  75. static uint8_t stx_state;
  76.  
  77. static uint8_t srx_buff[SRX_SIZE];
  78. static uint8_t srx_in;
  79. static uint8_t srx_out;
  80. static uint8_t srx_data;
  81. static uint8_t srx_state;
  82.  
  83.  
  84. void suart_init( void )
  85. {
  86.   OCR1A = BIT_TIME - 1;
  87.   TCCR1A = TX_HIGH;         // set OC1A high, T1 mode 4
  88.   TCCR1B = 1<<ICNC1^1<<WGM12^1<<CS10;   // noise canceler, 1-0 transition,
  89.                     // CLK/1, T1 mode 4 (CTC)
  90.   TCCR1C = 1<<FOC1A;
  91.   stx_state = 0;
  92.   stx_in = 0;
  93.   stx_out = 0;
  94.   srx_in = 0;
  95.   srx_out = 0;
  96.   STXD_DDR = 1;             // output enable
  97.   TIFR1 = 1<<ICF1;          // clear pending interrupt
  98.   TIMSK1 = 1<<ICIE1^1<<OCIE1A;      // enable tx and wait for start
  99. }
  100.  
  101.  
  102. uint8_t kbhit( void )           // check, if rx buffer not empty
  103. {
  104.   return srx_out ^ vuint8_t(srx_in);
  105. }
  106.  
  107.  
  108. uint8_t ugetchar( void )            // wait until byte received
  109. {
  110.   uint8_t data;
  111.  
  112.   while( !kbhit());             // until at least one byte in
  113.   data = srx_buff[srx_out];     // get byte
  114.   ROLLOVER( srx_out, SRX_SIZE );
  115.   return data;
  116. }
  117.  
  118.  
  119. void uputchar( uint8_t c )          // transmit byte
  120. {
  121.   uint8_t i = stx_in;
  122.  
  123.   ROLLOVER( i, STX_SIZE );
  124.   stx_buff[stx_in] = ~c;        // complement for stop bit after data
  125.   while( i == vuint8_t(stx_out));       // until at least one byte free
  126.                     // stx_out modified by interrupt !
  127.   stx_in = i;
  128. }
  129.  
  130.  
  131. void uputs_( uint8_t *s )           // transmit string from SRAM
  132. {
  133.   while( *s )
  134.     uputchar( *s++ );
  135. }
  136.  
  137. /****************************** Interrupts *******************************/
  138.  
  139. ISR( TIM1_CAPT_vect )               // start detection
  140. {
  141.   int16_t i = ICR1 - BIT_TIME / 2;          // scan at 0.5 bit time
  142.  
  143.   OPTR18                    // avoid disoptimization
  144.   if( i < 0 )
  145.     i += BIT_TIME;              // wrap around
  146.   OCR1B = i;
  147.   srx_state = 10;
  148.   TIFR1 = 1<<OCF1B;             // clear pending interrupt
  149.   if( SRXD_PIN == 0 )               // still low
  150.     TIMSK1 = 1<<OCIE1A^1<<OCIE1B;       // wait for first bit
  151. }
  152.  
  153.  
  154. ISR( TIM1_COMPB_vect )              // receive data bits
  155. {
  156.   uint8_t i;
  157.  
  158.   switch( --srx_state ){
  159.  
  160.     case 9:  if( SRXD_PIN == 0 )        // start bit valid
  161.            return;
  162.          break;
  163.  
  164.     default: i = srx_data >> 1;             // LSB first
  165.          if( SRXD_PIN == 1 )
  166.            i |= 0x80;           // data bit = 1
  167.          srx_data = i;
  168.          return;
  169.  
  170.     case 0:  if( SRXD_PIN == 1 ){       // stop bit valid
  171.            i = srx_in;
  172.            ROLLOVER( i, SRX_SIZE );
  173.            if( i != srx_out ){      // no buffer overflow
  174.          srx_buff[srx_in] = srx_data;
  175.          srx_in = i;            // advance in pointer
  176.            }
  177.          }
  178.          TIFR1 = 1<<ICF1;           // clear pending interrupt
  179.   }
  180.   TIMSK1 = 1<<ICIE1^1<<OCIE1A;          // enable next start
  181. }
  182.  
  183.  
  184. ISR( TIM1_COMPA_vect )              // transmit data bits
  185. {
  186.   if( stx_state ){
  187.     stx_state--;
  188.     TX_OUT = TX_HIGH;
  189.     if( stx_data & 1 )              // lsb first
  190.       TX_OUT = TX_LOW;
  191.     stx_data >>= 1;
  192.     return;
  193.   }
  194.   if( stx_in != stx_out ){          // next byte to sent
  195.     stx_data = stx_buff[stx_out];
  196.     ROLLOVER( stx_out, STX_SIZE );
  197.     stx_state = 9;              // 8 data bits + stop
  198.     TX_OUT = TX_LOW;                // start bit
  199.   }
  200. }
  201.