cpu/sam0: optimizations to the shared UART driver
This commit is contained in:
parent
48ef1cd6c9
commit
68abdff15a
@ -230,7 +230,7 @@ static inline void sercom_clk_en(void *sercom)
|
|||||||
if (sercom_id(sercom) < 5) {
|
if (sercom_id(sercom) < 5) {
|
||||||
MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom_id(sercom));
|
MCLK->APBCMASK.reg |= (MCLK_APBCMASK_SERCOM0 << sercom_id(sercom));
|
||||||
} else {
|
} else {
|
||||||
MCLK->ABPDMASK.reg |= (MCLK_APBCMASK_SERCOM5);
|
MCLK->APBDMASK.reg |= (MCLK_APBDMASK_SERCOM5);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
@ -248,7 +248,7 @@ static inline void sercom_clk_dis(void *sercom)
|
|||||||
if (sercom_id(sercom) < 5) {
|
if (sercom_id(sercom) < 5) {
|
||||||
MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom_id(sercom));
|
MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom_id(sercom));
|
||||||
} else {
|
} else {
|
||||||
MCLK->ABPDMASK.reg &= ~(MCLK_APBCMASK_SERCOM5);
|
MCLK->APBDMASK.reg &= ~(MCLK_APBDMASK_SERCOM5);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,28 +46,11 @@ static uart_isr_ctx_t uart_ctx[UART_NUMOF];
|
|||||||
*
|
*
|
||||||
* @return base register address
|
* @return base register address
|
||||||
*/
|
*/
|
||||||
static inline SercomUsart *_uart(uart_t dev)
|
static inline SercomUsart *dev(uart_t dev)
|
||||||
{
|
{
|
||||||
return uart_config[dev].dev;
|
return uart_config[dev].dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CPU_FAM_SAML21
|
|
||||||
|
|
||||||
static uint64_t _long_division(uint64_t n, uint64_t d);
|
|
||||||
|
|
||||||
static uint8_t sercom_gclk_id[] =
|
|
||||||
{
|
|
||||||
SERCOM0_GCLK_ID_CORE,
|
|
||||||
SERCOM1_GCLK_ID_CORE,
|
|
||||||
SERCOM2_GCLK_ID_CORE,
|
|
||||||
SERCOM3_GCLK_ID_CORE,
|
|
||||||
SERCOM4_GCLK_ID_CORE,
|
|
||||||
SERCOM5_GCLK_ID_CORE
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
||||||
{
|
{
|
||||||
if (uart >= UART_NUMOF) {
|
if (uart >= UART_NUMOF) {
|
||||||
@ -78,74 +61,48 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
|||||||
gpio_init(uart_config[uart].rx_pin, GPIO_IN);
|
gpio_init(uart_config[uart].rx_pin, GPIO_IN);
|
||||||
gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux);
|
gpio_init_mux(uart_config[uart].rx_pin, uart_config[uart].mux);
|
||||||
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
|
gpio_init(uart_config[uart].tx_pin, GPIO_OUT);
|
||||||
|
gpio_set(uart_config[uart].tx_pin);
|
||||||
gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux);
|
gpio_init_mux(uart_config[uart].tx_pin, uart_config[uart].mux);
|
||||||
|
|
||||||
#ifdef CPU_FAM_SAMD21
|
/* enable peripheral clock */
|
||||||
/* calculate baudrate */
|
sercom_clk_en(dev(uart));
|
||||||
uint32_t baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16);
|
|
||||||
/* enable sync and async clocks */
|
|
||||||
uart_poweron(uart);
|
|
||||||
/* reset the UART device */
|
/* reset the UART device */
|
||||||
_uart(uart)->CTRLA.reg = SERCOM_USART_CTRLA_SWRST;
|
dev(uart)->CTRLA.reg = SERCOM_USART_CTRLA_SWRST;
|
||||||
while (_uart(uart)->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST) {}
|
while (dev(uart)->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_SWRST) {}
|
||||||
|
|
||||||
|
/* configure clock generator */
|
||||||
|
sercom_set_gen(dev(uart), uart_config[uart].gclk_src);
|
||||||
|
|
||||||
/* set asynchronous mode w/o parity, LSB first, TX and RX pad as specified
|
/* 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 */
|
* by the board in the periph_conf.h, x16 sampling and use internal clock */
|
||||||
_uart(uart)->CTRLA.reg = (SERCOM_USART_CTRLA_DORD |
|
dev(uart)->CTRLA.reg = (SERCOM_USART_CTRLA_DORD |
|
||||||
SERCOM_USART_CTRLA_SAMPR(0x1) |
|
SERCOM_USART_CTRLA_SAMPR(0x1) |
|
||||||
SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) |
|
SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) |
|
||||||
SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) |
|
SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) |
|
||||||
SERCOM_USART_CTRLA_MODE_USART_INT_CLK |
|
SERCOM_USART_CTRLA_MODE(0x1) |
|
||||||
(uart_config[uart].runstdby ?
|
(uart_config[uart].runstdby ?
|
||||||
SERCOM_USART_CTRLA_RUNSTDBY : 0));
|
SERCOM_USART_CTRLA_RUNSTDBY : 0));
|
||||||
|
|
||||||
/* set baudrate */
|
/* calculate and set baudrate */
|
||||||
_uart(uart)->BAUD.FRAC.FP = (baud % 10);
|
uint32_t baud = ((((uint32_t)CLOCK_CORECLOCK * 10) / baudrate) / 16);
|
||||||
_uart(uart)->BAUD.FRAC.BAUD = (baud / 10);
|
dev(uart)->BAUD.FRAC.FP = (baud % 10);
|
||||||
/* enable receiver and transmitter, use 1 stop bit */
|
dev(uart)->BAUD.FRAC.BAUD = (baud / 10);
|
||||||
_uart(uart)->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN);
|
|
||||||
while (_uart(uart)->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_CTRLB) {}
|
|
||||||
#elif CPU_FAM_SAML21
|
|
||||||
/* Calculate the BAUD value */
|
|
||||||
uint64_t temp1 = ((16 * ((uint64_t)baudrate)) << 32);
|
|
||||||
uint64_t ratio = _long_division(temp1 , CLOCK_CORECLOCK);
|
|
||||||
uint64_t scale = ((uint64_t)1 << 32) - ratio;
|
|
||||||
uint64_t baud_calculated = (65536 * scale) >> 32;
|
|
||||||
|
|
||||||
_uart(uart)->CTRLA.bit.ENABLE = 0; /* Disable to write, need to sync tho */
|
/* enable transmitter, and configure 8N1 mode */
|
||||||
while(_uart(uart)->SYNCBUSY.bit.ENABLE) {}
|
dev(uart)->CTRLB.reg = (SERCOM_USART_CTRLB_TXEN);
|
||||||
|
/* enable receiver and RX interrupt if configured */
|
||||||
/* set to LSB, asynchronous mode without parity, PAD0 Tx, PAD1 Rx,
|
|
||||||
* 16x over-sampling, internal clk */
|
|
||||||
_uart(uart)->CTRLA.reg = SERCOM_USART_CTRLA_DORD \
|
|
||||||
| SERCOM_USART_CTRLA_FORM(0x0) \
|
|
||||||
| SERCOM_USART_CTRLA_SAMPA(0x0) \
|
|
||||||
| SERCOM_USART_CTRLA_TXPO(uart_config[uart].tx_pad) \
|
|
||||||
| SERCOM_USART_CTRLA_RXPO(uart_config[uart].rx_pad) \
|
|
||||||
| SERCOM_USART_CTRLA_SAMPR(0x0) \
|
|
||||||
| SERCOM_USART_CTRLA_MODE(0x1) \
|
|
||||||
| (uart_config[uart].runstdby ?
|
|
||||||
SERCOM_USART_CTRLA_RUNSTDBY : 0);
|
|
||||||
|
|
||||||
/* Set baud rate */
|
|
||||||
_uart(uart)->BAUD.bit.BAUD = baud_calculated;
|
|
||||||
|
|
||||||
/* enable receiver and transmitter, one stop bit*/
|
|
||||||
_uart(uart)->CTRLB.reg = (SERCOM_USART_CTRLB_RXEN | SERCOM_USART_CTRLB_TXEN);
|
|
||||||
while(_uart(uart)->SYNCBUSY.bit.CTRLB) {}
|
|
||||||
uart_poweron(uart);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* finally, enable the device */
|
|
||||||
_uart(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
|
||||||
|
|
||||||
/* register callbacks */
|
|
||||||
if (rx_cb) {
|
if (rx_cb) {
|
||||||
uart_ctx[uart].rx_cb = rx_cb;
|
uart_ctx[uart].rx_cb = rx_cb;
|
||||||
uart_ctx[uart].arg = arg;
|
uart_ctx[uart].arg = arg;
|
||||||
/* configure interrupts and enable RX interrupt */
|
NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(dev(uart)));
|
||||||
NVIC_EnableIRQ(SERCOM0_IRQn + sercom_id(_uart(uart)));
|
dev(uart)->CTRLB.reg |= SERCOM_USART_CTRLB_RXEN;
|
||||||
_uart(uart)->INTENSET.reg |= SERCOM_USART_INTENSET_RXC;
|
dev(uart)->INTENSET.reg |= SERCOM_USART_INTENSET_RXC;
|
||||||
}
|
}
|
||||||
|
while (dev(uart)->SYNCBUSY.reg & SERCOM_USART_SYNCBUSY_CTRLB) {}
|
||||||
|
|
||||||
|
/* and finally enable the device */
|
||||||
|
dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
||||||
|
|
||||||
return UART_OK;
|
return UART_OK;
|
||||||
}
|
}
|
||||||
@ -153,85 +110,36 @@ int uart_init(uart_t uart, uint32_t baudrate, uart_rx_cb_t rx_cb, void *arg)
|
|||||||
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
void uart_write(uart_t uart, const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < len; i++) {
|
for (size_t i = 0; i < len; i++) {
|
||||||
while (!(_uart(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {}
|
while (!(dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_DRE)) {}
|
||||||
_uart(uart)->DATA.reg = data[i];
|
dev(uart)->DATA.reg = data[i];
|
||||||
while (_uart(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {}
|
while (dev(uart)->INTFLAG.reg & SERCOM_USART_INTFLAG_TXC) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart_poweron(uart_t uart)
|
void uart_poweron(uart_t uart)
|
||||||
{
|
{
|
||||||
#ifdef CPU_FAM_SAMD21
|
sercom_clk_en(dev(uart));
|
||||||
PM->APBCMASK.reg |= (PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
|
dev(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
||||||
GCLK->CLKCTRL.reg = (GCLK_CLKCTRL_CLKEN |
|
|
||||||
GCLK_CLKCTRL_GEN(uart_config[uart].gclk_src) |
|
|
||||||
(SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) <<
|
|
||||||
GCLK_CLKCTRL_ID_Pos);
|
|
||||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
|
||||||
#elif CPU_FAM_SAML21
|
|
||||||
/* Enable the peripheral channel */
|
|
||||||
GCLK->PCHCTRL[sercom_gclk_id[sercom_id(_uart(uart))]].reg |=
|
|
||||||
GCLK_PCHCTRL_CHEN | GCLK_PCHCTRL_GEN(uart_config[uart].gclk_src);
|
|
||||||
|
|
||||||
while (!(GCLK->PCHCTRL[sercom_gclk_id[sercom_id(_uart(uart))]].reg &
|
|
||||||
GCLK_PCHCTRL_CHEN)) {}
|
|
||||||
if(sercom_gclk_id[sercom_id(_uart(uart))] < 5) {
|
|
||||||
MCLK->APBCMASK.reg |= MCLK_APBCMASK_SERCOM0 << sercom_id(_uart(uart));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MCLK->APBDMASK.reg |= MCLK_APBDMASK_SERCOM5;
|
|
||||||
}
|
|
||||||
while (_uart(uart)->SYNCBUSY.reg) {}
|
|
||||||
#endif
|
|
||||||
/* finally, enable the device */
|
|
||||||
_uart(uart)->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uart_poweroff(uart_t uart)
|
void uart_poweroff(uart_t uart)
|
||||||
{
|
{
|
||||||
#ifdef CPU_FAM_SAMD21
|
dev(uart)->CTRLA.reg &= ~(SERCOM_USART_CTRLA_ENABLE);
|
||||||
PM->APBCMASK.reg &= ~(PM_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
|
sercom_clk_dis(dev(uart));
|
||||||
GCLK->CLKCTRL.reg = ((SERCOM0_GCLK_ID_CORE + sercom_id(_uart(uart))) <<
|
|
||||||
GCLK_CLKCTRL_ID_Pos);
|
|
||||||
while (GCLK->STATUS.reg & GCLK_STATUS_SYNCBUSY) {}
|
|
||||||
#elif CPU_FAM_SAML21
|
|
||||||
/* Enable the peripheral channel */
|
|
||||||
GCLK->PCHCTRL[sercom_gclk_id[sercom_id(_uart(uart))]].reg &= ~GCLK_PCHCTRL_CHEN;
|
|
||||||
|
|
||||||
if(sercom_gclk_id[sercom_id(_uart(uart))] < 5) {
|
|
||||||
MCLK->APBCMASK.reg &= ~(MCLK_APBCMASK_SERCOM0 << sercom_id(_uart(uart)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
MCLK->APBDMASK.reg &= ~MCLK_APBDMASK_SERCOM5;
|
|
||||||
}
|
|
||||||
while (_uart(uart)->SYNCBUSY.reg) {}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void irq_handler(uint8_t uartnum)
|
static inline void irq_handler(unsigned uartnum)
|
||||||
{
|
{
|
||||||
#ifdef CPU_FAM_SAMD21
|
if (dev(uartnum)->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) {
|
||||||
if (_uart(uartnum)->INTFLAG.reg & SERCOM_USART_INTFLAG_RXC) {
|
|
||||||
/* interrupt flag is cleared by reading the data register */
|
/* interrupt flag is cleared by reading the data register */
|
||||||
uart_ctx[uartnum].rx_cb(uart_ctx[uartnum].arg,
|
uart_ctx[uartnum].rx_cb(uart_ctx[uartnum].arg,
|
||||||
(uint8_t)(_uart(uartnum)->DATA.reg));
|
(uint8_t)(dev(uartnum)->DATA.reg));
|
||||||
}
|
}
|
||||||
else if (_uart(uartnum)->INTFLAG.reg & SERCOM_USART_INTFLAG_ERROR) {
|
else if (dev(uartnum)->INTFLAG.reg & SERCOM_USART_INTFLAG_ERROR) {
|
||||||
/* clear error flag */
|
/* clear error flag */
|
||||||
_uart(uartnum)->INTFLAG.reg = SERCOM_USART_INTFLAG_ERROR;
|
dev(uartnum)->INTFLAG.reg = SERCOM_USART_INTFLAG_ERROR;
|
||||||
}
|
}
|
||||||
#elif CPU_FAM_SAML21
|
|
||||||
if (_uart(uartnum)->INTFLAG.bit.RXC) {
|
|
||||||
/* cleared by reading DATA regiser */
|
|
||||||
uint8_t data = (uint8_t)_uart(uartnum)->DATA.reg;
|
|
||||||
uart_ctx[uartnum].rx_cb(uart_ctx[uartnum].arg, data);
|
|
||||||
}
|
|
||||||
else if (_uart(uartnum)->INTFLAG.bit.ERROR) {
|
|
||||||
/* clear error flag */
|
|
||||||
_uart(uartnum)->INTFLAG.reg |= SERCOM_USART_INTFLAG_ERROR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
cortexm_isr_end();
|
cortexm_isr_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -277,28 +185,4 @@ void UART_5_ISR(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CPU_FAM_SAML21
|
|
||||||
static uint64_t _long_division(uint64_t n, uint64_t d)
|
|
||||||
{
|
|
||||||
int32_t i;
|
|
||||||
uint64_t q = 0, r = 0, bit_shift;
|
|
||||||
for (i = 63; i >= 0; i--) {
|
|
||||||
bit_shift = (uint64_t)1 << i;
|
|
||||||
|
|
||||||
r = r << 1;
|
|
||||||
|
|
||||||
if (n & bit_shift) {
|
|
||||||
r |= 0x01;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (r >= d) {
|
|
||||||
r = r - d;
|
|
||||||
q |= bit_shift;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return q;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* UART_NUMOF */
|
#endif /* UART_NUMOF */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user