* updated with integrated pin mux code for serial.

* serial asynch updated with review comments.
* removed sercom pin mux implementation in PeripheralPins.c
pull/1243/head
akhilpanayam 2015-07-07 20:09:43 +05:30 committed by Karthik Purushothaman
parent 17333d6c85
commit 57dc24edf8
5 changed files with 174 additions and 616 deletions

View File

@ -20,8 +20,6 @@
#include "pinmap.h"
#include "PeripheralNames.h"
void find_pin_settings (PinName output, PinName input, PinName clock, PinName chipsel, uint32_t* pad_pinmuxes); // clock also for RTS and chipsel for CTS
uint32_t find_mux_setting (PinName output, PinName input, PinName clock, PinName chipsel);
/************RTC***************/
//extern const PinMap PinMap_RTC[];

View File

@ -195,447 +195,5 @@ const PinMap PinMap_EXTINT[] = {
{PB31, EXTINT_15, 0}
};
/********SERCOM MAPPING*********/
struct pin_sercom {
uint8_t pad_num; // a pin always mapped to a pad
uint8_t com_num[2]; // a pin always mapped to maximum of 2 sercoms
// uint8_t pin_mux[2]; // Mux setting for the pin A,B...H ---> 0,1...7
};
struct pin_values {
uint8_t pin;
uint8_t pad;
uint8_t com;
};
struct pin_sercom SAM21[] = {{0, {1, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA00
{1, {1, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA01
{0, {0, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA04
{1, {0, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA05
{2, {0, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA06
{3, {0, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA07
{0, {0, 2}/*, {2, 3}*/}, // PA08
{1, {0, 2}/*, {2, 3}*/}, // PA09
{0, {2, SERCOM_NULL}/*, {2, MUX_NULL}*/}, // PA12
{1, {2, SERCOM_NULL}/*, {2, MUX_NULL}*/}, // PA13
{2, {2, SERCOM_NULL}/*, {2, MUX_NULL}*/}, // PA14
{3, {2, SERCOM_NULL}/*, {2, MUX_NULL}*/}, // PA15
{0, {1, 3}/*, {2, 3}*/}, // PA16
{1, {1, 3}/*, {2, 3}*/}, // PA17
{2, {1, 3}/*, {2, 3}*/}, // PA18
{3, {1, 3}/*, {2, 3}*/}, // PA19
{0, {3, 5}/*, {2, 3}*/}, // PA22
{1, {3, 5}/*, {2, 3}*/}, // PA23
{2, {3, 5}/*, {2, 3}*/}, // PA24
{3, {3, 5}/*, {2, 3}*/}, // PA25
{0, {3, SERCOM_NULL}/*, {5, MUX_NULL}*/}, // PA27
{1, {3, SERCOM_NULL}/*, {5, MUX_NULL}*/}, // PA28
{2, {1, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA30
{3, {1, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PA31
{0, {5, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PB02
{1, {5, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PB03
{2, {5, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PB22
{3, {5, SERCOM_NULL}/*, {3, MUX_NULL}*/}, // PB23
{2, {4, SERCOM_NULL}/*, {5, MUX_NULL}*/}, // PB30
{1, {4, SERCOM_NULL}/*, {5, MUX_NULL}*/}, // PB31
{3, {4, SERCOM_NULL}/*, {5, MUX_NULL}*/}, // PC18
{0, {4, SERCOM_NULL}/*, {5, MUX_NULL}*/} // PC19
};
const PinMap PinMap_SERCOM_PINS[] = {
{PA00},
{PA01},
{PA04},
{PA05},
{PA06},
{PA07},
{PA08},
{PA09},
{PA12},
{PA13},
{PA14},
{PA15},
{PA16},
{PA17},
{PA18},
{PA19},
{PA22},
{PA23},
{PA24},
{PA25},
{PA27},
{PA28},
{PA30},
{PA31},
{PB02},
{PB03},
{PB22},
{PB23},
{PB30},
{PB31},
{PC18},
{PC19}
};
uint32_t pinmap_find_sercom_index (PinName pin, const PinMap* map)
{
uint8_t count = 0;
while (map->pin != NC) {
if (map->pin == pin)
return count;
map++;
count++;
}
return (uint32_t)NC;
}
uint32_t pinmap_sercom_peripheral (PinName pin1, PinName pin2)
{
uint8_t index1 = 0, index2 = 0;
if ((pin1 == (PinName)NC) || (pin2 == (PinName)NC)) {
return (uint32_t)NC;
}
index1 = pinmap_find_sercom_index(pin1, PinMap_SERCOM_PINS);
index2 = pinmap_find_sercom_index(pin2, PinMap_SERCOM_PINS);
if (SAM21[index1].com_num[1] == SERCOM_NULL) {
return SAM21[index1].com_num[0];
} else {
if ((SAM21[index1].com_num[0] == SAM21[index2].com_num[0]) || (SAM21[index1].com_num[0] == SAM21[index2].com_num[1])) {
return SAM21[index1].com_num[0];
} else {
return SAM21[index1].com_num[1];
}
}
}
uint32_t pinmap_sercom_pad (PinName pin)
{
uint8_t index = 0;
if (pin == (PinName)NC)
return (uint32_t)NC;
index = pinmap_find_sercom_index(pin, PinMap_SERCOM_PINS);
return SAM21[index].pad_num;
}
uint32_t find_sercom_pinmux (struct pin_values* PinValues)
{
switch (PinValues->com) {
case 0: // SERCOM0
switch (PinValues->pin) {
case PA04:
return PINMUX_PA04D_SERCOM0_PAD0;
break;
case PA08:
return PINMUX_PA08C_SERCOM0_PAD0;
break;
case PA05:
return PINMUX_PA05D_SERCOM0_PAD1;
break;
case PA09:
return PINMUX_PA09C_SERCOM0_PAD1;
break;
case PA06:
return PINMUX_PA06D_SERCOM0_PAD2;
break;
case PA10:
return PINMUX_PA10C_SERCOM0_PAD2;
break;
case PA07:
return PINMUX_PA07D_SERCOM0_PAD3;
break;
case PA11:
return PINMUX_PA11C_SERCOM0_PAD3;
break;
default:
break;
}
break;
case 1: // SERCOM1
switch (PinValues->pin) {
case PA16:
return PINMUX_PA16C_SERCOM1_PAD0;
break;
case PA00:
return PINMUX_PA00D_SERCOM1_PAD0;
break;
case PA17:
return PINMUX_PA17C_SERCOM1_PAD1;
break;
case PA01:
return PINMUX_PA01D_SERCOM1_PAD1;
break;
case PA30:
return PINMUX_PA30D_SERCOM1_PAD2;
break;
case PA18:
return PINMUX_PA18C_SERCOM1_PAD2;
break;
case PA31:
return PINMUX_PA31D_SERCOM1_PAD3;
break;
case PA19:
return PINMUX_PA19C_SERCOM1_PAD3;
break;
default:
break;
}
break;
case 2: // SERCOM2
switch (PinValues->pin) {
case PA08:
return PINMUX_PA08D_SERCOM2_PAD0;
break;
case PA12:
return PINMUX_PA12C_SERCOM2_PAD0;
break;
case PA09:
return PINMUX_PA09D_SERCOM2_PAD1;
break;
case PA13:
return PINMUX_PA13C_SERCOM2_PAD1;
break;
case PA10:
return PINMUX_PA10D_SERCOM2_PAD2;
break;
case PA14:
return PINMUX_PA14C_SERCOM2_PAD2;
break;
case PA11:
return PINMUX_PA11D_SERCOM2_PAD3;
break;
case PA15:
return PINMUX_PA15C_SERCOM2_PAD3;
break;
default:
break;
}
break;
case 3: // SERCOM3
switch (PinValues->pin) {
case PA16:
return PINMUX_PA16D_SERCOM3_PAD0;
break;
case PA22:
return PINMUX_PA22C_SERCOM3_PAD0;
break;
case PA27:
return PINMUX_PA27F_SERCOM3_PAD0;
break;
case PA17:
return PINMUX_PA17D_SERCOM3_PAD1;
break;
case PA23:
return PINMUX_PA23C_SERCOM3_PAD1;
break;
case PA28:
return PINMUX_PA28F_SERCOM3_PAD1;
break;
case PA18:
return PINMUX_PA18D_SERCOM3_PAD2;
break;
case PA20:
return PINMUX_PA20D_SERCOM3_PAD2;
break;
case PA24:
return PINMUX_PA24C_SERCOM3_PAD2;
break;
case PA19:
return PINMUX_PA19D_SERCOM3_PAD3;
break;
case PA25:
return PINMUX_PA25C_SERCOM3_PAD3;
break;
default:
break;
}
break;
case 4: // SERCOM4
switch (PinValues->pin) {
case PA12:
return PINMUX_PA12D_SERCOM4_PAD0;
break;
case PB08:
return PINMUX_PB08D_SERCOM4_PAD0;
break;
case PC19:
return PINMUX_PC19F_SERCOM4_PAD0;
break;
case PA13:
return PINMUX_PA13D_SERCOM4_PAD1;
break;
case PB09:
return PINMUX_PB09D_SERCOM4_PAD1;
break;
case PB31:
return PINMUX_PB31F_SERCOM4_PAD1;
break;
case PA14:
return PINMUX_PA14D_SERCOM4_PAD2;
break;
case PB14:
return PINMUX_PB14C_SERCOM4_PAD2;
break;
case PB30:
return PINMUX_PB30F_SERCOM4_PAD2;
break;
case PA15:
return PINMUX_PA15D_SERCOM4_PAD3;
break;
case PB15:
return PINMUX_PB15C_SERCOM4_PAD3;
break;
case PC18:
return PINMUX_PC18F_SERCOM4_PAD3;
break;
default:
break;
}
break;
case 5: // SERCOM5
switch (PinValues->pin) {
case PB16:
return PINMUX_PB16C_SERCOM5_PAD0;
break;
case PA22:
return PINMUX_PA22D_SERCOM5_PAD0;
break;
case PB02:
return PINMUX_PB02D_SERCOM5_PAD0;
break;
case PB30:
return PINMUX_PB30D_SERCOM5_PAD0;
break;
case PB17:
return PINMUX_PB17C_SERCOM5_PAD1;
break;
case PA23:
return PINMUX_PA23D_SERCOM5_PAD1;
break;
case PB03:
return PINMUX_PB03D_SERCOM5_PAD1;
break;
case PB31:
return PINMUX_PB31D_SERCOM5_PAD1;
break;
case PA24:
return PINMUX_PA24D_SERCOM5_PAD2;
break;
case PB00:
return PINMUX_PB00D_SERCOM5_PAD2;
break;
case PB22:
return PINMUX_PB22D_SERCOM5_PAD2;
break;
case PA20:
return PINMUX_PA20C_SERCOM5_PAD2;
break;
case PA25:
return PINMUX_PA25D_SERCOM5_PAD3;
break;
case PB23:
return PINMUX_PB23D_SERCOM5_PAD3;
break;
default:
break;
}
break;
}
return NC;
}
uint32_t find_mux_setting (PinName output, PinName input, PinName clock, PinName chipsel)
{
struct pin_values input_values, output_values, clock_values, chipsel_values;
uint32_t mux_setting = 0;
input_values.pin = input;
output_values.pin = output;
clock_values.pin = clock;
chipsel_values.pin = chipsel;
input_values.com = pinmap_sercom_peripheral(input, output);
output_values.com = input_values.com;
clock_values.com = input_values.com;
chipsel_values.com = input_values.com;
input_values.pad = pinmap_sercom_pad(input);
output_values.pad = pinmap_sercom_pad(output);
clock_values.pad = pinmap_sercom_pad(clock);
chipsel_values.pad = pinmap_sercom_pad(chipsel);
switch(input_values.pad) { //TODO: Condition for hardware flow control enabled is different.
case 0:
mux_setting |= SERCOM_USART_CTRLA_RXPO(0);
break;
case 1:
mux_setting |= SERCOM_USART_CTRLA_RXPO(1);
break;
case 2:
mux_setting |= SERCOM_USART_CTRLA_RXPO(2);
break;
case 3:
mux_setting |= SERCOM_USART_CTRLA_RXPO(3);
break;
}
if ((clock == NC) && (chipsel == NC)) { // condition for no hardware control and uart
if ((output_values.pad == 0)) { // condition for hardware enable and usart is different
mux_setting |= SERCOM_USART_CTRLA_TXPO(0);
} else if((output_values.pad == 2)) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(1);
} else {
mux_setting = mux_setting; // dummy condition
}
} else { // for hardware flow control and uart // expecting the tx in pad 0, rts in pad2 and cts in pad 3
if((output_values.pad == 0) && (clock_values.pad/*rts pin*/ == 2) && (chipsel_values.pad/*cts pin*/ == 3)) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(2);
}
}
return mux_setting;
}
void find_pin_settings (PinName output, PinName input, PinName clock, PinName chipsel, uint32_t* pad_pinmuxes)
{
struct pin_values input_values, output_values, clock_values, chipsel_values;
uint8_t i = 0;
for (i = 0; i < 4 ; i++ ) { // load default values for the pins
pad_pinmuxes[i] = 0xFFFFFFFF; //PINMUX_UNUSED
}
input_values.pin = input;
output_values.pin = output;
clock_values.pin = clock;
chipsel_values.pin = chipsel;
input_values.com = pinmap_sercom_peripheral(input, output);
output_values.com = input_values.com;
clock_values.com = input_values.com;
chipsel_values.com = input_values.com;
input_values.pad = pinmap_sercom_pad(input);
output_values.pad = pinmap_sercom_pad(output);
clock_values.pad = pinmap_sercom_pad(clock);
chipsel_values.pad = pinmap_sercom_pad(chipsel);
if (input_values.pad < 0x04)
pad_pinmuxes[input_values.pad] = find_sercom_pinmux(&input_values);
if (output_values.pad < 0x04)
pad_pinmuxes[output_values.pad] = find_sercom_pinmux(&output_values);
if (clock_values.pad < 0x04)
pad_pinmuxes[clock_values.pad] = find_sercom_pinmux(&clock_values);
if (chipsel_values.pad < 0x04)
pad_pinmuxes[chipsel_values.pad] = find_sercom_pinmux(&chipsel_values);
}

View File

@ -40,6 +40,7 @@ struct port_s {
__IO uint32_t *OUTCLR;
__IO uint32_t *OUTSET;
__I uint32_t *IN;
__I uint32_t *OUT;
PortName port;
uint32_t mask;
@ -53,12 +54,7 @@ struct serial_s {
uint32_t character_size;
uint32_t mux_setting;
uint32_t baudrate;
uint32_t pinmux_pad0;
uint32_t pinmux_pad1;
uint32_t pinmux_pad2;
uint32_t pinmux_pad3;
PinName rxpin;
PinName txpin;
PinName pins[4];
#if DEVICE_SERIAL_ASYNCH
uint32_t events;
#endif

View File

@ -23,6 +23,21 @@
#include "pinmap_function.h"
static uint32_t pinmap_merge_pins(uint32_t a, uint32_t b)
{
// both are the same (inc both NC)
if (a == b)
return a;
// one (or both) is not connected
if (a == (uint32_t)NC)
return b;
if (b == (uint32_t)NC)
return a;
return (uint32_t)NC;
}
/** Find the common SERCOM shared by two pins
*
* Finds the common SERCOM index of two input pins.
@ -63,7 +78,7 @@ uint32_t pinmap_merge_sercom(PinName pin1, PinName pin2)
if (pin2_sercom[i] != NC) {
pin2_sercom[i] &= 0x0F;
}
sercom_index[(i*2) + j] = pinmap_merge(pin1_sercom[i], pin2_sercom[j]);
sercom_index[(i*2) + j] = pinmap_merge_pins(pin1_sercom[i], pin2_sercom[j]);
}
}

View File

@ -20,6 +20,12 @@
#include "pinmap.h"
#include "PeripheralPins.h"
#include "usart.h"
#include "pinmap_function.h"
#define USART_TX_INDEX 0
#define USART_RX_INDEX 1
#define USART_RXFLOW_INDEX 2
#define USART_TXFLOW_INDEX 3
#if DEVICE_SERIAL_ASYNCH
#define pUSART_S(obj) obj->serial.usart
@ -34,6 +40,7 @@
uint8_t serial_get_index(serial_t *obj);
IRQn_Type get_serial_irq_num (serial_t *obj);
uint32_t get_serial_vector (serial_t *obj);
static uint32_t serial_irq_ids[USART_NUM] = {0};
static uart_irq_handler irq_handler;
@ -89,6 +96,48 @@ static inline void reset_usart(serial_t *obj)
_USART(obj).CTRLA.reg = SERCOM_USART_CTRLA_SWRST;
}
uint32_t serial_find_mux_settings (serial_t *obj)
{
uint32_t mux_setting = 0;
uint32_t pinpad[4] = {0};
uint8_t i = 0;
uint32_t sercom_index = pinmap_merge_sercom(pSERIAL_S(obj)->pins[0], pSERIAL_S(obj)->pins[1]);
for (i = 0; i < 4 ; i++) {
pinpad[i] = pinmap_pad_sercom(pSERIAL_S(obj)->pins[i], sercom_index);
}
switch(pinpad[USART_RX_INDEX]) {
case 0:
mux_setting |= SERCOM_USART_CTRLA_RXPO(0);
break;
case 1:
mux_setting |= SERCOM_USART_CTRLA_RXPO(1);
break;
case 2:
mux_setting |= SERCOM_USART_CTRLA_RXPO(2);
break;
case 3:
mux_setting |= SERCOM_USART_CTRLA_RXPO(3);
break;
}
if ((pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] == NC) && (pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] == NC)) {
if (pinpad[USART_TX_INDEX] == 0) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(0);
} else if(pinpad[USART_RX_INDEX] == 2) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(1);
} else {
mux_setting = mux_setting; // dummy condition
}
} else { // for hardware flow control and uart // expecting the tx in pad 0, rts in pad2 and cts in pad 3
if((pinpad[USART_TX_INDEX] == 0) && (pinpad[USART_RXFLOW_INDEX]/*rts pin*/ == 2) && (pinpad[USART_TXFLOW_INDEX] /*cts pin*/ == 3)) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(2);
}
}
return mux_setting;
}
static enum status_code usart_set_config_default( serial_t *obj)
{
@ -160,10 +209,6 @@ void get_default_serial_values(serial_t *obj)
pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_8BIT;
pSERIAL_S(obj)->baudrate = 9600;
pSERIAL_S(obj)->mux_setting = USART_RX_1_TX_2_XCK_3;
pSERIAL_S(obj)->pinmux_pad0 = PINMUX_DEFAULT;
pSERIAL_S(obj)->pinmux_pad1 = PINMUX_DEFAULT;
pSERIAL_S(obj)->pinmux_pad2 = PINMUX_DEFAULT;
pSERIAL_S(obj)->pinmux_pad3 = PINMUX_DEFAULT;
};
void serial_init(serial_t *obj, PinName tx, PinName rx)
@ -172,67 +217,42 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
system_init();
g_sys_init = 1;
}
struct system_gclk_chan_config gclk_chan_conf;
UARTName uart;
uint32_t gclk_index;
uint32_t pm_index;
uint32_t sercom_index = 0;
uint32_t muxsetting = 0;
uint32_t padsetting[4] = {0};
/* Disable USART module */
disable_usart(obj);
get_default_serial_values(obj);
find_pin_settings(tx, rx, NC, NC, &padsetting[0]); // tx, rx, clk(rts), chipsel(cts) pad array // getting pads from pins
muxsetting = find_mux_setting(tx, rx, NC, NC); // getting mux setting from pins
sercom_index = pinmap_sercom_peripheral(tx, rx); // same variable sercom_index reused for optimization
switch (sercom_index) {
case 0:
uart = UART_0;
pUSART_S(obj) = SERCOM0;
break;
case 1:
uart = UART_1;
pUSART_S(obj) = SERCOM1;
break;
case 2:
uart = UART_2;
pUSART_S(obj) = SERCOM2;
break;
case 3:
uart = UART_3;
pUSART_S(obj) = SERCOM3;
break;
case 4:
uart = UART_4;
pUSART_S(obj) = SERCOM4;
break;
case 5:
uart = UART_5;
pUSART_S(obj) = SERCOM5;
break;
}
pSERIAL_S(obj)->pins[USART_TX_INDEX] = tx;
pSERIAL_S(obj)->pins[USART_RX_INDEX] = rx;
pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] = NC;
pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] = NC;
pSERIAL_S(obj)->txpin = tx;
pSERIAL_S(obj)->rxpin = rx;
pSERIAL_S(obj)->mux_setting = muxsetting;//EDBG_CDC_SERCOM_MUX_SETTING;
pSERIAL_S(obj)->pinmux_pad0 = padsetting[0];//EDBG_CDC_SERCOM_PINMUX_PAD0;
pSERIAL_S(obj)->pinmux_pad1 = padsetting[1];//EDBG_CDC_SERCOM_PINMUX_PAD1;
pSERIAL_S(obj)->pinmux_pad2 = padsetting[2];//EDBG_CDC_SERCOM_PINMUX_PAD2;
pSERIAL_S(obj)->pinmux_pad3 = padsetting[3];//EDBG_CDC_SERCOM_PINMUX_PAD3;
muxsetting = serial_find_mux_settings(obj); // getting mux setting from pins
sercom_index = pinmap_merge_sercom(tx, rx); // same variable sercom_index reused for optimization
if (sercom_index == NC) {
/*expecting a valid value for sercom index*/
return;
}
sercom_index &= 0x0F;
uart = pinmap_peripheral_sercom(NC, sercom_index);
pUSART_S(obj) = (Sercom *)uart;
pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
/* The module is busy resetting itself */
return; /* The module is busy resetting itself */
}
if (_USART(obj).CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
/* Check the module is enabled */
return; /* Check the module is enabled */
}
/* Turn on module in PM */
@ -244,29 +264,24 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
system_gclk_chan_enable(gclk_index);
sercom_set_gclk_generator(GCLK_GENERATOR_0, false);
pSERIAL_S(obj)->mux_setting = muxsetting;
/* Set configuration according to the config struct */
usart_set_config_default(obj);
struct system_pinmux_config pin_conf;
system_pinmux_get_config_defaults(&pin_conf);
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
pin_conf.powersave = false;
uint32_t pad_pinmuxes[] = {
pSERIAL_S(obj)->pinmux_pad0, pSERIAL_S(obj)->pinmux_pad1,
pSERIAL_S(obj)->pinmux_pad2, pSERIAL_S(obj)->pinmux_pad3
};
uint32_t mux_func;
/* Configure the SERCOM pins according to the user configuration */
for (uint8_t pad = 0; pad < 4; pad++) {
uint32_t current_pinmux = pad_pinmuxes[pad];
if (current_pinmux == PINMUX_DEFAULT) {
current_pinmux = _sercom_get_default_pad(pUSART_S(obj), pad);
}
if (current_pinmux != PINMUX_UNUSED) {
pin_conf.mux_position = current_pinmux & 0xFFFF;
system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
uint32_t current_pin = pSERIAL_S(obj)->pins[pad];
if (current_pin != NC) {
pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
if (NC != pin_conf.mux_position) {
system_pinmux_pin_set_config(current_pin, &pin_conf);
}
}
}
@ -274,13 +289,11 @@ void serial_init(serial_t *obj, PinName tx, PinName rx)
stdio_uart_inited = 1;
memcpy(&stdio_uart, obj, sizeof(serial_t));
}
/* Wait until synchronization is complete */
usart_syncing(obj);
/* Enable USART module */
enable_usart(obj);
}
void serial_free(serial_t *obj)
@ -428,87 +441,65 @@ void serial_set_flow_control(serial_t *obj, FlowControl type, PinName rxflow, Pi
{
uint32_t muxsetting = 0;
uint32_t sercom_index = 0;
uint32_t padsetting[4] = {0};
uint32_t mux_func;
IRQn_Type irq_n = (IRQn_Type)0;
uint32_t vector = 0;
switch ((int)pUSART_S(obj)) {
case UART_0:
vector = (uint32_t)uart0_irq;
break;
case UART_1:
vector = (uint32_t)uart1_irq;
break;
case UART_2:
vector = (uint32_t)uart2_irq;
break;
case UART_3:
vector = (uint32_t)uart3_irq;
break;
case UART_4:
vector = (uint32_t)uart4_irq;
break;
case UART_5:
vector = (uint32_t)uart5_irq;
break;
pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] = rxflow;
pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] = txflow;
muxsetting = serial_find_mux_settings(obj); // getting mux setting from pins
sercom_index = pinmap_merge_sercom(pSERIAL_S(obj)->pins[USART_TX_INDEX], pSERIAL_S(obj)->pins[USART_RX_INDEX]); // same variable sercom_index reused for optimization
if (sercom_index == NC) {
/*expecting a valid value for sercom index*/
return;
}
vector = get_serial_vector(obj);
irq_n = get_serial_irq_num(obj);
disable_usart(obj);
//TODO : assert for rxflow and txflow pis to be added
find_pin_settings(pSERIAL_S(obj)->txpin, pSERIAL_S(obj)->rxpin, rxflow, txflow, &padsetting[0]); // tx, rx, clk(rts), chipsel(cts) pad array // getting pads from pins
muxsetting = find_mux_setting(pSERIAL_S(obj)->txpin, pSERIAL_S(obj)->rxpin, rxflow, txflow); // getting mux setting from pins
pSERIAL_S(obj)->mux_setting = muxsetting;//EDBG_CDC_SERCOM_MUX_SETTING;
pSERIAL_S(obj)->pinmux_pad0 = padsetting[0];//EDBG_CDC_SERCOM_PINMUX_PAD0;
pSERIAL_S(obj)->pinmux_pad1 = padsetting[1];//EDBG_CDC_SERCOM_PINMUX_PAD1;
pSERIAL_S(obj)->pinmux_pad2 = padsetting[2];//EDBG_CDC_SERCOM_PINMUX_PAD2;
pSERIAL_S(obj)->pinmux_pad3 = padsetting[3];//EDBG_CDC_SERCOM_PINMUX_PAD3;
/* Set configuration according to the config struct */
pSERIAL_S(obj)->mux_setting = muxsetting; // mux setting to be changed for configuring hardware control
usart_set_config_default(obj);
struct system_pinmux_config pin_conf;
system_pinmux_get_config_defaults(&pin_conf);
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT;
pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
pin_conf.powersave = false;
uint32_t pad_pinmuxes[] = {
pSERIAL_S(obj)->pinmux_pad0, pSERIAL_S(obj)->pinmux_pad1,
pSERIAL_S(obj)->pinmux_pad2, pSERIAL_S(obj)->pinmux_pad3
};
/* Configure the SERCOM pins according to the user configuration */
for (uint8_t pad = 0; pad < 3; pad++) {
uint32_t current_pinmux = pad_pinmuxes[pad];
if (current_pinmux == PINMUX_DEFAULT) {
current_pinmux = _sercom_get_default_pad(pUSART_S(obj), pad);
}
if (current_pinmux != PINMUX_UNUSED) {
pin_conf.mux_position = current_pinmux & 0xFFFF;
system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
for (uint8_t pad = 0; pad < 2; pad++) { // setting for rx and tx
uint32_t current_pin = pSERIAL_S(obj)->pins[pad];
if (current_pin != NC) {
pin_conf.mux_position = pinmap_function_sercom(current_pin, sercom_index);
if (NC != pin_conf.mux_position) {
system_pinmux_pin_set_config(current_pin, &pin_conf);
}
}
}
if (pSERIAL_S(obj)->pinmux_pad3 != PINMUX_UNUSED) {
pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP;
pin_conf.mux_position = pSERIAL_S(obj)->pinmux_pad3 & 0xFFFF;
system_pinmux_pin_set_config(pSERIAL_S(obj)->pinmux_pad3 >> 16, &pin_conf);
if((FlowControlRTS == type) || (FlowControlRTSCTS== type)) {
if (pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] != NC) {
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; // setting for rxflow
pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP;
pin_conf.mux_position = pinmap_function_sercom(pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX] , sercom_index);
system_pinmux_pin_set_config(pSERIAL_S(obj)->pins[USART_RXFLOW_INDEX], &pin_conf);
}
}
if((FlowControlCTS == type) || (FlowControlRTSCTS== type)) {
if (pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] != NC) {
pin_conf.direction = SYSTEM_PINMUX_PIN_DIR_INPUT; // setting for txflow
pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_UP;
pin_conf.mux_position = pinmap_function_sercom(pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX] , sercom_index);
system_pinmux_pin_set_config(pSERIAL_S(obj)->pins[USART_TXFLOW_INDEX], &pin_conf);
}
}
NVIC_SetVector(irq_n, vector);
NVIC_EnableIRQ(irq_n);
enable_usart(obj);
_USART(obj).INTENSET.reg = SERCOM_USART_INTENCLR_CTSIC;
}
void serial_break_set(serial_t *obj)
{
disable_usart(obj);
_USART(obj).CTRLB.reg &= ~SERCOM_SPI_CTRLB_RXEN;
_USART(obj).CTRLB.reg &= ~SERCOM_USART_CTRLB_TXEN; // to be checked
usart_syncing(obj);
enable_usart(obj);
}
@ -516,7 +507,7 @@ void serial_break_set(serial_t *obj)
void serial_break_clear(serial_t *obj)
{
disable_usart(obj);
_USART(obj).CTRLB.reg |= SERCOM_SPI_CTRLB_RXEN;
_USART(obj).CTRLB.reg |= SERCOM_USART_CTRLB_TXEN; // to be checked
usart_syncing(obj);
enable_usart(obj);
}
@ -544,6 +535,7 @@ inline uint8_t serial_get_index(serial_t *obj)
}
return 0;
}
static inline void uart_irq(SercomUsart *const usart, uint32_t index)
{
uint16_t interrupt_status;
@ -559,10 +551,6 @@ static inline void uart_irq(SercomUsart *const usart, uint32_t index)
usart->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
irq_handler(serial_irq_ids[index], RxIrq);
}
if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) { // hardware flow control
usart->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC;
usart->INTFLAG.reg = SERCOM_USART_INTENCLR_CTSIC;
}
}
}
@ -596,6 +584,32 @@ void uart5_irq()
uart_irq((SercomUsart *)UART_5, 5);
}
uint32_t get_serial_vector (serial_t *obj)
{
uint32_t vector = 0;
switch ((int)pUSART_S(obj)) {
case UART_0:
vector = (uint32_t)uart0_irq;
break;
case UART_1:
vector = (uint32_t)uart1_irq;
break;
case UART_2:
vector = (uint32_t)uart2_irq;
break;
case UART_3:
vector = (uint32_t)uart3_irq;
break;
case UART_4:
vector = (uint32_t)uart4_irq;
break;
case UART_5:
vector = (uint32_t)uart5_irq;
break;
}
return vector;
}
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id)
{
irq_handler = handler;
@ -627,26 +641,7 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable)
IRQn_Type irq_n = (IRQn_Type)0;
uint32_t vector = 0;
switch ((int)pUSART_S(obj)) {
case UART_0:
vector = (uint32_t)uart0_irq;
break;
case UART_1:
vector = (uint32_t)uart1_irq;
break;
case UART_2:
vector = (uint32_t)uart2_irq;
break;
case UART_3:
vector = (uint32_t)uart3_irq;
break;
case UART_4:
vector = (uint32_t)uart4_irq;
break;
case UART_5:
vector = (uint32_t)uart5_irq;
break;
}
vector = get_serial_vector(obj);
irq_n = get_serial_irq_num(obj);
if (enable) {
@ -789,7 +784,6 @@ int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx
// if( hint == DMA_USAGE_NEVER) { //TODO: DMA to be implemented later
NVIC_ClearPendingIRQ(get_serial_irq_num(obj));
NVIC_DisableIRQ(get_serial_irq_num(obj));
NVIC_SetPriority(get_serial_irq_num(obj), 1);
NVIC_SetVector(get_serial_irq_num(obj), (uint32_t)handler);
NVIC_EnableIRQ(get_serial_irq_num(obj));
@ -798,6 +792,7 @@ int serial_tx_asynch(serial_t *obj, const void *tx, size_t tx_length, uint8_t tx
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_DRE;
}
// }
return 0;
}
void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_width, uint32_t handler, uint32_t event, uint8_t char_match, DMAUsage hint)
@ -807,11 +802,11 @@ void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_widt
serial_rx_enable_event(obj, SERIAL_EVENT_RX_ALL, false);
serial_rx_enable_event(obj, event, true);
serial_set_char_match(obj, char_match);
serial_rx_buffer_set(obj, rx, rx_length, rx_width);
// if( hint == DMA_USAGE_NEVER) { //TODO: DMA to be implemented later
NVIC_ClearPendingIRQ(get_serial_irq_num(obj));
NVIC_DisableIRQ(get_serial_irq_num(obj));
NVIC_SetVector(get_serial_irq_num(obj), (uint32_t)handler);
NVIC_EnableIRQ(get_serial_irq_num(obj));
@ -819,21 +814,23 @@ void serial_rx_asynch(serial_t *obj, void *rx, size_t rx_length, uint8_t rx_widt
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
}
// }
return;
}
uint8_t serial_tx_active(serial_t *obj)
{
return ((_USART(obj).INTENSET.reg & SERCOM_USART_INTFLAG_DRE) ? true : false);
return ((obj->tx_buff.length > 0) ? true : false);
}
uint8_t serial_rx_active(serial_t *obj)
{
return ((_USART(obj).INTENSET.reg & SERCOM_USART_INTFLAG_RXC) ? true : false);
return ((obj->rx_buff.length > 0) ? true : false);
}
int serial_tx_irq_handler_asynch(serial_t *obj)
{
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
serial_tx_abort_asynch(obj);
return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
}
@ -845,9 +842,7 @@ int serial_rx_irq_handler_asynch(serial_t *obj)
uint8_t error_code = 0;
uint16_t received_data = 0;
error_code = (uint8_t)(_USART(obj).STATUS.reg & SERCOM_USART_STATUS_MASK);
/* Check if an error has occurred during the receiving */
if (error_code) {
/* Check which error occurred */
@ -881,6 +876,7 @@ int serial_rx_irq_handler_asynch(serial_t *obj)
if((buf[obj->rx_buff.pos - 1] == obj->char_match) && (obj->serial.events & SERIAL_EVENT_RX_CHARACTER_MATCH)) {
event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
}
_USART(obj).INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
serial_rx_abort_asynch(obj);
return event & obj->serial.events;
}
@ -890,15 +886,12 @@ int serial_rx_irq_handler_asynch(serial_t *obj)
event |= SERIAL_EVENT_RX_CHARACTER_MATCH;
}
/* check for final char event */
if((obj->rx_buff.length) == 0) {
event |= SERIAL_EVENT_RX_COMPLETE & obj->serial.events;
}
/* Return to the call back if character match occured */
if(event != 0) {
serial_rx_abort_asynch(obj);
return event & obj->serial.events;
}
return 0;
}
int serial_irq_handler_asynch(serial_t *obj)
@ -914,12 +907,9 @@ int serial_irq_handler_asynch(serial_t *obj)
if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
/* Interrupt has another TX source */
if(obj->tx_buff.pos >= obj->tx_buff.length) {
/* Transfer complete. Switch off interrupt and return event. */
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
serial_tx_abort_asynch(obj);
return SERIAL_EVENT_TX_COMPLETE & obj->serial.events;
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
} else {
while((serial_writable(obj)) && (obj->tx_buff.pos <= (obj->tx_buff.length - 1))) {
_USART(obj).DATA.reg = buf[obj->tx_buff.pos];
@ -928,29 +918,30 @@ int serial_irq_handler_asynch(serial_t *obj)
}
}
if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {
serial_tx_irq_handler_asynch(obj);
return serial_tx_irq_handler_asynch(obj);
}
if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
serial_rx_irq_handler_asynch(obj);
return serial_rx_irq_handler_asynch(obj);
}
}
return 0;
}
void serial_tx_abort_asynch(serial_t *obj)
{
//TODO: DMA to be implemented
_USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
obj->tx_buff.pos = 0;
_USART(obj).INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;
obj->tx_buff.length = 0;
obj->rx_buff.pos = 0;
}
void serial_rx_abort_asynch(serial_t *obj)
{
//TODO: DMA to be implemented
_USART(obj).INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
obj->rx_buff.pos = 0;
_USART(obj).INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
obj->rx_buff.length = 0;
obj->rx_buff.pos = 0;
}
#endif