#include #include "Serial.h" #include "FIFO.h" /* initialize USART on SERCOM2 with TX on pad 2 (pin PA10) and RX on pad 3 (pin PA11) */ void Serial_init(void) { /* initialize FIFO buffers */ FIFO_init(); /* enable peripheral clock */ PM->APBCMASK.bit.SERCOM2_ = 1; /* enable generic clock */ GCLK->CLKCTRL.bit.ID = GCLK_CLKCTRL_ID_SERCOM2_CORE_Val; // configure generic clock for SERCOM2 GCLK->CLKCTRL.bit.GEN = GCLK_CLKCTRL_GEN_GCLK0_Val; // source is generic clock generator 0 GCLK->CLKCTRL.bit.CLKEN = 1; // enable generic clock /* enable GPIO pins alternative function */ PORT->Group[0].PINCFG[10].bit.PMUXEN = 1; // enable alternative function for pins PA10 and PA11 PORT->Group[0].PINCFG[11].bit.PMUXEN = 1; PORT->Group[0].DIRCLR.reg = PORT_PA11; PORT->Group[0].PINCFG[11].bit.INEN = 1; PORT->Group[0].PMUX[5].bit.PMUXE = MUX_PA10D_SERCOM2_PAD2; // PA10 alternative function D (SERCOM2 pad 2) PORT->Group[0].PMUX[5].bit.PMUXO = MUX_PA11D_SERCOM2_PAD3; // PA11 alternative function D (SERCOM2 pad 3) /* configure peripheral */ SERCOM2->USART.CTRLA.bit.MODE = SERCOM_USART_CTRLA_MODE_USART_INT_CLK_Val; // USART internal clock operation SERCOM2->USART.CTRLA.bit.RXPO = 0x03; // RX on pad 3 (pin PA11) SERCOM2->USART.CTRLA.bit.TXPO = 0x01; // TX on pad 2 (pin PA10) SERCOM2->USART.CTRLA.bit.DORD = 1; // LSB first SERCOM2->USART.CTRLA.bit.CMODE = 0x00; // asynchronous communication (UART) SERCOM2->USART.CTRLA.bit.FORM = 0x00; // no parity SERCOM2->USART.CTRLA.bit.SAMPR = 0x00; // 16 bit oversampling with arithmetic baud rate generation SERCOM2->USART.CTRLB.bit.CHSIZE = 0x00; // 8 bit data SERCOM2->USART.CTRLB.bit.SBMODE = 0x00; // one stop bit SERCOM2->USART.BAUD.reg = 63018; // BAUD = 65535 * (1 - num_samples * f_baud/f_clck) SERCOM2->USART.CTRLB.bit.RXEN = 1; // enable receiver SERCOM2->USART.CTRLB.bit.TXEN = 1; // enable transmitter /* enable interrupt */ SERCOM2->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC; // enable Reception Complete interrupt NVIC_EnableIRQ(SERCOM2_IRQn); // enable interrupts in NVIC /* enable peripheral */ SERCOM2->USART.CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE; /* avoid corrupted bytes at start */ delay_ms(100); } /* blocking implementation */ void Serial_transmit(uint8_t data) { while (!TX_FIFO_put(data)) ; /* TX buffer has new data: re enable DRE interrupt */ if (!(SERCOM2->USART.INTENSET.reg & SERCOM_USART_INTENSET_DRE)) SERCOM2->USART.INTENSET.reg = SERCOM_USART_INTENSET_DRE; SERCOM2->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC; } /* blocking implementation */ uint8_t Serial_receive(void) { uint8_t data; while (!RX_FIFO_get(&data)) ; /* RX buffer has space: re enable RXC interrupt */ if (!(SERCOM2->USART.INTENSET.reg & SERCOM_USART_INTENSET_RXC)) SERCOM2->USART.INTENSET.reg = SERCOM_USART_INTENSET_RXC; return data; } int Serial_receive_timeout(uint8_t *data, int timeout) { int count = 0; while (!RX_FIFO_get(data)) { count++; if (count == timeout) return 0; } return 1; } void Serial_write(const char *string) { while (*string) Serial_transmit(*string++); } void Serial_writeln(const char *string) { Serial_write(string); Serial_write("\r\n"); } void Serial_read(char *string, int length) { while (length--) *string++ = Serial_receive(); *string = '\0'; } void Serial_read_string(char *string) { while ((*string++ = Serial_receive()) != '\n') ; *string = '\0'; } int Serial_available(void) { return RX_FIFO_count(); } /* find a string in RX buffer (blocking until found) */ void Serial_find(const char *string) { const char *p = string; char c; while (*p != '\0') if ((c = Serial_receive()) == *p) p++; else if (p != string) { const char *q = p; while (p > string) { p--; if (*p == c) { int diff = q - p; const char *i; for (i = string ; i < p ; i++) if (*i != *(i + diff)) break; // for loop if (i == p) { p++; break; // while loop } } } } } /* find a string in RX buffer (returns 0 if timed out) */ int Serial_find_timeout(const char *string, int timeout) { const char *p = string; char c; while (*p != '\0') { if (!Serial_receive_timeout(&c, timeout)) return 0; else if (c == *p) p++; else if (p != string) { const char *q = p; while (p > string) { p--; if (*p == c) { int diff = q - p; const char *i; for (i = string ; i < p ; i++) if (*i != *(i + diff)) break; // for loop if (i == p) { p++; break; // while loop } } } } } return 1; } void SERCOM2_Handler(void) { /* handle RX interrupt */ if (SERCOM2->USART.INTFLAG.bit.RXC && SERCOM2->USART.INTENSET.bit.RXC) // if RXC interrupt is triggered and enabled if (!RX_FIFO_put(SERCOM2->USART.DATA.reg)) SERCOM2->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_RXC; // if RX buffer is full disable RXC interrupt /* handle TX interrupt */ if (SERCOM2->USART.INTFLAG.bit.DRE && SERCOM2->USART.INTENSET.bit.DRE) // if DRE interrupt is triggered and enabled { uint8_t data; if (!TX_FIFO_get(&data)) SERCOM2->USART.INTENCLR.reg = SERCOM_USART_INTENCLR_DRE; // if TX buffer is empty disable DRE interrupt else SERCOM2->USART.DATA.reg = data; } }