Commit 7fa3c7a4 authored by Jake Read's avatar Jake Read

fw 4 parallelism

parent d7f800da
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE eagle SYSTEM "eagle.dtd">
<eagle version="9.6.2">
<eagle version="9.6.0">
<drawing>
<settings>
<setting alwaysvectorfont="yes"/>
<setting alwaysvectorfont="no"/>
<setting verticaltext="up"/>
</settings>
<grid distance="1" unitdist="mm" unit="mm" style="lines" multiple="1" display="yes" altdistance="5" altunitdist="mil" altunit="mil"/>
......@@ -190,7 +190,7 @@
<wire x1="27.6" y1="49" x2="30" y2="46.6" width="0.1" layer="20" curve="90"/>
<wire x1="30" y1="46.6" x2="32.4" y2="49" width="0.1" layer="20" curve="90"/>
<dimension x1="0" y1="-2" x2="8" y2="-2" x3="4" y3="-7" textsize="1.27" layer="47"/>
<dimension x1="0" y1="-2" x2="44" y2="-2" x3="22" y3="-10" textsize="1.27" layer="47"/>
<dimension x1="0" y1="-2" x2="44" y2="-2" x3="22" y3="-15" textsize="1.27" layer="47"/>
<dimension x1="0" y1="-2" x2="52" y2="-2" x3="26" y3="69" textsize="1.27" layer="47"/>
<dimension x1="-2" y1="0" x2="-2" y2="5" x3="-4" y3="2.5" textsize="1.27" layer="47"/>
<dimension x1="-2" y1="0" x2="-2" y2="49" x3="-7" y3="24.5" textsize="1.27" layer="47"/>
......@@ -200,6 +200,9 @@
<dimension x1="0" y1="55" x2="48" y2="55" x3="24" y3="64" textsize="1.27" layer="47"/>
<dimension x1="54" y1="53" x2="54" y2="49" x3="57" y3="51" textsize="1.27" layer="47"/>
<dimension x1="54" y1="53" x2="54" y2="10" x3="60" y3="31.5" textsize="1.27" layer="47"/>
<dimension x1="0" y1="-2" x2="30" y2="-2" x3="15" y3="-11" textsize="1.27" layer="47"/>
<dimension x1="0" y1="-2" x2="26" y2="-2" x3="13" y3="-5" textsize="1.27" layer="47"/>
<dimension x1="-2" y1="0" x2="-2" y2="24" x3="-4" y3="12" textsize="1.27" layer="47"/>
</plain>
<libraries>
<library name="SparkFun-Connectors">
......
This diff is collapsed.
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE eagle SYSTEM "eagle.dtd">
<eagle version="9.6.2">
<eagle version="9.6.0">
<drawing>
<settings>
<setting alwaysvectorfont="yes"/>
<setting alwaysvectorfont="no"/>
<setting verticaltext="up"/>
</settings>
<grid distance="0.1" unitdist="mm" unit="mm" style="lines" multiple="1" display="yes" altdistance="5" altunitdist="mil" altunit="mil"/>
<grid distance="1" unitdist="mm" unit="mm" style="lines" multiple="1" display="yes" altdistance="5" altunitdist="mil" altunit="mil"/>
<layers>
<layer number="1" name="Top" color="4" fill="1" visible="yes" active="yes"/>
<layer number="2" name="Route2" color="16" fill="1" visible="no" active="no"/>
......@@ -54,7 +54,7 @@
<layer number="44" name="Drills" color="7" fill="1" visible="no" active="yes"/>
<layer number="45" name="Holes" color="7" fill="1" visible="no" active="yes"/>
<layer number="46" name="Milling" color="3" fill="1" visible="no" active="yes"/>
<layer number="47" name="Measures" color="7" fill="1" visible="no" active="yes"/>
<layer number="47" name="Measures" color="7" fill="1" visible="yes" active="yes"/>
<layer number="48" name="Document" color="7" fill="1" visible="yes" active="yes"/>
<layer number="49" name="Reference" color="7" fill="1" visible="yes" active="yes"/>
<layer number="50" name="dxf" color="7" fill="1" visible="no" active="no"/>
......@@ -196,10 +196,8 @@
<wire x1="28" y1="69" x2="30" y2="71" width="0" layer="20"/>
<text x="1" y="15" size="1.778" layer="21">GND</text>
<text x="1" y="8" size="1.778" layer="21">+24v</text>
<dimension x1="0" y1="73" x2="35" y2="73" x3="17.5" y3="76" textsize="1.778" layer="47"/>
<dimension x1="-2" y1="71" x2="-2" y2="67" x3="59.5" y3="69" textsize="1.778" layer="47"/>
<dimension x1="0" y1="73" x2="4" y2="73" x3="2" y3="-5" textsize="1.778" layer="47"/>
<dimension x1="0" y1="73" x2="23" y2="73" x3="11.5" y3="-10" textsize="1.778" layer="47"/>
<dimension x1="-2" y1="71" x2="-2" y2="27" x3="61" y3="49" textsize="1.778" layer="47"/>
<text x="25" y="23" size="1.016" layer="21" rot="R180" align="center">gnd / 24v</text>
<text x="18.5" y="29.6" size="1.016" layer="21" rot="R90" align="center">probes</text>
......@@ -208,6 +206,7 @@
<text x="30.6" y="64" size="0.8128" layer="21" rot="R180" align="center">PA23</text>
<text x="30.6" y="68" size="0.8128" layer="21" rot="R180" align="center">PA21</text>
<text x="47.6" y="30.4" size="0.8128" layer="21" rot="R180" align="center">&gt; bus &gt;</text>
<dimension x1="0" y1="73" x2="52" y2="73" x3="26" y3="80" textsize="0.8128" layer="47"/>
</plain>
<libraries>
<library name="SparkFun-Connectors">
......
This diff is collapsed.
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:adafruit_feather_m4]
platform = atmelsam
board = adafruit_feather_m4
framework = arduino
// DIPs
#include "dip_ucbus_config.h"
void dip_init(void){
// set direction in,
DIP_PORT.DIRCLR.reg = D_BM(D0_PIN) | D_BM(D1_PIN) | D_BM(D2_PIN) | D_BM(D3_PIN) | D_BM(D4_PIN) | D_BM(D5_PIN) | D_BM(D6_PIN) | D_BM(D7_PIN);
// enable in,
DIP_PORT.PINCFG[D0_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D1_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D2_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D3_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D4_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D5_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D6_PIN].bit.INEN = 1;
DIP_PORT.PINCFG[D7_PIN].bit.INEN = 1;
// enable pull,
DIP_PORT.PINCFG[D0_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D1_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D2_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D3_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D4_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D5_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D6_PIN].bit.PULLEN = 1;
DIP_PORT.PINCFG[D7_PIN].bit.PULLEN = 1;
// 'pull' references the value set in the 'out' register, so to pulldown:
DIP_PORT.OUTCLR.reg = D_BM(D0_PIN) | D_BM(D1_PIN) | D_BM(D2_PIN) | D_BM(D3_PIN) | D_BM(D4_PIN) | D_BM(D5_PIN) | D_BM(D6_PIN) | D_BM(D7_PIN);
}
uint8_t dip_read_lower_five(void){
uint32_t bits[5] = {0,0,0,0,0};
if(DIP_PORT.IN.reg & D_BM(D7_PIN)) { bits[0] = 1; }
if(DIP_PORT.IN.reg & D_BM(D6_PIN)) { bits[1] = 1; }
if(DIP_PORT.IN.reg & D_BM(D5_PIN)) { bits[2] = 1; }
if(DIP_PORT.IN.reg & D_BM(D4_PIN)) { bits[3] = 1; }
if(DIP_PORT.IN.reg & D_BM(D3_PIN)) { bits[4] = 1; }
/*
bits[0] = (DIP_PORT.IN.reg & D_BM(D7_PIN)) >> D7_PIN;
bits[1] = (DIP_PORT.IN.reg & D_BM(D6_PIN)) >> D6_PIN;
bits[2] = (DIP_PORT.IN.reg & D_BM(D5_PIN)) >> D5_PIN;
bits[3] = (DIP_PORT.IN.reg & D_BM(D4_PIN)) >> D4_PIN;
bits[4] = (DIP_PORT.IN.reg & D_BM(D3_PIN)) >> D3_PIN;
*/
uint32_t word = 0;
word = word | (bits[4] << 4) | (bits[3] << 3) | (bits[2] << 2) | (bits[1] << 1) | (bits[0] << 0);
return (uint8_t)word;
}
boolean dip_read_pin_0(void){
return DIP_PORT.IN.reg & D_BM(D0_PIN);
}
boolean dip_read_pin_1(void){
return DIP_PORT.IN.reg & D_BM(D1_PIN);
}
\ No newline at end of file
// DIP switch HAL macros
// pardon the mis-labeling: on board, and in the schem, these are 1-8,
// here they will be 0-7
// note: these are 'on' hi by default, from the factory.
// to set low, need to turn the internal pulldown on
#include <Arduino.h>
#define D0_PIN 5
#define D1_PIN 4
#define D2_PIN 3
#define D3_PIN 2
#define D4_PIN 1
#define D5_PIN 0
#define D6_PIN 31
#define D7_PIN 30
#define DIP_PORT PORT->Group[1]
#define D_BM(val) ((uint32_t)(1 << val))
void dip_init(void);
uint8_t dip_read_lower_five(void);
boolean dip_read_pin_0(void); // bus-head (hi) or bus-drop (lo)
boolean dip_read_pin_1(void); // if bus-drop, te-enable (hi) or no (lo)
\ No newline at end of file
// for the new one! with the DIP switch!
#define CLKLIGHT_PIN 30
#define CLKLIGHT_PORT PORT->Group[1]
#define ERRLIGHT_PIN 27
#define ERRLIGHT_PORT PORT->Group[0]
#define DEBUG1PIN_PIN 20
#define DEBUG1PIN_PORT PORT->Group[0]
#define DEBUG2PIN_PIN 6
#define DEBUG2PIN_PORT PORT->Group[1]
#define CLKLIGHT_BM (uint32_t)(1 << CLKLIGHT_PIN)
#define CLKLIGHT_ON
//CLKLIGHT_PORT.OUTCLR.reg = CLKLIGHT_BM
#define CLKLIGHT_OFF
//CLKLIGHT_PORT.OUTSET.reg = CLKLIGHT_BM
#define CLKLIGHT_TOGGLE
//CLKLIGHT_PORT.OUTTGL.reg = CLKLIGHT_BM
#define CLKLIGHT_SETUP
//CLKLIGHT_PORT.DIRSET.reg = CLKLIGHT_BM; CLKLIGHT_OFF
#define ERRLIGHT_BM (uint32_t)(1 << ERRLIGHT_PIN)
#define ERRLIGHT_ON
//ERRLIGHT_PORT.OUTCLR.reg = ERRLIGHT_BM
#define ERRLIGHT_OFF
//ERRLIGHT_PORT.OUTSET.reg = ERRLIGHT_BM
#define ERRLIGHT_TOGGLE
//ERRLIGHT_PORT.OUTTGL.reg = ERRLIGHT_BM
#define ERRLIGHT_SETUP
//ERRLIGHT_PORT.DIRSET.reg = ERRLIGHT_BM; ERRLIGHT_OFF
#define DEBUG1PIN_BM (uint32_t)(1 << DEBUG1PIN_PIN)
#define DEBUG1PIN_ON DEBUG1PIN_PORT.OUTSET.reg = DEBUG1PIN_BM
#define DEBUG1PIN_OFF DEBUG1PIN_PORT.OUTCLR.reg = DEBUG1PIN_BM
#define DEBUG1PIN_TOGGLE DEBUG1PIN_PORT.OUTTGL.reg = DEBUG1PIN_BM
#define DEBUG1PIN_SETUP DEBUG1PIN_PORT.DIRSET.reg = DEBUG1PIN_BM; DEBUG1PIN_OFF
#define DEBUG2PIN_BM (uint32_t)(1 << DEBUG2PIN_PIN)
#define DEBUG2PIN_ON DEBUG2PIN_PORT.OUTSET.reg = DEBUG2PIN_BM
#define DEBUG2PIN_OFF DEBUG2PIN_PORT.OUTCLR.reg = DEBUG2PIN_BM
#define DEBUG2PIN_TOGGLE DEBUG2PIN_PORT.OUTTGL.reg = DEBUG2PIN_BM
#define DEBUG2PIN_SETUP DEBUG2PIN_PORT.DIRSET.reg = DEBUG2PIN_BM; DEBUG2PIN_OFF
\ No newline at end of file
#ifndef PERIPHERAL_NUMS_H_
#define PERIPHERAL_NUMS_H_
#define PERIPHERAL_A 0
#define PERIPHERAL_B 1
#define PERIPHERAL_C 2
#define PERIPHERAL_D 3
#define PERIPHERAL_E 4
#define PERIPHERAL_F 5
#define PERIPHERAL_G 6
#define PERIPHERAL_H 7
#define PERIPHERAL_I 8
#define PERIPHERAL_K 9
#define PERIPHERAL_L 10
#define PERIPHERAL_M 11
#define PERIPHERAL_N 12
#endif
\ No newline at end of file
/*
drivers/pulse_counter.cpp
count input width: developed to measure RPM of rotor bell past hall sensor
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo
projects. Copyright is retained and must be preserved. The work is provided as
is; no warranty is provided, and users accept all liability.
*/
#include "pulse_counter.h"
#include "../utils/clocks_d51_module.h"
#include "indicators.h"
#include "peripheral_nums.h"
Pulse_Counter* Pulse_Counter::instance = 0;
Pulse_Counter* Pulse_Counter::getInstance(void){
if(instance == 0){
instance = new Pulse_Counter();
}
return instance;
}
Pulse_Counter* pulse_counter = Pulse_Counter::getInstance();
Pulse_Counter::Pulse_Counter(){}
// ok, currently setup with push/pull to input on PB14, which has TC4-0 on Peripheral E
#define PULSE_PORT PORT->Group[1]
#define PULSE_PIN 12
#define PULSE_PIN_BM (uint32_t)(1 << PULSE_PIN)
void Pulse_Counter::init(void){
// setup PB14 to this peripheral
PULSE_PORT.DIRCLR.reg = PULSE_PIN_BM; // not-output
PULSE_PORT.PINCFG[PULSE_PIN].bit.PMUXEN = 1; // allow peripheral mux
if(PULSE_PIN % 2){
PULSE_PORT.PMUX[PULSE_PIN >> 1].reg |= PORT_PMUX_PMUXO(PERIPHERAL_E);
} else {
PULSE_PORT.PMUX[PULSE_PIN >> 1].reg |= PORT_PMUX_PMUXE(PERIPHERAL_E);
}
// setup the xtal, will use to send a clock to this timer
d51_clock_boss->setup_16mhz_xtal();
// disable
TC4->COUNT16.CTRLA.bit.ENABLE = 0; // disable
// TC4->COUNT16.CTRLA.bit.SWRST = 1; // reset (would properly do this, but works without, doesn't work with)
// unmask clocks
MCLK->APBCMASK.reg |= MCLK_APBCMASK_TC4;
// send a clock to the ch
GCLK->PCHCTRL[TC4_GCLK_ID].reg = GCLK_PCHCTRL_CHEN
| GCLK_PCHCTRL_GEN(d51_clock_boss->mhz_xtal_gclk_num);
// setup timer
TC4->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16 // 16 bit timer
| TC_CTRLA_PRESCSYNC_PRESC // reload / reset on prescaler
| TC_CTRLA_PRESCALER_DIV4 // div the input clock (CALC TPS WITH THIS)
| TC_CTRLA_CAPTEN0 // enable for capture option on ch0
| TC_CTRLA_COPEN0; // capture on pin
// capture event defaults to the rising edge, that's OK.
// we need to get a capture and overflow interrupt,
TC4->COUNT16.INTENSET.bit.MC0 = 1;
TC4->COUNT16.INTENSET.bit.OVF = 1;
// now enable it,
while(TC4->COUNT16.SYNCBUSY.bit.ENABLE);
TC4->COUNT16.CTRLA.bit.ENABLE = 1;
// enable the IRQ
NVIC_EnableIRQ(TC4_IRQn);
}
void TC4_Handler(void){
DEBUG2PIN_TOGGLE;
if(TC4->COUNT16.INTFLAG.bit.MC0){
uint16_t width;
pulse_counter->_lastWasOVF ? width = 65534 : width = TC4->COUNT16.CC[0].reg;
pulse_counter->_lastWasOVF = false;
// clear, stash, and reset
TC4->COUNT16.INTFLAG.bit.MC0 = 1; // clear
pulse_counter->addPulse(width); // stash
TC4->COUNT16.CTRLBSET.reg = TC_CTRLBSET_CMD_RETRIGGER; // restart (?)
//DEBUG1PIN_TOGGLE;
}
if(TC4->COUNT16.INTFLAG.bit.OVF){
// clear, stash, reset is already happening
pulse_counter->_lastWasOVF = true;
TC4->COUNT16.INTFLAG.bit.OVF = 1;
pulse_counter->addPulse(65534); // the long nap
//DEBUG2PIN_TOGGLE;
}
}
void Pulse_Counter::addPulse(uint16_t width){
_widths[_wh] = width;
_wh ++;
if(_wh >= PULSE_WIDTHS_COUNT){
_wh = 0;
}
}
float Pulse_Counter::getAverageWidth(void){
float sum = 0;
NVIC_DisableIRQ(TC4_IRQn);
for(uint8_t i = 0; i < PULSE_WIDTHS_COUNT; i ++){
sum += _widths[i];
}
NVIC_EnableIRQ(TC4_IRQn);
return sum / (float)PULSE_WIDTHS_COUNT;
}
float Pulse_Counter::getTicksPerSecond(void){
return PULSE_TICKS_PER_SECOND;
}
\ No newline at end of file
/*
drivers/pulse_counter.h
count input width: developed to measure RPM of rotor bell past hall sensor
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo
projects. Copyright is retained and must be preserved. The work is provided as
is; no warranty is provided, and users accept all liability.
*/
#ifndef PULSE_COUNTER_H_
#define PULSE_COUNTER_H_
#include <Arduino.h>
#define PULSE_WIDTHS_COUNT 16
#define PULSE_TICKS_PER_SECOND 4000000 // DIV256: 62500, DIV4: 4000000
class Pulse_Counter {
private:
static Pulse_Counter* instance;
volatile uint16_t _widths[PULSE_WIDTHS_COUNT];
volatile uint8_t _wh = 0; // width head (write to)
public:
Pulse_Counter();
static Pulse_Counter* getInstance(void);
void init(void);
volatile boolean _lastWasOVF = true;
void addPulse(uint16_t width);
float getAverageWidth(void);
float getTicksPerSecond(void);
};
extern Pulse_Counter* pulse_counter;
#endif
\ No newline at end of file
/*
drivers/servo_pwm.cpp
output servo-type (20ms period, 1-2ms duty cycle) with TC on D51
Jake Read at the Center for Bits and Atoms
(c) Massachusetts Institute of Technology 2020
This work may be reproduced, modified, distributed, performed, and
displayed for any purpose, but must acknowledge the squidworks and ponyo
projects. Copyright is retained and must be preserved. The work is provided as
is; no warranty is provided, and users accept all liability.
*/
#include "servo_pwm.h"
#include "../utils/clocks_d51_module.h"
#include "indicators.h"
#include "peripheral_nums.h"
Servo_PWM* Servo_PWM::instance = 0;
Servo_PWM* Servo_PWM::getInstance(void){
if(instance == 0){
instance = new Servo_PWM();
}
return instance;
}
Servo_PWM* servo_pwm = Servo_PWM::getInstance();
Servo_PWM::Servo_PWM(){}
#define PWM_PORT PORT->Group[0]
#define PWM_PIN 22
#define PWM_PIN_BM (uint32_t)(1 << PWM_PIN)
#define PWM_PIN_HI PWM_PORT.OUTSET.reg = PWM_PIN_BM
#define PWM_PIN_LO PWM_PORT.OUTCLR.reg = PWM_PIN_BM
// PWM for servos is 20ms period, 1-2ms duty.
// do 2MHz input clock, wrap at 40000 ticks
// 1ms is 2000 ticks, 2ms is 4000 ticks
void Servo_PWM::init(void){
// set the pin as output: this is toggled on interrupt, not hardware TC
PWM_PORT.DIRSET.reg = PWM_PIN_BM;
// setup xtal for timer clk
d51_clock_boss->setup_16mhz_xtal();
// disable to setup
TC3->COUNT16.CTRLA.bit.ENABLE = 0;
// unmask clock
MCLK->APBBMASK.reg |= MCLK_APBBMASK_TC3;
// send clk to ch
GCLK->PCHCTRL[TC3_GCLK_ID].reg = GCLK_PCHCTRL_CHEN
| GCLK_PCHCTRL_GEN(d51_clock_boss->mhz_xtal_gclk_num);
// setup timer
TC3->COUNT16.CTRLA.reg = TC_CTRLA_MODE_COUNT16
| TC_CTRLA_PRESCSYNC_PRESC
| TC_CTRLA_PRESCALER_DIV8;
// want match pwm (MPWM) mode, should have a TOP register for period, and CC[x] for the swap
TC3->COUNT16.WAVE.reg = TC_WAVE_WAVEGEN_MPWM;
TC3->COUNT16.CC[0].reg = 5000; // CC0 is 'top' in match pwm: 40k here for 20ms period, 5k for 2.5ms / 400hz
TC3->COUNT16.CC[1].reg = 2000; // this should put the first tick at 1ms
// want interrupts
TC3->COUNT16.INTENSET.bit.MC0 = 1;
TC3->COUNT16.INTENSET.bit.MC1 = 1;
// the rest
// ...
// now enable
while(TC3->COUNT16.SYNCBUSY.bit.ENABLE);
TC3->COUNT16.CTRLA.bit.ENABLE = 1;
// enable the IRQ
NVIC_EnableIRQ(TC3_IRQn);
}
// need to finish setup above, to do... something, I think compare at duty cycle and wrap at 20ms
// then try write(0) and write(1) at some intervals in loop,
// configure your debugs (currently triggered on pulse_counter events) and watch scope
// then roll PID... tune... and do bus action
// maybe tune after bus action, have pid-config there, not too hard
void TC3_Handler(void){
if(TC3->COUNT16.INTFLAG.bit.MC0){
TC3->COUNT16.INTFLAG.bit.MC0 = 1;
PWM_PIN_HI;
DEBUG1PIN_ON;
// now, running a control loop any faster than on-this-interrupt is silly,
// so it's a handy place to also trigger some code (and is... only 50hz, wowow)
servo_pwm->onPwmTick();
}
if(TC3->COUNT16.INTFLAG.bit.MC1){
TC3->COUNT16.INTFLAG.bit.MC1 = 1;
PWM_PIN_LO;
DEBUG1PIN_OFF;
}
}
void Servo_PWM::setDuty(float duty){
// 0-1 -> 2000-4000
if(duty > 1.0F){
duty = 1.0F;
} else if (duty < 0.0F){
duty = 0.0F;
}
uint16_t ticks = duty * 2000;
TC3->COUNT16.CCBUF[1].reg = 2000 + ticks;
}
\ No newline at end of file