Category: Blog

  • tutorial-rails6-1

    Tutorial Rails 6 – Simple Project Management

    First tutorial of Ruby on Rails 6

    Note:

    • I am use a Bootstrap 5.
    • To install Fontawesome I use yarn.
    • In drag & drop task, only the grip icon enable the action.
    • Added changes between the part 2 and part 3 outside tutorial.
    • I tried remove the code “case” in the model.

    App

    Simple project management app

    Features

    • User authentication
    • Project management
    • Project task management
    • Drag & drop for ordering the tasks

    Documentation

    All documentation it is inside of our wiki.

    Deployment

    First you have to download the repository

    git clone https://github.com/demiancy/tutorial-rails6-1.git
    

    The repository have the files for deploy app in Docker, with the next command you start the app in the port 3000

    docker-compose up
    

    In case of not have Docker, you can copy the folder app into document root of your server

    Screenshots

    Screenshot 1 Screenshot 2

    Visit original content creator repository https://github.com/demiancy/tutorial-rails6-1
  • SAMD_PWM

    SAMD_PWM Library

    arduino-library-badge GitHub release GitHub contributions welcome GitHub issues

    Donate to my libraries using BuyMeACoffee



    Table of Contents



    Why do we need this SAMD_PWM library

    Features

    This hardware-based PWM library enables you to use Hardware-PWM on SAMD21/SAMD51 boards such as NANO_33_IOT, ITSYBITSY_M4, SEEED_XIAO_M0, SparkFun SAMD51_Thing_Plus, etc., to create and output PWM. These purely hardware-based PWM channels can generate very high PWM frequencies, depending on CPU clock and acceptable accuracy. The maximum resolution can be 16-bit for better accuracy when using Timer TCCx. With Timer TCx, only 8-bit resolution is supported with lower accuracy.

    This library is using the same or similar functions as other FastPWM sibling libraries, as follows, to enable you to port your PWM code easily between platforms

    1. RP2040_PWM
    2. AVR_PWM
    3. megaAVR_PWM
    4. ESP32_FastPWM
    5. SAMD_PWM
    6. SAMDUE_PWM
    7. nRF52_PWM
    8. Teensy_PWM
    9. ATtiny_PWM
    10. Dx_PWM
    11. Portenta_H7_PWM
    12. MBED_RP2040_PWM
    13. nRF52_MBED_PWM
    14. STM32_PWM

    The most important feature is they’re purely hardware-based PWM channels. Therefore, their operations are not blocked by bad-behaving software functions / tasks.

    This important feature is absolutely necessary for mission-critical tasks. These hardware PWM-channels, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That’s necessary if you need to control external systems (Servo, etc.) requiring better accuracy.

    New efficient setPWM_manual() function enables waveform creation using PWM.

    The PWM_Multi example will demonstrate the usage of multichannel PWM using multiple Hardware-PWM blocks (Timer & Channel). The 4 independent Hardware-PWM channels are used to control 4 different PWM outputs, with totally independent frequencies and dutycycles on SAMD21/SAMD51.

    Being hardware-based PWM, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet or Blynk services.

    This non-being-blocked important feature is absolutely necessary for mission-critical tasks.


    Why using hardware-based PWM is better

    Imagine you have a system with a mission-critical function, controlling a robot or doing something much more important. You normally use a software timer to poll, or even place the function in loop(). But what if another function is blocking the loop() or setup().

    So your function might not be executed, and the result would be disastrous.

    You’d prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.).

    The correct choice is to use hardware-based PWM.

    These hardware-based PWM channels still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWMs, using millis() or micros().

    Functions using normal software-based PWMs, relying on loop() and calling millis(), won’t work if the loop() or setup() is blocked by certain operation. For example, certain function is blocking while it’s connecting to WiFi or some services.


    Currently supported Boards

    • Arduino SAMD21 (ZERO, MKR, NANO_33_IOT, etc.).
    • Adafruit SAM21 (Itsy-Bitsy M0, Metro M0, Feather M0, Gemma M0, etc.).
    • Adafruit SAM51 (Itsy-Bitsy M4, Metro M4, Grand Central M4, Feather M4 Express, etc.).
    • Seeeduino SAMD21/SAMD51 boards (SEEED_WIO_TERMINAL, SEEED_FEMTO_M0, SEEED_XIAO_M0, Wio_Lite_MG126, WIO_GPS_BOARD, SEEEDUINO_ZERO, SEEEDUINO_LORAWAN, SEEED_GROVE_UI_WIRELESS, etc.)
    • Sparkfun SAMD21 boards such as SparkFun_RedBoard_Turbo, SparkFun_Qwiic_Micro, etc.
    • Sparkfun SAMD51 boards such as SparkFun_SAMD51_Thing_Plus, SparkFun_SAMD51_MicroMod, etc.


    Prerequisites

    1. Arduino IDE 1.8.19+ for Arduino. GitHub release
    2. Arduino SAMD core 1.8.13+ for SAMD ARM Cortex-M0+ boards. GitHub release
    3. Adafruit SAMD core 1.7.11+ for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). GitHub release
    4. Seeeduino SAMD core 1.8.3+ for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). Latest release
    5. Sparkfun SAMD core 1.8.3+ for SAMD21/SAMD51 boards (SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc.)
    6. Industruino SAMD core for SAMD21/SAMD51 boards


    Installation

    Use Arduino Library Manager

    The best and easiest way is to use Arduino Library Manager. Search for SAMD_PWM, then select / install the latest version. You can also use this link arduino-library-badge for more detailed instructions.

    Manual Install

    Another way to install is to:

    1. Navigate to SAMD_PWM page.
    2. Download the latest release SAMD_PWM-main.zip.
    3. Extract the zip file to SAMD_PWM-main directory
    4. Copy whole SAMD_PWM-main folder to Arduino libraries’ directory such as ~/Arduino/libraries/.

    VS Code & PlatformIO

    1. Install VS Code
    2. Install PlatformIO
    3. Install SAMD_PWM library by using Library Manager. Search for SAMD_PWM in Platform.io Author’s Libraries
    4. Use included platformio.ini file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at Project Configuration File


    Packages’ Patches

    1. For Arduino SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on Arduino SAMD (Nano-33-IoT, etc) boards, you have to copy the whole Arduino SAMD Packages_Patches directory into Arduino SAMD directory (~/.arduino15/packages/arduino/hardware/samd/1.8.13).

    For core version v1.8.10+

    Supposing the Arduino SAMD version is 1.8.13. Now only one file must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/1.8.13/platform.txt

    Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz

    This file must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/x.yy.zz/platform.txt

    For core version v1.8.9-

    Supposing the Arduino SAMD version is 1.8.9. These files must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/1.8.9/platform.txt
    • ~/.arduino15/packages/arduino/hardware/samd/1.8.9/cores/arduino/Arduino.h

    Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z

    These files must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/x.yy.z/platform.txt
    • ~/.arduino15/packages/arduino/hardware/samd/x.yy.z/cores/arduino/Arduino.h

    This is mandatory to fix the notorious Arduino SAMD compiler error. See Improve Arduino compatibility with the STL (min and max macro)

     ...\arm-none-eabi\include\c++\7.2.1\bits\stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2
         min(const _Tp& __a, const _Tp& __b, _Compare __comp)
    

    Whenever the above-mentioned compiler error issue is fixed with the new Arduino SAMD release, you don’t need to copy the Arduino.h file anymore.

    2. For Adafruit SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on Adafruit SAMD (Itsy-Bitsy M4, etc) boards, you have to copy the files in Adafruit SAMD Packages_Patches into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.11).

    Supposing the Adafruit SAMD core version is 1.7.11. This file must be copied into the directory:

    • ~/.arduino15/packages/adafruit/hardware/samd/1.7.11/platform.txt
    • ~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.h
    • ~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.cpp

    Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

    • ~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/platform.txt
    • ~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.h
    • ~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.cpp

    3. For Seeeduino SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on Seeeduino SAMD (XIAO M0, Wio Terminal, etc) boards, you have to copy the files in Seeeduino SAMD Packages_Patches into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3).

    Supposing the Seeeduino SAMD core version is 1.8.3. This file must be copied into the directory:

    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/platform.txt
    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Arduino.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.cpp

    Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/platform.txt
    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Arduino.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.cpp

    4. For SparkFun SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on SparkFun SAMD (XIAO SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc) boards, you have to copy the file SparkFun SAMD Packages_Patches into SparkFun samd directory (~/.arduino15/packages/SparkFun/hardware/samd/1.8.3).

    Supposing the SparkFun SAMD core version is 1.8.3. This file must be copied into the directory:

    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino/Print.cpp
    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino51/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino51/Print.cpp

    Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino/Print.cpp
    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino51/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino51/Print.cpp


    Usage

    Before using any PWM Timer and channel, you have to make sure the Timer and channel has not been used by any other purpose.

    // Not OK for Nano_33_IoT (0, 1, 7, 8, 13, 14, 15 )
    // OK for Nano_33_IoT (2, 3, 4, 5, 6, 9, 10, 11, 12, 16, 17)
    // TCC OK => pin 4, 5, 6, 8, 9, 10, 11, 16/A2, 17/A3
    // TC OK  => pin 12
    // For ITSYBITSY_M4 
    // 16-bit Higher accuracy, Lower Frequency, PWM Pin OK: TCCx: 0-2, 4, 5, 7, 9-13
    //  8-bit Lower  accuracy, Hi Frequency,    PWM Pin OK: TCx: 18-20, 24-25

    1. Create PWM Instance with Pin, Frequency, dutycycle, channel (default = 0) and PWM_resolution (default = 16)

    SAMD_PWM* PWM_Instance;
    
    PWM_Instance = new SAMD_PWM(pinToUse, frequency, dutyCycle, channel, PWM_resolution);

    2. Initialize PWM Instance

    if (PWM_Instance)
    {
      PWM_Instance->setPWM();
    }

    3. Set or change PWM frequency or dutyCycle

    To use float new_dutyCycle

    PWM_Instance->setPWM(PWM_Pins, new_frequency, new_dutyCycle);

    such as

    dutyCycle = 10.0f;
      
    Serial.print(F("Change PWM DutyCycle to ")); Serial.println(dutyCycle);
    PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

    To use uint32_t new_dutyCycle = (real_dutyCycle * 65536) / 100

    PWM_Instance->setPWM_Int(PWM_Pins, new_frequency, new_dutyCycle);

    such as for real_dutyCycle = 50%

    // 50% dutyCycle = (real_dutyCycle * 65536) / 100
    dutyCycle = 32768;
    
    Serial.print(F("Change PWM DutyCycle to (%) "));
    Serial.println((float) dutyCycle * 100 / 65536);
    PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);

    for real_dutyCycle = 50%

    // 20% dutyCycle = (real_dutyCycle * 65536) / 100
    dutyCycle = 13107;
    
    Serial.print(F("Change PWM DutyCycle to (%) "));
    Serial.println((float) dutyCycle * 100 / 65536);
    PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);

    4. Set or change PWM frequency and dutyCycle manually and efficiently in waveform creation

    Function prototype

    // Must have same frequency
    // From v1.0.1-, DCValue = 0-100
    // From v1.2.0+, DCValue = 0-65535
    bool setPWM_manual(const uint8_t& pin, const uint16_t& dutyCycle);
    
    // DCPercentage from 0.0f - 100.0f
    bool setPWM_DCPercentage_manual(const uint8_t& pin, const float& DCPercentage);
    
    // DCPercentage from 0-65535 for 0.0f - 100.0f
    bool setPWM_DCPercentageInt_manual(const uint8_t& pin, const uint16_t& DCPercentage);

    Need to call only once for each pin

    PWM_Instance->setPWM(PWM_Pins, frequency, dutyCycle);

    after that, if just changing dutyCycle / level, use the faster

    // dutycycle = 0-65535 for 0-100%
    // 1084 ns
    PWM_Instance->setPWM_manual(pinToUse, dutycycle);

    or better and much easier to use, but slowest

    // 1259 ns
    new_DCPercentage = 50.0f;
    PWM_Instance->setPWM_DCPercentage_manual(pinToUse, new_DCPercentage);

    or the fastest

    // dutycyclePercent = 0-65535 == 0-100%
    // 1067 ns
    dutycyclePercentInt = 1 << 15;   // 50%
    PWM_Instance->setPWM_DCPercentageInt_manual(pinToUse, dutycyclePercentInt);

    Don’t use the extremely inefficient setPWM() for this purpose

    // Very inefficient, don't use => 499251 ns, 500-time slower
    //PWM_Instance->setPWM(pinToUse, frequency, dutycyclePercent);


    Examples:

    1. PWM_Basic
    2. PWM_DynamicDutyCycle
    3. PWM_DynamicDutyCycle_Int
    4. PWM_DynamicFreq
    5. PWM_Multi
    6. PWM_MultiChannel
    7. PWM_Waveform
    8. PWM_StepperControl New
    9. PWM_manual New
    10. PWM_SpeedTest New


    Example PWM_Multi

    #define _PWM_LOGLEVEL_ 4
    #include SAMD_PWM.h
    // Not OK for Nano_33_IoT (0, 1, 7, 8, 13, 14, 15 )
    // OK for Nano_33_IoT (2, 3, 4, 5, 6, 9, 10, 11, 12, 16, 17)
    // TCC OK => pin 4, 5, 6, 8, 9, 10, 11, 16/A2, 17/A3
    // TC OK => pin 12
    // For ITSYBITSY_M4
    // 16-bit Higher accuracy, Lower Frequency, PWM Pin OK: TCCx: 0-2, 4, 5, 7, 9-13
    // 8-bit Lower accuracy, Hi Frequency, PWM Pin OK: TCx: 18-20, 24-25
    // Change to use the correct PWM pins from different TCx or TCCx, according to your boards
    #if defined(__SAMD51__)
    // Pin 5:TCC2_CH1, pin 7: TCC1_CH2, pin 11: TCC0_CH1, pin 25/MOSI: TC2_CH0
    uint32_t PWM_Pins[] = { 5, 7, 11, 25 };
    #else
    // pin 4: TCC1_CH1, Pin 5:TCC0_CH1, pin 11: TCC2_CH0, pin 12: TC3_CH1
    uint32_t PWM_Pins[] = { 4, 5, 11, 12 };
    #endif
    #define NUM_OF_PINS ( sizeof(PWM_Pins) / sizeof(uint32_t) )
    float dutyCycle[] = { 10.0f, 30.0f, 50.0f, 90.0f };
    float frequency[] = { 2000.0f, 3000.0f, 4000.0f, 8000.0f };
    SAMD_PWM* PWM_Instance[NUM_OF_PINS];
    char dashLine[] = =====================================================================================;
    void printPWMInfo(SAMD_PWM* PWM_Instance)
    {
    Serial.println(dashLine);
    Serial.print(Actual data: pin = );
    Serial.print(PWM_Instance->getPin());
    Serial.print(, PWM DC = );
    Serial.print(PWM_Instance->getActualDutyCycle());
    Serial.print(, PWMPeriod = );
    Serial.print(PWM_Instance->getPWMPeriod());
    Serial.print(, PWM Freq (Hz) = );
    Serial.println(PWM_Instance->getActualFreq(), 4);
    Serial.println(dashLine);
    }
    void setup()
    {
    Serial.begin(115200);
    while (!Serial && millis() < 5000);
    delay(500);
    Serial.print(F(\nStarting PWM_Multi on ));
    Serial.println(BOARD_NAME);
    Serial.println(SAMD_PWM_VERSION);
    for (uint8_t index = 0; index < NUM_OF_PINS; index++)
    {
    PWM_Instance[index] = new SAMD_PWM(PWM_Pins[index], frequency[index], dutyCycle[index]);
    if (PWM_Instance[index])
    {
    PWM_Instance[index]->setPWM();
    }
    }
    Serial.println(dashLine);
    Serial.println(Index\tPin\tPWM_freq\tDutyCycle\tActual Freq);
    Serial.println(dashLine);
    for (uint8_t index = 0; index < NUM_OF_PINS; index++)
    {
    if (PWM_Instance[index])
    {
    Serial.print(index);
    Serial.print(\t);
    Serial.print(PWM_Pins[index]);
    Serial.print(\t);
    Serial.print(frequency[index]);
    Serial.print(\t\t);
    Serial.print(dutyCycle[index]);
    Serial.print(\t\t);
    Serial.println(PWM_Instance[index]->getActualFreq(), 4);
    }
    else
    {
    Serial.println();
    }
    }
    for (uint8_t index = 0; index < NUM_OF_PINS; index++)
    {
    printPWMInfo(PWM_Instance[index]);
    }
    }
    void loop()
    {
    //Long delay has no effect on the operation of hardware-based PWM channels
    delay(1000000);
    }



    Debug Terminal Output Samples

    1. PWM_DynamicDutyCycle on SAMD_NANO_33_IOT

    The following is the sample terminal output when running example PWM_DynamicDutyCycle on SAMD21 SAMD_NANO_33_IOT, to demonstrate the ability to provide high PWM frequencies and ability to change DutyCycle on-the-fly using TCC timer for 16-bit PWM

    Starting PWM_DynamicDutyCycle on SAMD_NANO_33_IOT
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 200 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 9599
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4799 , input dutycycle = 32768 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC = 4799 , input dutycycle = 32768 , frequency = 5000.00
    =====================================================================================
    Change PWM DutyCycle to 90.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 8639 , input dutycycle = 58982 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: Old TCC => newDC = 8639 , input dutycycle = 58982 , frequency = 5000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 90.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
    =====================================================================================
    Change PWM DutyCycle to 20.00
    [PWM] setPWM: _dutycycle = 13107 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 1919 , input dutycycle = 13107 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: Old TCC => newDC = 1919 , input dutycycle = 13107 , frequency = 5000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 20.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
    =====================================================================================
    Change PWM DutyCycle to 90.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 8639 , input dutycycle = 58982 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: Old TCC => newDC = 8639 , input dutycycle = 58982 , frequency = 5000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 90.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
    =====================================================================================

    2. PWM_Multi on SAMD_NANO_33_IOT

    The following is the sample terminal output when running example PWM_Multi on SAMD21 SAMD_NANO_33_IOT, to demonstrate the ability to provide high PWM frequencies on multiple PWM-capable pins using TCC timer for 16-bit PWM

    Starting PWM_Multi on SAMD_NANO_33_IOT
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 4 , period = 500 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 6553 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD21 setPWM_Int: _tcNum = 1 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 2399 , input dutycycle = 6553 , _compareValue = 23999 , frequency = 2000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC= 2399 , input dutycycle = 6553 , frequency = 2000.00
    [PWM] calcTCCPrescaler: OK pin = 5 , period = 333 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 19660 , frequency = 3000.00 , _prescalerConfigBits = 0 , _compareValue = 15983
    [PWM] SAMD21 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4794 , input dutycycle = 19660 , _compareValue = 15983 , frequency = 3000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC= 4794 , input dutycycle = 19660 , frequency = 3000.00
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 250 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 4000.00 , _prescalerConfigBits = 0 , _compareValue = 11999
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 4000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC= 5999 , input dutycycle = 32768 , frequency = 4000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 125 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 8000.00 , _prescalerConfigBits = 0 , _compareValue = 5999
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 5399 , input dutycycle = 58982 , _compareValue = 5999 , frequency = 8000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 21 , input dutycycle = 58982 , _compareValue = 23 , frequency = 8000.00
    =====================================================================================
    Index	Pin	PWM_freq	DutyCycle	Actual Freq
    =====================================================================================
    0	4	2000.00		10.00		2000.0000
    1	5	3000.00		30.00		3000.0000
    2	11	4000.00		50.00		4000.0000
    3	12	8000.00		90.00		8000.0000
    =====================================================================================
    Actual data: pin = 4, PWM DC = 10.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =====================================================================================
    =====================================================================================
    Actual data: pin = 5, PWM DC = 30.00, PWMPeriod = 333.33, PWM Freq (Hz) = 3000.0000
    =====================================================================================
    =====================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 250.00, PWM Freq (Hz) = 4000.0000
    =====================================================================================
    =====================================================================================
    Actual data: pin = 12, PWM DC = 90.00, PWMPeriod = 125.00, PWM Freq (Hz) = 8000.0000
    =====================================================================================

    3. PWM_DynamicFreq on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_DynamicFreq on SAMD51 ITSYBITSY_M4, to demonstrate the ability to change dynamically PWM frequencies on SAMD51 using TCC timer for 16-bit PWM

    Starting PWM_DynamicFreq on ITSYBITSY_M4
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 100 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 10000.00 , _prescalerConfigBits = 0 , _compareValue = 11999
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    =====================================================================================
    Change PWM Freq to 20000.00
    [PWM] setPWM: _dutycycle = 32768 , frequency = 20000.00
    [PWM] setPWM_Int: change frequency to 20000.00 from 10000.00
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 50 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 20000.00 , _prescalerConfigBits = 0 , _compareValue = 5999
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 2999 , input dutycycle = 32768 , _compareValue = 5999 , frequency = 20000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 2999 , input dutycycle = 32768 , _compareValue = 5999 , frequency = 20000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 50.00, PWM Freq (Hz) = 20000.0000
    =====================================================================================
    Change PWM Freq to 10000.00
    [PWM] setPWM: _dutycycle = 32768 , frequency = 10000.00
    [PWM] setPWM_Int: change frequency to 10000.00 from 20000.00
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 100 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 10000.00 , _prescalerConfigBits = 0 , _compareValue = 11999
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 100.00, PWM Freq (Hz) = 10000.0000
    =====================================================================================

    4. PWM_Waveform on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_Waveform on SAMD51 ITSYBITSY_M4, to demonstrate how to use the setPWM_manual() function in wafeform creation using TCC timer for 16-bit PWM

    Starting PWM_Waveform on ITSYBITSY_M4
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 1000 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 0 , frequency = 1000.00 , _prescalerConfigBits = 0 , _compareValue = 119999
    [PWM] setPWM: _dutycycle = 655 , frequency = 1000.00
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 1199 , input dutycycle = 655 , _compareValue = 119999 , frequency = 1000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 1199 , input dutycycle = 655 , _compareValue = 119999 , frequency = 1000.00
    ============================================================================================
    Actual data: pin = 11, PWM DutyCycle = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000
    ============================================================================================
    [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 0 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 5 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 5999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 10 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 11999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 15 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 17999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 20 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 23999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 25 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 29999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 30 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 35999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 35 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 41999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 40 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 47999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 45 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 53999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 50 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 59999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 55 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 65999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 60 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 71999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 65 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 77999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 70 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 83999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 75 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 89999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 80 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 95999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 85 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 101999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 90 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 107999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 95 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 113999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 100 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 119999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 95 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 113999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 90 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 107999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 85 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 101999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 80 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 95999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 75 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 89999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 70 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 83999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 65 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 77999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 60 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 71999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 55 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 65999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 50 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 59999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 45 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 53999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 40 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 47999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 35 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 41999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 30 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 35999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 25 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 29999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 20 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 23999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 15 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 17999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 10 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 11999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 5 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 5999 , _compareValue = 119999

    5. PWM_Basic on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_Basic on SAMD51 ITSYBITSY_M4, to demonstrate how to use the basic function, using TC timer for 8-bit PWM

    Starting PWM_Basic on ITSYBITSY_M4
    SAMD_PWM v1.0.1
    [PWM] calcTCPrescaler: OK pin = 24 , period = 1000 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 0 , frequency = 1000.00 , _prescalerConfigBits = 0 , _compareValue = 119999
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 1000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 500 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 59999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 11999 , input dutycycle = 13107 , _compareValue = 59999 , frequency = 2000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 46 , input dutycycle = 13107 , _compareValue = 234 , frequency = 2000.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] setPWM_Int: change frequency to 5000.00 from 2000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 200 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 21598 , input dutycycle = 58982 , _compareValue = 23999 , frequency = 5000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 84 , input dutycycle = 58982 , _compareValue = 93 , frequency = 5000.00
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 5000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 500 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 59999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 11999 , input dutycycle = 13107 , _compareValue = 59999 , frequency = 2000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 46 , input dutycycle = 13107 , _compareValue = 234 , frequency = 2000.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] setPWM_Int: change frequency to 5000.00 from 2000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 200 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 21598 , input dutycycle = 58982 , _compareValue = 23999 , frequency = 5000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 84 , input dutycycle = 58982 , _compareValue = 93 , frequency = 5000.00

    6. PWM_Basic on SAMD_NANO_33_IOT

    The following is the sample terminal output when running example PWM_Basic on SAMD21 SAMD_NANO_33_IOT, to demonstrate how to use the basic function, using TC timer for 8-bit PWM

    Starting PWM_Basic on SAMD_NANO_33_IOT
    SAMD_PWM v1.0.1
    [PWM] calcTCPrescaler: OK pin = 12 , period = 1000 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 0 , frequency = 1000.00 , _prescalerConfigBits = 0 , _compareValue = 47999
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 1000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 500 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4799 , input dutycycle = 13107 , _compareValue = 23999 , frequency = 2000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 18 , input dutycycle = 13107 , _compareValue = 93 , frequency = 2000.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] setPWM_Int: change frequency to 5000.00 from 2000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 200 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 9599
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 8639 , input dutycycle = 58982 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 33 , input dutycycle = 58982 , _compareValue = 37 , frequency = 5000.00
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 5000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 500 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4799 , input dutycycle = 13107 , _compareValue = 23999 , frequency = 2000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 18 , input dutycycle = 13107 , _compareValue = 93 , frequency = 2000.00

    7. PWM_manual on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_manual on SAMD51 ITSYBITSY_M4, to demonstrate how to use the setPWM_manual() and setPWM_DCPercentage_manual() functions in wafeform creation

    Starting PWM_manual on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Not USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 0.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 5.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 10.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 15.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 20.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 25.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 30.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 35.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 40.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 45.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 55.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 60.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 65.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 70.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 75.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 80.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 85.01, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 90.01, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 95.01, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 100.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 0.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    ...

    8. PWM_SpeedTest on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_SpeedTest on ITSYBITSY_M4, to demonstrate how to use new faster setPWM_manual() function in wafeform creation, The time is 1084 ns compared to 499,500 ns when using setPWM() function. The fastest is setPWM_DCPercentageInt_manual with 1067 ns, which is better to be used with pre-calculated values in array

    USING_DC_PERCENT
    Starting PWM_SpeedTest on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Average time of setPWM function USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=937083, ns=1067
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=936335, ns=1067
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=936358, ns=1067
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=936334, ns=1067
    ...
    
    USING_DC_PERCENT with extremely slow setPWM()
    Starting PWM_SpeedTest on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Average time of setPWM function USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2002, ns=499500
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2003, ns=499251
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2003, ns=499251
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2003, ns=499251
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =======================================================
    
    not USING_DC_PERCENT
    Starting PWM_SpeedTest on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Average time of setPWM function not USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=922600, ns=1083
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921932, ns=1084
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921965, ns=1084
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921951, ns=1084
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921942, ns=1084


    Debug

    Debug is enabled by default on Serial.

    You can also change the debugging level _PWM_LOGLEVEL_ from 0 to 4

    // Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
    #define _PWM_LOGLEVEL_     0

    Troubleshooting

    If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards.

    Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions.



    Issues

    Submit issues to: SAMD_PWM issues



    TO DO

    1. Search for bug and improvement.
    2. Similar features for remaining Arduino boards

    DONE

    1. Basic hardware PWM-channels for SAMD21/SAMD51 boards such as NANO_33_IOT, ITSYBITSY_M4, SEEED_XIAO_M0, SparkFun SAMD51_Thing_Plus, etc. using
    1. Add example PWM_StepperControl to demo how to control Stepper Motor using PWM
    2. Add example PWM_manual to demo how to correctly use PWM to generate waveform
    3. Add function setPWM_DCPercentage_manual() to facilitate the setting PWM DC manually by using DCPercentage, instead of absolute DCValue depending on varying PWMPeriod
    4. Optimize speed with new setPWM_DCPercentageInt_manual function to improve speed almost 500 times compared to setPWM
    5. Add example PWM_SpeedTest to demo the better speed of new setPWM_DCPercentageInt_manual function
    6. Breaking change: Modify setPWM_manual function to take 16-bit dutycycle instead from merely 0-100 for better accuracy
    7. Modify example PWM_Waveform to adapt to breaking change of setPWM_manual function
    8. Improve README.md so that links can be used in other sites, such as PIO


    Contributions and Thanks

    Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library.

    1. Thanks to Paul van Dinther for proposing new way to use PWM to drive Stepper-Motor in Using PWM to step a stepper driver #16, leading to v2.0.3
    dinther
    Paul van Dinther


    Contributing

    If you want to contribute to this project:

    • Report bugs and errors
    • Ask for enhancements
    • Create issues and pull requests
    • Tell other people about this library

    License

    • The library is licensed under MIT

    Copyright

    Copyright (c) 2022- Khoi Hoang

    Visit original content creator repository https://github.com/khoih-prog/SAMD_PWM
  • SAMD_PWM

    SAMD_PWM Library

    arduino-library-badge GitHub release GitHub contributions welcome GitHub issues

    Donate to my libraries using BuyMeACoffee



    Table of Contents



    Why do we need this SAMD_PWM library

    Features

    This hardware-based PWM library enables you to use Hardware-PWM on SAMD21/SAMD51 boards such as NANO_33_IOT, ITSYBITSY_M4, SEEED_XIAO_M0, SparkFun SAMD51_Thing_Plus, etc., to create and output PWM. These purely hardware-based PWM channels can generate very high PWM frequencies, depending on CPU clock and acceptable accuracy. The maximum resolution can be 16-bit for better accuracy when using Timer TCCx. With Timer TCx, only 8-bit resolution is supported with lower accuracy.

    This library is using the same or similar functions as other FastPWM sibling libraries, as follows, to enable you to port your PWM code easily between platforms

    1. RP2040_PWM
    2. AVR_PWM
    3. megaAVR_PWM
    4. ESP32_FastPWM
    5. SAMD_PWM
    6. SAMDUE_PWM
    7. nRF52_PWM
    8. Teensy_PWM
    9. ATtiny_PWM
    10. Dx_PWM
    11. Portenta_H7_PWM
    12. MBED_RP2040_PWM
    13. nRF52_MBED_PWM
    14. STM32_PWM

    The most important feature is they’re purely hardware-based PWM channels. Therefore, their operations are not blocked by bad-behaving software functions / tasks.

    This important feature is absolutely necessary for mission-critical tasks. These hardware PWM-channels, still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software timers using millis() or micros(). That’s necessary if you need to control external systems (Servo, etc.) requiring better accuracy.

    New efficient setPWM_manual() function enables waveform creation using PWM.

    The PWM_Multi example will demonstrate the usage of multichannel PWM using multiple Hardware-PWM blocks (Timer & Channel). The 4 independent Hardware-PWM channels are used to control 4 different PWM outputs, with totally independent frequencies and dutycycles on SAMD21/SAMD51.

    Being hardware-based PWM, their executions are not blocked by bad-behaving functions / tasks, such as connecting to WiFi, Internet or Blynk services.

    This non-being-blocked important feature is absolutely necessary for mission-critical tasks.


    Why using hardware-based PWM is better

    Imagine you have a system with a mission-critical function, controlling a robot or doing something much more important. You normally use a software timer to poll, or even place the function in loop(). But what if another function is blocking the loop() or setup().

    So your function might not be executed, and the result would be disastrous.

    You’d prefer to have your function called, no matter what happening with other functions (busy loop, bug, etc.).

    The correct choice is to use hardware-based PWM.

    These hardware-based PWM channels still work even if other software functions are blocking. Moreover, they are much more precise (certainly depending on clock frequency accuracy) than other software-based PWMs, using millis() or micros().

    Functions using normal software-based PWMs, relying on loop() and calling millis(), won’t work if the loop() or setup() is blocked by certain operation. For example, certain function is blocking while it’s connecting to WiFi or some services.


    Currently supported Boards

    • Arduino SAMD21 (ZERO, MKR, NANO_33_IOT, etc.).
    • Adafruit SAM21 (Itsy-Bitsy M0, Metro M0, Feather M0, Gemma M0, etc.).
    • Adafruit SAM51 (Itsy-Bitsy M4, Metro M4, Grand Central M4, Feather M4 Express, etc.).
    • Seeeduino SAMD21/SAMD51 boards (SEEED_WIO_TERMINAL, SEEED_FEMTO_M0, SEEED_XIAO_M0, Wio_Lite_MG126, WIO_GPS_BOARD, SEEEDUINO_ZERO, SEEEDUINO_LORAWAN, SEEED_GROVE_UI_WIRELESS, etc.)
    • Sparkfun SAMD21 boards such as SparkFun_RedBoard_Turbo, SparkFun_Qwiic_Micro, etc.
    • Sparkfun SAMD51 boards such as SparkFun_SAMD51_Thing_Plus, SparkFun_SAMD51_MicroMod, etc.


    Prerequisites

    1. Arduino IDE 1.8.19+ for Arduino. GitHub release
    2. Arduino SAMD core 1.8.13+ for SAMD ARM Cortex-M0+ boards. GitHub release
    3. Adafruit SAMD core 1.7.11+ for SAMD ARM Cortex-M0+ and M4 boards (Nano 33 IoT, etc.). GitHub release
    4. Seeeduino SAMD core 1.8.3+ for SAMD21/SAMD51 boards (XIAO M0, Wio Terminal, etc.). Latest release
    5. Sparkfun SAMD core 1.8.3+ for SAMD21/SAMD51 boards (SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc.)
    6. Industruino SAMD core for SAMD21/SAMD51 boards


    Installation

    Use Arduino Library Manager

    The best and easiest way is to use Arduino Library Manager. Search for SAMD_PWM, then select / install the latest version. You can also use this link arduino-library-badge for more detailed instructions.

    Manual Install

    Another way to install is to:

    1. Navigate to SAMD_PWM page.
    2. Download the latest release SAMD_PWM-main.zip.
    3. Extract the zip file to SAMD_PWM-main directory
    4. Copy whole SAMD_PWM-main folder to Arduino libraries’ directory such as ~/Arduino/libraries/.

    VS Code & PlatformIO

    1. Install VS Code
    2. Install PlatformIO
    3. Install SAMD_PWM library by using Library Manager. Search for SAMD_PWM in Platform.io Author’s Libraries
    4. Use included platformio.ini file from examples to ensure that all dependent libraries will installed automatically. Please visit documentation for the other options and examples at Project Configuration File


    Packages’ Patches

    1. For Arduino SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on Arduino SAMD (Nano-33-IoT, etc) boards, you have to copy the whole Arduino SAMD Packages_Patches directory into Arduino SAMD directory (~/.arduino15/packages/arduino/hardware/samd/1.8.13).

    For core version v1.8.10+

    Supposing the Arduino SAMD version is 1.8.13. Now only one file must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/1.8.13/platform.txt

    Whenever a new version is installed, remember to copy this files into the new version directory. For example, new version is x.yy.zz

    This file must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/x.yy.zz/platform.txt

    For core version v1.8.9-

    Supposing the Arduino SAMD version is 1.8.9. These files must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/1.8.9/platform.txt
    • ~/.arduino15/packages/arduino/hardware/samd/1.8.9/cores/arduino/Arduino.h

    Whenever a new version is installed, remember to copy these files into the new version directory. For example, new version is x.yy.z

    These files must be copied into the directory:

    • ~/.arduino15/packages/arduino/hardware/samd/x.yy.z/platform.txt
    • ~/.arduino15/packages/arduino/hardware/samd/x.yy.z/cores/arduino/Arduino.h

    This is mandatory to fix the notorious Arduino SAMD compiler error. See Improve Arduino compatibility with the STL (min and max macro)

     ...\arm-none-eabi\include\c++\7.2.1\bits\stl_algobase.h:243:56: error: macro "min" passed 3 arguments, but takes just 2
         min(const _Tp& __a, const _Tp& __b, _Compare __comp)
    

    Whenever the above-mentioned compiler error issue is fixed with the new Arduino SAMD release, you don’t need to copy the Arduino.h file anymore.

    2. For Adafruit SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on Adafruit SAMD (Itsy-Bitsy M4, etc) boards, you have to copy the files in Adafruit SAMD Packages_Patches into Adafruit samd directory (~/.arduino15/packages/adafruit/hardware/samd/1.7.11).

    Supposing the Adafruit SAMD core version is 1.7.11. This file must be copied into the directory:

    • ~/.arduino15/packages/adafruit/hardware/samd/1.7.11/platform.txt
    • ~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.h
    • ~/.arduino15/packages/adafruit/hardware/samd/1.7.11/cores/arduino/Print.cpp

    Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

    • ~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/platform.txt
    • ~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.h
    • ~/.arduino15/packages/adafruit/hardware/samd/x.yy.zz/cores/arduino/Print.cpp

    3. For Seeeduino SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on Seeeduino SAMD (XIAO M0, Wio Terminal, etc) boards, you have to copy the files in Seeeduino SAMD Packages_Patches into Seeeduino samd directory (~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3).

    Supposing the Seeeduino SAMD core version is 1.8.3. This file must be copied into the directory:

    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/platform.txt
    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Arduino.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/1.8.3/cores/arduino/Print.cpp

    Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/platform.txt
    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Arduino.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.h
    • ~/.arduino15/packages/Seeeduino/hardware/samd/x.yy.zz/cores/arduino/Print.cpp

    4. For SparkFun SAMD boards

    To be able to compile without error and automatically detect and display BOARD_NAME on SparkFun SAMD (XIAO SparkFun_RedBoard_Turbo, SparkFun_SAMD51_Thing_Plus, etc) boards, you have to copy the file SparkFun SAMD Packages_Patches into SparkFun samd directory (~/.arduino15/packages/SparkFun/hardware/samd/1.8.3).

    Supposing the SparkFun SAMD core version is 1.8.3. This file must be copied into the directory:

    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino/Print.cpp
    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino51/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/1.8.3/cores/arduino51/Print.cpp

    Whenever a new version is installed, remember to copy this file into the new version directory. For example, new version is x.yy.zz This file must be copied into the directory:

    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino/Print.cpp
    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino51/Print.h
    • ~/.arduino15/packages/SparkFun/hardware/samd/x.yy.zz/cores/arduino51/Print.cpp


    Usage

    Before using any PWM Timer and channel, you have to make sure the Timer and channel has not been used by any other purpose.

    // Not OK for Nano_33_IoT (0, 1, 7, 8, 13, 14, 15 )
    // OK for Nano_33_IoT (2, 3, 4, 5, 6, 9, 10, 11, 12, 16, 17)
    // TCC OK => pin 4, 5, 6, 8, 9, 10, 11, 16/A2, 17/A3
    // TC OK  => pin 12
    // For ITSYBITSY_M4 
    // 16-bit Higher accuracy, Lower Frequency, PWM Pin OK: TCCx: 0-2, 4, 5, 7, 9-13
    //  8-bit Lower  accuracy, Hi Frequency,    PWM Pin OK: TCx: 18-20, 24-25

    1. Create PWM Instance with Pin, Frequency, dutycycle, channel (default = 0) and PWM_resolution (default = 16)

    SAMD_PWM* PWM_Instance;
    
    PWM_Instance = new SAMD_PWM(pinToUse, frequency, dutyCycle, channel, PWM_resolution);

    2. Initialize PWM Instance

    if (PWM_Instance)
    {
      PWM_Instance->setPWM();
    }

    3. Set or change PWM frequency or dutyCycle

    To use float new_dutyCycle

    PWM_Instance->setPWM(PWM_Pins, new_frequency, new_dutyCycle);

    such as

    dutyCycle = 10.0f;
      
    Serial.print(F("Change PWM DutyCycle to ")); Serial.println(dutyCycle);
    PWM_Instance->setPWM(pinToUse, frequency, dutyCycle);

    To use uint32_t new_dutyCycle = (real_dutyCycle * 65536) / 100

    PWM_Instance->setPWM_Int(PWM_Pins, new_frequency, new_dutyCycle);

    such as for real_dutyCycle = 50%

    // 50% dutyCycle = (real_dutyCycle * 65536) / 100
    dutyCycle = 32768;
    
    Serial.print(F("Change PWM DutyCycle to (%) "));
    Serial.println((float) dutyCycle * 100 / 65536);
    PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);

    for real_dutyCycle = 50%

    // 20% dutyCycle = (real_dutyCycle * 65536) / 100
    dutyCycle = 13107;
    
    Serial.print(F("Change PWM DutyCycle to (%) "));
    Serial.println((float) dutyCycle * 100 / 65536);
    PWM_Instance->setPWM_Int(pinToUse, frequency, dutyCycle);

    4. Set or change PWM frequency and dutyCycle manually and efficiently in waveform creation

    Function prototype

    // Must have same frequency
    // From v1.0.1-, DCValue = 0-100
    // From v1.2.0+, DCValue = 0-65535
    bool setPWM_manual(const uint8_t& pin, const uint16_t& dutyCycle);
    
    // DCPercentage from 0.0f - 100.0f
    bool setPWM_DCPercentage_manual(const uint8_t& pin, const float& DCPercentage);
    
    // DCPercentage from 0-65535 for 0.0f - 100.0f
    bool setPWM_DCPercentageInt_manual(const uint8_t& pin, const uint16_t& DCPercentage);

    Need to call only once for each pin

    PWM_Instance->setPWM(PWM_Pins, frequency, dutyCycle);

    after that, if just changing dutyCycle / level, use the faster

    // dutycycle = 0-65535 for 0-100%
    // 1084 ns
    PWM_Instance->setPWM_manual(pinToUse, dutycycle);

    or better and much easier to use, but slowest

    // 1259 ns
    new_DCPercentage = 50.0f;
    PWM_Instance->setPWM_DCPercentage_manual(pinToUse, new_DCPercentage);

    or the fastest

    // dutycyclePercent = 0-65535 == 0-100%
    // 1067 ns
    dutycyclePercentInt = 1 << 15;   // 50%
    PWM_Instance->setPWM_DCPercentageInt_manual(pinToUse, dutycyclePercentInt);

    Don’t use the extremely inefficient setPWM() for this purpose

    // Very inefficient, don't use => 499251 ns, 500-time slower
    //PWM_Instance->setPWM(pinToUse, frequency, dutycyclePercent);


    Examples:

    1. PWM_Basic
    2. PWM_DynamicDutyCycle
    3. PWM_DynamicDutyCycle_Int
    4. PWM_DynamicFreq
    5. PWM_Multi
    6. PWM_MultiChannel
    7. PWM_Waveform
    8. PWM_StepperControl New
    9. PWM_manual New
    10. PWM_SpeedTest New


    Example PWM_Multi

    #define _PWM_LOGLEVEL_ 4
    #include SAMD_PWM.h
    // Not OK for Nano_33_IoT (0, 1, 7, 8, 13, 14, 15 )
    // OK for Nano_33_IoT (2, 3, 4, 5, 6, 9, 10, 11, 12, 16, 17)
    // TCC OK => pin 4, 5, 6, 8, 9, 10, 11, 16/A2, 17/A3
    // TC OK => pin 12
    // For ITSYBITSY_M4
    // 16-bit Higher accuracy, Lower Frequency, PWM Pin OK: TCCx: 0-2, 4, 5, 7, 9-13
    // 8-bit Lower accuracy, Hi Frequency, PWM Pin OK: TCx: 18-20, 24-25
    // Change to use the correct PWM pins from different TCx or TCCx, according to your boards
    #if defined(__SAMD51__)
    // Pin 5:TCC2_CH1, pin 7: TCC1_CH2, pin 11: TCC0_CH1, pin 25/MOSI: TC2_CH0
    uint32_t PWM_Pins[] = { 5, 7, 11, 25 };
    #else
    // pin 4: TCC1_CH1, Pin 5:TCC0_CH1, pin 11: TCC2_CH0, pin 12: TC3_CH1
    uint32_t PWM_Pins[] = { 4, 5, 11, 12 };
    #endif
    #define NUM_OF_PINS ( sizeof(PWM_Pins) / sizeof(uint32_t) )
    float dutyCycle[] = { 10.0f, 30.0f, 50.0f, 90.0f };
    float frequency[] = { 2000.0f, 3000.0f, 4000.0f, 8000.0f };
    SAMD_PWM* PWM_Instance[NUM_OF_PINS];
    char dashLine[] = =====================================================================================;
    void printPWMInfo(SAMD_PWM* PWM_Instance)
    {
    Serial.println(dashLine);
    Serial.print(Actual data: pin = );
    Serial.print(PWM_Instance->getPin());
    Serial.print(, PWM DC = );
    Serial.print(PWM_Instance->getActualDutyCycle());
    Serial.print(, PWMPeriod = );
    Serial.print(PWM_Instance->getPWMPeriod());
    Serial.print(, PWM Freq (Hz) = );
    Serial.println(PWM_Instance->getActualFreq(), 4);
    Serial.println(dashLine);
    }
    void setup()
    {
    Serial.begin(115200);
    while (!Serial && millis() < 5000);
    delay(500);
    Serial.print(F(\nStarting PWM_Multi on ));
    Serial.println(BOARD_NAME);
    Serial.println(SAMD_PWM_VERSION);
    for (uint8_t index = 0; index < NUM_OF_PINS; index++)
    {
    PWM_Instance[index] = new SAMD_PWM(PWM_Pins[index], frequency[index], dutyCycle[index]);
    if (PWM_Instance[index])
    {
    PWM_Instance[index]->setPWM();
    }
    }
    Serial.println(dashLine);
    Serial.println(Index\tPin\tPWM_freq\tDutyCycle\tActual Freq);
    Serial.println(dashLine);
    for (uint8_t index = 0; index < NUM_OF_PINS; index++)
    {
    if (PWM_Instance[index])
    {
    Serial.print(index);
    Serial.print(\t);
    Serial.print(PWM_Pins[index]);
    Serial.print(\t);
    Serial.print(frequency[index]);
    Serial.print(\t\t);
    Serial.print(dutyCycle[index]);
    Serial.print(\t\t);
    Serial.println(PWM_Instance[index]->getActualFreq(), 4);
    }
    else
    {
    Serial.println();
    }
    }
    for (uint8_t index = 0; index < NUM_OF_PINS; index++)
    {
    printPWMInfo(PWM_Instance[index]);
    }
    }
    void loop()
    {
    //Long delay has no effect on the operation of hardware-based PWM channels
    delay(1000000);
    }



    Debug Terminal Output Samples

    1. PWM_DynamicDutyCycle on SAMD_NANO_33_IOT

    The following is the sample terminal output when running example PWM_DynamicDutyCycle on SAMD21 SAMD_NANO_33_IOT, to demonstrate the ability to provide high PWM frequencies and ability to change DutyCycle on-the-fly using TCC timer for 16-bit PWM

    Starting PWM_DynamicDutyCycle on SAMD_NANO_33_IOT
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 200 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 9599
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4799 , input dutycycle = 32768 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC = 4799 , input dutycycle = 32768 , frequency = 5000.00
    =====================================================================================
    Change PWM DutyCycle to 90.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 8639 , input dutycycle = 58982 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: Old TCC => newDC = 8639 , input dutycycle = 58982 , frequency = 5000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 90.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
    =====================================================================================
    Change PWM DutyCycle to 20.00
    [PWM] setPWM: _dutycycle = 13107 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 1919 , input dutycycle = 13107 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: Old TCC => newDC = 1919 , input dutycycle = 13107 , frequency = 5000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 20.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
    =====================================================================================
    Change PWM DutyCycle to 90.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 8639 , input dutycycle = 58982 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: Old TCC => newDC = 8639 , input dutycycle = 58982 , frequency = 5000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 90.00, PWMPeriod = 200.00, PWM Freq (Hz) = 5000.0000
    =====================================================================================

    2. PWM_Multi on SAMD_NANO_33_IOT

    The following is the sample terminal output when running example PWM_Multi on SAMD21 SAMD_NANO_33_IOT, to demonstrate the ability to provide high PWM frequencies on multiple PWM-capable pins using TCC timer for 16-bit PWM

    Starting PWM_Multi on SAMD_NANO_33_IOT
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 4 , period = 500 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 6553 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD21 setPWM_Int: _tcNum = 1 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 2399 , input dutycycle = 6553 , _compareValue = 23999 , frequency = 2000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC= 2399 , input dutycycle = 6553 , frequency = 2000.00
    [PWM] calcTCCPrescaler: OK pin = 5 , period = 333 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 19660 , frequency = 3000.00 , _prescalerConfigBits = 0 , _compareValue = 15983
    [PWM] SAMD21 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4794 , input dutycycle = 19660 , _compareValue = 15983 , frequency = 3000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC= 4794 , input dutycycle = 19660 , frequency = 3000.00
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 250 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 4000.00 , _prescalerConfigBits = 0 , _compareValue = 11999
    [PWM] SAMD21 setPWM_Int: _tcNum = 2 , _tcChannel = 0 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 4000.00
    [PWM] SAMD21 setPWM_Int: New TCC => newDC= 5999 , input dutycycle = 32768 , frequency = 4000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 125 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 8000.00 , _prescalerConfigBits = 0 , _compareValue = 5999
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 5399 , input dutycycle = 58982 , _compareValue = 5999 , frequency = 8000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 21 , input dutycycle = 58982 , _compareValue = 23 , frequency = 8000.00
    =====================================================================================
    Index	Pin	PWM_freq	DutyCycle	Actual Freq
    =====================================================================================
    0	4	2000.00		10.00		2000.0000
    1	5	3000.00		30.00		3000.0000
    2	11	4000.00		50.00		4000.0000
    3	12	8000.00		90.00		8000.0000
    =====================================================================================
    Actual data: pin = 4, PWM DC = 10.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =====================================================================================
    =====================================================================================
    Actual data: pin = 5, PWM DC = 30.00, PWMPeriod = 333.33, PWM Freq (Hz) = 3000.0000
    =====================================================================================
    =====================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 250.00, PWM Freq (Hz) = 4000.0000
    =====================================================================================
    =====================================================================================
    Actual data: pin = 12, PWM DC = 90.00, PWMPeriod = 125.00, PWM Freq (Hz) = 8000.0000
    =====================================================================================

    3. PWM_DynamicFreq on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_DynamicFreq on SAMD51 ITSYBITSY_M4, to demonstrate the ability to change dynamically PWM frequencies on SAMD51 using TCC timer for 16-bit PWM

    Starting PWM_DynamicFreq on ITSYBITSY_M4
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 100 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 10000.00 , _prescalerConfigBits = 0 , _compareValue = 11999
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    =====================================================================================
    Change PWM Freq to 20000.00
    [PWM] setPWM: _dutycycle = 32768 , frequency = 20000.00
    [PWM] setPWM_Int: change frequency to 20000.00 from 10000.00
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 50 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 20000.00 , _prescalerConfigBits = 0 , _compareValue = 5999
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 2999 , input dutycycle = 32768 , _compareValue = 5999 , frequency = 20000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 2999 , input dutycycle = 32768 , _compareValue = 5999 , frequency = 20000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 50.00, PWM Freq (Hz) = 20000.0000
    =====================================================================================
    Change PWM Freq to 10000.00
    [PWM] setPWM: _dutycycle = 32768 , frequency = 10000.00
    [PWM] setPWM_Int: change frequency to 10000.00 from 20000.00
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 100 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 32768 , frequency = 10000.00 , _prescalerConfigBits = 0 , _compareValue = 11999
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 5999 , input dutycycle = 32768 , _compareValue = 11999 , frequency = 10000.00
    =====================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 100.00, PWM Freq (Hz) = 10000.0000
    =====================================================================================

    4. PWM_Waveform on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_Waveform on SAMD51 ITSYBITSY_M4, to demonstrate how to use the setPWM_manual() function in wafeform creation using TCC timer for 16-bit PWM

    Starting PWM_Waveform on ITSYBITSY_M4
    SAMD_PWM v1.0.1
    [PWM] calcTCCPrescaler: OK pin = 11 , period = 1000 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCCPrescaler: _dutycycle = 0 , frequency = 1000.00 , _prescalerConfigBits = 0 , _compareValue = 119999
    [PWM] setPWM: _dutycycle = 655 , frequency = 1000.00
    [PWM] SAMD51 setPWM_Int: _tcNum = 0 , _tcChannel = 1 , _pinAttr = 512
    [PWM] SAMD51 setPWM_Int: newDC = 1199 , input dutycycle = 655 , _compareValue = 119999 , frequency = 1000.00
    [PWM] SAMD51 setPWM_Int: New TCC => newDC = 1199 , input dutycycle = 655 , _compareValue = 119999 , frequency = 1000.00
    ============================================================================================
    Actual data: pin = 11, PWM DutyCycle = 0.00, PWMPeriod = 1000.00, PWM Freq (Hz) = 1000.0000
    ============================================================================================
    [PWM] setPWM_manual: DCValue = 0 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 0 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 5 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 5999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 10 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 11999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 15 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 17999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 20 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 23999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 25 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 29999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 30 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 35999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 35 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 41999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 40 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 47999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 45 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 53999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 50 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 59999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 55 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 65999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 60 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 71999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 65 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 77999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 70 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 83999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 75 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 89999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 80 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 95999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 85 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 101999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 90 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 107999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 95 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 113999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 100 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 119999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 95 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 113999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 90 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 107999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 85 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 101999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 80 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 95999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 75 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 89999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 70 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 83999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 65 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 77999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 60 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 71999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 55 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 65999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 50 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 59999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 45 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 53999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 40 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 47999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 35 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 41999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 30 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 35999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 25 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 29999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 20 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 23999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 15 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 17999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 10 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 11999 , _compareValue = 119999
    [PWM] setPWM_manual: DCValue = 5 , _frequency = 1000.00
    [PWM] setPWM_manual: New DCValue = 5999 , _compareValue = 119999

    5. PWM_Basic on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_Basic on SAMD51 ITSYBITSY_M4, to demonstrate how to use the basic function, using TC timer for 8-bit PWM

    Starting PWM_Basic on ITSYBITSY_M4
    SAMD_PWM v1.0.1
    [PWM] calcTCPrescaler: OK pin = 24 , period = 1000 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 0 , frequency = 1000.00 , _prescalerConfigBits = 0 , _compareValue = 119999
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 1000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 500 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 59999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 11999 , input dutycycle = 13107 , _compareValue = 59999 , frequency = 2000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 46 , input dutycycle = 13107 , _compareValue = 234 , frequency = 2000.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] setPWM_Int: change frequency to 5000.00 from 2000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 200 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 21598 , input dutycycle = 58982 , _compareValue = 23999 , frequency = 5000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 84 , input dutycycle = 58982 , _compareValue = 93 , frequency = 5000.00
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 5000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 500 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 59999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 11999 , input dutycycle = 13107 , _compareValue = 59999 , frequency = 2000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 46 , input dutycycle = 13107 , _compareValue = 234 , frequency = 2000.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] setPWM_Int: change frequency to 5000.00 from 2000.00
    [PWM] calcTCPrescaler: OK pin = 24 , period = 200 , _prescaler = 1 , F_CPU = 120000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD51 setPWM_Int: _tcNum = 5 , _tcChannel = 1 , _pinAttr = 8
    [PWM] SAMD51 setPWM_Int: newDC = 21598 , input dutycycle = 58982 , _compareValue = 23999 , frequency = 5000.00
    [PWM] SAMD51 setPWM_Int: New TC => newDC = 84 , input dutycycle = 58982 , _compareValue = 93 , frequency = 5000.00

    6. PWM_Basic on SAMD_NANO_33_IOT

    The following is the sample terminal output when running example PWM_Basic on SAMD21 SAMD_NANO_33_IOT, to demonstrate how to use the basic function, using TC timer for 8-bit PWM

    Starting PWM_Basic on SAMD_NANO_33_IOT
    SAMD_PWM v1.0.1
    [PWM] calcTCPrescaler: OK pin = 12 , period = 1000 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 0 , frequency = 1000.00 , _prescalerConfigBits = 0 , _compareValue = 47999
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 1000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 500 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4799 , input dutycycle = 13107 , _compareValue = 23999 , frequency = 2000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 18 , input dutycycle = 13107 , _compareValue = 93 , frequency = 2000.00
    [PWM] setPWM: _dutycycle = 58982 , frequency = 5000.00
    [PWM] setPWM_Int: change frequency to 5000.00 from 2000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 200 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 58982 , frequency = 5000.00 , _prescalerConfigBits = 0 , _compareValue = 9599
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 8639 , input dutycycle = 58982 , _compareValue = 9599 , frequency = 5000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 33 , input dutycycle = 58982 , _compareValue = 37 , frequency = 5000.00
    [PWM] setPWM: _dutycycle = 13107 , frequency = 2000.00
    [PWM] setPWM_Int: change frequency to 2000.00 from 5000.00
    [PWM] calcTCPrescaler: OK pin = 12 , period = 500 , _prescaler = 1 , F_CPU = 48000000
    [PWM] calcTCPrescaler: _dutycycle = 13107 , frequency = 2000.00 , _prescalerConfigBits = 0 , _compareValue = 23999
    [PWM] SAMD21 setPWM_Int: _tcNum = 3 , _tcChannel = 1 , _pinAttr = 28
    [PWM] SAMD21 setPWM_Int: newDC = 4799 , input dutycycle = 13107 , _compareValue = 23999 , frequency = 2000.00
    [PWM] SAMD21 setPWM_Int: New TC => newDC = 18 , input dutycycle = 13107 , _compareValue = 93 , frequency = 2000.00

    7. PWM_manual on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_manual on SAMD51 ITSYBITSY_M4, to demonstrate how to use the setPWM_manual() and setPWM_DCPercentage_manual() functions in wafeform creation

    Starting PWM_manual on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Not USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 0.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 5.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 10.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 15.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 20.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 25.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 30.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 35.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 40.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 45.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 55.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 60.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 65.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 70.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 75.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 80.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 85.01, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 90.01, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 95.01, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 100.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    =================================================================================================
    Actual data: pin = 11, PWM DC = 0.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    ...

    8. PWM_SpeedTest on ITSYBITSY_M4

    The following is the sample terminal output when running example PWM_SpeedTest on ITSYBITSY_M4, to demonstrate how to use new faster setPWM_manual() function in wafeform creation, The time is 1084 ns compared to 499,500 ns when using setPWM() function. The fastest is setPWM_DCPercentageInt_manual with 1067 ns, which is better to be used with pre-calculated values in array

    USING_DC_PERCENT
    Starting PWM_SpeedTest on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Average time of setPWM function USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=937083, ns=1067
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=936335, ns=1067
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=936358, ns=1067
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=936334, ns=1067
    ...
    
    USING_DC_PERCENT with extremely slow setPWM()
    Starting PWM_SpeedTest on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Average time of setPWM function USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2002, ns=499500
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2003, ns=499251
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2003, ns=499251
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=2003, ns=499251
    =================================================================================================
    Actual data: pin = 11, PWM DC = 50.00, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =======================================================
    
    not USING_DC_PERCENT
    Starting PWM_SpeedTest on ITSYBITSY_M4
    SAMD_PWM v1.2.0
    Average time of setPWM function not USING_DC_PERCENT
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=922600, ns=1083
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921932, ns=1084
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921965, ns=1084
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921951, ns=1084
    =================================================================================================
    Actual data: pin = 11, PWM DC = 44.86, PWMPeriod = 500.00, PWM Freq (Hz) = 2000.0000
    =================================================================================================
    count=921942, ns=1084


    Debug

    Debug is enabled by default on Serial.

    You can also change the debugging level _PWM_LOGLEVEL_ from 0 to 4

    // Don't define _PWM_LOGLEVEL_ > 0. Only for special ISR debugging only. Can hang the system.
    #define _PWM_LOGLEVEL_     0

    Troubleshooting

    If you get compilation errors, more often than not, you may need to install a newer version of the core for Arduino boards.

    Sometimes, the library will only work if you update the board core to the latest version because I am using newly added functions.



    Issues

    Submit issues to: SAMD_PWM issues



    TO DO

    1. Search for bug and improvement.
    2. Similar features for remaining Arduino boards

    DONE

    1. Basic hardware PWM-channels for SAMD21/SAMD51 boards such as NANO_33_IOT, ITSYBITSY_M4, SEEED_XIAO_M0, SparkFun SAMD51_Thing_Plus, etc. using
    1. Add example PWM_StepperControl to demo how to control Stepper Motor using PWM
    2. Add example PWM_manual to demo how to correctly use PWM to generate waveform
    3. Add function setPWM_DCPercentage_manual() to facilitate the setting PWM DC manually by using DCPercentage, instead of absolute DCValue depending on varying PWMPeriod
    4. Optimize speed with new setPWM_DCPercentageInt_manual function to improve speed almost 500 times compared to setPWM
    5. Add example PWM_SpeedTest to demo the better speed of new setPWM_DCPercentageInt_manual function
    6. Breaking change: Modify setPWM_manual function to take 16-bit dutycycle instead from merely 0-100 for better accuracy
    7. Modify example PWM_Waveform to adapt to breaking change of setPWM_manual function
    8. Improve README.md so that links can be used in other sites, such as PIO


    Contributions and Thanks

    Many thanks for everyone for bug reporting, new feature suggesting, testing and contributing to the development of this library.

    1. Thanks to Paul van Dinther for proposing new way to use PWM to drive Stepper-Motor in Using PWM to step a stepper driver #16, leading to v2.0.3
    dinther
    Paul van Dinther


    Contributing

    If you want to contribute to this project:

    • Report bugs and errors
    • Ask for enhancements
    • Create issues and pull requests
    • Tell other people about this library

    License

    • The library is licensed under MIT

    Copyright

    Copyright (c) 2022- Khoi Hoang

    Visit original content creator repository https://github.com/khoih-prog/SAMD_PWM
  • french_text_sentiment

    French-Text Sentiment Analysis

    Welcome to this project !

    The topic covered here is Sentiment Analysis in texts written in French language. For that, we employ a Recurrent Neural Network that we build and run thru the Tensorflow / Keras framework.
    The architecture of the model is based on dual bi-directionnal GRU cells and it employs fastText word embeddings. We train this model using tranfer learning from rated product reviews that have been web-scrapped using the BeautifulSoup python library (the web-scraping code is not provided, but the collected data is).
    The figure on the left shows the structure of this project. There are two key points to notice :

    • A dedicated custom python package named my_NLP_RNN_fr_lib has been developped to serve this project.
    • There’s a whole sub-section to the herein project, detailled separately, on hyperparameters optimization,. It can be found there . Spoiler alert : we deal with random search first, then XGBoost + scikit-learn are called to get an extra edge.

    The French-Text Sentiment Analysis project we’re dealing with here is explained in details and accompagnied with full running python code in a walkthrough Jupyter Notebook.

    Jupyter Notebook

    KEYWORDS : Tensorflow, Keras, GRU, RNN, NLP, fastText, web-scraping, BeautifulSoup, transfer learning, french sentiment analysis

    Visit original content creator repository https://github.com/aurelienmorgan/french_text_sentiment
  • bytecode

    Bytecode instruction set and stack based virtual machine.

    Usage

    Usage: bytecode <COMMAND>
    
    Commands:
      b2r        ByteCode source code file -> RawBytes file  [ByteCode -> RawBytes]
      run        Interpret RawBytes file                     [RawBytes -> Execution]
      help       Print this message or the help of the given subcommand(s)
    
    Options:
      -h, --help     Print help
      -V, --version  Print version
    

    RawBytes is data consisting of raw bytecode instructions and data.

    $ bytecode b2r -i examples/example1 -o examples/example1.raw
    $ bytecode run -i examples/example1.raw

    Bytecode file

    A small language exists to facilitate bytecode representation and is very simple to use.

    opcode [operand] ; comment
    
    push 2           ; Push 2 onto the stack.
    push 0xFF        ; Push 255 onto the stack.
    

    Opcodes

    Opcode Hex Operand Stack Description
    Noop 0x00 Does nothing.
    Push 0x01 value [.., value] Push value onto the stack.
    Add 0x02 [.., A, B] -> [.., R] Pop two values, add them. (A + B = R)
    Sub 0x03 [.., A, B] -> [.., R] Pop two values, subtract them. (A + B = R)
    Mul 0x04 [.., A, B] -> [.., R] Pop two values, multiply them. (A + B = R)
    Div 0x05 [.., A, B] -> [.., R] Pop two values, divide them. (A + B = R)
    Mod 0x06 [.., A, B] -> [.., R] Pop two values, modulo them. (A + B = R)
    Jump 0x07 offset [.., ptr] -> [..] Jump to offset (pointer).
    JumpIfFalse 0x08 offset [.., ptr] -> [..] If top of stack is 0, jump to offset.
    GT 0x09 [.., A, B] -> [.., R] Pop two values, push true(1) if first is greater, else false(0).
    LT 0x0A [.., A, B] -> [.., R] Pop two values, push true(1) if first is less.
    GTE 0x0B [.., A, B] -> [.., R] Pop two values, push true(1) if first is greater or equal.
    LTE 0x0C [.., A, B] -> [.., R] Pop two values, push true(1) if first is less or equal.
    EQ 0x0D [.., A, B] -> [.., R] Pop two values, push true(1) if equal.
    Proc 0x0E length [.., ptr] -> [..] Instruction to delimit a procedure. instructions after length are omitted.
    Call 0x0F offset [.., ptr] -> [..] Call procedure at offset.
    Ret 0x10 Return from procedure. See procedures for more details.
    Store 0x11 index [.., value] -> [..] Pop value and store it at index.
    Load 0x12 index [..] -> [.., value] Load value at index and push it onto the stack.
    0x13 ~ 0xFD Not used.
    Exit 0xFE Exit the program.
    Debug 0xFF value Description Print the stack. -1 = pops all, value = pops value items.

    Procedures

    Proc opcode takes a length operand, which is the number of instructions to skip after the Proc opcode.

    Then, after executing the procedure in the CallStack using the Call instruction, the offset(pointer) to return to is stored.
    After that, Call jump to the first instruction in the procedure and executes the procedure.

    Return jumps to the return pointer stored in the CallStack.

    proc 2     ; 0, The 2 instructions below are omitted.
        noop   ; 1
        return ; 2, Jump to the pointer (4) stored in the CallStack.
    
    call 1     ; 3, After saving the pointer to return (4) to the CallStack, jump to the pointer 1 of the first instruction of the procedure.
    noop       ; 4, Executed after the procedure runs.
    

    Example

    See examples for more examples.

    Visit original content creator repository
    https://github.com/siglang/bytecode

  • tradingview-api-adapter

    tradingview-api-adapter

    📊 API Adapter for real-time market data as quoted prices and symbol ticker details from Tradingview 📈

    ♻︎ In developing

    ✅ Current Test Version: 1.2.0 [16.02.2023]

    👨🏻‍💻I need your feedback. Help improve the library for our general benefit

    Installation

    Stable version:

    npm i tradingview-api-adapter

    Examples

    Quote [Class]: Obtaining quoted data in real time

    Fields

      minmov, minmove2, circulating_supply, popularity
      average_volume, total_supply, total_shares_outstanding,   
      
      ask, bid,
      
      lp, low_price, open_price, high_price, prev_close_price, 
      open_time, chp, ch, volume, total_shares_diluted, total_value_traded,
      pricescale, pointvalue,
      
      first_bar_time_1s, first_bar_time_1m, first_bar_time_1d,
      all_time_high, all_time_open, all_time_low,
      price_52_week_low, price_percent_change_52_week, price_52_week_high, price_percent_change_1_week
      price_percent_change_1_week,
      
      'trade', 'minute-bar', 'daily-bar', 'prev-daily-bar'

    Usage

    import {TvApiAdapter} from 'tradingview-api-adapter'
    
    
    const adapter = new TvApiAdapter();
    
    adapter.Quote('BTCUSD', 'BINANCE', ['lp', 'ch', 'chp']).listen(data => {
        console.log('Last price: ', data.lp);
        console.log('Price change: ', data.ch);
        console.log('Price change in percent: ', data.ch);
    })

    Result for all fields

      minmove2: 0,
      minmov: 1,
    
      circulating_supply: 19289550,
      popularity: 6559928,
      average_volume: 1722.622664,
      total_supply: 19289550,
      total_shares_outstanding: 19289550,
    
    
      lp: 21666.54,
      low_price: 21431.41,
      open_price: 21793.12,
      high_price: 21899.36,
      prev_close_price: 21792.89,
      open_time: 1676246400,
      chp: -0.58,
      ch: -126.35,
      volume: 1113.41904,
      total_shares_diluted: 21000000,
      total_value_traded: 22323876304.39608,
    
      pricescale: 100,
      pointvalue: 1,
    
      first_bar_time_1s: 1660694401,
      first_bar_time_1m: 1578038400,
      first_bar_time_1d: 1578009600,
      all_time_high: 69275.4705132,
      all_time_open: 6976.1030327,
      all_time_low: 3717.974312,
      price_52_week_low: 15479.25,
      price_percent_change_52_week: -48.97188345,
      price_52_week_high: 48240.33,
      price_percent_change_1_week: -6.03974829,
      
      trade: {
        'data-update-time': '1676290514.699386',
        price: '21641.98',
        size: '0.01892',
        time: '1676290505'
      },
      'minute-bar': {
        close: '21641.98',
        'data-update-time': '1676290514.699386',
        high: '21641.98',
        low: '21641.17',
        open: '21641.37',
        time: '1676290500',
        'update-time': '1676290505.0',
        volume: '0.02528'
      },
      'daily-bar': {
        close: '21641.98',
        'data-update-time': '1676290514.699387',
        high: '21899.36',
        low: '21431.41',
        open: '21793.12',
        time: '1676246400',
        'update-time': '1676290505.0',
        volume: '1067.39197'
      },
      'prev-daily-bar': {
        close: '21792.89',
        'data-update-time': '1676246400.609871',
        high: '22092.14',
        low: '21640.57',
        open: '21851.81',
        time: '1676160000',
        'update-time': '1676246396.0',
        volume: '1171.77258'
      }
    }

    QuoteChannel [💎NEW Class]: Obtaining multi-quoted data in real time

    Usage

    import {TvApiAdapter} from 'tradingview-api-adapter'
    
    
    const adapter = new TvApiAdapter();
    
    const exChannel = adapter.QuoteChannel({
        'MUN': ['APC'],
        'Binance': ['BTCUSDT', 'DOGEUSDT']
    }, ['lp', 'ask', 'bid'])
    
    =====or=====
    
    const exChannel = adapter.QuoteChannel([
        'BINANCE:BTCUSDT', 'BINANCE:DOGEUSDT' 'MUN:APC'
    ], ['lp', 'ask', 'bid'])
    
    
    exChannel.listen(data => {
        console.log(data)
    })

    The result of the console

    {
      BINANCE: {
        DOGEUSDT: { lp: 0.08892, bid: 0.08892, ask: 0.08893 },
        BTCUSDT: { bid: 24597.31, ask: 24597.32, lp: 24597.23 }
      },
      MUN: { 
        APC: { lp: 145.24, bid: 144.86, ask: 144.92 } 
      }
    }

    TickerDetails [Class]: Allows you to get additional info about Ticker Symbol

    Usage

    import {TvApiAdapter} from 'tradingview-api-adapter'
    
    const adapter = new TvApiAdapter();
    
    const DogeInfo = adapter.TickerDetails('DOGEUSD', 'Binance');
    
    DogeInfo.ready(tm => {
        console.log(tm)
    })

    The result of the console

    {
        seriesKey: 'BINANCE:DOGEUSD',
        baseName: [ 'BINANCE:DOGEUSD' ],
        symbol: 'DOGEUSD',
        symbolFullname: 'BINANCE:DOGEUSD',
        feedTicker: 'DOGEUSD',
        exchangeListedSymbol: 'DOGEUSD',
        sessionId: 'crypto',
        sessionRegularDisplay: '24x7',
        sessionExtendedDisplay: '24x7',
        sessionExtended: '24x7',
        sessionDisplay: '24x7',
        sessionRegular: '24x7',
        subsessions: [
            {
                description: 'Regular Trading Hours',
                id: 'regular',
                private: false,
                session: '24x7',
                'session-display': '24x7'
            }
        ],
        subsessionId: 'regular',
        group: 'binance_spreads_runner2',
        perms: { rt: { prefix: 'BINANCE' } },
        marketStatus: { phase: 'regular', tradingday: '20230215' },
        internalStudyId: 'CurrencyConverter@tv-basicstudies-132!',
        internalStudyInputs: { rate: 'INDEX:BTCUSD', symbol: 'BINANCE:DOGEBTC', useRTRate: true },
        exchange: 'BINANCE',
        exchangeTraded: 'BINANCE',
        listedExchange: 'BINANCE',
        providerId: 'binance',
        description: 'Dogecoin / US Dollar (calculated by TradingView)',
        shortDescription: 'Dogecoin / US Dollar (calculated by TradingView)',
        type: 'crypto',
        currencyCode: 'USD',
        currencyId: 'USD',
        baseCurrency: 'DOGE',
        baseCurrencyId: 'XTVCDOGE',
        symbolPrimaryName: 'BINANCE:DOGEUSD',
        symbolProname: 'BINANCE:DOGEUSD',
        proName: 'BINANCE:DOGEUSD',
        shortName: 'DOGEUSD',
        originalName: 'BINANCE:DOGEUSD',
        maxPrecision: 8,
        isTradable: false,
        hasDepth: false,
        fundamentalData: true,
        fractional: false,
        popularityRank: 3.5793118736554446,
        proPerm: '',
        variableTickSize: '',
        historyTag: '',
        rtLag: '9.069304',
        rtUpdateTime: '1676465374.0',
        timezone: 'Etc/UTC',
        currentSession: 'market',
        feedHasIntraday: true,
        hasIntraday: true,
        isReplayable: true,
        hasPriceSnapshot: false,
        feed: 'runner-intraday',
        feedHasDwm: false,
        hasNoBbo: false,
        hasNoVolume: false,
        hasDwm: true,
        localPopularity: {
            AE: 790,
            BR: 4642,
            CN: 5611,
            DE: 13065,
            ES: 13891,
            FR: 15763,
            ID: 2634,
            IL: 318,
            IN: 13750,
            IT: 5159,
            JP: 6325,
            KR: 5983,
            PL: 5440,
            RU: 29302,
            SE: 645,
            TH: 7900,
            TR: 20474,
            TW: 3793,
            US: 539550,
            VN: 2443
        },
        localPopularityRank: {
            AE: 4.2420188926631495,
            BR: 3.8731514888536487,
            CN: 3.8369531543119244,
            DE: 3.5775828338723796,
            ES: 3.8642349392929574,
            FR: 3.5099721819085126,
            ID: 3.634900014607327,
            IL: 3.946343180230935,
            IN: 4.3838522732435745,
            IT: 3.65965996833445,
            JP: 4.086705608977654,
            KR: 3.7368189724535967,
            PL: 3.5024902792902957,
            RU: 3.7239316911388682,
            SE: 3.8583321674815934,
            TH: 3.512627747031323,
            TR: 3.629837049479071,
            TW: 3.74280732258542,
            US: 3.463184155816383,
            VN: 4.052303315748319
        },
        visiblePlotsSet: 'ohlcv',
        prefixes: [ 'RUNNER_BINANCE2' ],
        brokerNames: {},
        currencyLogoId: 'country/US',
        baseCurrencyLogoId: 'crypto/XTVCDOGE',
        volumeType: 'base',
        typespecs: [ 'synthetic' ]
    }

    Visit original content creator repository
    https://github.com/swarum/tradingview-api-adapter

  • The-Hungry-Kitchen

    The-Hungry-Kitchen

    The-Hungry-Kitchen is a recipe search website that allows users to discover recipes based on their dietary preferences and health considerations. Built with EJS, SASS, JavaScript, Node.js, RecipeSearchAPI, Nodemailer, MongoDB, and Express, it offers a rich user experience with a functional and intuitive interface.

    Features

    • Home page with popular meals and email sign-up section.
    • Recipe search functionality that displays recipes with details like calories, diet, and health labels.
    • Email notifications for updates and news via Nodemailer.
    • User email storage in MongoDB for future marketing and information dissemination.

    Live Demo

    You can try out a live demo of the application here: The-Hungry-Kitchen Live

    Installation

    To get a local copy up and running follow these simple steps.

    1. Clone the repository:

    git clone https://github.com/SamuelFanawopo/The-Hungry-Kitchen.git
    cd The-Hungry-Kitchen
    1. Install NPM packages:
    npm install

    Usage

    To start the server, run:

    npm start

    For development, you can use the nodemon server with:

    npm run dev

    License

    The Hungry Kitchen is open-sourced under the MIT License. Feel free to contribute, fork, and adapt it for your personal or professional projects.

    Acknowledgements

    • EJS – For the embedded JavaScript templates enabling dynamic content rendering.
    • SASS – For the powerful CSS extension language that simplifies styling.
    • Node.js – The JavaScript runtime that powers the server-side logic.
    • Edamam Recipe Search API – For providing an extensive recipe database and search functionality.
    • Nodemailer – For enabling email sending capabilities within the application.
    • MongoDB – For the scalable, high-performance NoSQL database.
    • Express – The fast and minimalist web framework for Node.js applications.

    Visit original content creator repository
    https://github.com/SamuelFanawopo/The-Hungry-Kitchen

  • alfresco-export-scripts

    Alfresco Export Scripts

    Alfresco shell scripts for extracting user, groups, sites, data and metadata information from Alfresco repository. For the extraction of metadata information it is needed to deploy a webscript in Alfresco Repository.

    Table of Contents

    Installation

    For running the shell scripts we need curl, wget, sed and jq shell utilities on the command line. For using metadata extraction, we need to deploy all webscript files under in /Data Dictionary/Web Scripts/net/zylk and then, to refresh Webscripts in /alfresco/service/index page.

    Environment vars

    Originally each shell script was provided with parameters in the command line (-e -u -p ). For making the script execution easier, we provide exportENVARS.sh script that may be used according to your environment, every script invokes it.

    $ cat exportENVARS.sh
    
    #! /bin/bash
    export ALFURL=http://localhost:8080/alfresco
    export MYUSER=admin
    export MYPASS=secret
    

    Bulk Export Scripts

    The following two scripts (downloadSite.sh and getMetadata.sh) are needed to extract Alfresco documents and their corresponding metadata from repository. For running getMetadata.sh properly we need to deploy export-bulk-metadata webscript in Alfresco Server.

    Note: A better approach is probably done with Alfresco Bulk Export Module but it only works from Alfresco 4.2 and above (JDK7 needed).

    downloadSite.sh

    It downloads a site (-s) or a given repository folder (-f) via wget using webdav,

    $ ./downloadSite.sh -h
    Usage: ./downloadAlfrescoSite.sh [-s <site-shortname>] | [-f <folder>]
    

    For downloading the example site in Alfresco (Web Site Design Project):

    $ ./downloadSite.sh -s swsdp
    

    ├── webdav
    │   └── Sitios
    │       └── swsdp
    │           └── documentLibrary
    │               ├── Agency Files
    │               │   ├── Contracts
    │               │   │   └── Project Contract.pdf
    │               │   ├── Images
    │               │   │   ├── coins.JPG
    │               │   │   ├── graph.JPG
    │               │   │   ├── grass.jpg
    │               │   │   ├── header.png
    │               │   │   ├── low consumption bulb.png
    │               │   │   ├── money.JPG
    │               │   │   ├── plugs.jpg
    │               │   │   ├── turbine.JPG
    │               │   │   ├── windmill.png
    │               │   │   ├── wind turbine.JPG
    │               │   │   └── wires.JPG
    │               │   ├── Logo Files
    │               │   │   ├── GE Logo.png
    │               │   │   └── logo.png
    │               │   ├── Mock-Ups
    │               │   │   ├── sample 1.png
    │               │   │   ├── sample 2.png
    │               │   │   └── sample 3.png
    │               │   └── Video Files
    │               │       └── WebSiteReview.mp4
    │               ├── Budget Files
    │               │   ├── budget.xls
    │               │   └── Invoices
    │               │       ├── inv I200-109.png
    │               │       └── inv I200-189.png
    │               ├── Meeting Notes
    │               │   ├── Meeting Notes 2011-01-27.doc
    │               │   ├── Meeting Notes 2011-02-03.doc
    │               │   └── Meeting Notes 2011-02-10.doc
    │               └── Presentations
    │                   ├── Project Objectives.ppt
    │                   └── Project Overview.ppt
    

    getMetadata.sh

    It gets metadata files (needed for a bulk import) of a previously downloaded site or folder.

    $ ./getMetadata.sh -h
    Usage: ./getMetadata.sh [-f <local-webdav-folder>]
    
    $ ./getMetadata.sh -f webdav
    

    generating the corresponding metadata.properties.xml foreach document and folder.

    ├── webdav
    │   ├── Sitios
    │   │   ├── swsdp
    │   │   │   ├── documentLibrary
    │   │   │   │   ├── Agency Files
    │   │   │   │   │   ├── Contracts
    │   │   │   │   │   │   ├── Project Contract.pdf
    │   │   │   │   │   │   └── Project Contract.pdf.metadata.properties.xml
    │   │   │   │   │   ├── Contracts.metadata.properties.xml
    │   │   │   │   │   ├── Images
    │   │   │   │   │   │   ├── coins.JPG
    │   │   │   │   │   │   ├── coins.JPG.metadata.properties.xml
    │   │   │   │   │   │   ├── graph.JPG
    │   │   │   │   │   │   ├── graph.JPG.metadata.properties.xml
    │   │   │   │   │   │   ├── grass.jpg
    │   │   │   │   │   │   ├── grass.jpg.metadata.properties.xml
    │   │   │   │   │   │   ├── header.png
    │   │   │   │   │   │   ├── header.png.metadata.properties.xml
    │   │   │   │   │   │   ├── low consumption bulb.png
    │   │   │   │   │   │   ├── low consumption bulb.png.metadata.properties.xml
    │   │   │   │   │   │   ├── money.JPG
    │   │   │   │   │   │   ├── money.JPG.metadata.properties.xml
    │   │   │   │   │   │   ├── plugs.jpg
    │   │   │   │   │   │   ├── plugs.jpg.metadata.properties.xml
    │   │   │   │   │   │   ├── turbine.JPG
    │   │   │   │   │   │   ├── turbine.JPG.metadata.properties.xml
    │   │   │   │   │   │   ├── windmill.png
    │   │   │   │   │   │   ├── windmill.png.metadata.properties.xml
    │   │   │   │   │   │   ├── wind turbine.JPG
    │   │   │   │   │   │   ├── wind turbine.JPG.metadata.properties.xml
    │   │   │   │   │   │   ├── wires.JPG
    │   │   │   │   │   │   └── wires.JPG.metadata.properties.xml
    │   │   │   │   │   ├── Images.metadata.properties.xml
    │   │   │   │   │   ├── Logo Files
    │   │   │   │   │   │   ├── GE Logo.png
    │   │   │   │   │   │   ├── GE Logo.png.metadata.properties.xml
    │   │   │   │   │   │   ├── logo.png
    │   │   │   │   │   │   └── logo.png.metadata.properties.xml
    │   │   │   │   │   ├── Logo Files.metadata.properties.xml
    │   │   │   │   │   ├── Mock-Ups
    │   │   │   │   │   │   ├── sample 1.png
    │   │   │   │   │   │   ├── sample 1.png.metadata.properties.xml
    │   │   │   │   │   │   ├── sample 2.png
    │   │   │   │   │   │   ├── sample 2.png.metadata.properties.xml
    │   │   │   │   │   │   ├── sample 3.png
    │   │   │   │   │   │   └── sample 3.png.metadata.properties.xml
    │   │   │   │   │   ├── Mock-Ups.metadata.properties.xml
    │   │   │   │   │   ├── Video Files
    │   │   │   │   │   │   ├── WebSiteReview.mp4
    │   │   │   │   │   │   └── WebSiteReview.mp4.metadata.properties.xml
    │   │   │   │   │   └── Video Files.metadata.properties.xml
    │   │   │   │   ├── Agency Files.metadata.properties.xml
    │   │   │   │   ├── Budget Files
    │   │   │   │   │   ├── budget.xls
    │   │   │   │   │   ├── budget.xls.metadata.properties.xml
    │   │   │   │   │   ├── Invoices
    │   │   │   │   │   │   ├── inv I200-109.png
    │   │   │   │   │   │   ├── inv I200-109.png.metadata.properties.xml
    │   │   │   │   │   │   ├── inv I200-189.png
    │   │   │   │   │   │   └── inv I200-189.png.metadata.properties.xml
    │   │   │   │   │   └── Invoices.metadata.properties.xml
    │   │   │   │   ├── Budget Files.metadata.properties.xml
    │   │   │   │   ├── Meeting Notes
    │   │   │   │   │   ├── Meeting Notes 2011-01-27.doc
    │   │   │   │   │   ├── Meeting Notes 2011-01-27.doc.metadata.properties.xml
    │   │   │   │   │   ├── Meeting Notes 2011-02-03.doc
    │   │   │   │   │   ├── Meeting Notes 2011-02-03.doc.metadata.properties.xml
    │   │   │   │   │   ├── Meeting Notes 2011-02-10.doc
    │   │   │   │   │   └── Meeting Notes 2011-02-10.doc.metadata.properties.xml
    │   │   │   │   ├── Meeting Notes.metadata.properties.xml
    │   │   │   │   ├── Presentations
    │   │   │   │   │   ├── Project Objectives.ppt
    │   │   │   │   │   ├── Project Objectives.ppt.metadata.properties.xml
    │   │   │   │   │   ├── Project Overview.ppt
    │   │   │   │   │   └── Project Overview.ppt.metadata.properties.xml
    │   │   │   │   └── Presentations.metadata.properties.xml
    │   │   │   └── documentLibrary.metadata.properties.xml
    │   │   └── swsdp.metadata.properties.xml
    │   └── Sitios.metadata.properties.xml
    

    The following webscript is needed to deploy in Alfresco in /Data Dictionary/Web Scripts/net/zylk:

    • export-bulk-metadata.get.desc.xml
    • export-bulk-metadata.get.js
    • export-bulk-metadata.get.text.ftl

    Other helper scripts

    This helper scripts are examples based on the blog post Alfresco REST API examples using curl and jq

    Note: A similar approach is done with Alfresco Shell Tools.

    getPeople.sh

    It provides a complete list of users of Alfresco repository. With -f option it adds first name, surname and user email.

    $ ./getPeople.sh -h
    Usage: ./getPeople.sh [-f]
    
    $ ./getPeople.sh
    guest
    admin
    abeecher
    mjackson
    
    $ ./getPeople.sh -f
    guest,Guest,,
    admin,Administrator,,admin@alfresco.com
    abeecher,Alice,Beecher,abeecher@example.com
    mjackson,Mike,Jackson,mjackson@example.com
    

    getGroups.sh

    It gives the list of repository groups. With -f option you may obtain additionally info.

    $ ./getGroups.sh -h
    Usage: ./getGroups.sh [-f]
    
    $ ./getGroups.sh
    ALFRESCO_ADMINISTRATORS
    ALFRESCO_MODEL_ADMINISTRATORS
    ALFRESCO_SEARCH_ADMINISTRATORS
    EMAIL_CONTRIBUTORS
    SITE_ADMINISTRATORS
    site_swsdp
    site_swsdp_SiteCollaborator
    site_swsdp_SiteConsumer
    site_swsdp_SiteContributor
    site_swsdp_SiteManager
    

    getSites.sh

    It gives a list with the shortnames of the sites. With -f option you additionally get the visibility and the title of the site.

    $ ./getSites.sh -h
    Usage: ./getSites.sh [-f]
    
    $ ./getSites.sh
    swsdp
    
    $ ./getSites.sh -f
    swsdp,PUBLIC,Sample: Web Site Design Project
    

    getSiteMemberships.sh

    It provides the list of users and roles of a given site (-s ).

    $ ./getSiteMemberships.sh -h
    Usage: ./getAlfrescoSiteMemberships.sh [-f | -s <site>]
    
    $ ./getSiteMemberships.sh -s swsdp
    swsdp,mjackson,SiteManager
    swsdp,admin,SiteManager
    swsdp,abeecher,SiteCollaborator
    

    With -f option you obtain the full list of users and roles for every site in Alfresco repository.

    getUserGroups.sh

    ./getUserGroups.sh -h
    Usage: ./getUserGroups.sh [-f] [-a user]
    

    It provides the groups of a given user (-a ).

    $ ./getUserGroups.sh -a admin
    GROUP_ALFRESCO_ADMINISTRATORS
    GROUP_ALFRESCO_MODEL_ADMINISTRATORS
    GROUP_ALFRESCO_SEARCH_ADMINISTRATORS
    GROUP_EMAIL_CONTRIBUTORS
    GROUP_SITE_ADMINISTRATORS
    

    getAuthority.sh

    It provides the users and groups of a given group (-g ). With -f option you obtain further details.

    $ ./getAuthority.sh -h
    Usage: ./getAuthority.sh [-f] [-g <group>]
    
    $ ./getAuthority.sh -g ALFRESCO_ADMINISTRATORS
    admin
    
    $ ./getAuthority.sh -g ALFRESCO_ADMINISTRATORS -f
    admin,Administrator,Administrator,USER
    

    More Download Scripts

    downloadDoc.sh

    It provides a download script for a given Alfresco uuid and filename

    $ ./downloadDoc.sh -h
    Usage: ./downloadDoc.sh [-d uuid] [-n name]
    

    downloadList.sh

    Download files selected from a webscript list resultset.

    $ ./downloadList.sh
    

    A second webscript is necessary to deploy in Alfresco in /Data Dictionary/Web Scripts/net/zylk:

    • get-download-list.get.desc.xml
    • get-download-list.get.js
    • get-download-list.get.text.ftl

    The webscript obtains a list of files flagged with “critical” tag, but may be customized for any alfresco-fts query:

    workspace://SpacesStore/5515d3e1-bb2a-42ed-833c-52802a367033;Sitios/swsdp/documentLibrary/Presentations;Project Objectives.ppt
    workspace://SpacesStore/99cb2789-f67e-41ff-bea9-505c138a6b23;Sitios/swsdp/documentLibrary/Presentations;Project Overview.ppt
    

    Permission Scripts

    getPerms.sh

    It provides the local permission template under a rootpath (given by a noderef). If no user is given it provides a full list of local permissions.

    $ ./getPerms.sh <noderef> [user]
    
    $ ./getPerms.sh workspace://SpacesStore/8f2105b4-daaf-4874-9e8a-2152569d109b
    
       /Company Home/Sites/swsdp/documentLibrary/Budget Files;mjackson;SiteManager;workspace://SpacesStore/8ab12916-4897-47fb-94eb-1ab699822ecb
       /Company Home/Sites/swsdp/documentLibrary/Budget Files;abeecher;SiteCollaborator;workspace://SpacesStore/8ab12916-4897-47fb-94eb-1ab699822ecb
       /Company Home/Sites/swsdp/documentLibrary/Agency Files;mjackson;SiteManager;workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28
       /Company Home/Sites/swsdp/documentLibrary/Agency Files;abeecher;SiteCollaborator;workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28
       /Company Home/Sites/swsdp/documentLibrary/Meeting Notes;mjackson;SiteManager;workspace://SpacesStore/a211774d-ba6d-4a35-b97f-dacfaac7bde3
       /Company Home/Sites/swsdp/documentLibrary/Presentations;abeecher;SiteCollaborator;workspace://SpacesStore/38745585-816a-403f-8005-0a55c0aec813
    

    The aim of this script is to obtain a template of permissions for a new user, with respect a given user. For example, I want to give user johndoe the same exact permissions of abeecher. With the following output (changing abeecher by johndoe) I would generate the input for set-perms.sh script.

    $ ./getPerms.sh workspace://SpacesStore/8f2105b4-daaf-4874-9e8a-2152569d109b abeecher
       /Company Home/Sites/swsdp/documentLibrary/Budget Files;abeecher;SiteCollaborator;workspace://SpacesStore/8ab12916-4897-47fb-94eb-1ab699822ecb
       /Company Home/Sites/swsdp/documentLibrary/Agency Files;abeecher;SiteCollaborator;workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28
       /Company Home/Sites/swsdp/documentLibrary/Presentations;abeecher;SiteCollaborator;workspace://SpacesStore/38745585-816a-403f-8005-0a55c0aec813
    

    This script may be useful for complex (local) permissions maps.

    getFolders.sh

    It provides a folder permission template under a rootpath (given by a noderef). It lists a complete folder list under a given node, normally when permissions are set.

    $ ./getFolders.sh <noderef> [user] [role]
    
    $ ./getFolders.sh workspace://SpacesStore/8f2105b4-daaf-4874-9e8a-2152569d109b
    
       /Company Home/Sites/swsdp/documentLibrary/Budget Files;johndoe;SiteManager;workspace://SpacesStore/8ab12916-4897-47fb-94eb-1ab699822ecb
       /Company Home/Sites/swsdp/documentLibrary/Agency Files;johndoe;SiteManager;workspace://SpacesStore/8bb36efb-c26d-4d2b-9199-ab6922f53c28
       /Company Home/Sites/swsdp/documentLibrary/Meeting Notes;johndoe;SiteManager;workspace://SpacesStore/a211774d-ba6d-4a35-b97f-dacfaac7bde3
       /Company Home/Sites/swsdp/documentLibrary/Presentations;johndoe;SiteManager;workspace://SpacesStore/38745585-816a-403f-8005-0a55c0aec813
       /Company Home/Sites/swsdp/documentLibrary/Agency Files/Contracts;johndoe;SiteManager;workspace://SpacesStore/e0856836-ed5e-4eee-b8e5-bd7e8fb9384c
       /Company Home/Sites/swsdp/documentLibrary/Agency Files/Images;johndoe;SiteManager;workspace://SpacesStore/880a0f47-31b1-4101-b20b-4d325e54e8b1
       /Company Home/Sites/swsdp/documentLibrary/Agency Files/Logo Files;johndoe;SiteManager;workspace://SpacesStore/b1a98357-4f7a-470d-bf4c-327501158689
       /Company Home/Sites/swsdp/documentLibrary/Agency Files/Mock-Ups;johndoe;SiteManager;workspace://SpacesStore/610771be-4d82-479a-a2d7-796adf498084
       /Company Home/Sites/swsdp/documentLibrary/Agency Files/Video Files;johndoe;SiteManager;workspace://SpacesStore/1d26e465-dea3-42f3-b415-faa8364b9692
       /Company Home/Sites/swsdp/documentLibrary/Budget Files/Invoices;johndoe;SiteManager;workspace://SpacesStore/d56afdc3-0174-4f8c-bce8-977cafd712ab
    

    If a user / role are not provided, johndoe and SiteManager were used.

    setPerms.sh

    It sets local permissions from a permission template file. The permission file template is the one given by getPerms.sh or getFolders.sh scripts

    $ ./setPerms.sh <permissions-file>
    

    3 new webscripts are needed to deploy in Alfresco in /Data Dictionary/Web Scripts/net/zylk:

    • get-folder-perms.get.desc.xml
    • get-folder-perms.get.js
    • get-folder-perms.get.text.ftl
    • get-perms.get.desc.xml
    • get-perms.get.js
    • get-perms.get.text.ftl
    • set-perm.get.desc.xml
    • set-perm.get.js
    • set-perm.get.text.ftl

    Tested on

    • Alfresco Enterprise 4.1.1
    • Alfresco Enterprise 5.2.3
    • Alfresco Community 201707GA
    • Alfresco Community 201911GA

    Known Limitations

    • Not able to download versions of documents via downloadSite.sh script.
    • Not able to download documents via webdav when Kerberos or NTML SSO is enabled.
    • Use -k option in curl commands or –no-check-certificate in wget scripts, in case of dealing with self-signed SSL certificates

    History

    • 202212 – Permissions scripts and webscripts.
    • 202209 – Maxlevel option for crawling and several encoding adjustments. Thanks to Romain Brochot.
    • 202206 – Fixing encoding functions for solving special character path issues
    • 202201 – Added download tagged doc list feature via webscript
    • 201808 – Initial release

    Author

    Links

    Visit original content creator repository
    https://github.com/zylklab/alfresco-export-scripts

  • blog-daohang

    中文博客列表导航项目

    stars     stars     stars

    logo

    目前我们依旧在维护 V2 版本 的项目程序,V3 版本的项目程序正在积极开发中,项目所涉及的审核标准和相关流程也在逐渐完善中。
    诚挚邀请对项目感兴趣的您参与到本项目的建设当中来,您可以选择参与开发参与维护的任意一项,通过本项目的 Issue 联系我们。
    当然,如果您对本项目有更好的建议或者意见,也欢迎您通过 Issue 向我们反馈,我们会慎重考虑您的意见和意见。
    中文博客列表导航 V3 版本前端 | 中文博客列表导航V3版本后端 | 联系我们


    功能列表

    本项目尝试链接全部中文独立博客,目前含有如下功能:

    1. 查看随机推荐的博客
    2. 随机前往已收录的博客,您可以通过在 URL 添加参数进行指定类型博客的随机跳转,如:https://zhblogs.ohyee.cc/go?tags=生活,即可随机访问生活类博客。
    3. 查看本项目 收录博客的部分数据统计 (如:博客架构统计域名统计 等)。

    博客收录

    目前,我们通过以下三种方式对博客进行收录:

    1. 通过一些博客集合(上游库)发现并收录。
    2. 参考已收录博客的友情链接进行收录。
    3. 博主的自主提交。

    我们会依据 项目相关标准 对博客进行 博客收录信息完善博客分类 等相关操作,如您发现项目中您博客的信息、分类等内容有误,或者在浏览过程中发现其它博客的信息有误,也欢迎您通过 Issue 提出修改意见,我们会尽快处理。

    项目相关标准

    我们对项目实行的相关标准和流程(下称 文档)放置在当前项目仓库的 WIKI 选项卡中,您可以点击链接前往阅读。

    以下是文档的简要目录和说明:

    标准名称 标准说明
    博客分类与博客标签标准 该文档对 中文博客列表导航标签分类系统 进行说明
    常用标签含义说明 对常见的(除了使用技术栈命名的标签)标签进行解释说明

    欢迎您对项目文档提出意见或建议,我们会考虑您的提议,来不断完善本项目的各种标准和流程。

    支持我们

    如果您喜欢本项目,不妨通过以下方式支持该项目:

    1. 您可以在项目中搜索您的博客,若未收录,您可以在 Issue 中找到申请添加的链接,若已收录,您可以在 Issue 中找到信息完善的选项,帮助我们完善您博客的相关信息。
    2. 您可以为本仓库点一个 Star。
    3. 您可以为本项目做宣传,让更多博主知道本项目。
    4. 您可以加入本项目的技术组或者维护组,对本项目进行维护。

    若您有博客申请收录、博客信息修改、博客失效反馈、博客信息完善、项目 BUG 反馈、项目功能建议等内容需要与项目组进行反馈,您可以前往 Issues · zh-blogs/blog-daohang 选择对应的模板进行反馈

    参与本项目相关标准构建,请参考:项目标准贡献

    参与 V3 版本前端开发,请参考:V3 版本前端贡献

    参与 V3 版本后端开发,以及加入项目维护组请通过上方 Issue 选项卡中的加入我们 与我们联系

    维护成员名单(排名不分先后)

    本项目尊重维护人员个人意愿,根据维护人员个人情况决定对项目是否继续进行维护。

    依照 项目维护意向调查 Issue #24

    感谢对本项目做出贡献的各位维护人员,你们的付出是对本项目最大的支持和鼓励。

    现项目维护人员:

    技术组:负责对本项目的相关程序进行开发和维护,包括但不限于项目的前端、后端、数据同步工具等。

    维护组:负责对本项目的项目数据进行维护,包括但不限于项目博客审核、信息完善、标准完善等。

    技术组 维护组
    OhYee(技术组负责人) linlinzzo(项目整体负责人、维护组负责人)
    soxft(技术组负责人) MYXXTS(维护组负责人、项目标准制定人)
    Mabbs aquausora
    wibus-wee Lafcadia
    liangmiQwQ
    Redish101

    前项目维护人员:

    @Innei @jsun969 @zkeq @Dian-C @huziyan1 @jonepengcn @Kagurain @liangmis @Timozaici @Changrui0101 @Lfhsheng @hydrogenoxide-user @Innei @Amitabha @waterelegance @linhaii @yzqzss @hilllei@gtxykn0504

    感谢以下网站对本项目的宣传

    友链 – 阿锋的小宇宙 (feng.pub)

    中文独立博客圈 – 博客志 (jetli.com.cn)

    中文博客列表导航项目 – 杜老师说 (dusays.com)

    谈谈几个博客聚合网站,以及个人推荐 – 铎鸣也 (wordpress.com)

    万亿及秭 – peachRL 的小站 (wanyijizi.com)

    Visit original content creator repository https://github.com/zh-blogs/blog-daohang
  • Draw2Text

    👁 Draw2Text: AI-powered digit recognition app

    Open in Streamlit

    Draw2Text is an innovative web application that recognizes numbers and letters drawn by users in the canvas. It uses advanced machine learning algorithms, including computer vision and deep learning, to segment the drawn image, predict the digit/letter label, and display the result to the user. The app also enables users to provide feedback, which can be used to fine-tune the model for better accuracy in future predictions.

    How it works

    1. The user draws a digit or letter on the provided canvas
    2. The app uses OpenCV, an open-source computer vision library, to segment the canvas in digits images
    3. The segmented image is then passed to a neural network created with Keras, which uses deep learning techniques to predict the digit label.
    4. The predicted label is then displayed to the user.
    5. The user can provide feedback to improve the model’s accuracy in future predictions.
    graph TD
        A["User Drawn Digit"] --> B["OpenCV Segmentation"]
        B --> C["Keras Model"]
        C --> D["Digit Label Prediction"]
        D --> E["Display Predictions"]
        E --> F["User Feedback for Future Tuning"]
        F --> C
    
    Loading

    Getting Started

    To run the app locally, please follow these steps:

    1. Clone the repository
    git clone https://github.com/olucaslopes/Draw2Text.git
    
    1. Install the required packages
    pip install -r requirements.txt
    
    1. Run the app
    streamlit run app.py
    

    Technologies used

    • Cloudinary to Cloud Storage the drawn digits and user true labels feedback for future tuning
    • Streamlit for the front end
    • TensorFlow Keras for model development
    • Image Hashing to avoid duplicated images
    • OpenCV to image segmentation through contours
    • Pandas and Numpy for data manipulation

    Model

    The app uses a TensorFlow Keras Multi Layer Perceptron (MLP) model to predict the digits drawn.

    Contact

    You can find out more about me on my Linkedin

    Visit original content creator repository https://github.com/olucaslopes/Draw2Text