diff options
| author | Scott Shawcroft <scott@tannewt.org> | 2017-09-22 18:05:51 -0700 |
|---|---|---|
| committer | Dan Halbert <halbert@halwitz.org> | 2017-09-22 21:05:51 -0400 |
| commit | 6839fff31303463d5c7942387fa498895edf1abf (patch) | |
| tree | f4c5b94c6534c8d5c65ea6b7209cd2d681508f5f /atmel-samd/asf4/samd21/hal/src | |
| parent | 3ad01ddb04b160b74b4baee9fce043da17dbcef5 (diff) | |
Move to ASF4 and introduce SAMD51 support. (#258)3.0.0-alpha.0
* atmel-samd: Remove ASF3. This will break builds.
* atmel-samd: Add ASF4 for the SAMD21 and SAMD51.
* Introduce the supervisor concept to facilitate porting.
The supervisor is the code which runs individual MicroPython VMs. By
splitting it out we make it more consistent and easier to find.
This also adds very basic SAMD21 and SAMD51 support using the
supervisor. Only the REPL currently works.
This begins the work for #178.
Diffstat (limited to 'atmel-samd/asf4/samd21/hal/src')
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_adc_sync.c | 254 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_atomic.c | 76 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_dac_sync.c | 141 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_delay.c | 90 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_flash.c | 324 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_gpio.c | 54 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_i2c_m_sync.c | 260 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_init.c | 57 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_io.c | 73 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_pwm.c | 169 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_sleep.c | 83 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_spi_m_sync.c | 212 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_timer.c | 263 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_usart_sync.c | 285 | ||||
| -rw-r--r-- | atmel-samd/asf4/samd21/hal/src/hal_usb_device.c | 602 |
15 files changed, 2943 insertions, 0 deletions
diff --git a/atmel-samd/asf4/samd21/hal/src/hal_adc_sync.c b/atmel-samd/asf4/samd21/hal/src/hal_adc_sync.c new file mode 100644 index 000000000..9c7c3ab52 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_adc_sync.c @@ -0,0 +1,254 @@ +/** + * \file + * + * \brief ADC functionality implementation. + * + * Copyright (C) 2014-2016 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 + * + */ + +/** + * \brief Indicates HAL being compiled. Must be defined before including. + */ +#define _COMPILING_HAL + +#include "hal_adc_sync.h" +#include <utils_assert.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief Maximum amount of ADC interface instances + */ +#define MAX_ADC_AMOUNT ADC_INST_NUM + +/** + * \brief Initialize ADC + */ +int32_t adc_sync_init(struct adc_sync_descriptor *const descr, void *const hw, void *const func) +{ + ASSERT(descr && hw); + + return _adc_sync_init(&descr->device, hw); +} + +/** + * \brief Deinitialize ADC + */ +int32_t adc_sync_deinit(struct adc_sync_descriptor *const descr) +{ + ASSERT(descr); + _adc_sync_deinit(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Enable ADC + */ +int32_t adc_sync_enable_channel(struct adc_sync_descriptor *const descr, const uint8_t channel) +{ + ASSERT(descr); + _adc_sync_enable_channel(&descr->device, channel); + + return ERR_NONE; +} + +/** + * \brief Disable ADC + */ +int32_t adc_sync_disable_channel(struct adc_sync_descriptor *const descr, const uint8_t channel) +{ + ASSERT(descr); + _adc_sync_disable_channel(&descr->device, channel); + return ERR_NONE; +} + +/* + * \brief Read data from ADC + */ +int32_t adc_sync_read_channel(struct adc_sync_descriptor *const descr, const uint8_t channel, uint8_t *const buffer, + const uint16_t length) +{ + uint8_t data_size; + uint16_t offset = 0; + + ASSERT(descr && buffer && length); + data_size = _adc_sync_get_data_size(&descr->device); + ASSERT(!(length % data_size)); + + do { + uint16_t result; + _adc_sync_convert(&descr->device); + + while (!_adc_sync_is_channel_conversion_done(&descr->device, channel)) + ; + + result = _adc_sync_read_channel_data(&descr->device, channel); + buffer[offset] = result; + if (1 < data_size) { + buffer[offset + 1] = result >> 8; + } + offset += data_size; + } while (offset < length); + + return offset; +} + +/** + * \brief Set ADC reference source + */ +int32_t adc_sync_set_reference(struct adc_sync_descriptor *const descr, const adc_reference_t reference) +{ + ASSERT(descr); + _adc_sync_set_reference_source(&descr->device, reference); + + return ERR_NONE; +} + +/** + * \brief Set ADC resolution + */ +int32_t adc_sync_set_resolution(struct adc_sync_descriptor *const descr, const adc_resolution_t resolution) +{ + ASSERT(descr); + _adc_sync_set_resolution(&descr->device, resolution); + + return ERR_NONE; +} + +/** + * \brief Set ADC input source of a channel + */ +int32_t adc_sync_set_inputs(struct adc_sync_descriptor *const descr, const adc_pos_input_t pos_input, + const adc_neg_input_t neg_input, const uint8_t channel) +{ + ASSERT(descr); + _adc_sync_set_inputs(&descr->device, pos_input, neg_input, channel); + + return ERR_NONE; +} + +/** + * \brief Set ADC thresholds + */ +int32_t adc_sync_set_thresholds(struct adc_sync_descriptor *const descr, const adc_threshold_t low_threshold, + const adc_threshold_t up_threshold) +{ + ASSERT(descr); + _adc_sync_set_thresholds(&descr->device, low_threshold, up_threshold); + + return ERR_NONE; +} + +/** + * \brief Set ADC gain + */ +int32_t adc_sync_set_channel_gain(struct adc_sync_descriptor *const descr, const uint8_t channel, const adc_gain_t gain) +{ + ASSERT(descr); + _adc_sync_set_channel_gain(&descr->device, channel, gain); + + return ERR_NONE; +} + +/** + * \brief Set ADC conversion mode + */ +int32_t adc_sync_set_conversion_mode(struct adc_sync_descriptor *const descr, const enum adc_conversion_mode mode) +{ + ASSERT(descr); + _adc_sync_set_conversion_mode(&descr->device, mode); + + return ERR_NONE; +} + +/** + * \brief Set ADC differential mode + */ +int32_t adc_sync_set_channel_differential_mode(struct adc_sync_descriptor *const descr, const uint8_t channel, + const enum adc_differential_mode mode) +{ + ASSERT(descr); + _adc_sync_set_channel_differential_mode(&descr->device, channel, mode); + + return ERR_NONE; +} + +/** + * \brief Set ADC window mode + */ +int32_t adc_sync_set_window_mode(struct adc_sync_descriptor *const descr, const adc_window_mode_t mode) +{ + ASSERT(descr); + _adc_sync_set_window_mode(&descr->device, mode); + + return ERR_NONE; +} + +/** + * \brief Retrieve threshold state + */ +int32_t adc_sync_get_threshold_state(const struct adc_sync_descriptor *const descr, adc_threshold_status_t *const state) +{ + ASSERT(descr && state); + _adc_sync_get_threshold_state(&descr->device, state); + + return ERR_NONE; +} + +/** + * \brief Check if conversion is complete + */ +int32_t adc_sync_is_channel_conversion_complete(const struct adc_sync_descriptor *const descr, const uint8_t channel) +{ + ASSERT(descr); + return _adc_sync_is_channel_conversion_done(&descr->device, channel); +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t adc_sync_get_version(void) +{ + return DRIVER_VERSION; +} + +//@} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_atomic.c b/atmel-samd/asf4/samd21/hal/src/hal_atomic.c new file mode 100644 index 000000000..82a11e2bd --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_atomic.c @@ -0,0 +1,76 @@ +/** + * \file + * + * \brief Critical sections related functionality implementation. + * + * Copyright (C) 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 + * + */ + +#include "hal_atomic.h" + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief Disable interrupts, enter critical section + */ +void atomic_enter_critical(hal_atomic_t volatile *atomic) +{ + *atomic = __get_PRIMASK(); + __disable_irq(); + __DMB(); +} + +/** + * \brief Exit atomic section + */ +void atomic_leave_critical(hal_atomic_t volatile *atomic) +{ + __DMB(); + __set_PRIMASK(*atomic); +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t atomic_get_version(void) +{ + return DRIVER_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_dac_sync.c b/atmel-samd/asf4/samd21/hal/src/hal_dac_sync.c new file mode 100644 index 000000000..a56e6aef7 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_dac_sync.c @@ -0,0 +1,141 @@ +/** + * \file + * + * \brief DAC functionality implementation. + * + * Copyright (C) 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 + * + */ + +#include "hal_dac_sync.h" +#include <utils_assert.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief Initialize the DAC HAL instance and hardware. + */ +int32_t dac_sync_init(struct dac_sync_descriptor *const descr, void *const hw) +{ + uint8_t i; + int32_t rc; + + ASSERT(descr && hw); + + rc = _dac_sync_init(&descr->device, hw); + if (rc) { + return rc; + } + + for (i = 0; i < CHANNEL_NUM; i++) { + descr->sel_ch[i].buffer = NULL; + descr->sel_ch[i].length = 0; + } + + return ERR_NONE; +} + +/** + * \brief Deinitialize the DAC HAL instance and hardware + */ +int32_t dac_sync_deinit(struct dac_sync_descriptor *const descr) +{ + ASSERT(descr); + + _dac_sync_deinit(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Enable DAC channel + */ +int32_t dac_sync_enable_channel(struct dac_sync_descriptor *const descr, const uint8_t ch) +{ + ASSERT(descr && (ch < CHANNEL_NUM)); + + _dac_sync_enable_channel(&descr->device, ch); + + return ERR_NONE; +} + +/** + * \brief Disable DAC channel + */ +int32_t dac_sync_disable_channel(struct dac_sync_descriptor *const descr, const uint8_t ch) +{ + ASSERT(descr && (ch < CHANNEL_NUM)); + + _dac_sync_disable_channel(&descr->device, ch); + + return ERR_NONE; +} + +/** + * \brief DAC convert digital data to analog output + */ +int32_t dac_sync_write(struct dac_sync_descriptor *descr, const uint8_t ch, uint16_t *buffer, uint32_t length) +{ + ASSERT(descr && (ch < CHANNEL_NUM) && buffer && length); + + /* check whether channel is enable */ + if (!_dac_sync_is_channel_enable(&descr->device, ch)) { + return ERR_NOT_READY; + } + + descr->sel_ch[ch].buffer = buffer; + descr->sel_ch[ch].length = length; + + while (descr->sel_ch[ch].length) { + _dac_sync_write_data(&descr->device, *(descr->sel_ch[ch].buffer), ch); + descr->sel_ch[ch].buffer++; + descr->sel_ch[ch].length--; + } + + return ERR_NONE; +} + +/** + * \brief Get DAC driver version + */ +uint32_t dac_sync_get_version(void) +{ + return DRIVER_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_delay.c b/atmel-samd/asf4/samd21/hal/src/hal_delay.c new file mode 100644 index 000000000..ce963db00 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_delay.c @@ -0,0 +1,90 @@ +/** + * \file + * + * \brief HAL delay related functionality implementation. + * + * Copyright (C) 2014-2016 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 + * + */ + +#include <hpl_irq.h> +#include <hpl_reset.h> +#include <hpl_sleep.h> +#include "hal_delay.h" +#include <hpl_delay.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief The pointer to a hardware instance used by the driver. + */ +static void *hardware; + +/** + * \brief Initialize Delay driver + */ +void delay_init(void *const hw) +{ + _delay_init(hardware = hw); +} + +/** + * \brief Perform delay in us + */ +void delay_us(const uint16_t us) +{ + _delay_cycles(hardware, _get_cycles_for_us(us)); +} + +/** + * \brief Perform delay in ms + */ +void delay_ms(const uint16_t ms) +{ + _delay_cycles(hardware, _get_cycles_for_ms(ms)); +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t delay_get_version(void) +{ + return DRIVER_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_flash.c b/atmel-samd/asf4/samd21/hal/src/hal_flash.c new file mode 100644 index 000000000..f3cc4bbfe --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_flash.c @@ -0,0 +1,324 @@ +/** + * \file + * + * \brief Flash functionality implementation. + * + * Copyright (C) 2015 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 + * + */ + +#include "hal_flash.h" +#include <utils_assert.h> +#include <utils.h> +#include <hal_atomic.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +static void flash_ready(struct _flash_device *device); +static void flash_error(struct _flash_device *device); + +static int32_t flash_is_address_aligned(struct flash_descriptor *flash, const uint32_t flash_addr); + +/** + * \brief Initialize the FLASH HAL instance and hardware for callback mode. + */ +int32_t flash_init(struct flash_descriptor *flash, void *const hw) +{ + int32_t rc; + + ASSERT(flash && hw); + + rc = _flash_init(&flash->dev, hw); + if (rc) { + return rc; + } + + flash->dev.flash_cb.ready_cb = flash_ready; + flash->dev.flash_cb.error_cb = flash_error; + + return ERR_NONE; +} + +/** + * \brief Deinitialize the FLASH HAL instance. + */ +int32_t flash_deinit(struct flash_descriptor *flash) +{ + ASSERT(flash); + + _flash_deinit(&flash->dev); + + return ERR_NONE; +} + +/** + * \brief Reads a number of bytes to a page in the internal Flash + */ +int32_t flash_read(struct flash_descriptor *flash, uint32_t src_addr, uint8_t *buffer, uint32_t length) +{ + ASSERT(flash && buffer && length); + + uint32_t page_size = _flash_get_page_size(&flash->dev); + uint32_t total_pages = _flash_get_total_pages(&flash->dev); + + /* Check if the address is valid */ + if ((src_addr > page_size * total_pages) || (src_addr + length > page_size * total_pages)) { + return ERR_BAD_ADDRESS; + } + + _flash_read(&flash->dev, src_addr, buffer, length); + + return ERR_NONE; +} + +/** + * \brief Updates several bytes to the internal Flash + */ +int32_t flash_write(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length) +{ + ASSERT(flash && buffer && length); + + uint32_t page_size = _flash_get_page_size(&flash->dev); + uint32_t total_pages = _flash_get_total_pages(&flash->dev); + + /* Check if the address is valid */ + if ((dst_addr > page_size * total_pages) || (dst_addr + length > page_size * total_pages)) { + return ERR_BAD_ADDRESS; + } + + if (_flash_is_locked(&flash->dev, dst_addr)) { + return ERR_DENIED; + } + + _flash_write(&flash->dev, dst_addr, buffer, length); + + return ERR_NONE; +} + +/** + * \brief Appends a number of bytes to a page in the internal Flash + */ +int32_t flash_append(struct flash_descriptor *flash, uint32_t dst_addr, uint8_t *buffer, uint32_t length) +{ + ASSERT(flash && buffer && length); + + uint32_t page_size = _flash_get_page_size(&flash->dev); + uint32_t total_pages = _flash_get_total_pages(&flash->dev); + + /* Check if the address is valid */ + if ((dst_addr > page_size * total_pages) || (dst_addr + length > page_size * total_pages)) { + return ERR_BAD_ADDRESS; + } + + if (_flash_is_locked(&flash->dev, dst_addr)) { + return ERR_DENIED; + } + + _flash_append(&flash->dev, dst_addr, buffer, length); + + return ERR_NONE; +} + +/** + * \brief Execute erase in the internal flash + */ +int32_t flash_erase(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums) +{ + ASSERT(flash && page_nums); + uint32_t page_size = _flash_get_page_size(&flash->dev); + uint32_t total_pages = _flash_get_total_pages(&flash->dev); + int32_t rc; + + rc = flash_is_address_aligned(flash, dst_addr); + if (rc) { + return rc; + } + + if ((page_nums > total_pages) || (dst_addr / page_size + page_nums > total_pages)) { + return ERR_INVALID_ARG; + } + + _flash_erase(&flash->dev, dst_addr, page_nums); + + return ERR_NONE; +} + +/** + * \brief Register a function as FLASH transfer completion callback + */ +int32_t flash_register_callback(struct flash_descriptor *flash, const enum flash_cb_type type, flash_cb_t func) +{ + ASSERT(flash); + + switch (type) { + case FLASH_CB_READY: + flash->callbacks.cb_ready = func; + break; + + case FLASH_CB_ERROR: + flash->callbacks.cb_error = func; + break; + + default: + return ERR_INVALID_ARG; + } + + _flash_set_irq_state(&flash->dev, (enum _flash_cb_type)type, NULL != func); + + return ERR_NONE; +} + +/** + * \brief Execute lock in the internal flash + */ +int32_t flash_lock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums) +{ + ASSERT(flash && page_nums); + uint32_t page_size = _flash_get_page_size(&flash->dev); + uint32_t total_pages = _flash_get_total_pages(&flash->dev); + int32_t rc; + + rc = flash_is_address_aligned(flash, dst_addr); + if (rc) { + return rc; + } + + if ((page_nums > total_pages) || (dst_addr / page_size + page_nums > total_pages)) { + return ERR_INVALID_ARG; + } + + return _flash_lock(&flash->dev, dst_addr, page_nums); +} + +/** + * \brief Execute unlock in the internal flash + */ +int32_t flash_unlock(struct flash_descriptor *flash, const uint32_t dst_addr, const uint32_t page_nums) +{ + ASSERT(flash && page_nums); + uint32_t page_size = _flash_get_page_size(&flash->dev); + uint32_t total_pages = _flash_get_total_pages(&flash->dev); + int32_t rc; + + rc = flash_is_address_aligned(flash, dst_addr); + if (rc) { + return rc; + } + + if ((page_nums > total_pages) || (dst_addr / page_size + page_nums > total_pages)) { + return ERR_INVALID_ARG; + } + + return _flash_unlock(&flash->dev, dst_addr, page_nums); +} + +/** + * \brief Get the flash page size. + */ +uint32_t flash_get_page_size(struct flash_descriptor *flash) +{ + ASSERT(flash); + return _flash_get_page_size(&flash->dev); +} + +/** + * \brief Get the numbers of flash page. + */ +uint32_t flash_get_total_pages(struct flash_descriptor *flash) +{ + ASSERT(flash); + return _flash_get_total_pages(&flash->dev); +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t flash_get_version(void) +{ + return DRIVER_VERSION; +} + +/** + * \internal check the address whether it is aligned + * \param[in, out] flash Pointer to the HAL FLASH instance. + * \param[in] flash_addr address to be check in flash + * + * \return whether it is valid + * \retval 0 Valid. + * \retval -1 Error, invalid. + */ +static int32_t flash_is_address_aligned(struct flash_descriptor *flash, const uint32_t flash_addr) +{ + ASSERT(flash); + + uint32_t page_size = _flash_get_page_size(&flash->dev); + + /* Check if the read address not aligned to the start of a page */ + if (flash_addr & (page_size - 1)) { + return ERR_BAD_ADDRESS; + } + return ERR_NONE; +} + +/** + * \internal Ready for a new flash command + * + * \param[in] device The pointer to flash device structure + */ +static void flash_ready(struct _flash_device *device) +{ + struct flash_descriptor *const descr = CONTAINER_OF(device, struct flash_descriptor, dev); + if (descr->callbacks.cb_ready) { + descr->callbacks.cb_ready(descr); + } +} + +/** + * \internal Error occurs in flash command + * + * \param[in] device The pointer to flash device structure + */ +static void flash_error(struct _flash_device *device) +{ + struct flash_descriptor *const descr = CONTAINER_OF(device, struct flash_descriptor, dev); + if (descr->callbacks.cb_error) { + descr->callbacks.cb_error(descr); + } +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_gpio.c b/atmel-samd/asf4/samd21/hal/src/hal_gpio.c new file mode 100644 index 000000000..319726290 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_gpio.c @@ -0,0 +1,54 @@ +/** + * \file + * + * \brief Port + * + * Copyright (C) 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 + * + */ + +#include "hal_gpio.h" + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +uint32_t gpio_get_version(void) +{ + return DRIVER_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_i2c_m_sync.c b/atmel-samd/asf4/samd21/hal/src/hal_i2c_m_sync.c new file mode 100644 index 000000000..c72fe2758 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_i2c_m_sync.c @@ -0,0 +1,260 @@ +/** + * \file + * + * \brief I/O I2C related functionality implementation. + * + * Copyright (C) 2014-2016 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 + * + */ +#include <hal_i2c_m_sync.h> +#include <utils.h> +#include <utils_assert.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief Sync version of I2C I/O read + */ +static int32_t i2c_m_sync_read(struct io_descriptor *io, uint8_t *buf, const uint16_t n) +{ + struct i2c_m_sync_desc *i2c = CONTAINER_OF(io, struct i2c_m_sync_desc, io); + struct _i2c_m_msg msg; + int32_t ret; + + msg.addr = i2c->slave_addr; + msg.len = n; + msg.flags = I2C_M_STOP | I2C_M_RD; + msg.buffer = buf; + + ret = _i2c_m_sync_transfer(&i2c->device, &msg); + + return (((int32_t)n) > i2c->device.service.msg.len) ? (((int32_t)n) - i2c->device.service.msg.len) : ret; +} + +/** + * \brief Sync version of I2C I/O write + */ +static int32_t i2c_m_sync_write(struct io_descriptor *io, const uint8_t *buf, const uint16_t n) +{ + struct i2c_m_sync_desc *i2c = CONTAINER_OF(io, struct i2c_m_sync_desc, io); + struct _i2c_m_msg msg; + int32_t ret; + + msg.addr = i2c->slave_addr; + msg.len = n; + msg.flags = I2C_M_STOP; + msg.buffer = (uint8_t *)buf; + + ret = _i2c_m_sync_transfer(&i2c->device, &msg); + + return (((int32_t)n) > i2c->device.service.msg.len) ? (((int32_t)n) - i2c->device.service.msg.len) : ret; +} + +/** + * \brief Sync version of i2c initialize + */ +int32_t i2c_m_sync_init(struct i2c_m_sync_desc *i2c, void *hw) +{ + int32_t init_status; + ASSERT(i2c); + + init_status = _i2c_m_sync_init(&i2c->device, hw); + if (init_status) { + return init_status; + } + + /* Init I/O */ + i2c->io.read = i2c_m_sync_read; + i2c->io.write = i2c_m_sync_write; + + return ERR_NONE; +} + +/** + * \brief deinitialize + */ +int32_t i2c_m_sync_deinit(struct i2c_m_sync_desc *i2c) +{ + int32_t status; + ASSERT(i2c); + + status = _i2c_m_sync_deinit(&i2c->device); + if (status) { + return status; + } + + i2c->io.read = NULL; + i2c->io.write = NULL; + + return ERR_NONE; +} + +/** + * \brief Sync version of i2c enable + */ +int32_t i2c_m_sync_enable(struct i2c_m_sync_desc *i2c) +{ + return _i2c_m_sync_enable(&i2c->device); +} + +/** + * \brief Sync version of i2c disable + */ +int32_t i2c_m_sync_disable(struct i2c_m_sync_desc *i2c) +{ + return _i2c_m_sync_disable(&i2c->device); +} + +/** + * \brief Sync version of i2c set slave address + */ +int32_t i2c_m_sync_set_slaveaddr(struct i2c_m_sync_desc *i2c, int16_t addr, int32_t addr_len) +{ + return i2c->slave_addr = (addr & 0x3ff) | (addr_len & I2C_M_TEN); +} + +/** + * \brief Sync version of i2c set baudrate + */ +int32_t i2c_m_sync_set_baudrate(struct i2c_m_sync_desc *i2c, uint32_t clkrate, uint32_t baudrate) +{ + return _i2c_m_sync_set_baudrate(&i2c->device, clkrate, baudrate); +} + +/** + * \brief Sync version of i2c write command + */ +int32_t i2c_m_sync_cmd_write(struct i2c_m_sync_desc *i2c, uint8_t reg, uint8_t *buffer, uint8_t length) +{ + struct _i2c_m_msg msg; + int32_t ret; + + msg.addr = i2c->slave_addr; + msg.len = 1; + msg.flags = 0; + msg.buffer = ® + + ret = _i2c_m_sync_transfer(&i2c->device, &msg); + + if (ret != 0) { + /* error occurred */ + return ret; + } + + msg.flags = I2C_M_STOP; + msg.buffer = buffer; + msg.len = length; + + ret = _i2c_m_sync_transfer(&i2c->device, &msg); + + if (ret != 0) { + /* error occurred */ + return ret; + } + + return ERR_NONE; +} + +/** + * \brief Sync version of i2c read command + */ +int32_t i2c_m_sync_cmd_read(struct i2c_m_sync_desc *i2c, uint8_t reg, uint8_t *buffer, uint8_t length) +{ + struct _i2c_m_msg msg; + int32_t ret; + + msg.addr = i2c->slave_addr; + msg.len = 1; + msg.flags = 0; + msg.buffer = ® + + ret = _i2c_m_sync_transfer(&i2c->device, &msg); + + if (ret != 0) { + /* error occurred */ + return ret; + } + + msg.flags = I2C_M_STOP | I2C_M_RD; + msg.buffer = buffer; + msg.len = length; + + ret = _i2c_m_sync_transfer(&i2c->device, &msg); + + if (ret != 0) { + /* error occurred */ + return ret; + } + + return ERR_NONE; +} + +/** + * \brief Sync version of i2c transfer command + */ +int32_t i2c_m_sync_transfer(struct i2c_m_sync_desc *const i2c, struct _i2c_m_msg *msg) +{ + return _i2c_m_sync_transfer(&i2c->device, msg); +} + +/** + * \brief Sync version of i2c send stop condition command + */ +int32_t i2c_m_sync_send_stop(struct i2c_m_sync_desc *const i2c) +{ + return _i2c_m_sync_send_stop(&i2c->device); +} + +/** + * \brief Retrieve I/O descriptor + */ +int32_t i2c_m_sync_get_io_descriptor(struct i2c_m_sync_desc *const i2c, struct io_descriptor **io) +{ + *io = &i2c->io; + return ERR_NONE; +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t i2c_m_sync_get_version(void) +{ + return DRIVER_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_init.c b/atmel-samd/asf4/samd21/hal/src/hal_init.c new file mode 100644 index 000000000..bdcf2a409 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_init.c @@ -0,0 +1,57 @@ +/** + * \file + * + * \brief HAL initialization related functionality implementation. + * + * Copyright (C) 2014-2015 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 + * + */ + +#include "hal_init.h" + +/** + * \brief Driver version + */ +#define HAL_INIT_VERSION 0x00000001u + +/** + * \brief Retrieve the current driver version + */ +uint32_t init_get_version(void) +{ + return HAL_INIT_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_io.c b/atmel-samd/asf4/samd21/hal/src/hal_io.c new file mode 100644 index 000000000..52638d9b0 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_io.c @@ -0,0 +1,73 @@ +/** + * \file + * + * \brief I/O functionality implementation. + * + * Copyright (C) 2015 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 + * + */ + +#include <hal_io.h> +#include <utils_assert.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +uint32_t io_get_version(void) +{ + return DRIVER_VERSION; +} + +/** + * \brief I/O write interface + */ +int32_t io_write(struct io_descriptor *const io_descr, const uint8_t *const buf, const uint16_t length) +{ + ASSERT(io_descr && buf); + return io_descr->write(io_descr, buf, length); +} + +/** + * \brief I/O read interface + */ +int32_t io_read(struct io_descriptor *const io_descr, uint8_t *const buf, const uint16_t length) +{ + ASSERT(io_descr && buf); + return io_descr->read(io_descr, buf, length); +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_pwm.c b/atmel-samd/asf4/samd21/hal/src/hal_pwm.c new file mode 100644 index 000000000..2b9d2606f --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_pwm.c @@ -0,0 +1,169 @@ +/** + * \file + * + * \brief PWM functionality implementation. + * + * Copyright (C) 2015 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 + * + */ + +#include "hal_pwm.h" +#include <utils_assert.h> +#include <utils.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +static void pwm_period_expired(struct _pwm_device *device); +static void pwm_detect_fault(struct _pwm_device *device); + +/** + * \brief Initialize pwm + */ +int32_t pwm_init(struct pwm_descriptor *const descr, void *const hw, struct _pwm_hpl_interface *const func) +{ + ASSERT(descr && hw); + _pwm_init(&descr->device, hw); + descr->device.callback.pwm_period_cb = pwm_period_expired; + descr->device.callback.pwm_error_cb = pwm_detect_fault; + return ERR_NONE; +} + +/** + * \brief Deinitialize pwm + */ +int32_t pwm_deinit(struct pwm_descriptor *const descr) +{ + ASSERT(descr); + _pwm_deinit(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Start pwm + */ +int32_t pwm_enable(struct pwm_descriptor *const descr) +{ + ASSERT(descr); + if (_pwm_is_enabled(&descr->device)) { + return ERR_DENIED; + } + _pwm_enable(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Stop pwm + */ +int32_t pwm_disable(struct pwm_descriptor *const descr) +{ + ASSERT(descr); + if (!_pwm_is_enabled(&descr->device)) { + return ERR_DENIED; + } + _pwm_disable(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Register PWM callback + */ +int32_t pwm_register_callback(struct pwm_descriptor *const descr, enum pwm_callback_type type, pwm_cb_t cb) +{ + switch (type) { + case PWM_PERIOD_CB: + descr->pwm_cb.period = cb; + break; + + case PWM_ERROR_CB: + descr->pwm_cb.error = cb; + break; + + default: + return ERR_INVALID_ARG; + } + ASSERT(descr); + _pwm_set_irq_state(&descr->device, (enum _pwm_callback_type)type, NULL != cb); + return ERR_NONE; +} + +/** + * \brief Change PWM parameter + */ +int32_t pwm_set_parameters(struct pwm_descriptor *const descr, const pwm_period_t period, const pwm_period_t duty_cycle) +{ + ASSERT(descr); + _pwm_set_param(&descr->device, period, duty_cycle); + return ERR_NONE; +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t pwm_get_version(void) +{ + return DRIVER_VERSION; +} + +/** + * \internal Process interrupts caused by period experied + */ +static void pwm_period_expired(struct _pwm_device *device) +{ + struct pwm_descriptor *const descr = CONTAINER_OF(device, struct pwm_descriptor, device); + + if (descr->pwm_cb.period) { + descr->pwm_cb.period(descr); + } +} + +/** + * \internal Process interrupts caused by pwm fault + */ +static void pwm_detect_fault(struct _pwm_device *device) +{ + struct pwm_descriptor *const descr = CONTAINER_OF(device, struct pwm_descriptor, device); + + if (descr->pwm_cb.error) { + descr->pwm_cb.error(descr); + } +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_sleep.c b/atmel-samd/asf4/samd21/hal/src/hal_sleep.c new file mode 100644 index 000000000..2d1aadd67 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_sleep.c @@ -0,0 +1,83 @@ +/** + * \file + * + * \brief Sleep related functionality implementation. + * + * Copyright (C) 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 + * + */ + +#include "hal_sleep.h" +#include <hpl_sleep.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief Set the sleep mode of the device and put the MCU to sleep + * + * For an overview of which systems are disabled in sleep for the different + * sleep modes, see the data sheet. + * + * \param[in] mode Sleep mode to use + * + * \return The status of a sleep request + * \retval -1 The requested sleep mode was invalid or not available + * \retval 0 The operation completed successfully, returned after leaving the + * sleep + */ +int sleep(const uint8_t mode) +{ + if (ERR_NONE != _set_sleep_mode(mode)) + return ERR_INVALID_ARG; + + _go_to_sleep(); + + return ERR_NONE; +} + +/** + * \brief Retrieve the current driver version + * + * \return Current driver version + */ +uint32_t sleep_get_version(void) +{ + return DRIVER_VERSION; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_spi_m_sync.c b/atmel-samd/asf4/samd21/hal/src/hal_spi_m_sync.c new file mode 100644 index 000000000..8ceaa9a4a --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_spi_m_sync.c @@ -0,0 +1,212 @@ +/** + * \file + * + * \brief I/O SPI related functionality implementation. + * + * Copyright (C) 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 + * + */ + +#include "hal_spi_m_sync.h" +#include <utils_assert.h> +#include <utils.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \brief Driver version + */ +#define SPI_M_SYNC_DRIVER_VERSION 0x00000001u + +#define SPI_DEACTIVATE_NEXT 0x8000 + +static int32_t _spi_m_sync_io_write(struct io_descriptor *const io, const uint8_t *const buf, const uint16_t length); +static int32_t _spi_m_sync_io_read(struct io_descriptor *const io, uint8_t *const buf, const uint16_t length); + +int32_t spi_m_sync_init(struct spi_m_sync_descriptor *spi, void *const hw) +{ + int32_t rc = 0; + + ASSERT(spi && hw); + + spi->dev.prvt = (void *)hw; + + rc = _spi_m_sync_init(&spi->dev, hw); + if (rc < 0) { + return rc; + } + + spi->flags = SPI_DEACTIVATE_NEXT; + spi->io.read = _spi_m_sync_io_read; + spi->io.write = _spi_m_sync_io_write; + + return ERR_NONE; +} + +void spi_m_sync_deinit(struct spi_m_sync_descriptor *spi) +{ + ASSERT(spi); + + _spi_m_sync_deinit(&spi->dev); +} + +void spi_m_sync_enable(struct spi_m_sync_descriptor *spi) +{ + ASSERT(spi); + + _spi_m_sync_enable(&spi->dev); +} + +void spi_m_sync_disable(struct spi_m_sync_descriptor *spi) +{ + ASSERT(spi); + + _spi_m_sync_disable(&spi->dev); +} + +int32_t spi_m_sync_set_baudrate(struct spi_m_sync_descriptor *spi, const uint32_t baud_val) +{ + ASSERT(spi); + + return _spi_m_sync_set_baudrate(&spi->dev, baud_val); +} + +int32_t spi_m_sync_set_mode(struct spi_m_sync_descriptor *spi, const enum spi_transfer_mode mode) +{ + ASSERT(spi); + + return _spi_m_sync_set_mode(&spi->dev, mode); +} + +int32_t spi_m_sync_set_char_size(struct spi_m_sync_descriptor *spi, const enum spi_char_size char_size) +{ + ASSERT(spi); + + return _spi_m_sync_set_char_size(&spi->dev, char_size); +} + +int32_t spi_m_sync_set_data_order(struct spi_m_sync_descriptor *spi, const enum spi_data_order dord) +{ + ASSERT(spi); + + return _spi_m_sync_set_data_order(&spi->dev, dord); +} + +/** \brief Do SPI read in polling way + * For SPI master, activate CS, do send 0xFFs and read data, deactivate CS. + * + * It blocks until all data read or error. + * + * \param[in, out] spi Pointer to the HAL SPI instance. + * \param[out] buf Pointer to the buffer to store read data. + * \param[in] size Size of the data in number of characters. + * \return Operation status. + * \retval size Success. + * \retval >=0 Time out, with number of characters read. + */ +static int32_t _spi_m_sync_io_read(struct io_descriptor *io, uint8_t *buf, const uint16_t length) +{ + ASSERT(io); + + struct spi_m_sync_descriptor *spi = CONTAINER_OF(io, struct spi_m_sync_descriptor, io); + struct spi_xfer xfer; + + xfer.rxbuf = buf; + xfer.txbuf = 0; + xfer.size = length; + + return spi_m_sync_transfer(spi, &xfer); +} + +/** \brief Do SPI data write in polling way + * For SPI master, activate CS, do buffer send and deactivate CS. The data back + * is discarded. + * + * The data read back is discarded. + * + * It blocks until all data sent or error. + * + * \param[in, out] spi Pointer to the HAL SPI instance. + * \param[in] p_xfer Pointer to the transfer information (\ref spi_transfer). + * \return Operation status. + * \retval size Success. + * \retval >=0 Timeout, with number of characters transferred. + */ +static int32_t _spi_m_sync_io_write(struct io_descriptor *const io, const uint8_t *const buf, const uint16_t length) +{ + ASSERT(io); + + struct spi_m_sync_descriptor *spi = CONTAINER_OF(io, struct spi_m_sync_descriptor, io); + struct spi_xfer xfer; + + xfer.rxbuf = 0; + xfer.txbuf = (uint8_t *)buf; + xfer.size = length; + + return spi_m_sync_transfer(spi, &xfer); +} + +int32_t spi_m_sync_transfer(struct spi_m_sync_descriptor *spi, const struct spi_xfer *p_xfer) +{ + struct spi_msg msg; + + ASSERT(spi && p_xfer); + + msg.txbuf = p_xfer->txbuf; + msg.rxbuf = p_xfer->rxbuf; + msg.size = p_xfer->size; + + return _spi_m_sync_trans(&spi->dev, &msg); +} + +int32_t spi_m_sync_get_io_descriptor(struct spi_m_sync_descriptor *const spi, struct io_descriptor **io) +{ + ASSERT(spi && io); + *io = &spi->io; + return 0; +} + +uint32_t spi_m_sync_get_version(void) +{ + return SPI_M_SYNC_DRIVER_VERSION; +} + +#ifdef __cplusplus +} +#endif diff --git a/atmel-samd/asf4/samd21/hal/src/hal_timer.c b/atmel-samd/asf4/samd21/hal/src/hal_timer.c new file mode 100644 index 000000000..08e096a1b --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_timer.c @@ -0,0 +1,263 @@ +/** + * \file + * + * \brief Timer functionality implementation. + * + * Copyright (C) 2014 - 2016 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 + * + */ + +#include "hal_timer.h" +#include <utils_assert.h> +#include <utils.h> +#include <hal_atomic.h> +#include <hpl_irq.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +/** + * \brief Timer flags + */ +#define TIMER_FLAG_QUEUE_IS_TAKEN 1 +#define TIMER_FLAG_INTERRUPT_TRIGERRED 2 + +static void timer_add_timer_task(struct list_descriptor *list, struct timer_task *const new_task, const uint32_t time); +static void timer_process_counted(struct _timer_device *device); + +/** + * \brief Initialize timer + */ +int32_t timer_init(struct timer_descriptor *const descr, void *const hw, struct _timer_hpl_interface *const func) +{ + ASSERT(descr && hw); + _timer_init(&descr->device, hw); + descr->time = 0; + descr->device.timer_cb.period_expired = timer_process_counted; + + return ERR_NONE; +} + +/** + * \brief Deinitialize timer + */ +int32_t timer_deinit(struct timer_descriptor *const descr) +{ + ASSERT(descr); + _timer_deinit(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Start timer + */ +int32_t timer_start(struct timer_descriptor *const descr) +{ + ASSERT(descr); + if (_timer_is_started(&descr->device)) { + return ERR_DENIED; + } + _timer_start(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Stop timer + */ +int32_t timer_stop(struct timer_descriptor *const descr) +{ + ASSERT(descr); + if (!_timer_is_started(&descr->device)) { + return ERR_DENIED; + } + _timer_stop(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Set amount of clock cycler per timer tick + */ +int32_t timer_set_clock_cycles_per_tick(struct timer_descriptor *const descr, const uint32_t clock_cycles) +{ + ASSERT(descr); + _timer_set_period(&descr->device, clock_cycles); + + return ERR_NONE; +} + +/** + * \brief Add timer task + */ +int32_t timer_add_task(struct timer_descriptor *const descr, struct timer_task *const task) +{ + ASSERT(descr && task); + + descr->flags |= TIMER_FLAG_QUEUE_IS_TAKEN; + if (is_list_element(&descr->tasks, task)) { + descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN; + ASSERT(false); + return ERR_ALREADY_INITIALIZED; + } + task->time_label = descr->time; + timer_add_timer_task(&descr->tasks, task, descr->time); + + descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN; + if (descr->flags & TIMER_FLAG_INTERRUPT_TRIGERRED) { + CRITICAL_SECTION_ENTER() + descr->flags &= ~TIMER_FLAG_INTERRUPT_TRIGERRED; + _timer_set_irq(&descr->device); + CRITICAL_SECTION_LEAVE() + } + + return ERR_NONE; +} + +/** + * \brief Remove timer task + */ +int32_t timer_remove_task(struct timer_descriptor *const descr, const struct timer_task *const task) +{ + ASSERT(descr && task); + + descr->flags |= TIMER_FLAG_QUEUE_IS_TAKEN; + if (!is_list_element(&descr->tasks, task)) { + descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN; + ASSERT(false); + return ERR_NOT_FOUND; + } + list_delete_element(&descr->tasks, task); + + descr->flags &= ~TIMER_FLAG_QUEUE_IS_TAKEN; + if (descr->flags & TIMER_FLAG_INTERRUPT_TRIGERRED) { + CRITICAL_SECTION_ENTER() + descr->flags &= ~TIMER_FLAG_INTERRUPT_TRIGERRED; + _timer_set_irq(&descr->device); + CRITICAL_SECTION_LEAVE() + } + + return ERR_NONE; +} + +/** + * \brief Retrieve the amount of clock cycles in a tick + */ +int32_t timer_get_clock_cycles_in_tick(const struct timer_descriptor *const descr, uint32_t *const cycles) +{ + ASSERT(descr && cycles); + *cycles = _timer_get_period(&descr->device); + return ERR_NONE; +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t timer_get_version(void) +{ + return DRIVER_VERSION; +} + +/** + * \internal Insert a timer task into sorted timer's list + * + * \param[in] head The pointer to the head of timer task list + * \param[in] task The pointer to task to add + * \param[in] time Current timer time + */ +static void timer_add_timer_task(struct list_descriptor *list, struct timer_task *const new_task, const uint32_t time) +{ + struct timer_task *it, *prev = NULL, *head = (struct timer_task *)list_get_head(list); + + if (!head) { + list_insert_as_head(list, new_task); + return; + } + + for (it = head; it; it = (struct timer_task *)list_get_next_element(it)) { + uint32_t time_left; + + if (it->time_label <= time) { + time_left = it->interval - (time - it->time_label); + } else { + time_left = it->interval - (0xFFFFFFFF - it->time_label) - time; + } + if (time_left >= new_task->interval) + break; + prev = it; + } + + if (it == head) { + list_insert_as_head(list, new_task); + } else { + list_insert_after(prev, new_task); + } +} + +/** + * \internal Process interrupts + */ +static void timer_process_counted(struct _timer_device *device) +{ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" + struct timer_descriptor *timer = CONTAINER_OF(device, struct timer_descriptor, device); + #pragma GCC diagnostic pop + struct timer_task * it = (struct timer_task *)list_get_head(&timer->tasks); + uint32_t time = ++timer->time; + + if ((timer->flags & TIMER_FLAG_QUEUE_IS_TAKEN) || (timer->flags & TIMER_FLAG_INTERRUPT_TRIGERRED)) { + timer->flags |= TIMER_FLAG_INTERRUPT_TRIGERRED; + return; + } + + while (it && ((time - it->time_label) >= it->interval)) { + struct timer_task *tmp = it; + + list_remove_head(&timer->tasks); + if (TIMER_TASK_REPEAT == tmp->mode) { + tmp->time_label = time; + timer_add_timer_task(&timer->tasks, tmp, time); + } + it = (struct timer_task *)list_get_head(&timer->tasks); + + tmp->cb(tmp); + } +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_usart_sync.c b/atmel-samd/asf4/samd21/hal/src/hal_usart_sync.c new file mode 100644 index 000000000..ccc832db8 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_usart_sync.c @@ -0,0 +1,285 @@ +/** + * \file + * + * \brief I/O USART related functionality implementation. + * + * Copyright (C) 2014 - 2016 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 + * + */ + +#include "hal_usart_sync.h" +#include <utils_assert.h> +#include <utils.h> + +/** + * \brief Driver version + */ +#define DRIVER_VERSION 0x00000001u + +static int32_t usart_sync_write(struct io_descriptor *const io_descr, const uint8_t *const buf, const uint16_t length); +static int32_t usart_sync_read(struct io_descriptor *const io_descr, uint8_t *const buf, const uint16_t length); + +/** + * \brief Initialize usart interface + */ +int32_t usart_sync_init(struct usart_sync_descriptor *const descr, void *const hw, void *const func) +{ + int32_t init_status; + ASSERT(descr && hw); + init_status = _usart_sync_init(&descr->device, hw); + if (init_status) { + return init_status; + } + + descr->io.read = usart_sync_read; + descr->io.write = usart_sync_write; + + return ERR_NONE; +} + +/** + * \brief Uninitialize usart interface + */ +int32_t usart_sync_deinit(struct usart_sync_descriptor *const descr) +{ + ASSERT(descr); + _usart_sync_deinit(&descr->device); + + descr->io.read = NULL; + descr->io.write = NULL; + + return ERR_NONE; +} + +/** + * \brief Enable usart interface + */ +int32_t usart_sync_enable(struct usart_sync_descriptor *const descr) +{ + ASSERT(descr); + _usart_sync_enable(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Disable usart interface + */ +int32_t usart_sync_disable(struct usart_sync_descriptor *const descr) +{ + ASSERT(descr); + _usart_sync_disable(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Retrieve I/O descriptor + */ +int32_t usart_sync_get_io_descriptor(struct usart_sync_descriptor *const descr, struct io_descriptor **io) +{ + ASSERT(descr && io); + + *io = &descr->io; + return ERR_NONE; +} + +/** + * \brief Specify action for flow control pins + */ +int32_t usart_sync_set_flow_control(struct usart_sync_descriptor *const descr, + const union usart_flow_control_state state) +{ + ASSERT(descr); + _usart_sync_set_flow_control_state(&descr->device, state); + + return ERR_NONE; +} + +/** + * \brief Set usart baud rate + */ +int32_t usart_sync_set_baud_rate(struct usart_sync_descriptor *const descr, const uint32_t baud_rate) +{ + ASSERT(descr); + _usart_sync_set_baud_rate(&descr->device, baud_rate); + + return ERR_NONE; +} + +/** + * \brief Set usart data order + */ +int32_t usart_sync_set_data_order(struct usart_sync_descriptor *const descr, const enum usart_data_order data_order) +{ + ASSERT(descr); + _usart_sync_set_data_order(&descr->device, data_order); + + return ERR_NONE; +} + +/** + * \brief Set usart mode + */ +int32_t usart_sync_set_mode(struct usart_sync_descriptor *const descr, const enum usart_mode mode) +{ + ASSERT(descr); + _usart_sync_set_mode(&descr->device, mode); + + return ERR_NONE; +} + +/** + * \brief Set usart parity + */ +int32_t usart_sync_set_parity(struct usart_sync_descriptor *const descr, const enum usart_parity parity) +{ + ASSERT(descr); + _usart_sync_set_parity(&descr->device, parity); + + return ERR_NONE; +} + +/** + * \brief Set usart stop bits + */ +int32_t usart_sync_set_stopbits(struct usart_sync_descriptor *const descr, const enum usart_stop_bits stop_bits) +{ + ASSERT(descr); + _usart_sync_set_stop_bits(&descr->device, stop_bits); + + return ERR_NONE; +} + +/** + * \brief Set usart character size + */ +int32_t usart_sync_set_character_size(struct usart_sync_descriptor *const descr, const enum usart_character_size size) +{ + ASSERT(descr); + _usart_sync_set_character_size(&descr->device, size); + + return ERR_NONE; +} + +/** + * \brief Retrieve the state of flow control pins + */ +int32_t usart_sync_flow_control_status(const struct usart_sync_descriptor *const descr, + union usart_flow_control_state *const state) +{ + ASSERT(descr && state); + *state = _usart_sync_get_flow_control_state(&descr->device); + + return ERR_NONE; +} + +/** + * \brief Check if the usart transmitter is empty + */ +int32_t usart_sync_is_tx_empty(const struct usart_sync_descriptor *const descr) +{ + ASSERT(descr); + return _usart_sync_is_byte_sent(&descr->device); +} + +/** + * \brief Check if the usart receiver is not empty + */ +int32_t usart_sync_is_rx_not_empty(const struct usart_sync_descriptor *const descr) +{ + ASSERT(descr); + return _usart_sync_is_byte_received(&descr->device); +} + +/** + * \brief Retrieve the current driver version + */ +uint32_t usart_sync_get_version(void) +{ + return DRIVER_VERSION; +} + +/* + * \internal Write the given data to usart interface + * + * \param[in] descr The pointer to an io descriptor + * \param[in] buf Data to write to usart + * \param[in] length The number of bytes to write + * + * \return The number of bytes written. + */ +static int32_t usart_sync_write(struct io_descriptor *const io_descr, const uint8_t *const buf, const uint16_t length) +{ + uint32_t offset = 0; + struct usart_sync_descriptor *descr = CONTAINER_OF(io_descr, struct usart_sync_descriptor, io); + + ASSERT(io_descr && buf && length); + while (!_usart_sync_is_byte_sent(&descr->device)) + ; + do { + _usart_sync_write_byte(&descr->device, buf[offset]); + while (!_usart_sync_is_byte_sent(&descr->device)) + ; + } while (++offset < length); + + return (int32_t)offset; +} + +/* + * \internal Read data from usart interface + * + * \param[in] descr The pointer to an io descriptor + * \param[in] buf A buffer to read data to + * \param[in] length The size of a buffer + * + * \return The number of bytes read. + */ +static int32_t usart_sync_read(struct io_descriptor *const io_descr, uint8_t *const buf, const uint16_t length) +{ + uint32_t offset = 0; + struct usart_sync_descriptor *descr = CONTAINER_OF(io_descr, struct usart_sync_descriptor, io); + + ASSERT(io_descr && buf && length); + do { + while (!_usart_sync_is_byte_received(&descr->device)) + ; + buf[offset] = _usart_sync_read_byte(&descr->device); + } while (++offset < length); + + return (int32_t)offset; +} diff --git a/atmel-samd/asf4/samd21/hal/src/hal_usb_device.c b/atmel-samd/asf4/samd21/hal/src/hal_usb_device.c new file mode 100644 index 000000000..f0efd9ff5 --- /dev/null +++ b/atmel-samd/asf4/samd21/hal/src/hal_usb_device.c @@ -0,0 +1,602 @@ +/** + * \file + * + * \brief SAM USB device HAL + * + * Copyright (C) 2015-2016 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 + * + */ + +#include "hal_usb_device.h" +#include "hal_atomic.h" + +#include <string.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** USB device HAL driver version. */ +#define USB_D_VERSION 0x00000001u + +/** + * Endpoint callbacks for data transfer. + */ +struct usb_d_ep_callbacks { + /** Callback that is invoked when setup packet is received. */ + usb_d_ep_cb_setup_t req; + /** Callback invoked when buffer is done, but last packet is full size + * packet without ZLP. Return \c true if new transfer has been submitted. + */ + usb_d_ep_cb_more_t more; + /** Callback invoked when transfer is finished/halted/aborted or error + * occurs. + */ + usb_d_ep_cb_xfer_t xfer; +}; + +/** + * Endpoint transfer descriptor header. + */ +struct usb_ep_xfer_hdr { + /** Transfer type, reuse \ref usb_ep_type. */ + uint8_t type; + /** Endpoint address. */ + uint8_t ep; + /** Endpoint state. */ + uint8_t state; + /** Last status code. */ + uint8_t status; +}; + +/** + * Transfer descriptor. + */ +struct usb_ep_xfer { + /** General transfer descriptor. */ + struct usb_ep_xfer_hdr hdr; + /** Pointer to data buffer. */ + uint8_t *buf; + /** Transfer size. */ + uint32_t size; + /** Control request packet. */ + uint8_t req[8]; +}; + +/** + * USB device endpoint descriptor. + */ +struct usb_d_ep { + /** On-going transfer on the endpoint. */ + struct usb_ep_xfer xfer; + /** Endpoint callbacks. */ + struct usb_d_ep_callbacks callbacks; +}; + +/** + * USB device HAL driver descriptor. + */ +struct usb_d_descriptor { + /** USB device endpoints. */ + struct usb_d_ep ep[CONF_USB_D_NUM_EP_SP]; +}; + +/** The USB HAL driver descriptor instance. */ +static struct usb_d_descriptor usb_d_inst; + +/** \brief Find the endpoint. + * \param[in] ep Endpoint address. + * \return Index of endpoint descriptor. + * \retval >=0 The index. + * \retval <0 Not found (endpoint is not initialized). + */ +static int8_t _usb_d_find_ep(const uint8_t ep) +{ + int8_t i; + for (i = 0; i < CONF_USB_D_NUM_EP_SP; i++) { + if (usb_d_inst.ep[i].xfer.hdr.ep == ep) { + return i; + } + if (usb_d_inst.ep[i].xfer.hdr.type == USB_EP_XTYPE_CTRL + && (ep & USB_EP_N_MASK) == usb_d_inst.ep[i].xfer.hdr.ep) { + return i; + } + } + return -1; +} + +/** + * \brief Start transactions + * \param[in] ep Endpoint address. + * \param[in] dir Endpoint transfer direction. + * \param[in] buf Pointer to transfer buffer. + * \param[in] size Transfer size. + * \param[in] zlp Auto append ZLP for IN, or wait ZLP for OUT. + */ +static inline int32_t _usb_d_trans(const uint8_t ep, const bool dir, const uint8_t *buf, const uint32_t size, + const uint8_t zlp) +{ + struct usb_d_transfer trans + = {(uint8_t *)buf, size, dir ? (uint8_t)(ep | USB_EP_DIR) : (uint8_t)(ep & USB_EP_N_MASK), zlp}; + + return _usb_d_dev_ep_trans(&trans); +} + +/** + * \brief Dummy callback that returns false + * \param[in] unused0 Unused parameter. + * \param[in] unused1 Unused parameter. + * \param[in] unused2 Unused parameter. + * \return Always \c false. + */ +static bool usb_d_dummy_cb_false(uint32_t unused0, uint32_t unused1, uint32_t unused2) +{ + (void)unused0; + (void)unused1; + (void)unused2; + return false; +} + +/** + * \brief Callback invoked when SETUP packet is ready + * \param[in] ep Endpoint number with transfer direction on bit 8. + */ +static void usb_d_cb_trans_setup(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + uint8_t * req = ept->xfer.req; + + uint8_t n = _usb_d_dev_ep_read_req(ep, req); + if (n != 8) { + _usb_d_dev_ep_stall(ep, USB_EP_STALL_SET); + _usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_SET); + return; + } + + _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR); + _usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_CLR); + ept->xfer.hdr.state = USB_EP_S_IDLE; + if (!ept->callbacks.req(ep, req)) { + ept->xfer.hdr.state = USB_EP_S_HALTED; + _usb_d_dev_ep_stall(ep, USB_EP_STALL_SET); + _usb_d_dev_ep_stall(ep | USB_EP_DIR, USB_EP_STALL_SET); + } +} + +/** + * \brief Callback invoked when request more data + * \param[in] ep Endpoint number with transfer direction on bit 8. + * \param[in] transfered Number of bytes transfered. + */ +static bool usb_d_cb_trans_more(const uint8_t ep, const uint32_t transfered) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + if (ept->xfer.hdr.state == USB_EP_S_X_DATA) { + return ept->callbacks.more(ep, transfered); + } + return false; +} + +/** + * \brief Handles the case that control endpoint transactions are done + * \param[in,out] ept Pointer to endpoint information. + */ +static inline void usb_d_ctrl_trans_done(struct usb_d_ep *ept) +{ + uint8_t state = ept->xfer.hdr.state; + bool req_dir = USB_GET_bmRequestType(ept->xfer.req) & USB_REQ_TYPE_IN; + + if (state == USB_EP_S_X_DATA) { + /* Data stage -> Status stage */ + bool err = ept->callbacks.xfer(ept->xfer.hdr.ep, USB_XFER_DATA, ept->xfer.req); + if (err) { + ept->xfer.hdr.state = USB_EP_S_HALTED; + ept->xfer.hdr.status = USB_XFER_HALT; + _usb_d_dev_ep_stall(req_dir ? ept->xfer.hdr.ep : (ept->xfer.hdr.ep | USB_EP_DIR), USB_EP_STALL_SET); + } else { + ept->xfer.hdr.state = USB_EP_S_X_STATUS; + _usb_d_trans(ept->xfer.hdr.ep, !req_dir, NULL, 0, 1); + } + } else { + /* Status stage done */ + ept->callbacks.xfer(ept->xfer.hdr.ep, USB_XFER_DONE, ept->xfer.req); + ept->xfer.hdr.state = USB_EP_S_X_SETUP; + } +} + +/** + * Callback when USB transactions are finished. + */ +static void _usb_d_cb_trans_done(const uint8_t ep, const int32_t code, const uint32_t transferred) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + + if (code == USB_TRANS_DONE) { + ept->xfer.hdr.status = USB_XFER_DONE; + if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) { + usb_d_ctrl_trans_done(ept); + return; + } + ept->xfer.hdr.state = USB_EP_S_IDLE; + } else if (code == USB_TRANS_STALL) { + ept->xfer.hdr.status = USB_XFER_HALT; + if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) { + ept->xfer.hdr.state = USB_EP_S_X_SETUP; + _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR); + } else { + ept->xfer.hdr.state = USB_EP_S_HALTED; + } + } else if (code == USB_TRANS_ABORT) { + ept->xfer.hdr.status = USB_XFER_ABORT; + if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) { + ept->xfer.hdr.state = USB_EP_S_X_SETUP; + return; + } + ept->xfer.hdr.state = USB_EP_S_IDLE; + } else if (code == USB_TRANS_RESET) { + ept->xfer.hdr.state = USB_EP_S_DISABLED; + ept->xfer.hdr.status = USB_XFER_RESET; + } else { + ept->xfer.hdr.state = USB_EP_S_ERROR; + ept->xfer.hdr.status = USB_XFER_ERROR; + } + + ept->callbacks.xfer(ep, (enum usb_xfer_code)ept->xfer.hdr.status, (void *)transferred); +} + +int32_t usb_d_init(void) +{ + int32_t rc = _usb_d_dev_init(); + uint8_t i; + if (rc < 0) { + return rc; + } + memset(usb_d_inst.ep, 0x00, sizeof(struct usb_d_ep) * CONF_USB_D_NUM_EP_SP); + for (i = 0; i < CONF_USB_D_NUM_EP_SP; i++) { + usb_d_inst.ep[i].xfer.hdr.ep = 0xFF; + usb_d_inst.ep[i].callbacks.req = (usb_d_ep_cb_setup_t)usb_d_dummy_cb_false; + usb_d_inst.ep[i].callbacks.more = (usb_d_ep_cb_more_t)usb_d_dummy_cb_false; + usb_d_inst.ep[i].callbacks.xfer = (usb_d_ep_cb_xfer_t)usb_d_dummy_cb_false; + } + /* Handles device driver endpoint callbacks to build transfer. */ + _usb_d_dev_register_ep_callback(USB_D_DEV_EP_CB_SETUP, (FUNC_PTR)usb_d_cb_trans_setup); + _usb_d_dev_register_ep_callback(USB_D_DEV_EP_CB_MORE, (FUNC_PTR)usb_d_cb_trans_more); + _usb_d_dev_register_ep_callback(USB_D_DEV_EP_CB_DONE, (FUNC_PTR)_usb_d_cb_trans_done); + return ERR_NONE; +} + +void usb_d_deinit(void) +{ + _usb_d_dev_deinit(); +} + +void usb_d_register_callback(const enum usb_d_cb_type type, const FUNC_PTR func) +{ + /* Directly uses device driver callback. */ + _usb_d_dev_register_callback(type, func); +} + +int32_t usb_d_enable(void) +{ + return _usb_d_dev_enable(); +} + +void usb_d_disable(void) +{ + _usb_d_dev_disable(); +} + +void usb_d_attach(void) +{ + _usb_d_dev_attach(); +} + +void usb_d_detach(void) +{ + _usb_d_dev_detach(); +} + +enum usb_speed usb_d_get_speed(void) +{ + return _usb_d_dev_get_speed(); +} + +uint16_t usb_d_get_frame_num(void) +{ + return _usb_d_dev_get_frame_n(); +} + +uint8_t usb_d_get_uframe_num(void) +{ + return _usb_d_dev_get_uframe_n(); +} + +void usb_d_set_address(const uint8_t addr) +{ + _usb_d_dev_set_address(addr); +} + +void usb_d_send_remotewakeup(void) +{ + _usb_d_dev_send_remotewakeup(); +} + +int32_t usb_d_ep0_init(const uint8_t max_pkt_size) +{ + return usb_d_ep_init(0, USB_EP_XTYPE_CTRL, max_pkt_size); +} + +int32_t usb_d_ep_init(const uint8_t ep, const uint8_t attr, const uint16_t max_pkt_size) +{ + int32_t rc; + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + if (ep_index >= 0) { + return -USB_ERR_REDO; + } else { + ep_index = _usb_d_find_ep(0xFF); + if (ep_index < 0) { + return -USB_ERR_ALLOC_FAIL; + } + ept = &usb_d_inst.ep[ep_index]; + } + rc = _usb_d_dev_ep_init(ep, attr, max_pkt_size); + if (rc < 0) { + return rc; + } + ept->xfer.hdr.ep = ep; + ept->xfer.hdr.type = attr & USB_EP_XTYPE_MASK; + return ERR_NONE; +} + +void usb_d_ep_deinit(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + if (ep_index < 0) { + return; + } + _usb_d_dev_ep_deinit(ep); + ept->xfer.hdr.ep = 0xFF; +} + +int32_t usb_d_ep_enable(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + int32_t rc; + if (ep_index < 0) { + return -USB_ERR_PARAM; + } + ept->xfer.hdr.state = (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) ? USB_EP_S_X_SETUP : USB_EP_S_IDLE; + rc = _usb_d_dev_ep_enable(ep); + if (rc < 0) { + ept->xfer.hdr.state = USB_EP_S_DISABLED; + } + return rc; +} + +void usb_d_ep_disable(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + if (ep_index < 0) { + return; + } + _usb_d_dev_ep_disable(ep); + ept->xfer.hdr.state = USB_EP_S_DISABLED; +} + +uint8_t *usb_d_ep_get_req(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + if (ep_index < 0) { + return NULL; + } + return usb_d_inst.ep[ep_index].xfer.req; +} + +int32_t usb_d_ep_transfer(const struct usb_d_transfer *xfer) +{ + int8_t ep_index = _usb_d_find_ep(xfer->ep); + struct usb_d_ep * ept = &usb_d_inst.ep[ep_index]; + bool dir = USB_EP_GET_DIR(xfer->ep), zlp = xfer->zlp; + uint32_t len = xfer->size; + int32_t rc; + volatile uint8_t state; + volatile hal_atomic_t flags; + + if (ep_index < 0) { + return -USB_ERR_PARAM; + } + + atomic_enter_critical(&flags); + state = ept->xfer.hdr.state; + if (state == USB_EP_S_IDLE) { + ept->xfer.hdr.state = USB_EP_S_X_DATA; + atomic_leave_critical(&flags); + } else { + atomic_leave_critical(&flags); + switch (state) { + case USB_EP_S_HALTED: + return USB_HALTED; + case USB_EP_S_ERROR: + return -USB_ERROR; + case USB_EP_S_DISABLED: + return -USB_ERR_FUNC + 1; + default: /* USB_EP_S_X_xxxx */ + return USB_BUSY; + } + } + + if (ept->xfer.hdr.type == USB_EP_XTYPE_CTRL) { + uint16_t req_len = USB_GET_wLength(ept->xfer.req); + /* SETUP without data: ZLP IN as status. */ + if (req_len == 0) { + dir = true; + len = 0; + zlp = true; + ept->xfer.hdr.state = USB_EP_S_X_STATUS; + } else { + dir = (USB_GET_bmRequestType(ept->xfer.req) & USB_REQ_TYPE_IN); + /* Data length not exceed requested. */ + if (len > req_len) { + len = req_len; + } + if (dir) { + /* Setup -> In */ + zlp = (req_len > len); + } else { + zlp = false; + } + } + } + + rc = _usb_d_trans(xfer->ep, dir, xfer->buf, len, zlp); + return rc; +} + +void usb_d_ep_abort(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + if (ep_index < 0) { + return; + } + _usb_d_dev_ep_abort(ep); + ept->xfer.hdr.state = USB_EP_S_IDLE; + ept->xfer.hdr.status = USB_XFER_ABORT; +} + +int32_t usb_d_ep_get_status(const uint8_t ep, struct usb_d_ep_status *stat) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep * ept = &usb_d_inst.ep[ep_index]; + struct usb_d_trans_status tmp; + uint8_t state = ept->xfer.hdr.state; + if (ep_index < 0) { + return -USB_ERR_PARAM; + } + if (stat) { + /* Check transaction status if transferring data. */ + _usb_d_dev_ep_get_status(ep, &tmp); + stat->ep = ep; + stat->state = state; + stat->code = ept->xfer.hdr.status; + stat->count = tmp.count; + stat->size = tmp.size; + } + switch (state) { + case USB_EP_S_IDLE: + return USB_OK; + case USB_EP_S_HALTED: + return USB_HALTED; + case USB_EP_S_ERROR: + return -USB_ERROR; + case USB_EP_S_DISABLED: + return -USB_ERR_FUNC; + default: + /* Busy */ + return USB_BUSY; + } +} + +static inline int32_t _usb_d_ep_halt_clr(const uint8_t ep) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + int32_t rc; + if (ep_index < 0) { + return -USB_ERR_PARAM; + } + if (ept->xfer.hdr.state == USB_EP_S_HALTED) { + rc = _usb_d_dev_ep_stall(ep, USB_EP_STALL_CLR); + if (rc < 0) { + return rc; + } + ept->xfer.hdr.state = USB_EP_S_IDLE; + ept->xfer.hdr.status = USB_XFER_UNHALT; + ept->callbacks.xfer(ep, USB_XFER_UNHALT, NULL); + } + return ERR_NONE; +} + +int32_t usb_d_ep_halt(const uint8_t ep, const enum usb_ep_halt_ctrl ctrl) +{ + if (ctrl == USB_EP_HALT_CLR) { + return _usb_d_ep_halt_clr(ep); + } else if (ctrl == USB_EP_HALT_SET) { + return _usb_d_dev_ep_stall(ep, USB_EP_STALL_SET); + } else { + return _usb_d_dev_ep_stall(ep, USB_EP_STALL_GET); + } +} + +void usb_d_ep_register_callback(const uint8_t ep, const enum usb_d_ep_cb_type type, const FUNC_PTR func) +{ + int8_t ep_index = _usb_d_find_ep(ep); + struct usb_d_ep *ept = &usb_d_inst.ep[ep_index]; + FUNC_PTR f = func ? (FUNC_PTR)func : (FUNC_PTR)usb_d_dummy_cb_false; + if (ep_index < 0) { + return; + } + switch (type) { + case USB_D_EP_CB_SETUP: + ept->callbacks.req = (usb_d_ep_cb_setup_t)f; + break; + case USB_D_EP_CB_MORE: + ept->callbacks.more = (usb_d_ep_cb_more_t)f; + break; + case USB_D_EP_CB_XFER: + ept->callbacks.xfer = (usb_d_ep_cb_xfer_t)f; + break; + default: + break; + } +} + +uint32_t usb_d_get_version(void) +{ + return USB_D_VERSION; +} + +#ifdef __cplusplus +} +#endif |
