uart.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. /*
  2. * UART interface
  3. *
  4. * Copyright (c) 2020 Michael Buesch <m@bues.ch>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  19. */
  20. #include "compat.h"
  21. #include "uart.h"
  22. #include "arithmetic.h"
  23. #include "debug.h"
  24. #include "pcint.h"
  25. #include "standby.h"
  26. #include "util.h"
  27. #include "watchdog.h"
  28. /* On wire data format:
  29. *
  30. * 7 bit channel transmission:
  31. * Data byte:
  32. * [0 x x x x x x x]
  33. * ^ ^ ^ ^ ^ ^ ^ ^
  34. * | |...........|
  35. * | | data byte 0
  36. * | data byte 7
  37. * constant 0
  38. *
  39. * 8 bit channel transmission:
  40. * First data byte: Second data byte:
  41. * [1 0 y y x x x x] [1 1 y y x x x x]
  42. * ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
  43. * | | | | |.....| | | | | |.....|
  44. * | | | | | data byte 0 | | | | | data byte 4
  45. * | | | | data byte 3 | | | | data byte 7
  46. * | | | channel select A | | | reserved (0)
  47. * | | channel select B | | reserved (0)
  48. * | constant 0 | constant 1
  49. * constant 1 constant 1
  50. *
  51. * constraint:
  52. * Currently only channel select 00 is supported.
  53. */
  54. #define BAUDRATE 19200ul
  55. #define USE_2X (((uint64_t)F_CPU % (8ull * BAUDRATE)) < \
  56. ((uint64_t)F_CPU % (16ull * BAUDRATE)))
  57. #define UBRRVAL ((uint64_t)F_CPU / ((USE_2X ? 8ull : 16ull) * BAUDRATE))
  58. #define UART_RXD_PCINT 16
  59. #define UART_TXD_PCINT 17
  60. #define UART_STANDBY_DELAY_MS 600u
  61. #define FLG_8BIT 0x80u /* 8-bit data nibble */
  62. #define FLG_8BIT_UPPER 0x40u /* 8-bit upper data nibble */
  63. #define FLG_8BIT_CHANB 0x20u /* Channel selection A */
  64. #define FLG_8BIT_CHANA 0x10u /* Channel selection B */
  65. #define MSK_4BIT 0x0Fu /* data nibble */
  66. #define MSK_7BIT 0x7Fu
  67. static struct {
  68. struct {
  69. bool enabled[UART_NR_CHAN];
  70. bool upper;
  71. uint8_t buf;
  72. uart_txready_cb_t ready_callback[UART_NR_CHAN];
  73. } tx;
  74. struct {
  75. bool upper;
  76. uint8_t buf;
  77. uart_rx_cb_t callback[UART_NR_CHAN];
  78. } rx;
  79. uint16_t standby_delay_ms;
  80. } uart;
  81. static void uart_update_standby_suppress(void)
  82. {
  83. if (USE_UART) {
  84. set_standby_suppress(STANDBY_SRC_UART,
  85. uart.standby_delay_ms > 0u);
  86. }
  87. }
  88. bool uart_tx_is_ready(enum uart_chan chan)
  89. {
  90. IF_UART(
  91. return !!(UCSR0A & (1 << UDRE0)) &&
  92. !uart.tx.upper;
  93. )
  94. return false;
  95. }
  96. void uart_tx_byte(uint8_t data, enum uart_chan chan)
  97. {
  98. if (USE_UART) {
  99. if (chan == UART_CHAN_7BIT) {
  100. uart.tx.upper = false;
  101. data = (uint8_t)(data & MSK_7BIT);
  102. memory_barrier();
  103. IF_UART(UDR0 = data);
  104. } else {
  105. uart.tx.upper = true;
  106. uart.tx.buf = data;
  107. data = (uint8_t)(data & MSK_4BIT);
  108. data |= FLG_8BIT;
  109. memory_barrier();
  110. IF_UART(UDR0 = data);
  111. }
  112. }
  113. }
  114. static void check_tx_disable(void)
  115. {
  116. bool all_disabled = true;
  117. uint8_t i;
  118. if (USE_UART) {
  119. for (i = 0u; i < UART_NR_CHAN; i++)
  120. all_disabled &= !uart.tx.enabled[i];
  121. if (!uart.tx.upper && all_disabled) {
  122. IF_UART(UCSR0B &= (uint8_t)~(1 << UDRIE0));
  123. } else {
  124. IF_UART(UCSR0B |= 1 << UDRIE0);
  125. }
  126. }
  127. }
  128. void uart_tx_enable(bool enable, enum uart_chan chan)
  129. {
  130. uint8_t irq_state;
  131. if (USE_UART) {
  132. irq_state = irq_disable_save();
  133. uart.tx.enabled[chan] = enable;
  134. check_tx_disable();
  135. irq_restore(irq_state);
  136. }
  137. }
  138. #if USE_UART
  139. ISR(USART_UDRE_vect)
  140. {
  141. uint8_t data;
  142. uint8_t i;
  143. if (uart.tx.upper) {
  144. uart.tx.upper = false;
  145. data = uart.tx.buf >> 4;
  146. data |= FLG_8BIT;
  147. data |= FLG_8BIT_UPPER;
  148. UDR0 = data;
  149. }
  150. for (i = 0u; i < UART_NR_CHAN; i++) {
  151. if (uart_tx_is_ready(i)) {
  152. if (uart.tx.ready_callback[i])
  153. uart.tx.ready_callback[i]();
  154. } else
  155. break;
  156. }
  157. check_tx_disable();
  158. }
  159. #endif /* USE_UART */
  160. #if USE_UART
  161. ISR(USART_RX_vect)
  162. {
  163. uint8_t status;
  164. uint8_t data;
  165. status = UCSR0A;
  166. data = UDR0;
  167. if ((status & ((1u << FE0) | (1u << DOR0) | (1u << UPE0))) == 0u)
  168. {
  169. if (data & FLG_8BIT) {
  170. if (uart.rx.upper) {
  171. uart.rx.upper = false;
  172. if (data & FLG_8BIT_UPPER) {
  173. data = (uint8_t)(data << 4);
  174. data = (uint8_t)(data | (uart.rx.buf & MSK_4BIT));
  175. if (uart.rx.callback[UART_CHAN_8BIT_0])
  176. uart.rx.callback[UART_CHAN_8BIT_0](data);
  177. }
  178. } else {
  179. if (!(data & FLG_8BIT_UPPER)) {
  180. uart.rx.upper = true;
  181. uart.rx.buf = data;
  182. }
  183. }
  184. } else {
  185. uart.rx.upper = false;
  186. if (uart.rx.callback[UART_CHAN_7BIT])
  187. uart.rx.callback[UART_CHAN_7BIT](data);
  188. }
  189. } else
  190. uart.rx.upper = false;
  191. }
  192. #endif /* USE_UART */
  193. void uart_register_callbacks(uart_txready_cb_t tx_ready,
  194. uart_rx_cb_t rx,
  195. enum uart_chan chan)
  196. {
  197. IF_UART(
  198. uart.tx.ready_callback[chan] = tx_ready;
  199. uart.rx.callback[chan] = rx;
  200. )
  201. }
  202. static void uart_enable(bool enable)
  203. {
  204. if (USE_UART) {
  205. if (enable) {
  206. uart.tx.upper = false;
  207. uart.rx.upper = false;
  208. memory_barrier();
  209. IF_UART(
  210. UBRR0 = UBRRVAL;
  211. UCSR0A = (1 << TXC0) | (!!(USE_2X) << U2X0) | (0 << MPCM0);
  212. UCSR0C = (0 << UMSEL01) | (0 << UMSEL00) |
  213. (0 << UPM01) | (0 << UPM00) |
  214. (1 << USBS0) |
  215. (1 << UCSZ01) | (1 << UCSZ00);
  216. UCSR0B = (1 << RXCIE0) | (0 << TXCIE0) | (0 << UDRIE0) |
  217. (1 << RXEN0) | (1 << TXEN0) |
  218. (0 << UCSZ02);
  219. )
  220. } else {
  221. IF_UART(
  222. UCSR0B = 0u;
  223. )
  224. }
  225. }
  226. }
  227. static void uart_rxd_pcint_handler(void)
  228. {
  229. if (USE_UART) {
  230. /* We woke up from deep sleep (power-down) by UART RX. */
  231. uart.standby_delay_ms = UART_STANDBY_DELAY_MS;
  232. system_handle_deep_sleep_wakeup();
  233. }
  234. }
  235. void uart_enter_deep_sleep(void)
  236. {
  237. if (USE_UART) {
  238. uart_enable(false);
  239. pcint_enable(UART_RXD_PCINT, true);
  240. }
  241. }
  242. /* Handle wake up from deep sleep.
  243. * Called with interrupts disabled. */
  244. void uart_handle_deep_sleep_wakeup(void)
  245. {
  246. if (USE_UART) {
  247. pcint_enable(UART_RXD_PCINT, false);
  248. uart_enable(true);
  249. uart_update_standby_suppress();
  250. }
  251. }
  252. /* Watchdog timer interrupt service routine
  253. * Called with interrupts disabled. */
  254. void uart_handle_watchdog_interrupt(void)
  255. {
  256. if (USE_UART) {
  257. uart.standby_delay_ms = sub_sat_u16(uart.standby_delay_ms,
  258. watchdog_interval_ms());
  259. uart_update_standby_suppress();
  260. }
  261. }
  262. void uart_init(void)
  263. {
  264. uint8_t i;
  265. if (USE_UART) {
  266. for (i = 0u; i < UART_NR_CHAN; i++) {
  267. uart.tx.ready_callback[i] = NULL;
  268. uart.rx.callback[i] = NULL;
  269. }
  270. pcint_register_callback(UART_RXD_PCINT, uart_rxd_pcint_handler);
  271. uart_update_standby_suppress();
  272. memory_barrier();
  273. uart_enable(true);
  274. }
  275. }