serial.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * File : serial.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://openlab.rt-thread.com/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2006-08-23 Bernard first version
  13. * 2009-05-14 Bernard add RT-THread device interface
  14. * 2010-03-14 MingBai US_IMR is read-only.
  15. * 2010-03-16 MingBai Changed interrupt source mode to level sensitive.
  16. */
  17. #include <rthw.h>
  18. #include <rtthread.h>
  19. #include "AT91SAM7X.h"
  20. #include "serial.h"
  21. /**
  22. * @addtogroup AT91SAM7X256
  23. */
  24. /*@{*/
  25. typedef volatile rt_uint32_t REG32;
  26. struct rt_at91serial_hw
  27. {
  28. REG32 US_CR; // Control Register
  29. REG32 US_MR; // Mode Register
  30. REG32 US_IER; // Interrupt Enable Register
  31. REG32 US_IDR; // Interrupt Disable Register
  32. REG32 US_IMR; // Interrupt Mask Register
  33. REG32 US_CSR; // Channel Status Register
  34. REG32 US_RHR; // Receiver Holding Register
  35. REG32 US_THR; // Transmitter Holding Register
  36. REG32 US_BRGR; // Baud Rate Generator Register
  37. REG32 US_RTOR; // Receiver Time-out Register
  38. REG32 US_TTGR; // Transmitter Time-guard Register
  39. REG32 Reserved0[5]; //
  40. REG32 US_FIDI; // FI_DI_Ratio Register
  41. REG32 US_NER; // Nb Errors Register
  42. REG32 Reserved1[1]; //
  43. REG32 US_IF; // IRDA_FILTER Register
  44. REG32 Reserved2[44]; //
  45. REG32 US_RPR; // Receive Pointer Register
  46. REG32 US_RCR; // Receive Counter Register
  47. REG32 US_TPR; // Transmit Pointer Register
  48. REG32 US_TCR; // Transmit Counter Register
  49. REG32 US_RNPR; // Receive Next Pointer Register
  50. REG32 US_RNCR; // Receive Next Counter Register
  51. REG32 US_TNPR; // Transmit Next Pointer Register
  52. REG32 US_TNCR; // Transmit Next Counter Register
  53. REG32 US_PTCR; // PDC Transfer Control Register
  54. REG32 US_PTSR; // PDC Transfer Status Register
  55. };
  56. struct rt_at91serial
  57. {
  58. struct rt_device parent;
  59. struct rt_at91serial_hw* hw_base;
  60. rt_uint16_t peripheral_id;
  61. rt_uint32_t baudrate;
  62. /* reception field */
  63. rt_uint16_t save_index, read_index;
  64. rt_uint8_t rx_buffer[RT_UART_RX_BUFFER_SIZE];
  65. };
  66. #ifdef RT_USING_UART1
  67. struct rt_at91serial serial1;
  68. #endif
  69. #ifdef RT_USING_UART2
  70. struct rt_at91serial serial2;
  71. #endif
  72. static void rt_hw_serial_isr(int irqno)
  73. {
  74. rt_base_t level;
  75. struct rt_device* device;
  76. struct rt_at91serial* serial = RT_NULL;
  77. #ifdef RT_USING_UART1
  78. if (irqno == AT91C_ID_US0)
  79. {
  80. /* serial 1 */
  81. serial = &serial1;
  82. }
  83. #endif
  84. #ifdef RT_USING_UART2
  85. if (irqno == AT91C_ID_US1)
  86. {
  87. /* serial 2 */
  88. serial = &serial2;
  89. }
  90. #endif
  91. RT_ASSERT(serial != RT_NULL);
  92. /* get generic device object */
  93. device = (rt_device_t)serial;
  94. /* disable interrupt */
  95. level = rt_hw_interrupt_disable();
  96. /* get received character */
  97. serial->rx_buffer[serial->save_index] = serial->hw_base->US_RHR;
  98. /* move to next position */
  99. serial->save_index ++;
  100. if (serial->save_index >= RT_UART_RX_BUFFER_SIZE)
  101. serial->save_index = 0;
  102. /* if the next position is read index, discard this 'read char' */
  103. if (serial->save_index == serial->read_index)
  104. {
  105. serial->read_index ++;
  106. if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
  107. serial->read_index = 0;
  108. }
  109. /* enable interrupt */
  110. rt_hw_interrupt_enable(level);
  111. /* indicate to upper layer application */
  112. if (device->rx_indicate != RT_NULL)
  113. device->rx_indicate(device, 1);
  114. /* ack interrupt */
  115. AT91C_AIC_EOICR = 1;
  116. }
  117. static rt_err_t rt_serial_init (rt_device_t dev)
  118. {
  119. rt_uint32_t bd;
  120. struct rt_at91serial* serial = (struct rt_at91serial*) dev;
  121. RT_ASSERT(serial != RT_NULL);
  122. /* must be US0 or US1 */
  123. RT_ASSERT((serial->peripheral_id == AT91C_ID_US0) ||
  124. (serial->peripheral_id == AT91C_ID_US1));
  125. /* Enable Clock for USART */
  126. AT91C_PMC_PCER = 1 << serial->peripheral_id;
  127. /* Enable RxD0 and TxDO Pin */
  128. if (serial->peripheral_id == AT91C_ID_US0)
  129. {
  130. /* set pinmux */
  131. //AT91C_PIO_PDR = (1 << 5) | (1 << 6);
  132. AT91C_PIO_PDR = 1 | (1 << 1); //fix bug 2010-3-9
  133. }
  134. else if (serial->peripheral_id == AT91C_ID_US1)
  135. {
  136. /* set pinmux */
  137. //AT91C_PIO_PDR = (1 << 21) | (1 << 22);
  138. AT91C_PIO_PDR = (1 << 5) | (1 << 6); //fix bug 2010-3-9
  139. }
  140. serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
  141. AT91C_US_RSTTX | /* Reset Transmitter */
  142. AT91C_US_RXDIS | /* Receiver Disable */
  143. AT91C_US_TXDIS; /* Transmitter Disable */
  144. serial->hw_base->US_MR = AT91C_US_USMODE_NORMAL | /* Normal Mode */
  145. AT91C_US_CLKS_CLOCK | /* Clock = MCK */
  146. AT91C_US_CHRL_8_BITS | /* 8-bit Data */
  147. AT91C_US_PAR_NONE | /* No Parity */
  148. AT91C_US_NBSTOP_1_BIT; /* 1 Stop Bit */
  149. /* set baud rate divisor */
  150. bd = ((MCK*10)/(serial->baudrate * 16));
  151. if ((bd % 10) >= 5) bd = (bd / 10) + 1;
  152. else bd /= 10;
  153. serial->hw_base->US_BRGR = bd;
  154. serial->hw_base->US_CR = AT91C_US_RXEN | /* Receiver Enable */
  155. AT91C_US_TXEN; /* Transmitter Enable */
  156. /* reset rx index */
  157. serial->save_index = 0;
  158. serial->read_index = 0;
  159. /* reset rx buffer */
  160. rt_memset(serial->rx_buffer, 0, RT_UART_RX_BUFFER_SIZE);
  161. return RT_EOK;
  162. }
  163. static rt_err_t rt_serial_open(rt_device_t dev, rt_uint16_t oflag)
  164. {
  165. struct rt_at91serial *serial = (struct rt_at91serial*)dev;
  166. RT_ASSERT(serial != RT_NULL);
  167. if (dev->flag & RT_DEVICE_FLAG_INT_RX)
  168. {
  169. /* enable UART rx interrupt */
  170. serial->hw_base->US_IER = 1 << 0; /* RxReady interrupt */
  171. // US_IMR is a READ-ONLY register!
  172. //serial->hw_base->US_IMR |= 1 << 0; /* umask RxReady interrupt */
  173. /* install UART handler */
  174. rt_hw_interrupt_install(serial->peripheral_id, rt_hw_serial_isr, RT_NULL);
  175. // SAM7X Datasheet 30.5.3:
  176. // It is notrecommended to use the USART interrupt line in edge sensitive mode
  177. //AT91C_AIC_SMR(serial->peripheral_id) = 5 | (0x01 << 5);
  178. AT91C_AIC_SMR(serial->peripheral_id) = 5;
  179. rt_hw_interrupt_umask(serial->peripheral_id);
  180. }
  181. return RT_EOK;
  182. }
  183. static rt_err_t rt_serial_close(rt_device_t dev)
  184. {
  185. struct rt_at91serial *serial = (struct rt_at91serial*)dev;
  186. RT_ASSERT(serial != RT_NULL);
  187. if (dev->flag & RT_DEVICE_FLAG_INT_RX)
  188. {
  189. /* disable interrupt */
  190. serial->hw_base->US_IDR = 1 << 0; /* RxReady interrupt */
  191. //serial->hw_base->US_IMR &= ~(1 << 0); /* mask RxReady interrupt */
  192. }
  193. serial->hw_base->US_CR = AT91C_US_RSTRX | /* Reset Receiver */
  194. AT91C_US_RSTTX | /* Reset Transmitter */
  195. AT91C_US_RXDIS | /* Receiver Disable */
  196. AT91C_US_TXDIS; /* Transmitter Disable */
  197. return RT_EOK;
  198. }
  199. static rt_size_t rt_serial_read (rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
  200. {
  201. rt_uint8_t* ptr;
  202. struct rt_at91serial *serial = (struct rt_at91serial*)dev;
  203. RT_ASSERT(serial != RT_NULL);
  204. /* point to buffer */
  205. ptr = (rt_uint8_t*) buffer;
  206. if (dev->flag & RT_DEVICE_FLAG_INT_RX)
  207. {
  208. while (size)
  209. {
  210. /* interrupt receive */
  211. rt_base_t level;
  212. /* disable interrupt */
  213. level = rt_hw_interrupt_disable();
  214. if (serial->read_index != serial->save_index)
  215. {
  216. *ptr = serial->rx_buffer[serial->read_index];
  217. serial->read_index ++;
  218. if (serial->read_index >= RT_UART_RX_BUFFER_SIZE)
  219. serial->read_index = 0;
  220. }
  221. else
  222. {
  223. /* no data in rx buffer */
  224. /* enable interrupt */
  225. rt_hw_interrupt_enable(level);
  226. break;
  227. }
  228. /* enable interrupt */
  229. rt_hw_interrupt_enable(level);
  230. ptr ++;
  231. size --;
  232. }
  233. return (rt_uint32_t)ptr - (rt_uint32_t)buffer;
  234. }
  235. else if (dev->flag & RT_DEVICE_FLAG_DMA_RX)
  236. {
  237. /* not support right now */
  238. RT_ASSERT(0);
  239. }
  240. else
  241. {
  242. /* poll mode */
  243. while (size)
  244. {
  245. /* Wait for Full Rx Buffer */
  246. while (!(serial->hw_base->US_CSR & AT91C_US_RXRDY));
  247. /* Read Character */
  248. *ptr = serial->hw_base->US_RHR;
  249. ptr ++;
  250. size --;
  251. }
  252. return (rt_size_t)ptr - (rt_size_t)buffer;
  253. }
  254. return 0;
  255. }
  256. static rt_size_t rt_serial_write (rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
  257. {
  258. rt_uint8_t* ptr;
  259. struct rt_at91serial *serial = (struct rt_at91serial*)dev;
  260. RT_ASSERT(serial != RT_NULL);
  261. ptr = (rt_uint8_t*) buffer;
  262. if (dev->open_flag & RT_DEVICE_OFLAG_WRONLY)
  263. {
  264. if (dev->flag & RT_DEVICE_FLAG_STREAM)
  265. {
  266. /* it's a stream mode device */
  267. while (size)
  268. {
  269. /* stream mode */
  270. if (*ptr == '\n')
  271. {
  272. while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
  273. serial->hw_base->US_THR = '\r';
  274. }
  275. /* Wait for Empty Tx Buffer */
  276. while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
  277. /* Transmit Character */
  278. serial->hw_base->US_THR = *ptr;
  279. ptr ++;
  280. size --;
  281. }
  282. }
  283. else
  284. {
  285. while (size)
  286. {
  287. /* Wait for Empty Tx Buffer */
  288. while (!(serial->hw_base->US_CSR & AT91C_US_TXRDY));
  289. /* Transmit Character */
  290. serial->hw_base->US_THR = *ptr;
  291. ptr ++;
  292. size --;
  293. }
  294. }
  295. }
  296. return (rt_size_t)ptr - (rt_size_t)buffer;
  297. }
  298. static rt_err_t rt_serial_control (rt_device_t dev, rt_uint8_t cmd, void *args)
  299. {
  300. return RT_EOK;
  301. }
  302. rt_err_t rt_hw_serial_init()
  303. {
  304. rt_device_t device;
  305. #ifdef RT_USING_UART1
  306. device = (rt_device_t) &serial1;
  307. /* init serial device private data */
  308. serial1.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US0;
  309. serial1.peripheral_id = AT91C_ID_US0;
  310. serial1.baudrate = 115200;
  311. /* set device virtual interface */
  312. device->init = rt_serial_init;
  313. device->open = rt_serial_open;
  314. device->close = rt_serial_close;
  315. device->read = rt_serial_read;
  316. device->write = rt_serial_write;
  317. device->control = rt_serial_control;
  318. /* register uart1 on device subsystem */
  319. rt_device_register(device, "uart1", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
  320. #endif
  321. #ifdef RT_USING_UART2
  322. device = (rt_device_t) &serial2;
  323. serial2.hw_base = (struct rt_at91serial_hw*)AT91C_BASE_US1;
  324. serial2.peripheral_id = AT91C_ID_US1;
  325. serial2.baudrate = 115200;
  326. /* set device virtual interface */
  327. device->init = rt_serial_init;
  328. device->open = rt_serial_open;
  329. device->close = rt_serial_close;
  330. device->read = rt_serial_read;
  331. device->write = rt_serial_write;
  332. device->control = rt_serial_control;
  333. /* register uart2 on device subsystem */
  334. rt_device_register(device, "uart2", RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
  335. #endif
  336. return RT_EOK;
  337. }
  338. /*@}*/