altos/lpc: Get USART running
authorKeith Packard <keithp@keithp.com>
Sat, 20 Apr 2013 05:20:55 +0000 (00:20 -0500)
committerKeith Packard <keithp@keithp.com>
Fri, 17 May 2013 10:50:07 +0000 (03:50 -0700)
Adds a simple demo thread that spews data to the serial port

Signed-off-by: Keith Packard <keithp@keithp.com>
src/lpc/ao_serial_lpc.c
src/lpc/lpc.h
src/lpc/registers.ld
src/lpcxpresso/ao_demo.c
src/lpcxpresso/ao_pins.h

index e47f743eec43ff9b73e751f226b256d06f9f81be..4ecaa175f0cc69f6da06bab4330bed758ee5d3d3 100644 (file)
@@ -27,10 +27,9 @@ ao_debug_out(char c)
 {
        if (c == '\n')
                ao_debug_out('\r');
-#if 0
-       while (!(stm_usart1.sr & (1 << STM_USART_SR_TXE)));
-       stm_usart1.dr = c;
-#endif
+       while (!(lpc_usart.lsr & (1 << LPC_USART_LSR_TEMT)))
+               ;
+       lpc_usart.rbr_thr = c;
 }
 
 static void
@@ -39,35 +38,28 @@ _ao_serial_tx_start(void)
        if (!ao_fifo_empty(ao_usart_tx_fifo) & !ao_usart_tx_started)
        {
                ao_usart_tx_started = 1;
-#if 0
-               ao_fifo_remove(ao_usart_tx_fifo, usart->reg->dr);
-#endif
+               ao_fifo_remove(ao_usart_tx_fifo, lpc_usart.rbr_thr);
        }
 }
 
 void
 lpc_usart_isr(void)
 {
-#if 0
-       uint32_t        sr;
-
-       sr = usart->reg->sr;
-       usart->reg->sr = 0;
+       (void) lpc_usart.iir_fcr;
 
-       if (sr & (1 << STM_USART_SR_RXNE)) {
-               char c = usart->reg->dr;
+       while (lpc_usart.lsr & (1 << LPC_USART_LSR_RDR)) {
+               char c = lpc_usart.rbr_thr;
                if (!ao_fifo_full(ao_usart_rx_fifo))
                        ao_fifo_insert(ao_usart_rx_fifo, c);
-               ao_wakeup(ao_usart_rx_fifo);
+               ao_wakeup(&ao_usart_rx_fifo);
                if (stdin)
                        ao_wakeup(&ao_stdin_ready);
        }
-       if (sr & (1 << STM_USART_SR_TC)) {
+       if (lpc_usart.lsr & (1 << LPC_USART_LSR_THRE)) {
                ao_usart_tx_started = 0;
-               _ao_usart_tx_start(usart);
-               ao_wakeup(ao_usart_tx_fifo);
+               _ao_serial_tx_start();
+               ao_wakeup(&ao_usart_tx_fifo);
        }
-#endif
 }
 
 int
@@ -116,24 +108,33 @@ ao_serial_drain(void)
        ao_arch_release_interrupts();
 }
 
+#include "ao_serial_lpc.h"
+
 void
 ao_serial_set_speed(uint8_t speed)
 {
        if (speed > AO_SERIAL_SPEED_115200)
                return;
-#if 0
-       usart->reg->brr = ao_usart_speeds[speed].brr;
-#endif
-}
 
-#include "ao_serial_lpc.h"
+       /* Flip to allow access to divisor latches */
+       lpc_usart.lcr |= (1 << LPC_USART_LCR_DLAB);
+
+       /* DL LSB */
+       lpc_usart.rbr_thr = ao_usart_speeds[speed].dl & 0xff;
+       
+       /* DL MSB */
+       lpc_usart.ier = (ao_usart_speeds[speed].dl >> 8) & 0xff;
+
+       lpc_usart.fdr = ((ao_usart_speeds[speed].divaddval << LPC_USART_FDR_DIVADDVAL) |
+                        (ao_usart_speeds[speed].mulval << LPC_USART_FDR_MULVAL));
+
+       /* Turn access to divisor latches back off */
+       lpc_usart.lcr &= ~(1 << LPC_USART_LCR_DLAB);
+}
 
 void
 ao_serial_init(void)
 {
-       /* Turn on the USART clock */
-       lpc_scb.uartclkdiv = 1;
-
 #if SERIAL_0_18_19
        lpc_ioconf.pio0_18 = ((LPC_IOCONF_FUNC_PIO0_18_RXD << LPC_IOCONF_FUNC) |
                              (LPC_IOCONF_MODE_INACTIVE << LPC_IOCONF_MODE) |
@@ -149,6 +150,53 @@ ao_serial_init(void)
 
        /* Turn on the USART */
        lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_USART);
-}
-
 
+       /* Turn on the USART clock */
+       lpc_scb.uartclkdiv = AO_LPC_CLKOUT / AO_LPC_USARTCLK;
+
+       /* Configure USART */
+
+       /* Enable FIFOs, reset fifo contents, interrupt on 1 received char */
+       lpc_usart.iir_fcr = ((1 << LPC_USART_FCR_FIFOEN) |
+                        (1 << LPC_USART_FCR_RXFIFORES) |
+                        (1 << LPC_USART_FCR_TXFIFORES) |
+                        (LPC_USART_FCR_RXTL_1 << LPC_USART_FCR_RXTL));
+
+       /* 8 n 1 */
+       lpc_usart.lcr = ((LPC_USART_LCR_WLS_8 << LPC_USART_LCR_WLS) |
+                        (LPC_USART_LCR_SBS_1 << LPC_USART_LCR_SBS) |
+                        (0 << LPC_USART_LCR_PE) |
+                        (LPC_USART_LCR_PS_ODD << LPC_USART_LCR_PS) |
+                        (0 << LPC_USART_LCR_BC) |
+                        (0 << LPC_USART_LCR_DLAB));
+
+       /* Disable flow control */
+       lpc_usart.mcr = ((0 << LPC_USART_MCR_DTRCTRL) |
+                        (0 << LPC_USART_MCR_RTSCTRL) |
+                        (0 << LPC_USART_MCR_LMS) |
+                        (0 << LPC_USART_MCR_RTSEN) |
+                        (0 << LPC_USART_MCR_CTSEN));
+
+       /* 16x oversampling */
+       lpc_usart.osr = ((0 << LPC_USART_OSR_OSFRAC) |
+                        ((16 - 1) << LPC_USART_OSR_OSINT) |
+                        (0 << LPC_USART_OSR_FDINT));
+
+       /* Full duplex */
+       lpc_usart.hden = ((0 << LPC_USART_HDEN_HDEN));
+
+       /* Set baud rate */
+       ao_serial_set_speed(AO_SERIAL_SPEED_9600);
+
+       /* Enable interrupts */
+       lpc_usart.ier = ((1 << LPC_USART_IER_RBRINTEN) |
+                        (1 << LPC_USART_IER_THREINTEN));
+
+       lpc_nvic_set_enable(LPC_ISR_USART_POS);
+       lpc_nvic_set_priority(LPC_ISR_USART_POS, 0);
+#if USE_SERIAL_0_STDIN
+       ao_add_stdio(_ao_serial_pollchar,
+                    ao_serial_putchar,
+                    NULL);
+#endif
+}
index 87af494a9c90274b3bc7e3e1859aac68a13d6c3f..81cd0cc8921a9f3e7a8e68222ae3914586b48e8f 100644 (file)
@@ -720,4 +720,193 @@ struct lpc_usart {
 
 extern struct lpc_usart lpc_usart;
 
+#define LPC_USART_IER_RBRINTEN 0
+#define LPC_USART_IER_THREINTEN        1
+#define LPC_USART_IER_RSLINTEN 2
+#define LPC_USART_IER_MSINTEN  3
+#define LPC_USART_IER_ABEOINTEN        8
+#define LPC_USART_IER_ABTOINTEN        9
+
+#define LPC_USART_IIR_INTSTATUS                0
+#define LPC_USART_IIR_INTID            1
+#define LPC_USART_IIR_INTID_RLS                        3
+#define LPC_USART_IIR_INTID_RDA                        2
+#define LPC_USART_IIR_INTID_CTI                        6
+#define LPC_USART_IIR_INTID_THRE               1
+#define LPC_USART_IIR_INTID_MS                 0
+#define LPC_USART_IIR_INTID_MASK               7
+#define LPC_USART_IIR_FIFOEN           6
+#define LPC_USART_IIR_ABEOINT          8
+#define LPC_USART_IIR_ABTOINT          9
+
+#define LPC_USART_FCR_FIFOEN           0
+#define LPC_USART_FCR_RXFIFORES                1
+#define LPC_USART_FCR_TXFIFORES                2
+#define LPC_USART_FCR_RXTL             6
+#define LPC_USART_FCR_RXTL_1                   0
+#define LPC_USART_FCR_RXTL_4                   1
+#define LPC_USART_FCR_RXTL_8                   2
+#define LPC_USART_FCR_RXTL_14                  3
+
+#define LPC_USART_LCR_WLS      0
+#define LPC_USART_LCR_WLS_5            0
+#define LPC_USART_LCR_WLS_6            1
+#define LPC_USART_LCR_WLS_7            2
+#define LPC_USART_LCR_WLS_8            3
+#define LPC_USART_LCR_WLS_MASK         3
+#define LPC_USART_LCR_SBS      2
+#define LPC_USART_LCR_SBS_1            0
+#define LPC_USART_LCR_SBS_2            1
+#define LPC_USART_LCR_SBS_MASK         1
+#define LPC_USART_LCR_PE       3
+#define LPC_USART_LCR_PS       4
+#define LPC_USART_LCR_PS_ODD           0
+#define LPC_USART_LCR_PS_EVEN          1
+#define LPC_USART_LCR_PS_ONE           2
+#define LPC_USART_LCR_PS_ZERO          3
+#define LPC_USART_LCR_PS_MASK          3
+#define LPC_USART_LCR_BC       6
+#define LPC_USART_LCR_DLAB     7
+
+#define LPC_USART_MCR_DTRCTRL  0
+#define LPC_USART_MCR_RTSCTRL  1
+#define LPC_USART_MCR_LMS      4
+#define LPC_USART_MCR_RTSEN    6
+#define LPC_USART_MCR_CTSEN    7
+
+#define LPC_USART_LSR_RDR      0
+#define LPC_USART_LSR_OE       1
+#define LPC_USART_LSR_PE       2
+#define LPC_USART_LSR_FE       3
+#define LPC_USART_LSR_BI       4
+#define LPC_USART_LSR_THRE     5
+#define LPC_USART_LSR_TEMT     6
+#define LPC_USART_LSR_RXFE     7
+#define LPC_USART_LSR_TXERR    8
+
+#define LPC_USART_MSR_DCTS     0
+#define LPC_USART_MSR_DDSR     1
+#define LPC_USART_MSR_TERI     2
+#define LPC_USART_MSR_DDCD     3
+#define LPC_USART_MSR_CTS      4
+#define LPC_USART_MSR_DSR      5
+#define LPC_USART_MSR_RI       6
+#define LPC_USART_MSR_DCD      7
+
+#define LPC_USART_ACR_START    0
+#define LPC_USART_ACR_MODE     1
+#define LPC_USART_ACR_AUTORESTART      2
+#define LPC_USART_ACR_ABEOINTCLR       8
+#define LPC_USART_ACR_ABTOINTCLR       9
+
+#define LPC_USART_FDR_DIVADDVAL        0
+#define LPC_USART_FDR_MULVAL   4
+
+#define LPC_USART_OSR_OSFRAC   1
+#define LPC_USART_OSR_OSINT    4
+#define LPC_USART_OSR_FDINT    8
+
+#define LPC_USART_TER_TXEN     7
+
+#define LPC_USART_HDEN_HDEN    0
+
+#define LPC_ISR_PIN_INT0_POS   0
+#define LPC_ISR_PIN_INT1_POS   1
+#define LPC_ISR_PIN_INT2_POS   2
+#define LPC_ISR_PIN_INT3_POS   3
+#define LPC_ISR_PIN_INT4_POS   4
+#define LPC_ISR_PIN_INT5_POS   5
+#define LPC_ISR_PIN_INT6_POS   6
+#define LPC_ISR_PIN_INT7_POS   7
+#define LPC_ISR_GINT0_POS      8
+#define LPC_ISR_GINT1_POS      9
+#define LPC_ISR_SSP1_POS       14
+#define LPC_ISR_I2C_POS                15
+#define LPC_ISR_CT16B0_POS     16
+#define LPC_ISR_CT16B1_POS     17
+#define LPC_ISR_CT32B0_POS     18
+#define LPC_ISR_CT32B1_POS     19
+#define LPC_ISR_SSP0_POS       20
+#define LPC_ISR_USART_POS      21
+#define LPC_ISR_USB_IRQ_POS    22
+#define LPC_ISR_USB_FIQ_POS    23
+#define LPC_ISR_ADC_POS                24
+#define LPC_ISR_WWDT_POS       25
+#define LPC_ISR_BOD_POS                26
+#define LPC_ISR_FLASH_POS      27
+#define LPC_ISR_USB_WAKEUP_POS 30
+
+struct lpc_nvic {
+       vuint32_t       iser;           /* 0x000 0xe000e100 Set Enable Register */
+
+       uint8_t         _unused020[0x080 - 0x004];
+
+       vuint32_t       icer;           /* 0x080 0xe000e180 Clear Enable Register */
+
+       uint8_t         _unused0a0[0x100 - 0x084];
+
+       vuint32_t       ispr;           /* 0x100 0xe000e200 Set Pending Register */
+
+       uint8_t         _unused120[0x180 - 0x104];
+
+       vuint32_t       icpr;           /* 0x180 0xe000e280 Clear Pending Register */
+
+       uint8_t         _unused1a0[0x300 - 0x184];
+
+       vuint32_t       ipr[8];         /* 0x300 0xe000e400 Priority Register */
+};
+
+extern struct lpc_nvic lpc_nvic;
+
+static inline void
+lpc_nvic_set_enable(int irq) {
+       lpc_nvic.iser |= (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_enable(int irq) {
+       lpc_nvic.icer |= (1 << irq);
+}
+
+static inline int
+lpc_nvic_enabled(int irq) {
+       return (lpc_nvic.iser >> irq) & 1;
+}
+
+       
+static inline void
+lpc_nvic_set_pending(int irq) {
+       lpc_nvic.ispr = (1 << irq);
+}
+
+static inline void
+lpc_nvic_clear_pending(int irq) {
+       lpc_nvic.icpr = (1 << irq);
+}
+
+static inline int
+lpc_nvic_pending(int irq) {
+       return (lpc_nvic.ispr >> irq) & 1;
+}
+
+#define IRQ_PRIO_REG(irq)      ((irq) >> 2)
+#define IRQ_PRIO_BIT(irq)      (((irq) & 3) << 3)
+#define IRQ_PRIO_MASK(irq)     (0xff << IRQ_PRIO_BIT(irq))
+
+static inline void
+lpc_nvic_set_priority(int irq, uint8_t prio) {
+       int             n = IRQ_PRIO_REG(irq);
+       uint32_t        v;
+
+       v = lpc_nvic.ipr[n];
+       v &= ~IRQ_PRIO_MASK(irq);
+       v |= (prio) << IRQ_PRIO_BIT(irq);
+       lpc_nvic.ipr[n] = v;
+}
+
+static inline uint8_t
+lpc_nvic_get_priority(int irq) {
+       return (lpc_nvic.ipr[IRQ_PRIO_REG(irq)] >> IRQ_PRIO_BIT(irq)) & IRQ_PRIO_MASK(0);
+}
+
 #endif /* _LPC_H_ */
index cd6ac5f5dc0acb118646c09b2ce10b9d4dec771a..e444d8325de2527b44d690d65a989c3fbab4bc46 100644 (file)
@@ -7,3 +7,4 @@ lpc_gpio_group0 = 0x4005c000;
 lpc_gpio_group1 = 0x40060000;
 lpc_gpio       = 0x50000000;
 lpc_systick    = 0xe000e000;
+lpc_nvic       = 0xe000e100;
index 56fef70635193840d59b0fa4f860b2a739d42071..eae9503efc4ca10fb210fac35bad96987e76db17 100644 (file)
@@ -26,6 +26,14 @@ static void demo(void) {
        }
 }
 
+static struct ao_task serial_task;
+
+static void serial(void) {
+       for (;;) {
+               printf ("hello, world\n");
+       }
+}
+
 int
 main(void)
 {
@@ -35,9 +43,12 @@ main(void)
        ao_clock_init();
        ao_timer_init();
        
+       ao_serial_init();
+
        ao_task_init();
 
        ao_add_task(&demo_task, demo, "demo");
+       ao_add_task(&serial_task, serial, "serial");
 
        ao_start_scheduler();
 
index 56391c2b7a66a8d37c87be6c947d29fecc1596a9..7748f73c86d9426708d70079907eeaf36e3fcd2f 100644 (file)
@@ -40,8 +40,9 @@
 
 /* USART */
 
-#define HAS_SERIAL     1
+#define HAS_SERIAL             1
+#define USE_SERIAL_0_STDIN     1
 #define SERIAL_0_18_19         1
-#define SERIAL_1_14_15         0
-#define SERIAL_1_17_18         0
-#define SERIAL_1_26_27         0
+#define SERIAL_0_14_15         0
+#define SERIAL_0_17_18         0
+#define SERIAL_0_26_27         0