mirror of https://github.com/ARMmbed/mbed-os.git
* 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
parent
5f120e40de
commit
cbcf0a8ed7
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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__ = . ;
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -94,6 +94,9 @@ typedef enum {
|
|||
PB29 = 61,
|
||||
PB30 = 62,
|
||||
PB31 = 63,
|
||||
|
||||
USBTX = PA04,
|
||||
USBRX = PA05,
|
||||
|
||||
// Not connected
|
||||
NC = (int)0xFFFFFFFF
|
||||
|
|
|
@ -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[] = {
|
||||
};
|
|
@ -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
|
||||
|
|
|
@ -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, ~)
|
|
@ -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 */
|
|
@ -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>
|
||||
|
|
@ -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
|
||||
}
|
|
@ -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 */
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue