* Pin mux logic added for sercom

* added support for 6 uarts in code.
* updated gpio for output setting
* updated device.h for adding async apis for serial
pull/1214/head
akhilpanayamparambil 2015-06-23 10:27:20 +05:30 committed by Karthik Purushothaman
parent 98d628b67f
commit a7b2cee60d
7 changed files with 684 additions and 125 deletions

View File

@ -33,7 +33,12 @@ extern "C" {
typedef enum { typedef enum {
UART_0 = (int)0x42000800UL // Base address of SERCOM0 UART_0 = (int)0x42000800UL, // Base address of SERCOM0
UART_1 = (int)0x42000C00UL, // Base address of SERCOM1
UART_2 = (int)0x42001000UL, // Base address of SERCOM2
UART_3 = (int)0x42001400UL, // Base address of SERCOM3
UART_4 = (int)0x42001800UL, // Base address of SERCOM4
UART_5 = (int)0x42001C00UL // Base address of SERCOM5
} UARTName; } UARTName;
/* /*
typedef enum { typedef enum {

View File

@ -20,6 +20,8 @@
#include "pinmap.h" #include "pinmap.h"
#include "PeripheralNames.h" #include "PeripheralNames.h"
void find_pin_settings (PinName output, PinName input, PinName clock, uint32_t* pad_pinmuxes);
uint32_t find_mux_setting (PinName output, PinName input, PinName clock);
/************RTC***************/ /************RTC***************/
//extern const PinMap PinMap_RTC[]; //extern const PinMap PinMap_RTC[];
@ -46,4 +48,6 @@ extern const PinMap PinMap_UART_RX[];
/************PWM***************/ /************PWM***************/
//extern const PinMap PinMap_PWM[]; //extern const PinMap PinMap_PWM[];
#endif #endif

View File

@ -94,9 +94,13 @@ typedef enum {
PB29 = 61, PB29 = 61,
PB30 = 62, PB30 = 62,
PB31 = 63, PB31 = 63,
PC16 = 64,
PC18 = 65,
PC19 = 66,
USBTX = PA04, USBTX = PA04,
USBRX = PA05, USBRX = PA05,
// Not connected // Not connected
NC = (int)0xFFFFFFFF NC = (int)0xFFFFFFFF

View File

@ -16,6 +16,18 @@
#include "PeripheralPins.h" #include "PeripheralPins.h"
#define SERCOM_NULL 0xFF
#define MUX_NULL 0xFF
#define SERCOM_USART_CTRLA_RXPO_Pos 20 /**< \brief (SERCOM_USART_CTRLA) Receive Data Pinout */
#define SERCOM_USART_CTRLA_RXPO_Msk (0x3ul << SERCOM_USART_CTRLA_RXPO_Pos)
#define SERCOM_USART_CTRLA_RXPO(value) ((SERCOM_USART_CTRLA_RXPO_Msk & ((value) << SERCOM_USART_CTRLA_RXPO_Pos)))
#define SERCOM_USART_CTRLA_TXPO_Pos 16 /**< \brief (SERCOM_USART_CTRLA) Transmit Data Pinout */
#define SERCOM_USART_CTRLA_TXPO_Msk (0x3ul << SERCOM_USART_CTRLA_TXPO_Pos)
#define SERCOM_USART_CTRLA_TXPO(value) ((SERCOM_USART_CTRLA_TXPO_Msk & ((value) << SERCOM_USART_CTRLA_TXPO_Pos)))
/************RTC***************/ /************RTC***************/
const PinMap PinMap_RTC[] = { const PinMap PinMap_RTC[] = {
}; };
@ -60,3 +72,438 @@ const PinMap PinMap_SPI_SSEL[] = {
/************PWM***************/ /************PWM***************/
const PinMap PinMap_PWM[] = { const PinMap PinMap_PWM[] = {
}; };
/********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;
}
}
uint32_t find_mux_setting (PinName output, PinName input, PinName clock)
{
struct pin_values input_values, output_values, clock_values;
uint32_t mux_setting = 0;
input_values.pin = input;
output_values.pin = output;
clock_values.pin = clock;
input_values.com = pinmap_sercom_peripheral(input, output);
output_values.com = input_values.com;
clock_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);
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 (((output_values.pad == 0) && (clock_values.pad == 1)) || (output_values.pad == 0)) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(0);
}
else if((output_values.pad == 2) && (clock_values.pad == 3)) {
mux_setting |= SERCOM_USART_CTRLA_TXPO(1);
}
/*else if((output_values.pad == 0)) { // condition for hardware enabled
mux_setting |= SERCOM_USART_CTRLA_TXPO(2);
}*/
else {
mux_setting = mux_setting; // dummy condition
}
return mux_setting;
}
void find_pin_settings (PinName output, PinName input, PinName clock, uint32_t* pad_pinmuxes)
{
struct pin_values input_values, output_values, clock_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;
input_values.com = pinmap_sercom_peripheral(input, output);
output_values.com = input_values.com;
clock_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);
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);
}

View File

@ -27,6 +27,7 @@
#define DEVICE_SERIAL 1 #define DEVICE_SERIAL 1
#define DEVICE_SERIAL_FC 1 #define DEVICE_SERIAL_FC 1
#define DEVICE_SERIAL_ASYNCH 1
#define DEVICE_I2C 0 #define DEVICE_I2C 0
#define DEVICE_I2CSLAVE 0 #define DEVICE_I2CSLAVE 0

View File

@ -79,7 +79,7 @@ void gpio_dir(gpio_t *obj, PinDirection direction) {
pin_conf.direction = PORT_PIN_DIR_INPUT; pin_conf.direction = PORT_PIN_DIR_INPUT;
break; break;
case PIN_OUTPUT: case PIN_OUTPUT:
pin_conf.direction = PORT_PIN_DIR_OUTPUT; pin_conf.direction = /*PORT_PIN_DIR_OUTPUT*/PORT_PIN_DIR_OUTPUT_WTH_READBACK;
break; break;
case PIN_INPUT_OUTPUT: case PIN_INPUT_OUTPUT:
pin_conf.direction = PORT_PIN_DIR_OUTPUT_WTH_READBACK; pin_conf.direction = PORT_PIN_DIR_OUTPUT_WTH_READBACK;

View File

@ -22,9 +22,18 @@
#include "usart.h" #include "usart.h"
#include "samr21_xplained_pro.h" #include "samr21_xplained_pro.h"
#define _USART(obj) obj->usart->USART #if DEVICE_SERIAL_ASYNCH
#define USART_NUM 1 // for SAMR21 // to be updated for samd21 #define pUSART_S(obj) obj->serial.usart
//#define USART_BUF 8 #define pSERIAL_S(obj) ((struct serial_s*)&(obj->serial))
#else
#define pUSART_S(obj) obj->serial
#define pSERIAL_S(obj) ((struct serial_s*)obj)
#endif
#define _USART(obj) pUSART_S(obj)->USART
#define USART_NUM 6
uint8_t serial_get_index(serial_t *obj);
static uint32_t serial_irq_ids[USART_NUM] = {0}; static uint32_t serial_irq_ids[USART_NUM] = {0};
static uart_irq_handler irq_handler; static uart_irq_handler irq_handler;
@ -32,13 +41,6 @@ static uart_irq_handler irq_handler;
int stdio_uart_inited = 0; int stdio_uart_inited = 0;
serial_t stdio_uart; serial_t stdio_uart;
/*struct serial_global_data_s{
uint8_t string[USART_BUF];
uint8_t count;
};
static struct serial_global_data_s uart_data[USART_NUM];*/
extern uint8_t g_sys_init; extern uint8_t g_sys_init;
static inline bool usart_syncing(serial_t *obj) static inline bool usart_syncing(serial_t *obj)
@ -56,7 +58,7 @@ static inline void enable_usart(serial_t *obj)
#if USART_CALLBACK_MODE == true //TODO: to be implemented #if USART_CALLBACK_MODE == true //TODO: to be implemented
/* Enable Global interrupt for module */ /* Enable Global interrupt for module */
system_interrupt_enable(_sercom_get_interrupt_vector(obj->usart)); // system_interrupt_enable(_sercom_get_interrupt_vector(pUSART_S(obj))); // not required in implementation
#endif #endif
/* Wait until synchronization is complete */ /* Wait until synchronization is complete */
@ -73,7 +75,7 @@ static inline void disable_usart(serial_t *obj)
#if USART_CALLBACK_MODE == true //TODO: to be implemented #if USART_CALLBACK_MODE == true //TODO: to be implemented
/* Disable Global interrupt for module */ /* Disable Global interrupt for module */
system_interrupt_disable(_sercom_get_interrupt_vector(obj->usart)); // system_interrupt_disable(_sercom_get_interrupt_vector(pUSART_S(obj))); // not required in implementation
#endif #endif
/* Wait until synchronization is complete */ /* Wait until synchronization is complete */
usart_syncing(obj); usart_syncing(obj);
@ -100,7 +102,7 @@ static enum status_code usart_set_config_asf( serial_t *obj)
{ {
/* Index for generic clock */ /* Index for generic clock */
uint32_t sercom_index = _sercom_get_sercom_inst_index(obj->usart); uint32_t sercom_index = _sercom_get_sercom_inst_index(pUSART_S(obj));
uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
/* Cache new register values to minimize the number of register writes */ /* Cache new register values to minimize the number of register writes */
@ -112,31 +114,31 @@ static enum status_code usart_set_config_asf( serial_t *obj)
enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
/* Set data order, internal muxing, and clock polarity */ /* Set data order, internal muxing, and clock polarity */
ctrla = (uint32_t)obj->data_order | ctrla = (uint32_t)pSERIAL_S(obj)->data_order |
(uint32_t)obj->mux_setting | (uint32_t)pSERIAL_S(obj)->mux_setting |
#ifdef FEATURE_USART_OVER_SAMPLE #ifdef FEATURE_USART_OVER_SAMPLE
obj->sample_adjustment | pSERIAL_S(obj)->sample_adjustment |
obj->sample_rate | pSERIAL_S(obj)->sample_rate |
#endif #endif
(obj->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos); (pSERIAL_S(obj)->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
/* Get baud value from mode and clock */ /* Get baud value from mode and clock */
switch (obj->transfer_mode) switch (pSERIAL_S(obj)->transfer_mode)
{ {
case USART_TRANSFER_SYNCHRONOUSLY: case USART_TRANSFER_SYNCHRONOUSLY:
if (!obj->use_external_clock) { if (!pSERIAL_S(obj)->use_external_clock) {
_sercom_get_sync_baud_val(obj->baudrate, _sercom_get_sync_baud_val(pSERIAL_S(obj)->baudrate,
system_gclk_chan_get_hz(gclk_index), &baud); system_gclk_chan_get_hz(gclk_index), &baud);
} }
break; break;
case USART_TRANSFER_ASYNCHRONOUSLY: case USART_TRANSFER_ASYNCHRONOUSLY:
if (obj->use_external_clock) { if (pSERIAL_S(obj)->use_external_clock) {
_sercom_get_async_baud_val(obj->baudrate, _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate,
obj->ext_clock_freq, &baud, mode, sample_num); pSERIAL_S(obj)->ext_clock_freq, &baud, mode, sample_num);
} else { } else {
_sercom_get_async_baud_val(obj->baudrate, _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate,
system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
} }
@ -150,9 +152,9 @@ static enum status_code usart_set_config_asf( serial_t *obj)
_USART(obj).BAUD.reg = baud; _USART(obj).BAUD.reg = baud;
/* Set sample mode */ /* Set sample mode */
ctrla |= obj->transfer_mode; ctrla |= pSERIAL_S(obj)->transfer_mode;
if (obj->use_external_clock == false) { if (pSERIAL_S(obj)->use_external_clock == false) {
ctrla |= SERCOM_USART_CTRLA_MODE(0x1); ctrla |= SERCOM_USART_CTRLA_MODE(0x1);
} }
else { else {
@ -160,23 +162,23 @@ static enum status_code usart_set_config_asf( serial_t *obj)
} }
/* Set stopbits, character size and enable transceivers */ /* Set stopbits, character size and enable transceivers */
ctrlb = (uint32_t)obj->stopbits | (uint32_t)obj->character_size | ctrlb = (uint32_t)pSERIAL_S(obj)->stopbits | (uint32_t)pSERIAL_S(obj)->character_size |
#ifdef FEATURE_USART_START_FRAME_DECTION #ifdef FEATURE_USART_START_FRAME_DECTION
(obj->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) | (pSERIAL_S(obj)->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
#endif #endif
(obj->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) | (pSERIAL_S(obj)->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
(obj->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos); (pSERIAL_S(obj)->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
/* Check parity mode bits */ /* Check parity mode bits */
if (obj->parity != USART_PARITY_NONE) { if (pSERIAL_S(obj)->parity != USART_PARITY_NONE) {
ctrla |= SERCOM_USART_CTRLA_FORM(1); ctrla |= SERCOM_USART_CTRLA_FORM(1);
ctrlb |= obj->parity; ctrlb |= pSERIAL_S(obj)->parity;
} else { } else {
ctrla |= SERCOM_USART_CTRLA_FORM(0); ctrla |= SERCOM_USART_CTRLA_FORM(0);
} }
/* Set whether module should run in standby. */ /* Set whether module should run in standby. */
if (obj->run_in_standby || system_is_debugger_present()) { if (pSERIAL_S(obj)->run_in_standby || system_is_debugger_present()) {
ctrla |= SERCOM_USART_CTRLA_RUNSTDBY; ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
} }
@ -195,6 +197,30 @@ static enum status_code usart_set_config_asf( serial_t *obj)
return STATUS_OK; return STATUS_OK;
} }
void get_default_serial_values(serial_t *obj){
/* Set default config to object */
pSERIAL_S(obj)->data_order = USART_DATAORDER_LSB;
pSERIAL_S(obj)->transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY;
pSERIAL_S(obj)->parity = USART_PARITY_NONE;
pSERIAL_S(obj)->stopbits = USART_STOPBITS_1;
pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_8BIT;
pSERIAL_S(obj)->baudrate = 9600;
pSERIAL_S(obj)->receiver_enable = true;
pSERIAL_S(obj)->transmitter_enable = true;
pSERIAL_S(obj)->clock_polarity_inverted = false;
pSERIAL_S(obj)->use_external_clock = false;
pSERIAL_S(obj)->ext_clock_freq = 0;
pSERIAL_S(obj)->mux_setting = USART_RX_1_TX_2_XCK_3;
pSERIAL_S(obj)->run_in_standby = false;
pSERIAL_S(obj)->generator_source = GCLK_GENERATOR_0;
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;
pSERIAL_S(obj)->start_frame_detection_enable = false;
};
void serial_init(serial_t *obj, PinName tx, PinName rx) { void serial_init(serial_t *obj, PinName tx, PinName rx) {
if (g_sys_init == 0) { if (g_sys_init == 0) {
system_init(); system_init();
@ -202,49 +228,51 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
} }
struct system_gclk_chan_config gclk_chan_conf; struct system_gclk_chan_config gclk_chan_conf;
UARTName uart;
uint32_t gclk_index; uint32_t gclk_index;
uint32_t pm_index; uint32_t pm_index;
uint32_t sercom_index = 0; uint32_t sercom_index = 0;
uint32_t muxsetting = 0;
obj->usart = EXT1_UART_MODULE; uint32_t padsetting[4] = {0};
pUSART_S(obj) = EXT1_UART_MODULE;
/* Disable USART module */ /* Disable USART module */
disable_usart(obj); disable_usart(obj);
/* Set default config to object */ get_default_serial_values(obj);
obj->data_order = USART_DATAORDER_LSB;
obj->transfer_mode = USART_TRANSFER_ASYNCHRONOUSLY;
obj->parity = USART_PARITY_NONE;
obj->stopbits = USART_STOPBITS_1;
obj->character_size = USART_CHARACTER_SIZE_8BIT;
obj->baudrate = 9600;
obj->receiver_enable = true;
obj->transmitter_enable = true;
obj->clock_polarity_inverted = false;
obj->use_external_clock = false;
obj->ext_clock_freq = 0;
obj->mux_setting = USART_RX_1_TX_2_XCK_3;
obj->run_in_standby = false;
obj->generator_source = GCLK_GENERATOR_0;
obj->pinmux_pad0 = PINMUX_DEFAULT;
obj->pinmux_pad1 = PINMUX_DEFAULT;
obj->pinmux_pad2 = PINMUX_DEFAULT;
obj->pinmux_pad3 = PINMUX_DEFAULT;
obj->start_frame_detection_enable = false;
obj->mux_setting = EDBG_CDC_SERCOM_MUX_SETTING; // to be done according to the pin received from user find_pin_settings(tx, rx, NC, &padsetting[0]); // tx, rx, clk, pad array // getting pads from pins
obj->pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0; muxsetting = find_mux_setting(tx, rx, NC); // getting mux setting from pins
obj->pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1; sercom_index = pinmap_sercom_peripheral(tx, rx); // same variable sercom_index reused for optimization
obj->pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2; switch (sercom_index){
obj->pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3; case 0:
uart = UART_0;
//TODO: now noly UART0. code to get the SERCOM instance from Pins (pinmapping) to be added later break;
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX); case 1:
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX); uart = UART_1;
UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx); break;
case 2:
sercom_index = _sercom_get_sercom_inst_index(obj->usart); uart = UART_2;
break;
case 3:
uart = UART_3;
break;
case 4:
uart = UART_4;
break;
case 5:
uart = UART_5;
break;
}
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;
sercom_index = _sercom_get_sercom_inst_index(pUSART_S(obj));
pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos; pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
@ -260,11 +288,11 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index); system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
/* Set up the GCLK for the module */ /* Set up the GCLK for the module */
obj->generator_source = GCLK_GENERATOR_0; pSERIAL_S(obj)->generator_source = GCLK_GENERATOR_0;
gclk_chan_conf.source_generator = obj->generator_source; gclk_chan_conf.source_generator = pSERIAL_S(obj)->generator_source;
system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
system_gclk_chan_enable(gclk_index); system_gclk_chan_enable(gclk_index);
sercom_set_gclk_generator(obj->generator_source, false); sercom_set_gclk_generator(pSERIAL_S(obj)->generator_source, false);
/* Set configuration according to the config struct */ /* Set configuration according to the config struct */
usart_set_config_asf(obj); usart_set_config_asf(obj);
@ -274,8 +302,8 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE; pin_conf.input_pull = SYSTEM_PINMUX_PIN_PULL_NONE;
uint32_t pad_pinmuxes[] = { uint32_t pad_pinmuxes[] = {
obj->pinmux_pad0, obj->pinmux_pad1, pSERIAL_S(obj)->pinmux_pad0, pSERIAL_S(obj)->pinmux_pad1,
obj->pinmux_pad2, obj->pinmux_pad3 pSERIAL_S(obj)->pinmux_pad2, pSERIAL_S(obj)->pinmux_pad3
}; };
/* Configure the SERCOM pins according to the user configuration */ /* Configure the SERCOM pins according to the user configuration */
@ -283,7 +311,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
uint32_t current_pinmux = pad_pinmuxes[pad]; uint32_t current_pinmux = pad_pinmuxes[pad];
if (current_pinmux == PINMUX_DEFAULT) { if (current_pinmux == PINMUX_DEFAULT) {
current_pinmux = _sercom_get_default_pad(obj->usart, pad); current_pinmux = _sercom_get_default_pad(pUSART_S(obj), pad);
} }
if (current_pinmux != PINMUX_UNUSED) { if (current_pinmux != PINMUX_UNUSED) {
@ -306,7 +334,7 @@ void serial_init(serial_t *obj, PinName tx, PinName rx) {
} }
void serial_free(serial_t *obj) { void serial_free(serial_t *obj) {
serial_irq_ids[obj->index] = 0; serial_irq_ids[serial_get_index(obj)] = 0;
} }
void serial_baud(serial_t *obj, int baudrate) { void serial_baud(serial_t *obj, int baudrate) {
@ -321,34 +349,34 @@ void serial_baud(serial_t *obj, int baudrate) {
enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC; enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16; enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
obj->baudrate = baudrate; pSERIAL_S(obj)->baudrate = baudrate;
disable_usart(obj); disable_usart(obj);
sercom_index = _sercom_get_sercom_inst_index(obj->usart); sercom_index = _sercom_get_sercom_inst_index(pUSART_S(obj));
gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE; gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
obj->generator_source = GCLK_GENERATOR_0; pSERIAL_S(obj)->generator_source = GCLK_GENERATOR_0;
gclk_chan_conf.source_generator = obj->generator_source; gclk_chan_conf.source_generator = pSERIAL_S(obj)->generator_source;
system_gclk_chan_set_config(gclk_index, &gclk_chan_conf); system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
system_gclk_chan_enable(gclk_index); system_gclk_chan_enable(gclk_index);
sercom_set_gclk_generator(obj->generator_source, false); sercom_set_gclk_generator(pSERIAL_S(obj)->generator_source, false);
/* Get baud value from mode and clock */ /* Get baud value from mode and clock */
switch (obj->transfer_mode) switch (pSERIAL_S(obj)->transfer_mode)
{ {
case USART_TRANSFER_SYNCHRONOUSLY: case USART_TRANSFER_SYNCHRONOUSLY:
if (!obj->use_external_clock) { if (!pSERIAL_S(obj)->use_external_clock) {
_sercom_get_sync_baud_val(obj->baudrate, _sercom_get_sync_baud_val(pSERIAL_S(obj)->baudrate,
system_gclk_chan_get_hz(gclk_index), &baud); system_gclk_chan_get_hz(gclk_index), &baud);
} }
break; break;
case USART_TRANSFER_ASYNCHRONOUSLY: case USART_TRANSFER_ASYNCHRONOUSLY:
if (obj->use_external_clock) { if (pSERIAL_S(obj)->use_external_clock) {
_sercom_get_async_baud_val(obj->baudrate, _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate,
obj->ext_clock_freq, &baud, mode, sample_num); pSERIAL_S(obj)->ext_clock_freq, &baud, mode, sample_num);
} else { } else {
_sercom_get_async_baud_val(obj->baudrate, _sercom_get_async_baud_val(pSERIAL_S(obj)->baudrate,
system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num); system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
} }
break; break;
@ -385,57 +413,54 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
switch (stop_bits){ switch (stop_bits){
case 1: case 1:
obj->stopbits = USART_STOPBITS_1; pSERIAL_S(obj)->stopbits = USART_STOPBITS_1;
break; break;
case 2: case 2:
obj->stopbits = USART_STOPBITS_2; pSERIAL_S(obj)->stopbits = USART_STOPBITS_2;
break; break;
default: default:
obj->stopbits = USART_STOPBITS_1; pSERIAL_S(obj)->stopbits = USART_STOPBITS_1;
} }
switch (parity){ switch (parity){
case ParityNone: case ParityNone:
obj->parity = USART_PARITY_NONE; pSERIAL_S(obj)->parity = USART_PARITY_NONE;
break; break;
case ParityOdd: case ParityOdd:
obj->parity = USART_PARITY_ODD; pSERIAL_S(obj)->parity = USART_PARITY_ODD;
break; break;
case ParityEven: case ParityEven:
obj->parity = USART_PARITY_EVEN; pSERIAL_S(obj)->parity = USART_PARITY_EVEN;
break; break;
default: default:
obj->parity = USART_PARITY_NONE; pSERIAL_S(obj)->parity = USART_PARITY_NONE;
} }
switch (data_bits){ switch (data_bits){
case 5: case 5:
obj->character_size = USART_CHARACTER_SIZE_5BIT; pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_5BIT;
break; break;
case 6: case 6:
obj->character_size = USART_CHARACTER_SIZE_6BIT; pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_6BIT;
break; break;
case 7: case 7:
obj->character_size = USART_CHARACTER_SIZE_7BIT; pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_7BIT;
break; break;
case 8: case 8:
obj->character_size = USART_CHARACTER_SIZE_8BIT; pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_8BIT;
break; break; // 9 bit transfer not required in mbed
/*case 9:
obj->character_size = USART_CHARACTER_SIZE_9BIT;
break;*/
default: default:
obj->character_size = USART_CHARACTER_SIZE_8BIT; pSERIAL_S(obj)->character_size = USART_CHARACTER_SIZE_8BIT;
} }
/* Set stopbits, character size and enable transceivers */ /* Set stopbits, character size and enable transceivers */
ctrlb = (uint32_t)obj->stopbits | (uint32_t)obj->character_size; ctrlb = (uint32_t)pSERIAL_S(obj)->stopbits | (uint32_t)pSERIAL_S(obj)->character_size;
/* Check parity mode bits */ /* Check parity mode bits */
if (obj->parity != USART_PARITY_NONE) { if (pSERIAL_S(obj)->parity != USART_PARITY_NONE) {
ctrla |= SERCOM_USART_CTRLA_FORM(1); ctrla |= SERCOM_USART_CTRLA_FORM(1);
ctrlb |= obj->parity; ctrlb |= pSERIAL_S(obj)->parity;
} else { } else {
ctrla |= SERCOM_USART_CTRLA_FORM(0); ctrla |= SERCOM_USART_CTRLA_FORM(0);
} }
@ -458,14 +483,38 @@ void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_b
/****************************************************************************** /******************************************************************************
* INTERRUPTS HANDLING * INTERRUPTS HANDLING
******************************************************************************/ ******************************************************************************/
/**
* Get index of serial object, relating it to the physical peripheral.
*
* @param obj pointer to serial object
* @return internal index of U(S)ART peripheral
*/
inline uint8_t serial_get_index(serial_t *obj)
{
switch ((int)pSERIAL_S(obj)) {
case UART_0:
return 0;
case UART_1:
return 1;
case UART_2:
return 2;
case UART_3:
return 3;
case UART_4:
return 4;
case UART_5:
return 5;
}
return 0;
}
static inline void uart_irq(SercomUsart *const usart, uint32_t index) { static inline void uart_irq(SercomUsart *const usart, uint32_t index) {
uint16_t interrupt_status; uint16_t interrupt_status;
interrupt_status = usart->INTFLAG.reg; interrupt_status = usart->INTFLAG.reg;
interrupt_status &= usart->INTENSET.reg; interrupt_status &= usart->INTENSET.reg;
if (serial_irq_ids[index] != 0) { if (serial_irq_ids[index] != 0) {
if (interrupt_status & SERCOM_USART_INTFLAG_TXC) // for transmit complete if (interrupt_status & SERCOM_USART_INTFLAG_TXC) // for transmit complete
{ {
usart->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC; usart->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
irq_handler(serial_irq_ids[index], TxIrq); irq_handler(serial_irq_ids[index], TxIrq);
} }
/*if (interrupt_status & SERCOM_USART_INTFLAG_DRE) // for data ready for transmit /*if (interrupt_status & SERCOM_USART_INTFLAG_DRE) // for data ready for transmit
@ -493,15 +542,29 @@ void uart0_irq() {
uart_irq((SercomUsart *)UART_0, 0); uart_irq((SercomUsart *)UART_0, 0);
} }
/*#if UART_NUM > 1 void uart1_irq() {
void uart1_irq() {uart_irq(UART1->S1, 1);} uart_irq((SercomUsart *)UART_1, 0);
void uart2_irq() {uart_irq(UART2->S1, 2);} }
#endif
*/ void uart2_irq() {
uart_irq((SercomUsart *)UART_2, 0);
}
void uart3_irq() {
uart_irq((SercomUsart *)UART_3, 0);
}
void uart4_irq() {
uart_irq((SercomUsart *)UART_4, 0);
}
void uart5_irq() {
uart_irq((SercomUsart *)UART_5, 0);
}
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) { void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
irq_handler = handler; irq_handler = handler;
serial_irq_ids[obj->index] = id; serial_irq_ids[serial_get_index(obj)] = id;
} }
void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) { void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
@ -512,11 +575,31 @@ void serial_irq_set(serial_t *obj, SerialIrq irq, uint32_t enable) {
disable_usart(obj); disable_usart(obj);
ctrlb = _USART(obj).CTRLB.reg; ctrlb = _USART(obj).CTRLB.reg;
switch ((int)obj->usart) { switch ((int)pUSART_S(obj)) {
case UART_0: case UART_0:
irq_n = SERCOM0_IRQn; irq_n = SERCOM0_IRQn;
vector = (uint32_t)&uart0_irq; vector = (uint32_t)&uart0_irq;
break; break;
case UART_1:
irq_n = SERCOM1_IRQn;
vector = (uint32_t)&uart1_irq;
break;
case UART_2:
irq_n = SERCOM2_IRQn;
vector = (uint32_t)&uart2_irq;
break;
case UART_3:
irq_n = SERCOM3_IRQn;
vector = (uint32_t)&uart3_irq;
break;
case UART_4:
irq_n = SERCOM4_IRQn;
vector = (uint32_t)&uart4_irq;
break;
case UART_5:
irq_n = SERCOM5_IRQn;
vector = (uint32_t)&uart5_irq;
break;
} }
if (enable) { if (enable) {
@ -559,9 +642,6 @@ int serial_getc(serial_t *obj) {
void serial_putc(serial_t *obj, int c) { void serial_putc(serial_t *obj, int c) {
uint16_t q = (c & SERCOM_USART_DATA_MASK); uint16_t q = (c & SERCOM_USART_DATA_MASK);
while (!serial_writable(obj)); while (!serial_writable(obj));
// uart_data[obj->index].count++;
// uart_data[obj->index].string[uart_data[obj->index].count] = q;
// _USART(obj).INTENSET.reg = SERCOM_USART_INTFLAG_DRE;
_USART(obj).DATA.reg = q; _USART(obj).DATA.reg = q;
while (!(_USART(obj).INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)); // wait till data is sent while (!(_USART(obj).INTFLAG.reg & SERCOM_USART_INTFLAG_TXC)); // wait till data is sent
} }
@ -627,7 +707,16 @@ void serial_rx_enable_event(serial_t *obj, int event, uint8_t enable)
*/ */
void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width) void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width)
{ {
// We only support byte buffers for now
MBED_ASSERT(width == 8);
if(serial_tx_active(obj)) return;
obj->tx_buff.buffer = tx;
obj->tx_buff.length = tx_length;
obj->tx_buff.pos = 0;
return;
} }
/** Configure the TX buffer for an asynchronous read serial transaction /** Configure the TX buffer for an asynchronous read serial transaction
@ -638,7 +727,16 @@ void serial_tx_buffer_set(serial_t *obj, void *tx, int tx_length, uint8_t width)
*/ */
void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width) void serial_rx_buffer_set(serial_t *obj, void *rx, int rx_length, uint8_t width)
{ {
// We only support byte buffers for now
MBED_ASSERT(width == 8);
if(serial_rx_active(obj)) return;
obj->rx_buff.buffer = rx;
obj->rx_buff.length = rx_length;
obj->rx_buff.pos = 0;
return;
} }
/** Set character to be matched. If an event is enabled, and received character /** Set character to be matched. If an event is enabled, and received character