* corrected the NVIC_NUM_VECTORS value in cmsis_nvic.h from 29 to 28.

* corrected  ld script for stack  and heap initializations.
* enabled main() and infinite while loop after that in startup_samd21.c
* added UART_0 in PerpheralNames.h
* updated PeripheralPins.h, objects.h, device.h, PinNames.h for including UART
* added PeripheralPins.c
* Base Commit for Serial/UART in SAMR21 (added ASFcode from Atmel Studio and serial_api.c)  - Not Working (To be updated with the new code)
pull/1214/head
akhilpanayamparambil 2015-06-15 13:37:34 +05:30 committed by Karthik Purushothaman
parent 5f120e40de
commit cbcf0a8ed7
15 changed files with 1793 additions and 16 deletions

View File

@ -185,10 +185,10 @@ void Reset_Handler(void)
__libc_init_array();
/* Branch to main function */ // expected to be done by MBED OS
// main();
main();
/* Infinite loop */
// while (1);
while (1);
}
/**

View File

@ -50,7 +50,7 @@ SEARCH_DIR(.)
MEMORY
{
rom (rx) : ORIGIN = 0x00000000, LENGTH = 0x00040000
ram (rwx) : ORIGIN = 0x20000000, LENGTH = 0x00008000
ram (rwx) : ORIGIN = 0x20000000 + 0xB0, LENGTH = 0x00008000 - 0xB0
}
/* The stack size used by the application. NOTE: you need to adjust according to your application. */
@ -142,6 +142,13 @@ SECTIONS
_ezero = .;
} > ram
.heap (NOLOAD) :
{
. = ALIGN(4);
__end__ = . ;
. = ORIGIN(ram) + LENGTH(ram) - STACK_SIZE;
} > ram
/* stack section */
.stack (NOLOAD):
{
@ -153,5 +160,4 @@ SECTIONS
} > ram
. = ALIGN(4);
__end__ = . ;
}

View File

@ -32,7 +32,7 @@
#ifndef MBED_CMSIS_NVIC_H
#define MBED_CMSIS_NVIC_H
#define NVIC_NUM_VECTORS (16 +29) // CORE + MCU Peripherals
#define NVIC_NUM_VECTORS (16 +28) // CORE + MCU Peripherals
#define NVIC_USER_IRQ_OFFSET 16
#include "cmsis.h"

View File

@ -22,14 +22,11 @@
#ifdef __cplusplus
extern "C" {
#endif
/*
typedef enum {
UART_0 = (int)LPC_UART0_BASE,
UART_1 = (int)LPC_UART1_BASE,
UART_2 = (int)LPC_UART2_BASE,
UART_3 = (int)LPC_UART3_BASE
} UARTName;
typedef enum {
UART_0 = (int)0x42000800UL // Base address of SERCOM0
} UARTName;
/*
typedef enum {
ADC0_0 = 0,
ADC0_1,

View File

@ -34,8 +34,8 @@
//extern const PinMap PinMap_I2C_SCL[];
/************UART***************/
//extern const PinMap PinMap_UART_TX[];
//extern const PinMap PinMap_UART_RX[];
extern const PinMap PinMap_UART_TX[];
extern const PinMap PinMap_UART_RX[];
/************SPI***************/
//extern const PinMap PinMap_SPI_SCLK[];

View File

@ -94,6 +94,9 @@ typedef enum {
PB29 = 61,
PB30 = 62,
PB31 = 63,
USBTX = PA04,
USBRX = PA05,
// Not connected
NC = (int)0xFFFFFFFF

View File

@ -0,0 +1,62 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "PeripheralPins.h"
/************RTC***************/
const PinMap PinMap_RTC[] = {
};
/************ADC***************/
const PinMap PinMap_ADC[] = {
};
/************DAC***************/
const PinMap PinMap_DAC[] = {
};
/************I2C***************/
const PinMap PinMap_I2C_SDA[] = {
};
const PinMap PinMap_I2C_SCL[] = {
};
/************UART***************/
const PinMap PinMap_UART_TX[] = {
{PA04, UART_0, 0}
};
const PinMap PinMap_UART_RX[] = {
{PA05, UART_0, 0}
};
/************SPI***************/
const PinMap PinMap_SPI_SCLK[] = {
};
const PinMap PinMap_SPI_MOSI[] = {
};
const PinMap PinMap_SPI_MISO[] = {
};
const PinMap PinMap_SPI_SSEL[] = {
};
/************PWM***************/
const PinMap PinMap_PWM[] = {
};

View File

@ -25,8 +25,8 @@
#define DEVICE_ANALOGIN 0
#define DEVICE_ANALOGOUT 0
#define DEVICE_SERIAL 0
#define DEVICE_SERIAL_FC 0
#define DEVICE_SERIAL 1
#define DEVICE_SERIAL_FC 1
#define DEVICE_I2C 0
#define DEVICE_I2CSLAVE 0

View File

@ -0,0 +1,141 @@
/**
* \file
*
* \brief SAM Serial Peripheral Interface Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#include "sercom_interrupt.h"
void *_sercom_instances[SERCOM_INST_NUM];
/** Save status of initialized handlers. */
static bool _handler_table_initialized = false;
/** Void pointers for saving device instance structures. */
static void (*_sercom_interrupt_handlers[SERCOM_INST_NUM])(const uint8_t instance);
/**
* \internal
* Default interrupt handler.
*
* \param[in] instance SERCOM instance used.
*/
static void _sercom_default_handler(
const uint8_t instance)
{
Assert(false);
}
/**
* \internal
* Saves the given callback handler.
*
* \param[in] instance Instance index.
* \param[in] interrupt_handler Pointer to instance callback handler.
*/
void _sercom_set_handler(
const uint8_t instance,
const sercom_handler_t interrupt_handler)
{
/* Initialize handlers with default handler and device instances with 0. */
if (_handler_table_initialized == false) {
for (uint32_t i = 0; i < SERCOM_INST_NUM; i++) {
_sercom_interrupt_handlers[i] = &_sercom_default_handler;
_sercom_instances[i] = NULL;
}
_handler_table_initialized = true;
}
/* Save interrupt handler. */
_sercom_interrupt_handlers[instance] = interrupt_handler;
}
/** \internal
* Converts a given SERCOM index to its interrupt vector index.
*/
#define _SERCOM_INTERRUPT_VECT_NUM(n, unused) \
SYSTEM_INTERRUPT_MODULE_SERCOM##n,
/** \internal
* Generates a SERCOM interrupt handler function for a given SERCOM index.
*/
#define _SERCOM_INTERRUPT_HANDLER(n, unused) \
void SERCOM##n##_Handler(void) \
{ \
_sercom_interrupt_handlers[n](n); \
}
/**
* \internal
* Returns the system interrupt vector.
*
* \param[in] sercom_instance Instance pointer
*
* \return Enum of system interrupt vector
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM0
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM1
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM2
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM3
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM4
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM5
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM6
* \retval SYSTEM_INTERRUPT_MODULE_SERCOM7
*/
enum system_interrupt_vector _sercom_get_interrupt_vector(
Sercom *const sercom_instance)
{
const uint8_t sercom_int_vectors[SERCOM_INST_NUM] =
{
MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_VECT_NUM, ~)
};
/* Retrieve the index of the SERCOM being requested */
uint8_t instance_index = _sercom_get_sercom_inst_index(sercom_instance);
/* Get the vector number from the lookup table for the requested SERCOM */
return (enum system_interrupt_vector)sercom_int_vectors[instance_index];
}
/** Auto-generate a set of interrupt handlers for each SERCOM in the device */
MREPEAT(SERCOM_INST_NUM, _SERCOM_INTERRUPT_HANDLER, ~)

View File

@ -0,0 +1,72 @@
/**
* \file
*
* \brief SAM Serial Peripheral Interface Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef SERCOM_INTERRUPT_H_INCLUDED
#define SERCOM_INTERRUPT_H_INCLUDED
#include "sercom.h"
#include <system_interrupt.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Look-up table for device instances. */
extern void *_sercom_instances[SERCOM_INST_NUM];
typedef void (*sercom_handler_t)(uint8_t instance);
enum system_interrupt_vector _sercom_get_interrupt_vector(
Sercom *const sercom_instance);
void _sercom_set_handler(
const uint8_t instance,
const sercom_handler_t interrupt_handler);
#ifdef __cplusplus
}
#endif
#endif /* SERCOM_INTERRUPT_H_INCLUDED */

View File

@ -0,0 +1,130 @@
/**
* \file
*
* \brief SAM USART Quick Start
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* \page asfdoc_sam0_sercom_usart_callback_use_case Quick Start Guide for SERCOM USART - Callback
*
* This quick start will echo back characters typed into the terminal, using
* asynchronous TX and RX callbacks from the USART peripheral. In this use case
* the USART will be configured with the following settings:
* - Asynchronous mode
* - 9600 Baudrate
* - 8-bits, No Parity and one Stop Bit
* - TX and RX enabled and connected to the Xplained Pro Embedded Debugger virtual COM port
*
* \section asfdoc_sam0_sercom_usart_callback_use_case_setup Setup
*
* \subsection asfdoc_sam0_sercom_usart_callback_use_case_prereq Prerequisites
* There are no special setup requirements for this use-case.
*
* \subsection asfdoc_sam0_usart_callback_use_case_setup_code Code
* Add to the main application source file, outside of any functions:
* \snippet qs_usart_callback.c module_inst
* \snippet qs_usart_callback.c rx_buffer_var
*
* Copy-paste the following callback function code to your user application:
* \snippet qs_usart_callback.c callback_funcs
*
* Copy-paste the following setup code to your user application:
* \snippet qs_usart_callback.c setup
*
* Add to user application initialization (typically the start of \c main()):
* \snippet qs_usart_callback.c setup_init
*
* \subsection asfdoc_sam0_usart_callback_use_case_setup_flow Workflow
* -# Create a module software instance structure for the USART module to store
* the USART driver state while it is in use.
* \snippet qs_usart_callback.c module_inst
* \note This should never go out of scope as long as the module is in use.
* In most cases, this should be global.
*
* -# Configure the USART module.
* -# Create a USART module configuration struct, which can be filled out to
* adjust the configuration of a physical USART peripheral.
* \snippet qs_usart_callback.c setup_config
* -# Initialize the USART configuration struct with the module's default values.
* \snippet qs_usart_callback.c setup_config_defaults
* \note This should always be performed before using the configuration
* struct to ensure that all values are initialized to known default
* settings.
*
* -# Alter the USART settings to configure the physical pinout, baudrate, and
* other relevant parameters.
* \snippet qs_usart_callback.c setup_change_config
* -# Configure the USART module with the desired settings, retrying while the
* driver is busy until the configuration is stressfully set.
* \snippet qs_usart_callback.c setup_set_config
* -# Enable the USART module.
* \snippet qs_usart_callback.c setup_enable
* -# Configure the USART callbacks.
* -# Register the TX and RX callback functions with the driver.
* \snippet qs_usart_callback.c setup_register_callbacks
* -# Enable the TX and RX callbacks so that they will be called by the driver
* when appropriate.
* \snippet qs_usart_callback.c setup_enable_callbacks
*
* \section asfdoc_sam0_usart_callback_use_case_main Use Case
*
* \subsection asfdoc_sam0_usart_callback_use_case_main_code Code
* Copy-paste the following code to your user application:
* \snippet qs_usart_callback.c main
*
* \subsection asfdoc_sam0_usart_callback_use_case_main_flow Workflow
* -# Enable global interrupts, so that the callbacks can be fired.
* \snippet qs_usart_callback.c enable_global_interrupts
* -# Send a string to the USART to show the demo is running, blocking until
* all characters have been sent.
* \snippet qs_usart_callback.c main_send_string
* -# Enter an infinite loop to continuously echo received values on the USART.
* \snippet qs_usart_callback.c main_loop
* -# Perform an asynchronous read of the USART, which will fire the registered
* callback when characters are received.
* \snippet qs_usart_callback.c main_read
*/
/**
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#include <asf.h>
#include <conf_clocks.h>

View File

@ -0,0 +1,660 @@
/**
* \file
*
* \brief SAM SERCOM USART Asynchronous Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#include "usart_interrupt.h"
/**
* \internal
* Asynchronous write of a buffer with a given length
*
* \param[in] module Pointer to USART software instance struct
* \param[in] tx_data Pointer to data to be transmitted
* \param[in] length Length of data buffer
*
*/
void _usart_write_buffer(
struct usart_module *const module,
uint8_t *tx_data,
uint16_t length)
{
/* Sanity check arguments */
Assert(module);
Assert(module->hw);
/* Get a pointer to the hardware module instance */
SercomUsart *const usart_hw = &(module->hw->USART);
/* Write parameters to the device instance */
module->remaining_tx_buffer_length = length;
module->tx_buffer_ptr = tx_data;
module->tx_status = STATUS_BUSY;
/* Enable the Data Register Empty Interrupt */
usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_DRE;
}
/**
* \internal
* Asynchronous read of a buffer with a given length
*
* \param[in] module Pointer to USART software instance struct
* \param[in] rx_data Pointer to data to be received
* \param[in] length Length of data buffer
*
*/
void _usart_read_buffer(
struct usart_module *const module,
uint8_t *rx_data,
uint16_t length)
{
/* Sanity check arguments */
Assert(module);
Assert(module->hw);
/* Get a pointer to the hardware module instance */
SercomUsart *const usart_hw = &(module->hw->USART);
/* Set length for the buffer and the pointer, and let
* the interrupt handler do the rest */
module->remaining_rx_buffer_length = length;
module->rx_buffer_ptr = rx_data;
module->rx_status = STATUS_BUSY;
/* Enable the RX Complete Interrupt */
usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXC;
#ifdef FEATURE_USART_LIN_SLAVE
/* Enable the break character is received Interrupt */
if(module->lin_slave_enabled) {
usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXBRK;
}
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
/* Enable a start condition is detected Interrupt */
if(module->start_frame_detection_enabled) {
usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_RXS;
}
#endif
}
/**
* \brief Registers a callback
*
* Registers a callback function which is implemented by the user.
*
* \note The callback must be enabled by \ref usart_enable_callback,
* in order for the interrupt handler to call it when the conditions for
* the callback type are met.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] callback_func Pointer to callback function
* \param[in] callback_type Callback type given by an enum
*
*/
void usart_register_callback(
struct usart_module *const module,
usart_callback_t callback_func,
enum usart_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
Assert(callback_func);
/* Register callback function */
module->callback[callback_type] = callback_func;
/* Set the bit corresponding to the callback_type */
module->callback_reg_mask |= (1 << callback_type);
}
/**
* \brief Unregisters a callback
*
* Unregisters a callback function which is implemented by the user.
*
* \param[in,out] module Pointer to USART software instance struct
* \param[in] callback_type Callback type given by an enum
*
*/
void usart_unregister_callback(
struct usart_module *const module,
enum usart_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
/* Unregister callback function */
module->callback[callback_type] = NULL;
/* Clear the bit corresponding to the callback_type */
module->callback_reg_mask &= ~(1 << callback_type);
}
/**
* \brief Asynchronous write a single char
*
* Sets up the driver to write the data given. If registered and enabled,
* a callback function will be called when the transmit is completed.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] tx_data Data to transfer
*
* \returns Status of the operation.
* \retval STATUS_OK If operation was completed
* \retval STATUS_BUSY If operation was not completed, due to the
* USART module being busy
* \retval STATUS_ERR_DENIED If the transmitter is not enabled
*/
enum status_code usart_write_job(
struct usart_module *const module,
const uint16_t *tx_data)
{
/* Sanity check arguments */
Assert(module);
Assert(tx_data);
/* Check if the USART transmitter is busy */
if (module->remaining_tx_buffer_length > 0) {
return STATUS_BUSY;
}
/* Check that the transmitter is enabled */
if (!(module->transmitter_enabled)) {
return STATUS_ERR_DENIED;
}
/* Call internal write buffer function with length 1 */
_usart_write_buffer(module, (uint8_t *)tx_data, 1);
return STATUS_OK;
}
/**
* \brief Asynchronous read a single char
*
* Sets up the driver to read data from the USART module to the data
* pointer given. If registered and enabled, a callback will be called
* when the receiving is completed.
*
* \param[in] module Pointer to USART software instance struct
* \param[out] rx_data Pointer to where received data should be put
*
* \returns Status of the operation.
* \retval STATUS_OK If operation was completed
* \retval STATUS_BUSY If operation was not completed
*/
enum status_code usart_read_job(
struct usart_module *const module,
uint16_t *const rx_data)
{
/* Sanity check arguments */
Assert(module);
Assert(rx_data);
/* Check if the USART receiver is busy */
if (module->remaining_rx_buffer_length > 0) {
return STATUS_BUSY;
}
/* Call internal read buffer function with length 1 */
_usart_read_buffer(module, (uint8_t *)rx_data, 1);
return STATUS_OK;
}
/**
* \brief Asynchronous buffer write
*
* Sets up the driver to write a given buffer over the USART. If registered and
* enabled, a callback function will be called.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] tx_data Pointer do data buffer to transmit
* \param[in] length Length of the data to transmit
*
* \note if using 9-bit data, the array that *tx_data point to should be defined
* as uint16_t array and should be casted to uint8_t* pointer. Because it
* is an address pointer, the highest byte is not discarded. For example:
* \code
#define TX_LEN 3
uint16_t tx_buf[TX_LEN] = {0x0111, 0x0022, 0x0133};
usart_write_buffer_job(&module, (uint8_t*)tx_buf, TX_LEN);
\endcode
*
* \returns Status of the operation.
* \retval STATUS_OK If operation was completed successfully.
* \retval STATUS_BUSY If operation was not completed, due to the
* USART module being busy
* \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
* arguments
* \retval STATUS_ERR_DENIED If the transmitter is not enabled
*/
enum status_code usart_write_buffer_job(
struct usart_module *const module,
uint8_t *tx_data,
uint16_t length)
{
/* Sanity check arguments */
Assert(module);
Assert(tx_data);
if (length == 0) {
return STATUS_ERR_INVALID_ARG;
}
/* Check if the USART transmitter is busy */
if (module->remaining_tx_buffer_length > 0) {
return STATUS_BUSY;
}
/* Check that the receiver is enabled */
if (!(module->transmitter_enabled)) {
return STATUS_ERR_DENIED;
}
/* Issue internal asynchronous write */
_usart_write_buffer(module, tx_data, length);
return STATUS_OK;
}
/**
* \brief Asynchronous buffer read
*
* Sets up the driver to read from the USART to a given buffer. If registered
* and enabled, a callback function will be called.
*
* \param[in] module Pointer to USART software instance struct
* \param[out] rx_data Pointer to data buffer to receive
* \param[in] length Data buffer length
*
* \note if using 9-bit data, the array that *rx_data point to should be defined
* as uint16_t array and should be casted to uint8_t* pointer. Because it
* is an address pointer, the highest byte is not discarded. For example:
* \code
#define RX_LEN 3
uint16_t rx_buf[RX_LEN] = {0x0,};
usart_read_buffer_job(&module, (uint8_t*)rx_buf, RX_LEN);
\endcode
*
* \returns Status of the operation.
* \retval STATUS_OK If operation was completed
* \retval STATUS_BUSY If operation was not completed, due to the
* USART module being busy
* \retval STATUS_ERR_INVALID_ARG If operation was not completed, due to invalid
* arguments
* \retval STATUS_ERR_DENIED If the transmitter is not enabled
*/
enum status_code usart_read_buffer_job(
struct usart_module *const module,
uint8_t *rx_data,
uint16_t length)
{
/* Sanity check arguments */
Assert(module);
Assert(rx_data);
if (length == 0) {
return STATUS_ERR_INVALID_ARG;
}
/* Check that the receiver is enabled */
if (!(module->receiver_enabled)) {
return STATUS_ERR_DENIED;
}
/* Check if the USART receiver is busy */
if (module->remaining_rx_buffer_length > 0) {
return STATUS_BUSY;
}
/* Issue internal asynchronous read */
_usart_read_buffer(module, rx_data, length);
return STATUS_OK;
}
/**
* \brief Cancels ongoing read/write operation
*
* Cancels the ongoing read/write operation modifying parameters in the
* USART software struct.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] transceiver_type Transfer type to cancel
*/
void usart_abort_job(
struct usart_module *const module,
enum usart_transceiver_type transceiver_type)
{
/* Sanity check arguments */
Assert(module);
Assert(module->hw);
/* Get a pointer to the hardware module instance */
SercomUsart *const usart_hw = &(module->hw->USART);
switch(transceiver_type) {
case USART_TRANSCEIVER_RX:
/* Clear the interrupt flag in order to prevent the receive
* complete callback to fire */
usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXC;
/* Clear the software reception buffer */
module->remaining_rx_buffer_length = 0;
break;
case USART_TRANSCEIVER_TX:
/* Clear the interrupt flag in order to prevent the receive
* complete callback to fire */
usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_TXC;
/* Clear the software reception buffer */
module->remaining_tx_buffer_length = 0;
break;
}
}
/**
* \brief Get status from the ongoing or last asynchronous transfer operation
*
* Returns the error from a given ongoing or last asynchronous transfer operation.
* Either from a read or write transfer.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] transceiver_type Transfer type to check
*
* \return Status of the given job.
* \retval STATUS_OK No error occurred during the last transfer
* \retval STATUS_BUSY A transfer is ongoing
* \retval STATUS_ERR_BAD_DATA The last operation was aborted due to a
* parity error. The transfer could be affected
* by external noise
* \retval STATUS_ERR_BAD_FORMAT The last operation was aborted due to a
* frame error
* \retval STATUS_ERR_OVERFLOW The last operation was aborted due to a
* buffer overflow
* \retval STATUS_ERR_INVALID_ARG An invalid transceiver enum given
*/
enum status_code usart_get_job_status(
struct usart_module *const module,
enum usart_transceiver_type transceiver_type)
{
/* Sanity check arguments */
Assert(module);
/* Variable for status code */
enum status_code status_code;
switch(transceiver_type) {
case USART_TRANSCEIVER_RX:
status_code = module->rx_status;
break;
case USART_TRANSCEIVER_TX:
status_code = module->tx_status;
break;
default:
status_code = STATUS_ERR_INVALID_ARG;
break;
}
return status_code;
}
/**
* \internal
* Handles interrupts as they occur, and it will run callback functions
* which are registered and enabled.
*
* \param[in] instance ID of the SERCOM instance calling the interrupt
* handler.
*/
void _usart_interrupt_handler(
uint8_t instance)
{
/* Temporary variables */
uint16_t interrupt_status;
uint16_t callback_status;
uint8_t error_code;
/* Get device instance from the look-up table */
struct usart_module *module
= (struct usart_module *)_sercom_instances[instance];
/* Pointer to the hardware module instance */
SercomUsart *const usart_hw
= &(module->hw->USART);
/* Wait for the synchronization to complete */
_usart_wait_for_sync(module);
/* Read and mask interrupt flag register */
interrupt_status = usart_hw->INTFLAG.reg;
interrupt_status &= usart_hw->INTENSET.reg;
callback_status = module->callback_reg_mask &
module->callback_enable_mask;
/* Check if a DATA READY interrupt has occurred,
* and if there is more to transfer */
if (interrupt_status & SERCOM_USART_INTFLAG_DRE) {
if (module->remaining_tx_buffer_length) {
/* Write value will be at least 8-bits long */
uint16_t data_to_send = *(module->tx_buffer_ptr);
/* Increment 8-bit pointer */
(module->tx_buffer_ptr)++;
if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
data_to_send |= (*(module->tx_buffer_ptr) << 8);
/* Increment 8-bit pointer */
(module->tx_buffer_ptr)++;
}
/* Write the data to send */
usart_hw->DATA.reg = (data_to_send & SERCOM_USART_DATA_MASK);
if (--(module->remaining_tx_buffer_length) == 0) {
/* Disable the Data Register Empty Interrupt */
usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
/* Enable Transmission Complete interrupt */
usart_hw->INTENSET.reg = SERCOM_USART_INTFLAG_TXC;
}
} else {
usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_DRE;
}
/* Check if the Transmission Complete interrupt has occurred and
* that the transmit buffer is empty */
}
if (interrupt_status & SERCOM_USART_INTFLAG_TXC) {
/* Disable TX Complete Interrupt, and set STATUS_OK */
usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_TXC;
module->tx_status = STATUS_OK;
/* Run callback if registered and enabled */
if (callback_status & (1 << USART_CALLBACK_BUFFER_TRANSMITTED)) {
(*(module->callback[USART_CALLBACK_BUFFER_TRANSMITTED]))(module);
}
/* Check if the Receive Complete interrupt has occurred, and that
* there's more data to receive */
}
if (interrupt_status & SERCOM_USART_INTFLAG_RXC) {
if (module->remaining_rx_buffer_length) {
/* Read out the status code and mask away all but the 4 LSBs*/
error_code = (uint8_t)(usart_hw->STATUS.reg & SERCOM_USART_STATUS_MASK);
#if !SAMD20
/* CTS status should not be considered as an error */
if(error_code & SERCOM_USART_STATUS_CTS) {
error_code &= ~SERCOM_USART_STATUS_CTS;
}
#endif
/* Check if an error has occurred during the receiving */
if (error_code) {
/* Check which error occurred */
if (error_code & SERCOM_USART_STATUS_FERR) {
/* Store the error code and clear flag by writing 1 to it */
module->rx_status = STATUS_ERR_BAD_FORMAT;
usart_hw->STATUS.reg |= SERCOM_USART_STATUS_FERR;
} else if (error_code & SERCOM_USART_STATUS_BUFOVF) {
/* Store the error code and clear flag by writing 1 to it */
module->rx_status = STATUS_ERR_OVERFLOW;
usart_hw->STATUS.reg |= SERCOM_USART_STATUS_BUFOVF;
} else if (error_code & SERCOM_USART_STATUS_PERR) {
/* Store the error code and clear flag by writing 1 to it */
module->rx_status = STATUS_ERR_BAD_DATA;
usart_hw->STATUS.reg |= SERCOM_USART_STATUS_PERR;
}
#ifdef FEATURE_USART_LIN_SLAVE
else if (error_code & SERCOM_USART_STATUS_ISF) {
/* Store the error code and clear flag by writing 1 to it */
module->rx_status = STATUS_ERR_PROTOCOL;
usart_hw->STATUS.reg |= SERCOM_USART_STATUS_ISF;
}
#endif
#ifdef FEATURE_USART_COLLISION_DECTION
else if (error_code & SERCOM_USART_STATUS_COLL) {
/* Store the error code and clear flag by writing 1 to it */
module->rx_status = STATUS_ERR_PACKET_COLLISION;
usart_hw->STATUS.reg |= SERCOM_USART_STATUS_COLL;
}
#endif
/* Run callback if registered and enabled */
if (callback_status
& (1 << USART_CALLBACK_ERROR)) {
(*(module->callback[USART_CALLBACK_ERROR]))(module);
}
} else {
/* Read current packet from DATA register,
* increment buffer pointer and decrement buffer length */
uint16_t received_data = (usart_hw->DATA.reg & SERCOM_USART_DATA_MASK);
/* Read value will be at least 8-bits long */
*(module->rx_buffer_ptr) = received_data;
/* Increment 8-bit pointer */
module->rx_buffer_ptr += 1;
if (module->character_size == USART_CHARACTER_SIZE_9BIT) {
/* 9-bit data, write next received byte to the buffer */
*(module->rx_buffer_ptr) = (received_data >> 8);
/* Increment 8-bit pointer */
module->rx_buffer_ptr += 1;
}
/* Check if the last character have been received */
if(--(module->remaining_rx_buffer_length) == 0) {
/* Disable RX Complete Interrupt,
* and set STATUS_OK */
usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
module->rx_status = STATUS_OK;
/* Run callback if registered and enabled */
if (callback_status
& (1 << USART_CALLBACK_BUFFER_RECEIVED)) {
(*(module->callback[USART_CALLBACK_BUFFER_RECEIVED]))(module);
}
}
}
} else {
/* This should not happen. Disable Receive Complete interrupt. */
usart_hw->INTENCLR.reg = SERCOM_USART_INTFLAG_RXC;
}
}
#ifdef FEATURE_USART_HARDWARE_FLOW_CONTROL
if (interrupt_status & SERCOM_USART_INTFLAG_CTSIC) {
/* Disable interrupts */
usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_CTSIC;
/* Clear interrupt flag */
usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_CTSIC;
/* Run callback if registered and enabled */
if (callback_status & (1 << USART_CALLBACK_CTS_INPUT_CHANGE)) {
(*(module->callback[USART_CALLBACK_CTS_INPUT_CHANGE]))(module);
}
}
#endif
#ifdef FEATURE_USART_LIN_SLAVE
if (interrupt_status & SERCOM_USART_INTFLAG_RXBRK) {
/* Disable interrupts */
usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXBRK;
/* Clear interrupt flag */
usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXBRK;
/* Run callback if registered and enabled */
if (callback_status & (1 << USART_CALLBACK_BREAK_RECEIVED)) {
(*(module->callback[USART_CALLBACK_BREAK_RECEIVED]))(module);
}
}
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
if (interrupt_status & SERCOM_USART_INTFLAG_RXS) {
/* Disable interrupts */
usart_hw->INTENCLR.reg = SERCOM_USART_INTENCLR_RXS;
/* Clear interrupt flag */
usart_hw->INTFLAG.reg = SERCOM_USART_INTFLAG_RXS;
/* Run callback if registered and enabled */
if (callback_status & (1 << USART_CALLBACK_START_RECEIVED)) {
(*(module->callback[USART_CALLBACK_START_RECEIVED]))(module);
}
}
#endif
}

View File

@ -0,0 +1,176 @@
/**
* \file
*
* \brief SAM SERCOM USART Asynchronous Driver
*
* Copyright (C) 2012-2014 Atmel Corporation. All rights reserved.
*
* \asf_license_start
*
* \page License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The name of Atmel may not be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* 4. This software may only be redistributed and used in connection with an
* Atmel microcontroller product.
*
* THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
* EXPRESSLY AND SPECIFICALLY DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* \asf_license_stop
*
*/
/**
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
*/
#ifndef USART_INTERRUPT_H_INCLUDED
#define USART_INTERRUPT_H_INCLUDED
#include "usart.h"
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(__DOXYGEN__)
void _usart_write_buffer(
struct usart_module *const module,
uint8_t *tx_data,
uint16_t length);
void _usart_read_buffer(
struct usart_module *const module,
uint8_t *rx_data,
uint16_t length);
void _usart_interrupt_handler(
uint8_t instance);
#endif
/**
* \addtogroup asfdoc_sam0_sercom_usart_group
*
* @{
*/
/**
* \name Callback Management
* @{
*/
void usart_register_callback(
struct usart_module *const module,
usart_callback_t callback_func,
enum usart_callback callback_type);
void usart_unregister_callback(
struct usart_module *module,
enum usart_callback callback_type);
/**
* \brief Enables callback
*
* Enables the callback function registered by the \ref usart_register_callback.
* The callback function will be called from the interrupt handler when the
* conditions for the callback type are met.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] callback_type Callback type given by an enum
*/
static inline void usart_enable_callback(
struct usart_module *const module,
enum usart_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
/* Enable callback */
module->callback_enable_mask |= (1 << callback_type);
}
/**
* \brief Disable callback
*
* Disables the callback function registered by the \ref usart_register_callback,
* and the callback will not be called from the interrupt routine.
*
* \param[in] module Pointer to USART software instance struct
* \param[in] callback_type Callback type given by an enum
*/
static inline void usart_disable_callback(
struct usart_module *const module,
enum usart_callback callback_type)
{
/* Sanity check arguments */
Assert(module);
/* Disable callback */
module->callback_enable_mask &= ~(1 << callback_type);
}
/**
* @}
*/
/**
* \name Writing and Reading
* @{
*/
enum status_code usart_write_job(
struct usart_module *const module,
const uint16_t *tx_data);
enum status_code usart_read_job(
struct usart_module *const module,
uint16_t *const rx_data);
enum status_code usart_write_buffer_job(
struct usart_module *const module,
uint8_t *tx_data,
uint16_t length);
enum status_code usart_read_buffer_job(
struct usart_module *const module,
uint8_t *rx_data,
uint16_t length);
void usart_abort_job(
struct usart_module *const module,
enum usart_transceiver_type transceiver_type);
enum status_code usart_get_job_status(
struct usart_module *const module,
enum usart_transceiver_type transceiver_type);
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif /* USART_INTERRUPT_H_INCLUDED */

View File

@ -39,6 +39,11 @@ struct port_s {
PortName port;
uint32_t mask;
};
struct serial_s {
SercomUsart *uart;
int index;
};
/*
struct pwmout_s {
__IO uint32_t *MR;

View File

@ -0,0 +1,525 @@
/* mbed Microcontroller Library
* Copyright (c) 2006-2013 ARM Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "mbed_assert.h"
#include "cmsis.h"
#include "serial_api.h"
#include <string.h>
#include "pinmap.h"
#include "PeripheralPins.h"
#include "usart.h"
#include "usart_interrupt.h"
#include "samr21_xplained_pro.h"
#define UART_NUM 1 // for SAMR21 // to be updated for samd21
struct usart_module usart_instance;
static uint32_t serial_irq_ids[UART_NUM] = {0};
static uart_irq_handler irq_handler;
int stdio_uart_inited = 0;
serial_t stdio_uart;
/**
* \internal
* Set Configuration of the USART module
*/
static enum status_code _usart_set_config(
struct usart_module *const module,
const struct usart_config *const config)
{
/* Sanity check arguments */
Assert(module);
Assert(module->hw);
/* Get a pointer to the hardware module instance */
SercomUsart *const usart_hw = &(module->hw->USART);
/* Index for generic clock */
uint32_t sercom_index = _sercom_get_sercom_inst_index(module->hw);
uint32_t gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
/* Cache new register values to minimize the number of register writes */
uint32_t ctrla = 0;
uint32_t ctrlb = 0;
uint16_t baud = 0;
enum sercom_asynchronous_operation_mode mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
enum sercom_asynchronous_sample_num sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
#ifdef FEATURE_USART_OVER_SAMPLE
switch (config->sample_rate) {
case USART_SAMPLE_RATE_16X_ARITHMETIC:
mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
break;
case USART_SAMPLE_RATE_8X_ARITHMETIC:
mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
break;
case USART_SAMPLE_RATE_3X_ARITHMETIC:
mode = SERCOM_ASYNC_OPERATION_MODE_ARITHMETIC;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_3;
break;
case USART_SAMPLE_RATE_16X_FRACTIONAL:
mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_16;
break;
case USART_SAMPLE_RATE_8X_FRACTIONAL:
mode = SERCOM_ASYNC_OPERATION_MODE_FRACTIONAL;
sample_num = SERCOM_ASYNC_SAMPLE_NUM_8;
break;
}
#endif
/* Set data order, internal muxing, and clock polarity */
ctrla = (uint32_t)config->data_order |
(uint32_t)config->mux_setting |
#ifdef FEATURE_USART_OVER_SAMPLE
config->sample_adjustment |
config->sample_rate |
#endif
#ifdef FEATURE_USART_IMMEDIATE_BUFFER_OVERFLOW_NOTIFICATION
(config->immediate_buffer_overflow_notification << SERCOM_USART_CTRLA_IBON_Pos) |
#endif
(config->clock_polarity_inverted << SERCOM_USART_CTRLA_CPOL_Pos);
enum status_code status_code = STATUS_OK;
/* Get baud value from mode and clock */
switch (config->transfer_mode)
{
case USART_TRANSFER_SYNCHRONOUSLY:
if (!config->use_external_clock) {
status_code = _sercom_get_sync_baud_val(config->baudrate,
system_gclk_chan_get_hz(gclk_index), &baud);
}
break;
case USART_TRANSFER_ASYNCHRONOUSLY:
if (config->use_external_clock) {
status_code =
_sercom_get_async_baud_val(config->baudrate,
config->ext_clock_freq, &baud, mode, sample_num);
} else {
status_code =
_sercom_get_async_baud_val(config->baudrate,
system_gclk_chan_get_hz(gclk_index), &baud, mode, sample_num);
}
break;
}
/* Check if calculating the baudrate failed */
if (status_code != STATUS_OK) {
/* Abort */
return status_code;
}
#ifdef FEATURE_USART_IRDA
if(config->encoding_format_enable) {
usart_hw->RXPL.reg = config->receive_pulse_length;
}
#endif
/* Wait until synchronization is complete */
_usart_wait_for_sync(module);
/*Set baud val */
usart_hw->BAUD.reg = baud;
/* Set sample mode */
ctrla |= config->transfer_mode;
if (config->use_external_clock == false) {
ctrla |= SERCOM_USART_CTRLA_MODE(0x1);
}
else {
ctrla |= SERCOM_USART_CTRLA_MODE(0x0);
}
/* Set stopbits, character size and enable transceivers */
ctrlb = (uint32_t)config->stopbits | (uint32_t)config->character_size |
#ifdef FEATURE_USART_IRDA
(config->encoding_format_enable << SERCOM_USART_CTRLB_ENC_Pos) |
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
(config->start_frame_detection_enable << SERCOM_USART_CTRLB_SFDE_Pos) |
#endif
#ifdef FEATURE_USART_COLLISION_DECTION
(config->collision_detection_enable << SERCOM_USART_CTRLB_COLDEN_Pos) |
#endif
(config->receiver_enable << SERCOM_USART_CTRLB_RXEN_Pos) |
(config->transmitter_enable << SERCOM_USART_CTRLB_TXEN_Pos);
/* Check parity mode bits */
if (config->parity != USART_PARITY_NONE) {
#ifdef FEATURE_USART_LIN_SLAVE
if(config->lin_slave_enable) {
ctrla |= SERCOM_USART_CTRLA_FORM(0x5);
} else {
ctrla |= SERCOM_USART_CTRLA_FORM(1);
}
#else
ctrla |= SERCOM_USART_CTRLA_FORM(1);
#endif
ctrlb |= config->parity;
} else {
#ifdef FEATURE_USART_LIN_SLAVE
if(config->lin_slave_enable) {
ctrla |= SERCOM_USART_CTRLA_FORM(0x4);
} else {
ctrla |= SERCOM_USART_CTRLA_FORM(0);
}
#else
ctrla |= SERCOM_USART_CTRLA_FORM(0);
#endif
}
/* Set whether module should run in standby. */
if (config->run_in_standby || system_is_debugger_present()) {
ctrla |= SERCOM_USART_CTRLA_RUNSTDBY;
}
/* Wait until synchronization is complete */
_usart_wait_for_sync(module);
/* Write configuration to CTRLB */
usart_hw->CTRLB.reg = ctrlb;
/* Wait until synchronization is complete */
_usart_wait_for_sync(module);
/* Write configuration to CTRLA */
usart_hw->CTRLA.reg = ctrla;
return STATUS_OK;
}
void serial_init(serial_t *obj, PinName tx, PinName rx) {
struct usart_config config_usart;
struct system_gclk_chan_config gclk_chan_conf;
uint32_t gclk_index;
uint32_t pm_index;
uint32_t sercom_index = 0; // index 0 for SERCOM0
enum status_code status_code = STATUS_OK;
usart_get_config_defaults(&config_usart); // get default configuration setting used below
config_usart.baudrate = 9600; // setting default configurations for SERCOM0 serial
config_usart.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
config_usart.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
config_usart.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
config_usart.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
config_usart.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
//TODO: now noly UART0. code to get the SERCOM instance from Pins (pinmapping) to be added later
UARTName uart_tx = (UARTName)pinmap_peripheral(tx, PinMap_UART_TX);
UARTName uart_rx = (UARTName)pinmap_peripheral(rx, PinMap_UART_RX);
UARTName uart = (UARTName)pinmap_merge(uart_tx, uart_rx);
obj->uart = (SercomUsart *)uart;
usart_instance.hw = (Sercom *)uart;
pm_index = sercom_index + PM_APBCMASK_SERCOM0_Pos;
gclk_index = sercom_index + SERCOM0_GCLK_ID_CORE;
if (obj->uart->CTRLA.reg & SERCOM_USART_CTRLA_SWRST) {
/* The module is busy resetting itself */
return;
}
if (obj->uart->CTRLA.reg & SERCOM_USART_CTRLA_ENABLE) {
/* Check the module is enabled */
return;
}
/* Turn on module in PM */
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, 1 << pm_index);
/* Set up the GCLK for the module */
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
gclk_chan_conf.source_generator = config_usart.generator_source;
system_gclk_chan_set_config(gclk_index, &gclk_chan_conf);
system_gclk_chan_enable(gclk_index);
sercom_set_gclk_generator(config_usart.generator_source, false);
/* Set character size */
usart_instance.character_size = config_usart.character_size;
/* Set transmitter and receiver status */
usart_instance.receiver_enabled = config_usart.receiver_enable;
usart_instance.transmitter_enabled = config_usart.transmitter_enable;
#ifdef FEATURE_USART_LIN_SLAVE
usart_instance.lin_slave_enabled = config_usart.lin_slave_enable;
#endif
#ifdef FEATURE_USART_START_FRAME_DECTION
usart_instance.start_frame_detection_enabled = config_usart.start_frame_detection_enable;
#endif
/* Set configuration according to the config struct */
status_code = _usart_set_config(&usart_instance, &config_usart);
if(status_code != STATUS_OK) {
return;
}
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;
uint32_t pad_pinmuxes[] = {
config_usart.pinmux_pad0, config_usart.pinmux_pad1,
config_usart.pinmux_pad2, config_usart.pinmux_pad3
};
/* 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(usart_instance.hw, pad);
}
if (current_pinmux != PINMUX_UNUSED) {
pin_conf.mux_position = current_pinmux & 0xFFFF;
system_pinmux_pin_set_config(current_pinmux >> 16, &pin_conf);
}
}
if (uart == STDIO_UART) {
stdio_uart_inited = 1;
memcpy(&stdio_uart, obj, sizeof(serial_t));
}
system_interrupt_enable(_sercom_get_interrupt_vector(usart_instance.hw));
/* Wait until synchronization is complete */
_usart_wait_for_sync(&usart_instance);
/* Enable USART module */
obj->uart->CTRLA.reg |= SERCOM_USART_CTRLA_ENABLE;
/* usart_get_config_defaults(&config_usart);
config_usart.baudrate = 9600;
config_usart.mux_setting = EDBG_CDC_SERCOM_MUX_SETTING;
config_usart.pinmux_pad0 = EDBG_CDC_SERCOM_PINMUX_PAD0;
config_usart.pinmux_pad1 = EDBG_CDC_SERCOM_PINMUX_PAD1;
config_usart.pinmux_pad2 = EDBG_CDC_SERCOM_PINMUX_PAD2;
config_usart.pinmux_pad3 = EDBG_CDC_SERCOM_PINMUX_PAD3;
while (usart_init(&usart_instance,
EDBG_CDC_MODULE, &config_usart) != STATUS_OK) {
}*/
}
/*
void serial_free(serial_t *obj) {
serial_irq_ids[obj->index] = 0;
}*/
void serial_baud(serial_t *obj, int baudrate) {
/* struct usart_config config_usart;
usart_get_config_defaults(&config_usart);
config_usart.baudrate = baudrate;
while (usart_init(&usart_instance,
EDBG_CDC_MODULE, &config_usart) != STATUS_OK) {
}*/
}
void serial_format(serial_t *obj, int data_bits, SerialParity parity, int stop_bits) {
/* struct usart_config config_usart;
MBED_ASSERT((stop_bits == 1) || (stop_bits == 2));
MBED_ASSERT((parity == ParityNone) || (parity == ParityOdd) || (parity == ParityEven));
MBED_ASSERT((data_bits == 5) || (data_bits == 6) || (data_bits == 7) || (data_bits == 8) || (data_bits == 9));
usart_get_config_defaults(&config_usart);
switch (stop_bits){
case 1:
config_usart.stopbits = USART_STOPBITS_1;
break;
case 2:
config_usart.stopbits = USART_STOPBITS_2;
break;
default:
config_usart.stopbits = USART_STOPBITS_1;
}
switch (parity){
case ParityNone:
config_usart.parity = USART_PARITY_NONE;
break;
case ParityOdd:
config_usart.parity = USART_PARITY_ODD;
break;
case ParityEven:
config_usart.parity = USART_PARITY_EVEN;
break;
default:
config_usart.parity = USART_PARITY_NONE;
}
switch (data_bits){
case 5:
config_usart.character_size = USART_CHARACTER_SIZE_5BIT;
break;
case 6:
config_usart.character_size = USART_CHARACTER_SIZE_6BIT;
break;
case 7:
config_usart.character_size = USART_CHARACTER_SIZE_7BIT;
break;
case 8:
config_usart.character_size = USART_CHARACTER_SIZE_8BIT;
break;
case 9:
config_usart.character_size = USART_CHARACTER_SIZE_9BIT;
break;
default:
config_usart.character_size = USART_CHARACTER_SIZE_8BIT;
}
while (usart_init(&usart_instance,
EDBG_CDC_MODULE, &config_usart) != STATUS_OK) {
}*/
}
/******************************************************************************
* INTERRUPTS HANDLING
******************************************************************************/
static inline void uart_irq(SercomUsart *const uart, uint32_t index) {
uint16_t interrupt_status;
/* Read and mask interrupt flag register */
interrupt_status = uart->INTFLAG.reg;
interrupt_status &= uart->INTENSET.reg;
if (serial_irq_ids[index] != 0) {
if (interrupt_status & /*SERCOM_USART_INTFLAG_TXC*/SERCOM_USART_INTFLAG_DRE) // for transmit complete
irq_handler(serial_irq_ids[index], TxIrq);
if (interrupt_status & SERCOM_USART_INTFLAG_RXC) // for recieve complete
irq_handler(serial_irq_ids[index], RxIrq);
}
}
void uart0_irq() {
uart_irq((SercomUsart *)UART_0, 0);
}
/*#if UART_NUM > 1
void uart1_irq() {uart_irq(UART1->S1, 1);}
void uart2_irq() {uart_irq(UART2->S1, 2);}
#endif
*/
void serial_irq_handler(serial_t *obj, uart_irq_handler handler, uint32_t id) {
irq_handler = handler;
serial_irq_ids[obj->index] = id;
}
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)obj->uart) {
case UART_0:
irq_n = (uint32_t)&SERCOM0_Handler;
vector = (uint32_t)&uart0_irq;
break;
}
if (enable) {
// usart_enable(&usart_instance);
switch (irq){
case RxIrq: obj->uart->INTENSET.reg |= SERCOM_USART_INTENSET_RXC; break;
case TxIrq: obj->uart->INTENSET.reg |= /*SERCOM_USART_INTENSET_TXC*/SERCOM_USART_INTFLAG_DRE; break;
}
/* switch (irq) {
case RxIrq: obj->uart->C2 |= (UARTLP_C2_RIE_MASK); break;
case TxIrq: obj->uart->C2 |= (UARTLP_C2_TIE_MASK); break;
}*/
NVIC_SetVector(irq_n, vector);
NVIC_EnableIRQ(irq_n);
} else { // disable
// usart_disable(&usart_instance);
// int all_disabled = 0;
// SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
switch (irq) {
case RxIrq: obj->uart->INTENCLR.reg &= ~(SERCOM_USART_INTENCLR_RXC); break;
case TxIrq: obj->uart->INTENCLR.reg &= ~(/*SERCOM_USART_INTENCLR_TXC*/SERCOM_USART_INTFLAG_DRE); break;
}
NVIC_DisableIRQ(irq_n);
/*int all_disabled = 0;
SerialIrq other_irq = (irq == RxIrq) ? (TxIrq) : (RxIrq);
switch (irq) {
case RxIrq: obj->uart->C2 &= ~(UARTLP_C2_RIE_MASK); break;
case TxIrq: obj->uart->C2 &= ~(UARTLP_C2_TIE_MASK); break;
}
switch (other_irq) {
case RxIrq: all_disabled = (obj->uart->C2 & (UARTLP_C2_RIE_MASK)) == 0; break;
case TxIrq: all_disabled = (obj->uart->C2 & (UARTLP_C2_TIE_MASK)) == 0; break;
}
if (all_disabled)
NVIC_DisableIRQ(irq_n);*/
}
}
/******************************************************************************
* READ/WRITE
******************************************************************************/
int serial_getc(serial_t *obj) {
while (!serial_readable(obj));
return obj->uart->DATA.reg ;
// return obj->uart->D;
}
void serial_putc(serial_t *obj, int c) {
while (!serial_writable(obj));
obj->uart->DATA.reg = (c & SERCOM_USART_DATA_MASK);
// obj->uart->D = c;
}
int serial_readable(serial_t *obj) {
// check overrun
/*if (obj->uart->S1 & UARTLP_S1_OR_MASK) {
obj->uart->S1 |= UARTLP_S1_OR_MASK;
}*/
return 0/*(obj->uart->S1 & UARTLP_S1_RDRF_MASK)*/;
}
int serial_writable(serial_t *obj) {
// check overrun
/*if (obj->uart->S1 & UARTLP_S1_OR_MASK) {
obj->uart->S1 |= UARTLP_S1_OR_MASK;
}*/
return 0/*(obj->uart->S1 & UARTLP_S1_TDRE_MASK)*/;
}
void serial_clear(serial_t *obj) {
}
void serial_pinout_tx(PinName tx) {
// pinmap_pinout(tx, PinMap_UART_TX);
}
void serial_break_set(serial_t *obj) {
// obj->uart->C2 |= UARTLP_C2_SBK_MASK;
}
void serial_break_clear(serial_t *obj) {
// obj->uart->C2 &= ~UARTLP_C2_SBK_MASK;
}