Compare commits

..

No commits in common. "master" and "pb-spi" have entirely different histories.

183 changed files with 940 additions and 11832 deletions

View file

@ -1,63 +0,0 @@
name: Build
on: [pull_request, push]
jobs:
build:
strategy:
fail-fast: false
matrix:
arduino-platform: ['metro_m0', 'hallowing', 'circuitplayground_m0',
'metro_m4', 'pybadge_m4', 'pygamer_m4', 'hallowing_m4', 'pyportal_m4', 'pyportal_m4_titano']
runs-on: ubuntu-latest
steps:
- name: Setup Python
uses: actions/setup-python@v1
with:
python-version: '3.x'
- name: Checkout code
uses: actions/checkout@v2
- name: Checkout submodules
shell: bash
run: |
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive
- name: Install Arduino CLI and Tools
run: |
# make all our directories we need for files and libraries
mkdir $HOME/.arduino15
mkdir $HOME/.arduino15/packages
mkdir $HOME/Arduino
mkdir $HOME/Arduino/libraries
curl -fsSL https://raw.githubusercontent.com/arduino/arduino-cli/master/install.sh | sh
echo "::add-path::$GITHUB_WORKSPACE/bin"
- name: Install BSP and Libraries
env:
BSP_URL: https://adafruit.github.io/arduino-board-index/package_adafruit_index.json
BSP_PATH: .arduino15/packages/adafruit/hardware/samd
LIB_DEPS: FlashStorage SD
run: |
arduino-cli config init
arduino-cli core update-index
arduino-cli core update-index --additional-urls $BSP_URL
arduino-cli core install arduino:samd --additional-urls $BSP_URL
arduino-cli core install adafruit:samd --additional-urls $BSP_URL
# Replace release BSP with our code
BSP_VERSION=`eval ls $HOME/$BSP_PATH`
rm -r $HOME/$BSP_PATH/*
ln -s $GITHUB_WORKSPACE $HOME/$BSP_PATH/$BSP_VERSION
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

3
.gitmodules vendored
View file

@ -1,3 +0,0 @@
[submodule "cores/arduino/TinyUSB/Adafruit_TinyUSB_ArduinoCore"]
path = cores/arduino/TinyUSB/Adafruit_TinyUSB_ArduinoCore
url = https://github.com/adafruit/Adafruit_TinyUSB_ArduinoCore.git

View file

@ -1,7 +1,5 @@
# Arduino Core for SAMD21 and SAMD51 CPU
[![Build Status](https://github.com/adafruit/ArduinoCore-samd/workflows/Build/badge.svg)](https://github.com/adafruit/ArduinoCore-samd/actions)
This repository contains the source code and configuration files of the Arduino Core
for Atmel's SAMD21 and SAMD51 processor (used on the Arduino/Genuino Zero, MKR1000 and MKRZero boards).

1129
boards.txt

File diff suppressed because it is too large Load diff

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -218,11 +218,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -222,11 +222,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -226,11 +226,7 @@ void I2S_Handler ( void );
* \brief Configuration of the Cortex-M0+ Processor and Core Peripherals
*/
#if defined(LITTLE_ENDIAN) && (LITTLE_ENDIAN != 1)
#error "Little Endian is already defined, but to different value than expected?!"
#else
#define LITTLE_ENDIAN 1
#endif
#define LITTLE_ENDIAN 1
#define __CM0PLUS_REV 1 /*!< Core revision r0p1 */
#define __MPU_PRESENT 0 /*!< MPU present or not */
#define __NVIC_PRIO_BITS 2 /*!< Number of bits used for Priority Levels */

View file

@ -97,33 +97,8 @@ void loop( void ) ;
#undef abs
#endif // abs
#ifdef __cplusplus
template<class T, class L>
auto min(const T& a, const L& b) -> decltype((b < a) ? b : a)
{
return (b < a) ? b : a;
}
template<class T, class L>
auto max(const T& a, const L& b) -> decltype((b < a) ? b : a)
{
return (a < b) ? b : a;
}
#else
#ifndef min
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#endif
#ifndef max
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#endif
#endif
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
@ -149,14 +124,10 @@ void loop( void ) ;
#define digitalPinToInterrupt(P) ( P )
#endif
// USB
#ifdef USE_TINYUSB
#include "Adafruit_TinyUSB_Core.h"
#else
// USB Device
#include "USB/USBDesc.h"
#include "USB/USBCore.h"
#include "USB/USBAPI.h"
#include "USB/USB_host.h"
#endif
#endif // Arduino_h

View file

@ -29,7 +29,7 @@
// location from which to read.
#ifndef SERIAL_BUFFER_SIZE
#define SERIAL_BUFFER_SIZE 350
#define SERIAL_BUFFER_SIZE 256
#endif
template <int N>

View file

@ -537,18 +537,8 @@ bool SERCOM::startTransmissionWIRE(uint8_t address, SercomWireReadWriteFlag flag
// 7-bits address + 1-bits R/W
address = (address << 0x1ul) | flag;
// If another master owns the bus or the last bus owner has not properly
// sent a stop, return failure early. This will prevent some misbehaved
// devices from deadlocking here at the cost of the caller being responsible
// for retrying the failed transmission. See SercomWireBusState for the
// possible bus states.
if(!isBusOwnerWIRE())
{
if( isBusBusyWIRE() || (isArbLostWIRE() && !isBusIdleWIRE()) || isBusUnknownWIRE() )
{
return false;
}
}
// Wait idle or owner bus mode
while ( !isBusIdleWIRE() && !isBusOwnerWIRE() );
// Send start and address
sercom->I2CM.ADDR.bit.ADDR = address;
@ -644,21 +634,6 @@ bool SERCOM::isBusOwnerWIRE( void )
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_OWNER_STATE;
}
bool SERCOM::isBusUnknownWIRE( void )
{
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_UNKNOWN_STATE;
}
bool SERCOM::isArbLostWIRE( void )
{
return sercom->I2CM.STATUS.bit.ARBLOST == 1;
}
bool SERCOM::isBusBusyWIRE( void )
{
return sercom->I2CM.STATUS.bit.BUSSTATE == WIRE_BUSY_STATE;
}
bool SERCOM::isDataReadyWIRE( void )
{
return sercom->I2CS.INTFLAG.bit.DRDY;

View file

@ -225,9 +225,6 @@ class SERCOM
bool isSlaveWIRE( void ) ;
bool isBusIdleWIRE( void ) ;
bool isBusOwnerWIRE( void ) ;
bool isBusUnknownWIRE( void ) ;
bool isArbLostWIRE( void );
bool isBusBusyWIRE( void );
bool isDataReadyWIRE( void ) ;
bool isStopDetectedWIRE( void ) ;
bool isRestartDetectedWIRE( void ) ;
@ -248,7 +245,7 @@ class SERCOM
uint32_t getFreqRef(void) { return freqRef; };
#else
// The equivalent SAMD21 dummy functions...
void setClockSource(int8_t idx, SercomClockSource src, bool core) { (void)idx; (void)src; (void)core; };
void setClockSource(int8_t idx, SercomClockSource src, bool core) { };
SercomClockSource getClockSource(void) { return SERCOM_CLOCK_SOURCE_FCPU; };
uint32_t getFreqRef(void) { return F_CPU; };
#endif

View file

@ -35,7 +35,6 @@ int Stream::timedRead()
do {
c = read();
if (c >= 0) return c;
yield(); // running TinyUSB task
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}
@ -48,7 +47,6 @@ int Stream::timedPeek()
do {
c = peek();
if (c >= 0) return c;
yield(); // running TinyUSB task
} while(millis() - _startMillis < _timeout);
return -1; // -1 indicates timeout
}

@ -1 +0,0 @@
Subproject commit e7b892095f2bb5d8bef6a748238369bdd268ed5e

View file

@ -1,195 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019, hathach for Adafruit
*
* 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.
*/
#ifdef USE_TINYUSB
#include "Arduino.h"
#include "Adafruit_TinyUSB_Core.h"
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
//--------------------------------------------------------------------+
// Forward USB interrupt events to TinyUSB IRQ Handler
//--------------------------------------------------------------------+
extern "C"
{
#if defined(__SAMD51__)
void USB_0_Handler (void) { tud_int_handler(0); }
void USB_1_Handler (void) { tud_int_handler(0); }
void USB_2_Handler (void) { tud_int_handler(0); }
void USB_3_Handler (void) { tud_int_handler(0); }
#else
void USB_Handler(void) { tud_int_handler(0); }
#endif
} // extern C
//--------------------------------------------------------------------+
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
//--------------------------------------------------------------------+
static void usb_hardware_init(void);
#if CFG_TUSB_DEBUG
extern "C" int serial1_printf(const char *__restrict format, ...)
{
char buf[PRINTF_BUF];
va_list ap;
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
Serial1.write(buf);
va_end(ap);
}
#endif
//--------------------------------------------------------------------+
// Core Init & Touch1200
//--------------------------------------------------------------------+
void Adafruit_TinyUSB_Core_init(void)
{
#if CFG_TUSB_DEBUG
Serial1.begin(115200);
serial1_printf("TinyUSB debugging with Serial1\n");
#endif
Serial.setStringDescriptor("TinyUSB Serial");
USBDevice.addInterface(Serial);
USBDevice.setID(USB_VID, USB_PID);
USBDevice.begin();
usb_hardware_init();
// Init tinyusb stack
tusb_init();
}
void Adafruit_TinyUSB_Core_touch1200(void)
{
initiateReset(250);
}
//--------------------------------------------------------------------+
// Adafruit_USBD_Device platform dependent
//--------------------------------------------------------------------+
uint8_t Adafruit_USBD_Device::getSerialDescriptor(uint16_t* serial_str)
{
enum { SERIAL_BYTE_LEN = 16 };
#ifdef __SAMD51__
uint32_t* id_addresses[4] = {(uint32_t *) 0x008061FC, (uint32_t *) 0x00806010,
(uint32_t *) 0x00806014, (uint32_t *) 0x00806018};
#else // samd21
uint32_t* id_addresses[4] = {(uint32_t *) 0x0080A00C, (uint32_t *) 0x0080A040,
(uint32_t *) 0x0080A044, (uint32_t *) 0x0080A048};
#endif
uint8_t raw_id[SERIAL_BYTE_LEN];
for (int i=0; i<4; i++) {
for (int k=0; k<4; k++) {
raw_id[4 * i + (3 - k)] = (*(id_addresses[i]) >> k * 8) & 0xff;
}
}
static const char nibble_to_hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
for (unsigned int i = 0; i < sizeof(raw_id); i++) {
for (int j = 0; j < 2; j++) {
uint8_t nibble = (raw_id[i] >> (j * 4)) & 0xf;
// Strings are UTF-16-LE encoded.
serial_str[i * 2 + (1 - j)] = nibble_to_hex[nibble];
}
}
return sizeof(raw_id)*2;
}
//--------------------------------------------------------------------+
// Helpers
//--------------------------------------------------------------------+
// Init usb hardware when starting up. Softdevice is not enabled yet
static void usb_hardware_init(void)
{
#ifdef PIN_LED_TXL
// txLEDPulse = 0;
pinMode(PIN_LED_TXL, OUTPUT);
digitalWrite(PIN_LED_TXL, HIGH);
#endif
#ifdef PIN_LED_RXL
// rxLEDPulse = 0;
pinMode(PIN_LED_RXL, OUTPUT);
digitalWrite(PIN_LED_RXL, HIGH);
#endif
/* Enable USB clock */
#if defined(__SAMD51__)
MCLK->APBBMASK.reg |= MCLK_APBBMASK_USB;
MCLK->AHBMASK.reg |= MCLK_AHBMASK_USB;
// Set up the USB DP/DN pins
PORT->Group[0].PINCFG[PIN_PA24H_USB_DM].bit.PMUXEN = 1;
PORT->Group[0].PMUX[PIN_PA24H_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24H_USB_DM & 0x01u)));
PORT->Group[0].PMUX[PIN_PA24H_USB_DM/2].reg |= MUX_PA24H_USB_DM << (4 * (PIN_PA24H_USB_DM & 0x01u));
PORT->Group[0].PINCFG[PIN_PA25H_USB_DP].bit.PMUXEN = 1;
PORT->Group[0].PMUX[PIN_PA25H_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25H_USB_DP & 0x01u)));
PORT->Group[0].PMUX[PIN_PA25H_USB_DP/2].reg |= MUX_PA25H_USB_DP << (4 * (PIN_PA25H_USB_DP & 0x01u));
GCLK->PCHCTRL[USB_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK1_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
NVIC_SetPriority(USB_0_IRQn, 0UL);
NVIC_SetPriority(USB_1_IRQn, 0UL);
NVIC_SetPriority(USB_2_IRQn, 0UL);
NVIC_SetPriority(USB_3_IRQn, 0UL);
#else
PM->APBBMASK.reg |= PM_APBBMASK_USB;
// Set up the USB DP/DN pins
PORT->Group[0].PINCFG[PIN_PA24G_USB_DM].bit.PMUXEN = 1;
PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg &= ~(0xF << (4 * (PIN_PA24G_USB_DM & 0x01u)));
PORT->Group[0].PMUX[PIN_PA24G_USB_DM/2].reg |= MUX_PA24G_USB_DM << (4 * (PIN_PA24G_USB_DM & 0x01u));
PORT->Group[0].PINCFG[PIN_PA25G_USB_DP].bit.PMUXEN = 1;
PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg &= ~(0xF << (4 * (PIN_PA25G_USB_DP & 0x01u)));
PORT->Group[0].PMUX[PIN_PA25G_USB_DP/2].reg |= MUX_PA25G_USB_DP << (4 * (PIN_PA25G_USB_DP & 0x01u));
// Put Generic Clock Generator 0 as source for Generic Clock Multiplexer 6 (USB reference)
GCLK->CLKCTRL.reg = GCLK_CLKCTRL_ID(6) | // Generic Clock Multiplexer 6
GCLK_CLKCTRL_GEN_GCLK0 | // Generic Clock Generator 0 is source
GCLK_CLKCTRL_CLKEN;
while (GCLK->STATUS.bit.SYNCBUSY)
;
NVIC_SetPriority((IRQn_Type) USB_IRQn, 0UL);
#endif
}
#endif // USE_TINYUSB

View file

@ -1,93 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2018, hathach for Adafruit
*
* 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 _TUSB_CONFIG_H_
#define _TUSB_CONFIG_H_
#ifdef __cplusplus
extern "C" {
#endif
//--------------------------------------------------------------------
// COMMON CONFIGURATION
//--------------------------------------------------------------------
#ifdef __SAMD51__
#define CFG_TUSB_MCU OPT_MCU_SAMD51
#else
#define CFG_TUSB_MCU OPT_MCU_SAMD21
#endif
#ifdef USE_TINYUSB
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
#else
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_NONE
#endif
#define CFG_TUSB_OS OPT_OS_NONE
#define CFG_TUSB_DEBUG 0
#if CFG_TUSB_DEBUG
#define tu_printf serial1_printf
extern int serial1_printf(const char *__restrict __format, ...);
#endif
#define CFG_TUSB_MEM_SECTION
#define CFG_TUSB_MEM_ALIGN TU_ATTR_ALIGNED(4)
//--------------------------------------------------------------------
// DEVICE CONFIGURATION
//--------------------------------------------------------------------
#define CFG_TUD_ENDOINT0_SIZE 64
//------------- CLASS -------------//
#define CFG_TUD_CDC 1
#define CFG_TUD_MSC 1
#define CFG_TUD_HID 1
#define CFG_TUD_MIDI 1
#define CFG_TUD_VENDOR 1
// CDC FIFO size of TX and RX
#define CFG_TUD_CDC_RX_BUFSIZE 256
#define CFG_TUD_CDC_TX_BUFSIZE 256
// MSC Buffer size of Device Mass storage
#define CFG_TUD_MSC_BUFSIZE 512
// HID buffer size Should be sufficient to hold ID (if any) + Data
#define CFG_TUD_HID_BUFSIZE 64
// MIDI FIFO size of TX and RX
#define CFG_TUD_MIDI_RX_BUFSIZE 128
#define CFG_TUD_MIDI_TX_BUFSIZE 128
// Vendor FIFO size of TX and RX
#define CFG_TUD_VENDOR_RX_BUFSIZE 64
#define CFG_TUD_VENDOR_TX_BUFSIZE 64
#ifdef __cplusplus
}
#endif
#endif /* _TUSB_CONFIG_H_ */

View file

@ -20,6 +20,12 @@
#include "Tone.h"
#include "variant.h"
#if defined(__SAMD51__)
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
#else
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
#endif
uint32_t toneMaxFrequency = F_CPU / 2;
uint32_t lastOutputPin = 0xFFFFFFFF;
@ -31,24 +37,22 @@ volatile bool toneIsActive = false;
volatile bool firstTimeRunning = false;
#if defined(__SAMD51__)
#define TONE_TC TC0
#define TONE_TC_IRQn TC0_IRQn
#define TONE_TC_GCLK_ID TC0_GCLK_ID
#define Tone_Handler TC0_Handler
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.SYNCBUSY.bit.ENABLE);
#define TONE_TC TC3
#define TONE_TC_IRQn TC3_IRQn
#define TONE_TC_GCLK_ID TC3_GCLK_ID
#else
#define TONE_TC TC5
#define TONE_TC_IRQn TC5_IRQn
#define Tone_Handler TC5_Handler
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
#define TONE_TC TC5
#define TONE_TC_IRQn TC5_IRQn
#endif
#define TONE_TC_TOP 0xFFFF
#define TONE_TC_CHANNEL 0
#if defined(__SAMD51__)
void TC2_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
#else
void TC5_Handler (void) __attribute__ ((weak, alias("Tone_Handler")));
#endif
static inline void resetTC (Tc* TCx)
{
// Disable TCx
@ -68,14 +72,6 @@ void toneAccurateClock (uint32_t accurateSystemCoreClockFrequency)
void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
// Avoid divide by zero error by calling 'noTone' instead
if (frequency == 0)
{
noTone(outputPin);
return;
}
// Configure interrupt request
NVIC_DisableIRQ(TONE_TC_IRQn);
NVIC_ClearPendingIRQ(TONE_TC_IRQn);
@ -84,16 +80,19 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
{
firstTimeRunning = true;
NVIC_SetPriority(TONE_TC_IRQn, 5);
NVIC_SetPriority(TONE_TC_IRQn, 0);
#if defined(__SAMD51__)
GCLK->PCHCTRL[TONE_TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
GCLK->PCHCTRL[TONE_TC_GCLK_ID].reg = GCLK_PCHCTRL_GEN_GCLK0_Val | (1 << GCLK_PCHCTRL_CHEN_Pos);
#else
// Enable GCLK for TC4 and TC5 (timer counter input clock)
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(GCM_TC4_TC5));
while (GCLK->STATUS.bit.SYNCBUSY);
#endif
}
//if it's a rest, set to 1Hz (below audio range)
frequency = (frequency > 0 ? frequency : 1);
if (toneIsActive && (outputPin != lastOutputPin))
noTone(lastOutputPin);
@ -180,19 +179,9 @@ void tone (uint32_t outputPin, uint32_t frequency, uint32_t duration)
void noTone (uint32_t outputPin)
{
/* 'tone' need to run at least once in order to enable GCLK for
* the timers used for the tone-functionality. If 'noTone' is called
* without ever calling 'tone' before then 'WAIT_TC16_REGS_SYNC(TCx)'
* will wait infinitely. The variable 'firstTimeRunning' is set the
* 1st time 'tone' is set so it can be used to detect wether or not
* 'tone' has been called before.
*/
if(firstTimeRunning)
{
resetTC(TONE_TC);
digitalWrite(outputPin, LOW);
toneIsActive = false;
}
resetTC(TONE_TC);
digitalWrite(outputPin, LOW);
toneIsActive = false;
}
#ifdef __cplusplus

View file

@ -16,8 +16,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#include <Arduino.h>
#include <Reset.h> // Needed for auto-reset with 1200bps port touch
@ -262,5 +260,3 @@ Serial_::operator bool()
Serial_ Serial(USBDevice);
#endif
#endif // USE_TINYUSB

View file

@ -17,8 +17,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#include "USBAPI.h"
#include "USBDesc.h"
#include "USBCore.h"
@ -115,6 +113,4 @@ PluggableUSB_::PluggableUSB_() : lastIf(CDC_ACM_INTERFACE + CDC_INTERFACE_COUNT)
}
#endif
#endif
#endif // USE_TINYUSB
#endif

View file

@ -5,7 +5,6 @@
* Author: deanm
*/
#ifndef USE_TINYUSB
#include "SAMD21_USBDevice.h"
@ -37,5 +36,3 @@ void USBDevice_SAMD21G18x::calibrate() {
usb.PADCAL.bit.TRANSP = pad_transp;
usb.PADCAL.bit.TRIM = pad_trim;
}
#endif // USE_TINYUSB

View file

@ -16,7 +16,7 @@
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#if defined(USBCON)
#include <Arduino.h>
@ -244,25 +244,26 @@ bool USBDeviceClass::sendDescriptor(USBSetup &setup)
}
else if (setup.wValueL == ISERIAL) {
#ifdef PLUGGABLE_USB_ENABLED
#ifdef __SAMD51__
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
#else // samd21
#if defined(__SAMD51__)
char name[ISERIAL_MAX_LEN];
PluggableUSB().getShortName(name);
return sendStringDescriptor((uint8_t*)name, setup.wLength);
#else
// from section 9.3.3 of the datasheet
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
#endif
char name[ISERIAL_MAX_LEN];
utox8(SERIAL_NUMBER_WORD_0, &name[0]);
utox8(SERIAL_NUMBER_WORD_1, &name[8]);
utox8(SERIAL_NUMBER_WORD_2, &name[16]);
utox8(SERIAL_NUMBER_WORD_3, &name[24]);
name[32] = '\0';
PluggableUSB().getShortName(&name[32]);
return sendStringDescriptor((uint8_t*)name, setup.wLength);
#endif
#endif
}
else {
@ -877,7 +878,6 @@ bool USBDeviceClass::handleStandardSetup(USBSetup &setup)
sendZlp(0);
return true;
}
return false;
case SET_ADDRESS:
setAddress(setup.wValueL);
@ -1039,4 +1039,3 @@ void USBDeviceClass::ISRHandler()
USBDeviceClass USBDevice;
#endif
#endif // USE_TINYUSB

View file

@ -17,7 +17,6 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef USE_TINYUSB
#include <stdio.h>
#include <stdint.h>
@ -554,5 +553,3 @@ uint32_t UHD_Pipe_Is_Transfer_Complete(uint32_t ul_pipe, uint32_t ul_token_type)
// }
#endif // HOST_DEFINED
#endif // USE_TINYUSB

View file

@ -250,9 +250,8 @@ void detachInterrupt(uint32_t pin)
* External Interrupt Controller NVIC Interrupt Handler
*/
#if defined(__SAMD51__)
void InterruptHandler(uint32_t unused_i)
void InterruptHandler(uint32_t i)
{
(void)unused_i;
// Calling the routine directly from -here- takes about 1us
// Depending on where you are in the list it will take longer

View file

@ -31,7 +31,7 @@ extern "C" {
#define FALLING 3
#define RISING 4
//#define DEFAULT 1
#define DEFAULT 1
#define EXTERNAL 0
typedef void (*voidFuncPtr)(void);

View file

@ -57,8 +57,6 @@ typedef enum _EAnalogChannel
ADC_Channel19=19,
DAC_Channel0,
DAC_Channel1,
ADC_Channel_Bandgap=0x1B,
ADC_Channel_PTAT=0x1C,
} EAnalogChannel ;
#if defined(__SAMD51__)
@ -101,16 +99,10 @@ typedef enum _ETCChannel
TCC0_CH3 = (0<<8)|(3),
TCC0_CH4 = (0<<8)|(4),
TCC0_CH5 = (0<<8)|(5),
TCC0_CH6 = (0<<8)|(6),
TCC0_CH7 = (0<<8)|(7),
TCC1_CH0 = (1<<8)|(0),
TCC1_CH1 = (1<<8)|(1),
TCC1_CH2 = (1<<8)|(2),
TCC1_CH3 = (1<<8)|(3),
TCC1_CH4 = (1<<8)|(4),
TCC1_CH5 = (1<<8)|(5),
TCC1_CH6 = (1<<8)|(6),
TCC1_CH7 = (1<<8)|(7),
TCC2_CH0 = (2<<8)|(0),
TCC2_CH1 = (2<<8)|(1),
TCC2_CH2 = (2<<8)|(2),
@ -130,10 +122,6 @@ typedef enum _ETCChannel
TC4_CH1 = (9<<8)|(1),
TC5_CH0 = (10<<8)|(0),
TC5_CH1 = (10<<8)|(1),
TC6_CH0 = (11<<8)|(0),
TC6_CH1 = (11<<8)|(1),
TC7_CH0 = (12<<8)|(0),
TC7_CH1 = (12<<8)|(1),
} ETCChannel ;
#elif defined(__SAMD51P19A__) || defined(__SAMD51P20A__)
@ -210,12 +198,6 @@ typedef enum _ETCChannel
TC4_CH1 = (4<<8)|(1),
TC5_CH0 = (5<<8)|(0),
TC5_CH1 = (5<<8)|(1),
#if defined (__SAMD21J18A__)
TC6_CH0 = (6<<8)|(0),
TC6_CH1 = (6<<8)|(1),
TC7_CH0 = (7<<8)|(0),
TC7_CH1 = (7<<8)|(1),
#endif // __SAMD21J18A__
} ETCChannel ;
// Definitions for PWM channels

View file

@ -25,14 +25,8 @@
#ifndef _IO_H_
#define _IO_H_
#ifdef __SAMD51__
#define RAMSTART (HSRAM_ADDR)
#define RAMSIZE (HSRAM_SIZE)
#else
#define RAMSTART (HMCRAMC0_ADDR)
#define RAMSIZE (HMCRAMC0_SIZE)
#endif
#define RAMSTART (HMCRAMC0_ADDR)
#define RAMSIZE (HMCRAMC0_SIZE)
#define RAMEND (RAMSTART + RAMSIZE - 1)
#endif

View file

@ -28,7 +28,6 @@
static void __empty() {
// Empty
}
void yield(void) __attribute__ ((weak, alias("__empty")));
/**

View file

@ -39,10 +39,7 @@ int main( void )
initVariant();
delay(1);
#if defined(USE_TINYUSB)
Adafruit_TinyUSB_Core_init();
#elif defined(USBCON)
#if defined(USBCON)
USBDevice.init();
USBDevice.attach();
#endif
@ -52,21 +49,8 @@ int main( void )
for (;;)
{
loop();
yield(); // yield run usb background task
if (serialEventRun) serialEventRun();
}
return 0;
}
#if defined(USE_TINYUSB)
// run TinyUSB background task when yield()
extern "C" void yield(void)
{
tud_task();
tud_cdc_write_flush();
}
#endif

View file

@ -164,19 +164,18 @@ void arm_float_to_q12_20(float *pIn, q31_t * pOut, uint32_t numSamples)
uint32_t arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
{
uint32_t i;
int32_t diff;
uint32_t diffCrnt = 0;
int32_t diff, diffCrnt = 0;
uint32_t maxDiff = 0;
for (i = 0; i < numSamples; i++)
{
diff = pIn[i] - pOut[i];
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
diff = pIn[i] - pOut[i];
diffCrnt = (diff > 0) ? diff : -diff;
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
}
return(maxDiff);
@ -193,19 +192,18 @@ uint32_t arm_compare_fixed_q15(q15_t *pIn, q15_t * pOut, uint32_t numSamples)
uint32_t arm_compare_fixed_q31(q31_t *pIn, q31_t * pOut, uint32_t numSamples)
{
uint32_t i;
int32_t diff;
uint32_t diffCrnt = 0;
int32_t diff, diffCrnt = 0;
uint32_t maxDiff = 0;
for (i = 0; i < numSamples; i++)
{
diff = pIn[i] - pOut[i];
diffCrnt = (uint32_t)( (diff > 0) ? diff : -diff );
diff = pIn[i] - pOut[i];
diffCrnt = (diff > 0) ? diff : -diff;
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
if(diffCrnt > maxDiff)
{
maxDiff = diffCrnt;
}
}
return(maxDiff);

View file

@ -41,10 +41,10 @@ uint32_t pulseIn(uint32_t pin, uint32_t state, uint32_t timeout)
* No assembly required, no conversion of loop counts to times (which is
* worrisome in the presence of cache.)
*/
const volatile uint32_t *port = &(PORT->Group[p.ulPort].IN.reg);
volatile uint32_t *port = &(PORT->Group[p.ulPort].IN.reg);
uint32_t usCallStart; // microseconds at start of call, for timeout.
uint32_t usPulseStart; // microseconds at start of measured pulse.
usCallStart = usPulseStart = micros();
usCallStart = micros();
// wait for any previous pulse to end
while ((*port & bit) == stateMask) {
if (micros() - usCallStart > timeout)

View file

@ -261,47 +261,6 @@ void SystemInit( void )
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
/* ----------------------------------------------------------------------------------------------
* 5) Load AC factory calibration values
*/
uint32_t bias0 = (*((uint32_t *)AC_FUSES_BIAS0_ADDR) & AC_FUSES_BIAS0_Msk) >> AC_FUSES_BIAS0_Pos;
AC->CALIB.reg = AC_CALIB_BIAS0(bias0);
/* ----------------------------------------------------------------------------------------------
* 6) Load ADC factory calibration values
*/
// ADC0 Bias Calibration
uint32_t biascomp = (*((uint32_t *)ADC0_FUSES_BIASCOMP_ADDR) & ADC0_FUSES_BIASCOMP_Msk) >> ADC0_FUSES_BIASCOMP_Pos;
uint32_t biasr2r = (*((uint32_t *)ADC0_FUSES_BIASR2R_ADDR) & ADC0_FUSES_BIASR2R_Msk) >> ADC0_FUSES_BIASR2R_Pos;
uint32_t biasref = (*((uint32_t *)ADC0_FUSES_BIASREFBUF_ADDR) & ADC0_FUSES_BIASREFBUF_Msk) >> ADC0_FUSES_BIASREFBUF_Pos;
ADC0->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref)
| ADC_CALIB_BIASR2R(biasr2r)
| ADC_CALIB_BIASCOMP(biascomp);
// ADC1 Bias Calibration
biascomp = (*((uint32_t *)ADC1_FUSES_BIASCOMP_ADDR) & ADC1_FUSES_BIASCOMP_Msk) >> ADC1_FUSES_BIASCOMP_Pos;
biasr2r = (*((uint32_t *)ADC1_FUSES_BIASR2R_ADDR) & ADC1_FUSES_BIASR2R_Msk) >> ADC1_FUSES_BIASR2R_Pos;
biasref = (*((uint32_t *)ADC1_FUSES_BIASREFBUF_ADDR) & ADC1_FUSES_BIASREFBUF_Msk) >> ADC1_FUSES_BIASREFBUF_Pos;
ADC1->CALIB.reg = ADC_CALIB_BIASREFBUF(biasref)
| ADC_CALIB_BIASR2R(biasr2r)
| ADC_CALIB_BIASCOMP(biascomp);
/* ----------------------------------------------------------------------------------------------
* 7) Load USB factory calibration values
*/
//USB Calibration
uint32_t usbtransn = (*((uint32_t *)USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
uint32_t usbtransp = (*((uint32_t *)USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
uint32_t usbtrim = (*((uint32_t *)USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
USB->DEVICE.PADCAL.reg = USB_PADCAL_TRIM(usbtrim)
| USB_PADCAL_TRANSN(usbtransn)
| USB_PADCAL_TRANSP(usbtransp);
//*************** END SAMD51 *************************//
#else
@ -577,3 +536,4 @@ void SystemInit( void )
NVMCTRL->CTRLB.bit.MANW = 1;
#endif
}

View file

@ -92,7 +92,7 @@ void init( void )
PM->APBCMASK.reg |= PM_APBCMASK_SERCOM0 | PM_APBCMASK_SERCOM1 | PM_APBCMASK_SERCOM2 | PM_APBCMASK_SERCOM3 | PM_APBCMASK_SERCOM4 | PM_APBCMASK_SERCOM5 ;
// Clock TC/TCC for Pulse and Analog
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 | PM_APBCMASK_TC6 | PM_APBCMASK_TC7;
PM->APBCMASK.reg |= PM_APBCMASK_TCC0 | PM_APBCMASK_TCC1 | PM_APBCMASK_TCC2 | PM_APBCMASK_TC3 | PM_APBCMASK_TC4 | PM_APBCMASK_TC5 ;
// ATSAMR, for example, doesn't have a DAC
#ifdef PM_APBCMASK_DAC

View file

@ -32,7 +32,7 @@ static int _writeResolution = 12;
static int _dacResolution = 12;
#else
static int _writeResolution = 8;
//static int _dacResolution = 10;
static int _dacResolution = 10;
#endif
@ -280,8 +280,8 @@ uint32_t analogRead(uint32_t pin)
#ifdef DAC
#if defined(__SAMD51__)
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
if (pin == A0 || pin == A1) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
if(dacEnabled[channel]){
dacEnabled[channel] = false;
@ -298,7 +298,7 @@ uint32_t analogRead(uint32_t pin)
while (DAC->SYNCBUSY.bit.ENABLE);
#else
if (pin == PIN_DAC0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
if (pin == A0) { // Disable DAC, if analogWrite(A0,dval) used previously the DAC is enabled
syncDAC();
DAC->CTRLA.bit.ENABLE = 0x00; // Disable DAC
@ -410,9 +410,9 @@ void analogWrite(uint32_t pin, uint32_t value)
{
// DAC handling code
#if defined(__SAMD51__)
if (pin == PIN_DAC0 || pin == PIN_DAC1) { // 2 DACs on A0 (PA02) and A1 (PA05)
if (pin == PIN_A0 || pin == PIN_A1) { // 2 DACs on A0 (PA02) and A1 (PA05)
#else
if (pin == PIN_DAC0) { // Only 1 DAC on A0 (PA02)
if (pin == PIN_A0) { // Only 1 DAC on A0 (PA02)
#endif
#if defined(__SAMD51__)
@ -420,7 +420,7 @@ void analogWrite(uint32_t pin, uint32_t value)
value = mapResolution(value, _writeResolution, _dacResolution);
uint8_t channel = (pin == PIN_DAC0 ? 0 : 1);
uint8_t channel = (pin == PIN_A0 ? 0 : 1);
pinPeripheral(pin, PIO_ANALOG);

View file

@ -30,43 +30,39 @@ void pinMode( uint32_t ulPin, uint32_t ulMode )
return ;
}
EPortType port = g_APinDescription[ulPin].ulPort;
uint32_t pin = g_APinDescription[ulPin].ulPin;
uint32_t pinMask = (1ul << pin);
// Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
switch ( ulMode )
{
case INPUT:
// Set pin to input mode
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
PORT->Group[port].DIRCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
break ;
case INPUT_PULLUP:
// Set pin to input mode with pull-up resistor enabled
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
PORT->Group[port].DIRCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.7 Data Output Value Set')
PORT->Group[port].OUTSET.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].OUTSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
break ;
case INPUT_PULLDOWN:
// Set pin to input mode with pull-down resistor enabled
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
PORT->Group[port].DIRCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN|PORT_PINCFG_PULLEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
// Enable pull level (cf '22.6.3.2 Input Configuration' and '22.8.6 Data Output Value Clear')
PORT->Group[port].OUTCLR.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].OUTCLR.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
break ;
case OUTPUT:
// enable input, to support reading back values, with pullups disabled
PORT->Group[port].PINCFG[pin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg=(uint8_t)(PORT_PINCFG_INEN) ;
// Set pin to output mode
PORT->Group[port].DIRSET.reg = pinMask ;
PORT->Group[g_APinDescription[ulPin].ulPort].DIRSET.reg = (uint32_t)(1<<g_APinDescription[ulPin].ulPin) ;
break ;
default:

View file

@ -1,124 +0,0 @@
import os
import glob
import sys
import subprocess
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' ]
)
args = parser.parse_args()
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
def build_examples(variant: str):
global args, exit_status, success_count, fail_count, skip_count, build_format, build_separator
print('\n')
print(build_separator)
print('| {:^76} |'.format('Board ' + variant))
print(build_separator)
print((build_format + '| {:6} |').format('Library', 'Example', 'Result', 'Time'))
print(build_separator)
fqbn = "{}{}".format(FQBN_PREFIX, variant)
for sketch in glob.iglob('libraries/**/*.ino', recursive=True):
start_time = time.monotonic()
# Skip if contains: ".board.test.skip" or ".all.test.skip"
# 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 "
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)))
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 "
fail_count += 1
else:
success = "\033[32msucceeded\033[0m"
success_count += 1
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))
if success != "\033[33mskipped\033[0m ":
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_time = time.monotonic()
for board in args.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_separator)
sys.exit(exit_status)

View file

@ -17,7 +17,6 @@ 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;
}

View file

@ -19,7 +19,6 @@ 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;
}

View file

@ -33,7 +33,6 @@ 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;
}

View file

@ -1 +0,0 @@
// fake empty header file to make Arduino IDE happy

View file

@ -1,12 +0,0 @@
#include <arm_math.h>
arm_rfft_fast_instance_f32 plan;
void setup() {
arm_rfft_fast_init_f32(&plan, 256);
}
void loop() {
float in[256] = { 0 }, out[256] = { 0 };
arm_rfft_fast_f32(&plan, in, out, 0);
}

View file

@ -46,16 +46,7 @@ SPIClass::SPIClass(SERCOM *p_sercom, uint8_t uc_pinMISO, uint8_t uc_pinSCK, uint
void SPIClass::begin()
{
if(!initialized) {
interruptMode = SPI_IMODE_NONE;
interruptSave = 0;
interruptMask = 0;
initialized = true;
}
if(!use_dma) {
dmaAllocate();
}
init();
// PIO init
pinPeripheral(_uc_pinMiso, g_APinDescription[_uc_pinMiso].ulPinType);
@ -65,6 +56,16 @@ void SPIClass::begin()
config(DEFAULT_SPI_SETTINGS);
}
void SPIClass::init()
{
if (initialized)
return;
interruptMode = SPI_IMODE_NONE;
interruptSave = 0;
interruptMask = 0;
initialized = true;
}
void SPIClass::config(SPISettings settings)
{
_p_sercom->disableSPI();
@ -79,7 +80,6 @@ void SPIClass::end()
{
_p_sercom->resetSPI();
initialized = false;
// Add DMA deallocation here
}
#ifndef interruptsStatus
@ -235,231 +235,157 @@ void SPIClass::transfer(void *buf, size_t count)
}
}
// DMA-based SPI transfer() function ---------------------------------------
// IMPORTANT: references to 65535 throughout the DMA code are INTENTIONAL.
// DO NOT try to 'fix' by changing to 65536, or large transfers will fail!
// The BTCNT value of a DMA descriptor is an unsigned 16-bit value with a
// max of 65535. Larger transfers are handled by linked descriptors.
// Pointer to SPIClass object, one per DMA channel. This allows the
// DMA callback (which has to exist outside the class context) to have
// a reference back to the originating SPIClass object.
// Pointer to SPIClass object, one per DMA channel.
static SPIClass *spiPtr[DMAC_CH_NUM] = { 0 }; // Legit inits list to NULL
void SPIClass::dmaCallback(Adafruit_ZeroDMA *dma) {
// dmaCallback() receives an Adafruit_ZeroDMA object. From this we can get
// a channel number (0 to DMAC_CH_NUM-1, always unique per ZeroDMA object),
// then locate the originating SPIClass object using array lookup, setting
// the dma_busy element 'false' to indicate end of transfer. Doesn't matter
// if it's a read or write transfer...both channels get pointers to it.
// the dma_busy element 'false' to indicate end of transfer.
spiPtr[dma->getChannel()]->dma_busy = false;
}
// For read-only and read+write transfers, a callback is assigned only
// to the read channel to indicate end-of-transfer, and the write channel's
// callback is assigned to this nonsense function (for reasons I'm not
// entirely sure of, setting the callback to NULL doesn't work).
static void dmaDoNothingCallback(Adafruit_ZeroDMA *dma) { (void)dma; }
// This could've gone in begin(), but for the sake of organization...
void SPIClass::dmaAllocate(void) {
// In order to support fully non-blocking SPI transfers, DMA descriptor
// lists must be created for the input and/or output data. Rather than
// do this dynamically with every transfer, the lists are allocated once
// on SPI init. Maximum list size is finite and knowable -- transfers to
// or from RAM or from flash memory will never exceed the corresponding
// memory size (if they do, you have bigger problems). Descriptors
// aren't large and there's usually only a handful to a dozen, so this
// isn't an excessive burden in exchange for big non-blocking transfers.
uint32_t maxWriteBytes = FLASH_SIZE; // Writes can't exceed all of flash
#if defined(__SAMD51__)
uint32_t maxReadBytes = HSRAM_SIZE; // Reads can't exceed all of RAM
#else
uint32_t maxReadBytes = HMCRAMC0_SIZE;
#endif
if(maxReadBytes > maxWriteBytes) { // I don't think any SAMD devices
maxWriteBytes = maxReadBytes; // have RAM > flash, but just in case
}
// VITAL to alloc read channel first, assigns it a higher DMA priority!
if(readChannel.allocate() == DMA_STATUS_OK) {
if(writeChannel.allocate() == DMA_STATUS_OK) {
// Both DMA channels (read and write) allocated successfully,
// set up transfer triggers and other basics...
// readChannel callback only needs to be set up once.
// Unlike the write callback which may get switched on or off,
// read callback stays put. In certain cases the read DMA job
// just isn't started and the callback is a non-issue then.
readChannel.setTrigger(getDMAC_ID_RX());
readChannel.setAction(DMA_TRIGGER_ACTON_BEAT);
readChannel.setCallback(dmaCallback);
spiPtr[readChannel.getChannel()] = this;
writeChannel.setTrigger(getDMAC_ID_TX());
writeChannel.setAction(DMA_TRIGGER_ACTON_BEAT);
spiPtr[writeChannel.getChannel()] = this;
// One descriptor per channel has already been allocated
// in Adafruit_ZeroDMA, this just gets pointers to them...
firstReadDescriptor = readChannel.addDescriptor(
(void *)getDataRegister(), // Source address (SPI data reg)
NULL, // Dest address (set later)
0, // Count (set later)
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
false, // Don't increment source address
true); // Increment dest address
firstWriteDescriptor = writeChannel.addDescriptor(
NULL, // Source address (set later)
(void *)getDataRegister(), // Dest (SPI data register)
0, // Count (set later)
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
true, // Increment source address
false); // Don't increment dest address
// This is the number of EXTRA descriptors beyond the first.
int numReadDescriptors = ((maxReadBytes + 65534) / 65535) - 1;
int numWriteDescriptors = ((maxWriteBytes + 65534) / 65535) - 1;
int totalDescriptors = numReadDescriptors + numWriteDescriptors;
if(totalDescriptors <= 0) { // Don't need extra descriptors,
use_dma = true; // channels are allocated, we're good.
} else { // Else allocate extra descriptor lists...
// Although DMA descriptors are technically a linked list, we just
// allocate a chunk all at once, and finesse the pointers later.
if((extraReadDescriptors = (DmacDescriptor *)malloc(
totalDescriptors * sizeof(DmacDescriptor)))) {
use_dma = true; // Everything allocated successfully
extraWriteDescriptors = &extraReadDescriptors[numReadDescriptors];
// Initialize descriptors (copy from first ones)
for(int i=0; i<numReadDescriptors; i++) {
memcpy(&extraReadDescriptors[i], firstReadDescriptor,
sizeof(DmacDescriptor));
}
for(int i=0; i<numWriteDescriptors; i++) {
memcpy(&extraWriteDescriptors[i], firstWriteDescriptor,
sizeof(DmacDescriptor));
}
} // end malloc
} // end extra descriptor check
if(use_dma) { // If everything allocated successfully,
return; // then we're done here.
} // Otherwise clean up interim allocations...
writeChannel.free();
} // end writeChannel alloc
readChannel.free();
} // end readChannel alloc
// NOT FATAL if channel or descriptor allocation fails.
// transfer() function will fall back on a manual byte-by-byte loop.
}
void SPIClass::transfer(const void *txbuf, void *rxbuf, size_t count,
void SPIClass::transfer(const void* txbuf, void* rxbuf, size_t count,
bool block) {
if((!txbuf && !rxbuf) || !count) { // Validate inputs
return;
}
// OK to assume now that txbuf and/or rxbuf are non-NULL, an if/else is
// often sufficient, don't need else-ifs for everything buffer related.
uint8_t *txbuf8 = (uint8_t *)txbuf; // Must cast to byte size
uint8_t *rxbuf8 = (uint8_t *)rxbuf; // for pointer math
if(use_dma) { // DMA-BASED TRANSFER YAY ----------------------------------
static const uint8_t dum = 0xFF; // Dummy byte for read-only xfers
// Set up DMA descriptor lists -----------------------------------------
DmacDescriptor *rDesc = firstReadDescriptor;
DmacDescriptor *wDesc = firstWriteDescriptor;
int descIdx = 0; // Index into extra descriptor lists
while(count) { // Counts down to end of transfer
uint32_t bytesThisDescriptor = count;
if(bytesThisDescriptor > 65535) { // Limit each descriptor
bytesThisDescriptor = 65535; // to 65535 (not 65536) bytes
}
rDesc->BTCNT.reg = wDesc->BTCNT.reg = bytesThisDescriptor;
if(rxbuf) { // Read-only or read+write
// Auto-inc addresses in DMA descriptors must point to END of data.
// Buf pointers would advance at end of loop anyway, do it now...
rxbuf8 += bytesThisDescriptor;
rDesc->DSTADDR.reg = (uint32_t)rxbuf8;
}
if(txbuf) { // Write-only or read+write
txbuf8 += bytesThisDescriptor; // Same as above
wDesc->SRCADDR.reg = (uint32_t)txbuf8;
wDesc->BTCTRL.bit.SRCINC = 1; // Increment source pointer
} else { // Read-only requires dummy write
wDesc->SRCADDR.reg = (uint32_t)&dum;
wDesc->BTCTRL.bit.SRCINC = 0; // Don't increment source pointer
}
count -= bytesThisDescriptor;
if(count) { // Still more data?
// Link to next descriptors. Extra descriptors are IN ADDITION
// to first, so it's safe and correct that descIdx starts at 0.
rDesc->DESCADDR.reg = (uint32_t)&extraReadDescriptors[descIdx];
wDesc->DESCADDR.reg = (uint32_t)&extraWriteDescriptors[descIdx];
rDesc = &extraReadDescriptors[descIdx]; // Update pointers to
wDesc = &extraWriteDescriptors[descIdx]; // next descriptors
descIdx++;
// A write-only transfer doesn't use the read descriptor list, but
// it's quicker to build it (full of nonsense) anyway than to check.
} else { // No more data, end descriptor linked lists
rDesc->DESCADDR.reg = wDesc->DESCADDR.reg = 0;
}
}
// Set up DMA transfer job(s) ------------------------------------------
if(rxbuf) { // Read+write or read-only
// End-of-read callback is already set up, disable write CB, start job
writeChannel.setCallback(dmaDoNothingCallback);
readChannel.startJob();
} else { // Write-only, use end-of-write callback
writeChannel.setCallback(dmaCallback);
}
// Run DMA jobs, blocking if requested ---------------------------------
dma_busy = true;
writeChannel.startJob(); // All xfers, even read-only, need write job.
if(block) { // If blocking transfer requested,
while(dma_busy); // wait for job to finish
}
} else { // NON-DMA FALLBACK ---------------------------------------------
if(txbuf8) {
if(rxbuf8) { // Write + read simultaneously
while(count--) {
*rxbuf8++ = _p_sercom->transferDataSPI(*txbuf8++);
// If receiving data and the RX DMA channel is not yet allocated...
if(rxbuf && (readChannel.getChannel() >= DMAC_CH_NUM)) {
if(readChannel.allocate() == DMA_STATUS_OK) {
readDescriptor =
readChannel.addDescriptor(
(void *)getDataRegister(), // Source address (SPI data reg)
NULL, // Dest address (set later)
0, // Count (set later)
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
false, // Don't increment source address
true); // Increment dest address
readChannel.setTrigger(getDMAC_ID_RX());
readChannel.setAction(DMA_TRIGGER_ACTON_BEAT);
spiPtr[readChannel.getChannel()] = this;
// Since all RX transfers involve a TX, a
// separate callback here is not necessary.
}
} else { // Write only
while(count--) {
(void)_p_sercom->transferDataSPI(*txbuf8++);
}
}
} else { // Read only
while(count--) {
*rxbuf8++ = _p_sercom->transferDataSPI(0xFF);
}
}
} // end non-DMA
// Unlike the rxbuf check above, where a RX DMA channel is allocated
// only if receiving data (and channel not previously alloc'd), the
// TX DMA channel is always needed, because even RX-only SPI requires
// writing dummy bytes to the peripheral.
if(writeChannel.getChannel() >= DMAC_CH_NUM) {
if(writeChannel.allocate() == DMA_STATUS_OK) {
writeDescriptor =
writeChannel.addDescriptor(
NULL, // Source address (set later)
(void *)getDataRegister(), // Dest (SPI data register)
0, // Count (set later)
DMA_BEAT_SIZE_BYTE, // Bytes/hwords/words
true, // Increment source address
false); // Don't increment dest address
writeChannel.setTrigger(getDMAC_ID_TX());
writeChannel.setAction(DMA_TRIGGER_ACTON_BEAT);
writeChannel.setCallback(dmaCallback);
spiPtr[writeChannel.getChannel()] = this;
}
}
if(writeDescriptor && (readDescriptor || !rxbuf)) {
static const uint8_t dum = 0xFF; // Dummy byte for read-only xfers
// Initialize read descriptor dest address to rxbuf
if(rxbuf) readDescriptor->DSTADDR.reg = (uint32_t)rxbuf;
// If reading only, set up writeDescriptor to issue dummy bytes
// (set SRCADDR to &dum and SRCINC to 0). Otherwise, set SRCADDR
// to txbuf and SRCINC to 1. Only needed once at start.
if(rxbuf && !txbuf) {
writeDescriptor->SRCADDR.reg = (uint32_t)&dum;
writeDescriptor->BTCTRL.bit.SRCINC = 0;
} else {
writeDescriptor->SRCADDR.reg = (uint32_t)txbuf;
writeDescriptor->BTCTRL.bit.SRCINC = 1;
}
while(count > 0) {
// Maximum bytes per DMA descriptor is 65,535 (NOT 65,536).
// We could set up a descriptor chain, but that gets more
// complex. For now, instead, break up long transfers into
// chunks of 65,535 bytes max...these transfers are all
// blocking, regardless of the "block" argument, except
// for the last one which will observe the background request.
// The fractional part is done first, so for any "partially
// blocking" transfers like these at least it's the largest
// single-descriptor transfer possible that occurs in the
// background, rather than the tail end.
int bytesThisPass;
bool blockThisPass;
if(count > 65535) { // Too big for 1 descriptor
blockThisPass = true;
bytesThisPass = count % 65535; // Fractional part
if(!bytesThisPass) bytesThisPass = 65535;
} else {
blockThisPass = block;
bytesThisPass = count;
}
// Issue 'bytesThisPass' bytes...
if(rxbuf) {
// Reading, or reading + writing.
// Set up read descriptor.
// Src address doesn't change, only dest & count.
// DMA needs address set to END of buffer, so
// increment the address now, before the transfer.
readDescriptor->DSTADDR.reg += bytesThisPass;
readDescriptor->BTCNT.reg = bytesThisPass;
// Start the RX job BEFORE the TX job!
// That's the whole secret sauce to the two-channel transfer.
// Nothing will actually happen until the write channel job
// is also started.
readChannel.startJob();
}
if(txbuf) {
// DMA needs address set to END of buffer, so
// increment the address now, before the transfer.
writeDescriptor->SRCADDR.reg += bytesThisPass;
}
writeDescriptor->BTCNT.reg = bytesThisPass;
dma_busy = true;
writeChannel.startJob();
count -= bytesThisPass;
if(blockThisPass) {
while(dma_busy);
}
}
} else {
// Non-DMA fallback.
uint8_t *txbuf8 = (uint8_t *)txbuf,
*rxbuf8 = (uint8_t *)rxbuf;
if(rxbuf8) {
if(txbuf8) {
// Writing and reading simultaneously
while(count--) {
*rxbuf8++ = _p_sercom->transferDataSPI(*txbuf8++);
}
} else {
// Reading only
while(count--) {
*rxbuf8++ = _p_sercom->transferDataSPI(0xFF);
}
}
} else if(txbuf) {
// Writing only
while(count--) {
(void)_p_sercom->transferDataSPI(*txbuf8++);
}
}
}
}
// Waits for a prior in-background DMA transfer to complete.
void SPIClass::waitForTransfer(void) {
while(dma_busy);
while(dma_busy);
}
// End DMA-based SPI transfer() code ---------------------------------------
void SPIClass::attachInterrupt() {
// Should be enableInterrupt()
}
@ -479,12 +405,8 @@ static const struct {
{ &SERCOM1->SPI.DATA.reg, SERCOM1_DMAC_ID_TX, SERCOM1_DMAC_ID_RX },
{ &SERCOM2->SPI.DATA.reg, SERCOM2_DMAC_ID_TX, SERCOM2_DMAC_ID_RX },
{ &SERCOM3->SPI.DATA.reg, SERCOM3_DMAC_ID_TX, SERCOM3_DMAC_ID_RX },
#if defined(SERCOM4)
{ &SERCOM4->SPI.DATA.reg, SERCOM4_DMAC_ID_TX, SERCOM4_DMAC_ID_RX },
#endif
#if defined(SERCOM5)
{ &SERCOM5->SPI.DATA.reg, SERCOM5_DMAC_ID_TX, SERCOM5_DMAC_ID_RX },
#endif
#if defined(SERCOM6)
{ &SERCOM6->SPI.DATA.reg, SERCOM6_DMAC_ID_TX, SERCOM6_DMAC_ID_RX },
#endif
@ -555,3 +477,4 @@ void SPIClass::setClockSource(SercomClockSource clk) {
#if SPI_INTERFACES_COUNT > 5
SPIClass SPI5(&PERIPH_SPI5, PIN_SPI5_MISO, PIN_SPI5_SCK, PIN_SPI5_MOSI, PAD_SPI5_TX, PAD_SPI5_RX);
#endif

View file

@ -52,11 +52,9 @@
// The datasheet specifies a typical SPI SCK period (tSCK) of 42 ns,
// see "Table 36-48. SPI Timing Characteristics and Requirements",
// which translates into a maximum SPI clock of 23.8 MHz.
// We'll permit use of 24 MHz SPI even though this is slightly out
// of spec. Given how clock dividers work, the next "sensible"
// threshold would be a substantial drop down to 12 MHz.
// Conservatively, the divider is set for a 12 MHz maximum SPI clock.
#if !defined(MAX_SPI)
#define MAX_SPI 24000000
#define MAX_SPI 12000000
#endif
#define SPI_MIN_CLOCK_DIVIDER (uint8_t)(1 + ((F_CPU - 1) / MAX_SPI))
#endif
@ -83,7 +81,7 @@ class SPISettings {
#if defined(__SAMD51__)
this->clockFreq = clock; // Clipping handled in SERCOM.cpp
#else
this->clockFreq = clock >= MAX_SPI ? MAX_SPI : clock;
this->clockFreq = (clock >= (MAX_SPI * 2 / SPI_MIN_CLOCK_DIVIDER) ? MAX_SPI * 2 / SPI_MIN_CLOCK_DIVIDER : clock);
#endif
this->bitOrder = (bitOrder == MSBFIRST ? MSB_FIRST : LSB_FIRST);
@ -149,10 +147,11 @@ class SPIClass {
#else
// On SAMD21, this compiles to nothing, so user code doesn't need to
// check and conditionally compile lines for different architectures.
void setClockSource(SercomClockSource clk) { (void)clk; };
void setClockSource(SercomClockSource clk) { };
#endif // end __SAMD51__
private:
void init();
void config(SPISettings settings);
SERCOM *_p_sercom;
@ -168,16 +167,12 @@ class SPIClass {
char interruptSave;
uint32_t interruptMask;
// transfer(txbuf, rxbuf, count, block) uses DMA when possible
Adafruit_ZeroDMA readChannel;
Adafruit_ZeroDMA writeChannel;
DmacDescriptor *firstReadDescriptor = NULL; // List entry point
DmacDescriptor *firstWriteDescriptor = NULL;
DmacDescriptor *extraReadDescriptors = NULL; // Add'l descriptors
DmacDescriptor *extraWriteDescriptors = NULL;
bool use_dma = false; // true on successful alloc
volatile bool dma_busy = false;
void dmaAllocate(void);
// transfer(txbuf, rxbuf, count, block) uses DMA if possible
Adafruit_ZeroDMA readChannel,
writeChannel;
DmacDescriptor *readDescriptor = NULL,
*writeDescriptor = NULL;
volatile bool dma_busy = false;
static void dmaCallback(Adafruit_ZeroDMA *dma);
};

View file

@ -1,25 +0,0 @@
= Servo Library for Arduino =
This library allows an Arduino board to control RC (hobby) servo motors.
For more information about this library please visit us at
http://www.arduino.cc/en/Reference/Servo
== License ==
Copyright (c) 2013 Arduino LLC. All right reserved.
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

View file

@ -1,27 +0,0 @@
/*
Controlling a servo position using a potentiometer (variable resistor)
by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>
modified on 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Knob
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int potpin = 0; // analog pin used to connect the potentiometer
int val; // variable to read the value from the analog pin
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
val = analogRead(potpin); // reads the value of the potentiometer (value between 0 and 1023)
val = map(val, 0, 1023, 0, 180); // scale it to use it with the servo (value between 0 and 180)
myservo.write(val); // sets the servo position according to the scaled value
delay(15); // waits for the servo to get there
}

View file

@ -1,32 +0,0 @@
/* Sweep
by BARRAGAN <http://barraganstudio.com>
This example code is in the public domain.
modified 8 Nov 2013
by Scott Fitzgerald
http://www.arduino.cc/en/Tutorial/Sweep
*/
#include <Servo.h>
Servo myservo; // create servo object to control a servo
// twelve servo objects can be created on most boards
int pos = 0; // variable to store the servo position
void setup() {
myservo.attach(9); // attaches the servo on pin 9 to the servo object
}
void loop() {
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(15); // waits 15ms for the servo to reach the position
}
}

View file

@ -1,24 +0,0 @@
#######################################
# Syntax Coloring Map Servo
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
Servo KEYWORD1 Servo
#######################################
# Methods and Functions (KEYWORD2)
#######################################
attach KEYWORD2
detach KEYWORD2
write KEYWORD2
read KEYWORD2
attached KEYWORD2
writeMicroseconds KEYWORD2
readMicroseconds KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View file

@ -1,9 +0,0 @@
name=Servo
version=1.1.4
author=Michael Margolis, Arduino
maintainer=Arduino <info@arduino.cc>
sentence=Allows Arduino/Genuino boards to control a variety of servo motors.
paragraph=This library can control a great number of servos.<br />It makes careful use of timers: the library can control 12 servos using only 1 timer.<br />On the Arduino Due you can control up to 60 servos.<br />
category=Device Control
url=http://www.arduino.cc/en/Reference/Servo
architectures=avr,megaavr,sam,samd,nrf52,stm32f4

View file

@ -1,121 +0,0 @@
/*
Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
A servo is activated by creating an instance of the Servo class passing
the desired pin to the attach() method.
The servos are pulsed in the background using the value most recently
written using the write() method.
Note that analogWrite of PWM on pins associated with the timer are
disabled when the first servo is attached.
Timers are seized as needed in groups of 12 servos - 24 servos use two
timers, 48 servos will use four.
The sequence used to sieze timers is defined in timers.h
The methods are:
Servo - Class for manipulating servo motors connected to Arduino pins.
attach(pin ) - Attaches a servo motor to an i/o pin.
attach(pin, min, max ) - Attaches to a pin setting min and max values in microseconds
default min is 544, max is 2400
write() - Sets the servo angle in degrees. (invalid angle that is valid as pulse in microseconds is treated as microseconds)
writeMicroseconds() - Sets the servo pulse width in microseconds
read() - Gets the last written servo pulse width as an angle between 0 and 180.
readMicroseconds() - Gets the last written servo pulse width in microseconds. (was read_us() in first release)
attached() - Returns true if there is a servo attached.
detach() - Stops an attached servos from pulsing its i/o pin.
*/
#ifndef Servo_h
#define Servo_h
#include <inttypes.h>
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
// Architecture specific include
#if defined(ARDUINO_ARCH_AVR)
#include "avr/ServoTimers.h"
#elif defined(ARDUINO_ARCH_SAM)
#include "sam/ServoTimers.h"
#elif defined(ARDUINO_ARCH_SAMD)
#include "samd/ServoTimers.h"
#elif defined(ARDUINO_ARCH_STM32F4)
#include "stm32f4/ServoTimers.h"
#elif defined(ARDUINO_ARCH_NRF52)
#include "nrf52/ServoTimers.h"
#elif defined(ARDUINO_ARCH_MEGAAVR)
#include "megaavr/ServoTimers.h"
#else
#error "This library only supports boards with an AVR, SAM, SAMD, NRF52 or STM32F4 processor."
#endif
#define Servo_VERSION 2 // software version of this library
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
#define DEFAULT_PULSE_WIDTH 1500 // default pulse width when servo is attached
#define REFRESH_INTERVAL 20000 // minumim time to refresh servos in microseconds
#define SERVOS_PER_TIMER 12 // the maximum number of servos controlled by one timer
#define MAX_SERVOS (_Nbr_16timers * SERVOS_PER_TIMER)
#define INVALID_SERVO 255 // flag indicating an invalid servo index
#if !defined(ARDUINO_ARCH_STM32F4)
typedef struct {
uint8_t nbr :6 ; // a pin number from 0 to 63
uint8_t isActive :1 ; // true if this channel is enabled, pin not pulsed if false
} ServoPin_t ;
typedef struct {
ServoPin_t Pin;
volatile unsigned int ticks;
} servo_t;
class Servo
{
public:
Servo();
uint8_t attach(int pin); // attach the given pin to the next free channel, sets pinMode, returns channel number or 0 if failure
uint8_t attach(int pin, int min, int max); // as above but also sets min and max values for writes.
void detach();
void write(int value); // if value is < 200 its treated as an angle, otherwise as pulse width in microseconds
void writeMicroseconds(int value); // Write pulse width in microseconds
int read(); // returns current pulse width as an angle between 0 and 180 degrees
int readMicroseconds(); // returns current pulse width in microseconds for this servo (was read_us() in first release)
bool attached(); // return true if this servo is attached, otherwise false
private:
uint8_t servoIndex; // index into the channel data for this servo
int8_t min; // minimum is this value times 4 added to MIN_PULSE_WIDTH
int8_t max; // maximum is this value times 4 added to MAX_PULSE_WIDTH
};
#endif
#endif

View file

@ -1,318 +0,0 @@
/*
Servo.cpp - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_AVR)
#include <avr/interrupt.h>
#include <Arduino.h>
#include "Servo.h"
#define usToTicks(_us) (( clockCyclesPerMicrosecond()* _us) / 8) // converts microseconds to tick (assumes prescale of 8) // 12 Aug 2009
#define ticksToUs(_ticks) (( (unsigned)_ticks * 8)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays // 12 August 2009
//#define NBR_TIMERS (MAX_SERVOS / SERVOS_PER_TIMER)
static servo_t servos[MAX_SERVOS]; // static array of servo structures
static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
uint8_t ServoCount = 0; // the total number of attached servos
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
/************ static functions common to all instances ***********************/
static inline void handle_interrupts(timer16_Sequence_t timer, volatile uint16_t *TCNTn, volatile uint16_t* OCRnA)
{
if( Channel[timer] < 0 )
*TCNTn = 0; // channel set to -1 indicated that refresh interval completed so reset the timer
else{
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true )
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,LOW); // pulse this channel low if activated
}
Channel[timer]++; // increment to the next channel
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
*OCRnA = *TCNTn + SERVO(timer,Channel[timer]).ticks;
if(SERVO(timer,Channel[timer]).Pin.isActive == true) // check if activated
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
}
else {
// finished all channels so wait for the refresh period to expire before starting over
if( ((unsigned)*TCNTn) + 4 < usToTicks(REFRESH_INTERVAL) ) // allow a few ticks to ensure the next OCR1A not missed
*OCRnA = (unsigned int)usToTicks(REFRESH_INTERVAL);
else
*OCRnA = *TCNTn + 4; // at least REFRESH_INTERVAL has elapsed
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
#ifndef WIRING // Wiring pre-defines signal handlers so don't define any if compiling for the Wiring platform
// Interrupt handlers for Arduino
#if defined(_useTimer1)
SIGNAL (TIMER1_COMPA_vect)
{
handle_interrupts(_timer1, &TCNT1, &OCR1A);
}
#endif
#if defined(_useTimer3)
SIGNAL (TIMER3_COMPA_vect)
{
handle_interrupts(_timer3, &TCNT3, &OCR3A);
}
#endif
#if defined(_useTimer4)
SIGNAL (TIMER4_COMPA_vect)
{
handle_interrupts(_timer4, &TCNT4, &OCR4A);
}
#endif
#if defined(_useTimer5)
SIGNAL (TIMER5_COMPA_vect)
{
handle_interrupts(_timer5, &TCNT5, &OCR5A);
}
#endif
#elif defined WIRING
// Interrupt handlers for Wiring
#if defined(_useTimer1)
void Timer1Service()
{
handle_interrupts(_timer1, &TCNT1, &OCR1A);
}
#endif
#if defined(_useTimer3)
void Timer3Service()
{
handle_interrupts(_timer3, &TCNT3, &OCR3A);
}
#endif
#endif
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if(timer == _timer1) {
TCCR1A = 0; // normal counting mode
TCCR1B = _BV(CS11); // set prescaler of 8
TCNT1 = 0; // clear the timer count
#if defined(__AVR_ATmega8__)|| defined(__AVR_ATmega128__)
TIFR |= _BV(OCF1A); // clear any pending interrupts;
TIMSK |= _BV(OCIE1A) ; // enable the output compare interrupt
#else
// here if not ATmega8 or ATmega128
TIFR1 |= _BV(OCF1A); // clear any pending interrupts;
TIMSK1 |= _BV(OCIE1A) ; // enable the output compare interrupt
#endif
#if defined(WIRING)
timerAttach(TIMER1OUTCOMPAREA_INT, Timer1Service);
#endif
}
#endif
#if defined (_useTimer3)
if(timer == _timer3) {
TCCR3A = 0; // normal counting mode
TCCR3B = _BV(CS31); // set prescaler of 8
TCNT3 = 0; // clear the timer count
#if defined(__AVR_ATmega128__)
TIFR |= _BV(OCF3A); // clear any pending interrupts;
ETIMSK |= _BV(OCIE3A); // enable the output compare interrupt
#else
TIFR3 = _BV(OCF3A); // clear any pending interrupts;
TIMSK3 = _BV(OCIE3A) ; // enable the output compare interrupt
#endif
#if defined(WIRING)
timerAttach(TIMER3OUTCOMPAREA_INT, Timer3Service); // for Wiring platform only
#endif
}
#endif
#if defined (_useTimer4)
if(timer == _timer4) {
TCCR4A = 0; // normal counting mode
TCCR4B = _BV(CS41); // set prescaler of 8
TCNT4 = 0; // clear the timer count
TIFR4 = _BV(OCF4A); // clear any pending interrupts;
TIMSK4 = _BV(OCIE4A) ; // enable the output compare interrupt
}
#endif
#if defined (_useTimer5)
if(timer == _timer5) {
TCCR5A = 0; // normal counting mode
TCCR5B = _BV(CS51); // set prescaler of 8
TCNT5 = 0; // clear the timer count
TIFR5 = _BV(OCF5A); // clear any pending interrupts;
TIMSK5 = _BV(OCIE5A) ; // enable the output compare interrupt
}
#endif
}
static void finISR(timer16_Sequence_t timer)
{
//disable use of the given timer
#if defined WIRING // Wiring
if(timer == _timer1) {
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
TIMSK1 &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
#else
TIMSK &= ~_BV(OCIE1A) ; // disable timer 1 output compare interrupt
#endif
timerDetach(TIMER1OUTCOMPAREA_INT);
}
else if(timer == _timer3) {
#if defined(__AVR_ATmega1281__)||defined(__AVR_ATmega2561__)
TIMSK3 &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
#else
ETIMSK &= ~_BV(OCIE3A); // disable the timer3 output compare A interrupt
#endif
timerDetach(TIMER3OUTCOMPAREA_INT);
}
#else
//For arduino - in future: call here to a currently undefined function to reset the timer
(void) timer; // squash "unused parameter 'timer' [-Wunused-parameter]" warning
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if( ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values - 12 Aug 2009
}
else
this->servoIndex = INVALID_SERVO ; // too many servos
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
if(this->servoIndex < MAX_SERVOS ) {
pinMode( pin, OUTPUT) ; // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false)
initISR(timer);
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex ;
}
void Servo::detach()
{
servos[this->servoIndex].Pin.isActive = false;
timer16_Sequence_t timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
if(value < MIN_PULSE_WIDTH)
{ // treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if(value < 0) value = 0;
if(value > 180) value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
this->writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if( value < SERVO_MIN() ) // ensure pulse width is valid
value = SERVO_MIN();
else if( value > SERVO_MAX() )
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead - 12 Aug 2009
uint8_t oldSREG = SREG;
cli();
servos[channel].ticks = value;
SREG = oldSREG;
}
}
int Servo::read() // return the value as degrees
{
return map( this->readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if( this->servoIndex != INVALID_SERVO )
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION ; // 12 aug 2009
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive ;
}
#endif // ARDUINO_ARCH_AVR

View file

@ -1,59 +0,0 @@
/*
Servo.h - Interrupt driven Servo library for Arduino using 16 bit timers- Version 2
Copyright (c) 2009 Michael Margolis. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
/**
* AVR Only definitions
* --------------------
*/
// Say which 16 bit timers can be used and in what order
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define _useTimer5
#define _useTimer1
#define _useTimer3
#define _useTimer4
typedef enum { _timer5, _timer1, _timer3, _timer4, _Nbr_16timers } timer16_Sequence_t;
#elif defined(__AVR_ATmega32U4__)
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#elif defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;
#elif defined(__AVR_ATmega128__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega2561__)
#define _useTimer3
#define _useTimer1
typedef enum { _timer3, _timer1, _Nbr_16timers } timer16_Sequence_t;
#else // everything else
#define _useTimer1
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif

View file

@ -1,211 +0,0 @@
#if defined(ARDUINO_ARCH_MEGAAVR)
#include <Arduino.h>
#include <Servo.h>
#define usToTicks(_us) ((clockCyclesPerMicrosecond() / 16 * _us) / 4) // converts microseconds to tick
#define ticksToUs(_ticks) (((unsigned) _ticks * 16) / (clockCyclesPerMicrosecond() / 4)) // converts from ticks back to microseconds
#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
void ServoHandler(int timer)
{
if (currentServoIndex[timer] < 0) {
// Write compare register
_timer->CCMP = 0;
} else {
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive == true) {
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
}
}
// Select the next servo controlled by this timer
currentServoIndex[timer]++;
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) {
if (SERVO(timer, currentServoIndex[timer]).Pin.isActive == true) { // check if activated
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
}
// Get the counter value
uint16_t tcCounterValue = 0; //_timer->CCMP;
_timer->CCMP = (uint16_t) (tcCounterValue + SERVO(timer, currentServoIndex[timer]).ticks);
}
else {
// finished all channels so wait for the refresh period to expire before starting over
// Get the counter value
uint16_t tcCounterValue = _timer->CCMP;
if (tcCounterValue + 4UL < usToTicks(REFRESH_INTERVAL)) { // allow a few ticks to ensure the next OCR1A not missed
_timer->CCMP = (uint16_t) usToTicks(REFRESH_INTERVAL);
}
else {
_timer->CCMP = (uint16_t) (tcCounterValue + 4UL); // at least REFRESH_INTERVAL has elapsed
}
currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
/* Clear flag */
_timer->INTFLAGS = TCB_CAPT_bm;
}
#if defined USE_TIMERB0
ISR(TCB0_INT_vect)
#elif defined USE_TIMERB1
ISR(TCB1_INT_vect)
#elif defined USE_TIMERB2
ISR(TCB2_INT_vect)
#endif
{
ServoHandler(0);
}
static void initISR(timer16_Sequence_t timer)
{
//TCA0.SINGLE.CTRLA = (TCA_SINGLE_CLKSEL_DIV16_gc) | (TCA_SINGLE_ENABLE_bm);
_timer->CTRLA = TCB_CLKSEL_CLKTCA_gc;
// Timer to Periodic interrupt mode
// This write will also disable any active PWM outputs
_timer->CTRLB = TCB_CNTMODE_INT_gc;
// Enable interrupt
_timer->INTCTRL = TCB_CAPTEI_bm;
// Enable timer
_timer->CTRLA |= TCB_ENABLE_bm;
}
static void finISR(timer16_Sequence_t timer)
{
// Disable interrupt
_timer->INTCTRL = 0;
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
timer16_Sequence_t timer;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (isTimerActive(timer) == false) {
initISR(timer);
}
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex;
}
void Servo::detach()
{
timer16_Sequence_t timer;
servos[this->servoIndex].Pin.isActive = false;
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < MIN_PULSE_WIDTH)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if (value < SERVO_MIN()) // ensure pulse width is valid
value = SERVO_MIN();
else if (value > SERVO_MAX())
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead
servos[channel].ticks = value;
}
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if (this->servoIndex != INVALID_SERVO)
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif

View file

@ -1,54 +0,0 @@
/*
Copyright (c) 2018 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
*/
#ifndef __SERVO_TIMERS_H__
#define __SERVO_TIMERS_H__
#include <avr/io.h>
#define USE_TIMERB1 // interferes with PWM on pin 3
//#define USE_TIMERB2 // interferes with PWM on pin 11
//#define USE_TIMERB0 // interferes with PWM on pin 6
#if !defined(USE_TIMERB1) && !defined(USE_TIMERB2) && !defined(USE_TIMERB0)
# error "No timers allowed for Servo"
/* Please uncomment a timer above and rebuild */
#endif
static volatile TCB_t* _timer =
#if defined(USE_TIMERB0)
&TCB0;
#endif
#if defined(USE_TIMERB1)
&TCB1;
#endif
#if defined(USE_TIMERB2)
&TCB2;
#endif
typedef enum {
timer0,
_Nbr_16timers } timer16_Sequence_t;
#endif /* __SERVO_TIMERS_H__ */

View file

@ -1,134 +0,0 @@
/*
Copyright (c) 2016 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_NRF52)
#include <Arduino.h>
#include <Servo.h>
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
uint32_t group_pins[3][NRF_PWM_CHANNEL_COUNT]={{NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}, {NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}, {NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED, NRF_PWM_PIN_NOT_CONNECTED}};
static uint16_t seq_values[3][NRF_PWM_CHANNEL_COUNT]={{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, 0, 2500);
}
uint8_t Servo::attach(int pin, int min, int max)
{
int servo_min, servo_max;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
if(min < servo_min) min = servo_min;
if (max > servo_max) max = servo_max;
this->min = min;
this->max = max;
servos[this->servoIndex].Pin.isActive = true;
}
return this->servoIndex;
}
void Servo::detach()
{
servos[this->servoIndex].Pin.isActive = false;
}
void Servo::write(int value)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, MIN_PULSE, MAX_PULSE);
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
uint8_t channel, instance;
uint8_t pin = servos[this->servoIndex].Pin.nbr;
//instance of pwm module is MSB - look at VWariant.h
instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16;
//index of pwm channel is LSB - look at VWariant.h
channel=g_APinDescription[pin].ulPWMChannel & 0x0F;
group_pins[instance][channel]=g_APinDescription[pin].ulPin;
NRF_PWM_Type * PWMInstance = instance == 0 ? NRF_PWM0 : (instance == 1 ? NRF_PWM1 : NRF_PWM2);
//configure pwm instance and enable it
seq_values[instance][channel]= value | 0x8000;
nrf_pwm_sequence_t const seq={
seq_values[instance],
NRF_PWM_VALUES_LENGTH(seq_values),
0,
0
};
nrf_pwm_pins_set(PWMInstance, group_pins[instance]);
nrf_pwm_enable(PWMInstance);
nrf_pwm_configure(PWMInstance, NRF_PWM_CLK_125kHz, NRF_PWM_MODE_UP, 2500); // 20ms - 50Hz
nrf_pwm_decoder_set(PWMInstance, NRF_PWM_LOAD_INDIVIDUAL, NRF_PWM_STEP_AUTO);
nrf_pwm_sequence_set(PWMInstance, 0, &seq);
nrf_pwm_loop_set(PWMInstance, 0UL);
nrf_pwm_task_trigger(PWMInstance, NRF_PWM_TASK_SEQSTART0);
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds(), MIN_PULSE, MAX_PULSE, 0, 180);
}
int Servo::readMicroseconds()
{
uint8_t channel, instance;
uint8_t pin=servos[this->servoIndex].Pin.nbr;
instance=(g_APinDescription[pin].ulPWMChannel & 0xF0)/16;
channel=g_APinDescription[pin].ulPWMChannel & 0x0F;
// remove the 16th bit we added before
return seq_values[instance][channel] & 0x7FFF;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif // ARDUINO_ARCH_NRF52

View file

@ -1,38 +0,0 @@
/*
Copyright (c) 2016 Arduino. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* NRF52 doesn't use timer, but pwm. This file include definitions to keep
* compatibility with the Servo library standards.
*/
#ifndef __SERVO_TIMERS_H__
#define __SERVO_TIMERS_H__
/**
* NRF52 Only definitions
* ---------------------
*/
#define MIN_PULSE 55
#define MAX_PULSE 284
// define one timer in order to have MAX_SERVOS = 12
typedef enum { _timer1, _Nbr_16timers } timer16_Sequence_t;
#endif // __SERVO_TIMERS_H__

View file

@ -1,283 +0,0 @@
/*
Copyright (c) 2013 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_SAM)
#include <Arduino.h>
#include <Servo.h>
#define usToTicks(_us) (( clockCyclesPerMicrosecond() * _us) / 32) // converts microseconds to tick
#define ticksToUs(_ticks) (( (unsigned)_ticks * 32)/ clockCyclesPerMicrosecond() ) // converts from ticks back to microseconds
#define TRIM_DURATION 2 // compensation ticks to trim adjust for digitalWrite delays
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
static volatile int8_t Channel[_Nbr_16timers ]; // counter for the servo being pulsed for each timer (or -1 if refresh interval)
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
/************ static functions common to all instances ***********************/
//------------------------------------------------------------------------------
/// Interrupt handler for the TC0 channel 1.
//------------------------------------------------------------------------------
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel);
#if defined (_useTimer1)
void HANDLER_FOR_TIMER1(void) {
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1);
}
#endif
#if defined (_useTimer2)
void HANDLER_FOR_TIMER2(void) {
Servo_Handler(_timer2, TC_FOR_TIMER2, CHANNEL_FOR_TIMER2);
}
#endif
#if defined (_useTimer3)
void HANDLER_FOR_TIMER3(void) {
Servo_Handler(_timer3, TC_FOR_TIMER3, CHANNEL_FOR_TIMER3);
}
#endif
#if defined (_useTimer4)
void HANDLER_FOR_TIMER4(void) {
Servo_Handler(_timer4, TC_FOR_TIMER4, CHANNEL_FOR_TIMER4);
}
#endif
#if defined (_useTimer5)
void HANDLER_FOR_TIMER5(void) {
Servo_Handler(_timer5, TC_FOR_TIMER5, CHANNEL_FOR_TIMER5);
}
#endif
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel)
{
// clear interrupt
tc->TC_CHANNEL[channel].TC_SR;
if (Channel[timer] < 0) {
tc->TC_CHANNEL[channel].TC_CCR |= TC_CCR_SWTRG; // channel set to -1 indicated that refresh interval completed so reset the timer
} else {
if (SERVO_INDEX(timer,Channel[timer]) < ServoCount && SERVO(timer,Channel[timer]).Pin.isActive == true) {
digitalWrite(SERVO(timer,Channel[timer]).Pin.nbr, LOW); // pulse this channel low if activated
}
}
Channel[timer]++; // increment to the next channel
if( SERVO_INDEX(timer,Channel[timer]) < ServoCount && Channel[timer] < SERVOS_PER_TIMER) {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + SERVO(timer,Channel[timer]).ticks;
if(SERVO(timer,Channel[timer]).Pin.isActive == true) { // check if activated
digitalWrite( SERVO(timer,Channel[timer]).Pin.nbr,HIGH); // its an active channel so pulse it high
}
}
else {
// finished all channels so wait for the refresh period to expire before starting over
if( (tc->TC_CHANNEL[channel].TC_CV) + 4 < usToTicks(REFRESH_INTERVAL) ) { // allow a few ticks to ensure the next OCR1A not missed
tc->TC_CHANNEL[channel].TC_RA = (unsigned int)usToTicks(REFRESH_INTERVAL);
}
else {
tc->TC_CHANNEL[channel].TC_RA = tc->TC_CHANNEL[channel].TC_CV + 4; // at least REFRESH_INTERVAL has elapsed
}
Channel[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
}
static void _initISR(Tc *tc, uint32_t channel, uint32_t id, IRQn_Type irqn)
{
pmc_enable_periph_clk(id);
TC_Configure(tc, channel,
TC_CMR_TCCLKS_TIMER_CLOCK3 | // MCK/32
TC_CMR_WAVE | // Waveform mode
TC_CMR_WAVSEL_UP_RC ); // Counter running up and reset when equals to RC
/* 84MHz, MCK/32, for 1.5ms: 3937 */
TC_SetRA(tc, channel, 2625); // 1ms
/* Configure and enable interrupt */
NVIC_EnableIRQ(irqn);
// TC_IER_CPAS: RA Compare
tc->TC_CHANNEL[channel].TC_IER = TC_IER_CPAS;
// Enables the timer clock and performs a software reset to start the counting
TC_Start(tc, channel);
}
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if (timer == _timer1)
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1);
#endif
#if defined (_useTimer2)
if (timer == _timer2)
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2);
#endif
#if defined (_useTimer3)
if (timer == _timer3)
_initISR(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3, ID_TC_FOR_TIMER3, IRQn_FOR_TIMER3);
#endif
#if defined (_useTimer4)
if (timer == _timer4)
_initISR(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4, ID_TC_FOR_TIMER4, IRQn_FOR_TIMER4);
#endif
#if defined (_useTimer5)
if (timer == _timer5)
_initISR(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5, ID_TC_FOR_TIMER5, IRQn_FOR_TIMER5);
#endif
}
static void finISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
TC_Stop(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1);
#endif
#if defined (_useTimer2)
TC_Stop(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2);
#endif
#if defined (_useTimer3)
TC_Stop(TC_FOR_TIMER3, CHANNEL_FOR_TIMER3);
#endif
#if defined (_useTimer4)
TC_Stop(TC_FOR_TIMER4, CHANNEL_FOR_TIMER4);
#endif
#if defined (_useTimer5)
TC_Stop(TC_FOR_TIMER5, CHANNEL_FOR_TIMER5);
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
timer16_Sequence_t timer;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (isTimerActive(timer) == false) {
initISR(timer);
}
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex;
}
void Servo::detach()
{
timer16_Sequence_t timer;
servos[this->servoIndex].Pin.isActive = false;
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < MIN_PULSE_WIDTH)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if (value < SERVO_MIN()) // ensure pulse width is valid
value = SERVO_MIN();
else if (value > SERVO_MAX())
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead
servos[channel].ticks = value;
}
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if (this->servoIndex != INVALID_SERVO)
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif // ARDUINO_ARCH_SAM

View file

@ -1,88 +0,0 @@
/*
Copyright (c) 2013 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
/**
* SAM Only definitions
* --------------------
*/
// For SAM3X:
#define _useTimer1
#define _useTimer2
#define _useTimer3
#define _useTimer4
#define _useTimer5
/*
TC0, chan 0 => TC0_Handler
TC0, chan 1 => TC1_Handler
TC0, chan 2 => TC2_Handler
TC1, chan 0 => TC3_Handler
TC1, chan 1 => TC4_Handler
TC1, chan 2 => TC5_Handler
TC2, chan 0 => TC6_Handler
TC2, chan 1 => TC7_Handler
TC2, chan 2 => TC8_Handler
*/
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC1
#define CHANNEL_FOR_TIMER1 0
#define ID_TC_FOR_TIMER1 ID_TC3
#define IRQn_FOR_TIMER1 TC3_IRQn
#define HANDLER_FOR_TIMER1 TC3_Handler
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC1
#define CHANNEL_FOR_TIMER2 1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#endif
#if defined (_useTimer3)
#define TC_FOR_TIMER3 TC1
#define CHANNEL_FOR_TIMER3 2
#define ID_TC_FOR_TIMER3 ID_TC5
#define IRQn_FOR_TIMER3 TC5_IRQn
#define HANDLER_FOR_TIMER3 TC5_Handler
#endif
#if defined (_useTimer4)
#define TC_FOR_TIMER4 TC0
#define CHANNEL_FOR_TIMER4 2
#define ID_TC_FOR_TIMER4 ID_TC2
#define IRQn_FOR_TIMER4 TC2_IRQn
#define HANDLER_FOR_TIMER4 TC2_Handler
#endif
#if defined (_useTimer5)
#define TC_FOR_TIMER5 TC0
#define CHANNEL_FOR_TIMER5 0
#define ID_TC_FOR_TIMER5 ID_TC0
#define IRQn_FOR_TIMER5 TC0_IRQn
#define HANDLER_FOR_TIMER5 TC0_Handler
#endif
typedef enum { _timer1, _timer2, _timer3, _timer4, _timer5, _Nbr_16timers } timer16_Sequence_t ;

View file

@ -1,391 +0,0 @@
/*
Copyright (c) 2015 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#if defined(ARDUINO_ARCH_SAMD)
#include <Arduino.h>
#include <Servo.h>
#if defined(__SAMD51__)
// Different prescalers depending on FCPU (avoid overflowing 16-bit counter)
#if(F_CPU > 200000000)
#define usToTicks(_us) ((clockCyclesPerMicrosecond() * _us) / 128)
#define ticksToUs(_ticks) (((unsigned) _ticks * 128) / clockCyclesPerMicrosecond())
#else
#define usToTicks(_us) ((clockCyclesPerMicrosecond() * _us) / 64)
#define ticksToUs(_ticks) (((unsigned) _ticks * 64) / clockCyclesPerMicrosecond())
#endif
#else
#define usToTicks(_us) ((clockCyclesPerMicrosecond() * _us) / 16) // converts microseconds to tick
#define ticksToUs(_ticks) (((unsigned) _ticks * 16) / clockCyclesPerMicrosecond()) // converts from ticks back to microseconds
#endif
#define TRIM_DURATION 5 // compensation ticks to trim adjust for digitalWrite delays
static servo_t servos[MAX_SERVOS]; // static array of servo structures
uint8_t ServoCount = 0; // the total number of attached servos
static volatile int8_t currentServoIndex[_Nbr_16timers]; // index for the servo being pulsed for each timer (or -1 if refresh interval)
// convenience macros
#define SERVO_INDEX_TO_TIMER(_servo_nbr) ((timer16_Sequence_t)(_servo_nbr / SERVOS_PER_TIMER)) // returns the timer controlling this servo
#define SERVO_INDEX_TO_CHANNEL(_servo_nbr) (_servo_nbr % SERVOS_PER_TIMER) // returns the index of the servo on this timer
#define SERVO_INDEX(_timer,_channel) ((_timer*SERVOS_PER_TIMER) + _channel) // macro to access servo index by timer and channel
#define SERVO(_timer,_channel) (servos[SERVO_INDEX(_timer,_channel)]) // macro to access servo class by timer and channel
#define SERVO_MIN() (MIN_PULSE_WIDTH - this->min * 4) // minimum value in uS for this servo
#define SERVO_MAX() (MAX_PULSE_WIDTH - this->max * 4) // maximum value in uS for this servo
// Referenced in SAMD21 code only, no harm in defining regardless
#define WAIT_TC16_REGS_SYNC(x) while(x->COUNT16.STATUS.bit.SYNCBUSY);
/************ static functions common to all instances ***********************/
void Servo_Handler(timer16_Sequence_t timer, Tc *pTc, uint8_t channel, uint8_t intFlag);
#if defined (_useTimer1)
void HANDLER_FOR_TIMER1(void) {
Servo_Handler(_timer1, TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, INTFLAG_BIT_FOR_TIMER_1);
}
#endif
#if defined (_useTimer2)
void HANDLER_FOR_TIMER2(void) {
Servo_Handler(_timer2, TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, INTFLAG_BIT_FOR_TIMER_2);
}
#endif
void Servo_Handler(timer16_Sequence_t timer, Tc *tc, uint8_t channel, uint8_t intFlag)
{
if (currentServoIndex[timer] < 0) {
tc->COUNT16.COUNT.reg = (uint16_t) 0;
#if defined(__SAMD51__)
while(tc->COUNT16.SYNCBUSY.bit.COUNT);
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
} else {
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && SERVO(timer, currentServoIndex[timer]).Pin.isActive == true) {
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, LOW); // pulse this channel low if activated
}
}
// Select the next servo controlled by this timer
currentServoIndex[timer]++;
if (SERVO_INDEX(timer, currentServoIndex[timer]) < ServoCount && currentServoIndex[timer] < SERVOS_PER_TIMER) {
if (SERVO(timer, currentServoIndex[timer]).Pin.isActive == true) { // check if activated
digitalWrite(SERVO(timer, currentServoIndex[timer]).Pin.nbr, HIGH); // it's an active channel so pulse it high
}
// Get the counter value
#if defined(__SAMD51__)
// Note from datasheet: Prior to any read access, this register must be synchronized by user by writing the according TC
// Command value to the Control B Set register (CTRLBSET.CMD=READSYNC)
while (tc->COUNT16.SYNCBUSY.bit.CTRLB);
tc->COUNT16.CTRLBSET.bit.CMD = TC_CTRLBSET_CMD_READSYNC_Val;
while (tc->COUNT16.SYNCBUSY.bit.CTRLB);
#endif
uint16_t tcCounterValue = tc->COUNT16.COUNT.reg;
#if defined(__SAMD51__)
while(tc->COUNT16.SYNCBUSY.bit.COUNT);
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
tc->COUNT16.CC[channel].reg = (uint16_t) (tcCounterValue + SERVO(timer, currentServoIndex[timer]).ticks);
#if defined(__SAMD51__)
if(channel == 0) {
while(tc->COUNT16.SYNCBUSY.bit.CC0);
} else if(channel == 1) {
while(tc->COUNT16.SYNCBUSY.bit.CC1);
}
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
}
else {
// finished all channels so wait for the refresh period to expire before starting over
// Get the counter value
uint16_t tcCounterValue = tc->COUNT16.COUNT.reg;
#if defined(__SAMD51__)
while(tc->COUNT16.SYNCBUSY.bit.COUNT);
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
if (tcCounterValue + 4UL < usToTicks(REFRESH_INTERVAL)) { // allow a few ticks to ensure the next OCR1A not missed
tc->COUNT16.CC[channel].reg = (uint16_t) usToTicks(REFRESH_INTERVAL);
}
else {
tc->COUNT16.CC[channel].reg = (uint16_t) (tcCounterValue + 4UL); // at least REFRESH_INTERVAL has elapsed
}
#if defined(__SAMD51__)
if(channel == 0) {
while(tc->COUNT16.SYNCBUSY.bit.CC0);
} else if(channel == 1) {
while(tc->COUNT16.SYNCBUSY.bit.CC1);
}
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
currentServoIndex[timer] = -1; // this will get incremented at the end of the refresh period to start again at the first channel
}
// Clear the interrupt
tc->COUNT16.INTFLAG.reg = intFlag;
}
static inline void resetTC (Tc* TCx)
{
// Disable TCx
TCx->COUNT16.CTRLA.reg &= ~TC_CTRLA_ENABLE;
#if defined(__SAMD51__)
while(TCx->COUNT16.SYNCBUSY.bit.ENABLE);
#else
WAIT_TC16_REGS_SYNC(TCx)
#endif
// Reset TCx
TCx->COUNT16.CTRLA.reg = TC_CTRLA_SWRST;
#if defined(__SAMD51__)
while(TCx->COUNT16.SYNCBUSY.bit.SWRST);
#else
WAIT_TC16_REGS_SYNC(TCx)
#endif
while (TCx->COUNT16.CTRLA.bit.SWRST);
}
static void _initISR(Tc *tc, uint8_t channel, uint32_t id, IRQn_Type irqn, uint8_t gcmForTimer, uint8_t intEnableBit)
{
(void)id;
// Select GCLK0 as timer/counter input clock source
#if defined(__SAMD51__)
int idx = gcmForTimer; // see datasheet Table 14-9
GCLK->PCHCTRL[idx].bit.GEN = 0; // Select GCLK0 as periph clock source
GCLK->PCHCTRL[idx].bit.CHEN = 1; // Enable peripheral
while(!GCLK->PCHCTRL[idx].bit.CHEN);
#else
GCLK->CLKCTRL.reg = (uint16_t) (GCLK_CLKCTRL_CLKEN | GCLK_CLKCTRL_GEN_GCLK0 | GCLK_CLKCTRL_ID(gcmForTimer));
while (GCLK->STATUS.bit.SYNCBUSY);
#endif
// Reset the timer
// TODO this is not the right thing to do if more than one channel per timer is used by the Servo library
resetTC(tc);
// Set timer counter mode to 16 bits
tc->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT16;
#if defined(__SAMD51__)
// Set timer counter mode as normal PWM
tc->COUNT16.WAVE.bit.WAVEGEN = TCC_WAVE_WAVEGEN_NPWM_Val;
// Set the prescaler factor to 64 or 128 depending on FCPU
// (avoid overflowing 16-bit clock counter)
#if(F_CPU > 200000000)
tc->COUNT16.CTRLA.bit.PRESCALER = TCC_CTRLA_PRESCALER_DIV128_Val;
#else
// At 120-200 MHz GCLK this is 1875-3125 ticks per millisecond
tc->COUNT16.CTRLA.bit.PRESCALER = TCC_CTRLA_PRESCALER_DIV64_Val;
#endif
#else
// Set timer counter mode as normal PWM
tc->COUNT16.CTRLA.reg |= TC_CTRLA_WAVEGEN_NPWM;
// Set the prescaler factor to GCLK_TC/16. At nominal 48MHz GCLK_TC this is 3000 ticks per millisecond
tc->COUNT16.CTRLA.reg |= TC_CTRLA_PRESCALER_DIV16;
#endif
// Count up
tc->COUNT16.CTRLBCLR.bit.DIR = 1;
#if defined(__SAMD51__)
while(tc->COUNT16.SYNCBUSY.bit.CTRLB);
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
// First interrupt request after 1 ms
tc->COUNT16.CC[channel].reg = (uint16_t) usToTicks(1000UL);
#if defined(__SAMD51__)
if(channel == 0) {
while(tc->COUNT16.SYNCBUSY.bit.CC0);
} else if(channel == 1) {
while(tc->COUNT16.SYNCBUSY.bit.CC1);
}
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
// Configure interrupt request
// TODO this should be changed if more than one channel per timer is used by the Servo library
NVIC_DisableIRQ(irqn);
NVIC_ClearPendingIRQ(irqn);
NVIC_SetPriority(irqn, 0);
NVIC_EnableIRQ(irqn);
// Enable the match channel interrupt request
tc->COUNT16.INTENSET.reg = intEnableBit;
// Enable the timer and start it
tc->COUNT16.CTRLA.reg |= TC_CTRLA_ENABLE;
#if defined(__SAMD51__)
while(tc->COUNT16.SYNCBUSY.bit.ENABLE);
#else
WAIT_TC16_REGS_SYNC(tc)
#endif
}
static void initISR(timer16_Sequence_t timer)
{
#if defined (_useTimer1)
if (timer == _timer1)
_initISR(TC_FOR_TIMER1, CHANNEL_FOR_TIMER1, ID_TC_FOR_TIMER1, IRQn_FOR_TIMER1, GCM_FOR_TIMER_1, INTENSET_BIT_FOR_TIMER_1);
#endif
#if defined (_useTimer2)
if (timer == _timer2)
_initISR(TC_FOR_TIMER2, CHANNEL_FOR_TIMER2, ID_TC_FOR_TIMER2, IRQn_FOR_TIMER2, GCM_FOR_TIMER_2, INTENSET_BIT_FOR_TIMER_2);
#endif
}
static void finISR(timer16_Sequence_t timer)
{
(void)timer;
#if defined (_useTimer1)
// Disable the match channel interrupt request
TC_FOR_TIMER1->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_1;
#endif
#if defined (_useTimer2)
// Disable the match channel interrupt request
TC_FOR_TIMER2->COUNT16.INTENCLR.reg = INTENCLR_BIT_FOR_TIMER_2;
#endif
}
static boolean isTimerActive(timer16_Sequence_t timer)
{
// returns true if any servo is active on this timer
for(uint8_t channel=0; channel < SERVOS_PER_TIMER; channel++) {
if(SERVO(timer,channel).Pin.isActive == true)
return true;
}
return false;
}
/****************** end of static functions ******************************/
Servo::Servo()
{
if (ServoCount < MAX_SERVOS) {
this->servoIndex = ServoCount++; // assign a servo index to this instance
servos[this->servoIndex].ticks = usToTicks(DEFAULT_PULSE_WIDTH); // store default values
} else {
this->servoIndex = INVALID_SERVO; // too many servos
}
}
uint8_t Servo::attach(int pin)
{
return this->attach(pin, MIN_PULSE_WIDTH, MAX_PULSE_WIDTH);
}
uint8_t Servo::attach(int pin, int min, int max)
{
timer16_Sequence_t timer;
if (this->servoIndex < MAX_SERVOS) {
pinMode(pin, OUTPUT); // set servo pin to output
servos[this->servoIndex].Pin.nbr = pin;
// todo min/max check: abs(min - MIN_PULSE_WIDTH) /4 < 128
this->min = (MIN_PULSE_WIDTH - min)/4; //resolution of min/max is 4 uS
this->max = (MAX_PULSE_WIDTH - max)/4;
// initialize the timer if it has not already been initialized
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if (isTimerActive(timer) == false) {
initISR(timer);
}
servos[this->servoIndex].Pin.isActive = true; // this must be set after the check for isTimerActive
}
return this->servoIndex;
}
void Servo::detach()
{
timer16_Sequence_t timer;
servos[this->servoIndex].Pin.isActive = false;
timer = SERVO_INDEX_TO_TIMER(servoIndex);
if(isTimerActive(timer) == false) {
finISR(timer);
}
}
void Servo::write(int value)
{
// treat values less than 544 as angles in degrees (valid values in microseconds are handled as microseconds)
if (value < MIN_PULSE_WIDTH)
{
if (value < 0)
value = 0;
else if (value > 180)
value = 180;
value = map(value, 0, 180, SERVO_MIN(), SERVO_MAX());
}
writeMicroseconds(value);
}
void Servo::writeMicroseconds(int value)
{
// calculate and store the values for the given channel
byte channel = this->servoIndex;
if( (channel < MAX_SERVOS) ) // ensure channel is valid
{
if (value < SERVO_MIN()) // ensure pulse width is valid
value = SERVO_MIN();
else if (value > SERVO_MAX())
value = SERVO_MAX();
value = value - TRIM_DURATION;
value = usToTicks(value); // convert to ticks after compensating for interrupt overhead
servos[channel].ticks = value;
}
}
int Servo::read() // return the value as degrees
{
return map(readMicroseconds()+1, SERVO_MIN(), SERVO_MAX(), 0, 180);
}
int Servo::readMicroseconds()
{
unsigned int pulsewidth;
if (this->servoIndex != INVALID_SERVO)
pulsewidth = ticksToUs(servos[this->servoIndex].ticks) + TRIM_DURATION;
else
pulsewidth = 0;
return pulsewidth;
}
bool Servo::attached()
{
return servos[this->servoIndex].Pin.isActive;
}
#endif // ARDUINO_ARCH_SAMD

View file

@ -1,98 +0,0 @@
/*
Copyright (c) 2015 Arduino LLC. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* Defines for 16 bit timers used with Servo library
*
* If _useTimerX is defined then TimerX is a 16 bit timer on the current board
* timer16_Sequence_t enumerates the sequence that the timers should be allocated
* _Nbr_16timers indicates how many 16 bit timers are available.
*/
#ifndef __SERVO_TIMERS_H__
#define __SERVO_TIMERS_H__
/**
* SAMD Only definitions
* ---------------------
*/
// For SAMD:
#define _useTimer1
//#define _useTimer2 // <- TODO do not activate until the code in Servo.cpp has been changed in order
// to manage more than one channel per timer on the SAMD architecture
#if defined(__SAMD51__)
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC1
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC1
#define IRQn_FOR_TIMER1 TC1_IRQn
#define HANDLER_FOR_TIMER1 TC1_Handler
#define GCM_FOR_TIMER_1 TC1_GCLK_ID
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC1
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define INTFLAG_BIT_FOR_TIMER_2 TC_INTFLAG_MC1
#define ID_TC_FOR_TIMER2 ID_TC1
#define IRQn_FOR_TIMER2 TC1_IRQn
#define HANDLER_FOR_TIMER2 TC1_Handler
#define GCM_FOR_TIMER_2 TC1_GCLK_ID
#endif
#else
#if defined (_useTimer1)
#define TC_FOR_TIMER1 TC4
#define CHANNEL_FOR_TIMER1 0
#define INTENSET_BIT_FOR_TIMER_1 TC_INTENSET_MC0
#define INTENCLR_BIT_FOR_TIMER_1 TC_INTENCLR_MC0
#define INTFLAG_BIT_FOR_TIMER_1 TC_INTFLAG_MC0
#define ID_TC_FOR_TIMER1 ID_TC4
#define IRQn_FOR_TIMER1 TC4_IRQn
#define HANDLER_FOR_TIMER1 TC4_Handler
#define GCM_FOR_TIMER_1 GCM_TC4_TC5
#endif
#if defined (_useTimer2)
#define TC_FOR_TIMER2 TC4
#define CHANNEL_FOR_TIMER2 1
#define INTENSET_BIT_FOR_TIMER_2 TC_INTENSET_MC1
#define INTENCLR_BIT_FOR_TIMER_2 TC_INTENCLR_MC1
#define ID_TC_FOR_TIMER2 ID_TC4
#define IRQn_FOR_TIMER2 TC4_IRQn
#define HANDLER_FOR_TIMER2 TC4_Handler
#define GCM_FOR_TIMER_2 GCM_TC4_TC5
#endif
#endif
typedef enum {
#if defined (_useTimer1)
_timer1,
#endif
#if defined (_useTimer2)
_timer2,
#endif
_Nbr_16timers } timer16_Sequence_t;
#endif // __SERVO_TIMERS_H__

View file

@ -1,194 +0,0 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010, LeafLabs, LLC.
*
* 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.
*****************************************************************************/
#if defined(ARDUINO_ARCH_STM32F4)
#include "ServoTimers.h"
#include "boards.h"
#include "io.h"
#include "pwm.h"
#include "math.h"
// 20 millisecond period config. For a 1-based prescaler,
//
// (prescaler * overflow / CYC_MSEC) msec = 1 timer cycle = 20 msec
// => prescaler * overflow = 20 * CYC_MSEC
//
// This picks the smallest prescaler that allows an overflow < 2^16.
#define MAX_OVERFLOW ((1 << 16) - 1)
#define CYC_MSEC (1000 * CYCLES_PER_MICROSECOND)
#define TAU_MSEC 20
#define TAU_USEC (TAU_MSEC * 1000)
#define TAU_CYC (TAU_MSEC * CYC_MSEC)
#define SERVO_PRESCALER (TAU_CYC / MAX_OVERFLOW + 1)
#define SERVO_OVERFLOW ((uint16)round((double)TAU_CYC / SERVO_PRESCALER))
// Unit conversions
#define US_TO_COMPARE(us) ((uint16)map((us), 0, TAU_USEC, 0, SERVO_OVERFLOW))
#define COMPARE_TO_US(c) ((uint32)map((c), 0, SERVO_OVERFLOW, 0, TAU_USEC))
#define ANGLE_TO_US(a) ((uint16)(map((a), this->minAngle, this->maxAngle, \
this->minPW, this->maxPW)))
#define US_TO_ANGLE(us) ((int16)(map((us), this->minPW, this->maxPW, \
this->minAngle, this->maxAngle)))
Servo::Servo() {
this->resetFields();
}
bool Servo::attach(uint8 pin, uint16 minPW, uint16 maxPW, int16 minAngle, int16 maxAngle)
{
// SerialUSB.begin(115200);
// SerialUSB.println(MAX_OVERFLOW);
timer_dev *tdev = PIN_MAP[pin].timer_device;
analogWriteResolution(16);
int prescaler = 6;
int overflow = 65400;
int minPW_correction = 300;
int maxPW_correction = 300;
pinMode(pin, OUTPUT);
if (tdev == NULL) {
// don't reset any fields or ASSERT(0), to keep driving any
// previously attach()ed servo.
return false;
}
if ( (tdev == TIMER1) || (tdev == TIMER8) || (tdev == TIMER10) || (tdev == TIMER11))
{
prescaler = 54;
overflow = 65400;
minPW_correction = 40;
maxPW_correction = 50;
}
if ( (tdev == TIMER2) || (tdev == TIMER3) || (tdev == TIMER4) || (tdev == TIMER5) )
{
prescaler = 6;
overflow = 64285;
minPW_correction = 370;
maxPW_correction = 350;
}
if ( (tdev == TIMER6) || (tdev == TIMER7) )
{
prescaler = 6;
overflow = 65400;
minPW_correction = 0;
maxPW_correction = 0;
}
if ( (tdev == TIMER9) || (tdev == TIMER12) || (tdev == TIMER13) || (tdev == TIMER14) )
{
prescaler = 6;
overflow = 65400;
minPW_correction = 30;
maxPW_correction = 0;
}
if (this->attached()) {
this->detach();
}
this->pin = pin;
this->minPW = (minPW + minPW_correction);
this->maxPW = (maxPW + maxPW_correction);
this->minAngle = minAngle;
this->maxAngle = maxAngle;
timer_pause(tdev);
timer_set_prescaler(tdev, prescaler); // prescaler is 1-based
timer_set_reload(tdev, overflow);
timer_generate_update(tdev);
timer_resume(tdev);
return true;
}
bool Servo::detach() {
if (!this->attached()) {
return false;
}
timer_dev *tdev = PIN_MAP[this->pin].timer_device;
uint8 tchan = PIN_MAP[this->pin].timer_channel;
timer_set_mode(tdev, tchan, TIMER_DISABLED);
this->resetFields();
return true;
}
void Servo::write(int degrees) {
degrees = constrain(degrees, this->minAngle, this->maxAngle);
this->writeMicroseconds(ANGLE_TO_US(degrees));
}
int Servo::read() const {
int a = US_TO_ANGLE(this->readMicroseconds());
// map() round-trips in a weird way we mostly correct for here;
// the round-trip is still sometimes off-by-one for write(1) and
// write(179).
return a == this->minAngle || a == this->maxAngle ? a : a + 1;
}
void Servo::writeMicroseconds(uint16 pulseWidth) {
if (!this->attached()) {
ASSERT(0);
return;
}
pulseWidth = constrain(pulseWidth, this->minPW, this->maxPW);
analogWrite(this->pin, US_TO_COMPARE(pulseWidth));
}
uint16 Servo::readMicroseconds() const {
if (!this->attached()) {
ASSERT(0);
return 0;
}
stm32_pin_info pin_info = PIN_MAP[this->pin];
uint16 compare = timer_get_compare(pin_info.timer_device,
pin_info.timer_channel);
return COMPARE_TO_US(compare);
}
void Servo::resetFields(void) {
this->pin = NOT_ATTACHED;
this->minAngle = MIN_ANGLE;
this->maxAngle = MAX_ANGLE;
this->minPW = MIN_PULSE_WIDTH;
this->maxPW = MAX_PULSE_WIDTH;
}
#endif

View file

@ -1,207 +0,0 @@
/******************************************************************************
* The MIT License
*
* Copyright (c) 2010, LeafLabs, LLC.
*
* 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.
*****************************************************************************/
/*
* Arduino srl - www.arduino.org
* 2017 Feb 23: Edited by Francesco Alessi (alfran) - francesco@arduino.org
*/
#ifndef _SERVO_H_
#define _SERVO_H_
#include "types.h"
#include "timer.h"
#include "wiring.h" /* hack for IDE compile */
/*
* Note on Arduino compatibility:
*
* In the Arduino implementation, PWM is done "by hand" in the sense
* that timer channels are hijacked in groups and an ISR is set which
* toggles Servo::attach()ed pins using digitalWrite().
*
* While this scheme allows any pin to drive a servo, it chews up
* cycles and complicates the programmer's notion of when a particular
* timer channel will be in use.
*
* This implementation only allows Servo instances to attach() to pins
* that already have a timer channel associated with them, and just
* uses pwmWrite() to drive the wave.
*
* This introduces an incompatibility: while the Arduino
* implementation of attach() returns the affected channel on success
* and 0 on failure, this one returns true on success and false on
* failure.
*
* RC Servos expect a pulse every 20ms. Since periods are set for
* entire timers, rather than individual channels, attach()ing a Servo
* to a pin can interfere with other pins associated with the same
* timer. As always, your board's pin map is your friend.
*/
// Pin number of unattached pins
#define NOT_ATTACHED (-1)
#define _Nbr_16timers 14 // mumber of STM32F469 Timers
#define SERVOS_PER_TIMER 4 // Number of timer channels
// Default min/max pulse widths (in microseconds) and angles (in
// degrees). Values chosen for Arduino compatibility. These values
// are part of the public API; DO NOT CHANGE THEM.
#define MIN_ANGLE 0
#define MAX_ANGLE 180
#define MIN_PULSE_WIDTH 544 // the shortest pulse sent to a servo
#define MAX_PULSE_WIDTH 2400 // the longest pulse sent to a servo
/** Class for interfacing with RC servomotors. */
class Servo {
public:
/**
* @brief Construct a new Servo instance.
*
* The new instance will not be attached to any pin.
*/
Servo();
/**
* @brief Associate this instance with a servomotor whose input is
* connected to pin.
*
* If this instance is already attached to a pin, it will be
* detached before being attached to the new pin. This function
* doesn't detach any interrupt attached with the pin's timer
* channel.
*
* @param pin Pin connected to the servo pulse wave input. This
* pin must be capable of PWM output.
*
* @param minPulseWidth Minimum pulse width to write to pin, in
* microseconds. This will be associated
* with a minAngle degree angle. Defaults to
* SERVO_DEFAULT_MIN_PW = 544.
*
* @param maxPulseWidth Maximum pulse width to write to pin, in
* microseconds. This will be associated
* with a maxAngle degree angle. Defaults to
* SERVO_DEFAULT_MAX_PW = 2400.
*
* @param minAngle Target angle (in degrees) associated with
* minPulseWidth. Defaults to
* SERVO_DEFAULT_MIN_ANGLE = 0.
*
* @param maxAngle Target angle (in degrees) associated with
* maxPulseWidth. Defaults to
* SERVO_DEFAULT_MAX_ANGLE = 180.
*
* @sideeffect May set pinMode(pin, PWM).
*
* @return true if successful, false when pin doesn't support PWM.
*/
bool attach(uint8 pin,
uint16 minPulseWidth=MIN_PULSE_WIDTH,
uint16 maxPulseWidth=MAX_PULSE_WIDTH,
int16 minAngle=MIN_ANGLE,
int16 maxAngle=MAX_ANGLE);
/**
* @brief Stop driving the servo pulse train.
*
* If not currently attached to a motor, this function has no effect.
*
* @return true if this call did anything, false otherwise.
*/
bool detach();
/**
* @brief Set the servomotor target angle.
*
* @param angle Target angle, in degrees. If the target angle is
* outside the range specified at attach() time, it
* will be clamped to lie in that range.
*
* @see Servo::attach()
*/
void write(int angle);
/**
* @brief Set the pulse width, in microseconds.
*
* @param pulseWidth Pulse width to send to the servomotor, in
* microseconds. If outside of the range
* specified at attach() time, it is clamped to
* lie in that range.
*
* @see Servo::attach()
*/
void writeMicroseconds(uint16 pulseWidth);
/**
* Get the servomotor's target angle, in degrees. This will
* lie inside the range specified at attach() time.
*
* @see Servo::attach()
*/
int read() const;
/**
* Get the current pulse width, in microseconds. This will
* lie within the range specified at attach() time.
*
* @see Servo::attach()
*/
uint16 readMicroseconds() const;
/**
* @brief Check if this instance is attached to a servo.
* @return true if this instance is attached to a servo, false otherwise.
* @see Servo::attachedPin()
*/
bool attached() const { return this->pin != NOT_ATTACHED; }
/**
* @brief Get the pin this instance is attached to.
* @return Pin number if currently attached to a pin, NOT_ATTACHED
* otherwise.
* @see Servo::attach()
*/
int attachedPin() const { return this->pin; }
private:
int16 pin;
uint16 minPW;
uint16 maxPW;
int16 minAngle;
int16 maxAngle;
void resetFields(void);
};
#endif /* _SERVO_H_ */

View file

@ -37,7 +37,7 @@ void setup(void)
while (!SERIAL_PORT_MONITOR); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
SERIAL_PORT_MONITOR.println("\r\nADK demo start");
if (usb.Init() == (uint32_t)-1)
if (usb.Init() == -1)
SERIAL_PORT_MONITOR.println("OSC did not start.");
delay(20);

View file

@ -83,7 +83,8 @@ void setup()
{
SerialDebug.begin( 115200 );
SerialDebug.println("USB Host Keyboard Controller Program started");
if (usb.Init() == (uint32_t)-1)
if (usb.Init() == -1)
SerialDebug.println("USB Host did not start.");
SerialDebug.println("USB Host started");

View file

@ -91,7 +91,7 @@ void setup()
SerialDebug.begin( 115200 );
SerialDebug.println("USB Host Mouse Controller Program started");
if (usb.Init() == (uint32_t)-1)
if (usb.Init() == -1)
SerialDebug.println("USB Host did not start.");
SerialDebug.println("USB Host started");

View file

@ -59,8 +59,8 @@ void setup()
SerialDebug.println("Starting USB Descriptor test");
SerialDebug.println("Initializing USB");
if (usb.Init() == (uint32_t)-1)
SerialDebug.println("USBhost did not start.");
if (usb.Init() == -1)
SerialDebug.println("USBhost did not start.");
delay( 20 );
@ -161,7 +161,6 @@ byte getdevdescr( byte addr, byte &num_conf )
void printhubdescr(uint8_t *descrptr, uint8_t addr)
{
(void)addr;
HubDescriptor *pHub = (HubDescriptor*) descrptr;
uint8_t len = *((uint8_t*)descrptr);
@ -210,11 +209,10 @@ byte getconfdescr( byte addr, byte conf )
{
uint8_t buf[ BUFSIZE ];
uint8_t* buf_ptr = buf;
byte rcode; // FIXME -- code does not actually check return code (no error handling!)
byte rcode;
byte descr_length;
byte descr_type;
uint16_t total_length;
// FIXME -- no check of return code from usb.getConfDescr()
rcode = usb.getConfDescr( addr, 0, 4, conf, buf ); //get total length
LOBYTE( total_length ) = buf[ 2 ];
HIBYTE( total_length ) = buf[ 3 ];
@ -222,7 +220,6 @@ byte getconfdescr( byte addr, byte conf )
printProgStr(Conf_Trunc_str);
total_length = sizeof(buf);
}
// FIXME -- no check of return code from usb.getConfDescr()
rcode = usb.getConfDescr( addr, 0, total_length, conf, buf ); //get the whole descriptor
while( buf_ptr < buf + total_length ) { //parsing descriptors
descr_length = *( buf_ptr );
@ -385,4 +382,3 @@ void printProgStr(const prog_char str[])
if(!str) return;
while((c = pgm_read_byte(str++)))
SerialDebug.print(c);
}

View file

@ -59,15 +59,15 @@ class ConfigDescParser : public USBReadParser {
uint32_t ifaceNumber; // Interface number
uint32_t ifaceAltSet; // Interface alternate settings
bool UseOr;
bool UseOr;
bool ParseDescriptor(uint8_t **pp, uint32_t *pcntdn);
void PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc);
public:
void SetOR(void) {
UseOr = true;
}
void SetOR(void) {
UseOr = true;
}
ConfigDescParser(UsbConfigXtracter *xtractor);
virtual void Parse(const uint32_t len, const uint8_t *pbuf, const uint32_t &offset);
};
@ -98,19 +98,8 @@ void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::Parse(const uin
compare masks for them. When the match is found, calls EndpointXtract passing buffer containing endpoint descriptor */
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor(uint8_t **pp, uint32_t *pcntdn) {
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
#pragma GCC diagnostic push // Available since GCC 4.6.4
/*
* FIXME -- Enabled and review all `-Wimplicit-fallthrough` messages
* This code has multiple switch statements that "fall through" to the
* next case -- but it's not always clear if this is intentional or not.
* Review and commenting of code, and reducing cyclomatic complexity
* are highly recommended....
*/
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
USB_CONFIGURATION_DESCRIPTOR* ucd = reinterpret_cast<USB_CONFIGURATION_DESCRIPTOR*>(varBuffer);
USB_INTERFACE_DESCRIPTOR* uid = reinterpret_cast<USB_INTERFACE_DESCRIPTOR*>(varBuffer);
switch(stateParseDescr) {
case 0:
theBuffer.valueSize = 2;
@ -123,7 +112,7 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
dscrType = *((uint8_t*)theBuffer.pValue + 1);
stateParseDescr = 2;
case 2:
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
// This is a sort of hack. Assuming that two bytes are all ready in the buffer
// the pointer is positioned two bytes ahead in order for the rest of descriptor
// to be read right after the size and the type fields.
// This should be used carefully. varBuffer should be used directly to handle data
@ -131,14 +120,14 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
theBuffer.pValue = varBuffer + 2;
stateParseDescr = 3;
case 3:
switch(dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
case USB_DESCRIPTOR_CONFIGURATION:
theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2;
break;
case USB_DESCRIPTOR_ENDPOINT:
theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2;
switch(dscrType) {
case USB_DESCRIPTOR_INTERFACE:
isGoodInterface = false;
case USB_DESCRIPTOR_CONFIGURATION:
theBuffer.valueSize = sizeof (USB_CONFIGURATION_DESCRIPTOR) - 2;
break;
case USB_DESCRIPTOR_ENDPOINT:
theBuffer.valueSize = sizeof (USB_ENDPOINT_DESCRIPTOR) - 2;
break;
case HID_DESCRIPTOR_HID:
theBuffer.valueSize = dscrLen - 2;
@ -147,37 +136,37 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
valParser.Initialize(&theBuffer);
stateParseDescr = 4;
case 4:
switch(dscrType) {
switch(dscrType) {
case USB_DESCRIPTOR_CONFIGURATION:
if(!valParser.Parse(pp, pcntdn))
return false;
confValue = ucd->bConfigurationValue;
if(!valParser.Parse(pp, pcntdn))
return false;
confValue = ucd->bConfigurationValue;
break;
case USB_DESCRIPTOR_INTERFACE:
if(!valParser.Parse(pp, pcntdn))
return false;
if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
break;
if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
break;
if(UseOr) {
if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
break;
} else {
if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
break;
}
isGoodInterface = true;
ifaceNumber = uid->bInterfaceNumber;
ifaceAltSet = uid->bAlternateSetting;
protoValue = uid->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if(!valParser.Parse(pp, pcntdn))
return false;
if(isGoodInterface)
if(theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
if(!valParser.Parse(pp, pcntdn))
return false;
if((MASK & CP_MASK_COMPARE_CLASS) && uid->bInterfaceClass != CLASS_ID)
break;
if((MASK & CP_MASK_COMPARE_SUBCLASS) && uid->bInterfaceSubClass != SUBCLASS_ID)
break;
if(UseOr) {
if((!((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol)))
break;
} else {
if((MASK & CP_MASK_COMPARE_PROTOCOL) && uid->bInterfaceProtocol != PROTOCOL_ID)
break;
}
isGoodInterface = true;
ifaceNumber = uid->bInterfaceNumber;
ifaceAltSet = uid->bAlternateSetting;
protoValue = uid->bInterfaceProtocol;
break;
case USB_DESCRIPTOR_ENDPOINT:
if(!valParser.Parse(pp, pcntdn))
return false;
if(isGoodInterface)
if(theXtractor)
theXtractor->EndpointXtract(confValue, ifaceNumber, ifaceAltSet, protoValue, (USB_ENDPOINT_DESCRIPTOR*)varBuffer);
break;
//case HID_DESCRIPTOR_HID:
// if (!valParser.Parse(pp, pcntdn))
@ -191,47 +180,44 @@ bool ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::ParseDescriptor
theBuffer.pValue = varBuffer;
stateParseDescr = 0;
}
#pragma GCC diagnostic pop
return true;
}
template <const uint8_t CLASS_ID, const uint8_t SUBCLASS_ID, const uint8_t PROTOCOL_ID, const uint8_t MASK>
void ConfigDescParser<CLASS_ID, SUBCLASS_ID, PROTOCOL_ID, MASK>::PrintHidDescriptor(const USB_HID_DESCRIPTOR *pDesc) {
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\n\r\nHID Descriptor:\r\n"), 0x80);
Notify(PSTR("bDescLength:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bLength, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbDescriptorType:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bDescriptorType, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbcdHID:\t\t\t"), 0x80);
PrintHex<uint16_t > (pDesc->bcdHID, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbCountryCode:\t\t"), 0x80);
PrintHex<uint8_t > (pDesc->bCountryCode, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
Notify(PSTR("\r\nbNumDescriptors:\t"), 0x80);
PrintHex<uint8_t > (pDesc->bNumDescriptors, 0x80);
//Notify(PSTR("\r\nbDescrType:\t\t"));
//PrintHex<uint8_t>(pDesc->bDescrType);
//
//Notify(PSTR("\r\nwDescriptorLength:\t"));
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
//Notify(PSTR("\r\nbDescrType:\t\t"));
//PrintHex<uint8_t>(pDesc->bDescrType);
//
//Notify(PSTR("\r\nwDescriptorLength:\t"));
//PrintHex<uint16_t>(pDesc->wDescriptorLength);
for (uint32_t i = 0; i < pDesc->bNumDescriptors; i++) {
HID_CLASS_DESCRIPTOR_LEN_AND_TYPE *pLT = (HID_CLASS_DESCRIPTOR_LEN_AND_TYPE*)&(pDesc->bDescrType);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nbDescrType:\t\t"), 0x80);
PrintHex<uint8_t > (pLT[i].bDescrType, 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"), 0x80);
Notify(PSTR("\r\nwDescriptorLength:\t"), 0x80);
PrintHex<uint16_t > (pLT[i].wDescriptorLength, 0x80);
}
Notify(PSTR("\r\n"), 0x80);
}
#endif // __CONFDESCPARSER_H__

View file

@ -994,6 +994,7 @@ void ReportDescParserBase::Parse(const uint32_t len, const uint8_t *pbuf, const
uint32_t cntdn = (uint32_t)len;
uint8_t *p = (uint8_t*)pbuf;
totalSize = 0;
while(cntdn) {
@ -1090,17 +1091,6 @@ void ReportDescParserBase::PrintItemTitle(uint8_t prefix) {
uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint32_t *pcntdn) {
//uint8_t ret = enErrorSuccess;
//reinterpret_cast<>(varBuffer);
#pragma GCC diagnostic push // Available since GCC 4.6.4
/*
* FIXME -- Enabled and review all `-Wimplicit-fallthrough` messages
* This code has multiple switch statements that "fall through" to the
* next case -- but it's not always clear if this is intentional or not.
* Review and commenting of code, and reducing cyclomatic complexity
* are highly recommended....
*/
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
switch(itemParseState) {
case 0:
if(**pp == HID_LONG_ITEM_PREFIX)
@ -1217,7 +1207,6 @@ uint8_t ReportDescParserBase::ParseItem(uint8_t **pp, uint32_t *pcntdn) {
} // switch (**pp & (TYPE_MASK | TAG_MASK))
}
} // switch (itemParseState)
#pragma GCC diagnostic pop
itemParseState = 0;
return enErrorSuccess;
}
@ -1247,18 +1236,18 @@ void ReportDescParserBase::SetUsagePage(uint16_t page) {
if(VALUE_BETWEEN(page, 0x00, 0x11))
pfUsage = (usagePageFunctions[page - 1]);
// Dead code...
//
// pfUsage = (UsagePageFunc)pgm_read_pointer(usagePageFunctions[page - 1]);
//else if (page > 0x7f && page < 0x84)
// E_Notify(pstrUsagePageMonitor);
//else if (page > 0x83 && page < 0x8c)
// E_Notify(pstrUsagePagePower);
//else if (page > 0x8b && page < 0x92)
// E_Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]));
//else if (page > 0xfeff && page <= 0xffff)
// E_Notify(pstrUsagePageVendorDefined);
//
// Dead code...
//
// pfUsage = (UsagePageFunc)pgm_read_pointer(usagePageFunctions[page - 1]);
//else if (page > 0x7f && page < 0x84)
// E_Notify(pstrUsagePageMonitor);
//else if (page > 0x83 && page < 0x8c)
// E_Notify(pstrUsagePagePower);
//else if (page > 0x8b && page < 0x92)
// E_Notify((char*)pgm_read_pointer(&usagePageTitles1[page - 0x8c]));
//else if (page > 0xfeff && page <= 0xffff)
// E_Notify(pstrUsagePageVendorDefined);
//
else
switch(page) {
case 0x14:
@ -1451,15 +1440,6 @@ void ReportDescParserBase::PrintMedicalInstrumentPageUsage(uint16_t usage) {
uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint32_t *pcntdn) {
//uint8_t ret = enErrorSuccess;
#pragma GCC diagnostic push // Available since GCC 4.6.4
/*
* FIXME -- Enabled and review all `-Wimplicit-fallthrough` messages
* This code has multiple switch statements that "fall through" to the
* next case -- but it's not always clear if this is intentional or not.
* Review and commenting of code, and reducing cyclomatic complexity
* are highly recommended....
*/
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
switch(itemParseState) {
case 0:
if(**pp == HID_LONG_ITEM_PREFIX)
@ -1539,8 +1519,6 @@ uint8_t ReportDescParser2::ParseItem(uint8_t **pp, uint32_t *pcntdn) {
} // switch (**pp & (TYPE_MASK | TAG_MASK))
}
} // switch (itemParseState)
#pragma GCC diagnostic pop
itemParseState = 0;
return enErrorSuccess;
}
@ -1580,7 +1558,8 @@ void ReportDescParser2::OnInputItem(uint8_t itm) {
// bits_to_copy - number of bits to copy to result buffer
// for each bit in a field
for(uint8_t bits_left = rptSize, bits_to_copy = 0; bits_left; bits_left -= bits_to_copy) {
for(uint8_t bits_left = rptSize, bits_to_copy = 0; bits_left;
bits_left -= bits_to_copy) {
bits_to_copy = (bits_left > bits_of_byte) ? bits_of_byte : bits_left;
result.dwResult <<= bits_to_copy; // Result buffer is shifted by the number of bits to be copied into it

View file

@ -17,14 +17,14 @@ e-mail : support@circuitsathome.com
#include "Usb.h"
bool MultiByteValueParser::Parse(uint8_t **pp, uint32_t *pcntdn) {
if(!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
if(!pBuf) {
Notify(PSTR("Buffer pointer is NULL!\r\n"), 0x80);
return false;
}
for (; countDown && (*pcntdn); countDown--, (*pcntdn)--, (*pp)++)
pBuf[valueSize - countDown] = (**pp);
if(countDown)
if(countDown)
return false;
countDown = valueSize;
@ -32,48 +32,36 @@ bool MultiByteValueParser::Parse(uint8_t **pp, uint32_t *pcntdn) {
}
bool PTPListParser::Parse(uint8_t **pp, uint32_t *pcntdn, PTP_ARRAY_EL_FUNC pf, const void *me) {
switch(nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
#pragma GCC diagnostic push // Available since GCC 4.6.4
/*
* FIXME -- Enabled and review all `-Wimplicit-fallthrough` messages
* This code has multiple switch statements that "fall through" to the
* next case -- but it's not always clear if this is intentional or not.
* Review and commenting of code, and reducing cyclomatic complexity
* are highly recommended....
*/
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
case 1:
if(!theParser.Parse(pp, pcntdn))
return false;
switch(nStage) {
case 0:
pBuf->valueSize = lenSize;
theParser.Initialize(pBuf);
nStage = 1;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
case 1:
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 3:
for(; arLenCntdn; arLenCntdn--) {
if(!theParser.Parse(pp, pcntdn))
return false;
arLen = 0;
arLen = (pBuf->valueSize >= 4) ? *((uint32_t*)pBuf->pValue) : (uint32_t)(*((uint16_t*)pBuf->pValue));
arLenCntdn = arLen;
nStage = 2;
case 2:
pBuf->valueSize = valSize;
theParser.Initialize(pBuf);
nStage = 3;
case 3:
for(; arLenCntdn; arLenCntdn--) {
if(!theParser.Parse(pp, pcntdn))
return false;
if(pf)
pf(pBuf, (arLen - arLenCntdn), me);
}
nStage = 0;
}
#pragma GCC diagnostic pop
return true;
}

View file

@ -35,12 +35,12 @@ class MultiByteValueParser {
public:
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
MultiByteValueParser() : pBuf(NULL), countDown(0), valueSize(0) {
};
const uint8_t* GetBuffer() {
return pBuf;
};
const uint8_t* GetBuffer() {
return pBuf;
};
void Initialize(MultiValueBuffer * const pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
@ -58,7 +58,7 @@ class ByteSkipper {
public:
ByteSkipper() : pBuf(NULL), nStage(0), countDown(0) {
};
};
void Initialize(MultiValueBuffer *pbuf) {
pBuf = (uint8_t*)pbuf->pValue;
@ -66,25 +66,16 @@ public:
};
bool Skip(uint8_t **pp, uint32_t *pcntdn, uint32_t bytes_to_skip) {
#pragma GCC diagnostic push // Available since GCC 4.6.4
/*
* FIXME -- Enabled and review all `-Wimplicit-fallthrough` messages
* This code has multiple switch statements that "fall through" to the
* next case -- but it's not always clear if this is intentional or not.
* Review and commenting of code, and reducing cyclomatic complexity
* are highly recommended....
*/
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
switch(nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if(!countDown)
nStage = 0;
switch(nStage) {
case 0:
countDown = bytes_to_skip;
nStage++;
case 1:
for(; countDown && (*pcntdn); countDown--, (*pp)++, (*pcntdn)--);
if(!countDown)
nStage = 0;
};
#pragma GCC diagnostic pop
return (!countDown);
};
};
@ -95,9 +86,9 @@ typedef void (*PTP_ARRAY_EL_FUNC)(const MultiValueBuffer * const p, uint32_t cou
class PTPListParser {
public:
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
enum ParseMode {
modeArray, modeRange/*, modeEnum*/
};
private:
uint32_t nStage;

View file

@ -287,13 +287,6 @@ void TwoWire::onService(void)
void WIRE_IT_HANDLER(void) {
Wire.onService();
}
#if defined(__SAMD51__)
void WIRE_IT_HANDLER_0(void) { Wire.onService(); }
void WIRE_IT_HANDLER_1(void) { Wire.onService(); }
void WIRE_IT_HANDLER_2(void) { Wire.onService(); }
void WIRE_IT_HANDLER_3(void) { Wire.onService(); }
#endif // __SAMD51__
#endif
#if WIRE_INTERFACES_COUNT > 1
@ -302,13 +295,6 @@ void TwoWire::onService(void)
void WIRE1_IT_HANDLER(void) {
Wire1.onService();
}
#if defined(__SAMD51__)
void WIRE1_IT_HANDLER_0(void) { Wire1.onService(); }
void WIRE1_IT_HANDLER_1(void) { Wire1.onService(); }
void WIRE1_IT_HANDLER_2(void) { Wire1.onService(); }
void WIRE1_IT_HANDLER_3(void) { Wire1.onService(); }
#endif // __SAMD51__
#endif
#if WIRE_INTERFACES_COUNT > 2
@ -317,13 +303,6 @@ void TwoWire::onService(void)
void WIRE2_IT_HANDLER(void) {
Wire2.onService();
}
#if defined(__SAMD51__)
void WIRE2_IT_HANDLER_0(void) { Wire2.onService(); }
void WIRE2_IT_HANDLER_1(void) { Wire2.onService(); }
void WIRE2_IT_HANDLER_2(void) { Wire2.onService(); }
void WIRE2_IT_HANDLER_3(void) { Wire2.onService(); }
#endif // __SAMD51__
#endif
#if WIRE_INTERFACES_COUNT > 3
@ -332,13 +311,6 @@ void TwoWire::onService(void)
void WIRE3_IT_HANDLER(void) {
Wire3.onService();
}
#if defined(__SAMD51__)
void WIRE3_IT_HANDLER_0(void) { Wire3.onService(); }
void WIRE3_IT_HANDLER_1(void) { Wire3.onService(); }
void WIRE3_IT_HANDLER_2(void) { Wire3.onService(); }
void WIRE3_IT_HANDLER_3(void) { Wire3.onService(); }
#endif // __SAMD51__
#endif
#if WIRE_INTERFACES_COUNT > 4
@ -347,13 +319,6 @@ void TwoWire::onService(void)
void WIRE4_IT_HANDLER(void) {
Wire4.onService();
}
#if defined(__SAMD51__)
void WIRE4_IT_HANDLER_0(void) { Wire4.onService(); }
void WIRE4_IT_HANDLER_1(void) { Wire4.onService(); }
void WIRE4_IT_HANDLER_2(void) { Wire4.onService(); }
void WIRE4_IT_HANDLER_3(void) { Wire4.onService(); }
#endif // __SAMD51__
#endif
#if WIRE_INTERFACES_COUNT > 5
@ -362,12 +327,5 @@ void TwoWire::onService(void)
void WIRE5_IT_HANDLER(void) {
Wire5.onService();
}
#if defined(__SAMD51__)
void WIRE5_IT_HANDLER_0(void) { Wire5.onService(); }
void WIRE5_IT_HANDLER_1(void) { Wire5.onService(); }
void WIRE5_IT_HANDLER_2(void) { Wire5.onService(); }
void WIRE5_IT_HANDLER_3(void) { Wire5.onService(); }
#endif // __SAMD51__
#endif

View file

@ -28,8 +28,6 @@ void loop()
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
(void)howMany; // avoid compiler warning about unused parameter
while(1 < Wire.available()) // loop through all but the last
{
char c = Wire.read(); // receive byte as a character

View file

@ -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.6.3
version=1.4.1
# Compile variables
# -----------------
@ -28,13 +28,13 @@ version=1.6.3
compiler.warning_flags=-w
compiler.warning_flags.none=-w
compiler.warning_flags.default=
compiler.warning_flags.more=-Wall -Wno-expansion-to-defined
compiler.warning_flags.all=-Wall -Wextra -Wno-expansion-to-defined
compiler.warning_flags.more=-Wall
compiler.warning_flags.all=-Wall -Wextra
compiler.path={runtime.tools.arm-none-eabi-gcc.path}/bin/
compiler.c.cmd=arm-none-eabi-gcc
compiler.c.flags=-mcpu={build.mcu} -mthumb -c -g -Os {compiler.warning_flags} -std=gnu11 -ffunction-sections -fdata-sections -nostdlib --param max-inline-insns-single=500 -MMD -D__SKETCH_NAME__="""{build.project_name}"""
compiler.c.elf.cmd=arm-none-eabi-g++
compiler.c.elf.cmd=arm-none-eabi-gcc
compiler.c.elf.flags=-Os -Wl,--gc-sections -save-temps
compiler.S.cmd=arm-none-eabi-gcc
compiler.S.flags=-c -g -x assembler-with-cpp -MMD
@ -44,13 +44,11 @@ compiler.ar.cmd=arm-none-eabi-ar
compiler.ar.flags=rcs
compiler.objcopy.cmd=arm-none-eabi-objcopy
compiler.objcopy.eep.flags=-O ihex -j .eeprom --set-section-flags=.eeprom=alloc,load --no-change-warnings --change-section-lma .eeprom=0
compiler.elf2hex.bin.flags=-O binary
compiler.elf2hex.hex.flags=-O ihex -R .eeprom
compiler.elf2hex.flags=-O binary
compiler.elf2hex.cmd=arm-none-eabi-objcopy
compiler.ldflags=-mcpu={build.mcu} -mthumb -Wl,--cref -Wl,--check-sections -Wl,--gc-sections -Wl,--unresolved-symbols=report-all -Wl,--warn-common -Wl,--warn-section-align
compiler.size.cmd=arm-none-eabi-size
compiler.define=-DARDUINO=
compiler.readelf.cmd=arm-none-eabi-readelf
# this can be overriden in boards.txt
build.extra_flags=
@ -58,8 +56,6 @@ build.cache_flags=
build.flags.optimize=
build.flags.maxspi=
build.flags.maxqspi=
build.flags.usbstack=
build.flags.debug=
# These can be overridden in platform.local.txt
compiler.c.extra_flags=
@ -70,17 +66,12 @@ compiler.S.extra_flags=
compiler.ar.extra_flags=
compiler.elf2hex.extra_flags=
compiler.arm.cmsis.c.flags="-I{runtime.tools.CMSIS-5.4.0.path}/CMSIS/Core/Include/" "-I{runtime.tools.CMSIS-5.4.0.path}/CMSIS/DSP/Include/" "-I{runtime.tools.CMSIS-Atmel-1.2.0.path}/CMSIS/Device/ATMEL/"
compiler.arm.cmsis.ldflags="-L{runtime.tools.CMSIS-5.4.0.path}/CMSIS/Lib/GCC/" -larm_cortexM0l_math
compiler.libraries.ldflags=
compiler.arm.cmsis.c.flags="-I{runtime.tools.CMSIS-4.5.0.path}/CMSIS/Include/" "-I{runtime.tools.CMSIS-Atmel-1.2.0.path}/CMSIS/Device/ATMEL/"
compiler.arm.cmsis.ldflags="-L{runtime.tools.CMSIS-4.5.0.path}/CMSIS/Lib/GCC/" -larm_cortexM0l_math
# USB Flags
# ---------
build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON -DUSB_CONFIG_POWER={build.usb_power} '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}' {build.flags.usbstack} {build.flags.debug} "-I{build.core.path}/TinyUSB" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore" "-I{build.core.path}/TinyUSB/Adafruit_TinyUSB_ArduinoCore/tinyusb/src"
# Default advertised device power setting in mA
build.usb_power=100
build.usb_flags=-DUSB_VID={build.vid} -DUSB_PID={build.pid} -DUSBCON '-DUSB_MANUFACTURER={build.usb_manufacturer}' '-DUSB_PRODUCT={build.usb_product}'
# Default usb manufacturer will be replaced at compile time using
# numeric vendor ID if available or by board's specific value.
@ -91,44 +82,41 @@ build.usb_manufacturer="Unknown"
# ----------------
## Compile c files
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cache_flags} {build.flags.debug} {build.flags.optimize} {build.flags.maxspi} {build.flags.maxqspi} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}"
recipe.c.o.pattern="{compiler.path}{compiler.c.cmd}" {compiler.c.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.c.extra_flags} {build.extra_flags} {build.cache_flags} {build.flags.optimize} {build.flags.maxspi} {build.flags.maxqspi} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}"
## Compile c++ files
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cache_flags} {build.flags.debug} {build.flags.optimize} {build.flags.maxspi} {build.flags.maxqspi} {build.extra_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}"
recipe.cpp.o.pattern="{compiler.path}{compiler.cpp.cmd}" {compiler.cpp.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.cpp.extra_flags} {build.extra_flags} {build.cache_flags} {build.flags.optimize} {build.flags.maxspi} {build.flags.maxqspi} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}"
## Compile S files
recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} -DF_CPU={build.f_cpu} -DARDUINO={runtime.ide.version} -DARDUINO_{build.board} -DARDUINO_ARCH_{build.arch} {compiler.S.extra_flags} {build.extra_flags} {build.cache_flags} {compiler.arm.cmsis.c.flags} {includes} "{source_file}" -o "{object_file}"
## Create archives
# archive_file_path is needed for backwards compatibility with IDE 1.6.5 or older, IDE 1.6.6 or newer overrides this value
archive_file_path={build.path}/{archive_file}
recipe.ar.pattern="{compiler.path}{compiler.ar.cmd}" {compiler.ar.flags} {compiler.ar.extra_flags} "{archive_file_path}" "{object_file}"
## Combine gc-sections, archives, and objects
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} {compiler.libraries.ldflags} -Wl,--start-group {compiler.arm.cmsis.ldflags} "-L{build.variant.path}" -lm "{build.path}/{archive_file}" -Wl,--end-group
recipe.c.combine.pattern="{compiler.path}{compiler.c.elf.cmd}" "-L{build.path}" {compiler.c.elf.flags} {compiler.c.elf.extra_flags} "-T{build.variant.path}/{build.ldscript}" "-Wl,-Map,{build.path}/{build.project_name}.map" --specs=nano.specs --specs=nosys.specs {compiler.ldflags} -o "{build.path}/{build.project_name}.elf" {object_files} -Wl,--start-group {compiler.arm.cmsis.ldflags} "-L{build.variant.path}" -lm "{build.path}/{archive_file}" -Wl,--end-group
## Create output (bin file)
recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.bin.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin"
## Create output (hex file)
recipe.objcopy.hex.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.hex"
build.preferred_out_format=bin
recipe.objcopy.bin.pattern="{compiler.path}{compiler.elf2hex.cmd}" {compiler.elf2hex.flags} {compiler.elf2hex.extra_flags} "{build.path}/{build.project_name}.elf" "{build.path}/{build.project_name}.bin"
## Save hex
recipe.output.tmp_file={build.project_name}.{build.preferred_out_format}
recipe.output.save_file={build.project_name}.{build.variant}.{build.preferred_out_format}
recipe.output.tmp_file={build.project_name}.bin
recipe.output.save_file={build.project_name}.{build.variant}.bin
## Compute size
recipe.size.pattern="{compiler.path}{compiler.size.cmd}" -A "{build.path}/{build.project_name}.elf"
recipe.size.regex=\.text\s+([0-9]+).*
# Uploader tools
# --------------
#
# BOSSA
#
tools.bossac.path={runtime.tools.bossac-1.7.0-arduino3.path}
tools.bossac.path={runtime.tools.bossac-1.7.0.path}
tools.bossac.cmd=bossac
tools.bossac.cmd.windows=bossac.exe
tools.bossac.upload.params.verbose=-i -d
tools.bossac.upload.params.quiet=
@ -151,68 +139,48 @@ tools.bossac18.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.por
tools.bossac18.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA
tools.bossac18.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b
#
# BOSSA (ignore binary size)
#
tools.bossacI.path={runtime.tools.bossac-1.7.0-arduino3.path}
tools.bossacI.cmd=bossac
tools.bossacI.cmd.windows=bossac.exe
tools.bossacI.upload.params.verbose=-i -d
tools.bossacI.upload.params.quiet=
tools.bossacI.upload.pattern="{path}/{cmd}" {upload.verbose} --port={serial.port.file} -I -U {upload.native_usb} -i -e -w "{build.path}/{build.project_name}.bin" -R
tools.bossacI_remote.upload.pattern=/usr/bin/run-bossac {upload.verbose} --port=ttyATH0 -U {upload.native_usb} -e -w -v /tmp/sketch.bin -R
tools.bossacI.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA
tools.bossacI.upload.network_pattern="{network_cmd}" -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b
#
# OpenOCD sketch upload
#
tools.openocd.path={runtime.tools.openocd-0.10.0-arduino7.path}
tools.openocd.path={runtime.tools.openocd.path}
tools.openocd.cmd=bin/openocd
tools.openocd.cmd.windows=bin/openocd.exe
tools.openocd.upload.params.verbose=-d2
tools.openocd.upload.params.quiet=-d0
tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.bin} verify reset 0x2000; shutdown"
tools.openocd.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.bin}} verify reset 0x00002000; shutdown"
tools.openocd.network_cmd={runtime.tools.arduinoOTA.path}/bin/arduinoOTA
tools.openocd.upload.network_pattern={network_cmd} -address {serial.port} -port 65280 -username arduino -password "{network.password}" -sketch "{build.path}/{build.project_name}.bin" -upload /sketch -b
# Program flashes the binary at 0x0000, so use the linker script without_bootloader
tools.openocd.program.params.verbose=-d2
tools.openocd.program.params.quiet=-d0
tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.elf} verify reset; shutdown"
tools.openocd.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.elf}} verify reset; shutdown"
tools.openocd.erase.params.verbose=-d3
tools.openocd.erase.params.quiet=-d0
tools.openocd.erase.pattern=
tools.openocd.bootloader.params.verbose=-d2
tools.openocd.bootloader.params.verbose=-d3
tools.openocd.bootloader.params.quiet=-d0
tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown"
tools.openocd.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f interface/{program.protocol}.cfg -c "{program.setup_command}" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{{runtime.platform.path}/bootloaders/{bootloader.file}}} verify reset; shutdown"
#
# OpenOCD sketch upload - version with configurable bootloader size
# FIXME: this programmer is a workaround for default options being overwritten by uploadUsingPreferences
#
tools.openocd-withbootsize.path={runtime.tools.openocd-0.10.0-arduino7.path}
tools.openocd-withbootsize.path={runtime.tools.openocd-0.9.0-arduino.path}
tools.openocd-withbootsize.cmd=bin/openocd
tools.openocd-withbootsize.cmd.windows=bin/openocd.exe
tools.openocd-withbootsize.upload.params.verbose=-d2
tools.openocd-withbootsize.upload.params.quiet=-d0
tools.openocd-withbootsize.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.bin} verify reset {bootloader.size}; shutdown"
tools.openocd-withbootsize.upload.pattern="{path}/{cmd}" {upload.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.bin}} verify reset {bootloader.size}; shutdown"
# Program flashes the binary at 0x0000, so use the linker script without_bootloader
tools.openocd-withbootsize.program.params.verbose=-d2
tools.openocd-withbootsize.program.params.quiet=-d0
tools.openocd-withbootsize.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{build.path}/{build.project_name}.elf} verify reset; shutdown"
tools.openocd-withbootsize.program.pattern="{path}/{cmd}" {program.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; program {{{build.path}/{build.project_name}.elf}} verify reset; shutdown"
tools.openocd-withbootsize.erase.params.verbose=-d3
tools.openocd-withbootsize.erase.params.quiet=-d0
@ -220,4 +188,4 @@ tools.openocd-withbootsize.erase.pattern=
tools.openocd-withbootsize.bootloader.params.verbose=-d2
tools.openocd-withbootsize.bootloader.params.quiet=-d0
tools.openocd-withbootsize.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{runtime.platform.path}/bootloaders/{bootloader.file}} verify reset; shutdown"
tools.openocd-withbootsize.bootloader.pattern="{path}/{cmd}" {bootloader.verbose} -s "{path}/share/openocd/scripts/" -f "{runtime.platform.path}/variants/{build.variant}/{build.openocdscript}" -c "telnet_port disabled; init; halt; at91samd bootloader 0; program {{{runtime.platform.path}/bootloaders/{bootloader.file}}} verify reset; shutdown"

View file

@ -1,31 +0,0 @@
#
# Arduino Zero OpenOCD script.
#
# Copyright (c) 2014-2015 Arduino LLC. All right reserved.
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
#
# Define 'reset' command
define reset
info reg
break main
# End of 'reset' command
end
target remote | openocd -c "interface cmsis-dap" -c "set CHIPNAME at91samd21g18" -f target/at91samdXX.cfg -c "gdb_port pipe; log_output openocd.log"

Some files were not shown because too many files have changed in this diff Show more