BeRTOS
|
00001 00038 #include <cfg/macros.h> /* for BV() */ 00039 #include <drv/gpio_lm3s.h> 00040 #include <drv/ser_p.h> 00041 #include <drv/ser.h> 00042 #include <drv/irq_cm3.h> 00043 #include "cfg/cfg_ser.h" 00044 #include "ser_lm3s.h" 00045 00046 /* From the high-level serial driver */ 00047 extern struct Serial *ser_handles[SER_CNT]; 00048 00049 struct CM3Serial 00050 { 00051 struct SerialHardware hw; 00052 bool sending; 00053 uint32_t base; 00054 sysirq_t irq; 00055 }; 00056 00057 /* Forward declaration */ 00058 static struct CM3Serial UARTDesc[SER_CNT]; 00059 00060 /* GPIO descriptor for UART pins */ 00061 struct gpio_uart_info 00062 { 00063 /* Sysctl */ 00064 uint32_t sysctl; 00065 /* GPIO base address register */ 00066 uint32_t base; 00067 /* Pin(s) bitmask */ 00068 uint8_t pins; 00069 }; 00070 00071 /* Table to retrieve GPIO pins configuration to work as UART pins */ 00072 static const struct gpio_uart_info gpio_uart[SER_CNT] = 00073 { 00074 /* UART0 */ 00075 { 00076 .base = GPIO_PORTA_BASE, 00077 .pins = BV(1) | BV(0), 00078 .sysctl = SYSCTL_RCGC2_GPIOA, 00079 }, 00080 /* UART1 */ 00081 { 00082 .base = GPIO_PORTD_BASE, 00083 .pins = BV(3) | BV(2), 00084 .sysctl = SYSCTL_RCGC2_GPIOD, 00085 }, 00086 /* UART2 */ 00087 { 00088 .base = GPIO_PORTG_BASE, 00089 .pins = BV(1) | BV(0), 00090 .sysctl = SYSCTL_RCGC2_GPIOG, 00091 }, 00092 }; 00093 00094 void lm3s_uartSetBaudRate(uint32_t base, unsigned long baud) 00095 { 00096 unsigned long div; 00097 bool hi_speed; 00098 00099 if (baud * 16 > CPU_FREQ) 00100 { 00101 hi_speed = true; 00102 baud /= 2; 00103 } 00104 div = (CPU_FREQ * 8 / baud + 1) / 2; 00105 00106 lm3s_uartDisable(base); 00107 if (hi_speed) 00108 HWREG(base + UART_O_CTL) |= UART_CTL_HSE; 00109 else 00110 HWREG(base + UART_O_CTL) &= ~UART_CTL_HSE; 00111 /* Set the baud rate */ 00112 HWREG(base + UART_O_IBRD) = div / 64; 00113 HWREG(base + UART_O_FBRD) = div % 64; 00114 lm3s_uartClear(base); 00115 lm3s_uartEnable(base); 00116 } 00117 00118 void lm3s_uartSetParity(uint32_t base, int parity) 00119 { 00120 /* Set 8-bit word, one stop bit by default */ 00121 uint32_t config = UART_LCRH_WLEN_8; 00122 00123 switch(parity) 00124 { 00125 case SER_PARITY_NONE: 00126 break; 00127 case SER_PARITY_ODD: 00128 config |= UART_LCRH_PEN; 00129 break; 00130 case SER_PARITY_EVEN: 00131 config |= UART_LCRH_EPS | UART_LCRH_PEN; 00132 break; 00133 default: 00134 ASSERT(0); 00135 return; 00136 } 00137 lm3s_uartDisable(base); 00138 HWREG(base + UART_O_LCRH) = config; 00139 lm3s_uartClear(base); 00140 lm3s_uartEnable(base); 00141 } 00142 00143 void lm3s_uartInit(int port) 00144 { 00145 uint32_t reg_clock, base; 00146 00147 ASSERT(port >= 0 && port < SER_CNT); 00148 00149 base = UARTDesc[port].base; 00150 reg_clock = 1 << port; 00151 00152 /* Enable the peripheral clock */ 00153 SYSCTL_RCGC1_R |= reg_clock; 00154 SYSCTL_RCGC2_R |= gpio_uart[port].sysctl; 00155 lm3s_busyWait(512); 00156 00157 /* Configure GPIO pins to work as UART pins */ 00158 lm3s_gpioPinConfig(gpio_uart[port].base, gpio_uart[port].pins, 00159 GPIO_DIR_MODE_HW, GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD); 00160 00161 /* Set serial param: 115.200 bps, no parity */ 00162 lm3s_uartSetBaudRate(base, 115200); 00163 lm3s_uartSetParity(base, SER_PARITY_NONE); 00164 } 00165 00166 static bool tx_sending(struct SerialHardware *_hw) 00167 { 00168 struct CM3Serial *hw = (struct CM3Serial *)_hw; 00169 return hw->sending; 00170 } 00171 00172 static void uart_irq_rx(int port) 00173 { 00174 struct FIFOBuffer *rxfifo = &ser_handles[port]->rxfifo; 00175 uint32_t base = UARTDesc[port].base; 00176 char c; 00177 00178 while (lm3s_uartRxReady(base)) 00179 { 00180 c = HWREG(base + UART_O_DR); 00181 if (fifo_isfull(rxfifo)) 00182 ser_handles[port]->status |= SERRF_RXFIFOOVERRUN; 00183 else 00184 fifo_push(rxfifo, c); 00185 } 00186 } 00187 00188 static void uart_irq_tx(int port) 00189 { 00190 struct FIFOBuffer *txfifo = &ser_handles[port]->txfifo; 00191 uint32_t base = UARTDesc[port].base; 00192 00193 while (lm3s_uartTxReady(base)) 00194 { 00195 if (fifo_isempty(txfifo)) 00196 { 00197 /* 00198 * Disable TX empty interrupts if there're no more 00199 * characters to transmit. 00200 */ 00201 HWREG(base + UART_O_IM) &= ~UART_IM_TXIM; 00202 UARTDesc[port].sending = false; 00203 break; 00204 } 00205 HWREG(base + UART_O_DR) = fifo_pop(txfifo); 00206 } 00207 } 00208 00209 static void uart_common_irq_handler(int port) 00210 { 00211 uint32_t base = UARTDesc[port].base; 00212 uint32_t status; 00213 00214 /* Read and clear the IRQ status */ 00215 status = HWREG(base + UART_O_RIS); 00216 00217 /* Process the IRQ */ 00218 if (status & (UART_RIS_RXRIS | UART_RIS_RTRIS)) 00219 uart_irq_rx(port); 00220 if (status & UART_RIS_TXRIS) 00221 uart_irq_tx(port); 00222 } 00223 00224 static void lm3s_uartIRQEnable(int port, sysirq_handler_t handler) 00225 { 00226 uint32_t base = UARTDesc[port].base; 00227 sysirq_t irq = UARTDesc[port].irq; 00228 00229 /* Register the IRQ handler */ 00230 sysirq_setHandler(irq, handler); 00231 /* Enable RX interrupt in the UART interrupt mask register */ 00232 HWREG(base + UART_O_IM) |= UART_IM_RXIM | UART_IM_RTIM; 00233 } 00234 00235 static void lm3s_uartIRQDisable(int port) 00236 { 00237 uint32_t base = UARTDesc[port].base; 00238 00239 HWREG(base + UART_O_IM) &= 00240 ~(UART_IM_TXIM | UART_IM_RXIM | UART_IM_RTIM); 00241 } 00242 00243 /* UART class definition */ 00244 #define UART_PORT(port) \ 00245 /* UART TX and RX buffers */ \ 00246 static unsigned char \ 00247 uart ## port ## _txbuffer[CONFIG_UART ## port ## _TXBUFSIZE]; \ 00248 static unsigned char \ 00249 uart ## port ## _rxbuffer[CONFIG_UART ## port ## _RXBUFSIZE]; \ 00250 \ 00251 /* UART interrupt handler */ \ 00252 static DECLARE_ISR(uart ## port ## _irq_handler) \ 00253 { \ 00254 uart_common_irq_handler(port); \ 00255 } \ 00256 \ 00257 /* UART public methods */ \ 00258 static void \ 00259 uart ## port ## _txStart(struct SerialHardware *_hw) \ 00260 { \ 00261 struct FIFOBuffer *txfifo = &ser_handles[port]->txfifo; \ 00262 struct CM3Serial *hw = (struct CM3Serial *)_hw; \ 00263 \ 00264 if (hw->sending) \ 00265 return; \ 00266 lm3s_uartPutChar(UART ## port ## _BASE, fifo_pop(txfifo)); \ 00267 if (!fifo_isempty(txfifo)) \ 00268 { \ 00269 HWREG(UART ## port ## _BASE + UART_O_IM) |= \ 00270 UART_IM_TXIM; \ 00271 hw->sending = true; \ 00272 } \ 00273 } \ 00274 \ 00275 static void \ 00276 uart ## port ## _setbaudrate(UNUSED_ARG(struct SerialHardware *, hw), \ 00277 unsigned long baud) \ 00278 { \ 00279 lm3s_uartSetBaudRate(UART ## port ## _BASE, baud); \ 00280 } \ 00281 \ 00282 static void \ 00283 uart ## port ## _setparity(UNUSED_ARG(struct SerialHardware *, hw), \ 00284 int parity) \ 00285 { \ 00286 lm3s_uartSetParity(UART ## port ## _BASE, parity); \ 00287 } \ 00288 \ 00289 static void \ 00290 uart ## port ## _cleanup(struct SerialHardware *_hw) \ 00291 { \ 00292 struct CM3Serial *hw = (struct CM3Serial *)_hw; \ 00293 \ 00294 hw->sending = false; \ 00295 lm3s_uartIRQDisable(port); \ 00296 lm3s_uartClear(UART ## port ## _BASE); \ 00297 lm3s_uartDisable(UART ## port ## _BASE); \ 00298 } \ 00299 \ 00300 static void \ 00301 uart ## port ## _init(UNUSED_ARG(struct SerialHardware *, hw), \ 00302 UNUSED_ARG(struct Serial *, ser)) \ 00303 { \ 00304 lm3s_uartInit(port); \ 00305 lm3s_uartEnable(UART ## port ## _BASE); \ 00306 lm3s_uartIRQEnable(port, uart ## port ## _irq_handler); \ 00307 } \ 00308 \ 00309 /* UART operations */ \ 00310 static const struct SerialHardwareVT UART ## port ## _VT = \ 00311 { \ 00312 .init = uart ## port ## _init, \ 00313 .cleanup = uart ## port ## _cleanup, \ 00314 .setBaudrate = uart ## port ## _setbaudrate, \ 00315 .setParity = uart ## port ## _setparity, \ 00316 .txStart = uart ## port ## _txStart, \ 00317 .txSending = tx_sending, \ 00318 }; 00319 00320 /* UART port instances */ 00321 UART_PORT(0) 00322 UART_PORT(1) 00323 UART_PORT(2) 00324 00325 static struct CM3Serial UARTDesc[SER_CNT] = 00326 { 00327 { 00328 .hw = { 00329 .table = &UART0_VT, 00330 .txbuffer = uart0_txbuffer, 00331 .rxbuffer = uart0_rxbuffer, 00332 .txbuffer_size = sizeof(uart0_txbuffer), 00333 .rxbuffer_size = sizeof(uart0_rxbuffer), 00334 }, 00335 .sending = false, 00336 .base = UART0_BASE, 00337 .irq = INT_UART0, 00338 }, 00339 { 00340 .hw = { 00341 .table = &UART1_VT, 00342 .txbuffer = uart1_txbuffer, 00343 .rxbuffer = uart1_rxbuffer, 00344 .txbuffer_size = sizeof(uart1_txbuffer), 00345 .rxbuffer_size = sizeof(uart1_rxbuffer), 00346 }, 00347 .sending = false, 00348 .base = UART1_BASE, 00349 .irq = INT_UART1, 00350 }, 00351 { 00352 .hw = { 00353 .table = &UART2_VT, 00354 .txbuffer = uart2_txbuffer, 00355 .rxbuffer = uart2_rxbuffer, 00356 .txbuffer_size = sizeof(uart2_txbuffer), 00357 .rxbuffer_size = sizeof(uart2_rxbuffer), 00358 }, 00359 .sending = false, 00360 .base = UART2_BASE, 00361 .irq = INT_UART2, 00362 }, 00363 }; 00364 00365 struct SerialHardware *ser_hw_getdesc(int port) 00366 { 00367 ASSERT(port >= 0 && port < SER_CNT); 00368 return &UARTDesc[port].hw; 00369 }