usart.c 10.7 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2021, RT-Thread Development Team
3
 *
4
 * SPDX-License-Identifier: Apache-2.0
5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * Change Logs:
 * Date           Author       Notes
 * 2011-01-13     weety       first version
 * 2013-07-21     weety       using serial component
 */

#include <rtthread.h>
#include <rthw.h>
#include <at91sam9g45.h>
#include <rtdevice.h>


struct at91_uart {
19 20
    AT91S_USART *port;
    int irq;
21 22 23 24 25 26 27 28
};


/**
 * This function will handle serial port interrupt
 */
void rt_at91_usart_handler(int vector, void *param)
{
29 30 31 32 33 34 35 36 37 38 39 40
    int status;
    struct at91_uart *uart;
    rt_device_t dev = (rt_device_t)param;
    uart = (struct at91_uart *)dev->user_data;
    status = uart->port->US_CSR;
    if (!(status & uart->port->US_IMR)) /* check actived and enabled interrupt */
    {
        return;
    }
    rt_interrupt_enter();
    rt_hw_serial_isr((struct rt_serial_device *)dev, RT_SERIAL_EVENT_RX_IND);
    rt_interrupt_leave();
41 42 43 44 45 46 47 48
}

/**
 * UART device in RT-Thread
 */
static rt_err_t at91_usart_configure(struct rt_serial_device *serial,
                                struct serial_configure *cfg)
{
49 50 51
    int div;
    int mode = 0;
    struct at91_uart *uart;
52

53
    RT_ASSERT(serial != RT_NULL);
54
    RT_ASSERT(cfg != RT_NULL);
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
    uart = (struct at91_uart *)serial->parent.user_data;

    uart->port->US_CR = AT91C_US_RSTTX | AT91C_US_RSTRX |
           AT91C_US_RXDIS | AT91C_US_TXDIS;
    mode |= AT91C_US_USMODE_NORMAL | AT91C_US_CLKS_CLOCK |
           AT91C_US_CHMODE_NORMAL;
    switch (cfg->data_bits)
    {
    case DATA_BITS_8:
        mode |= AT91C_US_CHRL_8_BITS;
        break;
    case DATA_BITS_7:
        mode |= AT91C_US_CHRL_7_BITS;
        break;
    case DATA_BITS_6:
        mode |= AT91C_US_CHRL_6_BITS;
        break;
    case DATA_BITS_5:
        mode |= AT91C_US_CHRL_5_BITS;
        break;
    default:
        mode |= AT91C_US_CHRL_8_BITS;
        break;
    }

    switch (cfg->stop_bits)
    {
    case STOP_BITS_2:
        mode |= AT91C_US_NBSTOP_2_BIT;
        break;
    case STOP_BITS_1:
    default:
        mode |= AT91C_US_NBSTOP_1_BIT;
        break;
    }

    switch (cfg->parity)
    {
    case PARITY_ODD:
        mode |= AT91C_US_PAR_ODD;
        break;
    case PARITY_EVEN:
        mode |= AT91C_US_PAR_EVEN;
        break;
    case PARITY_NONE:
    default:
        mode |= AT91C_US_PAR_NONE;
        break;
    }

    uart->port->US_MR = mode;
106
    /* Assume OVER is cleared and fractional baudrate generator is disabled */
107 108 109 110
    div = (clk_get_rate(clk_get("mck")) / 16 + cfg->baud_rate/2) / cfg->baud_rate;
    uart->port->US_BRGR = div;
    uart->port->US_CR = AT91C_US_RXEN | AT91C_US_TXEN;
    uart->port->US_IER = AT91C_US_RXRDY;
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126

    return RT_EOK;
}

static rt_err_t at91_usart_control(struct rt_serial_device *serial,
                              int cmd, void *arg)
{
    struct at91_uart* uart;

    RT_ASSERT(serial != RT_NULL);
    uart = (struct at91_uart *)serial->parent.user_data;

    switch (cmd)
    {
    case RT_DEVICE_CTRL_CLR_INT:
        /* disable rx irq */
127
        rt_hw_interrupt_mask(uart->irq);
128 129 130
        break;
    case RT_DEVICE_CTRL_SET_INT:
        /* enable rx irq */
131
        rt_hw_interrupt_umask(uart->irq);
132 133 134 135 136 137 138 139 140
        break;
    }

    return RT_EOK;
}

static int at91_usart_putc(struct rt_serial_device *serial, char c)
{
    //rt_uint32_t level;
141
    struct at91_uart *uart = serial->parent.user_data;
142 143

    while (!(uart->port->US_CSR & AT91C_US_TXRDY));
144
    uart->port->US_THR = c;
145 146 147 148 149 150 151

    return 1;
}

static int at91_usart_getc(struct rt_serial_device *serial)
{
    int result;
152
    struct at91_uart *uart = serial->parent.user_data;
153 154

    if (uart->port->US_CSR & AT91C_US_RXRDY)
155 156 157 158 159 160 161
    {
        result = uart->port->US_RHR & 0xff;
    }
    else
    {
        result = -1;
    }
162 163 164 165 166 167 168 169 170 171 172 173 174 175 176

    return result;
}

static const struct rt_uart_ops at91_usart_ops =
{
    at91_usart_configure,
    at91_usart_control,
    at91_usart_putc,
    at91_usart_getc,
};

#if defined(RT_USING_DBGU)
static struct rt_serial_device serial_dbgu;
struct at91_uart dbgu = {
177 178
    (AT91PS_USART)AT91C_BASE_DBGU,
    AT91C_ID_SYS
179 180 181 182 183 184 185
};

#endif

#if defined(RT_USING_UART0)
static struct rt_serial_device serial0;
struct at91_uart uart0 = {
186 187
    AT91C_BASE_US0,
    AT91C_ID_US0
188 189 190 191 192 193
};
#endif

#if defined(RT_USING_UART1)
static struct rt_serial_device serial1;
struct at91_uart uart1 = {
194 195
    AT91C_BASE_US1,
    AT91C_ID_US1
196 197 198 199 200 201
};
#endif

#if defined(RT_USING_UART2)
static struct rt_serial_device serial2;
struct at91_uart uart2 = {
202 203
    AT91C_BASE_US2,
    AT91C_ID_US2
204 205 206 207 208 209
};
#endif

#if defined(RT_USING_UART3)
static struct rt_serial_device serial3;
struct at91_uart uart3 = {
210 211
    AT91C_BASE_US3,
    AT91C_ID_US3
212 213 214 215 216 217 218
};
#endif


void at91_usart_gpio_init(void)
{
#ifdef RT_USING_DBGU
219 220 221 222 223 224 225
#define DRXD    12      // DBGU  rx as Peripheral A on PB12
#define DTXD    13      // DBGU  tx as Peripheral A on PB13
    AT91C_BASE_PIOB->PIO_IDR,   (1<<DRXD)|(1<<DTXD);   // Disables the Input Change Interrupt on the I/O line
    AT91C_BASE_PIOB->PIO_PPUDR, (1<<DRXD)|(1<<DTXD);   // Disables the pull up resistor on the I/O line
    AT91C_BASE_PIOB->PIO_ASR,   (1<<DRXD)|(1<<DTXD);   // Assigns the I/O line to the Peripheral A function
    AT91C_BASE_PIOB->PIO_PDR,   (1<<DRXD)|(1<<DTXD);   // enables peripheral control of the pin
    AT91C_BASE_PMC->PMC_PCER,    1 << AT91C_ID_SYS;
226 227 228
#endif

#ifdef RT_USING_UART0
229 230 231 232 233 234 235 236
#define RXD0    18      // UART0 rx as Peripheral A on PB18
#define TXD0    19      // UART0 tx as Peripheral A on PB19
    AT91C_BASE_PMC->PMC_PCER,    1 << AT91C_ID_US0;
    AT91C_BASE_PIOB->PIO_IDR,   (1<<RXD0)|(1<<TXD0);
    AT91C_BASE_PIOB->PIO_PPUER, (1<<RXD0);
    AT91C_BASE_PIOB->PIO_PPUDR, (1<<TXD0);
    AT91C_BASE_PIOB->PIO_ASR,   (1<<RXD0)|(1<<TXD0);
    AT91C_BASE_PIOB->PIO_PDR,   (1<<RXD0)|(1<<TXD0);
237 238 239
#endif

#ifdef RT_USING_UART1
240 241 242 243 244 245 246 247
#define TXD1     4      // UART1 tx as Peripheral A on PB4
#define RXD1     5      // UART1 rx as Peripheral A on PB5
    AT91C_BASE_PMC->PMC_PCER,    1 << AT91C_ID_US1;
    AT91C_BASE_PIOB->PIO_IDR,   (1<<RXD1)|(1<<TXD1);
    AT91C_BASE_PIOB->PIO_PPUER, (1<<RXD1);
    AT91C_BASE_PIOB->PIO_PPUDR, (1<<TXD1);
    AT91C_BASE_PIOB->PIO_ASR,   (1<<RXD1)|(1<<TXD1);
    AT91C_BASE_PIOB->PIO_PDR,   (1<<RXD1)|(1<<TXD1);
248 249 250
#endif

#ifdef RT_USING_UART2
251 252 253 254 255 256 257 258
#define TXD2     6      // UART2 tx as Peripheral A on PB6
#define RXD2     7      // UART2 rx as Peripheral A on PB7
    AT91C_BASE_PMC->PMC_PCER,    1 << AT91C_ID_US2;
    AT91C_BASE_PIOB->PIO_IDR,   (1<<RXD2)|(1<<TXD2);
    AT91C_BASE_PIOB->PIO_PPUER, (1<<RXD2);
    AT91C_BASE_PIOB->PIO_PPUDR, (1<<TXD2);
    AT91C_BASE_PIOB->PIO_ASR,   (1<<RXD2)|(1<<TXD2);
    AT91C_BASE_PIOB->PIO_PDR,   (1<<RXD2)|(1<<TXD2);
259 260 261
#endif

#ifdef RT_USING_UART3
262 263 264 265 266 267 268 269
#define TXD3     8      // UART3 tx as Peripheral A on PB8
#define RXD3     9      // UART3 rx as Peripheral A on PB9
    AT91C_BASE_PMC->PMC_PCER,    1<<AT91C_ID_US3;
    AT91C_BASE_PIOB->PIO_IDR,   (1<<RXD3)|(1<<TXD3);
    AT91C_BASE_PIOB->PIO_PPUER, (1<<RXD3);
    AT91C_BASE_PIOB->PIO_PPUDR, (1<<TXD3);
    AT91C_BASE_PIOB->PIO_ASR,   (1<<RXD3)|(1<<TXD3);
    AT91C_BASE_PIOB->PIO_PDR,   (1<<RXD3)|(1<<TXD3);
270 271 272 273 274 275 276 277
#endif
}

/**
 * This function will handle init uart
 */
int rt_hw_uart_init(void)
{
278
    at91_usart_gpio_init();
279 280

#if defined(RT_USING_DBGU)
281 282
    serial_dbgu.ops = &at91_usart_ops;
    serial_dbgu.config.baud_rate = BAUD_RATE_115200;
283 284 285 286 287
    serial_dbgu.config.bit_order = BIT_ORDER_LSB;
    serial_dbgu.config.data_bits = DATA_BITS_8;
    serial_dbgu.config.parity = PARITY_NONE;
    serial_dbgu.config.stop_bits = STOP_BITS_1;
    serial_dbgu.config.invert = NRZ_NORMAL;
288
    serial_dbgu.config.bufsz = RT_SERIAL_RB_BUFSZ;
289 290 291 292 293 294 295 296

    /* register vcom device */
    rt_hw_serial_register(&serial_dbgu, "dbgu",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                          &dbgu);
#endif

#if defined(RT_USING_UART0)
297 298
    serial0.ops = &at91_usart_ops;
    serial0.config.baud_rate = BAUD_RATE_115200;
299 300 301 302 303
    serial0.config.bit_order = BIT_ORDER_LSB;
    serial0.config.data_bits = DATA_BITS_8;
    serial0.config.parity = PARITY_NONE;
    serial0.config.stop_bits = STOP_BITS_1;
    serial0.config.invert = NRZ_NORMAL;
304
    serial0.config.bufsz = RT_SERIAL_RB_BUFSZ;
305 306 307 308 309

    /* register vcom device */
    rt_hw_serial_register(&serial0, "uart0",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_STREAM,
                          &uart0);
310 311 312
    rt_hw_interrupt_install(uart0.irq, rt_at91_usart_handler,
                            (void *)&(serial0.parent), "UART0");
    rt_hw_interrupt_umask(uart0.irq);
313 314 315
#endif

#if defined(RT_USING_UART1)
316 317
    serial1.ops = &at91_usart_ops;
    serial1.config.baud_rate = BAUD_RATE_115200;
318 319 320 321 322
    serial1.config.bit_order = BIT_ORDER_LSB;
    serial1.config.data_bits = DATA_BITS_8;
    serial1.config.parity = PARITY_NONE;
    serial1.config.stop_bits = STOP_BITS_1;
    serial1.config.invert = NRZ_NORMAL;
323
    serial1.config.bufsz = RT_SERIAL_RB_BUFSZ;
324 325 326 327 328

    /* register vcom device */
    rt_hw_serial_register(&serial1, "uart1",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                          &uart1);
329 330 331
    rt_hw_interrupt_install(uart1.irq, rt_at91_usart_handler,
                            (void *)&(serial1.parent), "UART1");
    rt_hw_interrupt_umask(uart1.irq);
332 333 334
#endif

#if defined(RT_USING_UART2)
335 336
    serial2.ops = &at91_usart_ops;
    serial2.config.baud_rate = BAUD_RATE_115200;
337 338 339 340 341
    serial2.config.bit_order = BIT_ORDER_LSB;
    serial2.config.data_bits = DATA_BITS_8;
    serial2.config.parity = PARITY_NONE;
    serial2.config.stop_bits = STOP_BITS_1;
    serial2.config.invert = NRZ_NORMAL;
342
    serial2.config.bufsz = RT_SERIAL_RB_BUFSZ;
343 344 345 346 347

    /* register vcom device */
    rt_hw_serial_register(&serial2, "uart2",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                          &uart2);
348 349 350
    rt_hw_interrupt_install(uart2.irq, rt_at91_usart_handler,
                            (void *)&(serial2.parent), "UART2");
    rt_hw_interrupt_umask(uart2.irq);
351 352 353
#endif

#if defined(RT_USING_UART3)
354 355
    serial3.ops = &at91_usart_ops;
    serial3.config.baud_rate = BAUD_RATE_115200;
356 357 358 359 360
    serial3.config.bit_order = BIT_ORDER_LSB;
    serial3.config.data_bits = DATA_BITS_8;
    serial3.config.parity = PARITY_NONE;
    serial3.config.stop_bits = STOP_BITS_1;
    serial3.config.invert = NRZ_NORMAL;
361
    serial3.config.bufsz = RT_SERIAL_RB_BUFSZ;
362 363 364 365 366

    /* register vcom device */
    rt_hw_serial_register(&serial3, "uart3",
                          RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX,
                          &uart3);
367 368 369
    rt_hw_interrupt_install(uart3.irq, rt_at91_usart_handler,
                            (void *)&(serial3.parent), "UART3");
    rt_hw_interrupt_umask(uart3.irq);
370 371
#endif

372
    return 0;
373 374 375 376 377 378 379
}

INIT_BOARD_EXPORT(rt_hw_uart_init);

#ifdef RT_USING_DBGU
void rt_dbgu_isr(void)
{
380
    rt_at91_usart_handler(dbgu.irq, &(serial_dbgu.parent));
381 382 383 384
}
#endif