diff --git a/.github/workflows/githubci.yml b/.github/workflows/githubci.yml index 283c88cae..b3519eed6 100644 --- a/.github/workflows/githubci.yml +++ b/.github/workflows/githubci.yml @@ -7,7 +7,7 @@ jobs: strategy: fail-fast: false matrix: - arduino-platform: + board: # Alphabetical order - 'metro_m0' - 'hallowing' @@ -66,8 +66,4 @@ jobs: arduino-cli lib install $LIB_DEPS - name: Build examples - run: python3 extras/build_all.py ${{ matrix.arduino-platform }} - - # How to mark this as allowed-to-fail? - - name: Build examples (-Wall) - run: python3 extras/build_all.py --all_warnings --warnings_do_not_cause_job_failure + run: python3 extras/build_all.py ${{ matrix.board }} diff --git a/.gitmodules b/.gitmodules index 5a5336ccf..8e657daeb 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "libraries/Adafruit_TinyUSB_Arduino"] path = libraries/Adafruit_TinyUSB_Arduino url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git +[submodule "libraries/Adafruit_ZeroDMA"] + path = libraries/Adafruit_ZeroDMA + url = https://github.com/adafruit/Adafruit_ZeroDMA diff --git a/extras/build_all.py b/extras/build_all.py index ad9742d78..068065a29 100644 --- a/extras/build_all.py +++ b/extras/build_all.py @@ -2,63 +2,49 @@ import glob import sys import subprocess +from subprocess import Popen, PIPE import time -import argparse - -FQBN_PREFIX='adafruit:samd:adafruit_' - -parser = argparse.ArgumentParser( - description='python wrapper for adafruit arduino CI workflows', - allow_abbrev=False - ) -parser.add_argument( - '--all_warnings', '--Wall', - action='store_true', - help='build with all warnings enabled (`--warnings all`)', - ) -parser.add_argument( - '--warnings_do_not_cause_job_failure', - action='store_true', - help='failed builds will be listed as failed, but not cause job to exit with an error status', - ) -parser.add_argument( - 'build_boards', - metavar='board', - nargs='*', - help='list of boards to be built -- Note that the fqbn is created by prepending "{}"'.format(FQBN_PREFIX), - default= [ 'metro_m0', 'metro_m4', 'circuitplayground_m0', 'feather_m4_can' ] - ) -args = parser.parse_args() +SUCCEEDED = "\033[32msucceeded\033[0m" +FAILED = "\033[31mfailed\033[0m" +SKIPPED = "\033[35mskipped\033[0m" +WARNING = "\033[33mwarnings\033[0m " exit_status = 0 success_count = 0 fail_count = 0 skip_count = 0 -build_format = '| {:22} | {:30} | {:9} ' -build_separator = '-' * 80 -def errorOutputFilter(line: str): - if len(line) == 0: - return False - if line.isspace(): # Note: empty string does not match here! - return False - # TODO: additional items to remove? - return True +build_format = '| {:20} | {:35} | {:18} | {:6} |' +build_separator = '-' * 83 + +FQBN_PREFIX='adafruit:samd:adafruit_' + +default_boards = [ 'metro_m0', 'metro_m4', 'circuitplayground_m0', 'feather_m4_can' ] +build_boards = [] + +# build all variants if input not existed +if len(sys.argv) > 1: + build_boards.append(sys.argv[1]) +else: + build_boards = default_boards + +all_examples = list(glob.iglob('libraries/**/*.ino', recursive=True)) +all_examples.sort() -def build_examples(variant: str): - global args, exit_status, success_count, fail_count, skip_count, build_format, build_separator +def build_examples(variant): + global exit_status, success_count, fail_count, skip_count, build_format, build_separator print('\n') print(build_separator) - print('| {:^76} |'.format('Board ' + variant)) + print('| {:^79} |'.format('Board ' + variant)) print(build_separator) - print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time')) + print(build_format.format('Library', 'Example', '\033[39mResult\033[0m', 'Time')) print(build_separator) fqbn = "{}{}".format(FQBN_PREFIX, variant) - for sketch in glob.iglob('libraries/**/*.ino', recursive=True): + for sketch in all_examples: # TODO skip TinyUSB library examples for now if "libraries/Adafruit_TinyUSB_Arduino" in sketch: continue @@ -69,60 +55,47 @@ def build_examples(variant: str): # Skip if not contains: ".board.test.only" for a specific board sketchdir = os.path.dirname(sketch) if os.path.exists(sketchdir + '/.all.test.skip') or os.path.exists(sketchdir + '/.' + variant + '.test.skip'): - success = "\033[33mskipped\033[0m " - elif glob.glob(sketchdir+"/.*.test.only") and not os.path.exists(sketchdir + '/.build.' + variant): - success = "\033[33mskipped\033[0m " + success = SKIPPED + skip_count += 1 + elif glob.glob(sketchdir+"/.*.test.only") and not os.path.exists(sketchdir + '/.' + variant + '.test.only'): + success = SKIPPED + skip_count += 1 else: - # TODO - preferably, would have STDERR show up in **both** STDOUT and STDERR. - # preferably, would use Python logging handler to get both distinct outputs and one merged output - # for now, split STDERR when building with all warnings enabled, so can detect warning/error output. - if args.all_warnings: - build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - else: - build_result = subprocess.run("arduino-cli compile --warnings default --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - - # get stderr into a form where len(warningLines) indicates a true warning was output to stderr - warningLines = []; - if args.all_warnings and build_result.stderr: - tmpWarningLines = build_result.stderr.decode("utf-8").splitlines() - warningLines = list(filter(errorOutputFilter, (tmpWarningLines))) + build_result = subprocess.run("arduino-cli compile --warnings all --fqbn {} {}".format(fqbn, sketch), shell=True, stdout=PIPE, stderr=PIPE) + # get stderr into a form where warning/error was output to stderr if build_result.returncode != 0: exit_status = build_result.returncode - success = "\033[31mfailed\033[0m " - fail_count += 1 - elif len(warningLines) != 0: - if not args.warnings_do_not_cause_job_failure: - exit_status = -1 - success = "\033[31mwarnings\033[0m " + success = FAILED fail_count += 1 else: - success = "\033[32msucceeded\033[0m" success_count += 1 + if build_result.stderr: + success = WARNING + else: + success = SUCCEEDED build_duration = time.monotonic() - start_time - print((build_format + '| {:5.2f}s |').format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, build_duration)) + print(build_format.format(sketch.split(os.path.sep)[1], os.path.basename(sketch), success, '{:5.2f}s'.format(build_duration))) - if success != "\033[33mskipped\033[0m ": + if success != SKIPPED: + # Build failed if build_result.returncode != 0: print(build_result.stdout.decode("utf-8")) - if (build_result.stderr): - print(build_result.stderr.decode("utf-8")) - if len(warningLines) != 0: - for line in warningLines: - print(line) - else: - skip_count += 1 + + # Build with warnings + if build_result.stderr: + print(build_result.stderr.decode("utf-8")) build_time = time.monotonic() -for board in args.build_boards: +for board in build_boards: build_examples(board) print(build_separator) build_time = time.monotonic() - build_time -print("Build Summary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m, {} \033[33mskipped\033[0m and took {:.2f}s".format(success_count, fail_count, skip_count, build_time)) +print("Build Summary: {} {}, {} {}, {} {} and took {:.2f}s".format(success_count, SUCCEEDED, fail_count, FAILED, skip_count, SKIPPED, build_time)) print(build_separator) sys.exit(exit_status) diff --git a/libraries/Adafruit_TinyUSB_Arduino b/libraries/Adafruit_TinyUSB_Arduino index d26aa1bbd..8f4bc1f43 160000 --- a/libraries/Adafruit_TinyUSB_Arduino +++ b/libraries/Adafruit_TinyUSB_Arduino @@ -1 +1 @@ -Subproject commit d26aa1bbd2c5563b3a96ab4a3acccecbd91bb690 +Subproject commit 8f4bc1f438c9d89a9080438b2e36291c527b4e0e diff --git a/libraries/Adafruit_ZeroDMA b/libraries/Adafruit_ZeroDMA new file mode 160000 index 000000000..1472d1f5d --- /dev/null +++ b/libraries/Adafruit_ZeroDMA @@ -0,0 +1 @@ +Subproject commit 1472d1f5d06a84f0458eca35839a8540583530a0 diff --git a/libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.cpp b/libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.cpp deleted file mode 100644 index 0adb78470..000000000 --- a/libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.cpp +++ /dev/null @@ -1,654 +0,0 @@ -#include -#include // memalign() function - -#include "utility/dma.h" -static volatile uint32_t _channelMask = 0; // Bitmask of allocated channels - -// DMA descriptor list entry point (and writeback buffer) per channel -__attribute__((__aligned__(16))) static DmacDescriptor // 128 bit alignment - _descriptor[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR, - _writeback[DMAC_CH_NUM] SECTION_DMAC_DESCRIPTOR; - -// Pointer to ZeroDMA object for each channel is needed for the -// ISR (in C, outside of class context) to access callbacks. -static Adafruit_ZeroDMA *_dmaPtr[DMAC_CH_NUM] = { 0 }; // Init to NULL - -// Adapted from ASF3 interrupt_sam_nvic.c: - -static volatile unsigned long cpu_irq_critical_section_counter = 0; -static volatile unsigned char cpu_irq_prev_interrupt_state = 0; - -static void cpu_irq_enter_critical(void) { - if(!cpu_irq_critical_section_counter) { - if(__get_PRIMASK() == 0) { // IRQ enabled? - __disable_irq(); // Disable it - __DMB(); - cpu_irq_prev_interrupt_state = 1; - } else { - // Make sure the to save the prev state as false - cpu_irq_prev_interrupt_state = 0; - } - } - - cpu_irq_critical_section_counter++; -} - -static void cpu_irq_leave_critical(void) { - // Check if the user is trying to leave a critical section - // when not in a critical section - if(cpu_irq_critical_section_counter > 0) { - cpu_irq_critical_section_counter--; - - // Only enable global interrupts when the counter - // reaches 0 and the state of the global interrupt flag - // was enabled when entering critical state */ - if((!cpu_irq_critical_section_counter) && - cpu_irq_prev_interrupt_state) { - __DMB(); - __enable_irq(); - } - } -} - -// CONSTRUCTOR ------------------------------------------------------------- - -// Constructor initializes Adafruit_ZeroDMA basics but does NOT allocate a -// DMA channel (that's done in allocate()) or start a job (that's done in -// startJob()). This is because constructors in a global context are called -// before a sketch's setup() function, which may have some other hardware -// initialization of its own, don't want it clobbering us. -Adafruit_ZeroDMA::Adafruit_ZeroDMA(void) { - channel = 0xFF; // Channel not yet allocated - jobStatus = DMA_STATUS_OK; - hasDescriptors = false; // No descriptors allocated yet - loopFlag = false; - peripheralTrigger = 0; // Software trigger only by default - triggerAction = DMA_TRIGGER_ACTON_TRANSACTION; - memset(callback, 0, sizeof(callback)); -} - -// TODO: add destructor? Should stop job, delete descriptors, free channel. - -// INTERRUPT SERVICE ROUTINE ----------------------------------------------- - -// This is a C function that exists outside the Adafruit_ZeroDMA context. -// DMA channel number is determined from the INTPEND register, from this -// we get a ZeroDMA object pointer through the _dmaPtr[] array. -// (It's done this way because jobStatus and callback[] are protected -// elements in the ZeroDMA object -- we can't touch them in C, but the -// next function after this, being part of the ZeroDMA class, can.) - -#ifdef __SAMD51__ -void DMAC_0_Handler(void) { -#else -void DMAC_Handler(void) { -#endif - cpu_irq_enter_critical(); - - uint8_t channel = DMAC->INTPEND.bit.ID; // Channel # causing interrupt - if(channel < DMAC_CH_NUM) { - Adafruit_ZeroDMA *dma; - if((dma = _dmaPtr[channel])) { // -> Channel's ZeroDMA object -#ifdef __SAMD51__ - // Call IRQ handler with channel # - dma->_IRQhandler(channel); -#else - DMAC->CHID.bit.ID = channel; - // Call IRQ handler with interrupt flag(s) - dma->_IRQhandler(DMAC->CHINTFLAG.reg); -#endif - } - } - - cpu_irq_leave_critical(); -} - -#ifdef __SAMD51__ -void DMAC_1_Handler(void) __attribute__((weak, alias("DMAC_0_Handler"))); -void DMAC_2_Handler(void) __attribute__((weak, alias("DMAC_0_Handler"))); -void DMAC_3_Handler(void) __attribute__((weak, alias("DMAC_0_Handler"))); -void DMAC_4_Handler(void) __attribute__((weak, alias("DMAC_0_Handler"))); -#endif - -void Adafruit_ZeroDMA::_IRQhandler(uint8_t flags) { -#ifdef __SAMD51__ - // 'flags' is initially passed in as channel number, - // from which we look up the actual interrupt flags... - flags = DMAC->Channel[flags].CHINTFLAG.reg; -#endif - if(flags & DMAC_CHINTENCLR_TERR) { - // Clear error flag -#ifdef __SAMD51__ - DMAC->Channel[channel].CHINTFLAG.reg = DMAC_CHINTENCLR_TERR; -#else - DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TERR; -#endif - jobStatus = DMA_STATUS_ERR_IO; - if(callback[DMA_CALLBACK_TRANSFER_ERROR]) { - callback[DMA_CALLBACK_TRANSFER_ERROR](this); - } - } else if(flags & DMAC_CHINTENCLR_TCMPL) { - // Clear transfer complete flag -#ifdef __SAMD51__ - DMAC->Channel[channel].CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; -#else - DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_TCMPL; -#endif - jobStatus = DMA_STATUS_OK; - if(callback[DMA_CALLBACK_TRANSFER_DONE]) { - callback[DMA_CALLBACK_TRANSFER_DONE](this); - } - } else if(flags & DMAC_CHINTENCLR_SUSP) { - // Clear channel suspend flag -#ifdef __SAMD51__ - DMAC->Channel[channel].CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP; -#else - DMAC->CHINTFLAG.reg = DMAC_CHINTENCLR_SUSP; -#endif - jobStatus = DMA_STATUS_SUSPEND; - if(callback[DMA_CALLBACK_CHANNEL_SUSPEND]) { - callback[DMA_CALLBACK_CHANNEL_SUSPEND](this); - } - } -} - -// DMA CHANNEL FUNCTIONS --------------------------------------------------- - -// Allocates channel for ZeroDMA object -ZeroDMAstatus Adafruit_ZeroDMA::allocate(void) { - - if(channel < DMAC_CH_NUM) return DMA_STATUS_OK; // Already alloc'd! - - // Find index of first free DMA channel. As currently written, - // this "does not play well with others" as it assumes _channelMask - // is the final arbiter of channels in use (this is true only within - // this library -- but other DMA-driven code may have allocated its - // own channel(s) elsewhere, sometimes with an equally broken - // approach). A possible alternate approach, I haven't tested this - // yet, might be to loop through each channel, set DMAC->CHID.bit.ID - // and then test whether CHCTRLA.bit.ENABLE is set? But for now... - for(channel=0; (channel < DMAC_CH_NUM) && - (_channelMask & (1 << channel)); channel++); - // Doesn't help that code later does a software reset of the DMA - // controller, which would blow out other DMA-using libraries - // anyway (or they're just as likely to blow out this one). - // I think it's just an all-or-nothing affair...use one library - // for DMA everything, never mix and match. - - if(channel >= DMAC_CH_NUM) { // No free channel! - return DMA_STATUS_ERR_NOT_FOUND; - } - - cpu_irq_enter_critical(); - - if(!_channelMask) { // No channels allocated yet; initialize DMA! -#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) - PM->AHBMASK.bit.DMAC_ = 1; -#elif defined(__SAMD51__) - MCLK->AHBMASK.bit.DMAC_ = 1; // Initialize DMA clocks -#else - PM->AHBMASK.bit.DMAC_ = 1; // Initialize DMA clocks - PM->APBBMASK.bit.DMAC_ = 1; -#endif - DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA controller - DMAC->CTRL.bit.SWRST = 1; // Perform software reset - - // Initialize descriptor list addresses - DMAC->BASEADDR.bit.BASEADDR = (uint32_t)_descriptor; - DMAC->WRBADDR.bit.WRBADDR = (uint32_t)_writeback; - memset(_descriptor, 0, sizeof(_descriptor)); - memset(_writeback , 0, sizeof(_writeback)); - - // Re-enable DMA controller with all priority levels - DMAC->CTRL.reg = DMAC_CTRL_DMAENABLE | DMAC_CTRL_LVLEN(0xF); - - // Enable DMA interrupt at lowest priority -#ifdef __SAMD51__ - IRQn_Type irqs[] = { DMAC_0_IRQn, DMAC_1_IRQn, DMAC_2_IRQn, - DMAC_3_IRQn, DMAC_4_IRQn }; - for(uint8_t i=0; i<(sizeof irqs / sizeof irqs[0]); i++) { - NVIC_EnableIRQ(irqs[i]); - NVIC_SetPriority(irqs[i], (1<<__NVIC_PRIO_BITS)-1); - } -#else - NVIC_EnableIRQ(DMAC_IRQn); - NVIC_SetPriority(DMAC_IRQn, (1 << __NVIC_PRIO_BITS) - 1); -#endif - } - - _channelMask |= 1 << channel; // Mark channel as allocated - _dmaPtr[channel] = this; // Channel-index-to-object pointer - - // Reset the allocated channel -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 0; - DMAC->Channel[channel].CHCTRLA.bit.SWRST = 1; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHCTRLA.bit.ENABLE = 0; - DMAC->CHCTRLA.bit.SWRST = 1; -#endif - - // Clear software trigger - DMAC->SWTRIGCTRL.reg &= ~(1 << channel); - - // Configure default behaviors -#ifdef __SAMD51__ - DMAC->Channel[channel].CHPRILVL.bit.PRILVL = 0; - DMAC->Channel[channel].CHCTRLA.bit.TRIGSRC = peripheralTrigger; - DMAC->Channel[channel].CHCTRLA.bit.TRIGACT = triggerAction; - DMAC->Channel[channel].CHCTRLA.bit.BURSTLEN = - DMAC_CHCTRLA_BURSTLEN_SINGLE_Val; // Single-beat burst length -#else - DMAC->CHCTRLB.bit.LVL = 0; - DMAC->CHCTRLB.bit.TRIGSRC = peripheralTrigger; - DMAC->CHCTRLB.bit.TRIGACT = triggerAction; -#endif - - cpu_irq_leave_critical(); - - return DMA_STATUS_OK; -} - -void Adafruit_ZeroDMA::setPriority(dma_priority pri) const { -#ifdef __SAMD51__ - DMAC->Channel[channel].CHPRILVL.bit.PRILVL = pri; -#else - DMAC->CHCTRLB.bit.LVL = pri; -#endif -} - -// Deallocate DMA channel -// TODO: should this delete/deallocate the descriptor list? -ZeroDMAstatus Adafruit_ZeroDMA::free(void) { - - ZeroDMAstatus status = DMA_STATUS_OK; - - cpu_irq_enter_critical(); // jobStatus is volatile - - if(jobStatus == DMA_STATUS_BUSY) { - status = DMA_STATUS_BUSY; // Can't leave when busy - } else if((channel < DMAC_CH_NUM) && (_channelMask & (1 << channel))) { - // Valid in-use channel; release it - _channelMask &= ~(1 << channel); // Clear bit - if(!_channelMask) { // No more channels in use? -#ifdef __SAMD51__ - NVIC_DisableIRQ(DMAC_0_IRQn); // Disable DMA interrupt - DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA - MCLK->AHBMASK.bit.DMAC_ = 0; // Disable DMA clock -#else - NVIC_DisableIRQ(DMAC_IRQn); // Disable DMA interrupt - DMAC->CTRL.bit.DMAENABLE = 0; // Disable DMA - PM->APBBMASK.bit.DMAC_ = 0; // Disable DMA clocks - PM->AHBMASK.bit.DMAC_ = 0; -#endif - } - _dmaPtr[channel] = NULL; - channel = 0xFF; - } else { - status = DMA_STATUS_ERR_NOT_INITIALIZED; // Channel not in use - } - - cpu_irq_leave_critical(); - - return status; -} - -// Start DMA transfer job. Channel and descriptors should be allocated -// before calling this. -ZeroDMAstatus Adafruit_ZeroDMA::startJob(void) { - ZeroDMAstatus status = DMA_STATUS_OK; - - cpu_irq_enter_critical(); // Job status is volatile - - if(jobStatus == DMA_STATUS_BUSY) { - status = DMA_STATUS_BUSY; // Resource is busy - } else if(channel >= DMAC_CH_NUM) { - status = DMA_STATUS_ERR_NOT_INITIALIZED; // Channel not in use - } else if(!hasDescriptors || (_descriptor[channel].BTCNT.reg <= 0)) { - status = DMA_STATUS_ERR_INVALID_ARG; // Bad transfer size - } else { - uint8_t i, interruptMask = 0; - for(i=0; iChannel[channel].CHINTENSET.reg = - DMAC_CHINTENSET_MASK & interruptMask; - DMAC->Channel[channel].CHINTENCLR.reg = - DMAC_CHINTENCLR_MASK & ~interruptMask; - DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 1; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHINTENSET.reg = DMAC_CHINTENSET_MASK & interruptMask; - DMAC->CHINTENCLR.reg = DMAC_CHINTENCLR_MASK & ~interruptMask; - DMAC->CHCTRLA.bit.ENABLE = 1; // Enable the transfer channel -#endif - } - - cpu_irq_leave_critical(); - - return status; -} - -// Set and enable callback function for ZeroDMA object. This can be called -// before or after channel and/or descriptors are allocated, but needs -// to be called before job is started. -void Adafruit_ZeroDMA::setCallback( - void (*cb)(Adafruit_ZeroDMA *), dma_callback_type type) { - callback[type] = cb; -} - -// Suspend/resume don't quite do what I thought -- avoid using for now. -void Adafruit_ZeroDMA::suspend(void) const { - cpu_irq_enter_critical(); -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLB.reg |= DMAC_CHCTRLB_CMD_SUSPEND; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_SUSPEND; -#endif - cpu_irq_leave_critical(); -} - -#define MAX_JOB_RESUME_COUNT 10000 -void Adafruit_ZeroDMA::resume(void) { - cpu_irq_enter_critical(); // jobStatus is volatile - if(jobStatus == DMA_STATUS_SUSPEND) { - int count; - uint32_t bitMask = 1 << channel; -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLB.reg |= DMAC_CHCTRLB_CMD_RESUME; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHCTRLB.reg |= DMAC_CHCTRLB_CMD_RESUME; -#endif - - for(count = 0; (count < MAX_JOB_RESUME_COUNT) && - !(DMAC->BUSYCH.reg & bitMask); count++); - - jobStatus = (count < MAX_JOB_RESUME_COUNT) ? - DMA_STATUS_BUSY : DMA_STATUS_ERR_TIMEOUT; - } - cpu_irq_leave_critical(); -} - -// Abort is OK though. -void Adafruit_ZeroDMA::abort(void) { - if(channel <= DMAC_CH_NUM) { - cpu_irq_enter_critical(); -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLA.reg = 0; // Disable channel -#else - DMAC->CHID.bit.ID = channel; // Select channel - DMAC->CHCTRLA.reg = 0; // Disable -#endif - jobStatus = DMA_STATUS_ABORTED; - cpu_irq_leave_critical(); - } -} - -// Set DMA peripheral trigger. -// This can be done before or after channel is allocated. -void Adafruit_ZeroDMA::setTrigger(uint8_t trigger) { - peripheralTrigger = trigger; // Save value for allocate() - - // If channel already allocated, configure peripheral trigger - // (old lib required configure before alloc -- either way OK now) - if(channel < DMAC_CH_NUM) { - cpu_irq_enter_critical(); -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLA.bit.TRIGSRC = trigger; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHCTRLB.bit.TRIGSRC = trigger; -#endif - cpu_irq_leave_critical(); - } -} - -// Set DMA trigger action. -// This can be done before or after channel is allocated. -void Adafruit_ZeroDMA::setAction(dma_transfer_trigger_action action) { - triggerAction = action; // Save value for allocate() - - // If channel already allocated, configure trigger action - // (old lib required configure before alloc -- either way OK now) - if(channel < DMAC_CH_NUM) { - cpu_irq_enter_critical(); -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLA.bit.TRIGACT = action; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHCTRLB.bit.TRIGACT = action; -#endif - cpu_irq_leave_critical(); - } -} - -// Issue software trigger. Channel must be allocated & descriptors added! -void Adafruit_ZeroDMA::trigger(void) const { - if((channel <= DMAC_CH_NUM) & hasDescriptors) { - DMAC->SWTRIGCTRL.reg |= (1 << channel); - } -} - -// Returns true if DMA transfer in progress. -bool Adafruit_ZeroDMA::isActive(void) const { - return _writeback[channel].BTCTRL.bit.VALID; -} - -// DMA DESCRIPTOR FUNCTIONS ------------------------------------------------ - -// Allocates a new DMA descriptor (if needed) and appends it to the -// channel's descriptor list. Returns pointer to DmacDescriptor, -// or NULL on various errors. You'll want to keep the pointer for -// later if you need to modify or free the descriptor. -// Channel must be allocated first! -DmacDescriptor *Adafruit_ZeroDMA::addDescriptor( - void *src, - void *dst, - uint32_t count, - dma_beat_size size, - bool srcInc, - bool dstInc, - uint32_t stepSize, - bool stepSel) { - - // Channel must be allocated first - if(channel >= DMAC_CH_NUM) return NULL; - - // Can't do while job's busy - if(jobStatus == DMA_STATUS_BUSY) return NULL; - - DmacDescriptor *desc; - - // Scan descriptor list to find last entry. If an entry's - // DESCADDR value is 0, that's the end of the list and it's - // currently un-looped. If the DESCADDR value is the same - // as the first entry, that's the end of the list and it's - // looped. Either way, set the last entry's DESCADDR value - // to the new descriptor, and the descriptor's own DESCADDR - // will be set later either to 0 or the list head. - if(hasDescriptors) { - // DMA descriptors must be 128-bit (16 byte) aligned. - // memalign() is considered 'obsolete' but it's replacements - // (aligned_alloc() or posix_memalign()) are not currently - // available in the version of ARM GCC in use, but this is, - // so here we are. - if(!(desc = (DmacDescriptor *)memalign(16, sizeof(DmacDescriptor)))) { - return NULL; - } - DmacDescriptor *prev = &_descriptor[channel]; - while(prev->DESCADDR.reg && - (prev->DESCADDR.reg != (uint32_t)&_descriptor[channel])) { - prev = (DmacDescriptor *)prev->DESCADDR.reg; - } - prev->DESCADDR.reg = (uint32_t)desc; - } else { - desc = &_descriptor[channel]; - } - hasDescriptors = true; - - uint8_t bytesPerBeat; // Beat transfer size IN BYTES - switch(size) { - default: bytesPerBeat = 1; break; - case DMA_BEAT_SIZE_HWORD: bytesPerBeat = 2; break; - case DMA_BEAT_SIZE_WORD: bytesPerBeat = 4; break; - } - - desc->BTCTRL.bit.VALID = true; - desc->BTCTRL.bit.EVOSEL = DMA_EVENT_OUTPUT_DISABLE; - desc->BTCTRL.bit.BLOCKACT = DMA_BLOCK_ACTION_NOACT; - desc->BTCTRL.bit.BEATSIZE = size; - desc->BTCTRL.bit.SRCINC = srcInc; - desc->BTCTRL.bit.DSTINC = dstInc; - desc->BTCTRL.bit.STEPSEL = stepSel; - desc->BTCTRL.bit.STEPSIZE = stepSize; - desc->BTCNT.reg = count; - desc->SRCADDR.reg = (uint32_t)src; - - if(srcInc) { - if(stepSel) { - desc->SRCADDR.reg += bytesPerBeat * count * (1 << stepSize); - } else { - desc->SRCADDR.reg += bytesPerBeat * count; - } - } - - desc->DSTADDR.reg = (uint32_t)dst; - - if(dstInc) { - if(!stepSel) { - desc->DSTADDR.reg += bytesPerBeat * count * (1 << stepSize); - } else { - desc->DSTADDR.reg += bytesPerBeat * count; - } - } - - desc->DESCADDR.reg = loopFlag ? (uint32_t)&_descriptor[channel] : 0; - - return desc; -} - -// Modify DMA descriptor with a new source address, destination address & -// block transfer count. All other attributes (including increment enables, -// etc.) are unchanged. Mostly for changing the data being pushed to a -// peripheral (DAC, SPI, whatev.) -void Adafruit_ZeroDMA::changeDescriptor(DmacDescriptor *desc, - void *src, void *dst, uint32_t count) { - - uint8_t bytesPerBeat; // Beat transfer size IN BYTES - switch(desc->BTCTRL.bit.BEATSIZE) { - default: bytesPerBeat = 1; break; - case DMA_BEAT_SIZE_HWORD: bytesPerBeat = 2; break; - case DMA_BEAT_SIZE_WORD: bytesPerBeat = 4; break; - } - - if(count) desc->BTCNT.reg = count; - - if(src) { - desc->SRCADDR.reg = (uint32_t)src; - if(desc->BTCTRL.bit.SRCINC) { - if(desc->BTCTRL.bit.STEPSEL) { - desc->SRCADDR.reg += desc->BTCNT.reg * - bytesPerBeat * (1 << desc->BTCTRL.bit.STEPSIZE); - } else { - desc->SRCADDR.reg += desc->BTCNT.reg * bytesPerBeat; - } - } - } - - if(dst) { - desc->DSTADDR.reg = (uint32_t)dst; - if(desc->BTCTRL.bit.DSTINC) { - if(!desc->BTCTRL.bit.STEPSEL) { - desc->DSTADDR.reg += desc->BTCNT.reg * - bytesPerBeat * (1 << desc->BTCTRL.bit.STEPSIZE); - } else { - desc->DSTADDR.reg += desc->BTCNT.reg * bytesPerBeat; - } - } - } - -// I think this code is here by accident -- disabling for now. -#if 0 - cpu_irq_enter_critical(); - jobStatus = DMA_STATUS_OK; -#ifdef __SAMD51__ - DMAC->Channel[channel].CHCTRLA.bit.ENABLE = 1; -#else - DMAC->CHID.bit.ID = channel; - DMAC->CHCTRLA.reg |= DMAC_CHCTRLA_ENABLE; -#endif - cpu_irq_leave_critical(); -#endif -} - -// TODO: delete descriptor, delete whole descriptor chain - -// Select whether channel's descriptor list should repeat or not. -// This can be done before or after channel & any descriptors are allocated. -void Adafruit_ZeroDMA::loop(boolean flag) { - // The loop selection is 'sticky' -- that is, you can enable or - // disable looping before a descriptor list is built, or after - // the fact. This requires some extra steps in the library code - // but avoids a must-do-in-X-order constraint on user. - loopFlag = flag; - - if(hasDescriptors) { // Descriptor list already started? - // Scan descriptor list to find last entry. If an entry's - // DESCADDR value is 0, that's the end of the list and it's - // currently un-looped. If the DESCADDR value is the same - // as the first entry, that's the end of the list and it's - // already looped. - DmacDescriptor *desc = &_descriptor[channel]; - while(desc->DESCADDR.reg && - (desc->DESCADDR.reg != (uint32_t)&_descriptor[channel])) { - desc = (DmacDescriptor *)desc->DESCADDR.reg; - } - // Loop or unloop descriptor list as appropriate - desc->DESCADDR.reg = loopFlag ? (uint32_t)&_descriptor[channel] : 0; - } -} - -// MISCELLANY -------------------------------------------------------------- - -void Adafruit_ZeroDMA::printStatus(ZeroDMAstatus s) const { - if(s == DMA_STATUS_JOBSTATUS) s = jobStatus; - Serial.print("Status: "); - switch(s) { - case DMA_STATUS_OK: - Serial.println("OK"); - break; - case DMA_STATUS_ERR_NOT_FOUND: - Serial.println("NOT FOUND"); - break; - case DMA_STATUS_ERR_NOT_INITIALIZED: - Serial.println("NOT INITIALIZED"); - break; - case DMA_STATUS_ERR_INVALID_ARG: - Serial.println("INVALID ARGUMENT"); - break; - case DMA_STATUS_ERR_IO: - Serial.println("IO ERROR"); - break; - case DMA_STATUS_ERR_TIMEOUT: - Serial.println("TIMEOUT"); - break; - case DMA_STATUS_BUSY: - Serial.println("BUSY"); - break; - case DMA_STATUS_SUSPEND: - Serial.println("SUSPENDED"); - break; - case DMA_STATUS_ABORTED: - Serial.println("ABORTED"); - break; - default: - Serial.print("Unknown 0x"); - Serial.println((int)s); - break; - } -} diff --git a/libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.h b/libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.h deleted file mode 100644 index fc8461993..000000000 --- a/libraries/Adafruit_ZeroDMA/Adafruit_ZeroDMA.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef _ADAFRUIT_ZERODMA_H_ -#define _ADAFRUIT_ZERODMA_H_ - -#include "Arduino.h" -#include "utility/dma.h" - -// Status codes returned by some DMA functions and/or held in -// a channel's jobStatus variable. -enum ZeroDMAstatus { - DMA_STATUS_OK = 0, - DMA_STATUS_ERR_NOT_FOUND, - DMA_STATUS_ERR_NOT_INITIALIZED, - DMA_STATUS_ERR_INVALID_ARG, - DMA_STATUS_ERR_IO, - DMA_STATUS_ERR_TIMEOUT, - DMA_STATUS_BUSY, - DMA_STATUS_SUSPEND, - DMA_STATUS_ABORTED, - DMA_STATUS_JOBSTATUS = -1 // For printStatus() function -}; - -class Adafruit_ZeroDMA { - public: - Adafruit_ZeroDMA(void); - - // DMA channel functions - ZeroDMAstatus allocate(void), // Allocates DMA channel - startJob(void), - free(void); // Deallocates DMA channel - void trigger(void) const, - setTrigger(uint8_t trigger), - setAction(dma_transfer_trigger_action action), - setCallback(void (*callback)(Adafruit_ZeroDMA *) = NULL, - dma_callback_type type = DMA_CALLBACK_TRANSFER_DONE), - loop(boolean flag), - suspend(void) const, - resume(void), - abort(void), - setPriority(dma_priority pri) const, - printStatus(ZeroDMAstatus s = DMA_STATUS_JOBSTATUS) const; - uint8_t getChannel(void) const { return channel; } - - // DMA descriptor functions - DmacDescriptor *addDescriptor(void *src, void *dst, uint32_t count = 0, - dma_beat_size size = DMA_BEAT_SIZE_BYTE, - bool srcInc = true, bool dstInc = true, - uint32_t stepSize = DMA_ADDRESS_INCREMENT_STEP_SIZE_1, - bool stepSel = DMA_STEPSEL_DST); - void changeDescriptor(DmacDescriptor *d, void *src = NULL, - void *dst = NULL, uint32_t count = 0); - bool isActive(void) const; - - void _IRQhandler(uint8_t flags); // DO NOT TOUCH - - - protected: - uint8_t channel; - volatile enum ZeroDMAstatus jobStatus; - bool hasDescriptors; - bool loopFlag; - uint8_t peripheralTrigger; - dma_transfer_trigger_action triggerAction; - void (*callback[DMA_CALLBACK_N])(Adafruit_ZeroDMA *); -}; - -#endif // _ADAFRUIT_ZERODMA_H_ diff --git a/libraries/Adafruit_ZeroDMA/LICENSE b/libraries/Adafruit_ZeroDMA/LICENSE deleted file mode 100644 index ee356f7b7..000000000 --- a/libraries/Adafruit_ZeroDMA/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2016 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. - diff --git a/libraries/Adafruit_ZeroDMA/README.md b/libraries/Adafruit_ZeroDMA/README.md deleted file mode 100644 index cbc5441cc..000000000 --- a/libraries/Adafruit_ZeroDMA/README.md +++ /dev/null @@ -1,6 +0,0 @@ -# Adafruit_ZeroDMA -DMA helper/wrapped for ATSAMD21 such as Arduino Zero & Feather M0 - -Current version of this library no longer requires Adafruit_ASFcore as a prerequisite. However...IT BREAKS COMPATIBILITY WITH PRIOR VERSIONS. Function names, calling sequence and return types/values have changed. See examples! - -Item(s) in 'utility' directory are much pared-down derivatives of Atmel ASFcore 3 files. Please keep their original copyright and license intact when editing. diff --git a/libraries/Adafruit_ZeroDMA/examples/zerodma_memcpy/zerodma_memcpy.ino b/libraries/Adafruit_ZeroDMA/examples/zerodma_memcpy/zerodma_memcpy.ino deleted file mode 100644 index 5a48a6b56..000000000 --- a/libraries/Adafruit_ZeroDMA/examples/zerodma_memcpy/zerodma_memcpy.ino +++ /dev/null @@ -1,95 +0,0 @@ -// Simple ZeroDMA example -- an equivalent to the memcpy() function. -// Decause it uses DMA, unlike memcpy(), your code could be doing other -// things simultaneously while the copy operation runs. - -#include -#include "utility/dma.h" - -Adafruit_ZeroDMA myDMA; -ZeroDMAstatus stat; // DMA status codes returned by some functions - -// The memory we'll be moving: -#define DATA_LENGTH 1024 -uint8_t source_memory[DATA_LENGTH], - destination_memory[DATA_LENGTH]; - -volatile bool transfer_is_done = false; // Done yet? - -// Callback for end-of-DMA-transfer -void dma_callback(Adafruit_ZeroDMA *dma) { - (void)dma; // avoid compiler warning about unused function parameter - transfer_is_done = true; -} - -void setup() { - uint32_t t; - pinMode(LED_BUILTIN, OUTPUT); // Onboard LED can be used for precise - digitalWrite(LED_BUILTIN, LOW); // benchmarking with an oscilloscope - Serial.begin(115200); - while(!Serial); // Wait for Serial monitor before continuing - - Serial.println("DMA test: memory copy"); - - Serial.print("Allocating DMA channel..."); - stat = myDMA.allocate(); - myDMA.printStatus(stat); - - Serial.println("Setting up transfer"); - myDMA.addDescriptor(source_memory, destination_memory, DATA_LENGTH); - - Serial.println("Adding callback"); - // register_callback() can optionally take a second argument - // (callback type), default is DMA_CALLBACK_TRANSFER_DONE - myDMA.setCallback(dma_callback); - - // Fill the source buffer with incrementing bytes, dest buf with 0's - for(uint32_t i=0; i -#include -#include "utility/dma.h" - -Adafruit_ZeroDMA myDMA; -ZeroDMAstatus stat; // DMA status codes returned by some functions - -// The memory we'll be issuing to SPI: -#define DATA_LENGTH 2048 -uint8_t source_memory[DATA_LENGTH]; - -volatile bool transfer_is_done = false; // Done yet? - -// Callback for end-of-DMA-transfer -void dma_callback(Adafruit_ZeroDMA *dma) { - (void)dma; // avoid compiler warning about unused parameter - transfer_is_done = true; -} - -void setup() { - uint32_t t; - pinMode(LED_BUILTIN, OUTPUT); // Onboard LED can be used for precise - digitalWrite(LED_BUILTIN, LOW); // benchmarking with an oscilloscope - Serial.begin(115200); - while(!Serial); // Wait for Serial monitor before continuing - - Serial.println("DMA test: SPI data out"); - - SPI.begin(); - - Serial.println("Configuring DMA trigger"); -#ifdef __SAMD51__ - // SERCOM2 is the 'native' SPI SERCOM on Metro M4 - myDMA.setTrigger(SERCOM2_DMAC_ID_TX); -#else - // SERCOM4 is the 'native' SPI SERCOM on most M0 boards - myDMA.setTrigger(SERCOM4_DMAC_ID_TX); -#endif - myDMA.setAction(DMA_TRIGGER_ACTON_BEAT); - - Serial.print("Allocating DMA channel..."); - stat = myDMA.allocate(); - myDMA.printStatus(stat); - - Serial.println("Setting up transfer"); - myDMA.addDescriptor( - source_memory, // move data from here -#ifdef __SAMD51__ - (void *)(&SERCOM2->SPI.DATA.reg), // to here (M4) -#else - (void *)(&SERCOM4->SPI.DATA.reg), // to here (M0) -#endif - DATA_LENGTH, // this many... - DMA_BEAT_SIZE_BYTE, // bytes/hword/words - true, // increment source addr? - false); // increment dest addr? - - Serial.println("Adding callback"); - // register_callback() can optionally take a second argument - // (callback type), default is DMA_CALLBACK_TRANSFER_DONE - myDMA.setCallback(dma_callback); - - // Fill the source buffer with incrementing bytes - for(uint32_t i=0; i -#include -#include "utility/dma.h" -#include "wiring_private.h" // pinPeripheral() function - -// Declare our own SPI peripheral 'mySPI' on pins 11/12/13: -// (Do not call this SPI1; Arduino Zero and Metro M0 already -// have an SPI1 (the EDBG interface) and it won't compile.) -SPIClass mySPI( - &sercom1, // -> Sercom peripheral - 34, // MISO pin (also digital pin 12) - 37, // SCK pin (also digital pin 13) - 35, // MOSI pin (also digital pin 11) - SPI_PAD_0_SCK_1, // TX pad (MOSI, SCK pads) - SERCOM_RX_PAD_3); // RX pad (MISO pad) - -Adafruit_ZeroDMA myDMA; -ZeroDMAstatus stat; // DMA status codes returned by some functions - -// Data we'll issue to mySPI. There are TWO buffers; one being -// filled with new data while the other's being transmitted in -// the background. -#define DATA_LENGTH 512 -uint8_t source_memory[2][DATA_LENGTH], - buffer_being_filled = 0, // Index of 'filling' buffer - buffer_value = 0; // Value of fill - -volatile bool transfer_is_done = true; // Done yet? - -// Callback for end-of-DMA-transfer -void dma_callback(Adafruit_ZeroDMA *dma) { - (void)dma; // avoid compiler warning about unused parameter - transfer_is_done = true; -} - -DmacDescriptor *desc; // DMA descriptor address (so we can change contents) - -void setup() { - Serial.begin(115200); - while(!Serial); // Wait for Serial monitor before continuing - - Serial.println("DMA test: SPI data out"); - - mySPI.begin(); - // Assign pins 11, 12, 13 to SERCOM functionality - pinPeripheral(11, PIO_SERCOM); - pinPeripheral(12, PIO_SERCOM); - pinPeripheral(13, PIO_SERCOM); - - // Configure DMA for SERCOM1 (our 'mySPI' port on 11/12/13) - Serial.println("Configuring DMA trigger"); - myDMA.setTrigger(SERCOM1_DMAC_ID_TX); - myDMA.setAction(DMA_TRIGGER_ACTON_BEAT); - - Serial.print("Allocating DMA channel..."); - stat = myDMA.allocate(); - myDMA.printStatus(stat); - - desc = myDMA.addDescriptor( - source_memory[buffer_being_filled], // move data from here - (void *)(&SERCOM1->SPI.DATA.reg), // to here - DATA_LENGTH, // this many... - DMA_BEAT_SIZE_BYTE, // bytes/hword/words - true, // increment source addr? - false); // increment dest addr? - - Serial.println("Adding callback"); - // register_callback() can optionally take a second argument - // (callback type), default is DMA_CALLBACK_TRANSFER_DONE - myDMA.setCallback(dma_callback); -} - -void loop() { - // Fill buffer with new data. The other buffer might - // still be transmitting in the background via DMA. - memset(source_memory[buffer_being_filled], buffer_value, DATA_LENGTH); - - // Wait for prior transfer to complete before starting new one... - Serial.print("Waiting on prior transfer..."); - while(!transfer_is_done) Serial.write('.'); - mySPI.endTransaction(); - Serial.println("Done!"); - - // Modify the DMA descriptor using the newly-filled buffer as source... - myDMA.changeDescriptor(desc, // DMA descriptor address - source_memory[buffer_being_filled]); // New src; dst & count don't change - - // Begin new transfer... - Serial.println("Starting new transfer job"); - mySPI.beginTransaction(SPISettings(12000000, MSBFIRST, SPI_MODE0)); - transfer_is_done = false; // Reset 'done' flag - stat = myDMA.startJob(); // Go! - myDMA.printStatus(stat); - - // Switch buffer indices so the alternate buffer is filled/xfer'd - // on the next pass. - buffer_being_filled = 1 - buffer_being_filled; - buffer_value++; -} - diff --git a/libraries/Adafruit_ZeroDMA/library.properties b/libraries/Adafruit_ZeroDMA/library.properties deleted file mode 100644 index 32ce0a1c1..000000000 --- a/libraries/Adafruit_ZeroDMA/library.properties +++ /dev/null @@ -1,9 +0,0 @@ -name=Adafruit Zero DMA Library -version=1.0.4 -author=Adafruit -maintainer=Adafruit -sentence=DMA helper/wrapped for ATSAMD21 such as Arduino Zero & Feather M0 -paragraph=DMA helper/wrapped for ATSAMD21 such as Arduino Zero & Feather M0 -category=Signal Input/Output -url=https://github.com/adafruit/Adafruit_ZeroDMA -architectures=samd diff --git a/libraries/Adafruit_ZeroDMA/utility/dma.h b/libraries/Adafruit_ZeroDMA/utility/dma.h deleted file mode 100644 index bafd36ae2..000000000 --- a/libraries/Adafruit_ZeroDMA/utility/dma.h +++ /dev/null @@ -1,145 +0,0 @@ -/** - * \file - * - * \brief SAM Direct Memory Access 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 Atmel Support - */ -#ifndef DMA_H_INCLUDED -#define DMA_H_INCLUDED - -// THIS IS A PARED-DOWN VERSION OF DMA.H FROM ATMEL ASFCORE 3. -// Please keep original copyright and license intact! - -#ifdef __cplusplus -extern "C" { -#endif - -#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || defined(__DOXYGEN__) || defined(__SAMD51__) -#define FEATURE_DMA_CHANNEL_STANDBY -#endif - -enum dma_transfer_trigger_action{ -#ifdef __SAMD51__ - // SAMD51 has a 'burst' transfer which can be set to one - // beat to accomplish same idea as SAMD21's 'beat' transfer. - // Trigger name is ACTON_BEAT for backward compatibility. - DMA_TRIGGER_ACTON_BLOCK = DMAC_CHCTRLA_TRIGACT_BLOCK_Val, - DMA_TRIGGER_ACTON_BEAT = DMAC_CHCTRLA_TRIGACT_BURST_Val, - DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLA_TRIGACT_TRANSACTION_Val, -#else - DMA_TRIGGER_ACTON_BLOCK = DMAC_CHCTRLB_TRIGACT_BLOCK_Val, - DMA_TRIGGER_ACTON_BEAT = DMAC_CHCTRLB_TRIGACT_BEAT_Val, - DMA_TRIGGER_ACTON_TRANSACTION = DMAC_CHCTRLB_TRIGACT_TRANSACTION_Val, -#endif -}; - -enum dma_callback_type { - // First item here is for any 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, - DMA_CALLBACK_TRANSFER_DONE, - DMA_CALLBACK_CHANNEL_SUSPEND, - DMA_CALLBACK_N, // Number of available callbacks -}; - -enum dma_beat_size { - DMA_BEAT_SIZE_BYTE = 0, // 8-bit - DMA_BEAT_SIZE_HWORD, // 16-bit - DMA_BEAT_SIZE_WORD, // 32-bit -}; - -enum dma_event_output_selection { - DMA_EVENT_OUTPUT_DISABLE = 0, // Disable event generation - DMA_EVENT_OUTPUT_BLOCK, // Event strobe when block xfer complete - DMA_EVENT_OUTPUT_RESERVED, - DMA_EVENT_OUTPUT_BEAT, // Event strobe when beat xfer complete -}; - -enum dma_block_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, -}; - -// DMA step selection. This bit determines whether the step size setting -// is applied to source or destination address. -enum dma_step_selection { - DMA_STEPSEL_DST = 0, - DMA_STEPSEL_SRC, -}; - -// 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 { - DMA_ADDRESS_INCREMENT_STEP_SIZE_1 = 0, // beat size * 1 - DMA_ADDRESS_INCREMENT_STEP_SIZE_2, // beat size * 2 - DMA_ADDRESS_INCREMENT_STEP_SIZE_4, // beat size * 4 - DMA_ADDRESS_INCREMENT_STEP_SIZE_8, // etc... - DMA_ADDRESS_INCREMENT_STEP_SIZE_16, - DMA_ADDRESS_INCREMENT_STEP_SIZE_32, - DMA_ADDRESS_INCREMENT_STEP_SIZE_64, - DMA_ADDRESS_INCREMENT_STEP_SIZE_128, -}; - -// higher numbers are higher priority -enum dma_priority { - DMA_PRIORITY_0, // lowest (default) - DMA_PRIORITY_1, - DMA_PRIORITY_2, - DMA_PRIORITY_3, // highest -}; - -#ifdef __cplusplus -} -#endif - -#endif // DMA_H_INCLUDED diff --git a/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp b/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp index a83f7f050..e39ab43e3 100644 --- a/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp +++ b/libraries/SAMD_AnalogCorrection/src/SAMD_AnalogCorrection.cpp @@ -19,6 +19,11 @@ #include "SAMD_AnalogCorrection.h" +#ifdef USE_TINYUSB +// For Serial when selecting TinyUSB +#include +#endif + void analogReadCorrection (int offset, uint16_t gain) { Adc *adc; diff --git a/libraries/SPI/SPI.cpp b/libraries/SPI/SPI.cpp index 48a7b99b9..0393752d7 100644 --- a/libraries/SPI/SPI.cpp +++ b/libraries/SPI/SPI.cpp @@ -22,6 +22,11 @@ #include #include +#ifdef USE_TINYUSB +// For Serial when selecting TinyUSB +#include +#endif + #define SPI_IMODE_NONE 0 #define SPI_IMODE_EXTINT 1 #define SPI_IMODE_GLOBAL 2 diff --git a/libraries/Wire/Wire.cpp b/libraries/Wire/Wire.cpp index ec3634133..da9732c59 100644 --- a/libraries/Wire/Wire.cpp +++ b/libraries/Wire/Wire.cpp @@ -24,6 +24,11 @@ extern "C" { #include #include +#ifdef USE_TINYUSB +// For Serial when selecting TinyUSB +#include +#endif + #include "Wire.h" TwoWire::TwoWire(SERCOM * s, uint8_t pinSDA, uint8_t pinSCL) diff --git a/platform.txt b/platform.txt index 0848a8db0..c1028a794 100644 --- a/platform.txt +++ b/platform.txt @@ -20,7 +20,7 @@ # https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification name=Adafruit SAMD (32-bits ARM Cortex-M0+ and Cortex-M4) Boards -version=1.7.1 +version=1.7.2 # Compile variables # -----------------