atmel-samd: Introduce audio sample playback via audioio.AudioOut.
This commit is contained in:
parent
30b8091df0
commit
58b9789d0c
@ -48,7 +48,8 @@ INC += -Iasf/common/services/usb/udc/
|
||||
INC += -Iasf/common/utils
|
||||
INC += -Iasf/common2/services/delay/
|
||||
INC += $(addprefix -Iasf/sam0/,\
|
||||
drivers/extint/ \
|
||||
drivers/events \
|
||||
drivers/extint \
|
||||
drivers/port \
|
||||
drivers/system \
|
||||
drivers/adc/adc_sam_d_r \
|
||||
@ -107,7 +108,6 @@ CFLAGS_CORTEX_M0 = \
|
||||
-ffunction-sections \
|
||||
-fdata-sections \
|
||||
-fshort-enums \
|
||||
-flto \
|
||||
-D ARM_MATH_CM0PLUS=true \
|
||||
-DSYSTICK_MODE \
|
||||
-DEXTINT_CALLBACK_MODE=true \
|
||||
@ -118,6 +118,7 @@ CFLAGS_CORTEX_M0 = \
|
||||
-DDAC_CALLBACK_MODE=false \
|
||||
-DTCC_ASYNC=false \
|
||||
-DADC_CALLBACK_MODE=false \
|
||||
-DEVENTS_INTERRUPT_HOOKS_MODE=false \
|
||||
-DTC_ASYNC=true \
|
||||
-DUSB_DEVICE_LPM_SUPPORT \
|
||||
--param max-inline-insns-single=500
|
||||
@ -129,7 +130,7 @@ CFLAGS = $(INC) -Wall -Werror -std=gnu11 -nostdlib $(CFLAGS_CORTEX_M0) $(COPT)
|
||||
ifeq ($(DEBUG), 1)
|
||||
CFLAGS += -Os -ggdb -DNDEBUG -DENABLE_MICRO_TRACE_BUFFER
|
||||
else
|
||||
CFLAGS += -Os -DNDEBUG
|
||||
CFLAGS += -Os -DNDEBUG -flto
|
||||
endif
|
||||
|
||||
ifneq ($(FROZEN_DIR),)
|
||||
@ -152,6 +153,8 @@ LIBS = -larm_cortexM0l_math -lm -lgcc -lc
|
||||
SRC_ASF = $(addprefix asf/sam0/,\
|
||||
drivers/adc/adc_sam_d_r/adc.c \
|
||||
drivers/dac/dac_sam_d_c/dac.c \
|
||||
drivers/dma/dma.c \
|
||||
drivers/events/events_sam_d_r/events.c \
|
||||
drivers/extint/extint_callback.c \
|
||||
drivers/extint/extint_sam_d_r/extint.c \
|
||||
drivers/nvm/nvm.c \
|
||||
@ -183,6 +186,7 @@ SRC_C = \
|
||||
moduos.c \
|
||||
mphalport.c \
|
||||
samd21_pins.c \
|
||||
shared_dma.c \
|
||||
rgb_led_status.c \
|
||||
tick.c \
|
||||
$(FLASH_IMPL) \
|
||||
@ -228,6 +232,8 @@ SRC_BINDINGS = \
|
||||
analogio/__init__.c \
|
||||
analogio/AnalogIn.c \
|
||||
analogio/AnalogOut.c \
|
||||
audioio/__init__.c \
|
||||
audioio/AudioOut.c \
|
||||
digitalio/__init__.c \
|
||||
digitalio/DigitalInOut.c \
|
||||
pulseio/__init__.c \
|
||||
|
654
atmel-samd/asf/sam0/drivers/dma/dma.c
Normal file
654
atmel-samd/asf/sam0/drivers/dma/dma.c
Normal file
@ -0,0 +1,654 @@
|
||||
/*
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Direct Memory Access Controller Driver
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "dma.h"
|
||||
#include "clock.h"
|
||||
#include "system_interrupt.h"
|
||||
|
||||
struct _dma_module {
|
||||
volatile bool _dma_init;
|
||||
volatile uint32_t allocated_channels;
|
||||
uint8_t free_channels;
|
||||
};
|
||||
|
||||
struct _dma_module _dma_inst = {
|
||||
._dma_init = false,
|
||||
.allocated_channels = 0,
|
||||
.free_channels = CONF_MAX_USED_CHANNEL_NUM,
|
||||
};
|
||||
|
||||
/** Maximum retry counter for resuming a job transfer. */
|
||||
#define MAX_JOB_RESUME_COUNT 10000
|
||||
|
||||
/** DMA channel mask. */
|
||||
#define DMA_CHANNEL_MASK (0x1f)
|
||||
|
||||
COMPILER_ALIGNED(16)
|
||||
DmacDescriptor descriptor_section[CONF_MAX_USED_CHANNEL_NUM] SECTION_DMAC_DESCRIPTOR;
|
||||
|
||||
/** Initial write back memory section. */
|
||||
COMPILER_ALIGNED(16)
|
||||
static DmacDescriptor _write_back_section[CONF_MAX_USED_CHANNEL_NUM] SECTION_DMAC_DESCRIPTOR;
|
||||
|
||||
/** Internal DMA resource pool. */
|
||||
static struct dma_resource* _dma_active_resource[CONF_MAX_USED_CHANNEL_NUM];
|
||||
|
||||
/* DMA channel interrup flag. */
|
||||
uint8_t g_chan_interrupt_flag[CONF_MAX_USED_CHANNEL_NUM]={0};
|
||||
|
||||
/**
|
||||
* \brief Find a free channel for a DMA resource.
|
||||
*
|
||||
* Find a channel for the requested DMA resource.
|
||||
*
|
||||
* \return Status of channel allocation.
|
||||
* \retval DMA_INVALID_CHANNEL No channel available
|
||||
* \retval count Allocated channel for the DMA resource
|
||||
*/
|
||||
static uint8_t _dma_find_first_free_channel_and_allocate(void)
|
||||
{
|
||||
uint8_t count;
|
||||
uint32_t tmp;
|
||||
bool allocated = false;
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
tmp = _dma_inst.allocated_channels;
|
||||
|
||||
for (count = 0; count < CONF_MAX_USED_CHANNEL_NUM; ++count) {
|
||||
if (!(tmp & 0x00000001)) {
|
||||
/* If free channel found, set as allocated and return
|
||||
*number */
|
||||
|
||||
_dma_inst.allocated_channels |= 1 << count;
|
||||
_dma_inst.free_channels--;
|
||||
allocated = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp >> 1;
|
||||
}
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
if (!allocated) {
|
||||
return DMA_INVALID_CHANNEL;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Release an allocated DMA channel.
|
||||
*
|
||||
* \param[in] channel Channel id to be released
|
||||
*
|
||||
*/
|
||||
static void _dma_release_channel(uint8_t channel)
|
||||
{
|
||||
_dma_inst.allocated_channels &= ~(1 << channel);
|
||||
_dma_inst.free_channels++;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Configure the DMA resource.
|
||||
*
|
||||
* \param[in] dma_resource Pointer to a DMA resource instance
|
||||
* \param[out] resource_config Configurations of the DMA resource
|
||||
*
|
||||
*/
|
||||
static void _dma_set_config(struct dma_resource *resource,
|
||||
struct dma_resource_config *resource_config)
|
||||
{
|
||||
Assert(resource);
|
||||
Assert(resource_config);
|
||||
uint32_t temp_CHCTRLB_reg;
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/** Select the DMA channel and clear software trigger */
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
DMAC->SWTRIGCTRL.reg &= (uint32_t)(~(1 << resource->channel_id));
|
||||
|
||||
temp_CHCTRLB_reg = DMAC_CHCTRLB_LVL(resource_config->priority) | \
|
||||
DMAC_CHCTRLB_TRIGSRC(resource_config->peripheral_trigger) | \
|
||||
DMAC_CHCTRLB_TRIGACT(resource_config->trigger_action);
|
||||
|
||||
|
||||
if(resource_config->event_config.input_action){
|
||||
temp_CHCTRLB_reg |= DMAC_CHCTRLB_EVIE | DMAC_CHCTRLB_EVACT(
|
||||
resource_config->event_config.input_action);
|
||||
}
|
||||
|
||||
/** Enable event output, the event output selection is configured in
|
||||
* each transfer descriptor */
|
||||
if (resource_config->event_config.event_output_enable) {
|
||||
temp_CHCTRLB_reg |= DMAC_CHCTRLB_EVOE;
|
||||
}
|
||||
|
||||
/* Write config to CTRLB register */
|
||||
DMAC->CHCTRLB.reg = temp_CHCTRLB_reg;
|
||||
|
||||
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief DMA interrupt service routine.
|
||||
*
|
||||
*/
|
||||
void DMAC_Handler( void )
|
||||
{
|
||||
uint8_t active_channel;
|
||||
struct dma_resource *resource;
|
||||
uint8_t isr;
|
||||
uint32_t write_size;
|
||||
uint32_t total_size;
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/* Get Pending channel */
|
||||
active_channel = DMAC->INTPEND.reg & DMAC_INTPEND_ID_Msk;
|
||||
|
||||
Assert(_dma_active_resource[active_channel]);
|
||||
|
||||
/* Get active DMA resource based on channel */
|
||||
resource = _dma_active_resource[active_channel];
|
||||
|
||||
/* Select the active channel */
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
isr = DMAC->CHINTFLAG.reg;
|
||||
|
||||
/* Calculate block transfer size of the DMA transfer */
|
||||
total_size = descriptor_section[resource->channel_id].BTCNT.reg;
|
||||
write_size = _write_back_section[resource->channel_id].BTCNT.reg;
|
||||
resource->transfered_size = total_size - write_size;
|
||||
|
||||
/* DMA channel interrupt handler */
|
||||
if (isr & DMAC_CHINTENCLR_TERR) {
|
||||
/* Clear transfer error flag */
|
||||
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR;
|
||||
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
|
||||
/* Execute the callback function */
|
||||
if ((resource->callback_enable & (1<<DMA_CALLBACK_TRANSFER_ERROR)) &&
|
||||
(resource->callback[DMA_CALLBACK_TRANSFER_ERROR])) {
|
||||
resource->callback[DMA_CALLBACK_TRANSFER_ERROR](resource);
|
||||
}
|
||||
} else if (isr & DMAC_CHINTENCLR_TCMPL) {
|
||||
/* Clear the transfer complete flag */
|
||||
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL;
|
||||
|
||||
/* Set job status */
|
||||
resource->job_status = STATUS_OK;
|
||||
|
||||
/* Execute the callback function */
|
||||
if ((resource->callback_enable & (1 << DMA_CALLBACK_TRANSFER_DONE)) &&
|
||||
(resource->callback[DMA_CALLBACK_TRANSFER_DONE])) {
|
||||
resource->callback[DMA_CALLBACK_TRANSFER_DONE](resource);
|
||||
}
|
||||
} else if (isr & DMAC_CHINTENCLR_SUSP) {
|
||||
/* Clear channel suspend flag */
|
||||
DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP;
|
||||
|
||||
/* Set job status */
|
||||
resource->job_status = STATUS_SUSPEND;
|
||||
|
||||
/* Execute the callback function */
|
||||
if ((resource->callback_enable & (1 << DMA_CALLBACK_CHANNEL_SUSPEND)) &&
|
||||
(resource->callback[DMA_CALLBACK_CHANNEL_SUSPEND])){
|
||||
resource->callback[DMA_CALLBACK_CHANNEL_SUSPEND](resource);
|
||||
}
|
||||
}
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes config with predefined default values.
|
||||
*
|
||||
* This function will initialize a given DMA configuration structure to
|
||||
* a set of known default values. This function should be called on
|
||||
* any new instance of the configuration structure before being
|
||||
* modified by the user application.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li Software trigger is used as the transfer trigger
|
||||
* \li Priority level 0
|
||||
* \li Only software/event trigger
|
||||
* \li Requires a trigger for each transaction
|
||||
* \li No event input /output
|
||||
* \li DMA channel is disabled during sleep mode (if has the feature)
|
||||
* \param[out] config Pointer to the configuration
|
||||
*
|
||||
*/
|
||||
void dma_get_config_defaults(struct dma_resource_config *config)
|
||||
{
|
||||
Assert(config);
|
||||
/* Set as priority 0 */
|
||||
config->priority = DMA_PRIORITY_LEVEL_0;
|
||||
/* Only software/event trigger */
|
||||
config->peripheral_trigger = 0;
|
||||
/* Transaction trigger */
|
||||
config->trigger_action = DMA_TRIGGER_ACTION_TRANSACTION;
|
||||
|
||||
/* Event configurations, no event input/output */
|
||||
config->event_config.input_action = DMA_EVENT_INPUT_NOACT;
|
||||
config->event_config.event_output_enable = false;
|
||||
#ifdef FEATURE_DMA_CHANNEL_STANDBY
|
||||
config->run_in_standby = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate a DMA with configurations.
|
||||
*
|
||||
* This function will allocate a proper channel for a DMA transfer request.
|
||||
*
|
||||
* \param[in,out] dma_resource Pointer to a DMA resource instance
|
||||
* \param[in] transfer_config Configurations of the DMA transfer
|
||||
*
|
||||
* \return Status of the allocation procedure.
|
||||
*
|
||||
* \retval STATUS_OK The DMA resource was allocated successfully
|
||||
* \retval STATUS_ERR_NOT_FOUND DMA resource allocation failed
|
||||
*/
|
||||
enum status_code dma_allocate(struct dma_resource *resource,
|
||||
struct dma_resource_config *config)
|
||||
{
|
||||
uint8_t new_channel;
|
||||
|
||||
Assert(resource);
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
if (!_dma_inst._dma_init) {
|
||||
/* Initialize clocks for DMA */
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
|
||||
system_ahb_clock_set_mask(MCLK_AHBMASK_DMAC);
|
||||
#else
|
||||
system_ahb_clock_set_mask(PM_AHBMASK_DMAC);
|
||||
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBB,
|
||||
PM_APBBMASK_DMAC);
|
||||
#endif
|
||||
|
||||
/* Perform a software reset before enable DMA controller */
|
||||
DMAC->CTRL.reg &= ~DMAC_CTRL_DMAENABLE;
|
||||
DMAC->CTRL.reg = DMAC_CTRL_SWRST;
|
||||
|
||||
/* Setup descriptor base address and write back section base
|
||||
* address */
|
||||
DMAC->BASEADDR.reg = (uint32_t)descriptor_section;
|
||||
DMAC->WRBADDR.reg = (uint32_t)_write_back_section;
|
||||
|
||||
/* Enable all priority level at the same time */
|
||||
DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xf);
|
||||
|
||||
_dma_inst._dma_init = true;
|
||||
}
|
||||
|
||||
/* Find the proper channel */
|
||||
new_channel = _dma_find_first_free_channel_and_allocate();
|
||||
|
||||
/* If no channel available, return not found */
|
||||
if (new_channel == DMA_INVALID_CHANNEL) {
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
return STATUS_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Set the channel */
|
||||
resource->channel_id = new_channel;
|
||||
|
||||
/** Perform a reset for the allocated channel */
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
DMAC->CHCTRLA.reg &= ~DMAC_CHCTRLA_ENABLE;
|
||||
DMAC->CHCTRLA.reg = DMAC_CHCTRLA_SWRST;
|
||||
|
||||
#ifdef FEATURE_DMA_CHANNEL_STANDBY
|
||||
if(config->run_in_standby){
|
||||
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_RUNSTDBY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** Configure the DMA control,channel registers and descriptors here */
|
||||
_dma_set_config(resource, config);
|
||||
|
||||
resource->descriptor = NULL;
|
||||
|
||||
/* Log the DMA resource into the internal DMA resource pool */
|
||||
_dma_active_resource[resource->channel_id] = resource;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free an allocated DMA resource.
|
||||
*
|
||||
* This function will free an allocated DMA resource.
|
||||
*
|
||||
* \param[in,out] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status of the free procedure.
|
||||
*
|
||||
* \retval STATUS_OK The DMA resource was freed successfully
|
||||
* \retval STATUS_BUSY The DMA resource was busy and can't be freed
|
||||
* \retval STATUS_ERR_NOT_INITIALIZED DMA resource was not initialized
|
||||
*/
|
||||
enum status_code dma_free(struct dma_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
Assert(resource->channel_id != DMA_INVALID_CHANNEL);
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/* Check if channel is busy */
|
||||
if (dma_is_busy(resource)) {
|
||||
system_interrupt_leave_critical_section();
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
/* Check if DMA resource was not allocated */
|
||||
if (!(_dma_inst.allocated_channels & (1 << resource->channel_id))) {
|
||||
system_interrupt_leave_critical_section();
|
||||
return STATUS_ERR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/* Release the DMA resource */
|
||||
_dma_release_channel(resource->channel_id);
|
||||
|
||||
/* Reset the item in the DMA resource pool */
|
||||
_dma_active_resource[resource->channel_id] = NULL;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Start a DMA transfer.
|
||||
*
|
||||
* This function will start a DMA transfer through an allocated DMA resource.
|
||||
*
|
||||
* \param[in,out] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status of the transfer start procedure.
|
||||
*
|
||||
* \retval STATUS_OK The transfer was started successfully
|
||||
* \retval STATUS_BUSY The DMA resource was busy and the transfer was not started
|
||||
* \retval STATUS_ERR_INVALID_ARG Transfer size is 0 and transfer was not started
|
||||
*/
|
||||
enum status_code dma_start_transfer_job(struct dma_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
Assert(resource->channel_id != DMA_INVALID_CHANNEL);
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/* Check if resource was busy */
|
||||
if (resource->job_status == STATUS_BUSY) {
|
||||
system_interrupt_leave_critical_section();
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
/* Check if transfer size is valid */
|
||||
if (resource->descriptor->BTCNT.reg == 0) {
|
||||
system_interrupt_leave_critical_section();
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Enable DMA interrupt */
|
||||
system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_DMA);
|
||||
|
||||
/* Set the interrupt flag */
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
DMAC->CHINTENSET.reg = (DMAC_CHINTENSET_MASK & g_chan_interrupt_flag[resource->channel_id]);
|
||||
/* Set job status */
|
||||
resource->job_status = STATUS_BUSY;
|
||||
|
||||
/* Set channel x descriptor 0 to the descriptor base address */
|
||||
memcpy(&descriptor_section[resource->channel_id], resource->descriptor,
|
||||
sizeof(DmacDescriptor));
|
||||
|
||||
/* Enable the transfer channel */
|
||||
DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Abort a DMA transfer.
|
||||
*
|
||||
* This function will abort a DMA transfer. The DMA channel used for the DMA
|
||||
* resource will be disabled.
|
||||
* The block transfer count will also be calculated and written to the DMA
|
||||
* resource structure.
|
||||
*
|
||||
* \note The DMA resource will not be freed after calling this function.
|
||||
* The function \ref dma_free() can be used to free an allocated resource.
|
||||
*
|
||||
* \param[in,out] resource Pointer to the DMA resource
|
||||
*
|
||||
*/
|
||||
void dma_abort_job(struct dma_resource *resource)
|
||||
{
|
||||
uint32_t write_size;
|
||||
uint32_t total_size;
|
||||
|
||||
Assert(resource);
|
||||
Assert(resource->channel_id != DMA_INVALID_CHANNEL);
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
DMAC->CHCTRLA.reg = 0;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
/* Get transferred size */
|
||||
total_size = descriptor_section[resource->channel_id].BTCNT.reg;
|
||||
write_size = _write_back_section[resource->channel_id].BTCNT.reg;
|
||||
resource->transfered_size = total_size - write_size;
|
||||
|
||||
resource->job_status = STATUS_ABORTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Suspend a DMA transfer.
|
||||
*
|
||||
* This function will request to suspend the transfer of the DMA resource.
|
||||
* The channel is kept enabled, can receive transfer triggers (the transfer
|
||||
* pending bit will be set), but will be removed from the arbitration scheme.
|
||||
* The channel operation can be resumed by calling \ref dma_resume_job().
|
||||
*
|
||||
* \note This function sets the command to suspend the DMA channel
|
||||
* associated with a DMA resource. The channel suspend interrupt flag
|
||||
* indicates whether the transfer is truly suspended.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
*
|
||||
*/
|
||||
void dma_suspend_job(struct dma_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
Assert(resource->channel_id != DMA_INVALID_CHANNEL);
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/* Select the channel */
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
|
||||
/* Send the suspend request */
|
||||
DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_SUSPEND;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Resume a suspended DMA transfer.
|
||||
*
|
||||
* This function try to resume a suspended transfer of a DMA resource.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
*
|
||||
*/
|
||||
void dma_resume_job(struct dma_resource *resource)
|
||||
{
|
||||
uint32_t bitmap_channel;
|
||||
uint32_t count = 0;
|
||||
|
||||
Assert(resource);
|
||||
Assert(resource->channel_id != DMA_INVALID_CHANNEL);
|
||||
|
||||
/* Get bitmap of the allocated DMA channel */
|
||||
bitmap_channel = (1 << resource->channel_id);
|
||||
|
||||
/* Check if channel was suspended */
|
||||
if (resource->job_status != STATUS_SUSPEND) {
|
||||
return;
|
||||
}
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/* Send resume request */
|
||||
DMAC->CHID.reg = DMAC_CHID_ID(resource->channel_id);
|
||||
DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_RESUME;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
/* Check if transfer job resumed */
|
||||
for (count = 0; count < MAX_JOB_RESUME_COUNT; count++) {
|
||||
if ((DMAC->BUSYCH.reg & bitmap_channel) == bitmap_channel) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (count < MAX_JOB_RESUME_COUNT) {
|
||||
/* Job resumed */
|
||||
resource->job_status = STATUS_BUSY;
|
||||
} else {
|
||||
/* Job resume timeout */
|
||||
resource->job_status = STATUS_ERR_TIMEOUT;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Create a DMA transfer descriptor with configurations.
|
||||
*
|
||||
* This function will set the transfer configurations to the DMA transfer
|
||||
* descriptor.
|
||||
*
|
||||
* \param[in] descriptor Pointer to the DMA transfer descriptor
|
||||
* \param[in] config Pointer to the descriptor configuration structure
|
||||
*
|
||||
*/
|
||||
void dma_descriptor_create(DmacDescriptor* descriptor,
|
||||
struct dma_descriptor_config *config)
|
||||
{
|
||||
/* Set block transfer control */
|
||||
descriptor->BTCTRL.bit.VALID = config->descriptor_valid;
|
||||
descriptor->BTCTRL.bit.EVOSEL = config->event_output_selection;
|
||||
descriptor->BTCTRL.bit.BLOCKACT = config->block_action;
|
||||
descriptor->BTCTRL.bit.BEATSIZE = config->beat_size;
|
||||
descriptor->BTCTRL.bit.SRCINC = config->src_increment_enable;
|
||||
descriptor->BTCTRL.bit.DSTINC = config->dst_increment_enable;
|
||||
descriptor->BTCTRL.bit.STEPSEL = config->step_selection;
|
||||
descriptor->BTCTRL.bit.STEPSIZE = config->step_size;
|
||||
|
||||
/* Set transfer size, source address and destination address */
|
||||
descriptor->BTCNT.reg = config->block_transfer_count;
|
||||
descriptor->SRCADDR.reg = config->source_address;
|
||||
descriptor->DSTADDR.reg = config->destination_address;
|
||||
|
||||
/* Set next transfer descriptor address */
|
||||
descriptor->DESCADDR.reg = config->next_descriptor_address;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a DMA transfer descriptor to a DMA resource.
|
||||
*
|
||||
* This function will add a DMA transfer descriptor to a DMA resource.
|
||||
* If there was a transfer descriptor already allocated to the DMA resource,
|
||||
* the descriptor will be linked to the next descriptor address.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] descriptor Pointer to the transfer descriptor
|
||||
*
|
||||
* \retval STATUS_OK The descriptor is added to the DMA resource
|
||||
* \retval STATUS_BUSY The DMA resource was busy and the descriptor is not added
|
||||
*/
|
||||
enum status_code dma_add_descriptor(struct dma_resource *resource,
|
||||
DmacDescriptor* descriptor)
|
||||
{
|
||||
DmacDescriptor* desc = resource->descriptor;
|
||||
|
||||
if (resource->job_status == STATUS_BUSY) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
/* Look up for an empty space for the descriptor */
|
||||
if (desc == NULL) {
|
||||
resource->descriptor = descriptor;
|
||||
} else {
|
||||
/* Looking for end of descriptor link */
|
||||
while(desc->DESCADDR.reg != 0) {
|
||||
desc = (DmacDescriptor*)(desc->DESCADDR.reg);
|
||||
}
|
||||
|
||||
/* Set to the end of descriptor list */
|
||||
desc->DESCADDR.reg = (uint32_t)descriptor;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
882
atmel-samd/asf/sam0/drivers/dma/dma.h
Normal file
882
atmel-samd/asf/sam0/drivers/dma/dma.h
Normal file
@ -0,0 +1,882 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Direct Memory Access Controller Driver
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef DMA_H_INCLUDED
|
||||
#define DMA_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup asfdoc_sam0_dma_group SAM Direct Memory Access Controller (DMAC) Driver
|
||||
*
|
||||
* This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration
|
||||
* and management of the Direct Memory Access Controller(DMAC) module within
|
||||
* the device. The DMAC can transfer data between memories and peripherals, and
|
||||
* thus off-load these tasks from the CPU. The module supports peripheral to
|
||||
* peripheral, peripheral to memory, memory to peripheral, and memory to memory
|
||||
* transfers.
|
||||
*
|
||||
* The following peripheral is used by the DMAC Driver:
|
||||
* - DMAC (Direct Memory Access Controller)
|
||||
*
|
||||
* The following devices can use this module:
|
||||
* - Atmel | SMART SAM D21
|
||||
* - Atmel | SMART SAM R21
|
||||
* - Atmel | SMART SAM D09/D10/D11
|
||||
* - Atmel | SMART SAM L21/L22
|
||||
* - Atmel | SMART SAM DA1
|
||||
* - Atmel | SMART SAM C20/C21
|
||||
* - Atmel | SMART SAM R30
|
||||
*
|
||||
* The outline of this documentation is as follows:
|
||||
* - \ref asfdoc_sam0_dma_prerequisites
|
||||
* - \ref asfdoc_sam0_dma_module_overview
|
||||
* - \ref asfdoc_sam0_dma_special_considerations
|
||||
* - \ref asfdoc_sam0_dma_extra_info
|
||||
* - \ref asfdoc_sam0_dma_examples
|
||||
* - \ref asfdoc_sam0_dma_api_overview
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_prerequisites Prerequisites
|
||||
*
|
||||
* There are no prerequisites for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_module_overview Module Overview
|
||||
*
|
||||
* SAM devices with DMAC enables high data transfer rates with minimum
|
||||
* CPU intervention and frees up CPU time. With access to all peripherals,
|
||||
* the DMAC can handle automatic transfer of data to/from modules.
|
||||
* It supports static and incremental addressing for both source and
|
||||
* destination.
|
||||
*
|
||||
* The DMAC when used with Event System or peripheral triggers, provides a
|
||||
* considerable advantage by reducing the power consumption and performing
|
||||
* data transfer in the background.
|
||||
* For example, if the ADC is configured to generate an event, it can trigger
|
||||
* the DMAC to transfer the data into another peripheral or SRAM.
|
||||
* The CPU can remain in sleep during this time to reduce the power consumption.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Device</th>
|
||||
* <th>Dma channel number</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>SAM D21/R21/C20/C21</td>
|
||||
* <td>12</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>SAM D09/D10/D11</td>
|
||||
* <td>6</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>SAM L21,SAMR30</td>
|
||||
* <td>16</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* The DMA channel operation can be suspended at any time by software, by events
|
||||
* from event system, or after selectable descriptor execution. The operation
|
||||
* can be resumed by software or by events from the event system.
|
||||
* The DMAC driver for SAM supports four types of transfers such as
|
||||
* peripheral to peripheral, peripheral to memory, memory to peripheral, and
|
||||
* memory to memory.
|
||||
*
|
||||
* The basic transfer unit is a beat, which is defined as a single bus access.
|
||||
* There can be multiple beats in a single block transfer and multiple block
|
||||
* transfers in a DMA transaction.
|
||||
* DMA transfer is based on descriptors, which holds transfer properties
|
||||
* such as the source and destination addresses, transfer counter, and other
|
||||
* additional transfer control information.
|
||||
* The descriptors can be static or linked. When static, a single block transfer
|
||||
* is performed. When linked, a number of transfer descriptors can be used to
|
||||
* enable multiple block transfers within a single DMA transaction.
|
||||
*
|
||||
* The implementation of the DMA driver is based on the idea that the DMA channel
|
||||
* is a finite resource of entities with the same abilities. A DMA channel resource
|
||||
* is able to move a defined set of data from a source address to destination
|
||||
* address triggered by a transfer trigger. On the SAM devices there are 12
|
||||
* DMA resources available for allocation. Each of these DMA resources can trigger
|
||||
* interrupt callback routines and peripheral events.
|
||||
* The other main features are:
|
||||
*
|
||||
* - Selectable transfer trigger source
|
||||
* - Software
|
||||
* - Event System
|
||||
* - Peripheral
|
||||
* - Event input and output is supported for the four lower channels
|
||||
* - Four level channel priority
|
||||
* - Optional interrupt generation on transfer complete, channel error, or channel suspend
|
||||
* - Supports multi-buffer or circular buffer mode by linking multiple descriptors
|
||||
* - Beat size configurable as 8-bit, 16-bit, or 32-bit
|
||||
*
|
||||
* A simplified block diagram of the DMA Resource can be seen in
|
||||
* \ref asfdoc_sam0_dma_module_block_diagram "the figure below".
|
||||
*
|
||||
* \anchor asfdoc_sam0_dma_module_block_diagram
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* splines = false;
|
||||
* rankdir=LR;
|
||||
*
|
||||
* mux1 [label="Transfer Trigger", shape=box];
|
||||
*
|
||||
* dma [label="DMA Channel", shape=polygon, sides=6, orientation=60, style=filled, fillcolor=darkolivegreen1, height=1, width=1];
|
||||
* descriptor [label="Transfer Descriptor", shape=box, style=filled, fillcolor=lightblue];
|
||||
*
|
||||
* mux1 -> dma;
|
||||
* descriptor -> dma;
|
||||
*
|
||||
* interrupt [label="Interrupt", shape=box];
|
||||
* events [label="Events", shape=box];
|
||||
*
|
||||
* dma:e -> interrupt:w;
|
||||
* dma:e -> events:w;
|
||||
*
|
||||
* {rank=same; descriptor dma}
|
||||
*
|
||||
* }
|
||||
* \enddot
|
||||
*
|
||||
* \subsection asfdoc_sam0_dma_features Driver Feature Macro Definition
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Driver Feature Macro</th>
|
||||
* <th>Supported devices</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>FEATURE_DMA_CHANNEL_STANDBY</td>
|
||||
* <td>SAM L21/L22/C20/C21/R30</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* \note The specific features are only available in the driver when the
|
||||
* selected device supports those features.
|
||||
*
|
||||
* \subsection asfdoc_sam0_dma_module_overview_dma_transf_term Terminology Used in DMAC Transfers
|
||||
*
|
||||
* <table border="0" cellborder="1" cellspacing="0" >
|
||||
* <tr>
|
||||
* <th> Name </th> <th> Description </th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Beat </td>
|
||||
* <td > It is a single bus access by the DMAC.
|
||||
* Configurable as 8-bit, 16-bit, or 32-bit.
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Burst </td>
|
||||
* <td> It is a transfer of n-beats (n=1,4,8,16).
|
||||
* For the DMAC module in SAM, the burst size is one beat.
|
||||
* Arbitration takes place each time a burst transfer is completed.
|
||||
* </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Block transfer </td>
|
||||
* <td> A single block transfer is a configurable number of (1 to 64k)
|
||||
* beat transfers
|
||||
* </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* \subsection asfdoc_sam0_dma_module_overview_dma_channels DMA Channels
|
||||
* The DMAC in each device consists of several DMA channels, which
|
||||
* along with the transfer descriptors defines the data transfer properties.
|
||||
* - The transfer control descriptor defines the source and destination
|
||||
* addresses, source and destination address increment settings, the
|
||||
* block transfer count, and event output condition selection
|
||||
* - Dedicated channel registers control the peripheral trigger source,
|
||||
* trigger mode settings, event input actions, and channel priority level
|
||||
* settings
|
||||
*
|
||||
* With a successful DMA resource allocation, a dedicated
|
||||
* DMA channel will be assigned. The channel will be occupied until the
|
||||
* DMA resource is freed. A DMA resource handle is used to identify the specific
|
||||
* DMA resource.
|
||||
* When there are multiple channels with active requests, the arbiter prioritizes
|
||||
* the channels requesting access to the bus.
|
||||
*
|
||||
* \subsection asfdoc_sam0_dma_module_overview_dma_trigger DMA Triggers
|
||||
* DMA transfer can be started only when a DMA transfer request is acknowledged/granted by the arbiter. A
|
||||
* transfer request can be triggered from software, peripheral, or an event. There
|
||||
* are dedicated source trigger selections for each DMA channel usage.
|
||||
|
||||
*
|
||||
* \subsection asfdoc_sam0_dma_module_overview_dma_transfer_descriptor DMA Transfer Descriptor
|
||||
* The transfer descriptor resides in the SRAM and
|
||||
* defines these channel properties.
|
||||
* <table border="0" cellborder="1" cellspacing="0" >
|
||||
* <tr>
|
||||
* <th> Field name </th> <th> Field width </th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Descriptor Next Address </td> <td > 32 bits </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Destination Address </td> <td> 32 bits </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Source Address </td> <td> 32 bits </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Block Transfer Counter </td> <td> 16 bits </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td > Block Transfer Control </td> <td> 16 bits </td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* Before starting a transfer, at least one descriptor should be configured.
|
||||
* After a successful allocation of a DMA channel, the transfer descriptor can
|
||||
* be added with a call to \ref dma_add_descriptor(). If there is a transfer
|
||||
* descriptor already allocated to the DMA resource, the descriptor will
|
||||
* be linked to the next descriptor address.
|
||||
*
|
||||
* \subsection asfdoc_sam0_dma_module_overview_dma_output DMA Interrupts/Events
|
||||
* Both an interrupt callback and an peripheral event can be triggered by the
|
||||
* DMA transfer. Three types of callbacks are supported by the DMA driver:
|
||||
* transfer complete, channel suspend, and transfer error. Each of these callback
|
||||
* types can be registered and enabled for each channel independently through
|
||||
* the DMA driver API.
|
||||
*
|
||||
* The DMAC module can also generate events on transfer complete. Event
|
||||
* generation is enabled through the DMA channel, event channel configuration,
|
||||
* and event user multiplexing is done through the events driver.
|
||||
*
|
||||
* The DMAC can generate events in the below cases:
|
||||
*
|
||||
* - When a block transfer is complete
|
||||
*
|
||||
* - When each beat transfer within a block transfer is complete
|
||||
*
|
||||
* \section asfdoc_sam0_dma_special_considerations Special Considerations
|
||||
*
|
||||
* There are no special considerations for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_extra_info Extra Information
|
||||
*
|
||||
* For extra information, see \ref asfdoc_sam0_dma_extra. This includes:
|
||||
* - \ref asfdoc_sam0_dma_extra_acronyms
|
||||
* - \ref asfdoc_sam0_dma_extra_dependencies
|
||||
* - \ref asfdoc_sam0_dma_extra_errata
|
||||
* - \ref asfdoc_sam0_dma_extra_history
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_examples Examples
|
||||
*
|
||||
* For a list of examples related to this driver, see
|
||||
* \ref asfdoc_sam0_dma_exqsg.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_api_overview API Overview
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include "conf_dma.h"
|
||||
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || defined(__DOXYGEN__)
|
||||
#define FEATURE_DMA_CHANNEL_STANDBY
|
||||
#endif
|
||||
|
||||
/** DMA invalid channel number. */
|
||||
#define DMA_INVALID_CHANNEL 0xff
|
||||
|
||||
/** ExInitial description section. */
|
||||
extern DmacDescriptor descriptor_section[CONF_MAX_USED_CHANNEL_NUM];
|
||||
|
||||
/* DMA channel interrup flag. */
|
||||
extern uint8_t g_chan_interrupt_flag[CONF_MAX_USED_CHANNEL_NUM];
|
||||
|
||||
/** DMA priority level. */
|
||||
enum dma_priority_level {
|
||||
/** Priority level 0. */
|
||||
DMA_PRIORITY_LEVEL_0,
|
||||
/** Priority level 1. */
|
||||
DMA_PRIORITY_LEVEL_1,
|
||||
/** Priority level 2. */
|
||||
DMA_PRIORITY_LEVEL_2,
|
||||
/** Priority level 3. */
|
||||
DMA_PRIORITY_LEVEL_3,
|
||||
};
|
||||
|
||||
/** DMA input actions. */
|
||||
enum dma_event_input_action {
|
||||
/** No action. */
|
||||
DMA_EVENT_INPUT_NOACT,
|
||||
/** Normal transfer and periodic transfer trigger. */
|
||||
DMA_EVENT_INPUT_TRIG,
|
||||
/** Conditional transfer trigger. */
|
||||
DMA_EVENT_INPUT_CTRIG,
|
||||
/** Conditional block transfer. */
|
||||
DMA_EVENT_INPUT_CBLOCK,
|
||||
/** Channel suspend operation. */
|
||||
DMA_EVENT_INPUT_SUSPEND,
|
||||
/** Channel resume operation. */
|
||||
DMA_EVENT_INPUT_RESUME,
|
||||
/** Skip next block suspend action. */
|
||||
DMA_EVENT_INPUT_SSKIP,
|
||||
};
|
||||
|
||||
/**
|
||||
* Address increment step size. These bits select the address increment step
|
||||
* size. The setting apply to source or destination address, depending on
|
||||
* STEPSEL setting.
|
||||
*/
|
||||
enum dma_address_increment_stepsize {
|
||||
/** The address is incremented by (beat size * 1). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_1 = 0,
|
||||
/** The address is incremented by (beat size * 2). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_2,
|
||||
/** The address is incremented by (beat size * 4). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_4,
|
||||
/** The address is incremented by (beat size * 8). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_8,
|
||||
/** The address is incremented by (beat size * 16). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_16,
|
||||
/** The address is incremented by (beat size * 32). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_32,
|
||||
/** The address is incremented by (beat size * 64). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_64,
|
||||
/** The address is incremented by (beat size * 128). */
|
||||
DMA_ADDRESS_INCREMENT_STEP_SIZE_128,
|
||||
};
|
||||
|
||||
/**
|
||||
* DMA step selection. This bit determines whether the step size setting
|
||||
* is applied to source or destination address.
|
||||
*/
|
||||
enum dma_step_selection {
|
||||
/** Step size settings apply to the destination address. */
|
||||
DMA_STEPSEL_DST = 0,
|
||||
/** Step size settings apply to the source address. */
|
||||
DMA_STEPSEL_SRC,
|
||||
};
|
||||
|
||||
/** The basic transfer unit in DMAC is a beat, which is defined as a
|
||||
* single bus access. Its size is configurable and applies to both read
|
||||
* and write. */
|
||||
enum dma_beat_size {
|
||||
/** 8-bit access. */
|
||||
DMA_BEAT_SIZE_BYTE = 0,
|
||||
/** 16-bit access. */
|
||||
DMA_BEAT_SIZE_HWORD,
|
||||
/** 32-bit access. */
|
||||
DMA_BEAT_SIZE_WORD,
|
||||
};
|
||||
|
||||
/**
|
||||
* Block action definitions.
|
||||
*/
|
||||
enum dma_block_action {
|
||||
/** No action. */
|
||||
DMA_BLOCK_ACTION_NOACT = 0,
|
||||
/** Channel in normal operation and sets transfer complete interrupt flag
|
||||
* after block transfer. */
|
||||
DMA_BLOCK_ACTION_INT,
|
||||
/** Trigger channel suspend after block transfer and sets channel
|
||||
* suspend interrupt flag once the channel is suspended. */
|
||||
DMA_BLOCK_ACTION_SUSPEND,
|
||||
/** Sets transfer complete interrupt flag after a block transfer and
|
||||
* trigger channel suspend. The channel suspend interrupt flag will be set
|
||||
* once the channel is suspended. */
|
||||
DMA_BLOCK_ACTION_BOTH,
|
||||
};
|
||||
|
||||
/** Event output selection. */
|
||||
enum dma_event_output_selection {
|
||||
/** Event generation disable. */
|
||||
DMA_EVENT_OUTPUT_DISABLE = 0,
|
||||
/** Event strobe when block transfer complete. */
|
||||
DMA_EVENT_OUTPUT_BLOCK,
|
||||
/** Event output reserved. */
|
||||
DMA_EVENT_OUTPUT_RESERVED,
|
||||
/** Event strobe when beat transfer complete. */
|
||||
DMA_EVENT_OUTPUT_BEAT,
|
||||
};
|
||||
|
||||
/** DMA trigger action type. */
|
||||
enum dma_transfer_trigger_action{
|
||||
/** Perform a block transfer when triggered. */
|
||||
DMA_TRIGGER_ACTION_BLOCK = DMAC_CHCTRLB_TRIGACT_BLOCK_Val,
|
||||
/** Perform a beat transfer when triggered. */
|
||||
DMA_TRIGGER_ACTION_BEAT = DMAC_CHCTRLB_TRIGACT_BEAT_Val,
|
||||
/** Perform a transaction when triggered. */
|
||||
DMA_TRIGGER_ACTION_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val,
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback types for DMA callback driver.
|
||||
*/
|
||||
enum dma_callback_type {
|
||||
/** Callback for any of transfer errors. A transfer error is flagged
|
||||
* if a bus error is detected during an AHB access or when the DMAC
|
||||
* fetches an invalid descriptor. */
|
||||
DMA_CALLBACK_TRANSFER_ERROR,
|
||||
/** Callback for transfer complete. */
|
||||
DMA_CALLBACK_TRANSFER_DONE,
|
||||
/** Callback for channel suspend. */
|
||||
DMA_CALLBACK_CHANNEL_SUSPEND,
|
||||
/** Number of available callbacks. */
|
||||
DMA_CALLBACK_N,
|
||||
};
|
||||
|
||||
/**
|
||||
* DMA transfer descriptor configuration. When the source or destination address
|
||||
* increment is enabled, the addresses stored into the configuration structure
|
||||
* must correspond to the end of the transfer.
|
||||
*
|
||||
*/
|
||||
struct dma_descriptor_config {
|
||||
/** Descriptor valid flag used to identify whether a descriptor is
|
||||
valid or not */
|
||||
bool descriptor_valid;
|
||||
/** This is used to generate an event on specific transfer action in
|
||||
a channel. Supported only in four lower channels. */
|
||||
enum dma_event_output_selection event_output_selection;
|
||||
/** Action taken when a block transfer is completed */
|
||||
enum dma_block_action block_action;
|
||||
/** Beat size is configurable as 8-bit, 16-bit, or 32-bit */
|
||||
enum dma_beat_size beat_size;
|
||||
/** Used for enabling the source address increment */
|
||||
bool src_increment_enable;
|
||||
/** Used for enabling the destination address increment */
|
||||
bool dst_increment_enable;
|
||||
/** This bit selects whether the source or destination address is
|
||||
using the step size settings */
|
||||
enum dma_step_selection step_selection;
|
||||
/** The step size for source/destination address increment.
|
||||
The next address is calculated
|
||||
as next_addr = addr + (2^step_size * beat size). */
|
||||
enum dma_address_increment_stepsize step_size;
|
||||
/** It is the number of beats in a block. This count value is
|
||||
* decremented by one after each beat data transfer. */
|
||||
uint16_t block_transfer_count;
|
||||
/** Transfer source address */
|
||||
uint32_t source_address;
|
||||
/** Transfer destination address */
|
||||
uint32_t destination_address;
|
||||
/** Set to zero for static descriptors. This must have a valid memory
|
||||
address for linked descriptors. */
|
||||
uint32_t next_descriptor_address;
|
||||
};
|
||||
|
||||
/** Configurations for DMA events. */
|
||||
struct dma_events_config {
|
||||
/** Event input actions */
|
||||
enum dma_event_input_action input_action;
|
||||
/** Enable DMA event output */
|
||||
bool event_output_enable;
|
||||
};
|
||||
|
||||
/** DMA configurations for transfer. */
|
||||
struct dma_resource_config {
|
||||
/** DMA transfer priority */
|
||||
enum dma_priority_level priority;
|
||||
/**DMA peripheral trigger index */
|
||||
uint8_t peripheral_trigger;
|
||||
/** DMA trigger action */
|
||||
enum dma_transfer_trigger_action trigger_action;
|
||||
#ifdef FEATURE_DMA_CHANNEL_STANDBY
|
||||
/** Keep DMA channel enabled in standby sleep mode if true */
|
||||
bool run_in_standby;
|
||||
#endif
|
||||
/** DMA events configurations */
|
||||
struct dma_events_config event_config;
|
||||
};
|
||||
|
||||
/** Forward definition of the DMA resource. */
|
||||
struct dma_resource;
|
||||
/** Type definition for a DMA resource callback function. */
|
||||
typedef void (*dma_callback_t)(struct dma_resource *const resource);
|
||||
|
||||
/** Structure for DMA transfer resource. */
|
||||
struct dma_resource {
|
||||
/** Allocated DMA channel ID */
|
||||
uint8_t channel_id;
|
||||
/** Array of callback functions for DMA transfer job */
|
||||
dma_callback_t callback[DMA_CALLBACK_N];
|
||||
/** Bit mask for enabled callbacks */
|
||||
uint8_t callback_enable;
|
||||
/** Status of the last job */
|
||||
volatile enum status_code job_status;
|
||||
/** Transferred data size */
|
||||
uint32_t transfered_size;
|
||||
/** DMA transfer descriptor */
|
||||
DmacDescriptor* descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get DMA resource status.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status of the DMA resource.
|
||||
*/
|
||||
static inline enum status_code dma_get_job_status(struct dma_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
return resource->job_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Check if the given DMA resource is busy.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status which indicates whether the DMA resource is busy.
|
||||
*
|
||||
* \retval true The DMA resource has an on-going transfer
|
||||
* \retval false The DMA resource is not busy
|
||||
*/
|
||||
static inline bool dma_is_busy(struct dma_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
return (resource->job_status == STATUS_BUSY);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_enable_callback(struct dma_resource *resource,
|
||||
enum dma_callback_type type)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
resource->callback_enable |= 1 << type;
|
||||
g_chan_interrupt_flag[resource->channel_id] |= (1UL << type);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_disable_callback(struct dma_resource *resource,
|
||||
enum dma_callback_type type)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
resource->callback_enable &= ~(1 << type);
|
||||
g_chan_interrupt_flag[resource->channel_id] &= (~(1UL << type) & DMAC_CHINTENSET_MASK);
|
||||
DMAC->CHINTENCLR.reg = (1UL << type);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Register a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* There are three types of callback functions, which can be registered:
|
||||
* - Callback for transfer complete
|
||||
* - Callback for transfer error
|
||||
* - Callback for channel suspend
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] callback Pointer to the callback function
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_register_callback(struct dma_resource *resource,
|
||||
dma_callback_t callback, enum dma_callback_type type)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
resource->callback[type] = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Unregister a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* There are three types of callback functions:
|
||||
* - Callback for transfer complete
|
||||
* - Callback for transfer error
|
||||
* - Callback for channel suspend
|
||||
*
|
||||
* The application can unregister any of the callback functions which
|
||||
* are already registered and are no longer needed.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_unregister_callback(struct dma_resource *resource,
|
||||
enum dma_callback_type type)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
resource->callback[type] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Will set a software trigger for resource.
|
||||
*
|
||||
* This function is used to set a software trigger on the DMA channel
|
||||
* associated with resource. If a trigger is already pending no new trigger
|
||||
* will be generated for the channel.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
*/
|
||||
static inline void dma_trigger_transfer(struct dma_resource *resource) {
|
||||
Assert(resource);
|
||||
|
||||
DMAC->SWTRIGCTRL.reg |= (1 << resource->channel_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes DMA transfer configuration with predefined default values.
|
||||
*
|
||||
* This function will initialize a given DMA descriptor configuration structure to
|
||||
* a set of known default values. This function should be called on
|
||||
* any new instance of the configuration structure before being
|
||||
* modified by the user application.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li Set the descriptor as valid
|
||||
* \li Disable event output
|
||||
* \li No block action
|
||||
* \li Set beat size as byte
|
||||
* \li Enable source increment
|
||||
* \li Enable destination increment
|
||||
* \li Step size is applied to the destination address
|
||||
* \li Address increment is beat size multiplied by 1
|
||||
* \li Default transfer size is set to 0
|
||||
* \li Default source address is set to NULL
|
||||
* \li Default destination address is set to NULL
|
||||
* \li Default next descriptor not available
|
||||
* \param[out] config Pointer to the configuration
|
||||
*
|
||||
*/
|
||||
static inline void dma_descriptor_get_config_defaults(struct dma_descriptor_config *config)
|
||||
{
|
||||
Assert(config);
|
||||
|
||||
/* Set descriptor as valid */
|
||||
config->descriptor_valid = true;
|
||||
/* Disable event output */
|
||||
config->event_output_selection = DMA_EVENT_OUTPUT_DISABLE;
|
||||
/* No block action */
|
||||
config->block_action = DMA_BLOCK_ACTION_NOACT;
|
||||
/* Set beat size to one byte */
|
||||
config->beat_size = DMA_BEAT_SIZE_BYTE;
|
||||
/* Enable source increment */
|
||||
config->src_increment_enable = true;
|
||||
/* Enable destination increment */
|
||||
config->dst_increment_enable = true;
|
||||
/* Step size is applied to the destination address */
|
||||
config->step_selection = DMA_STEPSEL_DST;
|
||||
/* Address increment is beat size multiplied by 1*/
|
||||
config->step_size = DMA_ADDRESS_INCREMENT_STEP_SIZE_1;
|
||||
/* Default transfer size is set to 0 */
|
||||
config->block_transfer_count = 0;
|
||||
/* Default source address is set to NULL */
|
||||
config->source_address = (uint32_t)NULL;
|
||||
/* Default destination address is set to NULL */
|
||||
config->destination_address = (uint32_t)NULL;
|
||||
/** Next descriptor address set to 0 */
|
||||
config->next_descriptor_address = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Update DMA descriptor.
|
||||
*
|
||||
* This function can update the descriptor of an allocated DMA resource.
|
||||
*
|
||||
*/
|
||||
static inline void dma_update_descriptor(struct dma_resource *resource,
|
||||
DmacDescriptor* descriptor)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
resource->descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reset DMA descriptor.
|
||||
*
|
||||
* This function will clear the DESCADDR register of an allocated DMA resource.
|
||||
*
|
||||
*/
|
||||
static inline void dma_reset_descriptor(struct dma_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
resource->descriptor = NULL;
|
||||
}
|
||||
|
||||
void dma_get_config_defaults(struct dma_resource_config *config);
|
||||
enum status_code dma_allocate(struct dma_resource *resource,
|
||||
struct dma_resource_config *config);
|
||||
enum status_code dma_free(struct dma_resource *resource);
|
||||
enum status_code dma_start_transfer_job(struct dma_resource *resource);
|
||||
void dma_abort_job(struct dma_resource *resource);
|
||||
void dma_suspend_job(struct dma_resource *resource);
|
||||
void dma_resume_job(struct dma_resource *resource);
|
||||
void dma_descriptor_create(DmacDescriptor* descriptor,
|
||||
struct dma_descriptor_config *config);
|
||||
enum status_code dma_add_descriptor(struct dma_resource *resource,
|
||||
DmacDescriptor* descriptor);
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \page asfdoc_sam0_dma_extra Extra Information for DMAC Driver
|
||||
*
|
||||
* \section asfdoc_sam0_dma_extra_acronyms Acronyms
|
||||
* Below is a table listing the acronyms used in this module, along with their
|
||||
* intended meanings.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Acronym</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>DMA</td>
|
||||
* <td>Direct Memory Access</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>DMAC</td>
|
||||
* <td>Direct Memory Access Controller </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>CPU</td>
|
||||
* <td>Central Processing Unit</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_extra_dependencies Dependencies
|
||||
* This driver has the following dependencies:
|
||||
*
|
||||
* - \ref asfdoc_sam0_system_clock_group "System Clock Driver"
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_extra_errata Errata
|
||||
* There are no errata related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_dma_extra_history Module History
|
||||
* An overview of the module history is presented in the table below, with
|
||||
* details on the enhancements and fixes made to the module since its first
|
||||
* release. The current version of this corresponds to the newest version in
|
||||
* the table.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Changelog</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Add SAM C21 support</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Add SAM L21 support</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Add SAM R30 support</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Initial Release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page asfdoc_sam0_dma_exqsg Examples for DMAC Driver
|
||||
*
|
||||
* This is a list of the available Quick Start Guides (QSGs) and example
|
||||
* applications for \ref asfdoc_sam0_dma_group. QSGs are simple examples with
|
||||
* step-by-step instructions to configure and use this driver in a selection of
|
||||
* use cases. Note that a QSG can be compiled as a standalone application or be
|
||||
* added to the user application.
|
||||
*
|
||||
* - \subpage asfdoc_sam0_dma_basic_use_case
|
||||
*
|
||||
* \note More DMA usage examples are available in peripheral QSGs.
|
||||
* A quick start guide for TC/TCC
|
||||
* shows the usage of DMA event trigger; SERCOM SPI/USART/I<SUP>2</SUP>C has example for
|
||||
* DMA transfer from peripheral to memory or from memory to peripheral;
|
||||
* ADC/DAC shows peripheral to peripheral transfer.
|
||||
*
|
||||
* \page asfdoc_sam0_dma_document_revision_history Document Revision History
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Doc. Rev.</th>
|
||||
* <th>Date</th>
|
||||
* <th>Comments</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42257C</td>
|
||||
* <td>12/2015</td>
|
||||
* <td>Added suppport for SAM L21/L22, SAM C21, SAM D09, SAMR30 and SAM DA1</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42257B</td>
|
||||
* <td>12/2014</td>
|
||||
* <td>Added support for SAM R21 and SAM D10/D11</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42257A</td>
|
||||
* <td>02/2014</td>
|
||||
* <td>Initial release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DMA_H_INCLUDED */
|
230
atmel-samd/asf/sam0/drivers/dma/dma_crc.h
Normal file
230
atmel-samd/asf/sam0/drivers/dma/dma_crc.h
Normal file
@ -0,0 +1,230 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM DMA cyclic redundancy check (CRC) Driver
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef DMA_CRC_H_INCLUDED
|
||||
#define DMA_CRC_H_INCLUDED
|
||||
|
||||
#include <compiler.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** DMA channel n offset. */
|
||||
#define DMA_CRC_CHANNEL_N_OFFSET 0x20
|
||||
|
||||
/** CRC Polynomial Type. */
|
||||
enum crc_polynomial_type {
|
||||
/** CRC16 (CRC-CCITT). */
|
||||
CRC_TYPE_16,
|
||||
/** CRC32 (IEEE 802.3). */
|
||||
CRC_TYPE_32,
|
||||
};
|
||||
|
||||
/** CRC Beat Type. */
|
||||
enum crc_beat_size {
|
||||
/** Byte bus access. */
|
||||
CRC_BEAT_SIZE_BYTE,
|
||||
/** Half-word bus access. */
|
||||
CRC_BEAT_SIZE_HWORD,
|
||||
/** Word bus access. */
|
||||
CRC_BEAT_SIZE_WORD,
|
||||
};
|
||||
|
||||
/** Configurations for CRC calculation. */
|
||||
struct dma_crc_config {
|
||||
/** CRC polynomial type. */
|
||||
enum crc_polynomial_type type;
|
||||
/** CRC beat size. */
|
||||
enum crc_beat_size size;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get DMA CRC default configurations.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li Polynomial type is set to CRC-16(CRC-CCITT)
|
||||
* \li CRC Beat size: BYTE
|
||||
*
|
||||
* \param[in] config default configurations
|
||||
*/
|
||||
static inline void dma_crc_get_config_defaults(struct dma_crc_config *config)
|
||||
{
|
||||
Assert(config);
|
||||
|
||||
config->type = CRC_TYPE_16;
|
||||
config->size = CRC_BEAT_SIZE_BYTE;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable DMA CRC module with an DMA channel.
|
||||
*
|
||||
* This function enables a CRC calculation with an allocated DMA channel. This channel ID
|
||||
* can be gotten from a successful \ref dma_allocate.
|
||||
*
|
||||
* \param[in] channel_id DMA channel expected with CRC calculation
|
||||
* \param[in] config CRC calculation configurations
|
||||
*
|
||||
* \return Status of the DMC CRC.
|
||||
* \retval STATUS_OK Get the DMA CRC module
|
||||
* \retval STATUS_BUSY DMA CRC module is already taken and not ready yet
|
||||
*/
|
||||
static inline enum status_code dma_crc_channel_enable(uint32_t channel_id,
|
||||
struct dma_crc_config *config)
|
||||
{
|
||||
if (DMAC->CRCSTATUS.reg & DMAC_CRCSTATUS_CRCBUSY) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
DMAC->CRCCTRL.reg = DMAC_CRCCTRL_CRCBEATSIZE(config->size) |
|
||||
DMAC_CRCCTRL_CRCPOLY(config->type) |
|
||||
DMAC_CRCCTRL_CRCSRC(channel_id+DMA_CRC_CHANNEL_N_OFFSET);
|
||||
|
||||
DMAC->CTRL.reg |= DMAC_CTRL_CRCENABLE;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable DMA CRC module.
|
||||
*
|
||||
*/
|
||||
static inline void dma_crc_disable(void)
|
||||
{
|
||||
DMAC->CTRL.reg &= ~DMAC_CTRL_CRCENABLE;
|
||||
DMAC->CRCCTRL.reg = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get DMA CRC checksum value.
|
||||
*
|
||||
* \return Calculated CRC checksum.
|
||||
*/
|
||||
static inline uint32_t dma_crc_get_checksum(void)
|
||||
{
|
||||
if (DMAC->CRCCTRL.bit.CRCSRC == DMAC_CRCCTRL_CRCSRC_IO_Val) {
|
||||
DMAC->CRCSTATUS.reg = DMAC_CRCSTATUS_CRCBUSY;
|
||||
}
|
||||
|
||||
return DMAC->CRCCHKSUM.reg;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable DMA CRC module with I/O.
|
||||
*
|
||||
* This function enables a CRC calculation with I/O mode.
|
||||
*
|
||||
* \param[in] config CRC calculation configurations.
|
||||
*
|
||||
* \return Status of the DMC CRC.
|
||||
* \retval STATUS_OK Get the DMA CRC module
|
||||
* \retval STATUS_BUSY DMA CRC module is already taken and not ready yet
|
||||
*/
|
||||
static inline enum status_code dma_crc_io_enable(
|
||||
struct dma_crc_config *config)
|
||||
{
|
||||
if (DMAC->CRCSTATUS.reg & DMAC_CRCSTATUS_CRCBUSY) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
if (DMAC->CTRL.reg & DMAC_CTRL_CRCENABLE) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
DMAC->CRCCTRL.reg = DMAC_CRCCTRL_CRCBEATSIZE(config->size) |
|
||||
DMAC_CRCCTRL_CRCPOLY(config->type) |
|
||||
DMAC_CRCCTRL_CRCSRC_IO;
|
||||
|
||||
if (config->type == CRC_TYPE_32) {
|
||||
DMAC->CRCCHKSUM.reg = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
DMAC->CTRL.reg |= DMAC_CTRL_CRCENABLE;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Calculate CRC with I/O.
|
||||
*
|
||||
* This function calculate the CRC of the input data buffer.
|
||||
*
|
||||
* \param[in] buffer CRC Pointer to calculation buffer
|
||||
* \param[in] total_beat_size Total beat size to be calculated
|
||||
*
|
||||
* \return Calculated CRC checksum value.
|
||||
*/
|
||||
static inline void dma_crc_io_calculation(void *buffer,
|
||||
uint32_t total_beat_size)
|
||||
{
|
||||
uint32_t counter = total_beat_size;
|
||||
uint8_t *buffer_8;
|
||||
uint16_t *buffer_16;
|
||||
uint32_t *buffer_32;
|
||||
|
||||
for (counter=0; counter<total_beat_size; counter++) {
|
||||
if (DMAC->CRCCTRL.bit.CRCBEATSIZE == CRC_BEAT_SIZE_BYTE) {
|
||||
buffer_8 = buffer;
|
||||
DMAC->CRCDATAIN.reg = buffer_8[counter];
|
||||
} else if (DMAC->CRCCTRL.bit.CRCBEATSIZE == CRC_BEAT_SIZE_HWORD) {
|
||||
buffer_16 = buffer;
|
||||
DMAC->CRCDATAIN.reg = buffer_16[counter];
|
||||
} else if (DMAC->CRCCTRL.bit.CRCBEATSIZE == CRC_BEAT_SIZE_WORD) {
|
||||
buffer_32 = buffer;
|
||||
DMAC->CRCDATAIN.reg = buffer_32[counter];
|
||||
}
|
||||
/* Wait several cycle to make sure CRC complete */
|
||||
nop();
|
||||
nop();
|
||||
nop();
|
||||
nop();
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DMA_CRC_H_INCLUDED */
|
557
atmel-samd/asf/sam0/drivers/dma/dma_sam_b.c
Normal file
557
atmel-samd/asf/sam0/drivers/dma/dma_sam_b.c
Normal file
@ -0,0 +1,557 @@
|
||||
/*
|
||||
* \file
|
||||
*
|
||||
* \brief Direct Memory Access Controller Driver for SAMB
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include "dma_sam_b.h"
|
||||
|
||||
struct _dma_module {
|
||||
volatile bool _dma_init;
|
||||
volatile uint32_t allocated_channels;
|
||||
uint8_t free_channels;
|
||||
};
|
||||
|
||||
struct _dma_module _dma_inst = {
|
||||
._dma_init = false,
|
||||
.allocated_channels = 0,
|
||||
.free_channels = CONF_MAX_USED_CHANNEL_NUM,
|
||||
};
|
||||
|
||||
/** Internal DMA resource pool. */
|
||||
static struct dma_resource* _dma_active_resource[CONF_MAX_USED_CHANNEL_NUM];
|
||||
|
||||
/**
|
||||
* \brief Get the assigned channel DMA value.
|
||||
*
|
||||
* \param[in] channel DMA channel index
|
||||
* \param[in] DMA register address
|
||||
*
|
||||
* \return The value of DMA register.
|
||||
*/
|
||||
static uint32_t get_channel_reg_val(uint8_t channel, uint32_t reg)
|
||||
{
|
||||
return *(uint32_t*)(reg + 0x100*channel);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Set the assigned channel DMA value.
|
||||
*
|
||||
* \param[in] channel DMA channel index
|
||||
* \param[in] DMA register address
|
||||
* \param[in] The value to be set
|
||||
*
|
||||
*/
|
||||
static void set_channel_reg_val(uint8_t channel, uint32_t reg, uint32_t val)
|
||||
{
|
||||
*(uint32_t*)(reg + 0x100*channel) = val;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the DMA status.
|
||||
*
|
||||
* \param[in] channel DMA channel index
|
||||
*
|
||||
* \return The status of DMA
|
||||
*/
|
||||
uint8_t dma_get_status(uint8_t channel)
|
||||
{
|
||||
return (uint8_t)get_channel_reg_val(channel, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_RAWSTAT_REG.reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the DMA interrupt status.
|
||||
*
|
||||
* \param[in] channel DMA channel index
|
||||
*
|
||||
* \return The interrupt of status DMA
|
||||
*/
|
||||
uint8_t dma_get_interrupt_status(uint8_t channel)
|
||||
{
|
||||
return get_channel_reg_val(channel, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_STATUS_REG.reg);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Get the DMA interrupt status.
|
||||
*
|
||||
* \param[in] channel DMA channel index
|
||||
* \param[in] flag The interrupt flag want to clear
|
||||
*
|
||||
*/
|
||||
void dma_clear_interrupt_status(uint8_t channel, uint8_t flag)
|
||||
{
|
||||
set_channel_reg_val(channel, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_CLEAR_REG.reg, 1 << flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Find a free channel for a DMA resource.
|
||||
*
|
||||
* Find a channel for the requested DMA resource.
|
||||
*
|
||||
* \return Status of channel allocation.
|
||||
* \retval DMA_INVALID_CHANNEL No channel available
|
||||
* \retval count Allocated channel for the DMA resource
|
||||
*/
|
||||
static uint8_t _dma_find_first_free_channel_and_allocate(void)
|
||||
{
|
||||
uint8_t count;
|
||||
uint32_t tmp;
|
||||
bool allocated = false;
|
||||
|
||||
tmp = _dma_inst.allocated_channels;
|
||||
|
||||
for (count = 0; count < CONF_MAX_USED_CHANNEL_NUM; ++count) {
|
||||
if (!(tmp & 0x00000001)) {
|
||||
/* If free channel found, set as allocated and return
|
||||
*number */
|
||||
|
||||
_dma_inst.allocated_channels |= 1 << count;
|
||||
_dma_inst.free_channels--;
|
||||
allocated = true;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
tmp = tmp >> 1;
|
||||
}
|
||||
|
||||
if (!allocated) {
|
||||
return DMA_INVALID_CHANNEL;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Release an allocated DMA channel.
|
||||
*
|
||||
* \param[in] channel Channel id to be released
|
||||
*
|
||||
*/
|
||||
static void _dma_release_channel(uint8_t channel)
|
||||
{
|
||||
_dma_inst.allocated_channels &= ~(1 << channel);
|
||||
_dma_inst.free_channels++;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes config with predefined default values.
|
||||
*
|
||||
* This function will initialize a given DMA configuration structure to
|
||||
* a set of known default values. This function should be called on
|
||||
* any new instance of the configuration structure before being
|
||||
* modified by the user application.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li Set source max burst number as 1
|
||||
* \li Set source tokens as 1
|
||||
* \li Set source peripheral as memory
|
||||
* \li Set source peripheral delay as 0
|
||||
* \li Disable source top priority
|
||||
* \li Set source top priority channel as 0
|
||||
* \li Disable source high priority
|
||||
* \li Set source high priority channel as 0
|
||||
* \li Set destination max burst number as 1
|
||||
* \li Set destination tokens as 1
|
||||
* \li Set destination peripheral as memory
|
||||
* \li Set destination peripheral delay as 0
|
||||
* \li Disable destination top priority
|
||||
* \li Set destination top priority channel as 0
|
||||
* \li Disable destination high priority
|
||||
* \li Set destination high priority channel as 0
|
||||
* \li Disable the joint mode
|
||||
* \li Disable the endian swap
|
||||
* \param[out] config Pointer to the configuration
|
||||
*
|
||||
*/
|
||||
void dma_get_config_defaults(struct dma_resource_config *config)
|
||||
{
|
||||
/* DMA source configuration */
|
||||
config->src.max_burst = 1;
|
||||
config->src.tokens = 1;
|
||||
config->src.enable_inc_addr = true;
|
||||
config->src.periph = MEMORY_DMA_PERIPHERAL;
|
||||
config->src.periph_delay = 0;
|
||||
config->src.enable_proi_top = false;
|
||||
config->src.proi_top_index = 0;
|
||||
config->src.enable_proi_high = false;
|
||||
config->src.proi_high_index = 0;
|
||||
/* DMA destination configuration */
|
||||
config->des.max_burst = 1;
|
||||
config->des.tokens = 1;
|
||||
config->des.enable_inc_addr = true;
|
||||
config->des.periph = MEMORY_DMA_PERIPHERAL;
|
||||
config->des.periph_delay = 0;
|
||||
config->des.enable_proi_top = false;
|
||||
config->des.proi_top_index = 0;
|
||||
config->des.enable_proi_high = false;
|
||||
config->des.proi_high_index = 0;
|
||||
/* DMA channel configuration */
|
||||
config->enable_joint_mode = false;
|
||||
config->swap = DMA_ENDIAN_NO_SWAP;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Configure the DMA resource.
|
||||
*
|
||||
* \param[in] dma_resource Pointer to a DMA resource instance
|
||||
* \param[out] config Configurations of the DMA resource
|
||||
*
|
||||
*/
|
||||
static void _dma_set_config(struct dma_resource *resource,
|
||||
struct dma_resource_config *config)
|
||||
{
|
||||
uint32_t regval = 0;
|
||||
|
||||
/* Static register configuration */
|
||||
regval = PROV_DMA_CTRL_CH0_STATIC_REG0_RD_BURST_MAX_SIZE(config->src.max_burst)|
|
||||
PROV_DMA_CTRL_CH0_STATIC_REG0_RD_TOKENS(config->src.tokens) |
|
||||
(config->src.enable_inc_addr << PROV_DMA_CTRL_CH0_STATIC_REG0_RD_INCR_Pos);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG0.reg, regval);
|
||||
/* Static register1 configuration */
|
||||
regval = PROV_DMA_CTRL_CH0_STATIC_REG1_WR_BURST_MAX_SIZE(config->des.max_burst) |
|
||||
PROV_DMA_CTRL_CH0_STATIC_REG1_WR_TOKENS(config->des.tokens) |
|
||||
(config->des.enable_inc_addr << PROV_DMA_CTRL_CH0_STATIC_REG0_RD_INCR_Pos);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG1.reg, regval);
|
||||
/* Static register2 configuration */
|
||||
regval = (config->enable_joint_mode << PROV_DMA_CTRL_CH0_STATIC_REG2_JOINT_Pos) |
|
||||
PROV_DMA_CTRL_CH0_STATIC_REG2_END_SWAP(config->swap);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG2.reg, regval);
|
||||
/* Static register4 configuration */
|
||||
regval = PROV_DMA_CTRL_CH0_STATIC_REG4_RD_PERIPH_NUM(config->src.periph) |
|
||||
PROV_DMA_CTRL_CH0_STATIC_REG4_RD_PERIPH_DELAY(config->src.periph_delay) |
|
||||
PROV_DMA_CTRL_CH0_STATIC_REG4_WR_PERIPH_NUM(config->des.periph) |
|
||||
PROV_DMA_CTRL_CH0_STATIC_REG4_WR_PERIPH_DELAY(config->des.periph_delay);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_STATIC_REG4.reg, regval);
|
||||
/* Priority channels configuration */
|
||||
regval = PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_TOP_NUM(config->src.proi_top_index) |
|
||||
(PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_TOP << config->src.enable_proi_top) |
|
||||
PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_HIGH_NUM(config->src.proi_high_index) |
|
||||
(PROV_DMA_CTRL_CORE_PRIORITY_RD_PRIO_HIGH << config->src.enable_proi_high) |
|
||||
PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_TOP_NUM(config->des.proi_top_index) |
|
||||
(PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_TOP << config->des.enable_proi_top) |
|
||||
PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_HIGH_NUM(config->des.proi_high_index) |
|
||||
(PROV_DMA_CTRL_CORE_PRIORITY_WR_PRIO_HIGH << config->des.enable_proi_high);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CORE_PRIORITY.reg, regval);
|
||||
/* Initial the global variety */
|
||||
for (int i = 0; i < DMA_CALLBACK_N; i++) {
|
||||
resource->callback[i] = NULL;
|
||||
}
|
||||
resource->callback_enable = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Free an allocated DMA resource.
|
||||
*
|
||||
* This function will free an allocated DMA resource.
|
||||
*
|
||||
* \param[in,out] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status of the free procedure.
|
||||
*
|
||||
* \retval STATUS_OK The DMA resource was freed successfully
|
||||
* \retval STATUS_BUSY The DMA resource was busy and can't be freed
|
||||
* \retval STATUS_ERR_NOT_INITIALIZED DMA resource was not initialized
|
||||
*/
|
||||
enum status_code dma_free(struct dma_resource *resource)
|
||||
{
|
||||
/* Check if channel is busy */
|
||||
if (dma_get_job_status(resource) == STATUS_BUSY) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
/* Check if DMA resource was not allocated */
|
||||
if (!(_dma_inst.allocated_channels & (1 << resource->channel_id))) {
|
||||
return STATUS_ERR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
/* Release the DMA resource */
|
||||
_dma_release_channel(resource->channel_id);
|
||||
|
||||
/* Reset the item in the DMA resource pool */
|
||||
_dma_active_resource[resource->channel_id] = NULL;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Add a DMA transfer descriptor to a DMA resource.
|
||||
*
|
||||
* This function will add a DMA transfer descriptor to a DMA resource.
|
||||
* If there was a transfer descriptor already allocated to the DMA resource,
|
||||
* the descriptor will be linked to the next descriptor address.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] descriptor Pointer to the transfer descriptor
|
||||
*
|
||||
* \retval STATUS_OK The descriptor is added to the DMA resource
|
||||
* \retval STATUS_BUSY The DMA resource was busy and the descriptor is not added
|
||||
*/
|
||||
enum status_code dma_add_descriptor(struct dma_resource *resource,
|
||||
struct dma_descriptor *descriptor)
|
||||
{
|
||||
struct dma_descriptor *desc = resource->descriptor;
|
||||
|
||||
/* Check if channel is busy */
|
||||
if (dma_get_job_status(resource) == STATUS_BUSY) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
/* Look up for an empty space for the descriptor */
|
||||
if (desc == NULL) {
|
||||
resource->descriptor = descriptor;
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG0.reg, descriptor->read_start_addr);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG1.reg, descriptor->write_start_addr);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG2.reg, descriptor->buffer_size);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG3.reg, 3);
|
||||
} else {
|
||||
/* Looking for end of descriptor link */
|
||||
while(((uint32_t)desc->cmd.next_addr) != 0) {
|
||||
desc = (struct dma_descriptor*)((uint32_t)desc->next);
|
||||
}
|
||||
if (resource->descriptor->cmd.next_addr == 0x0) {
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CMD_REG3.reg, ((uint32_t)descriptor & (~0x3)));
|
||||
}
|
||||
/* Set to the end of descriptor list */
|
||||
desc->next = (uint32_t)descriptor;
|
||||
/* The end of list should point to 0 */
|
||||
if (descriptor->cmd.next_addr != 0) {
|
||||
/* Enable transferred interrupt, and channel stops when buffer done */
|
||||
descriptor->next = 0x3;
|
||||
}
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Start a DMA transfer.
|
||||
*
|
||||
* This function will start a DMA transfer through an allocated DMA resource.
|
||||
*
|
||||
* \param[in,out] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status of the transfer start procedure.
|
||||
*
|
||||
* \retval STATUS_OK The transfer was started successfully
|
||||
* \retval STATUS_BUSY The DMA resource was busy and the transfer was not started
|
||||
* \retval STATUS_ERR_INVALID_ARG Transfer size is 0 and transfer was not started
|
||||
*/
|
||||
enum status_code dma_start_transfer_job(struct dma_resource *resource)
|
||||
{
|
||||
volatile uint32_t regval;
|
||||
|
||||
/* Check if resource was busy */
|
||||
if (resource->job_status == STATUS_BUSY) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
/* Check if transfer size is valid */
|
||||
if (resource->descriptor->buffer_size == 0) {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
/* Clear the interrupt flag */
|
||||
regval = get_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_STATUS_REG.reg);
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_CLEAR_REG.reg, regval);
|
||||
/* Set the interrupt flag */
|
||||
regval = PROV_DMA_CTRL_CH0_INT_ENABLE_REG_MASK & resource->callback_enable;
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_ENABLE_REG.reg, regval);
|
||||
/* Set job status */
|
||||
resource->job_status = STATUS_BUSY;
|
||||
|
||||
/* Enable the transfer channel */
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CH_ENABLE_REG.reg, 1);
|
||||
/* Start the transfer channel */
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_CH_START_REG.reg, 1);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
/**
|
||||
* \brief Get the channel index
|
||||
*
|
||||
* \param[in] channel Channel active
|
||||
*
|
||||
*/
|
||||
static uint8_t get_channel_index(uint8_t channel)
|
||||
{
|
||||
uint8_t index = 0;
|
||||
|
||||
channel = channel & 0x0f;
|
||||
do {
|
||||
channel = channel >> 1;
|
||||
index++;
|
||||
} while (channel);
|
||||
|
||||
return (index - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief DMA interrupt service routine.
|
||||
*
|
||||
*/
|
||||
static void dma_isr_handler( void )
|
||||
{
|
||||
uint8_t active_channel;
|
||||
static uint8_t channel_index; //
|
||||
struct dma_resource *resource;
|
||||
uint8_t isr;
|
||||
uint8_t isr_flag = 0;
|
||||
|
||||
/* Get active channel */
|
||||
active_channel = PROV_DMA_CTRL0->CORE_INT_STATUS.reg &
|
||||
PROV_DMA_CTRL_CORE_INT_STATUS_CHANNEL__Msk;
|
||||
|
||||
do {
|
||||
channel_index = get_channel_index(active_channel);
|
||||
/* Get active DMA resource based on channel */
|
||||
resource = _dma_active_resource[channel_index];
|
||||
isr = get_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_STATUS_REG.reg);
|
||||
/* Calculate block transfer size of the DMA transfer */
|
||||
resource->transfered_size = get_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_COUNT_REG.reg);
|
||||
|
||||
/* DMA channel interrupt handler */
|
||||
if (isr & (1 << DMA_CALLBACK_TRANSFER_DONE)) {
|
||||
/* Transfer complete flag */
|
||||
isr_flag = DMA_CALLBACK_TRANSFER_DONE;
|
||||
/* Set job status */
|
||||
resource->job_status = STATUS_OK;
|
||||
} else if (isr & (1 << DMA_CALLBACK_READ_ERR)) {
|
||||
/* Read error flag */
|
||||
isr_flag = DMA_CALLBACK_READ_ERR;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
} else if (isr & (1 << DMA_CALLBACK_WRITE_ERR)) {
|
||||
/* Write error flag */
|
||||
isr_flag = DMA_CALLBACK_WRITE_ERR;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
} else if (isr & (1 << DMA_CALLBACK_FIFO_OVERFLOW)) {
|
||||
/* Overflow flag */
|
||||
isr_flag = DMA_CALLBACK_FIFO_OVERFLOW;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
} else if (isr & (1 << DMA_CALLBACK_FIFO_UNDERFLOW)) {
|
||||
/* Underflow flag */
|
||||
isr_flag = DMA_CALLBACK_FIFO_UNDERFLOW;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
} else if (isr & (1 << DMA_CALLBACK_READ_TIMEOUT)) {
|
||||
/* Read timeout flag */
|
||||
isr_flag = DMA_CALLBACK_READ_TIMEOUT;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
} else if (isr & (1 << DMA_CALLBACK_WRITE_TIMEOUT)) {
|
||||
/* Write timeout flag */
|
||||
isr_flag = DMA_CALLBACK_WRITE_TIMEOUT;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
} else if (isr & (1 << DMA_CALLBACK_WDT_TRIGGER)) {
|
||||
/* Watchdog error flag */
|
||||
isr_flag = DMA_CALLBACK_WDT_TRIGGER;
|
||||
/* Set I/O ERROR status */
|
||||
resource->job_status = STATUS_ERR_IO;
|
||||
}
|
||||
|
||||
if (isr) {
|
||||
/* Clear the watch dog error flag */
|
||||
set_channel_reg_val(resource->channel_id, (uint32_t)&PROV_DMA_CTRL0->CH0_INT_CLEAR_REG.reg, 1<<isr_flag);
|
||||
/* Execute the callback function */
|
||||
if ((resource->callback_enable & (1<<isr_flag)) &&
|
||||
(resource->callback[isr_flag])) {
|
||||
resource->callback[isr_flag](resource);
|
||||
}
|
||||
}
|
||||
isr &= ~(1<<isr_flag);
|
||||
} while (isr);
|
||||
|
||||
NVIC_ClearPendingIRQ(PROV_DMA_CTRL0_IRQn);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Allocate a DMA with configurations.
|
||||
*
|
||||
* This function will allocate a proper channel for a DMA transfer request.
|
||||
*
|
||||
* \param[in,out] dma_resource Pointer to a DMA resource instance
|
||||
* \param[in] transfer_config Configurations of the DMA transfer
|
||||
*
|
||||
* \return Status of the allocation procedure.
|
||||
*
|
||||
* \retval STATUS_OK The DMA resource was allocated successfully
|
||||
* \retval STATUS_ERR_NOT_FOUND DMA resource allocation failed
|
||||
*/
|
||||
enum status_code dma_allocate(struct dma_resource *resource,
|
||||
struct dma_resource_config *config)
|
||||
{
|
||||
uint8_t new_channel;
|
||||
|
||||
if (!_dma_inst._dma_init) {
|
||||
/* Perform a reset before enable DMA controller */
|
||||
system_peripheral_reset(PERIPHERAL_DMA);
|
||||
/* Select Mux 15 as PROV_DMA_CTRL0 interrupt source */
|
||||
LPMCU_MISC_REGS0->IRQ_MUX_IO_SEL_3.bit.MUX_15 = LPMCU_MISC_REGS_IRQ_MUX_IO_SEL_3_MUX_15_16_Val;
|
||||
system_register_isr(31, (uint32_t)dma_isr_handler);
|
||||
|
||||
_dma_inst._dma_init = true;
|
||||
}
|
||||
|
||||
new_channel = _dma_find_first_free_channel_and_allocate();
|
||||
/* If no channel available, return not found */
|
||||
if (new_channel == DMA_INVALID_CHANNEL) {
|
||||
return STATUS_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Set the channel */
|
||||
resource->channel_id = new_channel;
|
||||
/* Configure the DMA control,channel registers and descriptors here */
|
||||
_dma_set_config(resource, config);
|
||||
|
||||
resource->descriptor = NULL;
|
||||
|
||||
/* Log the DMA resource into the internal DMA resource pool */
|
||||
_dma_active_resource[resource->channel_id] = resource;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
650
atmel-samd/asf/sam0/drivers/dma/dma_sam_b.h
Normal file
650
atmel-samd/asf/sam0/drivers/dma/dma_sam_b.h
Normal file
@ -0,0 +1,650 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief Direct Memory Access Controller Driver for SAMB
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef DMA_H_INCLUDED
|
||||
#define DMA_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup asfdoc_samb_dma_group SAM Direct Memory Access Controller Driver (DMAC)
|
||||
*
|
||||
* This driver for Atmel® | SMART SAM devices provides an interface for the configuration
|
||||
* and management of the Direct Memory Access Controller(DMAC) module within
|
||||
* the device. The DMAC can transfer data between memories and peripherals, and
|
||||
* thus off-load these tasks from the CPU. The module supports peripheral to
|
||||
* peripheral, peripheral to memory, memory to peripheral, and memory to memory
|
||||
* transfers.
|
||||
*
|
||||
* The following peripherals are used by the DMAC Driver:
|
||||
* - DMAC (Direct Memory Access Controller)
|
||||
*
|
||||
* The following devices can use this module:
|
||||
* - Atmel | SMART SAM B11
|
||||
*
|
||||
* The outline of this documentation is as follows:
|
||||
* - \ref asfdoc_samb_dma_prerequisites
|
||||
* - \ref asfdoc_samb_dma_module_overview
|
||||
* - \ref asfdoc_samb_dma_special_considerations
|
||||
* - \ref asfdoc_samb_dma_extra_info
|
||||
* - \ref asfdoc_samb_dma_examples
|
||||
* - \ref asfdoc_samb_dma_api_overview
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_prerequisites Prerequisites
|
||||
*
|
||||
* There are no prerequisites for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_module_overview Module Overview
|
||||
*
|
||||
* SAM devices with DMAC enables high data transfer rates with minimum
|
||||
* CPU intervention and frees up CPU time. With access to all peripherals,
|
||||
* the DMAC can handle automatic transfer of data to/from modules.
|
||||
* It supports static and incremental addressing for both source and
|
||||
* destination.
|
||||
*
|
||||
* The DMAC when used with peripheral triggers, provides a
|
||||
* considerable advantage by reducing the power consumption and performing
|
||||
* data transfer in the background.
|
||||
* The CPU can remain in sleep during this time to reduce power consumption.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Device</th>
|
||||
* <th>Dma channel number</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>SAMB11</td>
|
||||
* <td>4</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
* The DMA channel operation can be suspended at any time by software,
|
||||
* or after selectable descriptor execution. The DMAC driver for SAM
|
||||
* supports four types of transfers such as peripheral to peripheral,
|
||||
* peripheral to memory, memory to peripheral, and memory to memory.
|
||||
*
|
||||
* The basic transfer unit is a beat which is defined as a single bus access.
|
||||
* There can be multiple beats in a single block transfer and multiple block
|
||||
* transfers in a DMA transaction.
|
||||
* DMA transfer is based on descriptors, which holds transfer properties
|
||||
* such as the source and destination addresses, transfer counter, and other
|
||||
* additional transfer control information.
|
||||
* The descriptors can be static or linked. When static, a single block transfer
|
||||
* is performed. When linked, a number of transfer descriptors can be used to
|
||||
* enable multiple block transfers within a single DMA transaction.
|
||||
*
|
||||
* The implementation of the DMA driver is based on the idea that DMA channel
|
||||
* is a finite resource of entities with the same abilities. A DMA channel resource
|
||||
* is able to move a defined set of data from a source address to destination
|
||||
* address triggered by a transfer trigger. On the SAM devices there are 12
|
||||
* DMA resources available for allocation. Each of these DMA resources can trigger
|
||||
* interrupt callback routines.
|
||||
* The other main features are:
|
||||
*
|
||||
* - Selectable transfer trigger source
|
||||
* - Software
|
||||
* - Peripheral
|
||||
* - Tree level channel priority
|
||||
* - Normal level
|
||||
* - High level
|
||||
* - Top level
|
||||
* - Optional interrupt generation on transfer complete, channel error
|
||||
* - Supports multi-buffer or circular buffer mode by linking multiple descriptors
|
||||
* - Beat size configurable as 8-bit, 16-bit, or 32-bit
|
||||
*
|
||||
* A simplified block diagram of the DMA Resource can be seen in
|
||||
* \ref asfdoc_samb_dma_module_block_diagram "the figure below".
|
||||
*
|
||||
* \anchor asfdoc_samb_dma_module_block_diagram
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* splines = false;
|
||||
* rankdir=LR;
|
||||
*
|
||||
* mux1 [label="Transfer Trigger", shape=box];
|
||||
*
|
||||
* dma [label="DMA Channel", shape=polygon, sides=6, orientation=60, style=filled, fillcolor=darkolivegreen1, height=1, width=1];
|
||||
* descriptor [label="Transfer Descriptor", shape=box, style=filled, fillcolor=lightblue];
|
||||
*
|
||||
* mux1 -> dma;
|
||||
* descriptor -> dma;
|
||||
*
|
||||
* interrupt [label="Interrupt", shape=box];
|
||||
* events [label="Events", shape=box];
|
||||
*
|
||||
* dma:e -> interrupt:w;
|
||||
* dma:e -> events:w;
|
||||
*
|
||||
* {rank=same; descriptor dma}
|
||||
*
|
||||
* }
|
||||
* \enddot
|
||||
*
|
||||
* \subsection asfdoc_samb_dma_module_overview_dma_channels DMA Channels
|
||||
* The DMAC in each device consists of several DMA channels, which
|
||||
* along with the transfer descriptors defines the data transfer properties.
|
||||
* - The transfer control descriptor defines the source and destination
|
||||
* addresses, source and destination address increment settings, the
|
||||
* block transfer count
|
||||
* - Dedicated channel registers control the peripheral trigger source,
|
||||
* trigger mode settings, and channel priority level settings
|
||||
*
|
||||
* With a successful DMA resource allocation, a dedicated
|
||||
* DMA channel will be assigned. The channel will be occupied until the
|
||||
* DMA resource is freed. A DMA resource handle is used to identify the specific
|
||||
* DMA resource.
|
||||
* When there are multiple channels with active requests, the arbiter prioritizes
|
||||
* the channels requesting access to the bus.
|
||||
*
|
||||
* \subsection asfdoc_samb_dma_module_overview_dma_trigger DMA Triggers
|
||||
* DMA transfer can be started only when a DMA transfer request is acknowledged/granted by the arbiter. A
|
||||
* transfer request can be triggered from software, peripheral. There
|
||||
* are dedicated source trigger selections for each DMA channel usage.
|
||||
*
|
||||
* \subsection asfdoc_samb_dma_module_overview_dma_transfer_descriptor DMA Transfer Descriptor
|
||||
* The transfer descriptor resides in the SRAM and
|
||||
* defines these channel properties.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Field name</th>
|
||||
* <th>Field width</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Source Address</td>
|
||||
* <td>32 bits</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Destination Address</td>
|
||||
* <td>32 bits</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Block Transfer Counter</td>
|
||||
* <td>32 bits</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Descriptor Next Address</td>
|
||||
* <td>30 bits</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Block Transfer Interrupt</td>
|
||||
* <td>1 bit</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Block Transfer Stop Control</td>
|
||||
* <td>1 bit</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
* Before starting a transfer, at least one descriptor should be configured.
|
||||
* After a successful allocation of a DMA channel, the transfer descriptor can
|
||||
* be added with a call to \ref dma_add_descriptor(). If there is a transfer
|
||||
* descriptor already allocated to the DMA resource, the descriptor will
|
||||
* be linked to the next descriptor address.
|
||||
*
|
||||
* \subsection asfdoc_samb_dma_module_overview_dma_output DMA Interrupts
|
||||
* Both an interrupt callback and an peripheral can be triggered by the
|
||||
* DMA transfer. Three types of callbacks are supported by the DMA driver:
|
||||
* transfer complete, channel suspend, and transfer error. Each of these callback
|
||||
* types can be registered and enabled for each channel independently through
|
||||
* the DMA driver API.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_special_considerations Special Considerations
|
||||
*
|
||||
* There are no special considerations for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_extra_info Extra Information
|
||||
*
|
||||
* For extra information, see \ref asfdoc_samb_dma_extra. This includes:
|
||||
* - \ref asfdoc_samb_dma_extra_acronyms
|
||||
* - \ref asfdoc_samb_dma_extra_dependencies
|
||||
* - \ref asfdoc_samb_dma_extra_errata
|
||||
* - \ref asfdoc_samb_dma_extra_history
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_examples Examples
|
||||
*
|
||||
* For a list of examples related to this driver, see
|
||||
* \ref asfdoc_samb_dma_exqsg.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_api_overview API Overview
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include <system_sam_b.h>
|
||||
#include "conf_dma.h"
|
||||
|
||||
/** DMA IRQn number. */
|
||||
#define PROV_DMA_CTRL0_IRQn 15
|
||||
|
||||
/** DMA invalid channel number. */
|
||||
#define DMA_INVALID_CHANNEL 0xff
|
||||
|
||||
/** DMA peripheral index */
|
||||
enum dma_peripheral_index {
|
||||
MEMORY_DMA_PERIPHERAL = 0,
|
||||
UART0RX_DMA_PERIPHERAL,
|
||||
UART0TX_DMA_PERIPHERAL,
|
||||
UART1RX_DMA_PERIPHERAL,
|
||||
UART1TX_DMA_PERIPHERAL,
|
||||
SPI0RX_DMA_PERIPHERAL,
|
||||
SPI0TX_DMA_PERIPHERAL,
|
||||
SPI1RX_DMA_PERIPHERAL,
|
||||
SPI1TX_DMA_PERIPHERAL,
|
||||
I2C0RX_DMA_PERIPHERAL,
|
||||
I2C0TX_DMA_PERIPHERAL,
|
||||
I2C1RX_DMA_PERIPHERAL,
|
||||
I2C1TX_DMA_PERIPHERAL,
|
||||
DUALTIMER0_DMA_PERIPHERAL = 15,
|
||||
TIMER0_DMA_PERIPHERAL,
|
||||
};
|
||||
|
||||
/** DMA channel index */
|
||||
enum dma_ch_index {
|
||||
/** DMA channel 0 */
|
||||
DMA_CHANNEL_0 = 0,
|
||||
/** DMA channel 1 */
|
||||
DMA_CHANNEL_1,
|
||||
/** DMA channel 2 */
|
||||
DMA_CHANNEL_2,
|
||||
/** DMA channel 3 */
|
||||
DMA_CHANNEL_3,
|
||||
};
|
||||
|
||||
enum dma_endian_swap {
|
||||
/** DMA endian no swap */
|
||||
DMA_ENDIAN_NO_SWAP,
|
||||
/** DMA endian 16-bit */
|
||||
DMA_ENDIAN_SIZE_16,
|
||||
/** DMA endian 32-bit */
|
||||
DMA_ENDIAN_SIZE_32,
|
||||
/** DMA endian 64-bit */
|
||||
DMA_ENDIAN_SIZE_64,
|
||||
};
|
||||
|
||||
/**
|
||||
* Callback types for DMA callback driver.
|
||||
*/
|
||||
enum dma_callback_type {
|
||||
/** Callback for transfer complete */
|
||||
DMA_CALLBACK_TRANSFER_DONE,
|
||||
/** AHB read slave error */
|
||||
DMA_CALLBACK_READ_ERR,
|
||||
/** AHB write slave error */
|
||||
DMA_CALLBACK_WRITE_ERR,
|
||||
/** FIFO has been overflown */
|
||||
DMA_CALLBACK_FIFO_OVERFLOW,
|
||||
/** FIFO has been underflows */
|
||||
DMA_CALLBACK_FIFO_UNDERFLOW,
|
||||
/** Read timeout on AHB bus (timeout value fixed at 1024 cycles) */
|
||||
DMA_CALLBACK_READ_TIMEOUT,
|
||||
/** Write timeout on AHB bus (timeout value fixed at 1024 cycles) */
|
||||
DMA_CALLBACK_WRITE_TIMEOUT,
|
||||
/** Channel active but did not start a burst for 2048 cycles */
|
||||
DMA_CALLBACK_WDT_TRIGGER,
|
||||
/** Number of available callbacks */
|
||||
DMA_CALLBACK_N,
|
||||
};
|
||||
|
||||
/**
|
||||
* DMA transfer descriptor configuration. When the source or destination address
|
||||
* increment is enabled, the addresses stored into the configuration structure
|
||||
* must correspond to the end of the transfer.
|
||||
*/
|
||||
struct dma_descriptor {
|
||||
/** Start address of read buffer */
|
||||
uint32_t read_start_addr;
|
||||
/** Start address of write buffer */
|
||||
uint32_t write_start_addr;
|
||||
/** Size (in bytes) of buffer to transfer */
|
||||
uint32_t buffer_size;
|
||||
union {
|
||||
struct {
|
||||
/** Active high interrupt enable once buffer has been transferred */
|
||||
uint32_t set_interrupt:1;
|
||||
/** If set, channel stops when buffer done, otherwise load from cmd_next_addr */
|
||||
uint32_t last:1;
|
||||
/** Address of next command if cmd_last is not set */
|
||||
uint32_t next_addr:30;
|
||||
} cmd;
|
||||
uint32_t next;
|
||||
};
|
||||
};
|
||||
/** Structure for DMA source/description */
|
||||
struct dma_config {
|
||||
/** Maximum number of bytes of an AHB read/write burst */
|
||||
uint8_t max_burst;
|
||||
/** Number of AHB read/write commands to issue before channel is released */
|
||||
uint8_t tokens;
|
||||
/** If true, the controller will increment the next burst address */
|
||||
bool enable_inc_addr;
|
||||
/** Index of peripheral to read/write from (0 if memory or no peripheral flow control) */
|
||||
enum dma_peripheral_index periph;
|
||||
/**
|
||||
* Number of cycles to wait for read/write request signal to update
|
||||
* after issuing the read/write clear signal
|
||||
*/
|
||||
uint8_t periph_delay;
|
||||
/** Top priority enable */
|
||||
bool enable_proi_top;
|
||||
/** Top priority channel index */
|
||||
uint8_t proi_top_index;
|
||||
/** High priority enable */
|
||||
bool enable_proi_high;
|
||||
/** High priority channel index */
|
||||
uint8_t proi_high_index;
|
||||
};
|
||||
|
||||
/** Structure for DMA transfer resource */
|
||||
struct dma_resource_config {
|
||||
struct dma_config src;
|
||||
struct dma_config des;
|
||||
/** If true, channel will work in joint mode */
|
||||
bool enable_joint_mode;
|
||||
/** Endian Byte Swapping */
|
||||
enum dma_endian_swap swap;
|
||||
};
|
||||
|
||||
/** Forward definition of the DMA resource */
|
||||
struct dma_resource;
|
||||
/** Type definition for a DMA resource callback function */
|
||||
typedef void (*dma_callback_t)(struct dma_resource *const resource);
|
||||
|
||||
/** Structure for DMA transfer resource */
|
||||
struct dma_resource {
|
||||
/** Allocated DMA channel ID */
|
||||
uint8_t channel_id;
|
||||
/** Array of callback functions for DMA transfer job */
|
||||
dma_callback_t callback[DMA_CALLBACK_N];
|
||||
/** Bit mask for enabled callbacks */
|
||||
uint8_t callback_enable;
|
||||
/** Status of the last job */
|
||||
volatile enum status_code job_status;
|
||||
/** Transferred data size */
|
||||
uint32_t transfered_size;
|
||||
/** DMA transfer descriptor */
|
||||
struct dma_descriptor* descriptor;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Get DMA resource status.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
*
|
||||
* \return Status of the DMA resource.
|
||||
*/
|
||||
static inline enum status_code dma_get_job_status(struct dma_resource *resource)
|
||||
{
|
||||
return resource->job_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Enable a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_enable_callback(struct dma_resource *resource,
|
||||
enum dma_callback_type type)
|
||||
{
|
||||
resource->callback_enable |= 1 << type;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Disable a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_disable_callback(struct dma_resource *resource,
|
||||
enum dma_callback_type type)
|
||||
{
|
||||
resource->callback_enable &= ~(1 << type);
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Register a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* There are three types of callback functions, which can be registered:
|
||||
* - Callback for transfer complete
|
||||
* - Callback for transfer error
|
||||
* - Callback for channel suspend
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] callback Pointer to the callback function
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_register_callback(struct dma_resource *resource,
|
||||
dma_callback_t callback, enum dma_callback_type type)
|
||||
{
|
||||
resource->callback[type] = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Unregister a callback function for a dedicated DMA resource.
|
||||
*
|
||||
* There are three types of callback functions:
|
||||
* - Callback for transfer complete
|
||||
* - Callback for transfer error
|
||||
* - Callback for channel suspend
|
||||
*
|
||||
* The application can unregister any of the callback functions which
|
||||
* are already registered and are no longer needed.
|
||||
*
|
||||
* \param[in] resource Pointer to the DMA resource
|
||||
* \param[in] type Callback function type
|
||||
*
|
||||
*/
|
||||
static inline void dma_unregister_callback(struct dma_resource *resource,
|
||||
enum dma_callback_type type)
|
||||
{
|
||||
resource->callback[type] = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Initializes DMA transfer configuration with predefined default values.
|
||||
*
|
||||
* This function will initialize a given DMA descriptor configuration structure to
|
||||
* a set of known default values. This function should be called on
|
||||
* any new instance of the configuration structure before being
|
||||
* modified by the user application.
|
||||
*
|
||||
* The default configuration is as follows:
|
||||
* \li Set the read start address as 0
|
||||
* \li Set the write start address as 0
|
||||
* \li Set buffer size as 1
|
||||
* \li Set beat size as byte
|
||||
* \li Enable the interrupt
|
||||
* \li Enable the channel stops when buffer done
|
||||
* \li Set next command address to 0
|
||||
* \param[out] config Pointer to the configuration
|
||||
*
|
||||
*/
|
||||
static inline void dma_descriptor_get_config_defaults(struct dma_descriptor *config)
|
||||
{
|
||||
/* Default read buffer size is set to 0 */
|
||||
config->read_start_addr = 0;
|
||||
/* Default write buffer size is set to 0 */
|
||||
config->write_start_addr = 0;
|
||||
/* Set beat size to one byte */
|
||||
config->buffer_size = 1;
|
||||
/* Enable transferred interrupt */
|
||||
config->cmd.set_interrupt = 1;
|
||||
/* Channel stops when buffer done */
|
||||
config->cmd.last = 1;
|
||||
/* Set next command to 0 */
|
||||
config->cmd.next_addr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Update DMA descriptor.
|
||||
*
|
||||
* This function can update the descriptor of an allocated DMA resource.
|
||||
*
|
||||
*/
|
||||
static inline void dma_update_descriptor(struct dma_resource *resource,
|
||||
struct dma_descriptor* descriptor)
|
||||
{
|
||||
resource->descriptor = descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Reset DMA descriptor.
|
||||
*
|
||||
* This function will clear the DESCADDR register of an allocated DMA resource.
|
||||
*
|
||||
*/
|
||||
static inline void dma_reset_descriptor(struct dma_resource *resource)
|
||||
{
|
||||
resource->descriptor = NULL;
|
||||
}
|
||||
|
||||
void dma_get_config_defaults(struct dma_resource_config *config);
|
||||
enum status_code dma_allocate(struct dma_resource *resource,
|
||||
struct dma_resource_config *config);
|
||||
enum status_code dma_add_descriptor(struct dma_resource *resource,
|
||||
struct dma_descriptor* descriptor);
|
||||
enum status_code dma_start_transfer_job(struct dma_resource *resource);
|
||||
enum status_code dma_free(struct dma_resource *resource);
|
||||
uint8_t dma_get_status(uint8_t channel);
|
||||
uint8_t dma_get_interrupt_status(uint8_t channel);
|
||||
void dma_clear_interrupt_status(uint8_t channel, uint8_t flag);
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \page asfdoc_samb_dma_extra Extra Information for DMAC Driver
|
||||
*
|
||||
* \section asfdoc_samb_dma_extra_acronyms Acronyms
|
||||
* Below is a table listing the acronyms used in this module, along with their
|
||||
* intended meanings.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Acronym</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>DMA</td>
|
||||
* <td>Direct Memory Access</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>DMAC</td>
|
||||
* <td>Direct Memory Access Controller </td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>CPU</td>
|
||||
* <td>Central Processing Unit</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_extra_dependencies Dependencies
|
||||
* There are no dependencies related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_extra_errata Errata
|
||||
* There are no errata related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_samb_dma_extra_history Module History
|
||||
* An overview of the module history is presented in the table below, with
|
||||
* details on the enhancements and fixes made to the module since its first
|
||||
* release. The current version of this corresponds to the newest version in
|
||||
* the table.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Changelog</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Initial Release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page asfdoc_samb_dma_exqsg Examples for DMAC Driver
|
||||
*
|
||||
* This is a list of the available Quick Start Guides (QSGs) and example
|
||||
* applications for \ref asfdoc_samb_dma_group. QSGs are simple examples with
|
||||
* step-by-step instructions to configure and use this driver in a selection of
|
||||
* use cases. Note that QSGs can be compiled as a standalone application or be
|
||||
* added to the user application.
|
||||
*
|
||||
* - \subpage asfdoc_samb_dma_basic_use_case
|
||||
*
|
||||
* \note More DMA usage examples are available in peripheral QSGs.
|
||||
*
|
||||
* \page asfdoc_samb_dma_document_revision_history Document Revision History
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Doc. Rev.</td>
|
||||
* <th>Date</td>
|
||||
* <th>Comments</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>A</td>
|
||||
* <td>09/2015</td>
|
||||
* <td>Initial release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* DMA_H_INCLUDED */
|
51
atmel-samd/asf/sam0/drivers/dma/module_config/conf_dma.h
Normal file
51
atmel-samd/asf/sam0/drivers/dma/module_config/conf_dma.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Direct Memory Access Driver Configuration Header
|
||||
*
|
||||
* Copyright (C) 2013-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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef CONF_DMA_H_INCLUDED
|
||||
#define CONF_DMA_H_INCLUDED
|
||||
|
||||
# define CONF_MAX_USED_CHANNEL_NUM 5
|
||||
|
||||
#endif
|
729
atmel-samd/asf/sam0/drivers/events/events.h
Normal file
729
atmel-samd/asf/sam0/drivers/events/events.h
Normal file
@ -0,0 +1,729 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Event System Driver
|
||||
*
|
||||
* Copyright (C) 2012-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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef EVENTS_H_INCLUDED
|
||||
#define EVENTS_H_INCLUDED
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \defgroup asfdoc_sam0_events_group SAM Event System (EVENTS) Driver
|
||||
*
|
||||
* This driver for Atmel® | SMART ARM®-based microcontrollers provides
|
||||
* an interface for the configuration and management of the device's peripheral
|
||||
* event resources and users within the device, including enabling and disabling
|
||||
* of peripheral source selection and synchronization of clock domains between
|
||||
* various modules. The following API modes is covered by this manual:
|
||||
* - Polled API
|
||||
* \if EVENTS_INTERRUPT_HOOK_MODE
|
||||
* - Interrupt hook API
|
||||
* \endif
|
||||
*
|
||||
* The following peripheral is used by this module:
|
||||
* - EVSYS (Event System Management)
|
||||
*
|
||||
* The following devices can use this module:
|
||||
* - Atmel | SMART SAM D20/D21
|
||||
* - Atmel | SMART SAM R21
|
||||
* - Atmel | SMART SAM D09/D10/D11
|
||||
* - Atmel | SMART SAM L21/L22
|
||||
* - Atmel | SMART SAM DA1
|
||||
* - Atmel | SMART SAM C20/C21
|
||||
* - Atmel | SMART SAM R30
|
||||
*
|
||||
* The outline of this documentation is as follows:
|
||||
* - \ref asfdoc_sam0_events_prerequisites
|
||||
* - \ref asfdoc_sam0_events_module_overview
|
||||
* - \ref asfdoc_sam0_events_special_considerations
|
||||
* - \ref asfdoc_sam0_events_extra_info
|
||||
* - \ref asfdoc_sam0_events_examples
|
||||
* - \ref asfdoc_sam0_events_api_overview
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_prerequisites Prerequisites
|
||||
*
|
||||
* There are no prerequisites for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_module_overview Module Overview
|
||||
*
|
||||
* Peripherals within the SAM devices are capable of generating two types of
|
||||
* actions in response to given stimulus; set a register flag for later
|
||||
* intervention by the CPU (using interrupt or polling methods), or generate
|
||||
* event signals, which can be internally routed directly to other
|
||||
* peripherals within the device. The use of events allows for direct actions
|
||||
* to be performed in one peripheral in response to a stimulus in another
|
||||
* without CPU intervention. This can lower the overall power consumption of the
|
||||
* system if the CPU is able to remain in sleep modes for longer periods
|
||||
* (SleepWalking), and lowers the latency of the system response.
|
||||
*
|
||||
* The event system is comprised of a number of freely configurable Event
|
||||
* resources, plus a number of fixed Event Users. Each Event resource can be
|
||||
* configured to select the input peripheral that will generate the events
|
||||
* signal, as well as the synchronization path and edge detection mode.
|
||||
* The fixed-function Event Users, connected to peripherals within the device,
|
||||
* can then subscribe to an Event resource in a one-to-many relationship in order
|
||||
* to receive events as they are generated. An overview of the event system
|
||||
* chain is shown in
|
||||
* \ref asfdoc_sam0_events_module_overview_fig "the figure below".
|
||||
*
|
||||
* \anchor asfdoc_sam0_events_module_overview_fig
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* rankdir=LR;
|
||||
* node [label="Source\nPeripheral\n(Generator)" shape=ellipse style=filled fillcolor=lightgray] src_peripheral;
|
||||
* node [label="Event\nResource A" shape=square style=""] event_gen0;
|
||||
* node [label="Event\nUser X" shape=square style=""] event_user0;
|
||||
* node [label="Event\nUser Y" shape=square style=""] event_user1;
|
||||
* node [label="Destination\nPeripheral\n(User)" shape=ellipse style=filled fillcolor=lightgray] dst_peripheral0;
|
||||
* node [label="Destination\nPeripheral\n(User)" shape=ellipse style=filled fillcolor=lightgray] dst_peripheral1;
|
||||
*
|
||||
* src_peripheral -> event_gen0;
|
||||
* event_gen0 -> event_user0;
|
||||
* event_gen0 -> event_user1;
|
||||
* event_user0 -> dst_peripheral0;
|
||||
* event_user1 -> dst_peripheral1;
|
||||
* }
|
||||
* \enddot
|
||||
*
|
||||
* There are many different events that can be routed in the device, which can
|
||||
* then trigger many different actions. For example, an Analog Comparator module
|
||||
* could be configured to generate an event when the input signal rises above
|
||||
* the compare threshold, which then triggers a Timer Counter module to capture
|
||||
* the current count value for later use.
|
||||
*
|
||||
* \subsection asfdoc_sam0_events_module_overview_event_channels Event Channels
|
||||
* The Event module in each device consists of several channels, which can be
|
||||
* freely linked to an event generator (i.e. a peripheral within the device
|
||||
* that is capable of generating events). Each channel can be individually
|
||||
* configured to select the generator peripheral, signal path, and edge detection
|
||||
* applied to the input event signal, before being passed to any event user(s).
|
||||
*
|
||||
* Event channels can support multiple users within the device in a standardized
|
||||
* manner. When an Event User is linked to an Event Channel, the channel will
|
||||
* automatically handshake with all attached users to ensure that all modules
|
||||
* correctly receive and acknowledge the event.
|
||||
*
|
||||
* \subsection asfdoc_sam0_events_module_overview_event_users Event Users
|
||||
* Event Users are able to subscribe to an Event Channel, once it has been
|
||||
* configured. Each Event User consists of a fixed connection to one of the
|
||||
* peripherals within the device (for example, an ADC module, or Timer module)
|
||||
* and is capable of being connected to a single Event Channel.
|
||||
*
|
||||
* \subsection asfdoc_sam0_events_module_overview_edge_detection Edge Detection
|
||||
* For asynchronous events, edge detection on the event input is not possible,
|
||||
* and the event signal must be passed directly between the event generator and
|
||||
* event user. For synchronous and re-synchronous events, the input signal from
|
||||
* the event generator must pass through an edge detection unit, so that only
|
||||
* the rising, falling, or both edges of the event signal triggers an action in
|
||||
* the event user.
|
||||
*
|
||||
* \subsection asfdoc_sam0_events_module_overview_path_selection Path Selection
|
||||
* The event system in the SAM devices supports three signal path types from
|
||||
* the event generator to Event Users: asynchronous, synchronous, and
|
||||
* re-synchronous events.
|
||||
*
|
||||
* \subsubsection asfdoc_sam0_events_module_overview_path_selection_async Asynchronous Paths
|
||||
* Asynchronous event paths allow for an asynchronous connection between the
|
||||
* event generator and Event Users, when the source and destination
|
||||
* peripherals share the same \ref asfdoc_sam0_system_clock_group "Generic Clock"
|
||||
* channel. In this mode the event is propagated between the source and
|
||||
* destination directly to reduce the event latency, thus no edge detection is
|
||||
* possible. The asynchronous event chain is shown in
|
||||
* \ref asfdoc_sam0_events_module_async_path_fig "the figure below".
|
||||
*
|
||||
* \anchor asfdoc_sam0_events_module_async_path_fig
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* rankdir=LR;
|
||||
* node [label="Source\nPeripheral" shape=ellipse style=filled fillcolor=lightgray] src_peripheral;
|
||||
* node [label="<f0> EVSYS | <f1> Event\nChannel/User" fillcolor=white style="dashed" shape=record] events_chan;
|
||||
* node [label="Destination\nPeripheral" shape=ellipse style=filled fillcolor=lightgray] dst_peripheral;
|
||||
*
|
||||
* src_peripheral -> events_chan;
|
||||
* events_chan -> dst_peripheral;
|
||||
*
|
||||
* }
|
||||
* \enddot
|
||||
* \note Identically shaped borders in the diagram indicate a shared generic clock channel.
|
||||
*
|
||||
* \subsubsection asfdoc_sam0_events_module_overview_path_selection_sync Synchronous Paths
|
||||
* The Synchronous event path should be used when edge detection or interrupts
|
||||
* from the event channel are required, and the source event generator and the
|
||||
* event channel shares the same Generic Clock channel. The synchronous event
|
||||
* chain is shown in
|
||||
* \ref asfdoc_sam0_events_module_sync_path_fig "the figure below".
|
||||
*
|
||||
* Not all peripherals support Synchronous event paths; refer to the device datasheet.
|
||||
*
|
||||
* \anchor asfdoc_sam0_events_module_sync_path_fig
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* rankdir=LR;
|
||||
* node [label="Source\nPeripheral" shape=ellipse style="filled, dashed" fillcolor=lightgray] src_peripheral;
|
||||
* node [label="<f0> EVSYS | <f1> Event\nChannel/User" fillcolor=white shape=record style="dashed"] events_chan;
|
||||
* node [label="Destination\nPeripheral" shape=ellipse style="filled, solid" fillcolor=lightgray] dst_peripheral;
|
||||
*
|
||||
* src_peripheral -> events_chan;
|
||||
* events_chan -> dst_peripheral;
|
||||
*
|
||||
* }
|
||||
* \enddot
|
||||
* \note Identically shaped borders in the diagram indicate a shared generic clock channel.
|
||||
*
|
||||
* \subsubsection asfdoc_sam0_events_module_overview_path_selection_resync Re-synchronous Paths
|
||||
* Re-synchronous event paths are a special form of synchronous events, where
|
||||
* when edge detection or interrupts from the event channel are required, but
|
||||
* the event generator and the event channel use different Generic Clock
|
||||
* channels. The re-synchronous path allows the Event System to synchronize the
|
||||
* incoming event signal from the Event Generator to the clock of the Event
|
||||
* System module to avoid missed events, at the cost of a higher latency due to
|
||||
* the re-synchronization process. The re-synchronous event chain is shown in
|
||||
* \ref asfdoc_sam0_events_module_resync_path_fig "the figure below".
|
||||
*
|
||||
* Not all peripherals support re-synchronous event paths; refer to the device datasheet.
|
||||
* \anchor asfdoc_sam0_events_module_resync_path_fig
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* rankdir=LR;
|
||||
* node [label="Source\nPeripheral" shape=ellipse style="filled, dotted" fillcolor=lightgray] src_peripheral;
|
||||
* node [label="<f0> EVSYS | <f1> Event\nChannel/User" fillcolor=white shape=record style="dashed"] events_chan;
|
||||
* node [label="Destination\nPeripheral" shape=ellipse style=filled fillcolor=lightgray] dst_peripheral;
|
||||
*
|
||||
* src_peripheral -> events_chan;
|
||||
* events_chan -> dst_peripheral;
|
||||
*
|
||||
* }
|
||||
* \enddot
|
||||
* \note Identically shaped borders in the diagram indicate a shared generic clock channel.
|
||||
*
|
||||
* \subsection asfdoc_sam0_events_module_overview_physical Physical Connection
|
||||
*
|
||||
* \ref asfdoc_sam0_events_module_int_connections_fig "The diagram below"
|
||||
* shows how this module is interconnected within the device.
|
||||
*
|
||||
* \anchor asfdoc_sam0_events_module_int_connections_fig
|
||||
* \dot
|
||||
* digraph overview {
|
||||
* rankdir=LR;
|
||||
* node [label="Source\nPeripherals" shape=ellipse style=filled fillcolor=lightgray] src_peripheral;
|
||||
*
|
||||
* subgraph driver {
|
||||
* node [label="<f0> EVSYS | <f1> Event Channels" fillcolor=white shape=record] events_chan;
|
||||
* node [label="<f0> EVSYS | <f1> Event Users" fillcolor=white shape=record] events_user;
|
||||
* }
|
||||
*
|
||||
* node [label="Destination\nPeripherals" shape=ellipse style=filled fillcolor=lightgray] dst_peripheral;
|
||||
*
|
||||
* src_peripheral -> events_chan:f1 [label="Source\nMUXs"];
|
||||
* events_chan:f1 -> events_user:f1 [label="Channel\nMUXs"];
|
||||
* events_user:f1 -> dst_peripheral;
|
||||
* }
|
||||
* \enddot
|
||||
*
|
||||
* \subsection asfdoc_sam0_events_module_overview_config Configuring Events
|
||||
* For SAM devices, several steps are required to properly configure an
|
||||
* event chain, so that hardware peripherals can respond to events generated by
|
||||
* each other, as listed below.
|
||||
*
|
||||
* \subsubsection asfdoc_sam0_events_module_overview_config_src Source Peripheral
|
||||
* -# The source peripheral (that will generate events) must be configured and
|
||||
* enabled.
|
||||
* -# The source peripheral (that will generate events) must have an output
|
||||
* event enabled.
|
||||
|
||||
* \subsubsection asfdoc_sam0_events_module_overview_config_evsys Event System
|
||||
* -# An event system channel must be allocated and configured with the
|
||||
* correct source peripheral selected as the channel's event generator.
|
||||
* -# The event system user must be configured and enabled, and attached to
|
||||
# event channel previously allocated.
|
||||
|
||||
* \subsubsection asfdoc_sam0_events_module_overview_config_dst Destination Peripheral
|
||||
* -# The destination peripheral (that will receive events) must be configured
|
||||
* and enabled.
|
||||
* -# The destination peripheral (that will receive events) must have an input
|
||||
* event enabled.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_special_considerations Special Considerations
|
||||
*
|
||||
* There are no special considerations for this module.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_extra_info Extra Information
|
||||
*
|
||||
* For extra information, see \ref asfdoc_sam0_events_extra. This includes:
|
||||
* - \ref asfdoc_sam0_events_extra_acronyms
|
||||
* - \ref asfdoc_sam0_events_extra_dependencies
|
||||
* - \ref asfdoc_sam0_events_extra_errata
|
||||
* - \ref asfdoc_sam0_events_extra_history
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_examples Examples
|
||||
*
|
||||
* For a list of examples related to this driver, see
|
||||
* \ref asfdoc_sam0_events_exqsg.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_api_overview API Overview
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include <compiler.h>
|
||||
#include "events_common.h"
|
||||
|
||||
/**
|
||||
* \brief Edge detect enum.
|
||||
*
|
||||
* Event channel edge detect setting.
|
||||
*
|
||||
*/
|
||||
enum events_edge_detect {
|
||||
/** No event output */
|
||||
EVENTS_EDGE_DETECT_NONE,
|
||||
/** Event on rising edge */
|
||||
EVENTS_EDGE_DETECT_RISING,
|
||||
/** Event on falling edge */
|
||||
EVENTS_EDGE_DETECT_FALLING,
|
||||
/** Event on both edges */
|
||||
EVENTS_EDGE_DETECT_BOTH,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Path selection enum.
|
||||
*
|
||||
* Event channel path selection.
|
||||
*
|
||||
*/
|
||||
enum events_path_selection {
|
||||
/** Select the synchronous path for this event channel */
|
||||
EVENTS_PATH_SYNCHRONOUS,
|
||||
/** Select the resynchronizer path for this event channel */
|
||||
EVENTS_PATH_RESYNCHRONIZED,
|
||||
/** Select the asynchronous path for this event channel */
|
||||
EVENTS_PATH_ASYNCHRONOUS,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Events configuration struct.
|
||||
*
|
||||
* This event configuration struct is used to configure each of the channels.
|
||||
*
|
||||
*/
|
||||
struct events_config {
|
||||
/** Select edge detection mode */
|
||||
enum events_edge_detect edge_detect;
|
||||
/** Select events channel path */
|
||||
enum events_path_selection path;
|
||||
/** Set event generator for the channel */
|
||||
uint8_t generator;
|
||||
/** Clock source for the event channel */
|
||||
uint8_t clock_source;
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
|
||||
/** Run in standby mode for the channel */
|
||||
bool run_in_standby;
|
||||
/** Run On Demand */
|
||||
bool on_demand;
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief No event generator definition.
|
||||
*
|
||||
* Use this to disable any peripheral event input to a channel. This can be useful
|
||||
* if you only want to use a channel for software generated events.
|
||||
*
|
||||
*/
|
||||
|
||||
///@cond INTERNAL
|
||||
/**
|
||||
* \internal
|
||||
* Status bit offsets in the status register/interrupt register.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
|
||||
# define _EVENTS_START_OFFSET_BUSY_BITS 16
|
||||
# define _EVENTS_START_OFFSET_USER_READY_BIT 0
|
||||
# define _EVENTS_START_OFFSET_DETECTION_BIT 16
|
||||
# define _EVENTS_START_OFFSET_OVERRUN_BIT 0
|
||||
#else /* SAM D/R */
|
||||
# define _EVENTS_START_OFFSET_BUSY_BITS 8
|
||||
# define _EVENTS_START_OFFSET_USER_READY_BIT 0
|
||||
# define _EVENTS_START_OFFSET_DETECTION_BIT 8
|
||||
# define _EVENTS_START_OFFSET_OVERRUN_BIT 0
|
||||
#endif
|
||||
/** @} */
|
||||
///@endcond
|
||||
|
||||
/**
|
||||
* Definition for no generator selection.
|
||||
*/
|
||||
#define EVSYS_ID_GEN_NONE 0
|
||||
|
||||
/**
|
||||
* \brief Event channel resource.
|
||||
*
|
||||
* Event resource structure.
|
||||
*
|
||||
* \note The fields in this structure should not be altered by the user application;
|
||||
* they are reserved for driver internals only.
|
||||
*/
|
||||
struct events_resource {
|
||||
#if !defined(__DOXYGEN__)
|
||||
/** Channel allocated for the event resource */
|
||||
uint8_t channel;
|
||||
/** Channel setting in CHANNEL register */
|
||||
uint32_t channel_reg;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if EVENTS_INTERRUPT_HOOKS_MODE == true
|
||||
typedef void (*events_interrupt_hook)(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Event hook.
|
||||
*
|
||||
* Event hook structure.
|
||||
*
|
||||
*/
|
||||
struct events_hook {
|
||||
/** Event resource */
|
||||
struct events_resource *resource;
|
||||
/** Event hook function */
|
||||
events_interrupt_hook hook_func;
|
||||
/** Next event hook */
|
||||
struct events_hook *next;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \brief Initializes an event configurations struct to defaults.
|
||||
*
|
||||
* Initailizes an event configuration struct to predefined safe default settings.
|
||||
*
|
||||
* \param[in] config Pointer to an instance of \ref struct events_config
|
||||
*
|
||||
*/
|
||||
void events_get_config_defaults(struct events_config *config);
|
||||
|
||||
/**
|
||||
* \brief Allocate an event channel and set configuration.
|
||||
*
|
||||
* Allocates an event channel from the event channel pool and sets
|
||||
* the channel configuration.
|
||||
*
|
||||
* \param[out] resource Pointer to a \ref events_resource struct instance
|
||||
* \param[in] config Pointer to a \ref events_config struct
|
||||
*
|
||||
* \return Status of the configuration procedure.
|
||||
* \retval STATUS_OK Allocation and configuration went successful
|
||||
* \retval STATUS_ERR_NOT_FOUND No free event channel found
|
||||
*
|
||||
*/
|
||||
enum status_code events_allocate(struct events_resource *resource, struct events_config *config);
|
||||
|
||||
/**
|
||||
* \brief Attach user to the event channel.
|
||||
*
|
||||
* Attach a user peripheral to the event channel to receive events.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] user_id A number identifying the user peripheral found in the device header file
|
||||
*
|
||||
* \return Status of the user attach procedure.
|
||||
* \retval STATUS_OK No errors detected when attaching the event user
|
||||
*/
|
||||
enum status_code events_attach_user(struct events_resource *resource, uint8_t user_id);
|
||||
|
||||
/**
|
||||
* \brief Detach a user peripheral from the event channel.
|
||||
*
|
||||
* Deattach a user peripheral from the event channels so it does not receive any more events.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref event_resource struct instance
|
||||
* \param[in] user_id A number identifying the user peripheral found in the device header file
|
||||
*
|
||||
* \return Status of the user detach procedure.
|
||||
* \retval STATUS_OK No errors detected when detaching the event user
|
||||
*/
|
||||
enum status_code events_detach_user(struct events_resource *resource, uint8_t user_id);
|
||||
|
||||
/**
|
||||
* \brief Check if a channel is busy.
|
||||
*
|
||||
* Check if a channel is busy, a channel stays busy until all users connected to the channel
|
||||
* has handled an event.
|
||||
*
|
||||
* \param[in] resource Pointer to a \ref events_resource struct instance
|
||||
*
|
||||
* \return Status of the channels busy state.
|
||||
* \retval true One or more users connected to the channel has not handled the last event
|
||||
* \retval false All users are ready to handle new events
|
||||
*/
|
||||
bool events_is_busy(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Trigger software event.
|
||||
*
|
||||
* Trigger an event by software.
|
||||
*
|
||||
* \note Software event works on either a synchronous path or resynchronized path, and
|
||||
* edge detection must be configured to rising-edge detection.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct
|
||||
*
|
||||
* \return Status of the event software procedure.
|
||||
* \retval STATUS_OK No error was detected when the software tigger signal was issued
|
||||
* \retval STATUS_ERR_UNSUPPORTED_DEV If the channel path is asynchronous and/or the
|
||||
* edge detection is not set to RISING
|
||||
*/
|
||||
enum status_code events_trigger(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Check if all users connected to the channel are ready.
|
||||
*
|
||||
* Check if all users connected to the channel are ready to handle incoming events.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct
|
||||
*
|
||||
* \return The ready status of users connected to an event channel.
|
||||
* \retval true All the users connected to the event channel are ready to handle incoming events
|
||||
* \retval false One or more users connected to the event channel are not ready to handle incoming events
|
||||
*/
|
||||
bool events_is_users_ready(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Check if an event is detected on the event channel.
|
||||
*
|
||||
* Check if an event has been detected on the channel.
|
||||
*
|
||||
* \note This function will clear the event detected interrupt flag.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct
|
||||
*
|
||||
* \return Status of the event detection interrupt flag.
|
||||
* \retval true Event has been detected
|
||||
* \retval false Event has not been detected
|
||||
*/
|
||||
bool events_is_detected(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Check if there has been an overrun situation on this channel.
|
||||
*
|
||||
* \note This function will clear the event overrun detected interrupt flag.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct
|
||||
*
|
||||
* \return Status of the event overrun interrupt flag.
|
||||
* \retval true Event overrun has been detected
|
||||
* \retval false Event overrun has not been detected
|
||||
*/
|
||||
bool events_is_overrun(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Release allocated channel back the the resource pool.
|
||||
*
|
||||
* Release an allocated channel back to the resource pool to make it available for other purposes.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct
|
||||
*
|
||||
* \return Status of the channel release procedure.
|
||||
* \retval STATUS_OK No error was detected when the channel was released
|
||||
* \retval STATUS_BUSY One or more event users have not processed the last event
|
||||
* \retval STATUS_ERR_NOT_INITIALIZED Channel not allocated, and can therefore not be released
|
||||
*/
|
||||
enum status_code events_release(struct events_resource *resource);
|
||||
|
||||
/**
|
||||
* \brief Get the number of free channels.
|
||||
*
|
||||
* Get the number of allocatable channels in the events system resource pool.
|
||||
*
|
||||
* \return The number of free channels in the event system.
|
||||
*
|
||||
*/
|
||||
uint8_t events_get_free_channels(void);
|
||||
|
||||
|
||||
///@cond INTERNAL
|
||||
/**
|
||||
* \internal
|
||||
* Function to find bit position in the CHSTATUS and INTFLAG register,
|
||||
* and return bit mask of this position.
|
||||
*
|
||||
* @{
|
||||
*/
|
||||
uint32_t _events_find_bit_position(uint8_t channel, uint8_t start_offset);
|
||||
/** @} */
|
||||
///@endcond
|
||||
|
||||
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* \page asfdoc_sam0_events_extra Extra Information for EVENTS Driver
|
||||
*
|
||||
* \section asfdoc_sam0_events_extra_acronyms Acronyms
|
||||
* Below is a table listing the acronyms used in this module, along with their
|
||||
* intended meanings.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Acronym</th>
|
||||
* <th>Description</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>CPU</td>
|
||||
* <td>Central Processing Unit</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>MUX</td>
|
||||
* <td>Multiplexer</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_extra_dependencies Dependencies
|
||||
* This driver has the following dependencies:
|
||||
*
|
||||
* - \ref asfdoc_sam0_system_clock_group "System Clock Driver"
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_extra_errata Errata
|
||||
* There are no errata related to this driver.
|
||||
*
|
||||
*
|
||||
* \section asfdoc_sam0_events_extra_history Module History
|
||||
* An overview of the module history is presented in the table below, with
|
||||
* details on the enhancements and fixes made to the module since its first
|
||||
* release. The current version of this corresponds to the newest version in
|
||||
* the table.
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Changelog</th>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Fix a bug in internal function _events_find_bit_position()</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Rewrite of events driver</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>Initial Release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
/**
|
||||
* \page asfdoc_sam0_events_exqsg Examples for EVENTS Driver
|
||||
*
|
||||
* This is a list of the available Quick Start guides (QSGs) and example
|
||||
* applications for \ref asfdoc_sam0_events_group. QSGs are simple examples with
|
||||
* step-by-step instructions to configure and use this driver in a selection of
|
||||
* use cases. Note that a QSG can be compiled as a standalone application or be
|
||||
* added to the user application.
|
||||
*
|
||||
* - \subpage asfdoc_sam0_events_basic_use_case
|
||||
* \if EVENTS_INTERRUPT_HOOK_MODE
|
||||
* - \subpage asfdoc_sam0_events_interrupt_hook_use_case
|
||||
* \endif
|
||||
*
|
||||
* \page asfdoc_sam0_events_document_revision_history Document Revision History
|
||||
*
|
||||
* <table>
|
||||
* <tr>
|
||||
* <th>Doc. Rev.</td>
|
||||
* <th>Date</td>
|
||||
* <th>Comments</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108G</td>
|
||||
* <td>12/2015</td>
|
||||
* <td>Added support for SAM D09 and SAM L22</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108F</td>
|
||||
* <td>08/2015</td>
|
||||
* <td>Added support for SAM L21, SAM DA1, SAMR30 and SAM C20/C21</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108E</td>
|
||||
* <td>12/2014</td>
|
||||
* <td>Added support for interrupt hook mode.
|
||||
* Added support for SAM R21 and SAM D10/D11.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108D</td>
|
||||
* <td>01/2014</td>
|
||||
* <td>Update to support SAM D21 and corrected documentation typos</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108C</td>
|
||||
* <td>11/2013</td>
|
||||
* <td>Fixed incorrect documentation for the event signal paths. Added
|
||||
* configuration steps overview to the documentation.</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108B</td>
|
||||
* <td>06/2013</td>
|
||||
* <td>Corrected documentation typos</td>
|
||||
* </tr>
|
||||
* <tr>
|
||||
* <td>42108A</td>
|
||||
* <td>06/2013</td>
|
||||
* <td>Initial release</td>
|
||||
* </tr>
|
||||
* </table>
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* EVENTS_H_INCLUDED */
|
71
atmel-samd/asf/sam0/drivers/events/events_common.h
Normal file
71
atmel-samd/asf/sam0/drivers/events/events_common.h
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Event System Controller Driver
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef _EVENTS_COMMON_H_INCLUDED_
|
||||
#define _EVENTS_COMMON_H_INCLUDED_
|
||||
|
||||
/**
|
||||
* \internal Internal module structure to manage necessary globals
|
||||
*
|
||||
*
|
||||
*/
|
||||
struct _events_module {
|
||||
/* Allocated channels bitmask where 1 means allocated */
|
||||
volatile uint32_t allocated_channels;
|
||||
/* Free channels */
|
||||
uint8_t free_channels;
|
||||
|
||||
#if EVENTS_INTERRUPT_HOOKS_MODE == true
|
||||
/* Buffer to store a copy of the current interrupt flags */
|
||||
volatile uint32_t interrupt_flag_buffer;
|
||||
/* Buffer to store acknowledged interrupt sources */
|
||||
volatile uint32_t interrupt_flag_ack_buffer;
|
||||
|
||||
/* Interrup hook linked list start pointer */
|
||||
struct events_hook *hook_list;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
235
atmel-samd/asf/sam0/drivers/events/events_hooks.c
Normal file
235
atmel-samd/asf/sam0/drivers/events/events_hooks.c
Normal file
@ -0,0 +1,235 @@
|
||||
/*
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Event System Controller Driver
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#include "events.h"
|
||||
#include "events_hooks.h"
|
||||
#include "system_interrupt.h"
|
||||
|
||||
#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)
|
||||
# define _EVENTS_INTFLAGS_DETECT 0x0fff0000
|
||||
# define _EVENTS_INTFLAGS_OVERRUN 0x00000fff
|
||||
#else
|
||||
# define _EVENTS_INTFLAGS_DETECT 0x0f00ff00
|
||||
# define _EVENTS_INTFLAGS_OVERRUN 0x000f00ff
|
||||
#endif
|
||||
#define _EVENTS_INTFLAGS_MASK (_EVENTS_INTFLAGS_DETECT | _EVENTS_INTFLAGS_OVERRUN)
|
||||
|
||||
extern struct _events_module _events_inst;
|
||||
|
||||
enum status_code events_create_hook(struct events_hook *hook, events_interrupt_hook func)
|
||||
{
|
||||
/* Initialize the hook struct members */
|
||||
hook->next = NULL;
|
||||
hook->resource = NULL;
|
||||
hook->hook_func = func;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
enum status_code events_add_hook(struct events_resource *resource, struct events_hook *hook)
|
||||
{
|
||||
struct events_hook *tmp_hook = NULL;
|
||||
|
||||
/* Associate the hook with the resource */
|
||||
hook->resource = resource;
|
||||
|
||||
/* Check if this is the first hook in the list */
|
||||
if (_events_inst.hook_list == NULL) {
|
||||
_events_inst.hook_list = hook;
|
||||
} else {
|
||||
tmp_hook = _events_inst.hook_list;
|
||||
|
||||
/* Find the first free place in the list */
|
||||
while (tmp_hook->next != NULL) {
|
||||
tmp_hook = tmp_hook->next;
|
||||
}
|
||||
|
||||
/* Put the hook into the next free place in the list */
|
||||
tmp_hook->next = hook;
|
||||
}
|
||||
|
||||
/* Check if interrupts from the EVSYS module is enabled in the interrupt controller */
|
||||
if (!system_interrupt_is_enabled(SYSTEM_INTERRUPT_MODULE_EVSYS)) {
|
||||
system_interrupt_enable(SYSTEM_INTERRUPT_MODULE_EVSYS);
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
enum status_code events_del_hook(struct events_resource *resource, struct events_hook *hook)
|
||||
{
|
||||
struct events_hook *tmp_hook = _events_inst.hook_list;
|
||||
struct events_hook *last_hook = NULL;
|
||||
|
||||
if (tmp_hook != NULL) {
|
||||
/* Check if the first hook in the list is the one we are looking for */
|
||||
if (tmp_hook != hook) {
|
||||
/* Don't double check the first hook */
|
||||
tmp_hook = tmp_hook->next;
|
||||
|
||||
/* Check if the current hook is the one we are looking for */
|
||||
while (tmp_hook != hook) {
|
||||
|
||||
/* If the current hook pointer is NULL the hook is not found in the list */
|
||||
if(tmp_hook == NULL) {
|
||||
return STATUS_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
last_hook = tmp_hook;
|
||||
tmp_hook = tmp_hook->next;
|
||||
|
||||
}
|
||||
/* Remove the current hook from the list */
|
||||
last_hook->next = tmp_hook->next;
|
||||
} else {
|
||||
_events_inst.hook_list = tmp_hook->next;
|
||||
}
|
||||
} else {
|
||||
/* No hooks where found in the list */
|
||||
return STATUS_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
enum status_code events_enable_interrupt_source(struct events_resource *resource, enum events_interrupt_source source)
|
||||
{
|
||||
Assert((source == EVENTS_INTERRUPT_DETECT) || (source == EVENTS_INTERRUPT_OVERRUN));
|
||||
|
||||
if (source == EVENTS_INTERRUPT_DETECT) {
|
||||
EVSYS->INTENSET.reg = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_DETECTION_BIT);
|
||||
} else if (source == EVENTS_INTERRUPT_OVERRUN) {
|
||||
EVSYS->INTENSET.reg = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_OVERRUN_BIT);
|
||||
} else {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
enum status_code events_disable_interrupt_source(struct events_resource *resource, enum events_interrupt_source source)
|
||||
{
|
||||
Assert((source == EVENTS_INTERRUPT_DETECT) || (source == EVENTS_INTERRUPT_OVERRUN));
|
||||
|
||||
if (source == EVENTS_INTERRUPT_DETECT) {
|
||||
EVSYS->INTENCLR.reg = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_DETECTION_BIT);
|
||||
} else if (source == EVENTS_INTERRUPT_OVERRUN) {
|
||||
EVSYS->INTENCLR.reg = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_OVERRUN_BIT);
|
||||
} else {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
bool events_is_interrupt_set(struct events_resource *resource, enum events_interrupt_source source)
|
||||
{
|
||||
Assert((source == EVENTS_INTERRUPT_DETECT) || (source == EVENTS_INTERRUPT_OVERRUN));
|
||||
|
||||
uint32_t bitpos;
|
||||
|
||||
if (source == EVENTS_INTERRUPT_DETECT) {
|
||||
bitpos = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_DETECTION_BIT);
|
||||
} else if (source == EVENTS_INTERRUPT_OVERRUN) {
|
||||
bitpos = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_OVERRUN_BIT);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool)(_events_inst.interrupt_flag_buffer & bitpos);
|
||||
}
|
||||
|
||||
enum status_code events_ack_interrupt(struct events_resource *resource, enum events_interrupt_source source)
|
||||
{
|
||||
Assert((source == EVENTS_INTERRUPT_DETECT) || (source == EVENTS_INTERRUPT_OVERRUN));
|
||||
|
||||
uint32_t bitpos;
|
||||
|
||||
if (source == EVENTS_INTERRUPT_DETECT) {
|
||||
bitpos = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_DETECTION_BIT);
|
||||
} else if (source == EVENTS_INTERRUPT_OVERRUN) {
|
||||
bitpos = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_OVERRUN_BIT);
|
||||
} else {
|
||||
return STATUS_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
_events_inst.interrupt_flag_ack_buffer |= bitpos;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
void EVSYS_Handler(void)
|
||||
{
|
||||
struct events_hook *current_hook = _events_inst.hook_list;
|
||||
uint32_t flag;
|
||||
|
||||
/* Synch the interrupt flag buffer with the hardware register */
|
||||
flag = EVSYS->INTFLAG.reg;
|
||||
_events_inst.interrupt_flag_buffer |= flag;
|
||||
/* Clear all hardware interrupt flags */
|
||||
EVSYS->INTFLAG.reg = _EVENTS_INTFLAGS_MASK;
|
||||
|
||||
/* Traverse the linked list */
|
||||
while (current_hook != NULL) {
|
||||
current_hook->hook_func(current_hook->resource);
|
||||
current_hook = current_hook->next;
|
||||
}
|
||||
|
||||
/* Clear acknowledged interrupt sources from the interrupt flag buffer */
|
||||
flag = _events_inst.interrupt_flag_ack_buffer;
|
||||
_events_inst.interrupt_flag_buffer &= ~flag;
|
||||
}
|
||||
|
||||
|
||||
|
182
atmel-samd/asf/sam0/drivers/events/events_hooks.h
Normal file
182
atmel-samd/asf/sam0/drivers/events/events_hooks.h
Normal file
@ -0,0 +1,182 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Event System Driver
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#include "events.h"
|
||||
|
||||
#ifndef _EVENTS_HOOKS_H_INCLUDED_
|
||||
#define _EVENTS_HOOKS_H_INCLUDED_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* \addtogroup asfdoc_sam0_events_group
|
||||
* @{
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* \brief Interrupt source enumerator.
|
||||
*
|
||||
* Interrupt source selector definitions.
|
||||
*
|
||||
*/
|
||||
enum events_interrupt_source {
|
||||
/** Overrun in event channel detected interrupt */
|
||||
EVENTS_INTERRUPT_OVERRUN,
|
||||
/** Event signal propagation in event channel detected interrupt */
|
||||
EVENTS_INTERRUPT_DETECT,
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Initializes an interrupt hook for insertion in the event interrupt hook queue.
|
||||
*
|
||||
* Initializes a hook structure so it is ready for insertion in the interrupt hook queue.
|
||||
*
|
||||
* \param[out] hook Pointer to an \ref events_hook struct instance
|
||||
* \param[in] hook_func Pointer to a function containing the interrupt hook code
|
||||
*
|
||||
* \return Status of the hook creation procedure.
|
||||
* \retval STATUS_OK Creation and initialization of interrupt hook went successful
|
||||
*
|
||||
*/
|
||||
enum status_code events_create_hook(struct events_hook *hook, events_interrupt_hook hook_func);
|
||||
|
||||
/**
|
||||
* \brief Insert hook into the event drivers interrupt hook queue.
|
||||
*
|
||||
* Inserts a hook into the event drivers interrupt hook queue.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] hook Pointer to an \ref events_hook struct instance
|
||||
*
|
||||
* \return Status of the insertion procedure.
|
||||
* \retval STATUS_OK Insertion of hook went successful
|
||||
*
|
||||
*/
|
||||
enum status_code events_add_hook(struct events_resource *resource, struct events_hook *hook);
|
||||
|
||||
/**
|
||||
* \brief Remove hook from the event drivers interrupt hook queue.
|
||||
*
|
||||
* Removes a hook from the event drivers interrupt hook queue.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] hook Pointer to an \ref events_hook struct instance
|
||||
*
|
||||
* \return Status of the removal procedure.
|
||||
* \retval STATUS_OK Removal of hook went successful
|
||||
* \retval STATUS_ERR_NO_MEMORY There are no hooks instances in the event driver interrupt hook list
|
||||
* \retval STATUS_ERR_NOT_FOUND Interrupt hook not found in the event drivers interrupt hook list
|
||||
*
|
||||
*/
|
||||
enum status_code events_del_hook(struct events_resource *resource, struct events_hook *hook);
|
||||
|
||||
/**
|
||||
* \brief Enable interrupt source.
|
||||
*
|
||||
* Enable an interrupt source so can trigger execution of an interrupt hook.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] source One of the members in the \ref events_interrupt_source enumerator
|
||||
*
|
||||
* \return Status of the interrupt source enable procedure.
|
||||
* \retval STATUS_OK Enabling of the interrupt source was successful
|
||||
* \retval STATUS_ERR_INVALID_ARG Interrupt source does not exist
|
||||
*
|
||||
*/
|
||||
enum status_code events_enable_interrupt_source(struct events_resource *resource, enum events_interrupt_source source);
|
||||
|
||||
/**
|
||||
* \brief Disable interrupt source.
|
||||
*
|
||||
* Disable an interrupt source so can trigger execution of an interrupt hook.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] source One of the members in the \ref events_interrupt_source enumerator
|
||||
*
|
||||
* \return Status of the interrupt source enable procedure.
|
||||
* \retval STATUS_OK Enabling of the interrupt source went successful
|
||||
* \retval STATUS_ERR_INVALID_ARG Interrupt source does not exist
|
||||
*
|
||||
*/
|
||||
enum status_code events_disable_interrupt_source(struct events_resource *resource, enum events_interrupt_source source);
|
||||
|
||||
/**
|
||||
* \brief Check if interrupt source is set.
|
||||
*
|
||||
* Check if an interrupt source is set and should be processed.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] source One of the members in the \ref events_interrupt_source enumerator
|
||||
*
|
||||
* \return Status of the interrupt source.
|
||||
* \retval true Interrupt source is set
|
||||
* \retval false Interrupt source is not set
|
||||
*
|
||||
*/
|
||||
bool events_is_interrupt_set(struct events_resource *resource, enum events_interrupt_source source);
|
||||
|
||||
/**
|
||||
* \brief Acknowledge an interrupt source.
|
||||
*
|
||||
* Acknowledge an interrupt source so the interrupt state is cleared in hardware.
|
||||
*
|
||||
* \param[in] resource Pointer to an \ref events_resource struct instance
|
||||
* \param[in] source One of the members in the \ref events_interrupt_source enumerator
|
||||
*
|
||||
* \return Status of the interrupt source.
|
||||
* \retval STATUS_OK Interrupt source was acknowledged successfully
|
||||
*
|
||||
*/
|
||||
enum status_code events_ack_interrupt(struct events_resource *resource, enum events_interrupt_source source);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
328
atmel-samd/asf/sam0/drivers/events/events_sam_d_r/events.c
Normal file
328
atmel-samd/asf/sam0/drivers/events/events_sam_d_r/events.c
Normal file
@ -0,0 +1,328 @@
|
||||
/*
|
||||
* \file
|
||||
*
|
||||
* \brief SAM Event System Controller Driver
|
||||
*
|
||||
* Copyright (C) 2013-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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
|
||||
#include <events.h>
|
||||
#include <system.h>
|
||||
#include <system_interrupt.h>
|
||||
#include <status_codes.h>
|
||||
|
||||
#define EVENTS_INVALID_CHANNEL 0xff
|
||||
|
||||
struct _events_module _events_inst = {
|
||||
.allocated_channels = 0,
|
||||
.free_channels = EVSYS_CHANNELS,
|
||||
|
||||
#if EVENTS_INTERRUPT_HOOKS_MODE == true
|
||||
.interrupt_flag_buffer = 0,
|
||||
.interrupt_flag_ack_buffer = 0,
|
||||
|
||||
.hook_list = NULL,
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* \internal
|
||||
*
|
||||
*/
|
||||
uint32_t _events_find_bit_position(uint8_t channel, uint8_t start_offset)
|
||||
{
|
||||
uint32_t pos;
|
||||
|
||||
if (channel < _EVENTS_START_OFFSET_BUSY_BITS) {
|
||||
pos = 0x01UL << (start_offset + channel);
|
||||
} else {
|
||||
pos = 0x01UL << (start_offset + channel + _EVENTS_START_OFFSET_BUSY_BITS);
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
static uint8_t _events_find_first_free_channel_and_allocate(void)
|
||||
{
|
||||
uint8_t count;
|
||||
uint32_t tmp;
|
||||
bool allocated = false;
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
tmp = _events_inst.allocated_channels;
|
||||
|
||||
for(count = 0; count < EVSYS_CHANNELS; ++count) {
|
||||
|
||||
if(!(tmp & 0x00000001)) {
|
||||
/* If free channel found, set as allocated and return number */
|
||||
|
||||
_events_inst.allocated_channels |= 1 << count;
|
||||
_events_inst.free_channels--;
|
||||
allocated = true;
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
tmp = tmp >> 1;
|
||||
}
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
if(!allocated) {
|
||||
return EVENTS_INVALID_CHANNEL;
|
||||
} else {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
static void _events_release_channel(uint8_t channel)
|
||||
{
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
_events_inst.allocated_channels &= ~(1 << channel);
|
||||
_events_inst.free_channels++;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
}
|
||||
|
||||
|
||||
/* This function is called by the system_init function, but should not be a public API call */
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic push
|
||||
# pragma GCC diagnostic ignored "-Wmissing-prototypes"
|
||||
#endif
|
||||
void _system_events_init(void)
|
||||
{
|
||||
/* Enable EVSYS register interface */
|
||||
system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, PM_APBCMASK_EVSYS);
|
||||
|
||||
/* Make sure the EVSYS module is properly reset */
|
||||
EVSYS->CTRL.reg = EVSYS_CTRL_SWRST;
|
||||
|
||||
while (EVSYS->CTRL.reg & EVSYS_CTRL_SWRST) {
|
||||
}
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
# pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
void events_get_config_defaults(struct events_config *config)
|
||||
{
|
||||
/* Check that config is something other than NULL */
|
||||
Assert(config);
|
||||
|
||||
config->edge_detect = EVENTS_EDGE_DETECT_RISING;
|
||||
config->path = EVENTS_PATH_SYNCHRONOUS;
|
||||
config->generator = EVSYS_ID_GEN_NONE;
|
||||
config->clock_source = GCLK_GENERATOR_0;
|
||||
}
|
||||
|
||||
enum status_code events_allocate(
|
||||
struct events_resource *resource,
|
||||
struct events_config *config)
|
||||
{
|
||||
uint8_t new_channel;
|
||||
|
||||
Assert(resource);
|
||||
|
||||
new_channel = _events_find_first_free_channel_and_allocate();
|
||||
|
||||
if(new_channel == EVENTS_INVALID_CHANNEL) {
|
||||
return STATUS_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
resource->channel = new_channel;
|
||||
|
||||
if (config->path != EVENTS_PATH_ASYNCHRONOUS) {
|
||||
/* Set up a GLCK channel to use with the specific channel */
|
||||
struct system_gclk_chan_config gclk_chan_conf;
|
||||
|
||||
system_gclk_chan_get_config_defaults(&gclk_chan_conf);
|
||||
gclk_chan_conf.source_generator =
|
||||
(enum gclk_generator)config->clock_source;
|
||||
system_gclk_chan_set_config(EVSYS_GCLK_ID_0 + new_channel, &gclk_chan_conf);
|
||||
system_gclk_chan_enable(EVSYS_GCLK_ID_0 + new_channel);
|
||||
}
|
||||
|
||||
/* Save channel setting and configure it after user multiplexer */
|
||||
resource->channel_reg = EVSYS_CHANNEL_CHANNEL(new_channel) |
|
||||
EVSYS_CHANNEL_EVGEN(config->generator) |
|
||||
EVSYS_CHANNEL_PATH(config->path) |
|
||||
EVSYS_CHANNEL_EDGSEL(config->edge_detect);
|
||||
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
enum status_code events_release(struct events_resource *resource)
|
||||
{
|
||||
enum status_code err = STATUS_OK;
|
||||
|
||||
Assert(resource);
|
||||
|
||||
/* Check if channel is busy */
|
||||
if(events_is_busy(resource)) {
|
||||
return STATUS_BUSY;
|
||||
}
|
||||
|
||||
if (!(_events_inst.allocated_channels & (1<<resource->channel))) {
|
||||
err = STATUS_ERR_NOT_INITIALIZED;
|
||||
} else {
|
||||
_events_release_channel(resource->channel);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
enum status_code events_trigger(struct events_resource *resource)
|
||||
{
|
||||
|
||||
Assert(resource);
|
||||
|
||||
system_interrupt_enter_critical_section();
|
||||
|
||||
/* Because of indirect access the channel must be set first */
|
||||
((uint8_t*)&EVSYS->CHANNEL)[0] = EVSYS_CHANNEL_CHANNEL(resource->channel);
|
||||
|
||||
/* Assert if event path is asynchronous */
|
||||
if (EVSYS->CHANNEL.reg & EVSYS_CHANNEL_PATH(EVENTS_PATH_ASYNCHRONOUS)) {
|
||||
return STATUS_ERR_UNSUPPORTED_DEV;
|
||||
}
|
||||
|
||||
/* Assert if event edge detection is not set to RISING */
|
||||
if (!(EVSYS->CHANNEL.reg & EVSYS_CHANNEL_EDGSEL(EVENTS_EDGE_DETECT_RISING))) {
|
||||
return STATUS_ERR_UNSUPPORTED_DEV;
|
||||
}
|
||||
|
||||
|
||||
/* The GCLKREQ bit has to be set while triggering the software event */
|
||||
EVSYS->CTRL.reg = EVSYS_CTRL_GCLKREQ;
|
||||
|
||||
((uint16_t*)&EVSYS->CHANNEL)[0] = EVSYS_CHANNEL_CHANNEL(resource->channel) |
|
||||
EVSYS_CHANNEL_SWEVT;
|
||||
|
||||
EVSYS->CTRL.reg &= ~EVSYS_CTRL_GCLKREQ;
|
||||
|
||||
system_interrupt_leave_critical_section();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
bool events_is_busy(struct events_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
return EVSYS->CHSTATUS.reg & (_events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_BUSY_BITS));
|
||||
}
|
||||
|
||||
bool events_is_users_ready(struct events_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
return EVSYS->CHSTATUS.reg & (_events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_USER_READY_BIT));
|
||||
}
|
||||
|
||||
bool events_is_detected(struct events_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
uint32_t flag = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_DETECTION_BIT);
|
||||
|
||||
/* Clear flag when read */
|
||||
if (EVSYS->INTFLAG.reg & flag) {
|
||||
EVSYS->INTFLAG.reg = flag;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool events_is_overrun(struct events_resource *resource)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
uint32_t flag = _events_find_bit_position(resource->channel,
|
||||
_EVENTS_START_OFFSET_OVERRUN_BIT);
|
||||
|
||||
/* Clear flag when read */
|
||||
if (EVSYS->INTFLAG.reg & flag) {
|
||||
EVSYS->INTFLAG.reg = flag;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
enum status_code events_attach_user(struct events_resource *resource, uint8_t user_id)
|
||||
{
|
||||
Assert(resource);
|
||||
|
||||
/* First configure user multiplexer: channel number is n + 1 */
|
||||
EVSYS->USER.reg = EVSYS_USER_CHANNEL(resource->channel + 1) |
|
||||
EVSYS_USER_USER(user_id);
|
||||
|
||||
/* Then configure the channel */
|
||||
EVSYS->CHANNEL.reg = resource->channel_reg;
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
enum status_code events_detach_user(struct events_resource *resource, uint8_t user_id)
|
||||
{
|
||||
|
||||
Assert(resource);
|
||||
|
||||
/* Write 0 to the channel bit field to select no input */
|
||||
EVSYS->USER.reg = EVSYS_USER_USER(user_id);
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
uint8_t events_get_free_channels()
|
||||
{
|
||||
return _events_inst.free_channels;
|
||||
}
|
51
atmel-samd/asf_conf/conf_dma.h
Normal file
51
atmel-samd/asf_conf/conf_dma.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM D21 Direct Memory Access Driver Configuration Header
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef CONF_DMA_H_INCLUDED
|
||||
#define CONF_DMA_H_INCLUDED
|
||||
|
||||
# define CONF_MAX_USED_CHANNEL_NUM 2
|
||||
|
||||
#endif
|
51
atmel-samd/boards/circuitplayground_express/conf_dma.h
Normal file
51
atmel-samd/boards/circuitplayground_express/conf_dma.h
Normal file
@ -0,0 +1,51 @@
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* \brief SAM D21 Direct Memory Access Driver Configuration Header
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
/*
|
||||
* Support and FAQ: visit <a href="http://www.atmel.com/design-support/">Atmel Support</a>
|
||||
*/
|
||||
#ifndef CONF_DMA_H_INCLUDED
|
||||
#define CONF_DMA_H_INCLUDED
|
||||
|
||||
# define CONF_MAX_USED_CHANNEL_NUM 1
|
||||
|
||||
#endif
|
350
atmel-samd/common-hal/audioio/AudioOut.c
Normal file
350
atmel-samd/common-hal/audioio/AudioOut.c
Normal file
@ -0,0 +1,350 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/gc.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "py/runtime.h"
|
||||
#include "common-hal/audioio/AudioOut.h"
|
||||
#include "shared-bindings/audioio/AudioOut.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
|
||||
#include "asf/sam0/drivers/dac/dac.h"
|
||||
#include "asf/sam0/drivers/dma/dma.h"
|
||||
#include "asf/sam0/drivers/events/events.h"
|
||||
#include "asf/sam0/drivers/tc/tc.h"
|
||||
#include "samd21_pins.h"
|
||||
#include "shared_dma.h"
|
||||
|
||||
#undef ENABLE
|
||||
|
||||
// Shared with PWMOut
|
||||
// TODO(tannewt): Factor these out so audioio can exist without PWMOut.
|
||||
extern uint32_t target_timer_frequencies[TC_INST_NUM + TCC_INST_NUM];
|
||||
extern uint8_t timer_refcount[TC_INST_NUM + TCC_INST_NUM];
|
||||
extern const uint16_t prescaler[8];
|
||||
|
||||
// This timer is shared amongst all AudioOut objects under the assumption that
|
||||
// the code is single threaded.
|
||||
static struct tc_module* tc_instance;
|
||||
static struct dac_module* dac_instance;
|
||||
static struct events_resource* tc_event;
|
||||
static struct events_resource* dac_event;
|
||||
|
||||
// The AudioOut object is being currently played. Only it can pause the timer
|
||||
// and change its frequency.
|
||||
static audioio_audioout_obj_t* active_audioout;
|
||||
|
||||
static uint8_t refcount = 0;
|
||||
|
||||
void audioout_reset(void) {
|
||||
// Only reset DMA. PWMOut will reset the timer.
|
||||
refcount = 0;
|
||||
tc_instance = NULL;
|
||||
if (dac_instance != NULL) {
|
||||
dac_reset(dac_instance);
|
||||
}
|
||||
dac_instance = NULL;
|
||||
|
||||
if (tc_event != NULL) {
|
||||
events_detach_user(tc_event, EVSYS_ID_USER_DAC_START);
|
||||
events_release(tc_event);
|
||||
}
|
||||
tc_event = NULL;
|
||||
|
||||
if (dac_event != NULL) {
|
||||
events_detach_user(dac_event, EVSYS_ID_USER_DMAC_CH_0);
|
||||
events_release(dac_event);
|
||||
}
|
||||
dac_event = NULL;
|
||||
|
||||
dma_abort_job(&audio_dma);
|
||||
}
|
||||
|
||||
static void shared_construct(audioio_audioout_obj_t* self, const mcu_pin_obj_t* pin, uint32_t frequency) {
|
||||
assert_pin_free(pin);
|
||||
|
||||
// Configure the DAC to output on input event and to output an empty event
|
||||
// that triggers the DMA to load the next sample.
|
||||
dac_instance = gc_alloc(sizeof(struct dac_module), false);
|
||||
if (dac_instance == NULL) {
|
||||
mp_raise_msg(&mp_type_MemoryError, "");
|
||||
}
|
||||
struct dac_config config_dac;
|
||||
dac_get_config_defaults(&config_dac);
|
||||
config_dac.left_adjust = true;
|
||||
config_dac.reference = DAC_REFERENCE_AVCC;
|
||||
config_dac.clock_source = GCLK_GENERATOR_0;
|
||||
enum status_code status = dac_init(dac_instance, DAC, &config_dac);
|
||||
if (status != STATUS_OK) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
struct dac_chan_config channel_config;
|
||||
dac_chan_get_config_defaults(&channel_config);
|
||||
dac_chan_set_config(dac_instance, DAC_CHANNEL_0, &channel_config);
|
||||
dac_chan_enable(dac_instance, DAC_CHANNEL_0);
|
||||
|
||||
struct dac_events events_dac = { .generate_event_on_buffer_empty = true,
|
||||
.on_event_start_conversion = true };
|
||||
dac_enable_events(dac_instance, &events_dac);
|
||||
|
||||
dac_enable(dac_instance);
|
||||
|
||||
// Figure out which timer we are using.
|
||||
Tc *t = NULL;
|
||||
Tc *tcs[TC_INST_NUM] = TC_INSTS;
|
||||
for (uint8_t i = TC_INST_NUM; i > 0; i--) {
|
||||
if (tcs[i - 1]->COUNT16.CTRLA.bit.ENABLE == 0) {
|
||||
t = tcs[i - 1];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (t == NULL) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_RuntimeError("All timers in use");
|
||||
return;
|
||||
}
|
||||
tc_instance = gc_alloc(sizeof(struct tc_module), false);
|
||||
if (tc_instance == NULL) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_msg(&mp_type_MemoryError, "");
|
||||
}
|
||||
|
||||
// Don't bother setting the period. We set it before you playback anything.
|
||||
struct tc_config config_tc;
|
||||
tc_get_config_defaults(&config_tc);
|
||||
|
||||
config_tc.counter_size = TC_COUNTER_SIZE_16BIT;
|
||||
config_tc.clock_prescaler = TC_CLOCK_PRESCALER_DIV1;
|
||||
config_tc.wave_generation = TC_WAVE_GENERATION_MATCH_FREQ;
|
||||
if (tc_init(tc_instance, t, &config_tc) != STATUS_OK) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_printf(&mp_plat_print, "tc \n");
|
||||
mp_raise_OSError(MP_EIO);
|
||||
return;
|
||||
};
|
||||
|
||||
struct tc_events events_tc;
|
||||
events_tc.generate_event_on_overflow = true;
|
||||
tc_enable_events(tc_instance, &events_tc);
|
||||
|
||||
tc_enable(tc_instance);
|
||||
tc_stop_counter(tc_instance);
|
||||
|
||||
// Connect the timer overflow event, which happens at the target frequency,
|
||||
// to the DAC conversion trigger.
|
||||
tc_event = gc_alloc(sizeof(struct events_resource), false);
|
||||
if (tc_event == NULL) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_msg(&mp_type_MemoryError, "");
|
||||
}
|
||||
struct events_config config;
|
||||
events_get_config_defaults(&config);
|
||||
|
||||
uint8_t generator = EVSYS_ID_GEN_TC3_OVF;
|
||||
if (t == TC4) {
|
||||
generator = EVSYS_ID_GEN_TC4_OVF;
|
||||
} else if (t == TC5) {
|
||||
generator = EVSYS_ID_GEN_TC5_OVF;
|
||||
#ifdef TC6
|
||||
} else if (t == TC6) {
|
||||
generator = EVSYS_ID_GEN_TC6_OVF;
|
||||
#endif
|
||||
#ifdef TC7
|
||||
} else if (t == TC7) {
|
||||
generator = EVSYS_ID_GEN_TC7_OVF;
|
||||
#endif
|
||||
}
|
||||
|
||||
config.generator = generator;
|
||||
config.path = EVENTS_PATH_ASYNCHRONOUS;
|
||||
if (events_allocate(tc_event, &config) != STATUS_OK ||
|
||||
events_attach_user(tc_event, EVSYS_ID_USER_DAC_START) != STATUS_OK) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
// Connect the DAC to DMA
|
||||
dac_event = gc_alloc(sizeof(struct events_resource), false);
|
||||
if (tc_event == NULL) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_msg(&mp_type_MemoryError, "");
|
||||
}
|
||||
events_get_config_defaults(&config);
|
||||
config.generator = EVSYS_ID_GEN_DAC_EMPTY;
|
||||
config.path = EVENTS_PATH_ASYNCHRONOUS;
|
||||
if (events_allocate(dac_event, &config) != STATUS_OK ||
|
||||
events_attach_user(dac_event, EVSYS_ID_USER_DMAC_CH_0) != STATUS_OK) {
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
mp_raise_OSError(MP_EIO);
|
||||
return;
|
||||
}
|
||||
|
||||
// Leave the DMA setup to the specific constructor.
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_construct_from_buffer(audioio_audioout_obj_t* self,
|
||||
const mcu_pin_obj_t* pin,
|
||||
uint16_t* buffer,
|
||||
uint32_t len) {
|
||||
self->pin = pin;
|
||||
if (pin != &pin_PA02) {
|
||||
mp_raise_ValueError("Invalid pin");
|
||||
}
|
||||
if (refcount == 0) {
|
||||
refcount++;
|
||||
shared_construct(self, pin, 8000);
|
||||
}
|
||||
|
||||
self->buffer = (uint8_t*) buffer;
|
||||
// Input len is a count. Internal len is in bytes.
|
||||
self->len = 2 * len;
|
||||
self->frequency = 8000;
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_construct_from_file(audioio_audioout_obj_t* self,
|
||||
const mcu_pin_obj_t* pin,
|
||||
pyb_file_obj_t* file) {
|
||||
mp_raise_NotImplementedError("File playback not supported yet.");
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self) {
|
||||
refcount--;
|
||||
if (refcount == 0) {
|
||||
if (tc_instance != NULL) {
|
||||
tc_reset(tc_instance);
|
||||
gc_free(tc_instance);
|
||||
tc_instance = NULL;
|
||||
}
|
||||
if (dac_instance != NULL) {
|
||||
dac_reset(dac_instance);
|
||||
gc_free(dac_instance);
|
||||
dac_instance = NULL;
|
||||
}
|
||||
if (tc_event != NULL) {
|
||||
events_detach_user(tc_event, EVSYS_ID_USER_DAC_START);
|
||||
events_release(tc_event);
|
||||
gc_free(tc_event);
|
||||
tc_event = NULL;
|
||||
}
|
||||
if (dac_event != NULL) {
|
||||
events_release(dac_event);
|
||||
gc_free(dac_event);
|
||||
dac_event = NULL;
|
||||
}
|
||||
reset_pin(self->pin->pin);
|
||||
}
|
||||
}
|
||||
|
||||
static void set_timer_frequency(uint32_t frequency) {
|
||||
uint32_t system_clock = system_cpu_clock_get_hz();
|
||||
uint32_t new_top;
|
||||
uint8_t new_divisor;
|
||||
for (new_divisor = 0; new_divisor < 8; new_divisor++) {
|
||||
new_top = (system_clock / prescaler[new_divisor] / frequency) - 1;
|
||||
if (new_top < (1u << 16)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint8_t old_divisor = tc_instance->hw->COUNT16.CTRLA.bit.PRESCALER;
|
||||
if (new_divisor != old_divisor) {
|
||||
tc_disable(tc_instance);
|
||||
tc_instance->hw->COUNT16.CTRLA.bit.PRESCALER = new_divisor;
|
||||
tc_enable(tc_instance);
|
||||
}
|
||||
while (tc_is_syncing(tc_instance)) {
|
||||
/* Wait for sync */
|
||||
}
|
||||
tc_instance->hw->COUNT16.CC[0].reg = new_top;
|
||||
while (tc_is_syncing(tc_instance)) {
|
||||
/* Wait for sync */
|
||||
}
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop) {
|
||||
common_hal_audioio_audioout_get_playing(self);
|
||||
// Shut down any active playback.
|
||||
if (active_audioout != NULL) {
|
||||
tc_stop_counter(tc_instance);
|
||||
dma_abort_job(&audio_dma);
|
||||
}
|
||||
struct dma_descriptor_config descriptor_config;
|
||||
dma_descriptor_get_config_defaults(&descriptor_config);
|
||||
descriptor_config.beat_size = DMA_BEAT_SIZE_HWORD;
|
||||
descriptor_config.dst_increment_enable = false;
|
||||
// Block transfer count is the number of beats per block (aka descriptor).
|
||||
// In this case there are two bytes per beat so divide the length by two.
|
||||
descriptor_config.block_transfer_count = self->len / 2;
|
||||
descriptor_config.source_address = ((uint32_t)self->buffer + self->len);
|
||||
descriptor_config.destination_address = ((uint32_t)&DAC->DATABUF.reg);
|
||||
if (loop) {
|
||||
descriptor_config.next_descriptor_address = ((uint32_t)audio_dma.descriptor);
|
||||
}
|
||||
|
||||
dma_descriptor_create(audio_dma.descriptor, &descriptor_config);
|
||||
active_audioout = self;
|
||||
dma_start_transfer_job(&audio_dma);
|
||||
|
||||
set_timer_frequency(self->frequency);
|
||||
tc_start_counter(tc_instance);
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self) {
|
||||
if (common_hal_audioio_audioout_get_playing(self)) {
|
||||
tc_stop_counter(tc_instance);
|
||||
dma_abort_job(&audio_dma);
|
||||
active_audioout = NULL;
|
||||
// TODO(tannewt): Disable the DAC to save power.
|
||||
}
|
||||
}
|
||||
|
||||
bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t* self) {
|
||||
if (!dma_is_busy(&audio_dma)) {
|
||||
active_audioout = NULL;
|
||||
}
|
||||
return active_audioout == self;
|
||||
}
|
||||
|
||||
void common_hal_audioio_audioout_set_frequency(audioio_audioout_obj_t* self,
|
||||
uint32_t frequency) {
|
||||
if (frequency == 0 || frequency > 350000) {
|
||||
mp_raise_ValueError("Unsupported playback frequency");
|
||||
}
|
||||
self->frequency = frequency;
|
||||
|
||||
if (common_hal_audioio_audioout_get_playing(self)) {
|
||||
set_timer_frequency(frequency);
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t common_hal_audioio_audioout_get_frequency(audioio_audioout_obj_t* self) {
|
||||
return self->frequency;
|
||||
}
|
47
atmel-samd/common-hal/audioio/AudioOut.h
Normal file
47
atmel-samd/common-hal/audioio/AudioOut.h
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_AUDIOIO_AUDIOOUT_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_AUDIOIO_AUDIOOUT_H__
|
||||
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "asf/sam0/drivers/tc/tc.h"
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
typedef struct {
|
||||
mp_obj_base_t base;
|
||||
const mcu_pin_obj_t *pin;
|
||||
uint32_t frequency;
|
||||
uint8_t* buffer;
|
||||
// TODO(tannewt): Add a second buffer for double buffering from a file system.
|
||||
// Length of buffer in bytes.
|
||||
uint32_t len;
|
||||
} audioio_audioout_obj_t;
|
||||
|
||||
void audioout_reset(void);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_COMMON_HAL_AUDIOIO_AUDIOOUT_H__
|
1
atmel-samd/common-hal/audioio/__init__.c
Normal file
1
atmel-samd/common-hal/audioio/__init__.c
Normal file
@ -0,0 +1 @@
|
||||
// No audioio module functions.
|
@ -97,6 +97,7 @@ bool common_hal_mcu_pin_is_free(const mcu_pin_obj_t* pin) {
|
||||
return !apa102_sck_in_use;
|
||||
}
|
||||
#endif
|
||||
|
||||
PortGroup *const port = system_pinmux_get_group_from_gpio_pin(pin->pin);
|
||||
uint32_t pin_index = (pin->pin);
|
||||
PORT_PINCFG_Type state = port->PINCFG[pin_index];
|
||||
|
@ -32,6 +32,7 @@
|
||||
#include "asf/sam0/drivers/port/port.h"
|
||||
|
||||
#include "mpconfigport.h"
|
||||
#include "py/gc.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/pulseio/PulseOut.h"
|
||||
|
||||
@ -39,7 +40,7 @@
|
||||
|
||||
// This timer is shared amongst all PulseOut objects under the assumption that
|
||||
// the code is single threaded.
|
||||
static struct tc_module tc_instance;
|
||||
static struct tc_module* tc_instance;
|
||||
static uint8_t refcount = 0;
|
||||
|
||||
static __IO PORT_PINCFG_Type *active_pincfg = NULL;
|
||||
@ -68,7 +69,7 @@ void pulse_finish(struct tc_module *const module) {
|
||||
return;
|
||||
}
|
||||
current_compare = (current_compare + pulse_buffer[pulse_index] * 3 / 4) & 0xffff;
|
||||
tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
|
||||
tc_set_compare_value(tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
|
||||
if (pulse_index % 2 == 0) {
|
||||
turn_on(active_pincfg);
|
||||
}
|
||||
@ -76,6 +77,7 @@ void pulse_finish(struct tc_module *const module) {
|
||||
|
||||
void pulseout_reset() {
|
||||
refcount = 0;
|
||||
tc_instance = 0;
|
||||
active_pincfg = NULL;
|
||||
}
|
||||
|
||||
@ -94,6 +96,10 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
|
||||
if (t == NULL) {
|
||||
mp_raise_RuntimeError("All timers in use");
|
||||
}
|
||||
tc_instance = gc_alloc(sizeof(struct tc_module), false);
|
||||
if (t == NULL) {
|
||||
mp_raise_msg(&mp_type_MemoryError, "");
|
||||
}
|
||||
|
||||
struct tc_config config_tc;
|
||||
tc_get_config_defaults(&config_tc);
|
||||
@ -102,10 +108,10 @@ void common_hal_pulseio_pulseout_construct(pulseio_pulseout_obj_t* self,
|
||||
config_tc.clock_prescaler = TC_CTRLA_PRESCALER_DIV64;
|
||||
config_tc.wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ;
|
||||
|
||||
tc_init(&tc_instance, t, &config_tc);
|
||||
tc_register_callback(&tc_instance, pulse_finish, TC_CALLBACK_CC_CHANNEL0);
|
||||
tc_enable(&tc_instance);
|
||||
tc_stop_counter(&tc_instance);
|
||||
tc_init(tc_instance, t, &config_tc);
|
||||
tc_register_callback(tc_instance, pulse_finish, TC_CALLBACK_CC_CHANNEL0);
|
||||
tc_enable(tc_instance);
|
||||
tc_stop_counter(tc_instance);
|
||||
}
|
||||
refcount++;
|
||||
|
||||
@ -130,7 +136,9 @@ void common_hal_pulseio_pulseout_deinit(pulseio_pulseout_obj_t* self) {
|
||||
|
||||
refcount--;
|
||||
if (refcount == 0) {
|
||||
tc_reset(&tc_instance);
|
||||
tc_reset(tc_instance);
|
||||
gc_free(tc_instance);
|
||||
tc_instance = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
@ -144,11 +152,11 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu
|
||||
pulse_length = length;
|
||||
|
||||
current_compare = pulses[0] * 3 / 4;
|
||||
tc_set_compare_value(&tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
|
||||
tc_set_compare_value(tc_instance, TC_COMPARE_CAPTURE_CHANNEL_0, current_compare);
|
||||
|
||||
tc_enable_callback(&tc_instance, TC_CALLBACK_CC_CHANNEL0);
|
||||
tc_enable_callback(tc_instance, TC_CALLBACK_CC_CHANNEL0);
|
||||
turn_on(active_pincfg);
|
||||
tc_start_counter(&tc_instance);
|
||||
tc_start_counter(tc_instance);
|
||||
|
||||
while(pulse_index < length) {
|
||||
// Do other things while we wait. The interrupts will handle sending the
|
||||
@ -158,7 +166,7 @@ void common_hal_pulseio_pulseout_send(pulseio_pulseout_obj_t* self, uint16_t* pu
|
||||
#endif
|
||||
}
|
||||
|
||||
tc_stop_counter(&tc_instance);
|
||||
tc_disable_callback(&tc_instance, TC_CALLBACK_CC_CHANNEL0);
|
||||
tc_stop_counter(tc_instance);
|
||||
tc_disable_callback(tc_instance, TC_CALLBACK_CC_CHANNEL0);
|
||||
active_pincfg = NULL;
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <board.h>
|
||||
|
||||
#include "common-hal/analogio/AnalogIn.h"
|
||||
#include "common-hal/audioio/AudioOut.h"
|
||||
#include "common-hal/pulseio/PulseIn.h"
|
||||
#include "common-hal/pulseio/PulseOut.h"
|
||||
#include "common-hal/pulseio/PWMOut.h"
|
||||
@ -40,6 +41,7 @@
|
||||
#include "autoreset.h"
|
||||
#include "mpconfigboard.h"
|
||||
#include "rgb_led_status.h"
|
||||
#include "shared_dma.h"
|
||||
#include "tick.h"
|
||||
|
||||
fs_user_mount_t fs_user_mount_flash;
|
||||
@ -180,6 +182,7 @@ void reset_samd21(void) {
|
||||
system_pinmux_group_set_config(&(PORT->Group[0]), pin_mask[0] & ~MICROPY_PORT_A, &config);
|
||||
system_pinmux_group_set_config(&(PORT->Group[1]), pin_mask[1] & ~MICROPY_PORT_B, &config);
|
||||
|
||||
audioout_reset();
|
||||
pwmout_reset();
|
||||
|
||||
usb_hid_reset();
|
||||
@ -504,6 +507,8 @@ void samd21_init(void) {
|
||||
nvm_get_config_defaults(&config_nvm);
|
||||
config_nvm.manual_page_write = false;
|
||||
nvm_set_config(&config_nvm);
|
||||
|
||||
init_shared_dma();
|
||||
}
|
||||
|
||||
extern uint32_t _estack;
|
||||
|
@ -125,6 +125,7 @@ typedef long mp_off_t;
|
||||
// extra built in modules to add to the list of known ones
|
||||
extern const struct _mp_obj_module_t microcontroller_module;
|
||||
extern const struct _mp_obj_module_t bitbangio_module;
|
||||
extern const struct _mp_obj_module_t audioio_module;
|
||||
extern const struct _mp_obj_module_t analogio_module;
|
||||
extern const struct _mp_obj_module_t digitalio_module;
|
||||
extern const struct _mp_obj_module_t pulseio_module;
|
||||
@ -143,6 +144,7 @@ extern const struct _mp_obj_module_t usb_hid_module;
|
||||
#define MICROPY_PY_MICROPYTHON_MEM_INFO (1)
|
||||
#define MICROPY_PY_FRAMEBUF (1)
|
||||
#define EXTRA_BUILTIN_MODULES \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_audioio), (mp_obj_t)&audioio_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_pulseio), (mp_obj_t)&pulseio_module }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_bitbangio), (mp_obj_t)&bitbangio_module }
|
||||
#define EXPRESS_BOARD
|
||||
|
54
atmel-samd/shared_dma.c
Normal file
54
atmel-samd/shared_dma.c
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "shared_dma.h"
|
||||
|
||||
// We allocate two DMA resources for the entire lifecycle of the board (not the
|
||||
// vm) because the general_dma resource will be shared between the REPL and SPI
|
||||
// flash. Both uses must block each other in order to prevent conflict.
|
||||
struct dma_resource audio_dma;
|
||||
struct dma_resource general_dma;
|
||||
|
||||
void init_shared_dma(void) {
|
||||
struct dma_resource_config config;
|
||||
dma_get_config_defaults(&config);
|
||||
|
||||
// This allocates the lowest channel first so make sure the audio is first
|
||||
// so it gets the highest priority.
|
||||
config.peripheral_trigger = DAC_DMAC_ID_EMPTY;
|
||||
config.trigger_action = DMA_TRIGGER_ACTION_BEAT;
|
||||
config.event_config.input_action = DMA_EVENT_INPUT_TRIG;
|
||||
dma_allocate(&audio_dma, &config);
|
||||
// Turn on the transfer complete interrupt so that the job_status changes to done.
|
||||
g_chan_interrupt_flag[audio_dma.channel_id] |= (1UL << DMA_CALLBACK_TRANSFER_DONE);
|
||||
|
||||
dma_get_config_defaults(&config);
|
||||
dma_allocate(&general_dma, &config);
|
||||
|
||||
// Be sneaky and reuse the active descriptor memory.
|
||||
audio_dma.descriptor = &descriptor_section[audio_dma.channel_id];
|
||||
general_dma.descriptor = &descriptor_section[general_dma.channel_id];
|
||||
}
|
37
atmel-samd/shared_dma.h
Normal file
37
atmel-samd/shared_dma.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_ATMEL_SAMD_SHARED_DMA_H__
|
||||
#define __MICROPY_INCLUDED_ATMEL_SAMD_SHARED_DMA_H__
|
||||
|
||||
#include "asf/sam0/drivers/dma/dma.h"
|
||||
|
||||
extern struct dma_resource audio_dma;
|
||||
extern struct dma_resource general_dma;
|
||||
|
||||
void init_shared_dma(void);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_ATMEL_SAMD_SHARED_DMA_H__
|
@ -24,7 +24,8 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "py/mpconfig.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
|
||||
// *_ADHOC part is for cc3200 port which doesn't use general uPy
|
||||
// infrastructure and instead duplicates code. TODO: Resolve.
|
||||
#if MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC
|
||||
@ -37,15 +38,6 @@
|
||||
#include "py/stream.h"
|
||||
#include "py/mperrno.h"
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
|
||||
#if MICROPY_VFS_FAT
|
||||
#define mp_type_fileio fatfs_type_fileio
|
||||
#define mp_type_textio fatfs_type_textio
|
||||
#endif
|
||||
|
||||
extern const mp_obj_type_t mp_type_fileio;
|
||||
extern const mp_obj_type_t mp_type_textio;
|
||||
|
||||
// this table converts from FRESULT to POSIX errno
|
||||
const byte fresult_to_errno_table[20] = {
|
||||
@ -71,11 +63,6 @@ const byte fresult_to_errno_table[20] = {
|
||||
[FR_INVALID_PARAMETER] = MP_EINVAL,
|
||||
};
|
||||
|
||||
typedef struct _pyb_file_obj_t {
|
||||
mp_obj_base_t base;
|
||||
FIL fp;
|
||||
} pyb_file_obj_t;
|
||||
|
||||
STATIC void file_obj_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
|
||||
(void)kind;
|
||||
mp_printf(print, "<io.%s %p>", mp_obj_get_type_str(self_in), MP_OBJ_TO_PTR(self_in));
|
||||
|
@ -24,9 +24,35 @@
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_EXTMOD_VFS_FAT_FILE_H__
|
||||
#define __MICROPY_INCLUDED_EXTMOD_VFS_FAT_FILE_H__
|
||||
|
||||
#include "lib/fatfs/ff.h"
|
||||
#include "py/mpconfig.h"
|
||||
#include "py/obj.h"
|
||||
|
||||
#if MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC
|
||||
|
||||
extern const byte fresult_to_errno_table[20];
|
||||
|
||||
#if MICROPY_VFS_FAT
|
||||
#define mp_type_fileio fatfs_type_fileio
|
||||
#define mp_type_textio fatfs_type_textio
|
||||
#endif
|
||||
|
||||
extern const mp_obj_type_t mp_type_fileio;
|
||||
extern const mp_obj_type_t mp_type_textio;
|
||||
|
||||
typedef struct _pyb_file_obj_t {
|
||||
mp_obj_base_t base;
|
||||
FIL fp;
|
||||
} pyb_file_obj_t;
|
||||
|
||||
mp_obj_t fatfs_builtin_open(mp_uint_t n_args, const mp_obj_t *args, mp_map_t *kwargs);
|
||||
MP_DECLARE_CONST_FUN_OBJ_KW(mp_builtin_open_obj);
|
||||
|
||||
mp_obj_t fat_vfs_listdir(const char *path, bool is_str_type);
|
||||
|
||||
#endif // MICROPY_FSUSERMOUNT || MICROPY_FSUSERMOUNT_ADHOC
|
||||
|
||||
#endif // __MICROPY_INCLUDED_EXTMOD_VFS_FAT_FILE_H__
|
||||
|
@ -34,7 +34,7 @@ extern const mp_obj_type_t analogio_analogin_type;
|
||||
|
||||
void common_hal_analogio_analogin_construct(analogio_analogin_obj_t* self, const mcu_pin_obj_t *pin);
|
||||
void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t* self);
|
||||
uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self);
|
||||
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self);
|
||||
uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t* self);
|
||||
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t* self);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_ANALOGIO_ANALOGIN_H__
|
||||
|
222
shared-bindings/audioio/AudioOut.c
Normal file
222
shared-bindings/audioio/AudioOut.c
Normal file
@ -0,0 +1,222 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "lib/utils/context_manager_helpers.h"
|
||||
#include "py/objproperty.h"
|
||||
#include "py/runtime.h"
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audioio/AudioOut.h"
|
||||
|
||||
//| .. currentmodule:: audioio
|
||||
//|
|
||||
//| :class:`AudioOut` -- Output an analog audio signal
|
||||
//| ========================================================
|
||||
//|
|
||||
//| AudioOut can be used to output an analog audio signal on a given pin.
|
||||
//|
|
||||
//| .. class:: AudioOut(pin, sample_source)
|
||||
//|
|
||||
//| Create a AudioOut object associated with the given pin. This allows you to
|
||||
//| play audio signals out on the given pin. Sample_source must be a `bytes-like object <https://docs.python.org/3/glossary.html#term-bytes-like-object>`_.
|
||||
//|
|
||||
//| The sample itself should consist of 16 bit samples and be mono.
|
||||
//| Microcontrollers with a lower output resolution will use the highest order
|
||||
//| bits to output. For example, the SAMD21 has a 10 bit DAC that ignores the
|
||||
//| lowest 6 bits when playing 16 bit samples.
|
||||
//|
|
||||
//| :param ~microcontroller.Pin pin: The pin to output to
|
||||
//| :param bytes-like sample_source: The source of the sample
|
||||
//|
|
||||
//| Simple 8ksps 440 Hz sin wave::
|
||||
//|
|
||||
//| import audioio
|
||||
//| import board
|
||||
//| import array
|
||||
//| import time
|
||||
//| import math
|
||||
//|
|
||||
//| # Generate one period of sine wav.
|
||||
//| length = 8000 // 440
|
||||
//| b = array.array("H", [0] * length)
|
||||
//| for i in range(length):
|
||||
//| b[i] = int(math.sin(math.pi * 2 * i / 18) * (2 ** 15) + 2 ** 15)
|
||||
//|
|
||||
//| with audioio.AudioOut(board.SPEAKER, sin_wave) as sample:
|
||||
//| sample.play(loop=True)
|
||||
//| time.sleep(1)
|
||||
//| sample.stop()
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) {
|
||||
mp_arg_check_num(n_args, n_kw, 2, 2, true);
|
||||
mp_obj_t pin_obj = args[0];
|
||||
assert_pin(pin_obj, false);
|
||||
const mcu_pin_obj_t *pin = MP_OBJ_TO_PTR(pin_obj);
|
||||
// We explicitly don't check whether the pin is free because multiple
|
||||
// AudioOuts may share it.
|
||||
|
||||
// create PWM object from the given pin
|
||||
audioio_audioout_obj_t *self = m_new_obj(audioio_audioout_obj_t);
|
||||
self->base.type = &audioio_audioout_type;
|
||||
mp_buffer_info_t bufinfo;
|
||||
if (MP_OBJ_IS_TYPE(args[1], &fatfs_type_fileio)) {
|
||||
common_hal_audioio_audioout_construct_from_file(self, pin, MP_OBJ_TO_PTR(args[1]));
|
||||
} else if (mp_get_buffer(args[1], &bufinfo, MP_BUFFER_READ)) {
|
||||
if (bufinfo.len % 2 == 1) {
|
||||
mp_raise_ValueError("sample_source must be an even number of bytes (two per sample)");
|
||||
}
|
||||
common_hal_audioio_audioout_construct_from_buffer(self, pin, ((uint16_t*)bufinfo.buf), bufinfo.len / 2);
|
||||
} else {
|
||||
mp_raise_TypeError("sample_source must be a file or bytes-like object.");
|
||||
}
|
||||
|
||||
return MP_OBJ_FROM_PTR(self);
|
||||
}
|
||||
|
||||
//| .. method:: deinit()
|
||||
//|
|
||||
//| Deinitialises the PWMOut and releases any hardware resources for reuse.
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_deinit(mp_obj_t self_in) {
|
||||
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_audioio_audioout_deinit(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_deinit_obj, audioio_audioout_deinit);
|
||||
|
||||
//| .. method:: __enter__()
|
||||
//|
|
||||
//| No-op used by Context Managers.
|
||||
//|
|
||||
// Provided by context manager helper.
|
||||
|
||||
//| .. method:: __exit__()
|
||||
//|
|
||||
//| Automatically deinitializes the hardware when exiting a context.
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_obj___exit__(size_t n_args, const mp_obj_t *args) {
|
||||
(void)n_args;
|
||||
common_hal_audioio_audioout_deinit(args[0]);
|
||||
return mp_const_none;
|
||||
}
|
||||
STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(audioio_audioout___exit___obj, 4, 4, audioio_audioout_obj___exit__);
|
||||
|
||||
|
||||
//| .. method:: play(loop=False)
|
||||
//|
|
||||
//| Plays the sample once when loop=False and continuously when loop=True.
|
||||
//| Does not block. Use `playing` to block.
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_obj_play(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
|
||||
enum { ARG_loop };
|
||||
static const mp_arg_t allowed_args[] = {
|
||||
{ MP_QSTR_loop, MP_ARG_BOOL, {.u_bool = false} },
|
||||
};
|
||||
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(pos_args[0]);
|
||||
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
|
||||
mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
|
||||
|
||||
common_hal_audioio_audioout_play(self, args[ARG_loop].u_bool);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_KW(audioio_audioout_play_obj, 1, audioio_audioout_obj_play);
|
||||
|
||||
//| .. method:: stop()
|
||||
//|
|
||||
//| Stops playback of this sample. If another sample is playing instead, it
|
||||
//| won't be stopped.
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_obj_stop(mp_obj_t self_in) {
|
||||
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_audioio_audioout_stop(self);
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_stop_obj, audioio_audioout_obj_stop);
|
||||
|
||||
//| .. attribute:: playing
|
||||
//|
|
||||
//| True when the audio sample is being output.
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_obj_get_playing(mp_obj_t self_in) {
|
||||
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return mp_obj_new_bool(common_hal_audioio_audioout_get_playing(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_playing_obj, audioio_audioout_obj_get_playing);
|
||||
|
||||
const mp_obj_property_t audioio_audioout_playing_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&audioio_audioout_get_playing_obj,
|
||||
(mp_obj_t)&mp_const_none_obj,
|
||||
(mp_obj_t)&mp_const_none_obj},
|
||||
};
|
||||
|
||||
//| .. attribute:: frequency
|
||||
//|
|
||||
//| 32 bit value that dictates how quickly samples are loaded into the DAC
|
||||
//| in Hertz (cycles per second). When the sample is looped, this can change
|
||||
//| the pitch output without changing the underlying sample.
|
||||
//|
|
||||
STATIC mp_obj_t audioio_audioout_obj_get_frequency(mp_obj_t self_in) {
|
||||
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
return MP_OBJ_NEW_SMALL_INT(common_hal_audioio_audioout_get_frequency(self));
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_1(audioio_audioout_get_frequency_obj, audioio_audioout_obj_get_frequency);
|
||||
|
||||
STATIC mp_obj_t audioio_audioout_obj_set_frequency(mp_obj_t self_in, mp_obj_t frequency) {
|
||||
audioio_audioout_obj_t *self = MP_OBJ_TO_PTR(self_in);
|
||||
common_hal_audioio_audioout_set_frequency(self, mp_obj_get_int(frequency));
|
||||
return mp_const_none;
|
||||
}
|
||||
MP_DEFINE_CONST_FUN_OBJ_2(audioio_audioout_set_frequency_obj, audioio_audioout_obj_set_frequency);
|
||||
|
||||
const mp_obj_property_t audioio_audioout_frequency_obj = {
|
||||
.base.type = &mp_type_property,
|
||||
.proxy = {(mp_obj_t)&audioio_audioout_get_frequency_obj,
|
||||
(mp_obj_t)&audioio_audioout_set_frequency_obj,
|
||||
(mp_obj_t)&mp_const_none_obj},
|
||||
};
|
||||
|
||||
STATIC const mp_rom_map_elem_t audioio_audioout_locals_dict_table[] = {
|
||||
// Methods
|
||||
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&audioio_audioout_deinit_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&default___enter___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&audioio_audioout___exit___obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_play), MP_ROM_PTR(&audioio_audioout_play_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_stop), MP_ROM_PTR(&audioio_audioout_stop_obj) },
|
||||
|
||||
// Properties
|
||||
{ MP_ROM_QSTR(MP_QSTR_playing), MP_ROM_PTR(&audioio_audioout_playing_obj) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_frequency), MP_ROM_PTR(&audioio_audioout_frequency_obj) },
|
||||
};
|
||||
STATIC MP_DEFINE_CONST_DICT(audioio_audioout_locals_dict, audioio_audioout_locals_dict_table);
|
||||
|
||||
const mp_obj_type_t audioio_audioout_type = {
|
||||
{ &mp_type_type },
|
||||
.name = MP_QSTR_AudioOut,
|
||||
.make_new = audioio_audioout_make_new,
|
||||
.locals_dict = (mp_obj_dict_t*)&audioio_audioout_locals_dict,
|
||||
};
|
46
shared-bindings/audioio/AudioOut.h
Normal file
46
shared-bindings/audioio/AudioOut.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This file is part of the Micro Python project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H__
|
||||
#define __MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H__
|
||||
|
||||
#include "common-hal/audioio/AudioOut.h"
|
||||
#include "common-hal/microcontroller/Pin.h"
|
||||
#include "extmod/vfs_fat_file.h"
|
||||
|
||||
extern const mp_obj_type_t audioio_audioout_type;
|
||||
|
||||
void common_hal_audioio_audioout_construct_from_buffer(audioio_audioout_obj_t* self, const mcu_pin_obj_t* pin, uint16_t* buffer, uint32_t len);
|
||||
void common_hal_audioio_audioout_construct_from_file(audioio_audioout_obj_t* self, const mcu_pin_obj_t* pin, pyb_file_obj_t* file);
|
||||
|
||||
void common_hal_audioio_audioout_deinit(audioio_audioout_obj_t* self);
|
||||
void common_hal_audioio_audioout_play(audioio_audioout_obj_t* self, bool loop);
|
||||
void common_hal_audioio_audioout_stop(audioio_audioout_obj_t* self);
|
||||
bool common_hal_audioio_audioout_get_playing(audioio_audioout_obj_t* self);
|
||||
uint32_t common_hal_audioio_audioout_get_frequency(audioio_audioout_obj_t* self);
|
||||
void common_hal_audioio_audioout_set_frequency(audioio_audioout_obj_t* self, uint32_t frequency);
|
||||
|
||||
#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO_AUDIOOUT_H__
|
67
shared-bindings/audioio/__init__.c
Normal file
67
shared-bindings/audioio/__init__.c
Normal file
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "py/obj.h"
|
||||
#include "py/runtime.h"
|
||||
|
||||
#include "shared-bindings/microcontroller/Pin.h"
|
||||
#include "shared-bindings/audioio/__init__.h"
|
||||
#include "shared-bindings/audioio/AudioOut.h"
|
||||
|
||||
//| :mod:`audioio` --- Support for audio input and output
|
||||
//| =================================================
|
||||
//|
|
||||
//| .. module:: audioio
|
||||
//| :synopsis: Support for audio input and output
|
||||
//| :platform: SAMD21
|
||||
//|
|
||||
//| The `audioio` module contains classes to provide access to audio IO.
|
||||
//|
|
||||
//| Libraries
|
||||
//|
|
||||
//| .. toctree::
|
||||
//| :maxdepth: 3
|
||||
//|
|
||||
//| AudioOut
|
||||
//|
|
||||
//| All libraries change hardware state and should be deinitialized when they
|
||||
//| are no longer needed. To do so, either call :py:meth:`!deinit` or use a
|
||||
//| context manager.
|
||||
//|
|
||||
|
||||
STATIC const mp_rom_map_elem_t audioio_module_globals_table[] = {
|
||||
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_audioio) },
|
||||
{ MP_ROM_QSTR(MP_QSTR_AudioOut), MP_ROM_PTR(&audioio_audioout_type) },
|
||||
};
|
||||
|
||||
STATIC MP_DEFINE_CONST_DICT(audioio_module_globals, audioio_module_globals_table);
|
||||
|
||||
const mp_obj_module_t audioio_module = {
|
||||
.base = { &mp_type_module },
|
||||
.globals = (mp_obj_dict_t*)&audioio_module_globals,
|
||||
};
|
34
shared-bindings/audioio/__init__.h
Normal file
34
shared-bindings/audioio/__init__.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* This file is part of the MicroPython project, http://micropython.org/
|
||||
*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2017 Scott Shawcroft for Adafruit Industries
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H__
|
||||
#define __MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H__
|
||||
|
||||
#include "py/obj.h"
|
||||
|
||||
// Nothing now.
|
||||
|
||||
#endif // __MICROPY_INCLUDED_SHARED_BINDINGS_AUDIOIO___INIT___H__
|
Loading…
x
Reference in New Issue
Block a user