void uart_write(uart_t uart, const uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) { while (!(_uart(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {} _uart(uart)->DATA.reg = data[i]; } }
void uart_poweroff(uart_t uart) { PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart))); GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) << GCLK_CLKCTRL_ID_Pos); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {} }
void uart_write(uart_t dev, const uint8_t *data, size_t len) { for (size_t i = 0; i < len; i++) { while (!(_uart(dev)->STATUS & USART_STATUS_TXBL)); _uart(dev)->TXDATA = data[i]; } }
static inline void rx_irq(int dev) { if (_uart(dev)->IF & USART_IF_RXDATAV) { uint8_t data = (uint8_t)_uart(dev)->RXDATA; isr_ctx[dev].rx_cb(isr_ctx[dev].arg, data); } cortexm_isr_end(); }
void uart_poweron(uart_t uart) { PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << _sercom_id(_uart(uart))); GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | (SERCOM0_GCLK_ID_CORE + _sercom_id(_uart(uart))) << GCLK_CLKCTRL_ID_Pos); while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY); }
static inline void rx_irq(int dev) { if (_uart(dev)->IF & USART_IF_RXDATAV) { uint8_t data = (uint8_t)_uart(dev)->RXDATA; isr_ctx[dev].rx_cb(isr_ctx[dev].arg, data); } if (sched_context_switch_request) { thread_yield(); } }
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { /* initialize basic functionality */ int res = init_base(uart, baudrate); if (res != 0) { return res; } /* register callbacks */ uart_ctx[uart].rx_cb = rx_cb; uart_ctx[uart].arg = arg; /* configure interrupts and enable RX interrupt */ _uart(uart)->INTENSET.reg = SERCOM_USART_INTENSET_RXC; NVIC_EnableIRQ(SERCOM0_IRQn + _sercom_id(_uart(uart))); return 0; }
static inline void irq_handler(int dev) { SercomUsart *uart = _uart(dev); if (uart->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) { /* interrupt flag is cleared by reading the data register */ uart_ctx[dev].rx_cb(uart_ctx[dev].arg, (uint8_t)(uart->DATA.reg)); } else if (uart->INTFLAG.reg & SERCOM_USART_INTFLAG_ERROR) { /* clear error flag */ uart->INTFLAG.reg = SERCOM_USART_INTFLAG_ERROR; } cortexm_isr_end(); }
static inline void irq_handler(int dev) { SercomUsart *uart = _uart(dev); if (uart->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) { /* interrupt flag is cleared by reading the data register */ uart_ctx[dev].rx_cb(uart_ctx[dev].arg, (uint8_t)(uart->DATA.reg)); } else if (uart->INTFLAG.reg & SERCOM_USART_INTFLAG_ERROR) { /* clear error flag */ uart->INTFLAG.reg = SERCOM_USART_INTFLAG_ERROR; } if (sched_context_switch_request) { thread_yield(); } }
int uart_init(uart_t dev, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg) { USART_TypeDef *uart; /* check if device is valid and get base register address */ if (dev >= UART_NUMOF) { return UART_NODEV; } uart = _uart(dev); /* save interrupt callback context */ isr_ctx[dev].rx_cb = rx_cb; isr_ctx[dev].arg = arg; /* power on the device */ uart_poweron(dev); /* put device in asynchronous mode @ 16x oversampling (default UART) */ uart->CTRL = 0; /* configure to default 8N1 configuration */ uart->FRAME = (USART_FRAME_STOPBITS_ONE | USART_FRAME_DATABITS_EIGHT); /* configure the baudrate - this looks more complicated than it is, we just * multiply the HFPERCLK with 32 to cut down on rounding error when doing * the division afterwards... */ uart->CLKDIV = (((CLOCK_HFPERCLK << 5) / (16 * baudrate) - 32) << 3); /* configure the pins */ gpio_init(uart_config[dev].tx_pin, GPIO_OUT); if (rx_cb) { gpio_init(uart_config[dev].rx_pin, GPIO_IN); uart->ROUTE = ((uart_config[dev].loc << _USART_ROUTE_LOCATION_SHIFT) | USART_ROUTE_RXPEN | USART_ROUTE_TXPEN); } else { uart->ROUTE = ((uart_config[dev].loc << _USART_ROUTE_LOCATION_SHIFT) | USART_ROUTE_TXPEN); } if (rx_cb) { /* enable RX interrupt */ NVIC_EnableIRQ(uart_config[dev].irq); NVIC_EnableIRQ(uart_config[dev].irq + 1); uart->IEN |= USART_IEN_RXDATAV; /* enable receiver and transmitter */ uart->CMD = USART_CMD_TXEN | USART_CMD_RXEN; } else { uart->CMD = USART_CMD_TXEN; } return UART_OK; }
static int init_base(uart_t uart, uint32_t baudrate) { uint32_t baud; SercomUsart *dev; if ((unsigned int)uart >= UART_NUMOF) { return -1; } /* get the devices base register */ dev = _uart(uart); /* calculate baudrate */ baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16); /* enable sync and async clocks */ uart_poweron(uart); /* configure pins */ gpio_init(uart_config[uart].rx_pin, GPIO_IN); gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux); gpio_init(uart_config[uart].tx_pin, GPIO_OUT); gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); /* reset the UART device */ dev->CTRLA.reg = SERCOM_USART_CTRLA_SWRST; while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST) {} /* set asynchronous mode w/o parity, LSB first, TX and RX pad as specified * by the board in the periph_conf.h, x16 sampling and use internal clock */ dev->CTRLA.reg = (SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_SAMPR(0x1) | SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) | SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) | SERCOM_USART_CTRLA_MODE_USART_INT_CLK); /* set baudrate */ dev->BAUD.FRAC.FP = (baud % 10); dev->BAUD.FRAC.BAUD = (baud / 10); /* enable receiver and transmitter, use 1 stop bit */ dev->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN); while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_CTRLB) {} /* finally, enable the device */ dev->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; return 0; }
int uart_init_blocking(uart_t uart, uint32_t baudrate) { uint32_t baud; SercomUsart *dev; if (uart < 0 || uart >= UART_NUMOF) { return -1; } /* get the devices base register */ dev = _uart(uart); /* calculate baudrate */ baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16); /* enable sync and async clocks */ uart_poweron(uart); /* configure pins */ gpio_init(uart_config[uart].rx_pin, GPIO_DIR_IN, GPIO_NOPULL); gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux); gpio_init(uart_config[uart].tx_pin, GPIO_DIR_OUT, GPIO_NOPULL); gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux); /* reset the UART device */ dev->CTRLA.reg = SERCOM_USART_CTRLA_SWRST; while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST); /* set asynchronous mode w/o parity, LSB first, PAD0 to TX, PAD1 to RX and * use internal clock */ dev->CTRLA.reg = (SERCOM_USART_CTRLA_DORD | SERCOM_USART_CTRLA_RXPO(0x1) | SERCOM_USART_CTRLA_SAMPR(0x1) | SERCOM_USART_CTRLA_MODE_USART_INT_CLK); /* set baudrate */ dev->BAUD.FRAC.FP = (baud % 10); dev->BAUD.FRAC.BAUD = (baud / 10); /* enable receiver and transmitter, use 1 stop bit */ dev->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN); while (dev->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_CTRLB); /* finally, enable the device */ dev->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; return 0; }
int uart_write_blocking(uart_t uart, char data) { while (!(_uart(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)); _uart(uart)->DATA.reg = (uint8_t)data; return 1; }
int uart_write(uart_t uart, char data) { _uart(uart)->DATA.reg = (uint8_t)data; return 1; }
int uart_read_blocking(uart_t uart, char *data) { while(!(_uart(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC)); *data = (char)_uart(uart)->DATA.reg; return 1; }
void uart_tx_begin(uart_t uart) { _uart(uart)->INTENSET.reg = SERCOM_USART_INTENSET_TXC; }