diff options
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 |
