diff --git a/README.md b/README.md new file mode 100644 index 0000000..c18179e --- /dev/null +++ b/README.md @@ -0,0 +1,35 @@ +Compatible with SAMC21, more description will be added soon, check examples to use the code. Its still in alpha. + +This is to make SAMC21 functions faster same way as the SAMD21 speeduino, however it is not yet complete nor tested on a board as i am still waiting for one. Some features are also missing, while you can take advantage of two ADCs. + + +With centered analog read you can have relative ground on A0 which is half of supply voltage to compare against. + +Function descriptions and time they take: +Simplified: + +AnalogBegin(); - starts the ADC0 and attaches it to clock number 3. You can add one number inside to set resolution, deffault is 12 bit, possible are 8 10 and 12, then if you add one it will enable mode that centers values at half of the supply voltage, which now appears at pin A0, so you have negative and positive values, and after if you add 1 ADC will run in a freerun mode - it will keep taking reads again and again. Full form is AnalogBegin(Resolution, Centering, Freerun) ~ 30us + +AnalogBegin0(); - starts ADC0 + +AnalogBegin1(); - starts ADC1 + +FastAnalogRead(pin); - Attaches the Analog pin and reads it, returns an integer. ~ 3us + +AttachADC0(pin, centering) - Attaches to an analog pin and sets gain ~ 20us + +AttachADC1(pin, centering) - Attaches to an analog pin and sets gain ~ 20us + +Analog0Collect() - Reads and collects an analog value from last attached pin to ADC0 ~ 3us, but bit less than FastAnalogRead + +Analog1Collect() - Reads and collects an analog value from last attached pin to ADC1 ~ 3us, but bit less than FastAnalogRead + +PWMBegin(pin, frequency) - begins running a pin at a specified frequency while attaching it to clock 8, minimum is 1 hz - calls PWMSetup. ~ 87us + +PWMDuty(pin, dutycycle) - Sets the duty cycle at a specified number, in fractions. ~ 7us + +PWMFrequency(pin, frequency) - changes the frequency, minimum 1 hz, if the pin previously had lower frequency selected may cause issues. ~40us + +PWMSetup(pin, frequency, clock, Interrupts) - enables PWM, at a specidied pin, frequency which can go down to 0.00281 but it changes clock divisions, use clock 3-8. Enabling interrupts will make it call to Tch(); where you return duty cycle so it changes every cycle. ~ 124us, ~ 80us with frequency above 1hz + + diff --git a/examples/Analog_to_PWM/Analog_to_PWM.ino b/examples/Analog_to_PWM/Analog_to_PWM.ino new file mode 100644 index 0000000..4303805 --- /dev/null +++ b/examples/Analog_to_PWM/Analog_to_PWM.ino @@ -0,0 +1,56 @@ +#include "Snowduino.h" + + +const int ADCpin = 2; //Pin for ADC, 0 cant be used in IDACRed mode as it has the DAC tied to it. AO can be used for ref GND for sound card with sound pin to ADCpin. On zero, 2 stands for A1 +int PWMpin = 13; //PWM pin, 13 is usually connected to LED so you can see it working. + +const float Frequency = 10.0f; //PWM frequency, higher the frequency lower resolution. Wont work below 0.00281 hz wont work +const int ADCDiv = 5; //Set up dividor of time for ADC, with high PWM frequencies high values may let the Duty period only to change every few cycles, while too low values may lead to less stable output. Up to 255. +const int Samples = 1; //Ammount of ADC samples, can be 1, 2, 4, 8, 16, 32, 64, 128, 256, 512 or 1028 +int gain = 1; //1, 2, 4, 8, 16, 32, multiplier of input, only goes up to 16 in ICADRef mode +const int res = 12; //Set up Resolution of the ADC, 8 or 10 or 12 bits + +/* Calibration */ +int16_t minv = -2048; //Minimum meassured value of the input signal, make sure the value doesnt go below +int16_t maxv = 2047; //Maximum meassured value og the input signal + +/* DAC AREF */ +const bool IDACRef = 1; //Use DAC as a reference instead of GND +const int BaseV = 512; //0-1024 base voltage, 512 works the best as VCC/2 + +const bool Interrupt = 1; //Enable PWM Interrupts + +const int ADCClk = 3; //Selects ADC clock generator, both to be between 3-8 +const int PWMClk = 4; //Selects PWM clock generator, they cant be the same. + +//Not to be changed +int16_t Range; //Value dividor here Select between 3-8 +int16_t Analog; //Analog read values go here +int Period; //Time period calculated here + + +void setup() { + + + Range = (maxv - minv); + Period = PWMSetup(PWMpin, Frequency, PWMClk, 1); //Sets up PWM + ADC0Setup(IDACRef, res, Samples, ADCClk, ADCDiv, BaseV, 0, 0); + AttachADC0(ADCpin, IDACRef); + + +} + + +//Shared TCC handler +int Tch() { + ADC0->INTFLAG.reg = ADC_INTFLAG_RESRDY; //Wait for new analog value to be ready + Analog = ADC0->RESULT.reg; //Write it down + ADC0->SWTRIG.bit.START = true; //Start reading again +return (Period * (Analog - minv) / Range); //Value to be set for next Period +} + + +/* Repeating code */ +void loop() { +} + diff --git a/examples/BasicPWM/BasicPWM.ino b/examples/BasicPWM/BasicPWM.ino new file mode 100644 index 0000000..d775613 --- /dev/null +++ b/examples/BasicPWM/BasicPWM.ino @@ -0,0 +1,18 @@ +#include "Snowduino.h" + +int pin = 13; +float frequency = 2.0f; + + +void setup() { +PWMBegin(pin, frequency); +} + +void loop() { +PWMDuty(13, 0.2f); //second number is the duty cycle fraction +delay(10000); +PWMFrequency(13, 20.0f); +PWMDuty(13, 0.8f); +delay(10000); +PWMFrequency(13, 2.0f); +} diff --git a/examples/CenteredAnalogRead/CenteredAnalogRead.ino b/examples/CenteredAnalogRead/CenteredAnalogRead.ino new file mode 100644 index 0000000..22a9b74 --- /dev/null +++ b/examples/CenteredAnalogRead/CenteredAnalogRead.ino @@ -0,0 +1,11 @@ +#include "Snowduino.h" + +void setup() { +Analog0Begin(); +AttachADC0(2, 1); +Serial.begin(9600); +} + +void loop() { +Serial.println(Analog0Collect()); +} \ No newline at end of file diff --git a/examples/FastAnalogRead/FastAnalogRead.ino b/examples/FastAnalogRead/FastAnalogRead.ino new file mode 100644 index 0000000..08f8e48 --- /dev/null +++ b/examples/FastAnalogRead/FastAnalogRead.ino @@ -0,0 +1,18 @@ + +#include "Snowduino.h" + + + +void setup() { + AnalogBegin(); + Serial.begin(115200); +} + + + +/* Repeating code */ +void loop() { + Serial.println(FastAnalogRead(0)); +} + + diff --git a/library.properties b/library.properties new file mode 100644 index 0000000..c425cc1 --- /dev/null +++ b/library.properties @@ -0,0 +1,11 @@ +name=Snowduino +version=0.0.1 +author=Bexin Bexin#1128 +maintainer=Bexin bexinchannel@gmail.com +sentence=A library with faster commands for SAMC21 +paragraph=Faster ADC and PWM +category=Optimalization +url=https://github.com/Bexin3/FastDuino +architectures=samd +includes=Snowduino.h + diff --git a/src/ADCSetup.cpp b/src/ADCSetup.cpp new file mode 100644 index 0000000..03a68d4 --- /dev/null +++ b/src/ADCSetup.cpp @@ -0,0 +1,203 @@ +#include "ADCSetup.h" + +bool mp = 0; +int16_t anv = 0; + + + +void ADC0Setup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv) { + +/* genericClockSetup(ADCClk, ADCDiv); //Sets up ADC clock and divides it + AttachClock(ADCClk, 0x1E); + + if (DacRef) { + DACSetup(BaseV); //Setup DAC if needed + }; +*/ +ADC0->CALIB.reg = ADC_CALIB_BIASCOMP(0x7) | ADC_CALIB_BIASREFBUF(0x7); + + ADC0->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; + + + +if (PreDiv) { +if (Res == 8) { + ADC0->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC0->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_8BIT_Val; +} else if (Res == 10) { + ADC0->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC0->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_10BIT_Val; +} else if (Res == 12) { + ADC0->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC0->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_12BIT_Val; +} else { + Serial.println("Unsupported resolution, change the value res to 8 10 or 12"); +}; +} else { +if (Res == 8) { + ADC0->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC0->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_8BIT_Val; +} else if (Res == 10) { + ADC0->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC0->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_10BIT_Val; +} else if (Res == 12) { + ADC0->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV8_Val; + ADC0->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_12BIT_Val; +} else { + Serial.println("Unsupported resolution, change the value res to 8 10 or 12"); +}; +}; + + if (DacRef) { + ADC0->CTRLC.bit.DIFFMODE = 1; + }; + + + ADC0->AVGCTRL.bit.SAMPLENUM = log2(Samp); + + ADC0->CTRLC.bit.FREERUN = 0; + + ADC0->CTRLA.bit.ENABLE = 1; + + +} + + +void AttachADC0(int ADCpin, bool IDACRefon) { + + if (IDACRefon) { +ADC0->INPUTCTRL.bit.MUXNEG = 0; +ADC0->INPUTCTRL.bit.MUXPOS = ADCpin; + } else { +ADC0->INPUTCTRL.bit.MUXNEG = 0x18; +ADC0->INPUTCTRL.bit.MUXPOS = ADCpin; + }; + +} + +void AnalogBegin(int resolution, bool midphase, bool Freerun) { +Analog0Begin(resolution, midphase, Freerun); +} +void Analog0Begin(int resolution, bool midphase, bool Freerun) { + + ADC0Setup(midphase, resolution, 1, 3, 1, 512, Freerun, 1); + mp = midphase; + +} + + +int Analog0Collect() { +ADC0->SWTRIG.bit.START = true; //Start reading again +while (ADC0->INTFLAG.reg == ADC_INTFLAG_RESRDY) {}; //Wait for new analog value to be ready +anv = ADC0->RESULT.reg; +return(anv); +} + + +int FastAnalogRead(int pin) { + if (mp) { +ADC0->INPUTCTRL.bit.MUXNEG = 0; +ADC0->INPUTCTRL.bit.MUXPOS = pin; + } else { +ADC0->INPUTCTRL.bit.MUXNEG = 0x18; +ADC0->INPUTCTRL.bit.MUXPOS = pin; + }; +//while (ADC->STATUS.bit.SYNCBUSY) {}; +ADC0->SWTRIG.bit.START = true; //Start reading again +while (ADC0->INTFLAG.reg == ADC_INTFLAG_RESRDY) {}; //Wait for new analog value to be ready +anv = ADC0->RESULT.reg; +return(anv); //Write it down +} + + + + + + +void ADC1Setup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv) { + +/* genericClockSetup(ADCClk, ADCDiv); //Sets up ADC clock and divides it + AttachClock(ADCClk, 0x1E); + + if (DacRef) { + DACSetup(BaseV); //Setup DAC if needed + }; +*/ +ADC1->CALIB.reg = ADC_CALIB_BIASCOMP(0x7) | ADC_CALIB_BIASREFBUF(0x7); + + ADC1->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INTVCC1_Val; + + + +if (PreDiv) { +if (Res == 8) { + ADC1->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC1->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_8BIT_Val; +} else if (Res == 10) { + ADC1->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC1->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_10BIT_Val; +} else if (Res == 12) { + ADC1->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC1->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_12BIT_Val; +} else { + Serial.println("Unsupported resolution, change the value res to 8 10 or 12"); +}; +} else { +if (Res == 8) { + ADC1->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC1->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_8BIT_Val; +} else if (Res == 10) { + ADC1->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV2_Val; + ADC1->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_10BIT_Val; +} else if (Res == 12) { + ADC1->CTRLB.bit.PRESCALER = ADC_CTRLB_PRESCALER_DIV8_Val; + ADC1->CTRLC.bit.RESSEL = ADC_CTRLC_RESSEL_12BIT_Val; +} else { + Serial.println("Unsupported resolution, change the value res to 8 10 or 12"); +}; +}; + + if (DacRef) { + ADC1->CTRLC.bit.DIFFMODE = 1; + }; + + + ADC1->AVGCTRL.bit.SAMPLENUM = log2(Samp); + + ADC1->CTRLC.bit.FREERUN = 0; + + ADC1->CTRLA.bit.ENABLE = 1; + + +} + + +void AttachADC1(int ADCpin, bool IDACRefon) { + + if (IDACRefon) { +ADC1->INPUTCTRL.bit.MUXNEG = 0; +ADC1->INPUTCTRL.bit.MUXPOS = ADCpin; + } else { +ADC1->INPUTCTRL.bit.MUXNEG = 0x18; +ADC1->INPUTCTRL.bit.MUXPOS = ADCpin; + }; + +} + + +void Analog1Begin(int resolution, bool midphase, bool Freerun) { + + ADC1Setup(midphase, resolution, 1, 3, 1, 512, Freerun, 1); + mp = midphase; + +} + + +int Analog1Collect() { +ADC1->SWTRIG.bit.START = true; //Start reading again +while (ADC1->INTFLAG.reg == ADC_INTFLAG_RESRDY) {}; //Wait for new analog value to be ready +anv = ADC1->RESULT.reg; +return(anv); +} + + diff --git a/src/ADCSetup.h b/src/ADCSetup.h new file mode 100644 index 0000000..e18a53a --- /dev/null +++ b/src/ADCSetup.h @@ -0,0 +1,20 @@ +#ifndef ADCSetup_h +#define ADCSetup_h + +#include + +void ADC0Setup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv); +void ADC1Setup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv); +void genericClockSetup(int clk, int dFactor); +void AttachClock(int clk, int clkid); +void AttachADC0(int ADCpin = 0, bool IDACRefon = 0); +void AttachADC1(int ADCpin = 0, bool IDACRefon = 0); +void DACSetup(int BaseV); +void AnalogBegin(int resolution = 12, bool midphase = 0, bool Freerun = 0); +void Analog0Begin(int resolution = 12, bool midphase = 0, bool Freerun = 0); +void Analog1Begin(int resolution = 12, bool midphase = 0, bool Freerun = 0); +int FastAnalogRead(int pin); +int Analog0Collect(); +int Analog1Collect(); + +#endif diff --git a/src/ClockSetup.cpp b/src/ClockSetup.cpp new file mode 100644 index 0000000..5ae2969 --- /dev/null +++ b/src/ClockSetup.cpp @@ -0,0 +1,18 @@ +#include "ClockSetup.h" + +void genericClockSetup(int clk, int dFactor) { + + +GCLK->GENCTRL[clk].bit.IDC; +GCLK->GENCTRL[clk].bit.DIV = dFactor; +GCLK->GENCTRL[clk].bit.GENEN; +GCLK->GENCTRL[clk].bit.SRC = GCLK_GENCTRL_SRC_OSC48M_Val; + + +} + + + +void AttachClock(int clk, int clkid) { +GCLK->PCHCTRL[clkid].bit.GEN = clk; +} diff --git a/src/ClockSetup.h b/src/ClockSetup.h new file mode 100644 index 0000000..0d9e46e --- /dev/null +++ b/src/ClockSetup.h @@ -0,0 +1,11 @@ +#ifndef ClockSetup_h +#define ClockSetup_h + +#include + + +void genericClockSetup(int clk, int dFactor); +void AttachClock(int clk, int clkid); + + +#endif \ No newline at end of file diff --git a/src/DACSetup.cpp b/src/DACSetup.cpp new file mode 100644 index 0000000..2469922 --- /dev/null +++ b/src/DACSetup.cpp @@ -0,0 +1,15 @@ +#include "DACSetup.h" + +void DACSetup(int BaseVoltage) { + + AttachClock(1, 36); + + DAC->CTRLA.reg = DAC_CTRLA_SWRST; //Reset + while (DAC->CTRLA.reg & DAC_CTRLA_SWRST) + ; + + DAC->CTRLB.reg = DAC_CTRLB_EOEN | DAC_CTRLB_IOEN | DAC_CTRLB_REFSEL_AVCC; //Enable external and internal refferences + DAC->CTRLA.reg = DAC_CTRLA_ENABLE; //Enable the DAC + + DAC->DATA.reg = BaseVoltage; //Set up the DAC output value +} diff --git a/src/DACSetup.h b/src/DACSetup.h new file mode 100644 index 0000000..06ae67b --- /dev/null +++ b/src/DACSetup.h @@ -0,0 +1,11 @@ +#ifndef DACSetup_h +#define DACSetup_h + +#include + + +void DACSetup(int BaseVoltage); +void AttachClock(int clk, int clkid); + + +#endif \ No newline at end of file diff --git a/src/Interrupts.cpp b/src/Interrupts.cpp new file mode 100644 index 0000000..b4d0ab8 --- /dev/null +++ b/src/Interrupts.cpp @@ -0,0 +1,81 @@ +#include "Interrupts.h" + + + +uint8_t TCChannel; + + +void interset(uint32_t _tcNum, uint8_t _tcChannel) { +TCChannel = _tcChannel; + switch (_tcNum) { + case (0): + { + NVIC_SetPriority(TCC0_IRQn, 3); + NVIC_EnableIRQ(TCC0_IRQn); + } + case (1): + { + NVIC_SetPriority(TCC1_IRQn, 3); + NVIC_EnableIRQ(TCC1_IRQn); + } + case (2): + { + NVIC_SetPriority(TCC2_IRQn, 3); + NVIC_EnableIRQ(TCC2_IRQn); + } + case (3): + { + NVIC_SetPriority(TC3_IRQn, 3); + NVIC_EnableIRQ(TC3_IRQn); + } + case (4): + { + NVIC_SetPriority(TC4_IRQn, 3); + NVIC_EnableIRQ(TC4_IRQn); + } + }; +} + +#pragma weak Tch +int Tch() { + return 0; +} + +void TCC0_Handler() { //gets activated when PWM cycle ends + + TCC0->CC[TCChannel].reg = Tch(); + + TCC0->INTFLAG.bit.OVF = 1; //reset interrupt flag +} + + +void TCC1_Handler() { //gets activated when PWM cycle ends + + TCC1->CC[TCChannel].reg = Tch(); + + TCC1->INTFLAG.bit.OVF = 1; //reset interrupt flag +} + + +void TCC2_Handler() { //gets activated when PWM cycle ends + + TCC2->CC[TCChannel].reg = Tch(); + + TCC2->INTFLAG.bit.OVF = 1; //reset interrupt flag +} + +void TC3_Handler() { //gets activated when PWM cycle ends + + TC3->COUNT8.CC[TCChannel].reg = Tch(); + + TC3->COUNT8.INTFLAG.bit.OVF = 1; //reset interrupt flag +} + +void TC4_Handler() { //gets activated when PWM cycle ends + + TC4->COUNT8.CC[TCChannel].reg = Tch(); + + TC4->COUNT8.INTFLAG.bit.OVF = 1; //reset interrupt flag +} + + diff --git a/src/Interrupts.h b/src/Interrupts.h new file mode 100644 index 0000000..3b0b9b7 --- /dev/null +++ b/src/Interrupts.h @@ -0,0 +1,17 @@ +#ifndef Interrupts_h +#define Interrupts_h + +#include + + +void interset(uint32_t _tcNum, uint8_t _tcChannel); +void TCC0_Handler(); +void TCC1_Handler(); +void TCC2_Handler(); +void TC3_Handler(); +void TC4_Handler(); +int Tch(); + + + +#endif \ No newline at end of file diff --git a/src/PWMSetup.cpp b/src/PWMSetup.cpp new file mode 100644 index 0000000..a9fe948 --- /dev/null +++ b/src/PWMSetup.cpp @@ -0,0 +1,289 @@ +#include "PWMSetup.h" + + +int GCLKDIV; //Dividor of PWM GCLK +int PRESC; //Prescaler of PWM +int PRESVAL; //Value by which this divides +int PRESCALC; //Calculating which PRESC to use + +PinDescription _pinDesc; +uint32_t _pinAttr; +uint32_t _tcNum; +uint8_t _tcChannel; +bool EnablePWMInt; + +void PWMBegin(int pin, float frequency) { +if (frequency < 1) {frequency = 1;}; +PWMSetup(pin, frequency, 8, 0); +} + +void PWMDuty(int pin, float dutycycle) { + +PinDescription _pinDesc = g_APinDescription[pin]; + +_tcNum = GetTCNumber(_pinDesc.ulPWMChannel); +_tcChannel = GetTCChannelNumber(_pinDesc.ulPWMChannel); + + +if (_tcNum >= TCC_INST_NUM) { + // Convert to 8-bit + + // -- Configure TC + Tc *TCx = (Tc *)GetTC(_pinDesc.ulPWMChannel); + TCx->COUNT8.CC[_tcChannel].reg = int(TCx->COUNT8.PER.reg*dutycycle); + + +} else { + + Tcc *TCCx = (Tcc *)GetTC(_pinDesc.ulPWMChannel); + TCCx->CC[_tcChannel].reg = int(TCCx->PER.reg*dutycycle); + + +}; + +} + +void PWMFrequency(int pin, float frequency) { + + +PinDescription _pinDesc = g_APinDescription[pin]; + +_tcNum = GetTCNumber(_pinDesc.ulPWMChannel); +_tcChannel = GetTCChannelNumber(_pinDesc.ulPWMChannel); + + + +if (frequency < 1) {frequency = 1;}; +Prescaler(frequency); + + + + + + +int period = int((48000000 / frequency / PRESVAL) - 1); + + +if (_tcNum >= TCC_INST_NUM) { + // Convert to 8-bit + + // -- Configure TC + +Tc *TCx = (Tc *)GetTC(_pinDesc.ulPWMChannel); +TCx->COUNT8.CTRLA.bit.ENABLE = 0; +TCx->COUNT8.CTRLA.bit.PRESCALER = PRESC; +TCx->COUNT8.PER.reg = (uint8_t)period; +TCx->COUNT8.CTRLA.bit.ENABLE = 1; + + +} else { + + + +Tcc *TCCx = (Tcc *)GetTC(_pinDesc.ulPWMChannel); + TCCx->CTRLA.bit.ENABLE = 0; +TCCx->CTRLA.bit.PRESCALER = PRESC; +TCCx->PER.reg = period; + TCCx->CTRLA.bit.ENABLE = 1; + +}; + + +} + +int PWMSetup(int PMpin, float Frequency, int CLKID, bool EnablePWMInt) { + +PinDescription _pinDesc = g_APinDescription[PMpin]; +_pinAttr = _pinDesc.ulPinAttribute; +_tcNum = GetTCNumber(_pinDesc.ulPWMChannel); +_tcChannel = GetTCChannelNumber(_pinDesc.ulPWMChannel); + + + + + + + GCLKDIVCalc(Frequency); + //genericClockSetup(CLKID, GCLKDIV); //Sets up PWM clock and divides it + //AttachClock(CLKID, int(26 + (_tcNum / 2))); + Prescaler(Frequency); + + + int period = int((48000000 / Frequency / PRESVAL / GCLKDIV) - 1); + + if (EnablePWMInt) { + //interset(_tcNum, _tcChannel); + }; + + + //Which timer to use + if (_pinAttr & PIN_ATTR_TIMER) { + SetupPWMPins(PMpin, PIO_TIMER); + } else { + SetupPWMPins(PMpin, PIO_TIMER_ALT); + } + + + + // Check which timer to use + if (_tcNum >= TCC_INST_NUM) { + // Convert to 8-bit + + // -- Configure TC + Tc *TCx = (Tc *)GetTC(_pinDesc.ulPWMChannel); + + //reset + TCx->COUNT8.CTRLA.bit.SWRST = 1; + + + + // Disable TCx + TCx->COUNT8.CTRLA.bit.ENABLE = 0; + + + + // Set Timer counter Mode to 8 bits, normal PWM, PRESCALER_DIV1 + TCx->COUNT16.CTRLA.reg |= TC_CTRLA_MODE_COUNT8 | TC_CTRLA_PRESCALER_DIV1; + TCx->COUNT16.WAVE.reg |= TC_WAVE_WAVEGEN_NPWM; + + + // Set the Dutycycle + TCx->COUNT8.CC[_tcChannel].reg = (uint8_t)period; + + ; + + // Set PER to _compareValue to match frequency + // convert to 8-bit + TCx->COUNT8.PER.reg = period >> 8; + + + + /* Set up interrupts */ + TCx->COUNT8.EVCTRL.bit.OVFEO = 1; + TCx->COUNT8.INTENSET.bit.OVF = 1; + TCx->COUNT8.INTFLAG.bit.OVF = 1; + + + + TCx->COUNT8.CTRLA.bit.PRESCALER = PRESC; //Set calculated prescaler value + TCx->COUNT8.CTRLA.bit.ENABLE = 1; //Turn timer on + + + } else { + + + // -- Configure TCC + Tcc *TCCx = (Tcc *)GetTC(_pinDesc.ulPWMChannel); + + // Disable TCCx + TCCx->CTRLA.bit.ENABLE = 0; + + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + ; + + // Set prescaler + //TCCx->CTRLA.reg |= _prescalerConfigBits; + + // while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK); + + // Set TCCx as normal PWM + TCCx->WAVE.reg |= TCC_WAVE_WAVEGEN_NPWM; + + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + ; + + // Set the Dutycycle + TCCx->CC[_tcChannel].reg = period; + + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + ; + + // Set PER to _compareValue to match frequency + TCCx->PER.reg = period; + + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + ; + + /* Set up interrupts */ + TCCx->EVCTRL.bit.OVFEO = 1; + TCCx->INTENSET.bit.OVF = 1; + TCCx->INTFLAG.bit.OVF = 1; + + + + // Set prescaler value and enable + TCCx->CTRLA.bit.PRESCALER = PRESC; + TCCx->CTRLA.bit.ENABLE = 1; + + while (TCCx->SYNCBUSY.reg & TCC_SYNCBUSY_MASK) + ; + }; + + return period; +} + + +void SetupPWMPins(uint32_t ulPin, EPioType ulPeripheral) { //Set up PWM pins + + + if (g_APinDescription[ulPin].ulPin & 1) // is pin odd? + { + uint32_t temp; + + // Get whole current setup for both odd and even pins and remove odd one + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXE(0xF); + // Set new muxing + PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp | PORT_PMUX_PMUXO(ulPeripheral); + // Enable port mux + PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR; + } else // even pin + { + uint32_t temp; + + temp = (PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg) & PORT_PMUX_PMUXO(0xF); + + PORT->Group[g_APinDescription[ulPin].ulPort].PMUX[g_APinDescription[ulPin].ulPin >> 1].reg = temp | PORT_PMUX_PMUXE(ulPeripheral); + + PORT->Group[g_APinDescription[ulPin].ulPort].PINCFG[g_APinDescription[ulPin].ulPin].reg |= PORT_PINCFG_PMUXEN | PORT_PINCFG_DRVSTR; // Enable port mux + } +} + + +/* Sets up interrupts based on the timer channel */ + +void GCLKDIVCalc(float Frequency) { + GCLKDIV = int(1.44 / Frequency); + if (GCLKDIV < 1) { GCLKDIV = 1; }; + if (GCLKDIV > 255) { GCLKDIV = 255; }; +} + +void Prescaler(float Frequency) { + PRESCALC = (1500 / Frequency); + + if (PRESCALC > 256) { + PRESC = 7; + PRESVAL = 1024; + } else if (PRESCALC > 64) { + PRESC = 6; + PRESVAL = 256; + } else if (PRESCALC > 16) { + PRESC = 5; + PRESVAL = 64; + } else if (PRESCALC > 8) { + PRESC = 4; + PRESVAL = 16; + } else if (PRESCALC > 4) { + PRESC = 3; + PRESVAL = 8; + } else if (PRESCALC > 2) { + PRESC = 2; + PRESVAL = 4; + } else if (PRESCALC > 1) { + PRESC = 1; + PRESVAL = 2; + } else { + PRESC = 0; + PRESVAL = 1; + }; +} + diff --git a/src/PWMSetup.h b/src/PWMSetup.h new file mode 100644 index 0000000..ac929d7 --- /dev/null +++ b/src/PWMSetup.h @@ -0,0 +1,22 @@ + + +#ifndef PWMSetup_h +#define PWMSetup_h + +#include + +int PWMSetup(int PMpin, float Frequency, int CLKID, bool EnablePWMInt); +void PWMBegin(int pin, float frequency); +void PWMDuty(int pin, float dutycycle); +void SetupPWMPins(uint32_t ulPin, EPioType ulPeripheral); +void GCLKDIVCalc(float Frequency); +void Prescaler(float Frequency); +void interset(uint32_t _tcNum, uint8_t _tcChannel); +void genericClockSetup(int clk, int dFactor); +void AttachClock(int clk, int clkid); +void PWMFrequency(int pin, float frequency); + + + + +#endif diff --git a/src/Snowduino.cpp b/src/Snowduino.cpp new file mode 100644 index 0000000..6eef8b8 --- /dev/null +++ b/src/Snowduino.cpp @@ -0,0 +1,2 @@ +#include "Snowduino.h" + diff --git a/src/Snowduino.h b/src/Snowduino.h new file mode 100644 index 0000000..31f37c0 --- /dev/null +++ b/src/Snowduino.h @@ -0,0 +1,45 @@ +#ifndef Snowduino_h +#define Snowduino_h + +#include + +void ADCSetup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv); +void genericClockSetup(int clk, int dFactor); +void AttachClock(int clk, int clkid); +void AttachADC(int ADCpin = 0, bool IDACRefon = 0, int gain = 1); +void GainINIT(int Gain); +void DACSetup(int BaseV); +int FastAnalogRead(int pin); +void interset(uint32_t _tcNum, uint8_t _tcChannel); +void TCC0_Handler(); +void TCC1_Handler(); +void TCC2_Handler(); +void TC3_Handler(); +void TC4_Handler(); +void TC5_Handler(); +int Tch(); +int PWMSetup(int PMpin, float Frequency, int CLKID, bool EnablePWMInt); +void PWMBegin(int pin, float frequency); +void PWMDuty(int pin, float dutycycle); +void SetupPWMPins(uint32_t ulPin, EPioType ulPeripheral); +void GCLKDIVCalc(float Frequency); +void Prescaler(float Frequency); +void interset(uint32_t _tcNum, uint8_t _tcChannel); +void PWMFrequency(int pin, float frequency); +int AnalogCollect(); +void FastAttachADC(int ADCpin = 0, bool IDACRefon = 0); +void ADC0Setup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv); +void ADC1Setup(bool DacRef, int Res, int Samp, int ADCClk, int ADCDiv, int BaseV, bool Freerun, bool PreDiv); +void genericClockSetup(int clk, int dFactor); +void AttachClock(int clk, int clkid); +void AttachADC0(int ADCpin = 0, bool IDACRefon = 0); +void AttachADC1(int ADCpin = 0, bool IDACRefon = 0); +void DACSetup(int BaseV); +void AnalogBegin(int resolution = 12, bool midphase = 0, bool Freerun = 0); +void Analog0Begin(int resolution = 12, bool midphase = 0, bool Freerun = 0); +void Analog1Begin(int resolution = 12, bool midphase = 0, bool Freerun = 0); +int FastAnalogRead(int pin); +int Analog0Collect(); +int Analog1Collect(); + +#endif