BeRTOS
ser_lm3s.c
Go to the documentation of this file.
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 }