aboutsummaryrefslogtreecommitdiffstats
path: root/src/atsamd/serial.c
blob: f38fb3d8d9236fbcf6f6bda09bb963deae9e5ef9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
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
// samd21 serial port
//
// Copyright (C) 2018-2019  Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU GPLv3 license.

#include "board/serial_irq.h" // serial_rx_data
#include "command.h" // DECL_CONSTANT_STR
#include "internal.h" // enable_pclock
#include "sched.h" // DECL_INIT

void
serial_enable_tx_irq(void)
{
    SERCOM0->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE;
}

void __visible
SERCOM0_Handler(void)
{
    uint32_t status = SERCOM0->USART.INTFLAG.reg;
    if (status & SERCOM_USART_INTFLAG_RXC)
        serial_rx_byte(SERCOM0->USART.DATA.reg);
    if (status & SERCOM_USART_INTFLAG_DRE) {
        uint8_t data;
        int ret = serial_get_tx_byte(&data);
        if (ret)
            SERCOM0->USART.INTENCLR.reg = SERCOM_USART_INTENSET_DRE;
        else
            SERCOM0->USART.DATA.reg = data;
    }
}

// Aliases for irq handler on SAMD51
void SERCOM0_0_Handler(void)
    __visible __attribute__((alias("SERCOM0_Handler")));
void SERCOM0_1_Handler(void)
    __visible __attribute__((alias("SERCOM0_Handler")));
void SERCOM0_2_Handler(void)
    __visible __attribute__((alias("SERCOM0_Handler")));
void SERCOM0_3_Handler(void)
    __visible __attribute__((alias("SERCOM0_Handler")));

DECL_CONSTANT_STR("RESERVE_PINS_serial", "PA11,PA10");

void
serial_init(void)
{
    // Enable serial clock
    enable_pclock(SERCOM0_GCLK_ID_CORE, ID_SERCOM0);
    // Enable pins
    gpio_peripheral(GPIO('A', 11), 'C', 0);
    gpio_peripheral(GPIO('A', 10), 'C', 0);
    // Configure serial
    SercomUsart *su = &SERCOM0->USART;
    su->CTRLA.reg = 0;
    uint32_t areg = (SERCOM_USART_CTRLA_MODE(1)
                     | SERCOM_USART_CTRLA_DORD
                     | SERCOM_USART_CTRLA_SAMPR(1)
                     | SERCOM_USART_CTRLA_RXPO(3)
                     | SERCOM_USART_CTRLA_TXPO(1));
    su->CTRLA.reg = areg;
    su->CTRLB.reg = SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN;
    uint32_t freq = get_pclock_frequency(SERCOM0_GCLK_ID_CORE);
    uint32_t baud8 = freq / (2 * CONFIG_SERIAL_BAUD);
    su->BAUD.reg = (SERCOM_USART_BAUD_FRAC_BAUD(baud8 / 8)
                    | SERCOM_USART_BAUD_FRAC_FP(baud8 % 8));
    // enable irqs
    su->INTENSET.reg = SERCOM_USART_INTENSET_RXC;
    su->CTRLA.reg = areg | SERCOM_USART_CTRLA_ENABLE;
#if CONFIG_MACH_SAMD21
    NVIC_SetPriority(SERCOM0_IRQn, 0);
    NVIC_EnableIRQ(SERCOM0_IRQn);
#elif CONFIG_MACH_SAMD51
    NVIC_SetPriority(SERCOM0_0_IRQn, 0);
    NVIC_SetPriority(SERCOM0_1_IRQn, 0);
    NVIC_SetPriority(SERCOM0_2_IRQn, 0);
    NVIC_SetPriority(SERCOM0_3_IRQn, 0);
    NVIC_EnableIRQ(SERCOM0_0_IRQn);
    NVIC_EnableIRQ(SERCOM0_1_IRQn);
    NVIC_EnableIRQ(SERCOM0_2_IRQn);
    NVIC_EnableIRQ(SERCOM0_3_IRQn);
#endif
}
DECL_INIT(serial_init);