uart.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. /*---------------------------------------------------------*/
  2. /* UART functions for ATmega164A/PA/324A/PA/644A/PA/1284/P */
  3. /* #include-d by uart0.c and uart1.c */
  4. /*---------------------------------------------------------*/
  5. #if SZ_FIFO >= 256
  6. typedef uint16_t idx_t;
  7. #else
  8. typedef uint8_t idx_t;
  9. #endif
  10. typedef struct {
  11. idx_t start, len;
  12. uint8_t buff[SZ_FIFO];
  13. } FIFO;
  14. #if RECEIVE
  15. static
  16. volatile FIFO RxFifo;
  17. #endif
  18. #if USE_TXINT && TRANSMIT
  19. static
  20. volatile FIFO TxFifo;
  21. #endif
  22. static inline void fifo_add(volatile FIFO *fifo, char element) __attribute__((always_inline));
  23. static inline char fifo_get(volatile FIFO *fifo) __attribute__((always_inline));
  24. static inline void fifo_add(volatile FIFO *fifo, char element) {
  25. unsigned char SREG_buf = SREG;
  26. idx_t len = fifo->len;
  27. cli();
  28. idx_t idx = (fifo->start + len++) % SZ_FIFO;
  29. fifo->buff[idx] = element;
  30. if (len > SZ_FIFO) {
  31. len--;
  32. fifo->start = (fifo->start + 1) % SZ_FIFO;
  33. }
  34. fifo->len = len;
  35. SREG = SREG_buf;
  36. }
  37. static inline char fifo_get(volatile FIFO *fifo) {
  38. char ret = 0;
  39. unsigned char SREG_buf = SREG;
  40. idx_t start;
  41. cli();
  42. if (fifo->len > 0) {
  43. start = fifo->start;
  44. ret = fifo->buff[start];
  45. fifo->start = (start + 1) % SZ_FIFO;
  46. fifo->len--;
  47. }
  48. SREG = SREG_buf;
  49. return ret;
  50. }
  51. /* Initialize UART */
  52. void _uart_init (void)
  53. {
  54. _UCSRB = 0;
  55. _PORT |= _BV(_TX); _DDR |= _BV(_TX); /* Set TXD as output */
  56. _DDR &= ~_BV(_RX); _PORT &= ~_BV(_RX); /* Set RXD as input */
  57. #if RECEIVE
  58. RxFifo.len = 0;
  59. #endif
  60. #if USE_TXINT && TRANSMIT
  61. TxFifo.len = 0;
  62. #endif
  63. _UBRR = F_CPU / UART_BAUD / 16 - 1;
  64. #if RECEIVE && TRANSMIT
  65. _UCSRB = _BV(_RXEN) | _BV(_RXCIE) | _BV(_TXEN);
  66. #elif TRANSMIT
  67. _UCSRB = _BV(_TXEN);
  68. #elif RECEIVE
  69. _UCSRB = _BV(_RXEN) | _BV(_RXCIE);
  70. #endif
  71. }
  72. /* Deinitialize UART */
  73. void _uart_deinit (void)
  74. {
  75. _UCSRB = 0;
  76. }
  77. /* Get a received character */
  78. #if RECEIVE
  79. uint8_t _uart_test (void)
  80. {
  81. return RxFifo.len > 0;
  82. }
  83. uint8_t _uart_get (void)
  84. {
  85. return fifo_get(&RxFifo);
  86. }
  87. #endif
  88. /* Put a character to transmit */
  89. #if TRANSMIT
  90. void _uart_put (uint8_t d)
  91. {
  92. #if USE_TXINT
  93. unsigned char SREG_buf;
  94. idx_t len;
  95. do {
  96. SREG_buf = SREG;
  97. cli();
  98. len = TxFifo.len;
  99. SREG = SREG_buf;
  100. } while (len >= SZ_FIFO);
  101. fifo_add(&TxFifo, d);
  102. _UCSRB |= _BV(_UDRIE);
  103. #else
  104. loop_until_bit_is_set(_UCSRA, _UDRE);
  105. _UDR = d;
  106. #endif
  107. }
  108. #endif
  109. #if RECEIVE
  110. /* USART1 RXC interrupt */
  111. ISR(_USART_RX_vect)
  112. {
  113. uint8_t d;
  114. d = _UDR;
  115. fifo_add(&RxFifo, d);
  116. }
  117. #endif
  118. #if TRANSMIT && USE_TXINT
  119. ISR(_USART_UDRE_vect)
  120. {
  121. if (TxFifo.len)
  122. _UDR = fifo_get(&TxFifo);
  123. /* TxFifo.len is decremented by fifo_get */
  124. if (!TxFifo.len)
  125. _UCSRB &= ~_BV(_UDRIE);
  126. }
  127. #endif