thesis_bldc_controller/Examples/NeoPixel Example/Serial.c

200 lines
5.9 KiB
C

#include <asf.h>
#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;
}
}