From f5441b625738968f068d1333509e824a33fa2314 Mon Sep 17 00:00:00 2001 From: AlexeiBazlaev Date: Tue, 5 Jan 2021 00:30:37 +0700 Subject: [PATCH] 1.USB debugged 2.Added modules --- .vs/TE_Controller/v14/.atsuo | Bin 47104 -> 47104 bytes TE_Controller/TE_Controller.cproj | 747 ++--- TE_Controller/src/ASF/sam0/drivers/tc/tc.h | 1788 ++++++++++++ .../src/ASF/sam0/drivers/tc/tc_interrupt.c | 189 ++ .../src/ASF/sam0/drivers/tc/tc_interrupt.h | 169 ++ .../src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c | 675 +++++ .../drivers/tcc/quick_start/qs_tcc_basic.h | 139 + .../quick_start_buffering/qs_tcc_buffering.h | 145 + .../drivers/tcc/quick_start_dma/qs_tcc_dma.h | 275 ++ TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c | 1598 +++++++++++ TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h | 2487 +++++++++++++++++ TE_Controller/src/asf.h | 9 +- TE_Controller/src/include/adn8831.h | 16 + TE_Controller/src/include/backlight.h | 27 + TE_Controller/src/include/dht.h | 36 + .../src/include/light_ws2812_cortex.c | 128 + .../src/include/light_ws2812_cortex.h | 110 + TE_Controller/src/include/ntc.h | 27 + TE_Controller/src/include/realsence.h | 4 +- TE_Controller/src/include/tec.h | 19 + TE_Controller/src/include/tm_ds18b20.h | 273 ++ TE_Controller/src/include/tm_onewire.h | 293 ++ TE_Controller/src/include/tmpgood.h | 4 +- TE_Controller/src/main.c | 10 +- TE_Controller/src/main.h | 19 + TE_Controller/src/source/adc_user.c | 2 +- TE_Controller/src/source/adc_user.h | 2 +- TE_Controller/src/source/adn8831.c | 60 + TE_Controller/src/source/backlight.c | 127 + TE_Controller/src/source/dac_user.c | 4 +- TE_Controller/src/source/dht.c | 128 + .../src/source/light_ws2812_cortex.c | 128 + TE_Controller/src/source/ntc.c | 77 + TE_Controller/src/source/realsence.c | 4 +- TE_Controller/src/source/tec.c | 124 + TE_Controller/src/source/tm_ds18b20.c | 420 +++ TE_Controller/src/source/tm_onewire.c | 389 +++ TE_Controller/src/source/tmpgood.c | 5 +- TE_Controller/src/source/ws2812.c | 2 +- 39 files changed, 10320 insertions(+), 339 deletions(-) create mode 100644 TE_Controller/src/ASF/sam0/drivers/tc/tc.h create mode 100644 TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c create mode 100644 TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h create mode 100644 TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c create mode 100644 TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h create mode 100644 TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h create mode 100644 TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h create mode 100644 TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c create mode 100644 TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h create mode 100644 TE_Controller/src/include/adn8831.h create mode 100644 TE_Controller/src/include/backlight.h create mode 100644 TE_Controller/src/include/dht.h create mode 100644 TE_Controller/src/include/light_ws2812_cortex.c create mode 100644 TE_Controller/src/include/light_ws2812_cortex.h create mode 100644 TE_Controller/src/include/ntc.h create mode 100644 TE_Controller/src/include/tec.h create mode 100644 TE_Controller/src/include/tm_ds18b20.h create mode 100644 TE_Controller/src/include/tm_onewire.h create mode 100644 TE_Controller/src/source/adn8831.c create mode 100644 TE_Controller/src/source/backlight.c create mode 100644 TE_Controller/src/source/dht.c create mode 100644 TE_Controller/src/source/light_ws2812_cortex.c create mode 100644 TE_Controller/src/source/ntc.c create mode 100644 TE_Controller/src/source/tec.c create mode 100644 TE_Controller/src/source/tm_ds18b20.c create mode 100644 TE_Controller/src/source/tm_onewire.c diff --git a/.vs/TE_Controller/v14/.atsuo b/.vs/TE_Controller/v14/.atsuo index 6513e8ecda1f4af1d2a74c079d3ccf726f84cee4..1b9756a88014c856570250acae38e1688a4fcbee 100644 GIT binary patch delta 5561 zcmdT|3s}@u7XRO228X93A`p^{K!k)eAQ&nlqxb?55+BsEpn?V^Fu;&PZ8HD$kLAjV0Ov~L7e%c{jg^rI|8t_FjG zvcgCsQ@RcY@qRC=c9|!-k&ySSn<_U1faeQXQSL>3iyJ6C>^yhWJ%Lcb4TuE%fV%)S zFcG*1=m*>lJOK0oc#Rm;-u8BX)FHqCzy}xu^p+%p6o-aC5C!nd$D@t~1_IGQAP^34 zUoX@uARf367!8C0p1=^GFOUe_4-5s8fMGx~paq5lBY+fOByh_b%KNlhBS0hogMfC9 z)tZiWcOaX-m;0;6I`!}fnyR>D7ryF3)94Ldg+KXD!Z$0G1_hS;8))mZSV31k z@Dg3sz`AALKUKq8b4WoPTL;X^CM$09+4+dvW~*S+V-seY&Giw0R)pk?V}`>-xa}|z zZnKGuvQJ`rWgB3A8fw02+-7slu(v5WG=L7c`_imXjVE^&p`!+%hR|%YcPpj1Xe@2s zp5lLL$7*VI527bS)pyu&l(48%BZQolP3kN)dlS+ZXHu(7qhQTHM^zF1D5UoUaW_>) zWGLB;+1qpsZi_gkX^euyn(7zX-de~$`;wt#g?*-Zm3eJMHZvT1htiJ+|`fjdra`i0<{xBu~;h)3OT!w zj+sUf&(Mwg)0BKK*%>&xNUu2|XV=uph*@M_VKfg>i+JiA97?U;8ig7IPS_4o9~`25 z5EQ@9F~#*$5J7@|3W}im)NnbwOh=!`1rX-|6pM9rvk+#|s)tc>X)$d~cTdfiJ~_F& ztm5SbV_&YCzwShewt`3U(YeIH@%5K=(o%&~F6B!(aCTX++#Jx;q+&^f)*8~5*F;U1 zO2H|Y3eb}ybyCq%p%gK4%>37erW+T(e)jvuakE#DN#{$(hD5Q1n#bmmdUz( z$G0nXWgl-$h9%yjAPVXeZ)5!-I{OnRF8Z!KmFwsneQ!KxZ`V{ z=TRz^NP3*FRJsZ=7E^Rws#2OI%>XNh_UUR>4^7LGHe77nbae0710-%<$E;qS_5mzC zNI&5Zlr-5-b=m!?=TzbScdu&-I~TsF?qeR=tr*h8JIu+gO13Zd(2j#z+LAp*eUwZz zk!h$Y$yv^oSedtw=OpnQsR(;5!fyF6#kq;uU-c=gi}O4A^SiPQ=lC!*RUM(=&c{hx zI*a<3xVt5c+Mhi3n<0y>`O3U94fNd9hRA ze+YbJ@8`a=XnzcRV&|Ph{TXl`_#EJQU!eXH_{vUyjrtqluXdW(xs3J|iFSI7GDo&5 z<)GXEhkPw{3^}_r$FhpUAX=%a zw%v)n3kohRHbc%ar(@7u5P07J+aM3VU91%pi#1-z%$gLNAL|E(W6JIPSQFLzg(x|& zvFCJ*RMdjlMpfnvImfjQb|DBjYcuRgrg1$3>Z(N5l&a(iIKgS8*9Rbe0=O(9(-cFW z61ao}q<%3rW1q8f)bbv)-?5y3BYfb9gfCm!*t_Q;A?Uol%cxmr3d^%`W=OMfPs(wF z*j=dCpYMM0NbhOGgF;<2=l5LW$$t5`B{|ZokKMIQJH#?+ZNHD)5@*J&rcAZYJa~*8 z4zlAIq#yjQn{WXq*omv)c=Zld4auMb-chj}x!A0^6yw&iw~WC7rXw-c*mkis+;>gs zwdnN;Io>5Li(=RCF1oRs&5~+K40z&8hRHZ|huA6+ip@Dc%2zp01@I58;V!j%oAQX9X76-%=vwheSzV=W6<6p*3JWbQMYnjWhSFWj1+7CO7OMH(w+!*!T1oyLzye(QaF-+_v z(@29^9}&hG2HRIL=ISwnXZ?Q9rlhiqzSj9qQqZBjJHFsq>RA|2fjxg}?{ykrX7Cz^gXx{9;Z2h;}Wv>nh(S^a`84ULAU7 z(<0Xs%Rc3p_dvol}F{vptRTu^8i$1=8Z=fARVT7D@+A z=dNgP=KB9SF63&=h9t|L+~HztxLQW)z%Zo>;^&_b95zJy!1koJEigkN`g4!{XB5)+ z&QwN&!M{>ChI{EjyZ~@n!hY4IK$=E|$)uVf9;l|KWtaADzLopb>hcRVNe-NHh=w;r zQ&WO!L}!f1L#V63x(Nt3vA6~KxC7<5LNlZ}P)feE^U;Fb`+l6YbFtgo8@K14vVG97 zGeY1<*+`emd=NZ-8LSY6YGx$etLmk%xmlxKxOBr@-hdm&8@^~9X${_Q`%01rb}slo zkW6a>T|(Mxi(>6AQ9nmUB4q@*G!zTHEgNl8E5+0NNg?1I%WJxKeoF9d#-i2Fh*fy5 z77chdip_X#5qt35E1t5i;A7M7Qt@Xpg)bLd@wA}bJdxYY6D^pp&F1;q>_)KwmwzF8 zwOPx>i+H{yw&D4jKobA(LG;2Icq^CCaCPZl0n`UU4xgP6CP3F{|C9jAxQj)Wl43c=+-D=bq97GwV7XJ zk{@L@bnl}>a#D)F0-Jg1uUAw)+K()ukz?x%Z@K7gLt_(GsiLl`S}tCHQ7g*`eeY!U z^KRTxH`UubXpw5*^!vuiw`!I8^(Q!X%-;`u^*M)v-zA$saznLr4uat}ZWQtoz=i*$+ wTooDM2xe<0`gWUi-hIsbb2S5uFD~iHhn8J~h3R~KBCq_)->9~HSHCvk?{;Xt&j0`b delta 6377 zcmcgx3s_Xu7CvWSaDao32nePy0wN&FL-P7UhL`b5Fi6vn91!24pn?KkV^DjkCCoB2 z%>uNy0y1T0K0wiYg_@>4Ew!iCy>=rDZ_54GnKLqC-P`wh>&*AF_F8A}b@pC+?X~va z7_X>|S5y@vMeVkzZYnXB`l@`o>gp=eCto-trV4^!98IOFQt?gtNtH&;QkX+e2zS|0 zsof)@BZ>AsOiuP??RfklR|7r(^IbuGfi8e25CCWZe)l&}4}f*`2AqLjKq3$bxC6m} z3or=i2e<(}fT4g6=nF`|ctMybM4-TmyD4;pLR~@o03(5LU@+hXcmu-#Zo^Lq%69<+ zfg2W4dnn37Xr5n>%Ix0y6flasoh#f6ehiQXWZ1mpI+@`8Y-A6hOxf!1#2DGSRk_bb zb+T^5Z&=r)(Udu$<#lLeyYg4rwrpqq3P0VIvenKkV>{aeY;(4Af52*Ies8rim;Z;I zXLUBTY-cAZ{3CXbL_MpWc~bdr3x^WRzYG!p}HQ- zHX7@ES7o-QY$uqvfn7?CJ)nDmMup!8x*up(_=BMD0EZO*2@4ts<=xo!k5Kp+_{1V;KL`35@VUZY0KEu&q3~aUeyxyqMoMc7te=nkn8r%-pIC5lQFiPtB?@H7|j4RN|Q; zv2(MVu?{-v;jiXZaEaPHlPS(UT+Qp@Wh(Jn>^}}A9tc0>z#pCzFL_eXg1cu1eI0lM z*lw99`?9}yVmi-D%>QR%Zn1NiAMIC#i*-~KHpWHdH5?CEjqLCim~#SM3rps?QSS!( z3zdYYNE{uw7C$^4&JyO4U*n~smajCPy|Dr*%(IA)#;`xJASdiu-@&e|FZ2cCs z7Nl{nsc>Gp#L?3liMbKHI^BfMe}2mPC` z*bntWxKISc}3AW zr>xXdV4?v%FcF9a;(%_VAh3Z(16q{XoJl}3z>QNut?7^Xbnv9_rgNO2RJcJiod-)Z zz|B-7^s@5 zsZa{Ec}0c2PiqF;B8aM`8dqP54a`Qhs#d=b22MWI5=K7+cZ1r7rfD2)D}4&)3Y83# zD>lyLBf7(m8yC3a+*rw z(lk07u`|!?uK*s3E-CTu7!%eeERRtieF^5i4N^)uRi1xwU^s?v1Ke(BCvDJf6Ycbpo)Y9n)Nuq2YvTSq#7 z%L-UVMgAF@AvSfW)jy3F2Nm{9m+r=k5jHO!SAnSqEdEnfuA$Wr1^N}iGCWud<-z{& z#x$*C+~py!9xQpI?(*I~XQ;ezD^->IQu>@Q@dFaamo@Y{Bx-olti5wKf_VzSV{WG= zQLLpVKZ9B48Yohtdk7WwKt|Ex?O?##DsVcO4FEq=(1jdWjO{a`a#(?R-QJjjs{!vh zeXswL?cF^CURngh<|0aG!LYS3R}qiF*LDo-$1{Ze%R~3i+tu=JNYdsNJYJ*nzrWAzz4#~H>d|)&h6&Nosl0pAMZ|yIo?!IYA;q%Q{L0PI?_O9?FpBkuZJ9V zzi?ynERRijtPuWB)r&$%zaXNU0r50n&H(d4kHG!Pej}VH`EzW#)H$m7%2CB)2_^F+ zltsRF;O&)9{~UbJ*ja~O=q`^Tf1!uCgZma?>6_KP4X~d9#_331xxzKi<#lyi5)PzQ z8&-UJa!9GA&kl4c*Mq`T4yK8X4PzQb?UvbIYhp&2@2?8_&~fCn@QtLM5JugX45Heg z0PUA6PZ{j`-}~0IcMrs$n()eFtfR|xd?r`Or?UB^y)xra+v2TuR}UpR#JNUCt(1E? zWWf{$7?g)vy`HkrA7f~dk6u$!sN>&|->-pGUkVZfc(uWMTVu&sUe%qluM z@x_%@l{{LpnPRe|sbQHnd9R(UwRKXC1m=po0s_g$}}UcJ=5y@f~3_AS2cgpD->dF2N8NAD5L0 zl0Ua_zGa>8U&T|N%k`yTRaY`j3>dxOmgQ-Up*(SxXlUItbwpYYHqVR2PZgip+vRgF z!y`>g)}N9Mx=XggKUO%=($Ybk={)63hYxh_GWA^&Kt^LP(ymSYGu^3sk~NH_OPuj- zqnKnH#YprUNCRs_{byp}Q{|kx`$5;B<&inRtlQOZ+qhoWoY7p4fH>_K?=y;~>8~?;u;&u4eWG5LhgG#a!YKl3~ zOfpZZm@JA5N%W02W$Vj2`)Nnd4LB?mAkF1qRD9mxuw8(_-Fbw+UysMUqx5Y348zXi z*%z*R1Z^JS)!|dJS*apf?LP$vv~YYO9Ct&UT)Ex8q{nB+_-q)JGk*5<>UGq@vtoyX z4(-kR5qBc$62#JJ6kRv(cOsOYjCrH%rU`#?oN^=1bI&0RJV9M243SQ5jymUO2-*_4 z$~6UDwuCXHFr-3d4?qzCo=!Z%AH#jl234EF;w9@=o-HC@UAzS=HB(7gvWv*+*LFYd zz-MTi6L%BX59AX!?^P|Xs+_o8aZbvI5RbXNE=HulhEX)QW(;j;2$bxE*nt_D!^7}f z{9C&?Y7IWEv8t3i#m6cEr-@`2`9$Upwbl;H#|b{;bqM;bY6!t@pHJaNojnx~e5|Y- z6_x_a09N)e=p(?R3ja9h3SgzeKLPqAuv+2yg3JUEutt%s1$|m6^WkYd!22}TzY+8~ z;CTyQ)?ST54Y0`~Xnz6pMc^fce+BeafOj}s6j?239l-lhR@wk+2KerWc|NVZ3G7h# zouF?6yA*y8=w6^vD6=%!2WCIe46uTOpzi>O6#fY4QQ(-uw}2i8PAL3)pr-&nU~&61 zpl1Q)vaa);P{)-J?}E9(1<;GY7YhFs=+{d5ThL3uWre?aSvNe+a-lN(IK@rfZ5o=W zNkSE9vpDSg-0rqRB0Oa@UO3v;yyc{*K95(YsVyo+N0ozITc1biLyvfK mv&TrWX1#rbu2Jk-ud@6f0eupMUevU(mz~-|&FZRu_xukDz>A{* diff --git a/TE_Controller/TE_Controller.cproj b/TE_Controller/TE_Controller.cproj index e58519a..209b33d 100644 --- a/TE_Controller/TE_Controller.cproj +++ b/TE_Controller/TE_Controller.cproj @@ -30,319 +30,330 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + com.atmel.avrdbg.tool.atmelice J41800067100 @@ -383,6 +394,8 @@ SYSTICK_MODE ADC_CALLBACK_MODE=true DAC_CALLBACK_MODE=true + TCC_ASYNC=false + TC_ASYNC=true @@ -431,6 +444,9 @@ ../src/ASF/sam0/drivers/adc/adc_sam_d_r_h ../src/ASF/sam0/drivers/dac ../src/ASF/sam0/drivers/dac/dac_sam_d_c_h + ../src/ASF/sam0/drivers/tcc + ../src/ASF/sam0/drivers/tc + ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h Optimize for size (-Os) @@ -498,9 +514,12 @@ ../src/ASF/sam0/drivers/adc/adc_sam_d_r_h ../src/ASF/sam0/drivers/dac ../src/ASF/sam0/drivers/dac/dac_sam_d_c_h + ../src/ASF/sam0/drivers/tcc + ../src/ASF/sam0/drivers/tc + ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h - -DARM_MATH_CM0PLUS=true -DBOARD=SAMD21_XPLAINED_PRO -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21J18A__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true + -DARM_MATH_CM0PLUS=true -DBOARD=SAMD21_XPLAINED_PRO -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21J18A__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true -DTCC_ASYNC=false -DTC_ASYNC=true ../src @@ -547,6 +566,9 @@ ../src/ASF/sam0/drivers/adc/adc_sam_d_r_h ../src/ASF/sam0/drivers/dac ../src/ASF/sam0/drivers/dac/dac_sam_d_c_h + ../src/ASF/sam0/drivers/tcc + ../src/ASF/sam0/drivers/tc + ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h @@ -574,6 +596,8 @@ SYSTICK_MODE ADC_CALLBACK_MODE=true DAC_CALLBACK_MODE=true + TCC_ASYNC=false + TC_ASYNC=true @@ -623,6 +647,9 @@ ../src/ASF/sam0/drivers/adc/adc_sam_d_r_h ../src/ASF/sam0/drivers/dac ../src/ASF/sam0/drivers/dac/dac_sam_d_c_h + ../src/ASF/sam0/drivers/tcc + ../src/ASF/sam0/drivers/tc + ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h -fdata-sections @@ -691,10 +718,13 @@ ../src/ASF/sam0/drivers/adc/adc_sam_d_r_h ../src/ASF/sam0/drivers/dac ../src/ASF/sam0/drivers/dac/dac_sam_d_c_h + ../src/ASF/sam0/drivers/tcc + ../src/ASF/sam0/drivers/tc + ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h Default (-g) - -DARM_MATH_CM0PLUS=true -DBOARD=USER_BOARD -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21E16B__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true + -DARM_MATH_CM0PLUS=true -DBOARD=USER_BOARD -DEXTINT_CALLBACK_MODE=true -DUDD_ENABLE -DUSART_CALLBACK_MODE=true -DUSB_DEVICE_LPM_SUPPORT -D__SAMD21E16B__ -D__FREERTOS__ -DSYSTICK_MODE -DADC_CALLBACK_MODE=true -DDAC_CALLBACK_MODE=true -DTCC_ASYNC=false -DTC_ASYNC=true ../src @@ -741,6 +771,9 @@ ../src/ASF/sam0/drivers/adc/adc_sam_d_r_h ../src/ASF/sam0/drivers/dac ../src/ASF/sam0/drivers/dac/dac_sam_d_c_h + ../src/ASF/sam0/drivers/tcc + ../src/ASF/sam0/drivers/tc + ../src/ASF/sam0/drivers/tc/tc_sam_d_r_h Default (-Wa,-g) @@ -799,6 +832,12 @@ + + + + + + @@ -886,6 +925,33 @@ compile + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + + + compile + compile @@ -949,9 +1015,6 @@ compile - - compile - compile @@ -1681,15 +1744,39 @@ compile + + compile + + + compile + compile + + compile + + + compile + + + compile + compile + + compile + compile + + compile + + + compile + compile @@ -1699,15 +1786,39 @@ compile + + compile + + + compile + compile + + compile + + + compile + + + compile + compile + + compile + compile + + compile + + + compile + compile diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc.h b/TE_Controller/src/ASF/sam0/drivers/tc/tc.h new file mode 100644 index 0000000..2ed1f48 --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc.h @@ -0,0 +1,1788 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Driver + * + * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef TC_H_INCLUDED +#define TC_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_tc_group SAM Timer/Counter (TC) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the timer modules within the device, for waveform + * generation and timing operations. The following driver API modes are covered + * by this manual: + * + * - Polled APIs + * \if TC_CALLBACK_MODE + * - Callback APIs + * \endif + * + * + * The following peripheral is used by this module: + * - TC (Timer/Counter) + * + * The following devices can use this module: + * - Atmel | SMART SAM D20/D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D09/D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_tc_prerequisites + * - \ref asfdoc_sam0_tc_module_overview + * - \ref asfdoc_sam0_tc_special_considerations + * - \ref asfdoc_sam0_tc_extra_info + * - \ref asfdoc_sam0_tc_examples + * - \ref asfdoc_sam0_tc_api_overview + * + * + * \section asfdoc_sam0_tc_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * + * \section asfdoc_sam0_tc_module_overview Module Overview + * + * The Timer/Counter (TC) module provides a set of timing and counting related + * functionality, such as the generation of periodic waveforms, the capturing + * of a periodic waveform's frequency/duty cycle, and software timekeeping for + * periodic operations. TC modules can be configured to use an 8-, 16-, or + * 32-bit counter size. + * + * This TC module for the SAM is capable of the following functions: + * + * - Generation of PWM signals + * - Generation of timestamps for events + * - General time counting + * - Waveform period capture + * - Waveform frequency capture + * + * \ref asfdoc_sam0_tc_block_diagram "The diagram below" shows the overview + * of the TC module design. + * + * \anchor asfdoc_sam0_tc_block_diagram + * \image html overview.svg "Basic Overview of the TC Module" + * + * + * \subsection asfdoc_sam0_tc_features Driver Feature Macro Definition + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Driver Feature MacroSupported devices
FEATURE_TC_DOUBLE_BUFFEREDSAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2SAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_STAMP_PW_CAPTURESAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_READ_SYNCSAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_IO_CAPTURESAM L21/L22/C20/C21/R30/R34/R35
FEATURE_TC_GENERATE_DMA_TRIGGERSAM L21/L22/R30/R34/R35
+ * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_tc_module_overview_func_desc Functional Description + * Independent of the configured counter size, each TC module can be set up + * in one of two different modes; capture and compare. + * + * In capture mode, the counter value is stored when a configurable event + * occurs. This mode can be used to generate timestamps used in event capture, + * or it can be used for the measurement of a periodic input signal's + * frequency/duty cycle. + * + * In compare mode, the counter value is compared against one or more of the + * configured channel compare values. When the counter value coincides with a + * compare value an action can be taken automatically by the module, such as + * generating an output event or toggling a pin when used for frequency or + * Pulse Width Modulation (PWM) signal generation. + * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)" + * to route output event of one module to the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * \subsection asfdoc_sam0_tc_module_overview_tc_size Timer/Counter Size + * Each timer module can be configured in one of three different counter + * sizes; 8-, 16-, and 32-bit. The size of the counter determines the maximum + * value it can count to before an overflow occurs and the count is reset back + * to zero. \ref asfdoc_sam0_tc_count_size_vs_top "The table below" shows the + * maximum values for each of the possible counter sizes. + * + * \anchor asfdoc_sam0_tc_count_size_vs_top + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Timer Counter Sizes and Their Maximum Count Values
Counter sizeMax. (hexadecimal)Max. (decimal)
8-bit0xFF255
16-bit0xFFFF65,535
32-bit0xFFFFFFFF4,294,967,295
+ * + * When using the counter in 16- or 32-bit count mode, Compare Capture + * register 0 (CC0) is used to store the period value when running in PWM + * generation match mode. + * + * When using 32-bit counter size, two 16-bit counters are chained together + * in a cascade formation. Except in SAM D09/D10/D11. Even numbered TC modules + * (e.g. TC0, TC2) can be configured as 32-bit counters. The odd numbered + * counters will act as slaves to the even numbered masters, and will not + * be reconfigurable until the master timer is disabled. The pairing of timer + * modules for 32-bit mode is shown in \ref asfdoc_sam0_tc_module_ms_pairs + * "the table below". + * + * \anchor asfdoc_sam0_tc_module_ms_pairs + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TC Master and Slave Module Pairings
Master TC moduleSlave TC module
TC0TC1
TC2TC3
......
TCn-1TCn
+ * + * In SAM D09/D10/D11, odd numbered TC modules (e.g. TC1) can be configured as 32-bit + * counters. The even numbered (e.g. TC2) counters will act as slaves to the odd + * numbered masters. + * + * \subsection asfdoc_sam0_tc_module_overview_clock Clock Settings + * + * \subsubsection asfdoc_sam0_tc_module_overview_clock_selection Clock Selection + * Each TC peripheral is clocked asynchronously to the system clock by a GCLK + * (Generic Clock) channel. The GCLK channel connects to any of the GCLK + * generators. The GCLK generators are configured to use one of the available + * clock sources on the system such as internal oscillator, external crystals, + * etc. See the \ref asfdoc_sam0_system_clock_group "Generic Clock driver" + *for + * more information. + * + * \subsubsection asfdoc_sam0_tc_module_overview_clock_prescaler Prescaler + * Each TC module in the SAM has its own individual clock prescaler, which + * can be used to divide the input clock frequency used in the counter. This + * prescaler only scales the clock used to provide clock pulses for the counter + * to count, and does not affect the digital register interface portion of + * the module, thus the timer registers will synchronize to the raw GCLK + * frequency input to the module. + * + * As a result of this, when selecting a GCLK frequency and timer prescaler + * value the user application should consider both the timer resolution + * required and the synchronization frequency, to avoid lengthy + * synchronization times of the module if a very slow GCLK frequency is fed + * into the TC module. It is preferable to use a higher module GCLK frequency + * as the input to the timer, and prescale this down as much as possible to + * obtain a suitable counter frequency in latency-sensitive applications. + * + * \subsubsection asfdoc_sam0_tc_module_overview_clock_reloading Reloading + * Timer modules also contain a configurable reload action, used when a + * re-trigger event occurs. Examples of a re-trigger event are the counter + * reaching the maximum value when counting up, or when an event from the event + * system tells the counter to re-trigger. The reload action determines if the + * prescaler should be reset, and when this should happen. The counter will + * always be reloaded with the value it is set to start counting from. The user + * can choose between three different reload actions, described in + * \ref asfdoc_sam0_tc_module_reload_act "the table below". + * + * \anchor asfdoc_sam0_tc_module_reload_act + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TC Module Reload Actions
Reload actionDescription
\ref TC_RELOAD_ACTION_GCLK Reload TC counter value on next GCLK cycle. Leave prescaler + * as-is.
\ref TC_RELOAD_ACTION_PRESC Reloads TC counter value on next prescaler clock. Leave prescaler + * as-is.
\ref TC_RELOAD_ACTION_RESYNC Reload TC counter value on next GCLK cycle. Clear prescaler to + * zero.
+ * + * The reload action to use will depend on the specific application being + * implemented. One example is when an external trigger for a reload occurs; if + * the TC uses the prescaler, the counter in the prescaler should not have a + * value between zero and the division factor. The TC counter and the counter + * in the prescaler should both start at zero. When the counter is set to + * re-trigger when it reaches the maximum value on the other hand, this is not the + * right option to use. In such a case it would be better if the prescaler is + * left unaltered when the re-trigger happens, letting the counter reset on the + * next GCLK cycle. + * + * \subsection asfdoc_sam0_tc_module_overview_compare_match Compare Match Operations + * In compare match operation, Compare/Capture registers are used in comparison + * with the counter value. When the timer's count value matches the value of a + * compare channel, a user defined action can be taken. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_timer Basic Timer + * + * A Basic Timer is a simple application where compare match operations are used + * to determine when a specific period has elapsed. In Basic Timer operations, + * one or more values in the module's Compare/Capture registers are used to + * specify the time (as a number of prescaled GCLK cycles) when an action should + * be taken by the microcontroller. This can be an Interrupt Service Routine + * (ISR), event generator via the event system, or a software flag that is + * polled via the user application. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg Waveform Generation + * + * Waveform generation enables the TC module to generate square waves, or if + * combined with an external passive low-pass filter; analog waveforms. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg_pwm Waveform Generation - PWM + * + * Pulse width modulation is a form of waveform generation and a signalling + * technique that can be useful in many situations. When PWM mode is used, + * a digital pulse train with a configurable frequency and duty cycle can be + * generated by the TC module and output to a GPIO pin of the device. + * + * Often PWM is used to communicate a control or information parameter to an + * external circuit or component. Differing impedances of the source generator + * and sink receiver circuits are less of an issue when using PWM compared to + * using an analog voltage value, as noise will not generally affect the + * signal's integrity to a meaningful extent. + * + * \ref asfdoc_sam0_tc_module_pwm_normal_diag "The figure below" illustrates + * operations and different states of the counter and its output when running + * the counter in PWM normal mode. As can be seen, the TOP value is unchanged + * and is set to MAX. The compare match value is changed at several points to + * illustrate the resulting waveform output changes. The PWM output is set to + * normal (i.e. non-inverted) output mode. + * + * \anchor asfdoc_sam0_tc_module_pwm_normal_diag + * \image html pwm_normal_ex.svg "Example of PWM in Normal Mode, and Different Counter Operations" + * + * + * In \ref asfdoc_sam0_tc_module_pwm_match_diag "the figure below", the + * counter is set to generate PWM in Match mode. The PWM output is inverted via + * the appropriate configuration option in the TC driver configuration + * structure. In this example, the counter value is changed once, but the + * compare match value is kept unchanged. As can be seen, it is possible to + * change the TOP value when running in PWM match mode. + * + * \anchor asfdoc_sam0_tc_module_pwm_match_diag + * \image html pwm_match_ex.svg "Example of PWM in Match Mode and Different Counter Operations" + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_wg_freq Waveform Generation - Frequency + * + * Frequency Generation mode is in many ways identical to PWM + * generation. However, in Frequency Generation a toggle only occurs + * on the output when a match on a capture channels occurs. When the + * match is made, the timer value is reset, resulting in a variable + * frequency square wave with a fixed 50% duty cycle. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt Capture Operations + * + * In capture operations, any event from the event system or a pin change can + * trigger a capture of the counter value. This captured counter value can be + * used as a timestamp for the event, or it can be used in frequency and pulse + * width capture. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt_event_capture Capture Operations - Event + * + * Event capture is a simple use of the capture functionality, + * designed to create timestamps for specific events. When the TC + * module's input capture pin is externally toggled, the current timer + * count value is copied into a buffered register which can then be + * read out by the user application. + * + * Note that when performing any capture operation, there is a risk that the + * counter reaches its top value (MAX) when counting up, or the bottom value + * (zero) when counting down, before the capture event occurs. This can distort + * the result, making event timestamps to appear shorter than reality; the + * user application should check for timer overflow when reading a capture + * result in order to detect this situation and perform an appropriate + * adjustment. + * + * Before checking for a new capture, \ref TC_STATUS_COUNT_OVERFLOW + * should be checked. The response to an overflow error is left to the user + * application, however it may be necessary to clear both the capture overflow + * flag and the capture flag upon each capture reading. + * + * \subsubsection asfdoc_sam0_tc_module_overview_compare_match_capt_pwc Capture Operations - Pulse Width + * + * Pulse Width Capture mode makes it possible to measure the pulse width and + * period of PWM signals. This mode uses two capture channels of the counter. + * This means that the counter module used for Pulse Width Capture can not be + * used for any other purpose. There are two modes for pulse width capture; + * Pulse Width Period (PWP) and Period Pulse Width (PPW). In PWP mode, capture + * channel 0 is used for storing the pulse width and capture channel 1 stores + * the observed period. While in PPW mode, the roles of the two capture channels + * are reversed. + * + * As in the above example it is necessary to poll on interrupt flags to see + * if a new capture has happened and check that a capture overflow error has + * not occurred. + * + * \subsection asfdoc_sam0_tc_module_overview_oneshot One-shot Mode + * + * TC modules can be configured into a one-shot mode. When configured in this + * manner, starting the timer will cause it to count until the next overflow + * or underflow condition before automatically halting, waiting to be manually + * triggered by the user application software or an event signal from the event + * system. + * + * \subsubsection asfdoc_sam0_tc_module_overview_inversion Wave Generation Output Inversion + * + * The output of the wave generation can be inverted by hardware if desired, + * resulting in the logically inverted value being output to the configured + * device GPIO pin. + * + * + * \section asfdoc_sam0_tc_special_considerations Special Considerations + * + * The number of capture compare registers in each TC module is dependent on + * the specific SAM device being used, and in some cases the counter size. + * + * The maximum amount of capture compare registers available in any SAM + * device is two when running in 32-bit mode and four in 8- and 16-bit modes. + * + * + * \section asfdoc_sam0_tc_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_tc_extra. This includes: + * - \ref asfdoc_sam0_tc_extra_acronyms + * - \ref asfdoc_sam0_tc_extra_dependencies + * - \ref asfdoc_sam0_tc_extra_errata + * - \ref asfdoc_sam0_tc_extra_history + * + * + * \section asfdoc_sam0_tc_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_tc_exqsg. + * + * \section asfdoc_sam0_tc_api_overview API Overview + * @{ + */ + +#include +#include +#include +#include + +/** + * Define port features set according to different device family + * @{ +*/ +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30)|| (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** TC double buffered. */ +# define FEATURE_TC_DOUBLE_BUFFERED +/** SYNCBUSY scheme version 2. */ +# define FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2 +/** TC time stamp capture and pulse width capture. */ +# define FEATURE_TC_STAMP_PW_CAPTURE +/** Read synchronization of COUNT. */ +# define FEATURE_TC_READ_SYNC +/** I/O pin edge capture. */ +# define FEATURE_TC_IO_CAPTURE +#endif + +#if (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Generate Direct Memory Access (DMA) triggers. */ +# define FEATURE_TC_GENERATE_DMA_TRIGGER +#endif +/*@}*/ + +#if !defined(__DOXYGEN__) +#if SAMD20 || SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +# define TC_INSTANCE_OFFSET 0 +#endif +#if SAMD21 || SAMR21 || SAMDA1 || (SAMHA1) || (SAMHA0) +# define TC_INSTANCE_OFFSET 3 +#endif +#if SAMD09 || SAMD10 || SAMD11 +# define TC_INSTANCE_OFFSET 1 +#endif + +#if SAMD20 +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC8_NUM +#elif SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC0_CC_NUM +#elif SAMD09 || SAMD10 || SAMD11 +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC1_CC8_NUM +#else +# define NUMBER_OF_COMPARE_CAPTURE_CHANNELS TC3_CC8_NUM + /* Same number for 8-, 16- or 32-bit TC and all TC instances */ +#endif + +/** TC Instance MAX ID Number. */ +#if SAMD20E || SAMD20G || SAMD21G || SAMD21E || SAMR21 +# if SAMD21GXXL || SAM_PART_IS_DEFINED(SAMD21G17AU) || SAM_PART_IS_DEFINED(SAMD21G18AU) +# define TC_INST_MAX_ID 7 +# else +# define TC_INST_MAX_ID 5 +# endif +#elif SAML21 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +# define TC_INST_MAX_ID 4 +#elif SAML22 +# define TC_INST_MAX_ID 3 +#elif SAMD09 || SAMD10 || SAMD11 +# define TC_INST_MAX_ID 2 +#else +# define TC_INST_MAX_ID 7 +#endif + +#endif + +#if TC_ASYNC == true +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#if TC_ASYNC == true +/** Enum for the possible callback types for the TC module. */ +enum tc_callback { + /** Callback for TC overflow */ + TC_CALLBACK_OVERFLOW, + /** Callback for capture overflow error */ + TC_CALLBACK_ERROR, + /** Callback for capture compare channel 0 */ + TC_CALLBACK_CC_CHANNEL0, + /** Callback for capture compare channel 1 */ + TC_CALLBACK_CC_CHANNEL1, +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + TC_CALLBACK_N, +# endif +}; +#endif + +/** + * \name Module Status Flags + * + * TC status flags, returned by \ref tc_get_status() and cleared by + * \ref tc_clear_status(). + * + * @{ + */ + +/** Timer channel 0 has matched against its compare value, or has captured a + * new value. + */ +#define TC_STATUS_CHANNEL_0_MATCH (1UL << 0) + +/** Timer channel 1 has matched against its compare value, or has captured a + * new value. + */ +#define TC_STATUS_CHANNEL_1_MATCH (1UL << 1) + +/** Timer register synchronization has completed, and the synchronized count + * value may be read. + */ +#define TC_STATUS_SYNC_READY (1UL << 2) + +/** A new value was captured before the previous value was read, resulting in + * lost data. + */ +#define TC_STATUS_CAPTURE_OVERFLOW (1UL << 3) + +/** The timer count value has overflowed from its maximum value to its minimum + * when counting upward, or from its minimum value to its maximum when + * counting downward. + */ +#define TC_STATUS_COUNT_OVERFLOW (1UL << 4) + +#ifdef FEATURE_TC_DOUBLE_BUFFERED +/** Channel 0 compare or capture buffer valid. */ +#define TC_STATUS_CHN0_BUFFER_VALID (1UL << 5) +/** Channel 1 compare or capture buffer valid. */ +#define TC_STATUS_CHN1_BUFFER_VALID (1UL << 6) +/** Period buffer valid. */ +#define TC_STATUS_PERIOD_BUFFER_VALID (1UL << 7) +#endif +/** @} */ + +/** + * \brief Index of the compare capture channels. + * + * This enum is used to specify which capture/compare channel to do + * operations on. + */ +enum tc_compare_capture_channel { + /** Index of compare capture channel 0 */ + TC_COMPARE_CAPTURE_CHANNEL_0, + /** Index of compare capture channel 1 */ + TC_COMPARE_CAPTURE_CHANNEL_1, +}; + +/** + * \name TC Wave Generation Mode + * + * @{ + */ +#if SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +/** TC wave generation mode: normal frequency. */ +#define TC_WAVE_GENERATION_NORMAL_FREQ_MODE TC_WAVE_WAVEGEN_NFRQ +/** TC wave generation mode: match frequency. */ +#define TC_WAVE_GENERATION_MATCH_FREQ_MODE TC_WAVE_WAVEGEN_MFRQ +/** TC wave generation mode: normal PWM. */ +#define TC_WAVE_GENERATION_NORMAL_PWM_MODE TC_WAVE_WAVEGEN_NPWM +/** TC wave generation mode: match PWM. */ +#define TC_WAVE_GENERATION_MATCH_PWM_MODE TC_WAVE_WAVEGEN_MPWM +#else +/** TC wave generation mode: normal frequency. */ +#define TC_WAVE_GENERATION_NORMAL_FREQ_MODE TC_CTRLA_WAVEGEN_NFRQ +/** TC wave generation mode: match frequency. */ +#define TC_WAVE_GENERATION_MATCH_FREQ_MODE TC_CTRLA_WAVEGEN_MFRQ +/** TC wave generation mode: normal PWM. */ +#define TC_WAVE_GENERATION_NORMAL_PWM_MODE TC_CTRLA_WAVEGEN_NPWM +/** TC wave generation mode: match PWM. */ +#define TC_WAVE_GENERATION_MATCH_PWM_MODE TC_CTRLA_WAVEGEN_MPWM +#endif +/** @} */ + +/** + * \brief TC wave generation mode enum. + * + * This enum is used to select which mode to run the wave + * generation in. + * + */ +enum tc_wave_generation { + /** Top is maximum, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_NORMAL_FREQ = TC_WAVE_GENERATION_NORMAL_FREQ_MODE, + + /** Top is CC0, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_MATCH_FREQ = TC_WAVE_GENERATION_MATCH_FREQ_MODE, + + /** Top is maximum, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_NORMAL_PWM = TC_WAVE_GENERATION_NORMAL_PWM_MODE, + + /** Top is CC0, except in 8-bit counter size where it is the PER + * register + */ + TC_WAVE_GENERATION_MATCH_PWM = TC_WAVE_GENERATION_MATCH_PWM_MODE, +}; + +/** + * \brief Specifies if the counter is 8-, 16-, or 32-bit. + * + * This enum specifies the maximum value it is possible to count to. + */ +enum tc_counter_size { + /** The counter's maximum value is 0xFF, the period register is + * available to be used as top value + */ + TC_COUNTER_SIZE_8BIT = TC_CTRLA_MODE_COUNT8, + + /** The counter's maximum value is 0xFFFF. There is no separate + * period register, to modify top one of the capture compare + * registers has to be used. This limits the amount of + * available channels. + */ + TC_COUNTER_SIZE_16BIT = TC_CTRLA_MODE_COUNT16, + + /** The counter's maximum value is 0xFFFFFFFF. There is no separate + * period register, to modify top one of the capture compare + * registers has to be used. This limits the amount of + * available channels. + */ + TC_COUNTER_SIZE_32BIT = TC_CTRLA_MODE_COUNT32, +}; + +/** + * \brief TC Counter reload action enum. + * + * This enum specify how the counter and prescaler should reload. + */ +enum tc_reload_action { + /** The counter is reloaded/reset on the next GCLK and starts + * counting on the prescaler clock + */ + TC_RELOAD_ACTION_GCLK = TC_CTRLA_PRESCSYNC_GCLK, + + /** The counter is reloaded/reset on the next prescaler clock + */ + TC_RELOAD_ACTION_PRESC = TC_CTRLA_PRESCSYNC_PRESC, + + /** The counter is reloaded/reset on the next GCLK, and the + * prescaler is restarted as well + */ + TC_RELOAD_ACTION_RESYNC = TC_CTRLA_PRESCSYNC_RESYNC, +}; + +/** + * \brief TC clock prescaler values. + * + * This enum is used to choose the clock prescaler + * configuration. The prescaler divides the clock frequency of the TC + * module to make the counter count slower. + */ +enum tc_clock_prescaler { + /** Divide clock by 1 */ + TC_CLOCK_PRESCALER_DIV1 = TC_CTRLA_PRESCALER(0), + /** Divide clock by 2 */ + TC_CLOCK_PRESCALER_DIV2 = TC_CTRLA_PRESCALER(1), + /** Divide clock by 4 */ + TC_CLOCK_PRESCALER_DIV4 = TC_CTRLA_PRESCALER(2), + /** Divide clock by 8 */ + TC_CLOCK_PRESCALER_DIV8 = TC_CTRLA_PRESCALER(3), + /** Divide clock by 16 */ + TC_CLOCK_PRESCALER_DIV16 = TC_CTRLA_PRESCALER(4), + /** Divide clock by 64 */ + TC_CLOCK_PRESCALER_DIV64 = TC_CTRLA_PRESCALER(5), + /** Divide clock by 256 */ + TC_CLOCK_PRESCALER_DIV256 = TC_CTRLA_PRESCALER(6), + /** Divide clock by 1024 */ + TC_CLOCK_PRESCALER_DIV1024 = TC_CTRLA_PRESCALER(7), +}; + +/** + * \brief TC module count direction. + * + * Timer/Counter count direction. + */ +enum tc_count_direction { + /** Timer should count upward from zero to MAX */ + TC_COUNT_DIRECTION_UP, + + /** Timer should count downward to zero from MAX */ + TC_COUNT_DIRECTION_DOWN, +}; + +/** + * \name Waveform Inversion Mode + * + * @{ + */ +#if SAML21 || SAML22 || SAMC20 || SAMC21 || SAMR30 || (SAMR34) || (SAMR35) || (WLR089) +/** Waveform inversion CC0 mode. */ +#define TC_WAVEFORM_INVERT_CC0_MODE TC_DRVCTRL_INVEN(1) +/** Waveform inversion CC1 mode. */ +#define TC_WAVEFORM_INVERT_CC1_MODE TC_DRVCTRL_INVEN(2) +#else +/** Waveform inversion CC0 mode. */ +#define TC_WAVEFORM_INVERT_CC0_MODE TC_CTRLC_INVEN(1) +/** Waveform inversion CC1 mode. */ +#define TC_WAVEFORM_INVERT_CC1_MODE TC_CTRLC_INVEN(2) +#endif + +/** + * \brief Waveform inversion mode. + * + * Output waveform inversion mode. + */ +enum tc_waveform_invert_output { + /** No inversion of the waveform output */ + TC_WAVEFORM_INVERT_OUTPUT_NONE = 0, + /** Invert output from compare channel 0 */ + TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_0 = TC_WAVEFORM_INVERT_CC0_MODE, + /** Invert output from compare channel 1 */ + TC_WAVEFORM_INVERT_OUTPUT_CHANNEL_1 = TC_WAVEFORM_INVERT_CC1_MODE, +}; + +/** + * \brief Action to perform when the TC module is triggered by an event. + * + * Event action to perform when the module is triggered by an event. + */ +enum tc_event_action { + /** No event action */ + TC_EVENT_ACTION_OFF = TC_EVCTRL_EVACT_OFF, + /** Re-trigger on event */ + TC_EVENT_ACTION_RETRIGGER = TC_EVCTRL_EVACT_RETRIGGER, + /** Increment counter on event */ + TC_EVENT_ACTION_INCREMENT_COUNTER = TC_EVCTRL_EVACT_COUNT, + /** Start counter on event */ + TC_EVENT_ACTION_START = TC_EVCTRL_EVACT_START, + + /** Store period in capture register 0, pulse width in capture + * register 1 + */ + TC_EVENT_ACTION_PPW = TC_EVCTRL_EVACT_PPW, + + /** Store pulse width in capture register 0, period in capture + * register 1 + */ + TC_EVENT_ACTION_PWP = TC_EVCTRL_EVACT_PWP, +#ifdef FEATURE_TC_STAMP_PW_CAPTURE + /** Time stamp capture */ + TC_EVENT_ACTION_STAMP = TC_EVCTRL_EVACT_STAMP, + /** Pulse width capture */ + TC_EVENT_ACTION_PW = TC_EVCTRL_EVACT_PW, +#endif +}; + +/** + * \brief TC event enable/disable structure. + * + * Event flags for the \ref tc_enable_events() and \ref tc_disable_events(). + */ +struct tc_events { + /** Generate an output event on a compare channel match */ + bool generate_event_on_compare_channel + [NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; + /** Generate an output event on counter overflow */ + bool generate_event_on_overflow; + /** Perform the configured event action when an incoming event is signalled */ + bool on_event_perform_action; + /** Specifies if the input event source is inverted, when used in PWP or + * PPW event action modes + */ + bool invert_event_input; + /** Specifies which event to trigger if an event is triggered */ + enum tc_event_action event_action; +}; + +/** + * \brief Configuration struct for TC module in 8-bit size counter mode. + */ +struct tc_8bit_config { + /** Initial timer count value */ + uint8_t value; + /** Where to count to or from depending on the direction on the counter */ + uint8_t period; + /** Value to be used for compare match on each channel */ + uint8_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +}; + +/** + * \brief Configuration struct for TC module in 16-bit size counter mode. + */ +struct tc_16bit_config { + /** Initial timer count value */ + uint16_t value; + /** Value to be used for compare match on each channel */ + uint16_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +}; + +/** + * \brief Configuration struct for TC module in 32-bit size counter mode. + */ +struct tc_32bit_config { + /** Initial timer count value */ + uint32_t value; + /** Value to be used for compare match on each channel */ + uint32_t compare_capture_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +}; + +/** + * \brief Configuration struct for TC module in 32-bit size counter mode. + */ +struct tc_pwm_channel { + /** When \c true, PWM output for the given channel is enabled */ + bool enabled; + /** Specifies pin output for each channel */ + uint32_t pin_out; + /** Specifies Multiplexer (MUX) setting for each output channel pin */ + uint32_t pin_mux; +}; + +/** + * \brief TC configuration structure. + * + * Configuration struct for a TC instance. This structure should be + * initialized by the \ref tc_get_config_defaults function before being + * modified by the user application. + */ +struct tc_config { + /** GCLK generator used to clock the peripheral */ + enum gclk_generator clock_source; + + /** When \c true the module is enabled during standby */ + bool run_in_standby; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /** Run on demand */ + bool on_demand; +#endif + /** Specifies either 8-, 16-, or 32-bit counter size */ + enum tc_counter_size counter_size; + /** Specifies the prescaler value for GCLK_TC */ + enum tc_clock_prescaler clock_prescaler; + /** Specifies which waveform generation mode to use */ + enum tc_wave_generation wave_generation; + + /** Specifies the reload or reset time of the counter and prescaler + * resynchronization on a re-trigger event for the TC + */ + enum tc_reload_action reload_action; + + /** Specifies which channel(s) to invert the waveform on. + For SAM L21/L22/C20/C21, it's also used to invert I/O input pin. */ + uint8_t waveform_invert_output; + + /** Specifies which channel(s) to enable channel capture + * operation on + */ + bool enable_capture_on_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +#ifdef FEATURE_TC_IO_CAPTURE + /** Specifies which channel(s) to enable I/O capture + * operation on + */ + bool enable_capture_on_IO[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; +#endif + + /** When \c true, one-shot will stop the TC on next hardware or software + * re-trigger event or overflow/underflow + */ + bool oneshot; + + /** Specifies the direction for the TC to count */ + enum tc_count_direction count_direction; + + /** Specifies the PWM channel for TC */ + struct tc_pwm_channel pwm_channel[NUMBER_OF_COMPARE_CAPTURE_CHANNELS]; + + /** Access the different counter size settings through this configuration member. */ + union { + /** Struct for 8-bit specific timer configuration */ + struct tc_8bit_config counter_8_bit; + /** Struct for 16-bit specific timer configuration */ + struct tc_16bit_config counter_16_bit; + /** Struct for 32-bit specific timer configuration */ + struct tc_32bit_config counter_32_bit; + }; + +#ifdef FEATURE_TC_DOUBLE_BUFFERED + /** Set to \c true to enable double buffering write. When enabled any write + * through \ref tc_set_top_value(), \ref tc_set_compare_value() and + * will direct to the buffer register as buffered + * value, and the buffered value will be committed to effective register + * on UPDATE condition, if update is not locked. + */ + bool double_buffering_enabled; +#endif +}; + +#if TC_ASYNC == true +/** Forward Declaration for the device instance. */ +struct tc_module; + +/** Type of the callback functions. */ +typedef void (*tc_callback_t)(struct tc_module *const module); +#endif + +/** + * \brief TC software device instance structure. + * + * TC software instance structure, used to retain software state information + * of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved for module-internal use only. + */ +struct tc_module { +#if !defined(__DOXYGEN__) + /** Hardware module pointer of the associated Timer/Counter peripheral */ + Tc *hw; + + /** Size of the initialized Timer/Counter module configuration */ + enum tc_counter_size counter_size; +# if TC_ASYNC == true + /** Array of callbacks */ + tc_callback_t callback[TC_CALLBACK_N]; + /** Bit mask for callbacks registered */ + uint8_t register_callback_mask; + /** Bit mask for callbacks enabled */ + uint8_t enable_callback_mask; +# endif +#ifdef FEATURE_TC_DOUBLE_BUFFERED + /** Set to \c true to enable double buffering write */ + bool double_buffering_enabled; +#endif +#endif +}; + +#if !defined(__DOXYGEN__) +uint8_t _tc_get_inst_index( + Tc *const hw); +#endif + +/** + * \name Driver Initialization and Configuration + * @{ + */ + +/** + * \brief Determines if the hardware module(s) are currently synchronizing to + * the bus. + * + * Checks to see if the underlying hardware peripheral module(s) are currently + * synchronizing across multiple clock domains to the hardware bus. This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Synchronization status of the underlying hardware module(s). + * + * \retval false If the module has completed synchronization + * \retval true If the module synchronization is ongoing + */ +static inline bool tc_is_syncing( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + return (tc_module->SYNCBUSY.reg); +#else + return (tc_module->STATUS.reg & TC_STATUS_SYNCBUSY); +#endif +} + +/** + * \brief Initializes config with predefined default values. + * + * This function will initialize a given TC configuration structure to + * a set of known default values. This function should be called on + * any new instance of the configuration structures before being + * modified by the user application. + * + * The default configuration is as follows: + * \li GCLK generator 0 (GCLK main) clock source + * \li 16-bit counter size on the counter + * \li No prescaler + * \li Normal frequency wave generation + * \li GCLK reload action + * \li Don't run in standby + * \li Don't run on demand for SAM L21/L22/C20/C21 + * \li No inversion of waveform output + * \li No capture enabled + * \li No I/O capture enabled for SAM L21/L22/C20/C21 + * \li No event input enabled + * \li Count upward + * \li Don't perform one-shot operations + * \li No event action + * \li No channel 0 PWM output + * \li No channel 1 PWM output + * \li Counter starts on 0 + * \li Capture compare channel 0 set to 0 + * \li Capture compare channel 1 set to 0 + * \li No PWM pin output enabled + * \li Pin and MUX configuration not set + * \li Double buffer disabled (if have this feature) + * + * \param[out] config Pointer to a TC module configuration structure to set + */ +static inline void tc_get_config_defaults( + struct tc_config *const config) +{ + /* Sanity check arguments */ + Assert(config); + + /* Write default config to config struct */ + config->clock_source = GCLK_GENERATOR_0; + config->counter_size = TC_COUNTER_SIZE_16BIT; + config->clock_prescaler = TC_CLOCK_PRESCALER_DIV1; + config->wave_generation = TC_WAVE_GENERATION_NORMAL_FREQ; + config->reload_action = TC_RELOAD_ACTION_GCLK; + config->run_in_standby = false; +#if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + config->on_demand = false; +#endif + config->waveform_invert_output = TC_WAVEFORM_INVERT_OUTPUT_NONE; + config->enable_capture_on_channel[TC_COMPARE_CAPTURE_CHANNEL_0] = false; + config->enable_capture_on_channel[TC_COMPARE_CAPTURE_CHANNEL_1] = false; +#ifdef FEATURE_TC_IO_CAPTURE + config->enable_capture_on_IO[TC_COMPARE_CAPTURE_CHANNEL_0] = false; + config->enable_capture_on_IO[TC_COMPARE_CAPTURE_CHANNEL_1] = false; +#endif + + config->count_direction = TC_COUNT_DIRECTION_UP; + config->oneshot = false; + + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].enabled = false; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].pin_out = 0; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_0].pin_mux = 0; + + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].enabled = false; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].pin_out = 0; + config->pwm_channel[TC_COMPARE_CAPTURE_CHANNEL_1].pin_mux = 0; + + config->counter_16_bit.value = 0x0000; + config->counter_16_bit.compare_capture_channel\ + [TC_COMPARE_CAPTURE_CHANNEL_0] = 0x0000; + config->counter_16_bit.compare_capture_channel\ + [TC_COMPARE_CAPTURE_CHANNEL_1] = 0x0000; +#ifdef FEATURE_TC_DOUBLE_BUFFERED + config->double_buffering_enabled = false; +#endif + +} + +enum status_code tc_init( + struct tc_module *const module_inst, + Tc *const hw, + const struct tc_config *const config); + +/** @} */ + +/** + * \name Event Management + * @{ + */ + +/** + * \brief Enables a TC module event input or output. + * + * Enables one or more input or output events to or from the TC module. + * See \ref tc_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] events Struct containing flags of events to enable + */ +static inline void tc_enable_events( + struct tc_module *const module_inst, + struct tc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Tc *const tc_module = module_inst->hw; + + uint32_t event_mask = 0; + + if (events->invert_event_input == true) { + event_mask |= TC_EVCTRL_TCINV; + } + + if (events->on_event_perform_action == true) { + event_mask |= TC_EVCTRL_TCEI; + } + + if (events->generate_event_on_overflow == true) { + event_mask |= TC_EVCTRL_OVFEO; + } + + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (events->generate_event_on_compare_channel[i] == true) { + event_mask |= (TC_EVCTRL_MCEO(1) << i); + } + } + + tc_module->COUNT8.EVCTRL.reg |= event_mask | events->event_action; +} + +/** + * \brief Disables a TC module event input or output. + * + * Disables one or more input or output events to or from the TC module. + * See \ref tc_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] events Struct containing flags of events to disable + */ +static inline void tc_disable_events( + struct tc_module *const module_inst, + struct tc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Tc *const tc_module = module_inst->hw; + + uint32_t event_mask = 0; + + if (events->invert_event_input == true) { + event_mask |= TC_EVCTRL_TCINV; + } + + if (events->on_event_perform_action == true) { + event_mask |= TC_EVCTRL_TCEI; + } + + if (events->generate_event_on_overflow == true) { + event_mask |= TC_EVCTRL_OVFEO; + } + + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (events->generate_event_on_compare_channel[i] == true) { + event_mask |= (TC_EVCTRL_MCEO(1) << i); + } + } + + tc_module->COUNT8.EVCTRL.reg &= ~event_mask; +} + +/** @} */ + +/** + * \name Enable/Disable/Reset + * @{ + */ + +enum status_code tc_reset( + const struct tc_module *const module_inst); + +/** + * \brief Enable the TC module. + * + * Enables a TC module that has been previously initialized. The counter will + * start when the counter is enabled. + * + * \note When the counter is configured to re-trigger on an event, the counter + * will not start until the start function is used. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_enable( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Enable TC module */ + tc_module->CTRLA.reg |= TC_CTRLA_ENABLE; +} + +/** + * \brief Disables the TC module. + * + * Disables a TC module and stops the counter. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_disable( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Disbale interrupt */ + tc_module->INTENCLR.reg = TC_INTENCLR_MASK; + /* Clear interrupt flag */ + tc_module->INTFLAG.reg = TC_INTFLAG_MASK; + + /* Disable TC module */ + tc_module->CTRLA.reg &= ~TC_CTRLA_ENABLE; +} + +/** @} */ + +/** + * \name Get/Set Count Value + * @{ + */ + +uint32_t tc_get_count_value( + const struct tc_module *const module_inst); + +enum status_code tc_set_count_value( + const struct tc_module *const module_inst, + const uint32_t count); + +/** @} */ + +/** + * \name Start/Stop Counter + * @{ + */ + +/** + * \brief Stops the counter. + * + * This function will stop the counter. When the counter is stopped + * the value in the count value is set to 0 if the counter was + * counting up, or maximum if the counter was counting + * down when stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_stop_counter( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_STOP_Val); +} + +/** + * \brief Starts the counter. + * + * Starts or restarts an initialized TC module's counter. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_start_counter( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_RETRIGGER_Val); +} + +/** @} */ + +#ifdef FEATURE_TC_DOUBLE_BUFFERED +/** + * \name Double Buffering + * @{ + */ + +/** + * \brief Update double buffer. + * + * Update double buffer. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_update_double_buffer( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_UPDATE_Val); +} +/** @} */ +#endif + +#ifdef FEATURE_TC_READ_SYNC +/** + * \name Count Read Synchronization + * @{ + */ + +/** + * \brief Read synchronization of COUNT. + * + * Read synchronization of COUNT. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_sync_read_count( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_READSYNC_Val); +#if (SAMC20) || (SAMC21) || (SAML21) || (SAML22) || (SAMR30) + /* wait for the CMD bits in CTRLBSET to be cleared, meaning the CMD has been executed */ + while(tc_module->CTRLBSET.reg & TC_CTRLBSET_CMD_READSYNC); +#endif +} +/** @} */ +#endif + +#ifdef FEATURE_TC_GENERATE_DMA_TRIGGER +/** + * \name Generate TC DMA Triggers Command + * @{ + */ + +/** + * \brief TC DMA Trigger. + * + * TC DMA trigger command. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tc_dma_trigger_command( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tc_module->CTRLBCLR.reg = TC_CTRLBCLR_CMD_NONE; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + +#if (SAMC20) || (SAMC21) || (SAML22) || (SAML21XXXB) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Write command to execute */ + tc_module->CTRLBSET.reg = TC_CTRLBSET_CMD(TC_CTRLBSET_CMD_DMAOS_Val); +#endif +} +/** @} */ +#endif + +/** + * \name Get Capture Set Compare + * @{ + */ + +uint32_t tc_get_capture_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index); + +enum status_code tc_set_compare_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index, + const uint32_t compare_value); + +/** @} */ + +/** + * \name Set Top Value + * @{ + */ + +enum status_code tc_set_top_value( + const struct tc_module *const module_inst, + const uint32_t top_value); + +/** @} */ + +/** + * \name Status Management + * @{ + */ + +/** + * \brief Retrieves the current module status. + * + * Retrieves the status of the module, giving overall state information. + * + * \param[in] module_inst Pointer to the TC software instance struct + * + * \return Bitmask of \c TC_STATUS_* flags. + * + * \retval TC_STATUS_CHANNEL_0_MATCH Timer channel 0 compare/capture match + * \retval TC_STATUS_CHANNEL_1_MATCH Timer channel 1 compare/capture match + * \retval TC_STATUS_SYNC_READY Timer read synchronization has completed + * \retval TC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed + * \retval TC_STATUS_COUNT_OVERFLOW Timer count value has overflowed + * \retval TC_STATUS_CHN0_BUFFER_VALID Timer count channel 0 compare/capture buffer valid + * \retval TC_STATUS_CHN1_BUFFER_VALID Timer count channel 1 compare/capture buffer valid + * \retval TC_STATUS_PERIOD_BUFFER_VALID Timer count period buffer valid + */ +static inline uint32_t tc_get_status( + struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + uint32_t int_flags = tc_module->INTFLAG.reg; + + uint32_t status_flags = 0; + + /* Check for TC channel 0 match */ + if (int_flags & TC_INTFLAG_MC(1)) { + status_flags |= TC_STATUS_CHANNEL_0_MATCH; + } + + /* Check for TC channel 1 match */ + if (int_flags & TC_INTFLAG_MC(2)) { + status_flags |= TC_STATUS_CHANNEL_1_MATCH; + } + +#if !defined(FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2) + /* Check for TC read synchronization ready */ + if (int_flags & TC_INTFLAG_SYNCRDY) { + status_flags |= TC_STATUS_SYNC_READY; + } +#endif + + /* Check for TC capture overflow */ + if (int_flags & TC_INTFLAG_ERR) { + status_flags |= TC_STATUS_CAPTURE_OVERFLOW; + } + + /* Check for TC count overflow */ + if (int_flags & TC_INTFLAG_OVF) { + status_flags |= TC_STATUS_COUNT_OVERFLOW; + } +#ifdef FEATURE_TC_DOUBLE_BUFFERED + uint8_t double_buffer_valid_status = tc_module->STATUS.reg; + + /* Check channel 0 compare or capture buffer valid */ + if (double_buffer_valid_status & TC_STATUS_CCBUFV0) { + status_flags |= TC_STATUS_CHN0_BUFFER_VALID; + } + /* Check channel 0 compare or capture buffer valid */ + if (double_buffer_valid_status & TC_STATUS_CCBUFV1) { + status_flags |= TC_STATUS_CHN1_BUFFER_VALID; + } + /* Check period buffer valid */ + if (double_buffer_valid_status & TC_STATUS_PERBUFV) { + status_flags |= TC_STATUS_PERIOD_BUFFER_VALID; + } +#endif + + return status_flags; +} + +/** + * \brief Clears a module status flag. + * + * Clears the given status flag of the module. + * + * \param[in] module_inst Pointer to the TC software instance struct + * \param[in] status_flags Bitmask of \c TC_STATUS_* flags to clear + */ +static inline void tc_clear_status( + struct tc_module *const module_inst, + const uint32_t status_flags) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + uint32_t int_flags = 0; + + /* Check for TC channel 0 match */ + if (status_flags & TC_STATUS_CHANNEL_0_MATCH) { + int_flags |= TC_INTFLAG_MC(1); + } + + /* Check for TC channel 1 match */ + if (status_flags & TC_STATUS_CHANNEL_1_MATCH) { + int_flags |= TC_INTFLAG_MC(2); + } + +#if !defined(FEATURE_TC_SYNCBUSY_SCHEME_VERSION_2) + /* Check for TC read synchronization ready */ + if (status_flags & TC_STATUS_SYNC_READY) { + int_flags |= TC_INTFLAG_SYNCRDY; + } +#endif + + /* Check for TC capture overflow */ + if (status_flags & TC_STATUS_CAPTURE_OVERFLOW) { + int_flags |= TC_INTFLAG_ERR; + } + + /* Check for TC count overflow */ + if (status_flags & TC_STATUS_COUNT_OVERFLOW) { + int_flags |= TC_INTFLAG_OVF; + } + + /* Clear interrupt flag */ + tc_module->INTFLAG.reg = int_flags; +} + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * \page asfdoc_sam0_tc_extra Extra Information for TC Driver + * + * \section asfdoc_sam0_tc_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
DMADirect Memory Access
TCTimer Counter
PWMPulse Width Modulation
PWPPulse Width Period
PPWPeriod Pulse Width
+ * + * + * \section asfdoc_sam0_tc_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_tc_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_tc_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Added support for SAM D21 and do some modifications as below: + * \li Clean up in the configuration structure, the counter size + * setting specific registers is accessed through the counter_8_bit, + * counter_16_bit, and counter_32_bit structures + * \li All event related settings moved into the tc_event structure
Added automatic digital clock interface enable for the slave TC + * module when a timer is initialized in 32-bit mode
Initial release
+ */ + +/** + * \page asfdoc_sam0_tc_exqsg Examples for TC Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_tc_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that QSGs can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_tc_basic_use_case + * - \subpage asfdoc_sam0_tc_macth_freq_use_case + * \if TC_CALLBACK_MODE + * - \subpage asfdoc_sam0_tc_timer_use_case + * - \subpage asfdoc_sam0_tc_callback_use_case + * \endif + * - \subpage asfdoc_sam0_tc_dma_use_case + * + * \page asfdoc_sam0_tc_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev. + * Date + * Comments + *
42123E12/2015Added support for SAM L21/L22, SAM DA1, SAM D09, and SAM C21
42123D12/2014Added timer use case. + * Added support for SAM R21 and SAM D10/D11
42123C01/2014Added support for SAM D21
42123B06/2013Corrected documentation typos
42123A06/2013Initial document release
+ */ + +#endif /* TC_H_INCLUDED */ diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c new file mode 100644 index 0000000..3b54fee --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.c @@ -0,0 +1,189 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Callback Driver + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/* + * Support and FAQ: visit Microchip Support + */ + +#include "tc_interrupt.h" + +void *_tc_instances[TC_INST_NUM]; + +void _tc_interrupt_handler(uint8_t instance); + +/** + * \brief Registers a callback. + * + * Registers a callback function which is implemented by the user. + * + * \note The callback must be enabled by \ref tc_enable_callback, + * in order for the interrupt handler to call it when the conditions for the + * callback type is met. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_func Pointer to callback function + * \param[in] callback_type Callback type given by an enum + */ +enum status_code tc_register_callback( + struct tc_module *const module, + tc_callback_t callback_func, + const enum tc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + Assert(callback_func); + + /* Register callback function */ + module->callback[callback_type] = callback_func; + + /* Set the bit corresponding to the callback_type */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->register_callback_mask |= TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->register_callback_mask |= TC_INTFLAG_MC(2); + } + else { + module->register_callback_mask |= (1 << callback_type); + } + return STATUS_OK; +} + +/** + * \brief Unregisters a callback. + * + * Unregisters a callback function implemented by the user. The callback should be + * disabled before it is unregistered. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_type Callback type given by an enum + */ +enum status_code tc_unregister_callback( + struct tc_module *const module, + const enum tc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + /* Unregister callback function */ + module->callback[callback_type] = NULL; + + /* Clear the bit corresponding to the callback_type */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->register_callback_mask &= ~TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->register_callback_mask &= ~TC_INTFLAG_MC(2); + } + else { + module->register_callback_mask &= ~(1 << callback_type); + } + return STATUS_OK; +} + +/** + * \internal ISR handler for TC + * + * Auto-generate a set of interrupt handlers for each TC in the device. + */ +#define _TC_INTERRUPT_HANDLER(n, m) \ + void TC##n##_Handler(void) \ + { \ + _tc_interrupt_handler(m); \ + } + +#if (SAML21E) || (SAML21G) || (SAMR30E) || (SAMR30G) + _TC_INTERRUPT_HANDLER(0,0) + _TC_INTERRUPT_HANDLER(1,1) + _TC_INTERRUPT_HANDLER(4,2) +#else + MRECURSION(TC_INST_NUM, _TC_INTERRUPT_HANDLER, TC_INST_MAX_ID) +#endif + + +/** + * \internal Interrupt Handler for TC module + * + * Handles interrupts as they occur, it will run the callback functions + * that are registered and enabled. + * + * \param[in] instance ID of the TC instance calling the interrupt + * handler + */ +void _tc_interrupt_handler( + uint8_t instance) +{ + /* Temporary variable */ + uint8_t interrupt_and_callback_status_mask; + + /* Get device instance from the look-up table */ + struct tc_module *module + = (struct tc_module *)_tc_instances[instance]; + + /* Read and mask interrupt flag register */ + interrupt_and_callback_status_mask = module->hw->COUNT8.INTFLAG.reg & + module->register_callback_mask & + module->enable_callback_mask; + + /* Check if an Overflow interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_OVF) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_OVERFLOW])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_OVF; + } + + /* Check if an Error interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_ERR) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_ERROR])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_ERR; + } + + /* Check if an Match/Capture Channel 0 interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_MC(1)) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_CC_CHANNEL0])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_MC(1); + } + + /* Check if an Match/Capture Channel 1 interrupt has occurred */ + if (interrupt_and_callback_status_mask & TC_INTFLAG_MC(2)) { + /* Invoke registered and enabled callback function */ + (module->callback[TC_CALLBACK_CC_CHANNEL1])(module); + /* Clear interrupt flag */ + module->hw->COUNT8.INTFLAG.reg = TC_INTFLAG_MC(2); + } +} diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h new file mode 100644 index 0000000..0d3a0b0 --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc_interrupt.h @@ -0,0 +1,169 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Callback Driver + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ + +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef TC_INTERRUPT_H_INCLUDED +#define TC_INTERRUPT_H_INCLUDED + +#include "tc.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(__DOXYGEN__) +extern void *_tc_instances[TC_INST_NUM]; + +# define _TC_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_TC##n, +/** + * \internal Get the interrupt vector for the given device instance + * + * \param[in] TC module instance number + * + * \return Interrupt vector for of the given TC module instance. + */ +static enum system_interrupt_vector _tc_interrupt_get_interrupt_vector( + uint32_t inst_num) +{ + static uint8_t tc_interrupt_vectors[TC_INST_NUM] = + { +#if (SAML21E) || (SAML21G) || (SAMR30E) || (SAMR30G) + SYSTEM_INTERRUPT_MODULE_TC0, + SYSTEM_INTERRUPT_MODULE_TC1, + SYSTEM_INTERRUPT_MODULE_TC4 +#else + MRECURSION(TC_INST_NUM, _TC_INTERRUPT_VECT_NUM, TC_INST_MAX_ID) +#endif + }; + + return (enum system_interrupt_vector)tc_interrupt_vectors[inst_num]; +} +#endif /* !defined(__DOXYGEN__) */ + +/** + * \name Callback Management + * {@ + */ + +enum status_code tc_register_callback( + struct tc_module *const module, + tc_callback_t callback_func, + const enum tc_callback callback_type); + +enum status_code tc_unregister_callback( + struct tc_module *const module, + const enum tc_callback callback_type); + +/** + * \brief Enables callback. + * + * Enables the callback function registered by the \ref + * tc_register_callback. The callback function will be called from the + * interrupt handler when the conditions for the callback type are + * met. This function will also enable the appropriate interrupts. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_type Callback type given by an enum + */ +static inline void tc_enable_callback( + struct tc_module *const module, + const enum tc_callback callback_type) +{ + /* Sanity check arguments */ + Assert(module); + + + /* Enable interrupts for this TC module */ + system_interrupt_enable(_tc_interrupt_get_interrupt_vector(_tc_get_inst_index(module->hw))); + + /* Enable callback */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->enable_callback_mask |= TC_INTFLAG_MC(1); + module->hw->COUNT8.INTENSET.reg = TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->enable_callback_mask |= TC_INTFLAG_MC(2); + module->hw->COUNT8.INTENSET.reg = TC_INTFLAG_MC(2); + } + else { + module->enable_callback_mask |= (1 << callback_type); + module->hw->COUNT8.INTENSET.reg = (1 << callback_type); + } +} + +/** + * \brief Disables callback. + * + * Disables the callback function registered by the \ref + * tc_register_callback, and the callback will not be called from the + * interrupt routine. The function will also disable the appropriate + * interrupts. + * + * \param[in] module Pointer to TC software instance struct + * \param[in] callback_type Callback type given by an enum + */ +static inline void tc_disable_callback( + struct tc_module *const module, + const enum tc_callback callback_type){ + /* Sanity check arguments */ + Assert(module); + + /* Disable callback */ + if (callback_type == TC_CALLBACK_CC_CHANNEL0) { + module->hw->COUNT8.INTENCLR.reg = TC_INTFLAG_MC(1); + module->enable_callback_mask &= ~TC_INTFLAG_MC(1); + } + else if (callback_type == TC_CALLBACK_CC_CHANNEL1) { + module->hw->COUNT8.INTENCLR.reg = TC_INTFLAG_MC(2); + module->enable_callback_mask &= ~TC_INTFLAG_MC(2); + } + else { + module->hw->COUNT8.INTENCLR.reg = (1 << callback_type); + module->enable_callback_mask &= ~(1 << callback_type); + } +} + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif /* TC_INTERRUPT_H_INCLUDED */ diff --git a/TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c b/TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c new file mode 100644 index 0000000..766fd55 --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tc/tc_sam_d_r_h/tc.c @@ -0,0 +1,675 @@ +/** + * \file + * + * \brief SAM TC - Timer Counter Driver + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "tc.h" + +#if TC_ASYNC == true +# include "tc_interrupt.h" +# include + +/** \internal + * Converts a given TC index to its interrupt vector index. + */ +# define _TC_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_TC##n, +#endif + +#if !defined(__DOXYGEN__) +# define _TC_GCLK_ID(n,unused) TPASTE3(TC,n,_GCLK_ID) , +# define _TC_PM_APBCMASK(n,unused) TPASTE2(PM_APBCMASK_TC,n) , + +# define TC_INST_GCLK_ID { MRECURSION(TC_INST_NUM, _TC_GCLK_ID, TC_INST_MAX_ID) } +# define TC_INST_PM_APBCMASK { MRECURSION(TC_INST_NUM, _TC_PM_APBCMASK, TC_INST_MAX_ID) } + +#endif + +/** + * \internal Find the index of given TC module instance. + * + * \param[in] TC module instance pointer + * + * \return Index of the given TC module instance. + */ +uint8_t _tc_get_inst_index( + Tc *const hw) +{ + /* List of available TC modules. */ + Tc *const tc_modules[TC_INST_NUM] = TC_INSTS; + + /* Find index for TC instance. */ + for (uint32_t i = 0; i < TC_INST_NUM; i++) { + if (hw == tc_modules[i]) { + return i; + } + } + + /* Invalid data given. */ + Assert(false); + return 0; +} + + +/** + * \brief Initializes a hardware TC module instance. + * + * Enables the clock and initializes the TC module, based on the given + * configuration values. + * + * \param[in,out] module_inst Pointer to the software module instance struct + * \param[in] hw Pointer to the TC hardware module + * \param[in] config Pointer to the TC configuration options struct + * + * \return Status of the initialization procedure. + * + * \retval STATUS_OK The module was initialized successfully + * \retval STATUS_BUSY Hardware module was busy when the + * initialization procedure was attempted + * \retval STATUS_INVALID_ARG An invalid configuration option or argument + * was supplied + * \retval STATUS_ERR_DENIED Hardware module was already enabled, or the + * hardware module is configured in 32-bit + * slave mode + */ +enum status_code tc_init( + struct tc_module *const module_inst, + Tc *const hw, + const struct tc_config *const config) +{ + /* Sanity check arguments */ + Assert(hw); + Assert(module_inst); + Assert(config); + + /* Temporary variable to hold all updates to the CTRLA + * register before they are written to it */ + uint16_t ctrla_tmp = 0; + /* Temporary variable to hold all updates to the CTRLBSET + * register before they are written to it */ + uint8_t ctrlbset_tmp = 0; + /* Temporary variable to hold all updates to the CTRLC + * register before they are written to it */ + uint8_t ctrlc_tmp = 0; + /* Temporary variable to hold TC instance number */ + uint8_t instance = _tc_get_inst_index(hw); + + /* Array of GLCK ID for different TC instances */ + uint8_t inst_gclk_id[] = TC_INST_GCLK_ID; + /* Array of PM APBC mask bit position for different TC instances */ + uint16_t inst_pm_apbmask[] = TC_INST_PM_APBCMASK; + + struct system_pinmux_config pin_config; + struct system_gclk_chan_config gclk_chan_config; + +#if TC_ASYNC == true + /* Initialize parameters */ + for (uint8_t i = 0; i < TC_CALLBACK_N; i++) { + module_inst->callback[i] = NULL; + } + module_inst->register_callback_mask = 0x00; + module_inst->enable_callback_mask = 0x00; + + /* Register this instance for callbacks*/ + _tc_instances[instance] = module_inst; +#endif + + /* Associate the given device instance with the hardware module */ + module_inst->hw = hw; + +#if SAMD09 || SAMD10 || SAMD11 || SAMHA1 || SAMHA0 + /* Check if even numbered TC modules are being configured in 32-bit + * counter size. Only odd numbered counters are allowed to be + * configured in 32-bit counter size. + */ + if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && + !((instance + TC_INSTANCE_OFFSET) & 0x01)) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } +#else + /* Check if odd numbered TC modules are being configured in 32-bit + * counter size. Only even numbered counters are allowed to be + * configured in 32-bit counter size. + */ + if ((config->counter_size == TC_COUNTER_SIZE_32BIT) && + ((instance + TC_INSTANCE_OFFSET) & 0x01)) { + Assert(false); + return STATUS_ERR_INVALID_ARG; + } +#endif + + /* Make the counter size variable in the module_inst struct reflect + * the counter size in the module + */ + module_inst->counter_size = config->counter_size; + + if (hw->COUNT8.CTRLA.reg & TC_CTRLA_SWRST) { + /* We are in the middle of a reset. Abort. */ + return STATUS_BUSY; + } + + if (hw->COUNT8.STATUS.reg & TC_STATUS_SLAVE) { + /* Module is used as a slave */ + return STATUS_ERR_DENIED; + } + + if (hw->COUNT8.CTRLA.reg & TC_CTRLA_ENABLE) { + /* Module must be disabled before initialization. Abort. */ + return STATUS_ERR_DENIED; + } + + /* Set up the TC PWM out pin for channel 0 */ + if (config->pwm_channel[0].enabled) { + system_pinmux_get_config_defaults(&pin_config); + pin_config.mux_position = config->pwm_channel[0].pin_mux; + pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; + system_pinmux_pin_set_config( + config->pwm_channel[0].pin_out, &pin_config); + } + + /* Set up the TC PWM out pin for channel 1 */ + if (config->pwm_channel[1].enabled) { + system_pinmux_get_config_defaults(&pin_config); + pin_config.mux_position = config->pwm_channel[1].pin_mux; + pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; + system_pinmux_pin_set_config( + config->pwm_channel[1].pin_out, &pin_config); + } + + /* Enable the user interface clock in the PM */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, + inst_pm_apbmask[instance]); + + /* Enable the slave counter if counter_size is 32-bit */ + if ((config->counter_size == TC_COUNTER_SIZE_32BIT)) + { + /* Enable the user interface clock in the PM */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, + inst_pm_apbmask[instance + 1]); + } + + /* Setup clock for module */ + system_gclk_chan_get_config_defaults(&gclk_chan_config); + gclk_chan_config.source_generator = config->clock_source; + system_gclk_chan_set_config(inst_gclk_id[instance], &gclk_chan_config); + system_gclk_chan_enable(inst_gclk_id[instance]); + + /* Set ctrla register */ + ctrla_tmp = + (uint32_t)config->counter_size | + (uint32_t)config->wave_generation | + (uint32_t)config->reload_action | + (uint32_t)config->clock_prescaler; + + if (config->run_in_standby) { + ctrla_tmp |= TC_CTRLA_RUNSTDBY; + } + + /* Write configuration to register */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + hw->COUNT8.CTRLA.reg = ctrla_tmp; + + /* Set ctrlb register */ + if (config->oneshot) { + ctrlbset_tmp = TC_CTRLBSET_ONESHOT; + } + + if (config->count_direction) { + ctrlbset_tmp |= TC_CTRLBSET_DIR; + } + + /* Clear old ctrlb configuration */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + hw->COUNT8.CTRLBCLR.reg = 0xFF; + + /* Check if we actually need to go into a wait state. */ + if (ctrlbset_tmp) { + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + /* Write configuration to register */ + hw->COUNT8.CTRLBSET.reg = ctrlbset_tmp; + } + + /* Set ctrlc register*/ + ctrlc_tmp = config->waveform_invert_output; + for (uint8_t i = 0; i < NUMBER_OF_COMPARE_CAPTURE_CHANNELS; i++) { + if (config->enable_capture_on_channel[i] == true) { + ctrlc_tmp |= (TC_CTRLC_CPTEN(1) << i); + } + } + + /* Write configuration to register */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + hw->COUNT8.CTRLC.reg = ctrlc_tmp; + + /* Write configuration to register */ + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Switch for TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.COUNT.reg = + config->counter_8_bit.value; + + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.PER.reg = + config->counter_8_bit.period; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.CC[0].reg = + config->counter_8_bit.compare_capture_channel[0]; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT8.CC[1].reg = + config->counter_8_bit.compare_capture_channel[1]; + + return STATUS_OK; + + case TC_COUNTER_SIZE_16BIT: + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT16.COUNT.reg + = config->counter_16_bit.value; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT16.CC[0].reg = + config->counter_16_bit.compare_capture_channel[0]; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT16.CC[1].reg = + config->counter_16_bit.compare_capture_channel[1]; + + return STATUS_OK; + + case TC_COUNTER_SIZE_32BIT: + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT32.COUNT.reg + = config->counter_32_bit.value; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT32.CC[0].reg = + config->counter_32_bit.compare_capture_channel[0]; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + hw->COUNT32.CC[1].reg = + config->counter_32_bit.compare_capture_channel[1]; + + return STATUS_OK; + } + + Assert(false); + return STATUS_ERR_INVALID_ARG; +} + +/** + * \brief Sets TC module count value. + * + * Sets the current timer count value of a initialized TC module. The + * specified TC module may be started or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] count New timer count value to set + * + * \return Status of the count update procedure. + * + * \retval STATUS_OK The timer count was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid timer counter size was specified + */ +enum status_code tc_set_count_value( + const struct tc_module *const module_inst, + const uint32_t count) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance*/ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Write to based on the TC counter_size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + tc_module->COUNT8.COUNT.reg = (uint8_t)count; + return STATUS_OK; + + case TC_COUNTER_SIZE_16BIT: + tc_module->COUNT16.COUNT.reg = (uint16_t)count; + return STATUS_OK; + + case TC_COUNTER_SIZE_32BIT: + tc_module->COUNT32.COUNT.reg = (uint32_t)count; + return STATUS_OK; + + default: + return STATUS_ERR_INVALID_ARG; + } +} + +/** + * \brief Get TC module count value. + * + * Retrieves the current count value of a TC module. The specified TC module + * may be started or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Count value of the specified TC module. + */ +uint32_t tc_get_count_value( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Read from based on the TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + return (uint32_t)tc_module->COUNT8.COUNT.reg; + + case TC_COUNTER_SIZE_16BIT: + return (uint32_t)tc_module->COUNT16.COUNT.reg; + + case TC_COUNTER_SIZE_32BIT: + return tc_module->COUNT32.COUNT.reg; + } + + Assert(false); + return 0; +} + +/** + * \brief Gets the TC module capture value. + * + * Retrieves the capture value in the indicated TC module capture channel. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the Compare Capture channel to read + * + * \return Capture value stored in the specified timer channel. + */ +uint32_t tc_get_capture_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Read out based on the TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + return tc_module->COUNT8.CC[channel_index].reg; + } + + case TC_COUNTER_SIZE_16BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + return tc_module->COUNT16.CC[channel_index].reg; + } + + case TC_COUNTER_SIZE_32BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + return tc_module->COUNT32.CC[channel_index].reg; + } + } + + Assert(false); + return 0; +} + +/** + * \brief Sets a TC module compare value. + * + * Writes a compare value to the given TC module compare/capture channel. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the compare channel to write to + * \param[in] compare New compare value to set + * + * \return Status of the compare update procedure. + * + * \retval STATUS_OK The compare value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied + */ +enum status_code tc_set_compare_value( + const struct tc_module *const module_inst, + const enum tc_compare_capture_channel channel_index, + const uint32_t compare) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + /* Read out based on the TC counter size */ + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + tc_module->COUNT8.CC[channel_index].reg = + (uint8_t)compare; + return STATUS_OK; + } + + case TC_COUNTER_SIZE_16BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + tc_module->COUNT16.CC[channel_index].reg = + (uint16_t)compare; + return STATUS_OK; + } + + case TC_COUNTER_SIZE_32BIT: + if (channel_index < + NUMBER_OF_COMPARE_CAPTURE_CHANNELS) { + tc_module->COUNT32.CC[channel_index].reg = + (uint32_t)compare; + return STATUS_OK; + } + } + + return STATUS_ERR_INVALID_ARG; +} + +/** + * \brief Resets the TC module. + * + * Resets the TC module, restoring all hardware module registers to their + * default values and disabling the module. The TC module will not be + * accessible while the reset is being performed. + * + * \note When resetting a 32-bit counter only the master TC module's instance + * structure should be passed to the function. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Status of the procedure. + * \retval STATUS_OK The module was reset successfully + * \retval STATUS_ERR_UNSUPPORTED_DEV A 32-bit slave TC module was passed to + * the function. Only use reset on master + * TC + */ +enum status_code tc_reset( + const struct tc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module hardware instance */ + TcCount8 *const tc_module = &(module_inst->hw->COUNT8); + + if (tc_module->STATUS.reg & TC_STATUS_SLAVE) { + return STATUS_ERR_UNSUPPORTED_DEV; + } + + /* Disable this module if it is running */ + if (tc_module->CTRLA.reg & TC_CTRLA_ENABLE) { + tc_disable(module_inst); + while (tc_is_syncing(module_inst)) { + /* wait while module is disabling */ + } + } + + /* Reset this TC module */ + tc_module->CTRLA.reg |= TC_CTRLA_SWRST; + + return STATUS_OK; +} + +/** + * \brief Set the timer TOP/period value. + * + * For 8-bit counter size this function writes the top value to the period + * register. + * + * For 16- and 32-bit counter size this function writes the top value to + * Capture Compare register 0. The value in this register can not be used for + * any other purpose. + * + * \note This function is designed to be used in PWM or frequency + * match modes only, when the counter is set to 16- or 32-bit counter + * size. In 8-bit counter size it will always be possible to change the + * top value even in normal mode. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] top_value New timer TOP value to set + * + * \return Status of the TOP set procedure. + * + * \retval STATUS_OK The timer TOP value was updated successfully + * \retval STATUS_ERR_INVALID_ARG The configured TC module counter size in the + * module instance is invalid + */ +enum status_code tc_set_top_value ( + const struct tc_module *const module_inst, + const uint32_t top_value) +{ + Assert(module_inst); + Assert(module_inst->hw); + Assert(top_value); + + Tc *const tc_module = module_inst->hw; + + while (tc_is_syncing(module_inst)) { + /* Wait for sync */ + } + + switch (module_inst->counter_size) { + case TC_COUNTER_SIZE_8BIT: + tc_module->COUNT8.PER.reg = (uint8_t)top_value; + return STATUS_OK; + + case TC_COUNTER_SIZE_16BIT: + tc_module->COUNT16.CC[0].reg = (uint16_t)top_value; + return STATUS_OK; + + case TC_COUNTER_SIZE_32BIT: + tc_module->COUNT32.CC[0].reg = (uint32_t)top_value; + return STATUS_OK; + + default: + Assert(false); + return STATUS_ERR_INVALID_ARG; + } +} diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h new file mode 100644 index 0000000..5acefad --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start/qs_tcc_basic.h @@ -0,0 +1,139 @@ +/** + * \file + * + * \brief SAM TCC Driver Quick Start + * + * Copyright (c) 2013-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +/** + * \page asfdoc_sam0_tcc_basic_use_case Quick Start Guide for TCC - Basic + * + * The supported board list: + * - SAM D21/R21/L21/L22/DA1/C21/HA1G16A Xplained Pro + * + * In this use case, the TCC will be used to generate a PWM signal. Here + * the pulse width is set to one quarter of the period. + * When the PWM signal connects to LED, LED will light. To see the waveform, + * you may need an oscilloscope. + * SAMHA1G16A Xpro LED is PA00 which isn't connected out, use PA04 instead, + * so we can't see LED blink but only see the waveform from oscilloscope. + * + * The PWM output is set up as follows: + * + * + * + * + * + * + * + * + * + *
Board Pin Connect to
SAM D21 Xpro PB30 LED0
SAM R21 Xpro PA19 LED0
SAM L21 Xpro PB10 LED0
SAM L22 Xpro PC27 LED0
SAM DA1 Xpro PB30 LED0
SAM C21 Xpro PA15 LED0
SAM HA1G16A Xpro PA04 NULL
+ * + * The TCC module will be set up as follows: + * - GCLK generator 0 (GCLK main) clock source + * - Use double buffering write when set top, compare, or pattern through API + * - No dithering on the counter or compare + * - Prescaler is set to 256 + * - Single Slope PWM wave generation + * - GCLK reload action + * - Don't run in standby + * - No fault or waveform extensions + * - No inversion of waveform output + * - No capture enabled + * - Count upward + * - Don't perform one-shot operations + * - No event input enabled + * - No event action + * - No event generation enabled + * - Counter starts on 0 + * - Counter top set to 0xFFFF + * - Capture compare channel 0 set to 0xFFFF/4 + * + * \section asfdoc_sam0_tcc_basic_use_case_setup Quick Start + * + * \subsection asfdoc_sam0_tcc_basic_use_case_prereq Prerequisites + * There are no prerequisites for this use case. + * + * \subsection asfdoc_sam0_tcc_basic_use_case_setup_code Code + * + * Add to the main application source file, before any functions: + * \snippet conf_quick_start.h definition_pwm + * + * Add to the main application source file, outside of any functions: + * \snippet qs_tcc_basic.c module_inst + * + * Copy-paste the following setup code to your user application: + * \snippet qs_tcc_basic.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_tcc_basic.c setup_init + * + * \subsection asfdoc_sam0_tcc_basic_use_case_setup_flow Workflow + * -# Create a module software instance structure for the TCC module to store + * the TCC driver state while it is in use. + * \snippet qs_tcc_basic.c module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Configure the TCC module. + * -# Create a TCC module configuration struct, which can be filled out to + * adjust the configuration of a physical TCC peripheral. + * \snippet qs_tcc_basic.c setup_config + * -# Initialize the TCC configuration struct with the module's default values. + * \snippet qs_tcc_basic.c setup_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Alter the TCC settings to configure the counter width, wave generation + * mode, and the compare channel 0 value. + * \snippet qs_tcc_basic.c setup_change_config + * -# Alter the TCC settings to configure the PWM output on a physical device + * pin. + * \snippet qs_tcc_basic.c setup_change_config_pwm + * -# Configure the TCC module with the desired settings. + * \snippet qs_tcc_basic.c setup_set_config + * -# Enable the TCC module to start the timer and begin PWM signal generation. + * \snippet qs_tcc_basic.c setup_enable + * + * + * \section asfdoc_sam0_tcc_basic_use_case_main Use Case + * + * \subsection asfdoc_sam0_tcc_basic_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_tcc_basic.c main + * + * \subsection asfdoc_sam0_tcc_basic_use_case_main_flow Workflow + * -# Enter an infinite loop while the PWM wave is generated via the TCC module. + * \snippet qs_tcc_basic.c main_loop + */ diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h new file mode 100644 index 0000000..b6038cc --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_buffering/qs_tcc_buffering.h @@ -0,0 +1,145 @@ +/** + * \file + * + * \brief SAM TCC Driver Double Buffering Quick Start + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +/** + * \page asfdoc_sam0_tcc_buffering_use_case Quick Start Guide for TCC - Double Buffering and Circular + * + * The supported board list: + * - SAM D21/R21/L21/L22/DA1/C21/HA1G16A Xplained Pro + * + * In this use case, the TCC will be used to generate a PWM signal. Here + * the pulse width alters in one quarter and three quarter of the period. + * When the PWM signal connects to LED, LED will light. To see the waveform, + * you may need an oscilloscope. + * SAMHA1G16A Xpro LED is PA00 which isn't connected out, use PA04 instead, + * so we can't see LED blink but only see the waveform from oscilloscope. + * + * The PWM output is set up as follows: + * + * + * + * + * + * + * + * + * + *
Board Pin Connect to
SAM D21 Xpro PB30 LED0
SAM R21 Xpro PA19 LED0
SAM L21 Xpro PB10 LED0
SAM L22 Xpro PC27 LED0
SAM DA1 Xpro PB30 LED0
SAM C21 Xpro PA15 LED0
SAM HA1G16A Xpro PA04 NULL
+ * + * The TCC module will be set up as follows: + * - GCLK generator 0 (GCLK main) clock source + * - Use double buffering write when set top, compare, or pattern through API + * - No dithering on the counter or compare + * - Prescaler is set to 1024 + * - Single Slope PWM wave generation + * - GCLK reload action + * - Don't run in standby + * - No fault or waveform extensions + * - No inversion of waveform output + * - No capture enabled + * - Count upward + * - Don't perform one-shot operations + * - No event input enabled + * - No event action + * - No event generation enabled + * - Counter starts on 0 + * - Counter top set to 8000 + * - Capture compare channel set to 8000/4 + * - Capture compare channel buffer set to 8000*3/4 + * - Circular option for compare channel is enabled so that the compare + * values keep switching on update condition + * + * \section asfdoc_sam0_tcc_buffering_use_case_setup Quick Start + * + * \subsection asfdoc_sam0_tcc_buffering_use_case_prereq Prerequisites + * There are no prerequisites for this use case. + * + * \subsection asfdoc_sam0_tcc_buffering_use_case_setup_code Code + * + * Add to the main application source file, before any functions: + * \snippet conf_quick_start_buffering.h definition_pwm + * + * Add to the main application source file, outside of any functions: + * \snippet qs_tcc_buffering.c module_inst + * + * Copy-paste the following setup code to your user application: + * \snippet qs_tcc_buffering.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_tcc_buffering.c setup_init + * + * \subsection asfdoc_sam0_tcc_buffering_use_case_setup_flow Workflow + * -# Create a module software instance structure for the TCC module to store + * the TCC driver state while it is in use. + * \snippet qs_tcc_buffering.c module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * + * -# Configure the TCC module. + * -# Create a TCC module configuration struct, which can be filled out to + * adjust the configuration of a physical TCC peripheral. + * \snippet qs_tcc_buffering.c setup_config + * -# Initialize the TCC configuration struct with the module's default values. + * \snippet qs_tcc_buffering.c setup_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * + * -# Alter the TCC settings to configure the counter width, wave generation + * mode, and the compare channel 0 value. + * \snippet qs_tcc_buffering.c setup_change_config + * -# Alter the TCC settings to configure the PWM output on a physical device + * pin. + * \snippet qs_tcc_buffering.c setup_change_config_pwm + * -# Configure the TCC module with the desired settings. + * \snippet qs_tcc_buffering.c setup_set_config + * -# Set to compare buffer value and enable circular of double buffered + * compare values. + * \snippet qs_tcc_buffering.c setup_set_buffering + * -# Enable the TCC module to start the timer and begin PWM signal generation. + * \snippet qs_tcc_buffering.c setup_enable + * + * + * \section asfdoc_sam0_tcc_buffering_use_case_main Use Case + * + * \subsection asfdoc_sam0_tcc_buffering_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_tcc_buffering.c main + * + * \subsection asfdoc_sam0_tcc_buffering_use_case_main_flow Workflow + * -# Enter an infinite loop while the PWM wave is generated via the TCC module. + * \snippet qs_tcc_buffering.c main_loop + */ diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h new file mode 100644 index 0000000..d7fc301 --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tcc/quick_start_dma/qs_tcc_dma.h @@ -0,0 +1,275 @@ +/** + * \file + * + * \brief SAM TCC Driver Quick Start with DMA + * + * Copyright (c) 2014-2018 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +/** + * \page asfdoc_sam0_tcc_dma_use_case Quick Start Guide for Using DMA with TCC + * + * The supported board list: + * - SAM D21/R21/L21/L22/DA1/C21/HA1G16A Xplained Pro + * + * In this use case, the TCC will be used to generate a PWM signal. Here + * the pulse width varies through the following values with the help of DMA + * transfer: one quarter of the period, half of the period, and three quarters + * of the period. + * The PWM output can be used to drive a LED. The waveform can also be + * viewed using an oscilloscope. + * The output signal is also fed back to another TCC channel by event system, + * the event stamps are captured and transferred to a buffer by DMA. + * SAMHA1G16A Xpro LED is PA00 which isn't connected out, use PA04 instead, + * so we can't see LED blink but only see the waveform from oscilloscope. + * + * The PWM output is set up as follows: + * + * + * + * + * + * + * + * + * + *
Board Pin Connect to
SAM D21 Xpro PB30 LED0
SAM R21 Xpro PA19 LED0
SAM L21 Xpro PB10 LED0
SAM L22 Xpro PC27 LED0
SAM DA1 Xpro PB30 LED0
SAM C21 Xpro PA15 LED0
SAM HA1G16A Xpro PA04 NULL
+ * + * The TCC module will be setup as follows: + * - GCLK generator 0 (GCLK main) clock source + * - Use double buffering write when set top, compare, or pattern through API + * - No dithering on the counter or compare + * - Prescaler is set to 1024 + * - Single Slope PWM wave generation + * - GCLK reload action + * - Don't run in standby + * - No fault or waveform extensions + * - No inversion of waveform output + * - No capture enabled + * - Count upward + * - Don't perform one-shot operations + * - Counter starts on 0 + * - Counter top set to 0x1000 + * - Channel 0 (on SAM D21 Xpro) or 3 (on SAM R21 Xpro) is set to + * compare and match value 0x1000*3/4 and generate event + * - Channel 1 is set to capture on input event + * + * The event resource of EVSYS module will be setup as follows: + * - TCC match capture channel 0 (on SAM D21 Xpro) or 3 (on SAM R21 Xpro) is + * selected as event generator + * - Event generation is synchronous, with rising edge detected + * - TCC match capture channel 1 is the event user + * + * The DMA resource of DMAC module will be setup as follows: + * - Two DMA resources are used + * - Both DMA resources use peripheral trigger + * - Both DMA resources perform beat transfer on trigger + * - Both DMA resources use beat size of 16 bits + * - Both DMA resources are configured to transfer three beats and + * then repeat again in same buffer + * - On DMA resource which controls the compare value + * - TCC0 overflow triggers DMA transfer + * - The source address increment is enabled + * - The destination address is fixed to TCC channel 0 Compare/Capture + *register + * - On DMA resource which reads the captured value + * - TCC0 capture on channel 1 triggers DMA transfer + * - The source address is fixed to TCC channel 1 Compare/Capture register + * - The destination address increment is enabled + * - The captured value is transferred to an array in SRAM + * + * \section asfdoc_sam0_tcc_dma_use_case_setup Quick Start + * + * \subsection asfdoc_sam0_tcc_dma_use_case_prereq Prerequisites + * There are no prerequisites for this use case. + * + * \subsection asfdoc_sam0_tcc_dma_use_case_setup_code Code + * + * Add to the main application source file, before any functions, according to + * the kit used: + * - SAM D21 Xplained Pro + * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_pwm + * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_feedback + * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger + * \snippet samd21_xplained_pro/conf_quick_start_dma.h definition_dma_capture_trigger + * - SAM R21 Xplained Pro + * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_pwm + * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_feedback + * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger + * \snippet samr21_xplained_pro/conf_quick_start_dma.h definition_dma_capture_trigger + * - SAM L21 Xplained Pro + * \snippet saml21_xplained_pro/conf_quick_start_dma.h definition_pwm + * \snippet saml21_xplained_pro/conf_quick_start_dma.h definition_feedback + * \snippet saml21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger + * - SAM L22 Xplained Pro + * \snippet saml22_xplained_pro/conf_quick_start_dma.h definition_pwm + * \snippet saml22_xplained_pro/conf_quick_start_dma.h definition_feedback + * \snippet saml22_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger + * - SAM DA1 Xplained Pro + * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_pwm + * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_feedback + * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger + * \snippet samda1_xplained_pro/conf_quick_start_dma.h definition_dma_capture_trigger + * - SAM C21 Xplained Pro + * \snippet samc21_xplained_pro/conf_quick_start_dma.h definition_pwm + * \snippet samc21_xplained_pro/conf_quick_start_dma.h definition_feedback + * \snippet samc21_xplained_pro/conf_quick_start_dma.h definition_dma_compare_trigger + * + * Add to the main application source file, outside of any functions: + * \snippet qs_tcc_dma.c module_inst + * \snippet qs_tcc_dma.c capture_variables + * \snippet qs_tcc_dma.c compare_variables + * + * Copy-paste the following setup code to your user application: + * \snippet qs_tcc_dma.c config_event_for_capture + * \snippet qs_tcc_dma.c config_dma_for_capture + * \snippet qs_tcc_dma.c config_dma_for_wave + * \snippet qs_tcc_dma.c setup + * + * Add to user application initialization (typically the start of \c main()): + * \snippet qs_tcc_dma.c setup_init + * + * \subsection asfdoc_sam0_tcc_dma_use_case_setup_flow Workflow + * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_tcc Configure the TCC + * -# Create a module software instance structure for the TCC module to store + * the TCC driver state while it is in use. + * \snippet qs_tcc_dma.c module_inst + * \note This should never go out of scope as long as the module is in use. + * In most cases, this should be global. + * -# Create a TCC module configuration struct, which can be filled out to + * adjust the configuration of a physical TCC peripheral. + * \snippet qs_tcc_dma.c setup_config + * -# Initialize the TCC configuration struct with the module's default values. + * \snippet qs_tcc_dma.c setup_config_defaults + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * -# Alter the TCC settings to configure the counter width, wave generation + * mode, and the compare channel 0 value. + * \snippet qs_tcc_dma.c setup_change_config + * -# Alter the TCC settings to configure the PWM output on a physical device + * pin. + * \snippet qs_tcc_dma.c setup_change_config_pwm + * -# Configure the TCC module with the desired settings. + * \snippet qs_tcc_dma.c setup_set_config + * -# Configure and enable the desired events for the TCC module. + * \snippet qs_tcc_dma.c setup_events + * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_event Configure the Event System + * Configure the EVSYS module to wire channel 0 event to channel 1. + * -# Create an event resource instance. + * \snippet qs_tcc_dma.c capture_event_resource + * \note This should never go out of scope as long as the resource is in + * use. In most cases, this should be global. + * + * -# Create an event resource configuration struct. + * \snippet qs_tcc_dma.c event_setup_1 + * -# Initialize the event resource configuration struct with default values. + * \snippet qs_tcc_dma.c event_setup_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * -# Adjust the event resource configuration to desired values. + * \snippet qs_tcc_dma.c event_setup_3 + * -# Allocate and configure the resource using the configuration structure. + * \snippet qs_tcc_dma.c event_setup_4 + * -# Attach a user to the resource. + * \snippet qs_tcc_dma.c event_setup_5 + * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_dma_capture Configure the DMA for Capture TCC Channel 1 + * Configure the DMAC module to obtain captured value from TCC channel 1. + * -# Create a DMA resource instance. + * \snippet qs_tcc_dma.c capture_dma_resource + * \note This should never go out of scope as long as the resource is in + * use. In most cases, this should be global. + * -# Create a DMA resource configuration struct. + * \snippet qs_tcc_dma.c dma_setup_1 + * -# Initialize the DMA resource configuration struct with default values. + * \snippet qs_tcc_dma.c dma_setup_2 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * -# Adjust the DMA resource configurations. + * \snippet qs_tcc_dma.c dma_setup_3 + * -# Allocate a DMA resource with the configurations. + * \snippet qs_tcc_dma.c dma_setup_4 + * -# Prepare DMA transfer descriptor. + * -# Create a DMA transfer descriptor. + * \snippet qs_tcc_dma.c capture_dma_descriptor + * \note When multiple descriptors are linked, the linked item should + * never go out of scope before it is loaded (to DMA Write-Back + * memory section). In most cases, if more than one descriptors are + * used, they should be global except the very first one. + * -# Create a DMA transfer descriptor struct. + * -# Create a DMA transfer descriptor configuration structure, which can be + * filled out to adjust the configuration of a single DMA transfer. + * \snippet qs_tcc_dma.c dma_setup_5 + * -# Initialize the DMA transfer descriptor configuration struct with + * default values. + * \snippet qs_tcc_dma.c dma_setup_6 + * \note This should always be performed before using the configuration + * struct to ensure that all values are initialized to known default + * settings. + * -# Adjust the DMA transfer descriptor configurations. + * \snippet qs_tcc_dma.c dma_setup_7 + * -# Create the DMA transfer descriptor with the given configuration. + * \snippet qs_tcc_dma.c dma_setup_8 + * -# Start DMA transfer job with prepared descriptor. + * -# Add the DMA transfer descriptor to the allocated DMA resource. + * \snippet qs_tcc_dma.c dma_setup_10 + * \note When adding multiple descriptors, the last one added is linked + * at the end of the descriptor queue. If ringed list is needed, + * just add the first descriptor again to build the circle. + * -# Start the DMA transfer job with the allocated DMA resource and + * transfer descriptor. + * \snippet qs_tcc_dma.c dma_setup_11 + * \subsubsection asfdoc_sam0_tcc_dma_use_case_setup_flow_dma_compare Configure the DMA for Compare TCC Channel 0 + * Configure the DMAC module to update TCC channel 0 compare value. + * The flow is similar to last DMA configure step for capture. + * -# Allocate and configure the DMA resource. + * \snippet qs_tcc_dma.c compare_dma_resource + * \snippet qs_tcc_dma.c config_dma_resource_for_wave + * -# Prepare DMA transfer descriptor. + * \snippet qs_tcc_dma.c compare_dma_descriptor + * \snippet qs_tcc_dma.c config_dma_descriptor_for_wave + * -# Start DMA transfer job with prepared descriptor. + * \snippet qs_tcc_dma.c config_dma_job_for_wave + * -# Enable the TCC module to start the timer and begin PWM signal generation. + * \snippet qs_tcc_dma.c setup_enable + * + * \section asfdoc_sam0_tcc_dma_use_case_main Use Case + * + * \subsection asfdoc_sam0_tcc_dma_use_case_main_code Code + * Copy-paste the following code to your user application: + * \snippet qs_tcc_dma.c main + * + * \subsection asfdoc_sam0_tcc_dma_use_case_main_flow Workflow + * -# Enter an infinite loop while the PWM wave is generated via the TCC module. + * \snippet qs_tcc_dma.c main_loop + */ diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c new file mode 100644 index 0000000..feed971 --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.c @@ -0,0 +1,1598 @@ +/** + * \file + * + * \brief SAM TCC - Timer Counter for Control Applications Driver + * + * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#include "tcc.h" + +#if TCC_ASYNC == true +# include "tcc_callback.h" +# include + +/** \internal + * Converts a given TCC index to its interrupt vector index. + */ +# define _TCC_INTERRUPT_VECT_NUM(n, unused) \ + SYSTEM_INTERRUPT_MODULE_TCC##n, +#endif + +#define _SIZE_MAX(size) ((size==32u) ? 0xFFFFFFFF : ( \ + (1u << size) - 1)) + +#define _SIZE_MAX_WITH_DITHER 0x03FFFFFF + +/* Extension support mapping bits */ +#define _TCC_DITHERING_B 16u +#define _TCC_PG_B 8u +#define _TCC_SWAP_B 4u +#define _TCC_DTI_B 2u +#define _TCC_OTMX_B 1u + +#if !defined(__DOXYGEN__) + +# define _TCC_GCLK_ID(n,unused) TPASTE3(TCC,n,_GCLK_ID), +# if (SAML21) || (SAML22) || (SAMC20) || (SAMC21) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) +# define _TCC_APBCMASK(n,unused) TPASTE2(MCLK_APBCMASK_TCC,n), +# else +# define _TCC_APBCMASK(n,unused) TPASTE2(PM_APBCMASK_TCC,n), +# endif + +# define _TCC_SIZE(n,unused) TPASTE3(TCC,n,_SIZE), +# define _TCC_MAX(n,unused) _SIZE_MAX(TPASTE3(TCC,n,_SIZE)), +# define _TCC_EXT(n,unused) TPASTE3(TCC,n,_EXT), +# define _TCC_CC_NUM(n,unused) min(TPASTE3(TCC,n,_CC_NUM),TCC_NUM_CHANNELS), +# define _TCC_OW_NUM(n,unused) min(TPASTE3(TCC,n,_OW_NUM),TCC_NUM_WAVE_OUTPUTS), + +# define TCC_GCLK_IDS { MREPEAT(TCC_INST_NUM, _TCC_GCLK_ID, 0) } +# define TCC_APBCMASKS { MREPEAT(TCC_INST_NUM, _TCC_APBCMASK, 0) } + +# define TCC_SIZES { MREPEAT(TCC_INST_NUM, _TCC_SIZE, 0) } +# define TCC_MAXS { MREPEAT(TCC_INST_NUM, _TCC_MAX, 0) } +# define TCC_EXTS { MREPEAT(TCC_INST_NUM, _TCC_EXT, 0) } +# define TCC_CC_NUMS { MREPEAT(TCC_INST_NUM, _TCC_CC_NUM, 0) } +# define TCC_OW_NUMS { MREPEAT(TCC_INST_NUM, _TCC_OW_NUM, 0) } + +#endif + +/* List of available TCC modules. */ +const Tcc *const tcc_modules[TCC_INST_NUM] = TCC_INSTS; + +/* List of TCC GCLK IDs */ +const uint8_t _tcc_gclk_ids[TCC_INST_NUM] = TCC_GCLK_IDS; + +/* List of TCC APBC Masks */ +const uint32_t _tcc_apbcmasks[TCC_INST_NUM] = TCC_APBCMASKS; + +/* List of extension support of TCC modules. */ +const uint8_t _tcc_exts[TCC_INST_NUM] = TCC_EXTS; + +/* List of sizes support of TCC modules. */ +const uint8_t _tcc_sizes[TCC_INST_NUM] = TCC_SIZES; + +/* List of maximumvalues supported of TCC modules. */ +const uint32_t _tcc_maxs[TCC_INST_NUM] = TCC_MAXS; + +/* List of available channel number of TCC modules. */ +const uint8_t _tcc_cc_nums[TCC_INST_NUM] = TCC_CC_NUMS; + +/* List of available output number of TCC modules. */ +const uint8_t _tcc_ow_nums[TCC_INST_NUM] = TCC_OW_NUMS; + +/** + * \internal Find the index of the given TCC module instance. + * + * \param[in] The TCC module instance pointer + * + * \return Index of the given TCC module instance. + */ +uint8_t _tcc_get_inst_index( + Tcc *const hw) +{ + /* Find index for TCC instance. */ + for (uint32_t i = 0; i < TCC_INST_NUM; i++) { + if (hw == tcc_modules[i]) { + return i; + } + } + + /* Invalid data given. */ + Assert(false); + return 0; +} + +/** + * \brief Initializes config with predefined default values. + * + * This function will initialize a given TCC configuration structure to + * a set of known default values. This function should be called on + * any new instance of the configuration structures before being + * modified by the user application. + * + * The default configuration is as follows: + * \li Don't run in standby + * \li When setting top, compare, or pattern by API, do double buffering write + * \li The base timer/counter configurations: + * - GCLK generator 0 clock source + * - No prescaler + * - GCLK reload action + * - Count upward + * - Don't perform one-shot operations + * - Counter starts on 0 + * - Period/top value set to maximum + * \li The match/capture configurations: + * - All Capture compare channel value set to 0 + * - No capture enabled (all channels use compare function) + * - Normal frequency wave generation + * - Waveform generation polarity set to 0 + * - Don't perform ramp on waveform + * \li The waveform extension configurations: + * - No recoverable fault is enabled, fault actions are disabled, filter + * is set to 0 + * - No non-recoverable fault state output is enabled and filter is 0 + * - No inversion of waveform output + * \li No channel output enabled + * \li No PWM pin output enabled + * \li Pin and MUX configuration not set + * + * \param[out] config Pointer to a TCC module configuration structure to set + * \param[in] hw Pointer to the TCC hardware module + * + */ +void tcc_get_config_defaults( + struct tcc_config *const config, + Tcc *const hw) +{ + /* TCC instance index */ + uint8_t module_index = _tcc_get_inst_index(hw); + + /* Base counter defaults */ + config->counter.count = 0; + + config->counter.period = _tcc_maxs[module_index]; + + config->counter.clock_source = GCLK_GENERATOR_0; + config->counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1; + config->counter.reload_action = TCC_RELOAD_ACTION_GCLK; + + config->counter.direction = TCC_COUNT_DIRECTION_UP; + config->counter.oneshot = false; + +#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER + config->counter.dma_trigger_mode = TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_CONTINUE; +#endif + + /* Match/Capture defaults */ +# define _TCC_CHANNEL_MATCH_VALUE_INIT(n, value) \ + config->compare.match[n] = value; + MREPEAT(TCC_NUM_CHANNELS, + _TCC_CHANNEL_MATCH_VALUE_INIT, 0) +# undef _TCC_CHANNEL_MATCH_VALUE_INIT + + /* Wave polarity defaults */ +# define _TCC_CHANNEL_WAVE_POLARITY_INIT(n, value) \ + config->compare.wave_polarity[n] = value; + MREPEAT(TCC_NUM_CHANNELS, + _TCC_CHANNEL_WAVE_POLARITY_INIT, TCC_WAVE_POLARITY_0) +# undef _TCC_CHANNEL_WAVE_POLARITY_INIT + + config->compare.wave_generation = TCC_WAVE_GENERATION_NORMAL_FREQ; + config->compare.wave_ramp = TCC_RAMP_RAMP1; + +# define _TCC_CHANNEL_FUNCTION_INIT(n, value) \ + config->compare.channel_function[n] = value; + MREPEAT(TCC_NUM_CHANNELS, + _TCC_CHANNEL_FUNCTION_INIT, TCC_CHANNEL_FUNCTION_COMPARE) +# undef _TCC_CHANNEL_FUNCTION_INIT + + /* Recoverable fault defaults */ +# define _TCC_FAULT_FUNCTION_INIT(n, dummy) \ + config->wave_ext.recoverable_fault[n].filter_value = 0; \ + config->wave_ext.recoverable_fault[n].blanking_cycles = 0; \ + config->wave_ext.recoverable_fault[n].restart = false; \ + config->wave_ext.recoverable_fault[n].keep = false; \ + config->wave_ext.recoverable_fault[n].qualification = false; \ + config->wave_ext.recoverable_fault[n].source = TCC_FAULT_SOURCE_DISABLE; \ + config->wave_ext.recoverable_fault[n].blanking = TCC_FAULT_BLANKING_DISABLE; \ + config->wave_ext.recoverable_fault[n].halt_action = TCC_FAULT_HALT_ACTION_DISABLE; \ + config->wave_ext.recoverable_fault[n].capture_action = TCC_FAULT_CAPTURE_DISABLE; \ + config->wave_ext.recoverable_fault[n].capture_channel = TCC_FAULT_CAPTURE_CHANNEL_0; + MREPEAT(TCC_NUM_FAULTS, _TCC_FAULT_FUNCTION_INIT, 0) +# undef _TCC_FAULT_FUNCTION_INIT + + /* Non-recoverable fault defaults */ +# define _TCC_NRF_FUNCTION_INIT(n, dummy) \ + config->wave_ext.non_recoverable_fault[n].filter_value = 0; \ + config->wave_ext.non_recoverable_fault[n].output = TCC_FAULT_STATE_OUTPUT_OFF; + MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_NRF_FUNCTION_INIT, 0) +# undef _TCC_NRF_FUNCTION_INIT + + /* Output inversion defaults */ +# define _TCC_OUT_INVERT_INIT(n, value) \ + config->wave_ext.invert[n] = value; + MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_OUT_INVERT_INIT, false) +# undef _TCC_OUT_INVERT_INIT + +# define _TCC_CHANNEL_OUT_PIN_INIT(n, dummy) \ + config->pins.enable_wave_out_pin[n] = false;\ + config->pins.wave_out_pin[TCC_WAVE_OUTPUT_##n] = 0; \ + config->pins.wave_out_pin_mux[TCC_WAVE_OUTPUT_##n] = 0; + MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_CHANNEL_OUT_PIN_INIT, 0) +# undef _TCC_CHANNEL_OUT_PIN_INIT + + config->double_buffering_enabled = true; + config->run_in_standby = false; +} + + +/** + * \brief Build CTRLA register value from configuration. + * + * \param[in] module_index The software module instance index + * \param[in] config Pointer to the TCC configuration options struct + * \param[out] value_buffer Pointer to the buffer to fill with built value + * + * \return Configuration validation status. + * + * \retval STATUS_OK Configuration values are good and register + * value built and save to buffer + * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: + * assigned dither mode is invalid for module; + * used capture channel is invalid for module + */ +static inline enum status_code _tcc_build_ctrla( + const uint8_t module_index, + const struct tcc_config *const config, + uint32_t *value_buffer) +{ + uint32_t ctrla = 0; + + int i; + for (i = 0; i < TCC_NUM_CHANNELS; i ++) { + if (config->capture.channel_function[i] == + TCC_CHANNEL_FUNCTION_CAPTURE) { + + if (i > _tcc_cc_nums[module_index]) { + /* Channel not supported */ + return STATUS_ERR_INVALID_ARG; + } + ctrla |= (TCC_CTRLA_CPTEN0 << i); + } + } + + if (config->run_in_standby) { + ctrla |= TCC_CTRLA_RUNSTDBY; + } + ctrla |= config->counter.reload_action << TCC_CTRLA_PRESCSYNC_Pos; + ctrla |= config->counter.clock_prescaler << TCC_CTRLA_PRESCALER_Pos; + + *value_buffer = ctrla; + return STATUS_OK; +} + +/** + * \brief Build CTRLB register value from configuration. + * + * \param[in] module_index The software module instance index + * \param[in] config Pointer to the TCC configuration options struct + * \param[out] value_buffer Pointer to the buffer to fill with built value + */ +static inline void _tcc_build_ctrlb( + const uint8_t module_index, + const struct tcc_config *const config, + uint8_t *value_buffer) +{ + uint8_t ctrlb = 0; + + if (config->counter.oneshot) { + ctrlb |= TCC_CTRLBSET_ONESHOT; + } + if (config->counter.direction == TCC_COUNT_DIRECTION_DOWN) { + ctrlb |= TCC_CTRLBSET_DIR; + } + + *value_buffer = ctrlb; +} + +/** + * \brief Build FAULTs register values from configuration. + * + * \param[in] module_index The software module instance index + * \param[in] config Pointer to the TCC configuration options struct + * \param[out] value_buffer Pointer to the buffer to fill with built values + * + * \retval STATUS_OK Configuration values are good and register + * value built and save to buffer + * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned fault + * capture channel is invalid; assigned filter + * value is invalid + */ +static inline enum status_code _tcc_build_faults( + const uint8_t module_index, + const struct tcc_config *const config, + uint32_t *value_buffer) +{ + struct tcc_recoverable_fault_config *cfg; + uint8_t cc_num = _tcc_cc_nums[module_index]; + uint32_t fault; + int i; + for (i = 0; i < TCC_NUM_FAULTS; i ++) { + cfg = (struct tcc_recoverable_fault_config *) + &config->wave_ext.recoverable_fault[i]; + if (cfg->capture_channel >= cc_num) { + return STATUS_ERR_INVALID_ARG; + } + if (cfg->filter_value > 0xF) { + return STATUS_ERR_INVALID_ARG; + } + fault = TCC_FCTRLA_FILTERVAL(cfg->filter_value) + | TCC_FCTRLA_BLANKVAL(cfg->blanking_cycles) + | (cfg->restart ? TCC_FCTRLA_RESTART : 0) + | (cfg->keep ? TCC_FCTRLA_KEEP : 0) + | (cfg->qualification ? TCC_FCTRLA_QUAL : 0) + | TCC_FCTRLA_SRC(cfg->source) + | TCC_FCTRLA_BLANK(cfg->blanking) + | TCC_FCTRLA_HALT(cfg->halt_action) + | TCC_FCTRLA_CAPTURE(cfg->capture_action) + | TCC_FCTRLA_CHSEL(cfg->capture_channel); + value_buffer[i] = fault; + } + return STATUS_OK; +} + +/** + * \brief Build DRVCTRL register values from configuration. + * + * \param[in] module_index The software module instance index + * \param[in] config Pointer to the TCC configuration options struct + * \param[out] value_buffer Pointer to the buffer to fill with built value + * + * \retval STATUS_OK Configuration values are good and register + * value built and save to buffer + * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned output line + * is invalid; filter value is invalid + */ +static inline enum status_code _tcc_build_drvctrl( + const uint8_t module_index, + const struct tcc_config *const config, + uint32_t *value_buffer) +{ + uint32_t i; + uint8_t ow_num = _tcc_ow_nums[module_index]; + uint32_t drvctrl; + + drvctrl = 0; + + for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) { + if (config->wave_ext.invert[i]) { + if (i >= ow_num) { + return STATUS_ERR_INVALID_ARG; + } + drvctrl |= (TCC_DRVCTRL_INVEN0 << i); + } + if (config->wave_ext.non_recoverable_fault[i].output != + TCC_FAULT_STATE_OUTPUT_OFF) { + if (i >= ow_num) { + return STATUS_ERR_INVALID_ARG; + } + if (config->wave_ext.non_recoverable_fault[i].output == + TCC_FAULT_STATE_OUTPUT_1) { + drvctrl |= (TCC_DRVCTRL_NRE0 | TCC_DRVCTRL_NRV0) << i; + } else { + drvctrl |= (TCC_DRVCTRL_NRE0) << i; + } + } + } + *value_buffer = drvctrl; + return STATUS_OK; +} + +/** + * \brief Build WAVE & WAVEB register values from configuration. + * + * \param[in] module_index The software module instance index + * \param[in] config Pointer to the TCC configuration options struct + * \param[out] value_buffer Pointer to the buffer to fill with built value + * + * \retval STATUS_OK Configuration values are good and register + * value built and save to buffer + * \retval STATUS_ERR_INVALID_ARG Invalid parameter found: assigned output line + * is invalid; circular and double buffering + * conflict; assigned function not supported by + * module + */ +static inline enum status_code _tcc_build_waves( + const uint8_t module_index, + const struct tcc_config *const config, + uint32_t *value_buffer) +{ + int n; + + uint8_t cc_num = _tcc_cc_nums[module_index]; + struct tcc_match_wave_config const *wav_cfg = &config->compare; + + uint32_t wave; + + wave = TCC_WAVE_RAMP(wav_cfg->wave_ramp) | + TCC_WAVE_WAVEGEN(wav_cfg->wave_generation); + + for (n = 0; n < TCC_NUM_CHANNELS; n++) { + if (wav_cfg->wave_polarity[n]) { + if (n >= cc_num) { + return STATUS_ERR_INVALID_ARG; + } + wave |= (TCC_WAVE_POL0 << n); + } + } + + value_buffer[0] = wave; + + return STATUS_OK; +} + +/** + * \brief Initializes a hardware TCC module instance. + * + * Enables the clock and initializes the given TCC module, based on the given + * configuration values. + * + * \param[in,out] module_inst Pointer to the software module instance struct + * \param[in] hw Pointer to the TCC hardware module + * \param[in] config Pointer to the TCC configuration options struct + * + * \return Status of the initialization procedure. + * + * \retval STATUS_OK The module was initialized successfully + * \retval STATUS_BUSY The hardware module was busy when the + * initialization procedure was attempted + * \retval STATUS_INVALID_ARG An invalid configuration option or argument + * was supplied + * \retval STATUS_ERR_DENIED The hardware module was already enabled + */ +enum status_code tcc_init( + struct tcc_module *const module_inst, + Tcc *const hw, + const struct tcc_config *const config) +{ + int i; + + /* Sanity check arguments */ + Assert(hw); + Assert(module_inst); + Assert(config); + + /* TCC instance index */ + uint8_t module_index = _tcc_get_inst_index(hw); + + /* Enable the user interface clock for TCC */ + system_apb_clock_set_mask(SYSTEM_CLOCK_APB_APBC, + _tcc_apbcmasks[module_index]); + + /* Check if it's enabled. */ + if (hw->CTRLA.reg & TCC_CTRLA_ENABLE) { + return STATUS_ERR_DENIED; + } + /* Check if it's resetting */ + if (hw->CTRLA.reg & TCC_CTRLA_SWRST) { + return STATUS_ERR_DENIED; + } + + enum status_code status; + + /* Check COUNT, PER, CCx */ + uint32_t count_max = _tcc_maxs[module_index]; + + /* Check all counter values */ + if ((config->counter.count > count_max) + || (config->counter.period > count_max) + ) { + return STATUS_ERR_INVALID_ARG; + } + + /* Check all channel values */ + for (i = 0; i < TCC_NUM_CHANNELS; i ++) { + if ((config->compare.match[i] > count_max) + ) { + return STATUS_ERR_INVALID_ARG; + } + } + + /* Check all outputs */ + for (i = 0; i < TCC_NUM_WAVE_OUTPUTS; i ++) { + if (!config->pins.enable_wave_out_pin[i]) { + continue; + } + /* Output line is not supported */ + if (i >= _tcc_ow_nums[module_index]) { + return STATUS_ERR_INVALID_ARG; + } + } + + /* CTRLA settings */ + uint32_t ctrla = 0; + status = _tcc_build_ctrla(module_index, config, &ctrla); + if (STATUS_OK != status) { + return status; + } + + /* CTRLB settings */ + uint8_t ctrlb; + _tcc_build_ctrlb(module_index, config, &ctrlb); + + /* FAULTs settings */ + uint32_t faults[TCC_NUM_FAULTS]; + + status = _tcc_build_faults(module_index, config, faults); + if (STATUS_OK != status) { + return status; + } + + /* DRVCTRL */ + uint32_t drvctrl = 0; + + status = _tcc_build_drvctrl(module_index, config, &drvctrl); + if (STATUS_OK != status) { + return status; + } + + /* WAVE */ + uint32_t waves[1]; + + status = _tcc_build_waves(module_index, config, waves); + if (STATUS_OK != status) { + return status; + } + + /* Initialize module */ +#if TCC_ASYNC + /* Initialize parameters */ + for (i = 0; i < TCC_CALLBACK_N; i ++) { + module_inst->callback[i] = NULL; + } + module_inst->register_callback_mask = 0; + module_inst->enable_callback_mask = 0; + _tcc_instances[module_index] = module_inst; +#endif + + module_inst->hw = hw; + + module_inst->double_buffering_enabled = config->double_buffering_enabled; + + /* Setup clock for module */ + struct system_gclk_chan_config gclk_chan_config; + system_gclk_chan_get_config_defaults(&gclk_chan_config); + gclk_chan_config.source_generator = config->counter.clock_source; + system_gclk_chan_set_config(_tcc_gclk_ids[module_index], &gclk_chan_config); + system_gclk_chan_enable(_tcc_gclk_ids[module_index]); + + /* Initialize pins */ + struct system_pinmux_config pin_config; + for (i = 0; i < _tcc_ow_nums[module_index]; i ++) { + if (!config->pins.enable_wave_out_pin[i]) { + continue; + } + + system_pinmux_get_config_defaults(&pin_config); + pin_config.mux_position = config->pins.wave_out_pin_mux[i]; + pin_config.direction = SYSTEM_PINMUX_PIN_DIR_OUTPUT; + system_pinmux_pin_set_config( + config->pins.wave_out_pin[i], &pin_config); + } + + /* Write to registers */ + + hw->CTRLA.reg = ctrla; + while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + + hw->CTRLBCLR.reg = 0xFF; + while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + hw->CTRLBSET.reg = ctrlb; + + hw->FCTRLA.reg = faults[0]; + hw->FCTRLB.reg = faults[1]; + + hw->DRVCTRL.reg = drvctrl; + +#if (!SAML21) && (!SAMC20) && (!SAMC21) && (!SAML22) && (!SAMR30) && (!SAMR34) && (!SAMR35) && !(WLR089) + while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_WAVE | TCC_SYNCBUSY_WAVEB)) { + /* Wait for sync */ + } +#endif + hw->WAVE.reg = waves[0]; + + while (hw->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) { + /* Wait for sync */ + } + hw->COUNT.reg = config->counter.count; + +#if (!SAML21) && (!SAMC20) && (!SAMC21) && (!SAML22) && (!SAMR30) && (!SAMR34) && (!SAMR35) && !(WLR089) + while (hw->SYNCBUSY.reg & (TCC_SYNCBUSY_PER | TCC_SYNCBUSY_PERB)) { + /* Wait for sync */ + } +#endif + hw->PER.reg = (config->counter.period); + + for (i = 0; i < _tcc_cc_nums[module_index]; i ++) { +#if (!SAML21) && (!SAMC20) && (!SAMC21) && (!SAML22) && (!SAMR30) && (!SAMR34) && (!SAMR35) && !(WLR089) + while (hw->SYNCBUSY.reg & ( + (TCC_SYNCBUSY_CC0 | TCC_SYNCBUSY_CCB0) << i)) { + /* Wait for sync */ + } +#endif + hw->CC[i].reg = (config->compare.match[i]); + } + + return STATUS_OK; +} + + +/** + * \brief Enables the TCC module event input or output. + * + * Enables one or more input or output events to or from the TCC module. + * See \ref tcc_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] events Struct containing flags of events to enable or + * configure + * + * \return Status of the events setup procedure. + * + * \retval STATUS_OK The module was initialized successfully + * \retval STATUS_INVALID_ARG An invalid configuration option or argument + * was supplied + */ +enum status_code tcc_enable_events( + struct tcc_module *const module_inst, + struct tcc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Tcc *const tcc_module = module_inst->hw; + + /* Check if it's enabled or resetting. */ + if (tcc_module->CTRLA.reg & (TCC_CTRLA_ENABLE | TCC_CTRLA_SWRST)) { + return STATUS_ERR_DENIED; + } + + uint32_t evctrl = tcc_module->EVCTRL.reg; + + /* Setup event output action */ + if (events->output_config.modify_generation_selection) { + evctrl &= ~ TCC_EVCTRL_CNTSEL_Msk; + switch(events->output_config.generation_selection) { + case TCC_EVENT_GENERATION_SELECTION_START: + evctrl |= TCC_EVCTRL_CNTSEL_START; + break; + case TCC_EVENT_GENERATION_SELECTION_END: + evctrl |= TCC_EVCTRL_CNTSEL_END; + break; + case TCC_EVENT_GENERATION_SELECTION_BETWEEN: + evctrl |= TCC_EVCTRL_CNTSEL_BETWEEN; + break; + case TCC_EVENT_GENERATION_SELECTION_BOUNDARY: + evctrl |= TCC_EVCTRL_CNTSEL_BOUNDARY; + break; + default: + Assert(false); + /* Wrong configuration */ + return STATUS_ERR_INVALID_ARG; + } + } + /* Setup input event0 */ + if (events->on_input_event_perform_action[0]) { + evctrl |= TCC_EVCTRL_TCEI0; + } + if (events->input_config[0].invert) { + evctrl |= TCC_EVCTRL_TCINV0; + } + if (events->input_config[0].modify_action) { + evctrl &= ~ TCC_EVCTRL_EVACT0_Msk; + switch(events->input_config[0].action) { + case TCC_EVENT0_ACTION_OFF: + evctrl |= TCC_EVCTRL_EVACT0_OFF; + break; + case TCC_EVENT0_ACTION_RETRIGGER: + evctrl |= TCC_EVCTRL_EVACT0_RETRIGGER; + break; + case TCC_EVENT0_ACTION_COUNT_EVENT: + evctrl |= TCC_EVCTRL_EVACT0_COUNTEV; + break; + case TCC_EVENT0_ACTION_START: + evctrl |= TCC_EVCTRL_EVACT0_START; + break; + case TCC_EVENT0_ACTION_INCREMENT: + evctrl |= TCC_EVCTRL_EVACT0_INC; + break; + case TCC_EVENT0_ACTION_COUNT_DURING_ACTIVE: + evctrl |= TCC_EVCTRL_EVACT0_COUNT; + break; + case TCC_EVENT0_ACTION_NON_RECOVERABLE_FAULT: + evctrl |= TCC_EVCTRL_EVACT0_FAULT; + break; + default: + Assert(false); + /* Wrong configuration */ + return STATUS_ERR_INVALID_ARG; + } + } + /* Setup input event1 */ + if (events->on_input_event_perform_action[1]) { + evctrl |= TCC_EVCTRL_TCEI1; + } + if (events->input_config[1].invert) { + evctrl |= TCC_EVCTRL_TCINV1; + } + if (events->input_config[1].modify_action) { + evctrl &= ~ TCC_EVCTRL_EVACT1_Msk; + switch(events->input_config[1].action) { + case TCC_EVENT1_ACTION_OFF: + evctrl |= TCC_EVCTRL_EVACT1_OFF; + break; + case TCC_EVENT1_ACTION_RETRIGGER: + evctrl |= TCC_EVCTRL_EVACT1_RETRIGGER; + break; + case TCC_EVENT1_ACTION_DIR_CONTROL: + evctrl |= TCC_EVCTRL_EVACT1_DIR; + break; + case TCC_EVENT1_ACTION_STOP: + evctrl |= TCC_EVCTRL_EVACT1_STOP; + break; + case TCC_EVENT1_ACTION_DECREMENT: + evctrl |= TCC_EVCTRL_EVACT1_DEC; + break; + case TCC_EVENT1_ACTION_PERIOD_PULSE_WIDTH_CAPTURE: + evctrl |= TCC_EVCTRL_EVACT1_PPW | + TCC_EVCTRL_MCEI0 | TCC_EVCTRL_MCEI1; + break; + case TCC_EVENT1_ACTION_PULSE_WIDTH_PERIOD_CAPTURE: + evctrl |= TCC_EVCTRL_EVACT1_PWP | + TCC_EVCTRL_MCEI0 | TCC_EVCTRL_MCEI1; + break; + case TCC_EVENT1_ACTION_NON_RECOVERABLE_FAULT: + evctrl |= TCC_EVCTRL_EVACT1_FAULT; + break; + default: + Assert(false); + /* Wrong configuration */ + return STATUS_ERR_INVALID_ARG; + } + } + uint32_t ch; + for(ch = 0; ch < TCC_NUM_CHANNELS; ch ++) { + if (events->generate_event_on_channel[ch]) { + evctrl |= (TCC_EVCTRL_MCEO(1) << ch); + } + if (events->on_event_perform_channel_action[ch]) { + evctrl |= (TCC_EVCTRL_MCEI(1) << ch); + } + } + if (events->generate_event_on_counter_overflow) { + evctrl |= TCC_EVCTRL_OVFEO; + } + if (events->generate_event_on_counter_retrigger) { + evctrl |= TCC_EVCTRL_TRGEO; + } + if (events->generate_event_on_counter_event) { + evctrl |= TCC_EVCTRL_CNTEO; + } + + tcc_module->EVCTRL.reg = evctrl; + + return STATUS_OK; +} + +/** + * \brief Disables the event input or output of a TCC instance. + * + * Disables one or more input or output events for the given TCC module. + * See \ref tcc_events for a list of events this module supports. + * + * \note Events cannot be altered while the module is enabled. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] events Struct containing flags of events to disable + */ +void tcc_disable_events( + struct tcc_module *const module_inst, + struct tcc_events *const events) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + Assert(events); + + Tcc *const tcc_module = module_inst->hw; + + /* Check if it's enabled or resetting. */ + if (tcc_module->CTRLA.reg & (TCC_CTRLA_ENABLE | TCC_CTRLA_SWRST)) { + return; + } + + + uint32_t evctrl = 0; + uint32_t ch; + for(ch = 0; ch < TCC_NUM_CHANNELS; ch ++) { + if (events->generate_event_on_channel[ch]) { + evctrl |= (TCC_EVCTRL_MCEO(1) << ch); + } + if (events->on_event_perform_channel_action[ch]) { + evctrl |= (TCC_EVCTRL_MCEI(1) << ch); + } + } + if (events->generate_event_on_counter_overflow) { + evctrl |= TCC_EVCTRL_OVFEO; + } + if (events->generate_event_on_counter_retrigger) { + evctrl |= TCC_EVCTRL_TRGEO; + } + if (events->generate_event_on_counter_event) { + evctrl |= TCC_EVCTRL_CNTEO; + } + if (events->on_input_event_perform_action[0]) { + evctrl |= TCC_EVCTRL_TCEI0; + } + if (events->on_input_event_perform_action[1]) { + evctrl |= TCC_EVCTRL_TCEI1; + } + if (events->input_config[0].invert) { + evctrl |= TCC_EVCTRL_TCINV0; + } + if (events->input_config[1].invert) { + evctrl |= TCC_EVCTRL_TCINV1; + } + + tcc_module->EVCTRL.reg &= ~evctrl; +} + + + +/** + * \brief Sets count value for the given TCC module. + * + * Sets the timer count value of an initialized TCC module. The + * specified TCC module can remain running or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] count New timer count value to set + * + * \return Status which indicates whether the new value is set. + * + * \retval STATUS_OK The timer count was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid timer counter size was specified + */ +enum status_code tcc_set_count_value( + const struct tcc_module *const module_inst, + const uint32_t count) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance*/ + Tcc *const tcc_module = module_inst->hw; + /* Get a index of the module */ + uint8_t module_index = _tcc_get_inst_index(tcc_module); + + uint32_t max_count = _tcc_maxs[module_index]; + + if (count > max_count) { + return STATUS_ERR_INVALID_ARG; + } + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) { + /* Wait for sync */ + } + + /* Write to based on the TCC dithering */ + tcc_module->COUNT.reg = (count); + + return STATUS_OK; +} + +/** + * \brief Get count value of the given TCC module. + * + * Retrieves the current count value of a TCC module. The specified TCC module + * can remain running or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Count value of the specified TCC module. + */ +uint32_t tcc_get_count_value( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance*/ + Tcc *const tcc_module = module_inst->hw; + uint32_t last_cmd; + + /* Wait last command done */ + do { + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk; + if (TCC_CTRLBSET_CMD_NONE == last_cmd) { + /* Issue read command and break */ + tcc_module->CTRLBSET.bit.CMD = TCC_CTRLBSET_CMD_READSYNC_Val; + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + break; + } else if (TCC_CTRLBSET_CMD_READSYNC == last_cmd) { + /* Command have been issued */ + break; + } + } while (1); + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_COUNT) { + /* Wait for sync */ + } + return (tcc_module->COUNT.reg); +} + + + +/** + * \brief Gets the TCC module capture value. + * + * Retrieves the capture value in the indicated TCC module capture channel. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the Compare Capture channel to read + * + * \return Capture value stored in the specified timer channel. + */ +uint32_t tcc_get_capture_value( + const struct tcc_module *const module_inst, + const enum tcc_match_capture_channel channel_index) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + Assert(channel_index < _tcc_cc_nums[_tcc_get_inst_index(module_inst->hw)]); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + while(tcc_module->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << channel_index)) { + /* Sync wait */ + } + + return tcc_module->CC[channel_index].reg; +} + +/** + * \internal + * \brief Sets a TCC module compare value/buffer. + * + * Writes a compare value to the given TCC module compare/capture channel or + * buffer one. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the compare channel to write to + * \param[in] compare New compare value/buffer value to set + * \param[in] double_buffering_enabled Set to \c true to write to CCBx + * + * \return Status of the compare update procedure. + * + * \retval STATUS_OK The compare value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or + * compare value exceed resolution + */ +static enum status_code _tcc_set_compare_value( + const struct tcc_module *const module_inst, + const enum tcc_match_capture_channel channel_index, + const uint32_t compare, + const bool double_buffering_enabled) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + /* Get a index of the module */ + uint8_t module_index = _tcc_get_inst_index(tcc_module); + + /* Check index */ + if (channel_index >= _tcc_cc_nums[module_index]) { + return STATUS_ERR_INVALID_ARG; + } + + uint32_t max_count = _tcc_maxs[module_index]; + + /* Check compare value */ + if (compare > max_count) { + return STATUS_ERR_INVALID_ARG; + } + + if (double_buffering_enabled) { +#if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + tcc_module->CCBUF[channel_index].reg = compare; +#else + while(tcc_module->STATUS.reg & + (TCC_STATUS_CCBV0 << channel_index)) { + /* Valid check */ + } + while(tcc_module->SYNCBUSY.reg & + (TCC_SYNCBUSY_CCB0 << channel_index)) { + /* Sync wait */ + } + tcc_module->CCB[channel_index].reg = compare; +#endif + } else { + while(tcc_module->SYNCBUSY.reg & (TCC_SYNCBUSY_CC0 << channel_index)) { + /* Sync wait */ + } + tcc_module->CC[channel_index].reg = compare; + } + return STATUS_OK; +} + + +/** + * \brief Sets a TCC module compare value. + * + * Writes a compare value to the given TCC module compare/capture channel. + * + * If double buffering is enabled it always write to the buffer + * register. The value will then be updated immediately by calling + * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit + * is cleared and the UPDATE condition happen. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the compare channel to write to + * \param[in] compare New compare value to set + * + * \return Status of the compare update procedure. + * + * \retval STATUS_OK The compare value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or + * compare value exceed resolution + */ +enum status_code tcc_set_compare_value( + const struct tcc_module *const module_inst, + const enum tcc_match_capture_channel channel_index, + const uint32_t compare) +{ + /* Sanity check arguments */ + Assert(module_inst); + + return _tcc_set_compare_value(module_inst, channel_index, compare, + module_inst->double_buffering_enabled); +} + +/** + * \brief Sets a TCC module compare value and buffer value. + * + * Writes compare value and buffer to the given TCC module compare/capture + * channel. Usually as preparation for double buffer or circulared double buffer + * (circular buffer). + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] channel_index Index of the compare channel to write to + * \param[in] compare New compare value to set + * \param[in] compare_buffer New compare buffer value to set + * + * \return Status of the compare update procedure. + * + * \retval STATUS_OK The compare value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or + * compare value exceed resolution + */ +enum status_code tcc_set_double_buffer_compare_values( + struct tcc_module *const module_inst, + const enum tcc_match_capture_channel channel_index, + const uint32_t compare, const uint32_t compare_buffer) +{ + /* Sanity check arguments */ + Assert(module_inst); + + enum status_code status; + status = _tcc_set_compare_value(module_inst, channel_index, compare, false); + if (status != STATUS_OK) { + return status; + } + return _tcc_set_compare_value(module_inst, channel_index, compare_buffer, + true); +} + + +/** + * \internal + * \brief Set the timer TOP/PERIOD buffer/value. + * + * This function writes the given value to the PER/PERB register. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] top_value New value to be loaded into the PER/PERB register + * \param[in] double_buffering_enabled Set to \c true to write to PERB + * + * \return Status of the TOP set procedure. + * + * \retval STATUS_OK The timer TOP value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or + * top/period value exceed resolution + */ +static enum status_code _tcc_set_top_value( + const struct tcc_module *const module_inst, + const uint32_t top_value, + const bool double_buffering_enabled) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + /* Get a index of the module */ + uint8_t module_index = _tcc_get_inst_index(tcc_module); + + uint32_t max_count = _tcc_maxs[module_index]; + + /* Check compare value */ + if (top_value > max_count) { + return STATUS_ERR_INVALID_ARG; + } + + if (double_buffering_enabled) { +#if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + tcc_module->PERBUF.reg = top_value; +#else + while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PERB) { + /* Sync wait */ + } + tcc_module->PERB.reg = top_value; +#endif + } else { + while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PER) { + /* Sync wait */ + } + tcc_module->PER.reg = top_value; + } + return STATUS_OK; +} + + +/** + * \brief Set the timer TOP/PERIOD value. + * + * This function writes the given value to the PER/PERB register. + * + * If double buffering is enabled it always write to the buffer + * register (PERB). The value will then be updated immediately by calling + * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit + * is cleared and the UPDATE condition happen. + * + * When using MFRQ, the top value is defined by the CC0 register value and the + * PER value is ignored, so + * \ref tcc_set_compare_value (module,channel_0,value) must be used instead of + * this function to change the actual top value in that case. + * For all other waveforms operation the top value is defined by PER register + * value. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] top_value New value to be loaded into the PER/PERB register + * + * \return Status of the TOP set procedure. + * + * \retval STATUS_OK The timer TOP value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or + * top/period value exceed resolution + */ +enum status_code tcc_set_top_value( + const struct tcc_module *const module_inst, + const uint32_t top_value) +{ + /* Sanity check arguments */ + Assert(module_inst); + + return _tcc_set_top_value(module_inst, top_value, + module_inst->double_buffering_enabled); +} + +/** + * \brief Set the timer TOP/PERIOD value and buffer value. + * + * This function writes the given value to the PER and PERB register. Usually as + * preparation for double buffer or circulared double buffer (circular buffer). + * + * When using MFRQ, the top values are defined by the CC0 and CCB0, the PER and + * PERB values are ignored, so + * \ref tcc_set_double_buffer_compare_values (module,channel_0,value,buffer) must + * be used instead of this function to change the actual top values in that + * case. For all other waveforms operation the top values are defined by PER and + * PERB registers values. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] top_value New value to be loaded into the PER register + * \param[in] top_buffer_value New value to be loaded into the PERB register + * + * \return Status of the TOP set procedure. + * + * \retval STATUS_OK The timer TOP value was updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid channel index was supplied or + * top/period value exceed resolution + */ +enum status_code tcc_set_double_buffer_top_values( + const struct tcc_module *const module_inst, + const uint32_t top_value, const uint32_t top_buffer_value) +{ + /* Sanity check arguments */ + Assert(module_inst); + + enum status_code status; + status = _tcc_set_top_value(module_inst, top_value, false); + if (status != STATUS_OK) { + return status; + } + return _tcc_set_top_value(module_inst, top_buffer_value, true); +} + + +/** + * \brief Sets the TCC module waveform output pattern. + * + * Force waveform output line to generate specific pattern (0, 1, or as is). + * + * If double buffering is enabled it always write to the buffer + * register. The value will then be updated immediately by calling + * \ref tcc_force_double_buffer_update(), or be updated when the lock update bit + * is cleared and the UPDATE condition happen. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] line_index Output line index + * \param[in] pattern Output pattern to use (\ref tcc_output_pattern) + * + * \return Status of the pattern set procedure. + * + * \retval STATUS_OK The PATT register is updated successfully + * \retval STATUS_ERR_INVALID_ARG An invalid line index was supplied + */ +enum status_code tcc_set_pattern( + const struct tcc_module *const module_inst, + const uint32_t line_index, + const enum tcc_output_pattern pattern) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + /* Get a index of the module */ + uint8_t module_index = _tcc_get_inst_index(tcc_module); + /* Get number of output lines */ + uint8_t ow_num = _tcc_ow_nums[module_index]; + + /* Check if line number is OK */ + if (line_index >= ow_num) { + return STATUS_ERR_INVALID_ARG; + } + + uint32_t patt_value; + + while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PATT) { + /* Sync wait */ + } + patt_value = tcc_module->PATT.reg; + if (TCC_OUTPUT_PATTERN_DISABLE == pattern) { + patt_value &= ~(TCC_PATT_PGE0 << line_index); + } else if (TCC_OUTPUT_PATTERN_0 == pattern) { + patt_value &= ~(TCC_PATT_PGV0 << line_index); + patt_value |= (TCC_PATT_PGE0 << line_index); + } else { + patt_value |= ((TCC_PATT_PGE0 | TCC_PATT_PGV0) << line_index); + } + + if (module_inst->double_buffering_enabled) { +#if (SAML21) || (SAMC20) || (SAMC21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + tcc_module->PATTBUF.reg = patt_value; +#else + while(tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_PATTB) { + /* Sync wait */ + } + tcc_module->PATTB.reg = patt_value; +#endif + } else { + tcc_module->PATT.reg = patt_value; + } + return STATUS_OK; +} + +/** + * \brief Retrieves the current module status. + * + * Retrieves the status of the module, giving overall state information. + * + * \param[in] module_inst Pointer to the TCC software instance struct + * + * \return Bitmask of \c TCC_STATUS_* flags. + * + * \retval TCC_STATUS_CHANNEL_MATCH_CAPTURE(n) Channel n match/capture has occured + * \retval TCC_STATUS_CHANNEL_OUTPUT(n) Channel n match/capture output state + * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(x) Non-recoverable fault x has occured + * \retval TCC_STATUS_RECOVERABLE_FAULT_OCCUR(n) Recoverable fault n has occured + * \retval TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(x) Non-recoverable fault x input present + * \retval TCC_STATUS_RECOVERABLE_FAULT_PRESENT(n) Recoverable fault n input present + * \retval TCC_STATUS_SYNC_READY None of register is syncing + * \retval TCC_STATUS_CAPTURE_OVERFLOW Timer capture data has overflowed + * \retval TCC_STATUS_COUNTER_EVENT Timer counter event has occurred + * \retval TCC_STATUS_COUNT_OVERFLOW Timer count value has overflowed + * \retval TCC_STATUS_COUNTER_RETRIGGERED Timer counter has been retriggered + * \retval TCC_STATUS_STOP Timer counter has been stopped + * \retval TCC_STATUS_RAMP_CYCLE_INDEX Wave ramp index for cycle + */ +uint32_t tcc_get_status( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + uint32_t int_flags = module_inst->hw->INTFLAG.reg; + uint32_t status_flags = module_inst->hw->STATUS.reg; + uint32_t status = 0; + int i; + + /* SYNC */ + if (module_inst->hw->SYNCBUSY.reg == 0) { + status |= TCC_STATUS_SYNC_READY; + } + + /* Channels */ + for (i = 0; i < TCC_NUM_CHANNELS; i++) { + if (int_flags & TCC_INTFLAG_MC(i)) { + status |= TCC_STATUS_CHANNEL_MATCH_CAPTURE(i); + } + if (status_flags & TCC_STATUS_CMP(i)) { + status |= TCC_STATUS_CHANNEL_OUTPUT(i); + } + } + /* Non-recoverable fault state */ + if ((int_flags & TCC_INTFLAG_FAULT1) || + (status_flags & TCC_STATUS_FAULT1)) { + status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1); + } + if ((int_flags & TCC_INTFLAG_FAULT0) || + (status_flags & TCC_STATUS_FAULT0)) { + status |= TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0); + } + /* Non-recoverable fault inputs */ + if (status_flags & TCC_STATUS_FAULT0IN) { + status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(0); + } + if (status_flags & TCC_STATUS_FAULT1IN) { + status |= TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(1); + } + /* Recoverable fault state */ + if ((int_flags & TCC_INTFLAG_FAULTB) || + (status_flags & TCC_STATUS_FAULTB)) { + status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1); + } + if ((int_flags & TCC_INTFLAG_FAULTA) || + (status_flags & TCC_STATUS_FAULTA)) { + status |= TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0); + } + /* Recoverable fault inputs */ + if (status_flags & TCC_STATUS_FAULTAIN) { + status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(0); + } + if (status_flags & TCC_STATUS_FAULTBIN) { + status |= TCC_STATUS_RECOVERABLE_FAULT_PRESENT(1); + } + + /* Check for TCC capture overflow */ + if (int_flags & TCC_INTFLAG_ERR) { + status |= TCC_STATUS_CAPTURE_OVERFLOW; + } + /* Check for TCC count counter */ + if (int_flags & TCC_INTFLAG_CNT) { + status |= TCC_STATUS_COUNTER_EVENT; + } + /* Check for TCC count retrigger */ + if (int_flags & TCC_INTFLAG_TRG) { + status |= TCC_STATUS_COUNTER_RETRIGGERED; + } + /* Check for TCC count overflow */ + if (int_flags & TCC_INTFLAG_OVF) { + status |= TCC_STATUS_COUNT_OVERFLOW; + } + /* Check for TCC count stop */ + if (status_flags & TCC_STATUS_STOP) { + status |= TCC_STATUS_STOPPED; + } + /* Check for TCC RAMP index */ + if (status_flags & TCC_STATUS_IDX) { + status |= TCC_STATUS_RAMP_CYCLE_INDEX; + } + return status; +} + +/** + * \brief Clears a module status flag. + * + * Clears the given status flag of the module. + * + * \param[in] module_inst Pointer to the TCC software instance struct + * \param[in] status_flags Bitmask of \c TCC_STATUS_* flags to clear + */ +void tcc_clear_status( + struct tcc_module *const module_inst, + const uint32_t status_flags) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + uint32_t int_clr = 0; + uint32_t status_clr = 0; + int i; + + /* Channels */ + for (i = 0; i < TCC_NUM_CHANNELS; i++) { + if (status_flags & TCC_STATUS_CHANNEL_MATCH_CAPTURE(i)) { + int_clr |= TCC_INTFLAG_MC(i); + } + } + /* Faults */ + if (status_flags & TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(1)) { + int_clr |= TCC_INTFLAG_FAULT1; + status_clr |= TCC_STATUS_FAULT1; + } + if (status_flags & TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(0)) { + int_clr |= TCC_INTFLAG_FAULT0; + status_clr |= TCC_STATUS_FAULT0; + } + if (status_flags & TCC_STATUS_RECOVERABLE_FAULT_OCCUR(1)) { + int_clr |= TCC_INTFLAG_FAULTB; + status_clr |= TCC_STATUS_FAULTB; + } + if (status_flags & TCC_STATUS_RECOVERABLE_FAULT_OCCUR(0)) { + int_clr |= TCC_INTFLAG_FAULTA; + status_clr |= TCC_STATUS_FAULTA; + } + /* Check for TCC capture overflow */ + if (status_flags & TCC_STATUS_CAPTURE_OVERFLOW) { + int_clr |= TCC_INTFLAG_ERR; + } + /* Check for TCC count counter */ + if (status_flags & TCC_STATUS_COUNTER_EVENT) { + int_clr |= TCC_INTFLAG_CNT; + } + /* Check for TCC count retrigger */ + if (status_flags & TCC_STATUS_COUNTER_RETRIGGERED) { + int_clr = TCC_INTFLAG_TRG; + } + /* Check for TCC count overflow */ + if (status_flags & TCC_STATUS_COUNT_OVERFLOW) { + int_clr |= TCC_INTFLAG_OVF; + } + /* Clear status flag */ + module_inst->hw->STATUS.reg = status_clr; + /* Clear interrupt flag */ + module_inst->hw->INTFLAG.reg = int_clr; +} + +/** + * \brief Enable circular option for double buffered compare values. + * + * Enable circular option for the double buffered channel compare values. + * On each UPDATE condition, the contents of CCBx and CCx are switched, meaning + * that the contents of CCBx are transferred to CCx and the contents of CCx are + * transferred to CCBx. + * + * \param[in] module_inst Pointer to the TCC software instance struct + * \param[in] channel_index Index of the compare channel to set up to + * + * \retval STATUS_OK The module was initialized successfully + * \retval STATUS_INVALID_ARG An invalid channel index is supplied + */ +enum status_code tcc_enable_circular_buffer_compare( + struct tcc_module *const module_inst, + enum tcc_match_capture_channel channel_index) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + /* Get a index of the module */ + uint8_t module_index = _tcc_get_inst_index(tcc_module); + + /* Check index */ + if (channel_index > 3) { + return STATUS_ERR_INVALID_ARG; + } + if (channel_index >= _tcc_cc_nums[module_index]) { + return STATUS_ERR_INVALID_ARG; + } + + tcc_module->WAVE.reg |= (TCC_WAVE_CICCEN0 << channel_index); + + return STATUS_OK; +} + +/** + * \brief Disable circular option for double buffered compare values. + * + * Stop circularing the double buffered compare values. + * + * \param[in] module_inst Pointer to the TCC software instance struct + * \param[in] channel_index Index of the compare channel to set up to + * + * \retval STATUS_OK The module was initialized successfully + * \retval STATUS_INVALID_ARG An invalid channel index is supplied + */ +enum status_code tcc_disable_circular_buffer_compare( + struct tcc_module *const module_inst, + enum tcc_match_capture_channel channel_index) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + /* Get a index of the module */ + uint8_t module_index = _tcc_get_inst_index(tcc_module); + + /* Check index */ + if (channel_index > 3) { + return STATUS_ERR_INVALID_ARG; + } + if (channel_index >= _tcc_cc_nums[module_index]) { + return STATUS_ERR_INVALID_ARG; + } + + tcc_module->WAVE.reg &= ~(TCC_WAVE_CICCEN0 << channel_index); + + return STATUS_OK; +} diff --git a/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h new file mode 100644 index 0000000..eae07f8 --- /dev/null +++ b/TE_Controller/src/ASF/sam0/drivers/tcc/tcc.h @@ -0,0 +1,2487 @@ +/** + * \file + * + * \brief SAM TCC - Timer Counter for Control Applications Driver + * + * Copyright (c) 2013-2020 Microchip Technology Inc. and its subsidiaries. + * + * \asf_license_start + * + * \page License + * + * Subject to your compliance with these terms, you may use Microchip + * software and any derivatives exclusively with Microchip products. + * It is your responsibility to comply with third party license terms applicable + * to your use of third party software (including open source software) that + * may accompany Microchip software. + * + * THIS SOFTWARE IS SUPPLIED BY MICROCHIP "AS IS". NO WARRANTIES, + * WHETHER EXPRESS, IMPLIED OR STATUTORY, APPLY TO THIS SOFTWARE, + * INCLUDING ANY IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY, + * AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT WILL MICROCHIP BE + * LIABLE FOR ANY INDIRECT, SPECIAL, PUNITIVE, INCIDENTAL OR CONSEQUENTIAL + * LOSS, DAMAGE, COST OR EXPENSE OF ANY KIND WHATSOEVER RELATED TO THE + * SOFTWARE, HOWEVER CAUSED, EVEN IF MICROCHIP HAS BEEN ADVISED OF THE + * POSSIBILITY OR THE DAMAGES ARE FORESEEABLE. TO THE FULLEST EXTENT + * ALLOWED BY LAW, MICROCHIP'S TOTAL LIABILITY ON ALL CLAIMS IN ANY WAY + * RELATED TO THIS SOFTWARE WILL NOT EXCEED THE AMOUNT OF FEES, IF ANY, + * THAT YOU HAVE PAID DIRECTLY TO MICROCHIP FOR THIS SOFTWARE. + * + * \asf_license_stop + * + */ +/* + * Support and FAQ: visit Microchip Support + */ + +#ifndef TCC_H_INCLUDED +#define TCC_H_INCLUDED + +/** + * \defgroup asfdoc_sam0_tcc_group SAM Timer Counter for Control Applications (TCC) Driver + * + * This driver for Atmel® | SMART ARM®-based microcontrollers provides an interface for the configuration + * and management of the TCC module within the device, for waveform + * generation and timing operations. It also provides extended options for + * control applications. + * + * The following driver API modes are covered + * by this manual: + * + * - Polled APIs + * \if TCC_CALLBACK_MODE + * - Callback APIs + * \endif + * + * The following peripheral is used by this module: + * - TCC (Timer/Counter for Control Applications) + * + * The following devices can use this module: + * - Atmel | SMART SAM D21 + * - Atmel | SMART SAM R21 + * - Atmel | SMART SAM D10/D11 + * - Atmel | SMART SAM L21/L22 + * - Atmel | SMART SAM DA1 + * - Atmel | SMART SAM C20/C21 + * - Atmel | SMART SAM HA1 + * - Atmel | SMART SAM R30 + * - Atmel | SMART SAM R34 + * - Atmel | SMART SAM R35 + * + * The outline of this documentation is as follows: + * - \ref asfdoc_sam0_tcc_prerequisites + * - \ref asfdoc_sam0_tcc_module_overview + * - \ref asfdoc_sam0_tcc_special_considerations + * - \ref asfdoc_sam0_tcc_extra_info + * - \ref asfdoc_sam0_tcc_examples + * - \ref asfdoc_sam0_tcc_api_overview + * + * \section asfdoc_sam0_tcc_prerequisites Prerequisites + * + * There are no prerequisites for this module. + * + * \section asfdoc_sam0_tcc_module_overview Module Overview + * + * The Timer/Counter for Control Applications (TCC) module provides a set of + * timing and counting related functionality, such as the generation of periodic + * waveforms, the capturing of a periodic waveform's frequency/duty cycle, + * software timekeeping for periodic operations, waveform extension control, + * fault detection etc. + * + * The counter size of the TCC modules can be 16- or 24-bit depending on + * the TCC instance. + * Refer \ref asfdoc_sam0_tcc_special_considerations_tcc_d21 and + * \ref asfdoc_sam0_tcc_special_considerations_tcc_d11 for details on TCC instances. + * + * The TCC module for the SAM includes the following functions: + * + * - Generation of PWM signals + * - Generation of timestamps for events + * - General time counting + * - Waveform period capture + * - Waveform frequency capture + * - Additional control for generated waveform outputs + * - Fault protection for waveform generation + * + * \ref asfdoc_sam0_tcc_block_diagram "The diagram below" shows the overview + * of the TCC Module. + * + * \anchor asfdoc_sam0_tcc_block_diagram + * \image html overview.svg "Overview of the TCC Module" + * + * \subsection asfdoc_sam0_tcc_module_overview_parts Functional Description + * The TCC module consists of following sections: + * - Base Counter + * - Compare/Capture channels, with waveform generation + * - Waveform extension control and fault detection + * - Interface to the event system, DMAC, and the interrupt system + * + * The base counter can be configured to either count a prescaled generic + * clock or events from the event system.(TCEx, with event action configured + * to counting). + * The counter value can be used by compare/capture channels which can be + * set up either in compare mode or capture mode. + * + * In capture mode, the counter value is stored when a configurable event + * occurs. This mode can be used to generate timestamps used in event capture, + * or it can be used for the measurement of a periodic input signal's + * frequency/duty cycle. + * + * In compare mode, the counter value is compared against one or more of the + * configured channels' compare values. When the counter value coincides with a + * compare value an action can be taken automatically by the module, such as + * generating an output event or toggling a pin when used for frequency or PWM + * signal generation. + * + * \note The connection of events between modules requires the use of the + * \ref asfdoc_sam0_events_group "SAM Event System Driver (EVENTS)" + * to route output event of one module to the the input event of another. + * For more information on event routing, refer to the event driver + * documentation. + * + * In compare mode, when output signal is generated, extended waveform controls + * are available, to arrange the compare outputs into specific formats. + * The Output matrix can change the channel output routing. Pattern generation + * unit can overwrite the output signal line to specific state. + * The Fault protection feature of the TCC supports recoverable and + * non-recoverable faults. + * + * \subsection asfdoc_sam0_tcc_module_overview_tc Base Timer/Counter + * + * \subsubsection asfdoc_sam0_tcc_module_overview_tc_size Timer/Counter Size + * Each TCC has a counter size of either 16- or 24-bits. The size of the + * counter determines the maximum value it can count to before an overflow + * occurs. + * \ref asfdoc_sam0_tcc_count_size_vs_top "The table below" shows the + * maximum values for each of the possible counter sizes. + * + * \anchor asfdoc_sam0_tcc_count_size_vs_top + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Timer Counter Sizes and Their Maximum Count Values
Counter sizeMax. (hexadecimal)Max. (decimal)
16-bit0xFFFF65,535
24-bit0xFFFFFF16,777,215
+ * + * The period/top value of the counter can be set, to define counting period. + * This will allow the counter to overflow when the counter value reaches the + * period/top value. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_tc_clk Timer/Counter Clock and Prescaler + * TCC is clocked asynchronously to the system clock by a GCLK + * (Generic Clock) channel. The GCLK channel can be connected to any of the GCLK + * generators. The GCLK generators are configured to use one of the available + * clock sources in the system such as internal oscillator, external crystals, + * etc. See the \ref asfdoc_sam0_system_clock_group "Generic Clock driver" for + * more information. + * + * Each TCC module in the SAM has its own individual clock prescaler, which + * can be used to divide the input clock frequency used by the counter. This + * prescaler only scales the clock used to provide clock pulses for the counter + * to count, and does not affect the digital register interface portion of + * the module, thus the timer registers will be synchronized to the raw GCLK + * frequency input to the module. + * + * As a result of this, when selecting a GCLK frequency and timer prescaler + * value, the user application should consider both the timer resolution + * required and the synchronization frequency to avoid lengthy + * synchronization times of the module if a very slow GCLK frequency is fed + * into the TCC module. It is preferable to use a higher module GCLK frequency + * as the input to the timer, and prescale this down as much as possible to + * obtain a suitable counter frequency in latency-sensitive applications. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_tc_ctrl Timer/Counter Control Inputs (Events) + * + * The TCC can take several actions on the occurrence of an input event. + * The event actions are listed + * in \ref asfdoc_sam0_tcc_module_event_act "events action settings". + * + * \anchor asfdoc_sam0_tcc_module_event_act + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC Module Event Actions
Event actionDescriptionApplied event
TCC_EVENT_ACTION_OFFNo action on the event inputAll
TCC_EVENT_ACTION_RETRIGGERRe-trigger Counter on eventAll
TCC_EVENT_ACTION_NON_RECOVERABLE_FAULTGenerate Non-Recoverable Fault on eventAll
TCC_EVENT_ACTION_STARTCounter start on eventEV0
TCC_EVENT_ACTION_DIR_CONTROLCounter direction controlEV0
TCC_EVENT_ACTION_DECREMENTCounter decrement on eventEV0
TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURECapture pulse period and pulse widthEV0
TCC_EVENT_ACTION_PULSE_WIDTH_PERIOD_CAPTURECapture pulse width and pulse periodEV0
TCC_EVENT_ACTION_STOPCounter stop on eventEV1
TCC_EVENT_ACTION_COUNT_EVENTCounter count on eventEV1
TCC_EVENT_ACTION_INCREMENTCounter increment on eventEV1
TCC_EVENT_ACTION_COUNT_DURING_ACTIVECounter count during active state of asynchronous eventEV1
+ * + * \subsubsection asfdoc_sam0_tcc_module_overview_tc_reload Timer/Counter Reloading + * + * The TCC also has a configurable reload action, used when a + * re-trigger event occurs. Examples of a re-trigger event could be the counter + * reaching the maximum value when counting up, or when an event from the event + * system makes the counter to re-trigger. The reload action determines if the + * prescaler should be reset, and on which clock. The counter will + * always be reloaded with the value it is set to start counting. The user + * can choose between three different reload actions, described in + * \ref asfdoc_sam0_tcc_module_reload_act "the table below". + * + * \anchor asfdoc_sam0_tcc_module_reload_act + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC Module Reload Actions
Reload actionDescription
TCC_RELOAD_ACTION_GCLKReload TCC counter value on next GCLK cycle. Leave prescaler + * as-is.
TCC_RELOAD_ACTION_PRESCReloads TCC counter value on next prescaler clock. Leave prescaler + * as-is.
TCC_RELOAD_ACTION_RESYNCReload TCC counter value on next GCLK cycle. Clear prescaler to + * zero.
+ * + * The reload action to use will depend on the specific application being + * implemented. One example is when an external trigger for a reload occurs; if + * the TCC uses the prescaler, the counter in the prescaler should not have a + * value between zero and the division factor. The counter in the TCC module + * and the counter in the prescaler should both start at zero. + * If the counter is set to re-trigger when it reaches the maximum value, + * this is not the right option to use. In such a case it would be better if + * the prescaler is left unaltered when the re-trigger happens, letting the + * counter reset on the next GCLK cycle. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_tc_oneshot One-shot Mode + * + * The TCC module can be configured in one-shot mode. When configured in this + * manner, starting the timer will cause it to count until the next overflow + * or underflow condition before automatically halting, waiting to be manually + * triggered by the user application software or an event from the event + * system. + * + * \subsection asfdoc_sam0_tcc_module_overview_capt Capture Operations + * + * In capture operations, any event from the event system or a pin change can + * trigger a capture of the counter value. This captured counter value can be + * used as timestamps for the events, or it can be used in frequency and pulse + * width capture. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_capt_ev Capture Operations - Event + * + * Event capture is a simple use of the capture functionality, + * designed to create timestamps for specific events. When the input event + * appears, the current counter value is copied into the corresponding + * compare/capture register, which can then be read by the user application. + * + * Note that when performing any capture operation, there is a risk that the + * counter reaches its top value (MAX) when counting up, or the bottom value + * (zero) when counting down, before the capture event occurs. This can distort + * the result, making event timestamps to appear shorter than they really are. + * In this case, the user application should check for timer overflow when + * reading a capture result in order to detect this situation and perform an + * appropriate adjustment. + * + * Before checking for a new capture, \ref TCC_STATUS_COUNT_OVERFLOW + * should be checked. The response to an overflow error is left to the user + * application, however, it may be necessary to clear both the overflow + * flag and the capture flag upon each capture reading. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_capt_pulse Capture Operations - Pulse Width + * + * Pulse Width Capture mode makes it possible to measure the pulse width and + * period of PWM signals. This mode uses two capture channels of the counter. + * There are two modes for pulse width capture; + * Pulse Width Period (PWP) and Period Pulse Width (PPW). In PWP mode, capture + * channel 0 is used for storing the pulse width and capture channel 1 stores + * the observed period. While in PPW mode, the roles of the two capture channels + * are reversed. + * + * As in the above example it is necessary to poll on interrupt flags to see + * if a new capture has happened and check that a capture overflow error has + * not occurred. + * + * Refer to \ref asfdoc_sam0_tcc_module_overview_tc_ctrl to set up the input + * event to perform pulse width capture. + * + * \subsection asfdoc_sam0_tcc_module_overview_mc Compare Match Operation + * + * In compare match operation, Compare/Capture registers are compared + * with the counter value. When the timer's count value matches the value of a + * compare channel, a user defined action can be taken. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_mc_timer Basic Timer + * + * A Basic Timer is a simple application where compare match operation is used + * to determine when a specific period has elapsed. In Basic Timer operations, + * one or more values in the module's Compare/Capture registers are used to + * specify the time (in terms of the number of prescaled GCLK cycles, or + * input events) at which + * an action should be taken by the microcontroller. This can be an Interrupt + * Service Routine (ISR), event generation via the event system, or a software + * flag that is polled from the user application. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_mc_wave Waveform Generation + * + * Waveform generation enables the TCC module to generate square waves, or, if + * combined with an external passive low-pass filter, analog waveforms. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_mc_wave_pwm Waveform Generation - PWM + * + * Pulse width modulation is a form of waveform generation and a signalling + * technique that can be useful in many applications. When PWM mode is used, + * a digital pulse train with a configurable frequency and duty cycle can be + * generated by the TCC module and output to a GPIO pin of the device. + * + * Often PWM is used to communicate a control or information parameter to an + * external circuit or component. Differing impedances of the source generator + * and sink receiver circuits is less of an issue when using PWM compared to + * using an analog voltage value, as noise will not generally affect the + * signal's integrity to a meaningful extent. + * + * \ref asfdoc_sam0_tcc_module_pwm_single_diag "The figure below" illustrates + * operations and different states of the counter and its output when using + * the timer in Normal PWM mode (Single Slope). As can be seen, the TOP/PERIOD + * value is + * unchanged and is set to MAX. The compare match value is changed at several + * points to illustrate the resulting waveform output changes. The PWM output is + * set to normal (i.e. non-inverted) output mode. + * + * \anchor asfdoc_sam0_tcc_module_pwm_single_diag + * \image html pwm_single_ex.svg "Example Of PWM In Single-Slope Mode, and Different Counter Operations" + * + * Several PWM modes are supported by the TCC module, refer to + * datasheet for the details on PWM waveform generation. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_mc_wave_freq Waveform Generation - Frequency + * + * Normal Frequency Generation is in many ways identical to PWM generation. + * However, only in Frequency Generation, a toggle occurs on the output when a + * match on a compare channels occurs. + * + * When the Match Frequency Generation is used, the timer value is reset on + * match condition, resulting in a variable frequency square wave with a + * fixed 50% duty cycle. + * + * \subsection asfdoc_sam0_tcc_module_overview_ext Waveform Extended Controls + * + * \subsubsection asfdoc_sam0_tcc_module_overview_ext_pat Pattern Generation + * + * Pattern insertion allows the TCC module to change the actual pin output level + * without modifying the compare/match settings. + * + * \anchor asfdoc_sam0_tcc_module_pattern_gen + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC Module Output Pattern Generation
PatternDescription
TCC_OUTPUT_PATTERN_DISABLEPattern disabled, generate output as is
TCC_OUTPUT_PATTERN_0Generate pattern 0 on output (keep the output LOW)
TCC_OUTPUT_PATTERN_1Generate pattern 1 on output (keep the output HIGH)
+ * + * \subsubsection asfdoc_sam0_tcc_module_overview_ext_r_fault Recoverable Faults + * + * The recoverable faults can trigger one or several of following fault actions: + * -# *Halt* action: The recoverable faults can halt the TCC timer/counter, + * so that the final output wave is kept at a defined state. When the fault + * state is removed it is possible to recover the counter and waveform + * generation. The halt action is defined as: + * \anchor asfdoc_sam0_tcc_module_fault_halt_action + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC Module Recoverable Fault Halt Actions
ActionDescription
TCC_FAULT_HALT_ACTION_DISABLEHalt action is disabled
TCC_FAULT_HALT_ACTION_HW_HALTThe timer/counter is halted as long as the corresponding fault is + * present
TCC_FAULT_HALT_ACTION_SW_HALTThe timer/counter is halted until the corresponding fault is removed + * and fault state cleared by software
TCC_FAULT_HALT_ACTION_NON_RECOVERABLEForce all the TCC output pins to a pre-defined level, as what + * Non-Recoverable Fault do
+ * -# *Restart* action: When enabled, the recoverable faults can restart the TCC + * timer/counter. + * -# *Keep* action: When enabled, the recoverable faults can keep the + * corresponding channel output to zero when the fault condition is present. + * -# *Capture* action: When the recoverable fault occurs, the capture action can + * time stamps the corresponding fault. The following capture mode is + * supported: + * \anchor asfdoc_sam0_tcc_module_fault_capt_action + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC Module Recoverable Fault Capture Actions
ActionDescription
TCC_FAULT_CAPTURE_DISABLECapture action is disabled
TCC_FAULT_CAPTURE_EACHEquivalent to standard capture operation, on each fault occurrence + * the time stamp is captured
TCC_FAULT_CAPTURE_MINIMUMGet the minimum time stamped value in all time stamps
TCC_FAULT_CAPTURE_MAXIMUMGet the maximum time stamped value in all time stamps
TCC_FAULT_CAPTURE_SMALLERTime stamp the fault input if the value is smaller than last one
TCC_FAULT_CAPTURE_BIGGERTime stamp the fault input if the value is bigger than last one
TCC_FAULT_CAPTURE_CHANGETime stamp the fault input if the time stamps changes its increment + * direction
+ * + * In TCC module, only the first two compare channels (CC0 and CC1) can work + * with recoverable fault inputs. The corresponding event inputs (TCCx MC0 + * and TCCx MC1) are then used as fault inputs respectively. + * The faults are called Fault A and Fault B. + * + * The recoverable fault can be filtered or effected by corresponding channel + * output. On fault condition there are many other settings that can be chosen. + * Refer to data sheet for more details about the recoverable fault + * operations. + * + * \subsubsection asfdoc_sam0_tcc_module_overview_ext_n_fault Non-Recoverable Faults + * + * The non-recoverable faults force all the TCC output pins to a pre-defined + * level (can be forced to 0 or 1). The input control signal of non-recoverable + * fault is from timer/counter event (TCCx EV0 and TCCx EV1). + * To enable non-recoverable fault, + * corresponding TCEx event action must be set to non-recoverable fault action + * (\ref TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT). + * Refer to \ref asfdoc_sam0_tcc_module_overview_tc_ctrl to see the available + * event input action. + * + * \subsection asfdoc_sam0_tcc_module_overview_buffering Double and Circular Buffering + * + * The pattern, period, and the compare channels registers are double buffered. + * For these options there are effective registers (PATT, PER, and CCx) and + * buffer registers (PATTB, PERB, and CCx). When writing to the buffer + * registers, the values are buffered and will be committed to effective + * registers on UPDATE condition. + * + * Usually the buffered value is cleared after it is committed, but there is also + * an option to circular the register buffers. The period (PER) and four lowest + * compare channels register (CCx, x is 0 ~ 3) support this function. When + * circular buffer is used, on UPDATE the previous period or compare values are + * copied back into the corresponding period buffer and compare buffers. + * This way, the register value and its buffer register value is actually + * switched on UPDATE condition, and will be switched back on next UPDATE + * condition. + * + * For input capture, the buffer register (CCBx) and the corresponding capture + * channel register (CCx) act like a FIFO. When regular register (CCx) is empty + * or read, any content in the buffer register is passed to regular one. + * + * In TCC module driver, when the double buffering write is enabled, any + * write through \ref tcc_set_top_value(), \ref tcc_set_compare_value(), and + * \ref tcc_set_pattern() will be done to the corresponding buffer register. + * Then the value in the buffer register will be transferred to the regular + * register on the next UPDATE condition or by a force UPDATE using + * \ref tcc_force_double_buffer_update(). + * + * \subsection asfdoc_sam0_tcc_module_overview_sleep Sleep Mode + * + * TCC modules can be configured to operate in any sleep mode, with its "run + * in standby" function enabled. It can wake up the device using interrupts or + * perform internal actions with the help of the Event System. + * + * \section asfdoc_sam0_tcc_special_considerations Special Considerations + * + * \subsection asfdoc_sam0_tcc_special_considerations_specific_features Driver Feature Macro Definition + * \ref asfdoc_sam0_tcc_feature_table "The table below" shows some specific features + * of the TCC Module. + * + * \anchor asfdoc_sam0_tcc_feature_table + * + * + * + * + * + * + * + * + * + * + *
TCC Module Specific Features
Driver Feature MacroSupported devices
FEATURE_TCC_GENERATE_DMA_TRIGGERSAM L21/L22/R30/R34/R35
+ * + * \note The specific features are only available in the driver when the + * selected device supports those features. + * + * \subsection asfdoc_sam0_tcc_special_considerations_tcc_feature Module Features + * + * The features of TCC, such as timer/counter size, number of compare capture + * channels, and number of outputs, are dependent on the TCC module instance being + * used. + * + * \subsubsection asfdoc_sam0_tcc_special_considerations_tcc_d21 SAM TCC Feature List + * For SAM D21/R21/L21/L22/DA1/C21/R30, the TCC features are: + * \anchor asfdoc_sam0_tcc_features_d21 + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC module features for SAM D21/R21/L21/L22/DA1/C21/R30
TCC#Match/Capture channelsWave outputsCounter size [bits]FaultDitheringOutput matrixDead-Time insertionSWAPPattern
04824YYYYYY
12424YYY
22216Y
+ * + * \subsubsection asfdoc_sam0_tcc_special_considerations_tcc_d11 SAM D10/D11 TCC Feature List + * For SAM D10/D11, the TCC features are: + * \anchor asfdoc_sam0_tcc_features_d11 + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
TCC Module Features For SAM D10/D11
TCC#Match/Capture channelsWave outputsCounter size [bits]FaultDitheringOutput matrixDead-Time insertionSWAPPattern
04824YYYYYY
+ * + * \subsection asfdoc_sam0_tcc_special_considerations_tcc_pin Channels vs. Pinouts + * + * As the TCC module may have more waveform output pins than the number of + * compare/capture channels, the free pins (with number higher than number of + * channels) will reuse the waveform generated by channels subsequently. E.g., + * if the number of channels is four and the number of wave output pins is eight, channel + * 0 output will be available on out pin 0 and 4, channel 1 output + * on wave out pin 1 and 5, and so on. + * + * \section asfdoc_sam0_tcc_extra_info Extra Information + * + * For extra information, see \ref asfdoc_sam0_tcc_extra. This includes: + * - \ref asfdoc_sam0_tcc_extra_acronyms + * - \ref asfdoc_sam0_tcc_extra_dependencies + * - \ref asfdoc_sam0_tcc_extra_errata + * - \ref asfdoc_sam0_tcc_extra_history + * + * + * \section asfdoc_sam0_tcc_examples Examples + * + * For a list of examples related to this driver, see + * \ref asfdoc_sam0_tcc_exqsg. + * + * \section asfdoc_sam0_tcc_api_overview API Overview + * @{ + */ + +#include +#include +#include +#include + +/** Maximum number of channels supported by the driver + * (Channel index from 0 to \c TCC_NUM_CHANNELS - 1). + */ +#define TCC_NUM_CHANNELS 4 + +/** Maximum number of wave outputs lines supported by the driver + * (Output line index from 0 to \c TCC_NUM_WAVE_OUTPUTS - 1). + */ +#define TCC_NUM_WAVE_OUTPUTS 8 + +/** Maximum number of (recoverable) faults supported by the driver. */ +#define TCC_NUM_FAULTS 2 + +#if TCC_ASYNC == true +# include +#endif + +/** + * \name Driver Feature Definition + * Define port features set according to different device family. + * @{ +*/ +#if (SAML21) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) || defined(__DOXYGEN__) +/** Generate DMA triggers */ +# define FEATURE_TCC_GENERATE_DMA_TRIGGER +#endif +/*@}*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** Generates a table enum list entry for a given type + and index (e.g. "TCC_CALLBACK_MC_CHANNEL_0,"). */ +#define _TCC_ENUM(n, type) TCC_##type##_##n, + +/** Generates table enum list entries for all channels of a + given type and channel number on TCC module. */ +#define _TCC_CHANNEL_ENUM_LIST(type) \ + MREPEAT(TCC_NUM_CHANNELS, _TCC_ENUM, type##_CHANNEL) +/** Generates table enum list entries for all output of a + given type and waveform output number on TCC module. */ +#define _TCC_WO_ENUM_LIST(type) \ + MREPEAT(TCC_NUM_WAVE_OUTPUTS, _TCC_ENUM, type) + + +#if TCC_ASYNC == true +/** Enum for the possible callback types for the TCC module. */ +enum tcc_callback { + /** Callback for TCC overflow */ + TCC_CALLBACK_OVERFLOW, + /** Callback for TCC Retrigger */ + TCC_CALLBACK_RETRIGGER, + /** Callback for TCC counter event */ + TCC_CALLBACK_COUNTER_EVENT, + /** Callback for capture overflow error */ + TCC_CALLBACK_ERROR, + /** Callback for Recoverable Fault A */ + TCC_CALLBACK_FAULTA, + /** Callback for Recoverable Fault B */ + TCC_CALLBACK_FAULTB, + /** Callback for Non-Recoverable Fault 0 */ + TCC_CALLBACK_FAULT0, + /** Callback for Non-Recoverable Fault 1 */ + TCC_CALLBACK_FAULT1, + +# if defined(__DOXYGEN__) + /** Channel callback type table for TCC + * + * Each TCC module may contain several callback types for channels; each + * channel will have its own callback type in the table, with the channel + * index number substituted for "n" in the channel callback type + * (e.g. \c TCC_MATCH_CAPTURE_CHANNEL_0). + */ + TCC_CALLBACK_CHANNEL_n = n, +# else + /** Callbacks for Match/Capture channels, e.g., TCC_CALLBACK_CHANNEL_0 */ + _TCC_CHANNEL_ENUM_LIST(CALLBACK) +# endif + +# if !defined(__DOXYGEN__) + /** Number of available callbacks */ + TCC_CALLBACK_N +# endif +}; +#endif /* #if TCC_ASYNC == true */ + +/** + * \name Module Status Flags + * + * TCC status flags, returned by \ref tcc_get_status() and cleared by + * \ref tcc_clear_status(). + * + * @{ + */ + +/** Timer channel \c ch (0 ~ 3) has matched against its compare value, + * or has captured a new value. + */ +#define TCC_STATUS_CHANNEL_MATCH_CAPTURE(ch) (1UL << (ch)) +/** Timer channel \c ch (0 ~ 3) match/compare output state. */ +#define TCC_STATUS_CHANNEL_OUTPUT(ch) (1UL << ((ch)+8)) +/** A Non-Recoverable Fault \c x (0 ~ 1) has occurred. */ +#define TCC_STATUS_NON_RECOVERABLE_FAULT_OCCUR(x) (1UL << ((x)+16)) +/** A Recoverable Fault \c n (0 ~ 1 representing A ~ B) has occured. */ +#define TCC_STATUS_RECOVERABLE_FAULT_OCCUR(n) (1UL << ((n)+18)) +/** The Non-Recoverable Fault \c x (0 ~ 1) input is present. */ +#define TCC_STATUS_NON_RECOVERABLE_FAULT_PRESENT(x) (1UL << ((x)+20)) +/** A Recoverable Fault \c n (0 ~ 1 representing A ~ B) is present. */ +#define TCC_STATUS_RECOVERABLE_FAULT_PRESENT(n) (1UL << ((n)+22)) +/** Timer registers synchronization has completed, and the synchronized count + * value may be read. + */ +#define TCC_STATUS_SYNC_READY (1UL << 23) +/** A new value was captured before the previous value was read, resulting in + * lost data. + */ +#define TCC_STATUS_CAPTURE_OVERFLOW (1UL << 24) +/** A counter event occurred. */ +#define TCC_STATUS_COUNTER_EVENT (1UL << 25) +/** A counter retrigger occurred. */ +#define TCC_STATUS_COUNTER_RETRIGGERED (1UL << 26) +/** The timer count value has overflowed from its maximum value to its minimum + * when counting upward, or from its minimum value to its maximum when + * counting downward. + */ +#define TCC_STATUS_COUNT_OVERFLOW (1UL << 27) +/** Ramp period cycle index. + * In ramp operation, each two period cycles are marked as cycle A and B, + * the index 0 represents cycle A and 1 represents cycle B. */ +#define TCC_STATUS_RAMP_CYCLE_INDEX (1UL << 28) +/** The counter has been stopped (due to disable, stop command, or one-shot). */ +#define TCC_STATUS_STOPPED (1UL << 29) + +/** @} */ + +/** + * \brief Index of the match capture channels + * + * This enum is used to specify which capture/match channel to do + * operations on. + */ +enum tcc_match_capture_channel { +# if defined(__DOXYGEN__) + /** Match capture channel index table for TCC + * + * Each TCC module may contain several match capture channels; each channel + * will have its own index in the table, with the index number substituted + * for "n" in the index name (e.g. \c TCC_MATCH_CAPTURE_CHANNEL_0). + */ + TCC_MATCH_CAPTURE_CHANNEL_n = n, +# else + /** Indexes of match capture channels, e.g., TCC_MATCH_CAPTURE_CHANNEL_0 */ + _TCC_CHANNEL_ENUM_LIST(MATCH_CAPTURE) +# endif +# if !defined(__DOXYGEN__) + /** Number of supported channels */ + TCC_MATCH_CAPTURE_CHANNEL_N +# endif +}; + +/** + * \brief Index of the wave outputs + * + * This enum is used to specify which wave output to do + * operations on. + */ +enum tcc_wave_output { +# if defined(__DOXYGEN__) + /** Waveform output index table for TCC + * + * Each TCC module may contain several wave outputs; each output + * will have its own index in the table, with the index number substituted + * for "n" in the index name (e.g. \c TCC_WAVE_OUTPUT_0). + */ + TCC_WAVE_OUTPUT_n = n, +# else + /** Indexes of match capture channels, e.g., TCC_WAVEFORM_OUTPUT_0 */ + _TCC_WO_ENUM_LIST(WAVE_OUTPUT) +# endif +# if !defined(__DOXYGEN__) + /** Number of supported channels */ + TCC_WAVE_OUTPUT_N +# endif +}; + +/** + * \brief TCC wave generation mode enum + * + * This enum is used to specify the waveform generation mode. + * + */ +enum tcc_wave_generation { + /** Normal Frequency: Top is the PER register, output toggled on each + * compare match */ + TCC_WAVE_GENERATION_NORMAL_FREQ = 0, + /** Match Frequency: Top is CC0 register, output toggles on each update + * condition */ + TCC_WAVE_GENERATION_MATCH_FREQ = 1, + /** Single-Slope PWM: Top is the PER register, CCx controls duty cycle + * (output active when count is greater than CCx) */ + TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM = 2, + + /** Double-slope (count up and down), non centre-aligned: Top is the PER + * register, CC[x] controls duty cycle while counting up and CC[x+N/2] + * controls it while counting down */ + TCC_WAVE_GENERATION_DOUBLE_SLOPE_CRITICAL = 4, + /** Double-slope (count up and down), interrupt/event at Bottom (Top is the + * PER register, output active when count is greater than CCx) */ + TCC_WAVE_GENERATION_DOUBLE_SLOPE_BOTTOM = 5, + /** Double-slope (count up and down), interrupt/event at Bottom and Top: (Top is the + * PER register, output active when count is lower than CCx) */ + TCC_WAVE_GENERATION_DOUBLE_SLOPE_BOTH = 6, + /** Double-slope (count up and down), interrupt/event at Top (Top is the + * PER register, output active when count is greater than CCx) */ + TCC_WAVE_GENERATION_DOUBLE_SLOPE_TOP = 7, +}; + +/** + * \brief Polarity of TCC wave generation on channels + * + * Specifies whether the wave output needs to be inverted or not. + */ +enum tcc_wave_polarity { + /** Wave output is not inverted */ + TCC_WAVE_POLARITY_0, + /** Wave output is inverted */ + TCC_WAVE_POLARITY_1 +}; + +/** + * \brief TCC pattern generator for outputs + * + * Used when disabling output pattern or when selecting a specific pattern. + */ +enum tcc_output_pattern { + /** SWAP output pattern is not used */ + TCC_OUTPUT_PATTERN_DISABLE, + /** Pattern 0 is applied to SWAP output */ + TCC_OUTPUT_PATTERN_0, + /** Pattern 1 is applied to SWAP output */ + TCC_OUTPUT_PATTERN_1 +}; + +/** + * \brief Ramp Operations which are supported in single-slope PWM generation + * + * Ramp operations which are supported in single-slope PWM generation. + */ +enum tcc_ramp { + /** Default timer/counter PWM operation */ + TCC_RAMP_RAMP1 = 0, + + /** Uses a single channel (CC0) to control both CC0/CC1 compare outputs. + * In cycle A, the channel 0 output is disabled, and + * in cycle B, the channel 1 output is disabled. */ + TCC_RAMP_RAMP2A, + + /** Uses channels CC0 and CC1 to control compare outputs. + * In cycle A, the channel 0 output is disabled, and + * in cycle B, the channel 1 output is disabled.*/ + TCC_RAMP_RAMP2 +}; + +/** + * \brief Ramp Index for TCC wave generation + * + * In ramp operation, each two period cycles are marked as cycle A and B, + * the index 0 represents cycle A and 1 represents cycle B. + */ +enum tcc_ramp_index { + /** Default, cycle index toggles. */ + TCC_RAMP_INDEX_DEFAULT, + /** Force next cycle to be cycle B (set to 1) */ + TCC_RAMP_INDEX_FORCE_B, + /** Force next cycle to be cycle A (clear to 0) */ + TCC_RAMP_INDEX_FORCE_A, + /** Force next cycle keeping the same as current */ + TCC_RAMP_INDEX_FORCE_KEEP +}; + +/** + * \brief TCC output inversion + * + * Used when enabling or disabling output inversion. + */ +enum tcc_output_invertion { + /** Output inversion not to be enabled */ + TCC_OUTPUT_INVERTION_DISABLE, + /** Invert the output from WO[x] */ + TCC_OUTPUT_INVERTION_ENABLE +}; + +/** + * \brief TCC Counter reload action enum + * + * This enum specify how the counter is reloaded and whether the prescaler + * should be restarted. + */ +enum tcc_reload_action { + /** The counter is reloaded/reset on the next GCLK and starts + * counting on the prescaler clock + */ + TCC_RELOAD_ACTION_GCLK, + /** The counter is reloaded/reset on the next prescaler clock + */ + TCC_RELOAD_ACTION_PRESC, + /** The counter is reloaded/reset on the next GCLK, and the + * prescaler is restarted as well + */ + TCC_RELOAD_ACTION_RESYNC +}; + + +/** + * \brief TCC clock prescaler values + * + * This enum is used to choose the clock prescaler + * configuration. The prescaler divides the clock frequency of the TCC + * module to operate TCC at a slower clock rate. + */ +enum tcc_clock_prescaler { + /** Divide clock by 1 */ + TCC_CLOCK_PRESCALER_DIV1, + /** Divide clock by 2 */ + TCC_CLOCK_PRESCALER_DIV2, + /** Divide clock by 4 */ + TCC_CLOCK_PRESCALER_DIV4, + /** Divide clock by 8 */ + TCC_CLOCK_PRESCALER_DIV8, + /** Divide clock by 16 */ + TCC_CLOCK_PRESCALER_DIV16, + /** Divide clock by 64 */ + TCC_CLOCK_PRESCALER_DIV64, + /** Divide clock by 256 */ + TCC_CLOCK_PRESCALER_DIV256, + /** Divide clock by 1024 */ + TCC_CLOCK_PRESCALER_DIV1024 +}; + +/** + * \brief TCC module count direction + * + * Used when selecting the Timer/Counter count direction. + */ +enum tcc_count_direction { + /** Timer should count upward */ + TCC_COUNT_DIRECTION_UP, + /** Timer should count downward */ + TCC_COUNT_DIRECTION_DOWN, +}; + +#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER +/** + * \brief TCC module counter overflow DMA request mode + * + * Used when selecting the Timer/Counter overflow DMA request mode. + */ +enum tcc_count_overflow_dma_trigger_mode { + /** TCC generates a DMA request on each cycle when an update condition + * is detected + */ + TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_CONTINUE, + /** When an update condition is detected, the TCC generates a DMA trigger + * on the cycle following the DMA One-Shot Command written to the Control + * B register + */ + TCC_COUNT_OVERFLOW_DMA_TRIGGER_MODE_ONE_SHOT, +}; +#endif + +/** + * \brief Action to perform when the TCC module is triggered by events + * + * Event action to perform when the module is triggered by events. + */ +enum tcc_event_action { + /** No event action */ + TCC_EVENT_ACTION_OFF, + /** Stop counting, the counter will maintain its current value, waveforms + * are set to a defined Non-Recoverable State output + * (\ref tcc_non_recoverable_state_output). */ + TCC_EVENT_ACTION_STOP, + /** Re-trigger counter on event, may generate an event if the re-trigger + * event output is enabled. + * \note When re-trigger event action is enabled, enabling the counter + * will not start until the next incoming event appears. */ + TCC_EVENT_ACTION_RETRIGGER, + + /** Start counter when previously stopped. + * Start counting on the event rising edge. Further events will not + * restart the counter; + * the counter keeps on counting using prescaled GCLK_TCCx, until it + * reaches TOP or Zero + * depending on the direction. */ + TCC_EVENT_ACTION_START, + /** Count events; i.e. Increment or decrement depending on count + * direction. */ + TCC_EVENT_ACTION_COUNT_EVENT, + /** The event source must be an asynchronous event, input value will + * overrides the direction settings (input low: counting up, input high: + * counting down). */ + TCC_EVENT_ACTION_DIR_CONTROL, + /** Increment the counter on event, irrespective of count direction */ + TCC_EVENT_ACTION_INCREMENT, + /** Decrement the counter on event, irrespective of count direction */ + TCC_EVENT_ACTION_DECREMENT, + /** Count during active state of asynchronous event. In this case, + * depending on the count direction, the count will be incremented + * or decremented on each prescaled GCLK_TCCx, as long as the input + * event remains active. */ + TCC_EVENT_ACTION_COUNT_DURING_ACTIVE, + + /** Store period in capture register 0, pulse width in capture + * register 1 + */ + TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURE, + /** Store pulse width in capture register 0, period in capture + * register 1 + */ + TCC_EVENT_ACTION_PULSE_WIDTH_PERIOD_CAPTURE, + + /** Generate Non-Recoverable Fault on event */ + TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT, +}; + + +/** + * \brief Action to be performed when the TCC module is triggered by event0 + * + * Event action to perform when the module is triggered by event0. + */ +enum tcc_event0_action { + /** No event action */ + TCC_EVENT0_ACTION_OFF = TCC_EVENT_ACTION_OFF, + /** Re-trigger Counter on event */ + TCC_EVENT0_ACTION_RETRIGGER = TCC_EVENT_ACTION_RETRIGGER, + /** Count events (increment or decrement, depending on count direction) + */ + TCC_EVENT0_ACTION_COUNT_EVENT = TCC_EVENT_ACTION_COUNT_EVENT, + /** Start counter on event */ + TCC_EVENT0_ACTION_START = TCC_EVENT_ACTION_START, + /** Increment counter on event */ + TCC_EVENT0_ACTION_INCREMENT = TCC_EVENT_ACTION_INCREMENT, + /** Count during active state of asynchronous event */ + TCC_EVENT0_ACTION_COUNT_DURING_ACTIVE = TCC_EVENT_ACTION_COUNT_DURING_ACTIVE, + + /** Generate Non-Recoverable Fault on event */ + TCC_EVENT0_ACTION_NON_RECOVERABLE_FAULT = TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT +}; + +/** + * \brief Action to perform when the TCC module is triggered by event1 + * + * Event action to perform when the module is triggered by event1. + */ +enum tcc_event1_action { + /** No event action */ + TCC_EVENT1_ACTION_OFF = TCC_EVENT_ACTION_OFF, + /** Re-trigger Counter on event */ + TCC_EVENT1_ACTION_RETRIGGER = TCC_EVENT_ACTION_RETRIGGER, + /** The event source must be an asynchronous event, and the input value + * will override the direction settings. + * If TCEINVx is 0 and input event is LOW: counter will count up. + * If TCEINVx is 0 and input event is HIGH: counter will count down. + */ + TCC_EVENT1_ACTION_DIR_CONTROL = TCC_EVENT_ACTION_DIR_CONTROL, + /** Stop counter on event */ + TCC_EVENT1_ACTION_STOP = TCC_EVENT_ACTION_STOP, + /** Decrement on event */ + TCC_EVENT1_ACTION_DECREMENT = TCC_EVENT_ACTION_DECREMENT, + + /** Store period in capture register 0, pulse width in capture + * register 1 + */ + TCC_EVENT1_ACTION_PERIOD_PULSE_WIDTH_CAPTURE = TCC_EVENT_ACTION_PERIOD_PULSE_WIDTH_CAPTURE, + /** Store pulse width in capture register 0, period in capture + * register 1 + */ + TCC_EVENT1_ACTION_PULSE_WIDTH_PERIOD_CAPTURE = TCC_EVENT_ACTION_PULSE_WIDTH_PERIOD_CAPTURE, + + /** Generate Non-Recoverable Fault on event */ + TCC_EVENT1_ACTION_NON_RECOVERABLE_FAULT = TCC_EVENT_ACTION_NON_RECOVERABLE_FAULT +}; + +/** + * \brief On which part of the counter cycle the counter event output is generated + * + * This enum is used to define the point at which the counter event is generated. + */ +enum tcc_event_generation_selection { + /** Counter Event is generated when a new counter cycle starts */ + TCC_EVENT_GENERATION_SELECTION_START, + /** Counter Event is generated when a counter cycle ends */ + TCC_EVENT_GENERATION_SELECTION_END, + /** Counter Event is generated when a counter cycle ends, except for the + * first and last cycles */ + TCC_EVENT_GENERATION_SELECTION_BETWEEN, + /** Counter Event is generated when a new counter cycle starts or ends */ + TCC_EVENT_GENERATION_SELECTION_BOUNDARY +}; + +/** + * \brief TCC channel operation modes + * + * To set a timer channel either in compare or in capture mode. + */ +enum tcc_channel_function { + /** TCC channel performs compare operation */ + TCC_CHANNEL_FUNCTION_COMPARE, + /** TCC channel performs capture operation */ + TCC_CHANNEL_FUNCTION_CAPTURE +}; + +/** + * \brief TCC (recoverable) fault Halt action + */ +enum tcc_fault_halt_action { + /** Halt action disabled. */ + TCC_FAULT_HALT_ACTION_DISABLE, + /** Hardware halt action, counter is halted until restart */ + TCC_FAULT_HALT_ACTION_HW_HALT, + /** Software halt action, counter is halted until fault bit cleared */ + TCC_FAULT_HALT_ACTION_SW_HALT, + /** Non-Recoverable fault, force output to pre-defined level */ + TCC_FAULT_HALT_ACTION_NON_RECOVERABLE +}; + +/** + * \brief TCC (recoverable) fault Capture action + */ +enum tcc_fault_capture_action { + /** Capture disabled */ + TCC_FAULT_CAPTURE_DISABLE, + /** Capture on Fault, each value is captured */ + TCC_FAULT_CAPTURE_EACH, + /** Capture the minimum detection, but notify on smaller ones */ + TCC_FAULT_CAPTURE_MINIMUM, + /** Capture the maximum detection, but notify on bigger ones */ + TCC_FAULT_CAPTURE_MAXIMUM, + /** Capture if the value is smaller than last, notify event or interrupt + * if previous stamp is confirmed to be "local minimum" (not bigger than + * current stamp). */ + TCC_FAULT_CAPTURE_SMALLER, + /** Capture if the value is bigger than last, notify event or interrupt + * if previous stamp is confirmed to be "local maximum" (not smaller than + * current stamp). */ + TCC_FAULT_CAPTURE_BIGGER, + /** Capture if the time stamps changes its increment direction */ + TCC_FAULT_CAPTURE_CHANGE +}; + +/** + * \brief Capture Channel triggered by TCC (recoverable) fault + */ +enum tcc_fault_capture_channel { + /** Recoverable fault triggers channel 0 capture operation */ + TCC_FAULT_CAPTURE_CHANNEL_0, + /** Recoverable fault triggers channel 1 capture operation */ + TCC_FAULT_CAPTURE_CHANNEL_1, + /** Recoverable fault triggers channel 2 capture operation */ + TCC_FAULT_CAPTURE_CHANNEL_2, + /** Recoverable fault triggers channel 3 capture operation */ + TCC_FAULT_CAPTURE_CHANNEL_3 +}; + +/** + * \brief TCC (recoverable) fault Input Source + */ +enum tcc_fault_source { + /** Fault input is disabled */ + TCC_FAULT_SOURCE_DISABLE, + /** Match Capture Event x (x=0,1) input */ + TCC_FAULT_SOURCE_ENABLE, + /** Inverted MCEx (x=0,1) event input */ + TCC_FAULT_SOURCE_INVERT, + /** Alternate fault (A or B) state at the end of the previous period */ + TCC_FAULT_SOURCE_ALTFAULT +}; + +/** + * \brief TCC (recoverable) fault Input Blanking Start Point + */ +enum tcc_fault_blanking { + /** No blanking */ + TCC_FAULT_BLANKING_DISABLE, + /** Blanking applied from rising edge of the output waveform */ + TCC_FAULT_BLANKING_RISING_EDGE, + /** Blanking applied from falling edge of the output waveform */ + TCC_FAULT_BLANKING_FALLING_EDGE, + /** Blanking applied from each toggle of the output waveform */ + TCC_FAULT_BLANKING_BOTH_EDGE +}; + +/** + * \brief TCC (recoverable) fault Input Qualification Action + */ +enum tcc_fault_qualification { + /** The input is not disabled on compare condition */ + TCC_FAULT_QUALIFICATION_DISABLE, + /** The input is disabled when match output signal is at inactive level */ + TCC_FAULT_QUALIFICATION_BY_OUTPUT +}; + +/** + * \brief TCC (recoverable) fault Output Keep Action + */ +enum tcc_fault_keep { + /** Disable keeping, wave output released as soon as fault is released */ + TCC_FAULT_KEEP_DISABLE, + /** Keep wave output until end of TCC cycle */ + TCC_FAULT_KEEP_TILL_END +}; + +/** + * \brief TCC Non-recoverable State Outupt + */ +enum tcc_fault_state_output { + /** Non-recoverable fault output is tri-stated */ + TCC_FAULT_STATE_OUTPUT_OFF, + /** Non-recoverable fault force output 0 */ + TCC_FAULT_STATE_OUTPUT_0, + /** Non-recoverable fault force output 1 */ + TCC_FAULT_STATE_OUTPUT_1 +}; + +/** + * \brief TCC (recoverable) fault Restart Action + */ +enum tcc_fault_restart { + /** Restart Action disabled */ + TCC_FAULT_RESTART_DISABLE, + /** Restart Action enabled */ + TCC_FAULT_RESTART_ENABLE +}; + +/** + * \brief Configuration struct for TCC module recoverable fault + */ +struct tcc_recoverable_fault_config { + /** Fault filter value applied on MCEx event input line (0x0 ~ 0xF). + * Must be 0 when MCEx event is used as synchronous event. + * Apply to both recoverable and non-recoverable fault. */ + uint8_t filter_value; + /** Fault blanking value (0 ~ 255), disable input source for several TCC + * clocks after the detection of the waveform edge */ + uint8_t blanking_cycles; + + /** Set to \c true to enable restart action */ + bool restart; + /** Set to \c true to enable keep action (keep until end of TCC cycle) */ + bool keep; + + /** Set to \c true to enable input qualification + * (disable input when output is inactive) */ + bool qualification; + + /** Specifies if the event input generates recoverable Fault. + * The event system channel connected to MCEx event input must be + * configured as asynchronous. + */ + enum tcc_fault_source source; + /** Fault Blanking Start Point for recoverable Fault */ + enum tcc_fault_blanking blanking; + + /** Halt action for recoverable Fault */ + enum tcc_fault_halt_action halt_action; + /** Capture action for recoverable Fault */ + enum tcc_fault_capture_action capture_action; + /** Channel triggered by recoverable Fault */ + enum tcc_fault_capture_channel capture_channel; +}; + +/** + * \brief Configuration struct for TCC module non-recoverable fault + */ +struct tcc_non_recoverable_fault_config { + /** Fault filter value applied on TCEx event input line (0x0 ~ 0xF). + * Must be 0 when TCEx event is used as synchronous event. */ + uint8_t filter_value; + /** Output */ + enum tcc_fault_state_output output; +}; + +/** + * \brief TCC input event enable/disable/configure structure + * + * For configuring an input event. + */ +struct tcc_input_event_config { + /** Event action on incoming event */ + enum tcc_event_action action; + /** Modify event action */ + bool modify_action; + /** Invert incoming event input line */ + bool invert; +}; + +/** + * \brief TCC output event enable/disable/configure structure + * + * Structure used for configuring an output event. + */ +struct tcc_output_event_config { + /** It decides which part of the counter cycle the counter event output + * is generated */ + enum tcc_event_generation_selection generation_selection; + /** A switch to allow enable/disable of events, without modifying the + * event output configuration + */ + bool modify_generation_selection; +}; + +/** + * \brief TCC event enable/disable structure + * + * Event flags for the \ref tcc_enable_events() and \ref tcc_disable_events(). + */ +struct tcc_events { + /** Input events configuration */ + struct tcc_input_event_config input_config[2]; + /** Output event configuration */ + struct tcc_output_event_config output_config; + + /** Perform the configured event action when an incoming event is + * signalled */ + bool on_input_event_perform_action[2]; + + /** Perform the configured event action when an incoming channel event is + * signalled */ + bool on_event_perform_channel_action[TCC_NUM_CHANNELS]; + /** Generate an output event on a channel capture/match. + * Specify which channels will generate events */ + bool generate_event_on_channel[TCC_NUM_CHANNELS]; + + /** Generate an output event on counter overflow/underflow */ + bool generate_event_on_counter_overflow; + /** Generate an output event on counter retrigger */ + bool generate_event_on_counter_retrigger; + /** Generate an output event on counter boundary. + * See \ref tcc_event_output_action. */ + bool generate_event_on_counter_event; +}; + +/** + * \brief Configuration struct for the TCC module base counter + * + * Structure for configuring a TCC as a counter. + */ +struct tcc_counter_config { + /** Value to initialize the count register */ + uint32_t count; + /** Period/top and period/top buffer values for counter */ + uint32_t period; + + /** When \c true, the counter will be stopped on the next hardware or + * software re-trigger event or overflow/underflow + */ + bool oneshot; + +#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER + /** Counter overflow trigger a DMA request mode */ + enum tcc_count_overflow_dma_trigger_mode dma_trigger_mode; +#endif + + /** Specifies the direction for the TCC to count */ + enum tcc_count_direction direction; + + /** GCLK generator used to clock the peripheral */ + enum gclk_generator clock_source; + /** Specifies the prescaler value for GCLK_TCC */ + enum tcc_clock_prescaler clock_prescaler; + /** Specifies the reload or reset time of the counter and prescaler + * resynchronization on a re-trigger event for the TCC + */ + enum tcc_reload_action reload_action; +}; + +/** + * \brief Configuration struct for the TCC module capture + * + * Structure used when configuring TCC channels in capture mode. + */ +struct tcc_capture_config { + /** Channel functions selection (capture/match) */ + enum tcc_channel_function channel_function[TCC_NUM_CHANNELS]; +}; + +/** + * \brief Configuration struct for the TCC module match/wave generation + * + * The structure, which helps to configure a TCC channel for compare + * operation and wave generation. + */ +struct tcc_match_wave_config { + /** Channel functions selection (capture/match) */ + enum tcc_channel_function channel_function[TCC_NUM_CHANNELS]; + + /** Specifies polarity for match output waveform generation */ + enum tcc_wave_polarity wave_polarity[TCC_NUM_CHANNELS]; + /** Specifies which waveform generation mode to use */ + enum tcc_wave_generation wave_generation; + /** Specifies Ramp mode for waveform generation */ + enum tcc_ramp wave_ramp; + + /** Value to be used for compare match on each channel */ + uint32_t match[TCC_NUM_CHANNELS]; +}; + +/** + * \brief Configuration struct for the TCC module waveform extension + * + * This structure is used to specify the waveform extension features for TCC. + */ +struct tcc_wave_extension_config { + /** Configuration for recoverable faults */ + struct tcc_recoverable_fault_config + recoverable_fault[TCC_NUM_FAULTS]; + /** Configuration for non-recoverable faults */ + struct tcc_non_recoverable_fault_config + non_recoverable_fault[TCC_NUM_WAVE_OUTPUTS]; + + /** Invert waveform final outputs lines */ + bool invert[TCC_NUM_WAVE_OUTPUTS]; +}; + +/** + * \brief Configuration struct for the TCC module output pins + * + * Structure which is used when taking wave output from TCC. + */ +struct tcc_pins_config { + /** Specifies pin output for each channel */ + uint32_t wave_out_pin[TCC_NUM_WAVE_OUTPUTS]; + /** Specifies MUX setting for each output channel pin */ + uint32_t wave_out_pin_mux[TCC_NUM_WAVE_OUTPUTS]; + /** When \c true, PWM output pin for the given channel is enabled */ + bool enable_wave_out_pin[TCC_NUM_WAVE_OUTPUTS]; +}; + +/** + * \brief TCC configuration structure + * + * Configuration struct for a TCC instance. This structure should be + * initialized by the \ref tcc_get_config_defaults function before being + * modified by the user application. + */ +struct tcc_config { + /** Structure for configuring TCC base timer/counter */ + struct tcc_counter_config counter; + /** TCC match/capture configurations */ + union { + /** Helps to configure a TCC channel in capture mode */ + struct tcc_capture_config capture; + /** For configuring a TCC channel in compare mode */ + struct tcc_match_wave_config compare; + /** Serves the same purpose as compare. Used as an alias for + * compare, + * when a TCC channel is configured for wave generation */ + struct tcc_match_wave_config wave; + }; + + /** Structure for configuring TCC waveform extension */ + struct tcc_wave_extension_config wave_ext; + + /** Structure for configuring TCC output pins */ + struct tcc_pins_config pins; + + /** Set to \c true to enable double buffering write. When enabled any write + * through \ref tcc_set_top_value(), \ref tcc_set_compare_value() and + * \ref tcc_set_pattern() will direct to the buffer register as buffered + * value, and the buffered value will be committed to effective register + * on UPDATE condition, if update is not locked. + * + * \note The init values in \ref tcc_config for \ref tcc_init are always + * filled to effective registers, no matter if double buffering is + * enabled or not. + */ + bool double_buffering_enabled; + + /** When \c true the module is enabled during standby */ + bool run_in_standby; +}; + +#if TCC_ASYNC == true +/* Forward Declaration for the device instance. */ +struct tcc_module; + +/** Type definition for the TCC callback function. */ +typedef void (*tcc_callback_t)(struct tcc_module *const module); +#endif + +/** + * \brief TCC software device instance structure + * + * TCC software instance structure, used to retain software state information + * of an associated hardware module instance. + * + * \note The fields of this structure should not be altered by the user + * application; they are reserved only for module-internal use. + */ +struct tcc_module { + /** Hardware module pointer of the associated Timer/Counter peripheral. */ + Tcc *hw; + +# if TCC_ASYNC == true + /** Array of callbacks */ + tcc_callback_t callback[TCC_CALLBACK_N]; + /** Bit mask for callbacks registered */ + uint32_t register_callback_mask; + /** Bit mask for callbacks enabled */ + uint32_t enable_callback_mask; +# endif + + /** Set to \c true to write to buffered registers */ + bool double_buffering_enabled; +}; + +#if !defined(__DOXYGEN__) +uint8_t _tcc_get_inst_index( + Tcc *const hw); +#endif + +/** + * \name Driver Initialization and Configuration + * @{ + */ + +/** + * \brief Determines if the hardware module is currently synchronizing to the bus + * + * Checks to see if the underlying hardware peripheral module is currently + * synchronizing across multiple clock domains to the hardware bus. This + * function can be used to delay further operations on a module until such time + * that it is ready, to prevent blocking delays for synchronization in the + * user application. + * + * \param[in] module_inst Pointer to the software module instance struct + * + * \return Synchronization status of the underlying hardware module. + * + * \retval false If the module has completed synchronization + * \retval true If the module synchronization is ongoing + */ +static inline bool tcc_is_syncing( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + return (module_inst->hw->SYNCBUSY.reg > 0); +} + + +void tcc_get_config_defaults( + struct tcc_config *const config, + Tcc *const hw); + +enum status_code tcc_init( + struct tcc_module *const module_inst, + Tcc *const hw, + const struct tcc_config *const config); + +/** @} */ + +/** + * \name Event Management + * @{ + */ + +enum status_code tcc_enable_events( + struct tcc_module *const module_inst, + struct tcc_events *const events); + +void tcc_disable_events( + struct tcc_module *const module_inst, + struct tcc_events *const events); + +/** @} */ + +/** + * \name Enable/Disable/Reset + * @{ + */ + +/** + * \brief Enable the TCC module + * + * Enables a TCC module that has been previously initialized. The counter will + * start when the counter is enabled. + * + * \note When the counter is configured to re-trigger on an event, the counter + * will not start until the next incoming event appears. Then it + * restarts on any following event. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tcc_enable( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_ENABLE) { + /* Wait for sync */ + } + + /* Enable the TCC module */ + tcc_module->CTRLA.reg |= TCC_CTRLA_ENABLE; +} + +/** + * \brief Disables the TCC module + * + * Disables a TCC module and stops the counter. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tcc_disable( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_ENABLE) { + /* Wait for sync */ + } + + /* Disbale interrupt */ + tcc_module->INTENCLR.reg = TCC_INTENCLR_MASK; + /* Clear interrupt flag */ + tcc_module->INTFLAG.reg = TCC_INTFLAG_MASK; + + /* Disable the TCC module */ + tcc_module->CTRLA.reg &= ~TC_CTRLA_ENABLE; +} + +/** + * \brief Resets the TCC module + * + * Resets the TCC module, restoring all hardware module registers to their + * default values and disabling the module. The TCC module will not be + * accessible while the reset is being performed. + * + * \note When resetting a 32-bit counter only the master TCC module's instance + * structure should be passed to the function. + * + * \param[in] module_inst Pointer to the software module instance struct + * + */ +static inline void tcc_reset( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + /* Disable this module if it is running */ + if (tcc_module->CTRLA.reg & TCC_CTRLA_ENABLE) { + tcc_disable(module_inst); + while (tcc_is_syncing(module_inst)) { + /* wait while module is disabling */ + } + } + + /* Reset this TC module */ + tcc_module->CTRLA.reg |= TCC_CTRLA_SWRST; +} + +/** @} */ + + +/** + * \name Set/Toggle Count Direction + * @{ + */ + +/** + * \brief Sets the TCC module count direction + * + * Sets the count direction of an initialized TCC module. The + * specified TCC module can remain running or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] dir New timer count direction to set + */ +static inline void tcc_set_count_direction( + const struct tcc_module *const module_inst, + enum tcc_count_direction dir) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + + /* Set count direction */ + if (TCC_COUNT_DIRECTION_DOWN == dir) { + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_DIR; + return; + } + tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_DIR; +} + +/** + * \brief Toggles the TCC module count direction + * + * Toggles the count direction of an initialized TCC module. The + * specified TCC module can remain running or stopped. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tcc_toggle_count_direction( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + bool dir_value_1 = tcc_module->CTRLBSET.bit.DIR; + if (dir_value_1) { + tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_DIR; + } else { + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_DIR; + } +} + +/** @} */ + +/** + * \name Get/Set Count Value + * @{ + */ + +uint32_t tcc_get_count_value( + const struct tcc_module *const module_inst); + +enum status_code tcc_set_count_value( + const struct tcc_module *const module_inst, + const uint32_t count); + +/** @} */ + +/** + * \name Stop/Restart Counter + * @{ + */ + +/** + * \brief Stops the counter + * + * This function will stop the counter. When the counter is stopped + * the value in the count register is set to 0 if the counter was + * counting up, or maximum or the top value if the counter was counting + * down. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tcc_stop_counter( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + uint32_t last_cmd; + + /* Wait until last command is done */ + do { + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk; + if (last_cmd == TCC_CTRLBSET_CMD_NONE) { + break; + } else if (last_cmd == TCC_CTRLBSET_CMD_STOP) { + /* Command have been issued */ + return; + } else if (last_cmd == TCC_CTRLBSET_CMD_RETRIGGER) { + /* Cancel RETRIGGER command and issue STOP */ + tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_CMD_Msk; + } + } while (1); + + /* Write command to execute */ + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_STOP; +} + +/** + * \brief Starts the counter from beginning + * + * Restarts an initialized TCC module's counter. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tcc_restart_counter( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + uint32_t last_cmd; + + /* Wait until last command is done */ + do { + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk; + if (last_cmd == TCC_CTRLBSET_CMD_NONE) { + break; + } else if (last_cmd == TCC_CTRLBSET_CMD_RETRIGGER) { + /* Command have been issued */ + return; + } else if (last_cmd == TCC_CTRLBSET_CMD_STOP) { + /* Cancel STOP command and issue RETRIGGER */ + tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_CMD_Msk; + } + } while (1); + + /* Write command to execute */ + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_RETRIGGER; +} + +/** @} */ + +#ifdef FEATURE_TCC_GENERATE_DMA_TRIGGER +/** + * \name Generate TCC DMA Triggers Command + * @{ + */ + +/** + * \brief TCC DMA Trigger. + * + * TCC DMA trigger command. + * + * \param[in] module_inst Pointer to the software module instance struct + */ +static inline void tcc_dma_trigger_command( + const struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + + /* Make certain that there are no conflicting commands in the register */ + tcc_module->CTRLBCLR.reg = TCC_CTRLBCLR_CMD_NONE; + + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + +#if !(SAML21 || SAML22 || SAMR30 || SAMR34 || SAMR35 || WLR089) + /* Write command to execute */ + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_DMATRG; +#endif + +#if (SAML21XXXB) || (SAML22) || (SAMR30) || (SAMR34) || (SAMR35) || (WLR089) + /* Write command to execute */ + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_DMAOS; +#endif +} +/** @} */ +#endif + +/** + * \name Get/Set Compare/Capture Register + * @{ + */ + +uint32_t tcc_get_capture_value( + const struct tcc_module *const module_inst, + const enum tcc_match_capture_channel channel_index); + +enum status_code tcc_set_compare_value( + const struct tcc_module *const module_inst, + const enum tcc_match_capture_channel channel_index, + const uint32_t compare); + +/** @} */ + +/** + * \name Set Top Value + * @{ + */ + +enum status_code tcc_set_top_value( + const struct tcc_module *const module_inst, + const uint32_t top_value); + +/** @} */ + + +/** + * \name Set Output Pattern + * @{ + */ + +enum status_code tcc_set_pattern( + const struct tcc_module *const module_inst, + const uint32_t line_index, + const enum tcc_output_pattern pattern); + +/** @} */ + + +/** + * \name Set Ramp Index + * @{ + */ + +/** + * \brief Sets the TCC module ramp index on next cycle + * + * In RAMP2 and RAMP2A operation, we can force either cycle A or cycle B at + * the output, on the next clock cycle. + * When ramp index command is disabled, cycle A and cycle B will appear at + * the output, on alternate clock cycles. + * See \ref tcc_ramp. + * + * \param[in] module_inst Pointer to the software module instance struct + * \param[in] ramp_index Ramp index (\ref tcc_ramp_index) of the next cycle + */ +static inline void tcc_set_ramp_index( + const struct tcc_module *const module_inst, + const enum tcc_ramp_index ramp_index) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + uint32_t last_cmd; + + /* Wait until last command is done */ + do { + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + if (TCC_RAMP_INDEX_DEFAULT == ramp_index) { + /* Cancel pending command */ + tcc_module->CTRLBCLR.reg = TCC_CTRLBSET_IDXCMD_HOLD; + return; + } + last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_IDXCMD_Msk; + if (last_cmd == TCC_CTRLBSET_IDXCMD_DISABLE) { + break; + } else if (last_cmd == TCC_CTRLBSET_IDXCMD(ramp_index)) { + /* Command have been issued */ + return; + } + } while (1); + + /* Write command to execute */ + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_IDXCMD(ramp_index); +} + +/** @} */ + +/** + * \name Status Management + * @{ + */ + +/** + * \brief Checks if the timer/counter is running + * + * \param[in] module_inst Pointer to the TCC software instance struct + * + * \return Status which indicates whether the module is running. + * + * \retval true The timer/counter is running + * \retval false The timer/counter is stopped + */ +static inline bool tcc_is_running( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + return !module_inst->hw->STATUS.bit.STOP; +} + +uint32_t tcc_get_status( + struct tcc_module *const module_inst); + +void tcc_clear_status( + struct tcc_module *const module_inst, + const uint32_t status_flags); + +/** @} */ + +/** + * \name Double Buffering Management + * @{ + */ + +/** + * \brief Enable TCC double buffering write + * + * When double buffering write is enabled, the following function will write + * values to buffered registers instead of effective ones (buffered): + * - PERB: through \ref tcc_set_top_value() + * - CCBx(x is 0~3): through \ref tcc_set_compare_value() + * - PATTB: through \ref tcc_set_pattern() + * + * Then, on UPDATE condition the buffered registers are committed to regular ones + * to take effect. + * + * \param[in] module_inst Pointer to the TCC software instance struct + */ +static inline void tcc_enable_double_buffering( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + + module_inst->double_buffering_enabled = true; +} + +/** + * \brief Disable TCC double buffering Write + * + * When double buffering write is disabled, following function will write values + * to effective registers (not buffered): + * - PER: through \ref tcc_set_top_value() + * - CCx(x is 0~3): through \ref tcc_set_compare_value() + * - PATT: through \ref tcc_set_pattern() + * + * \note This function does not lock double buffer update, which means on next + * UPDATE condition the last written buffered values will be committed to + * take effect. Invoke \ref tcc_lock_double_buffer_update() before this + * function to disable double buffering update, if this change is not + * expected. + * + * \param[in] module_inst Pointer to the TCC software instance struct + */ +static inline void tcc_disable_double_buffering( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + module_inst->double_buffering_enabled = false; +} + +/** + * \brief Lock the TCC double buffered registers updates + * + * Locks the double buffered registers so they will not be updated through + * their buffered values on UPDATE conditions. + * + * \param[in] module_inst Pointer to the TCC software instance struct + * + */ +static inline void tcc_lock_double_buffer_update( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + while (module_inst->hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + module_inst->hw->CTRLBSET.reg = TCC_CTRLBSET_LUPD; +} + +/** + * \brief Unlock the TCC double buffered registers updates + * + * Unlock the double buffered registers so they will be updated through + * their buffered values on UPDATE conditions. + * + * \param[in] module_inst Pointer to the TCC software instance struct + * + */ +static inline void tcc_unlock_double_buffer_update( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + while (module_inst->hw->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + module_inst->hw->CTRLBCLR.reg = TCC_CTRLBCLR_LUPD; +} + +/** + * \brief Force the TCC double buffered registers to update once + * + * \param[in] module_inst Pointer to the TCC software instance struct + * + */ +static inline void tcc_force_double_buffer_update( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + /* Get a pointer to the module's hardware instance */ + Tcc *const tcc_module = module_inst->hw; + uint32_t last_cmd; + + /* Wait until last command is done */ + do { + while (tcc_module->SYNCBUSY.reg & TCC_SYNCBUSY_CTRLB) { + /* Wait for sync */ + } + last_cmd = tcc_module->CTRLBSET.reg & TCC_CTRLBSET_CMD_Msk; + if (last_cmd == TCC_CTRLBSET_CMD_NONE) { + break; + } else if (last_cmd == TCC_CTRLBSET_CMD_UPDATE) { + /* Command have been issued */ + return; + } + } while (1); + + /* Write command to execute */ + tcc_module->CTRLBSET.reg = TCC_CTRLBSET_CMD_UPDATE; +} + +/** + * \brief Enable Circular option for double buffered Top/Period Values + * + * Enable circular option for the double buffered top/period values. + * On each UPDATE condition, the contents of PERB and PER are switched, meaning + * that the contents of PERB are transferred to PER and the contents of PER are + * transferred to PERB. + * + * \param[in] module_inst Pointer to the TCC software instance struct + */ +static inline void tcc_enable_circular_buffer_top( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + module_inst->hw->WAVE.reg |= TCC_WAVE_CIPEREN; +} + +/** + * \brief Disable Circular option for double buffered Top/Period Values + * + * Stop circularing the double buffered top/period values. + * + * \param[in] module_inst Pointer to the TCC software instance struct + */ +static inline void tcc_disable_circular_buffer_top( + struct tcc_module *const module_inst) +{ + /* Sanity check arguments */ + Assert(module_inst); + Assert(module_inst->hw); + + module_inst->hw->WAVE.reg &= ~TCC_WAVE_CIPEREN; +} + +enum status_code tcc_set_double_buffer_top_values( + const struct tcc_module *const module_inst, + const uint32_t top_value, const uint32_t top_buffer_value); + + +enum status_code tcc_enable_circular_buffer_compare( + struct tcc_module *const module_inst, + enum tcc_match_capture_channel channel_index); +enum status_code tcc_disable_circular_buffer_compare( + struct tcc_module *const module_inst, + enum tcc_match_capture_channel channel_index); +enum status_code tcc_set_double_buffer_compare_values( + struct tcc_module *const module_inst, + enum tcc_match_capture_channel channel_index, + const uint32_t compare, + const uint32_t compare_buffer); + + +/** @} */ + +/** @} */ + +#ifdef __cplusplus +} +#endif + +/** + * \page asfdoc_sam0_tcc_extra Extra Information for TCC Driver + * + * \section asfdoc_sam0_tcc_extra_acronyms Acronyms + * The table below presents the acronyms used in this module: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
AcronymDescription
DMADirect Memory Access
TCCTimer Counter for Control Applications
PWMPulse Width Modulation
PWPPulse Width Period
PPWPeriod Pulse Width
+ * + * + * \section asfdoc_sam0_tcc_extra_dependencies Dependencies + * This driver has the following dependencies: + * + * - \ref asfdoc_sam0_system_pinmux_group "System Pin Multiplexer Driver" + * + * + * \section asfdoc_sam0_tcc_extra_errata Errata + * There are no errata related to this driver. + * + * + * \section asfdoc_sam0_tcc_extra_history Module History + * An overview of the module history is presented in the table below, with + * details on the enhancements and fixes made to the module since its first + * release. The current version of this corresponds to the newest version in + * the table. + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Changelog
Add double buffering functionality
Add fault handling functionality
Initial Release
+ */ + +/** + * \page asfdoc_sam0_tcc_exqsg Examples for TCC Driver + * + * This is a list of the available Quick Start guides (QSGs) and example + * applications for \ref asfdoc_sam0_tcc_group. QSGs are simple examples with + * step-by-step instructions to configure and use this driver in a selection of + * use cases. Note that QSGs can be compiled as a standalone application or be + * added to the user application. + * + * - \subpage asfdoc_sam0_tcc_basic_use_case + * - \subpage asfdoc_sam0_tcc_buffering_use_case + * \if TCC_CALLBACK_MODE + * - \subpage asfdoc_sam0_tcc_timer_use_case + * - \subpage asfdoc_sam0_tcc_callback_use_case + * - \subpage asfdoc_sam0_tcc_faultx_use_case + * - \subpage asfdoc_sam0_tcc_faultn_use_case + * \endif + * - \subpage asfdoc_sam0_tcc_dma_use_case + * + * \page asfdoc_sam0_tcc_document_revision_history Document Revision History + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
Doc. Rev.DateComments
42256C12/2015Added support for SAM L21/L22, SAM DA1, and SAM C20/C21
42256B12/2014Added fault handling functionality. + * Added double buffering functionality with use case. + * Added timer use case. + * Added SAM R21/D10/D11 support.
42256A01/2014Initial release
+ */ + +#endif /* TCC_H_INCLUDED */ diff --git a/TE_Controller/src/asf.h b/TE_Controller/src/asf.h index 7976a11..ab148d1 100644 --- a/TE_Controller/src/asf.h +++ b/TE_Controller/src/asf.h @@ -73,7 +73,7 @@ // From module: FreeRTOS - kernel 10.0.0 #include -#include +//#include #include #include #include @@ -135,6 +135,13 @@ #include #include +// From module: TC - Timer Counter (Callback APIs) +#include +#include + +// From module: TCC - Timer Counter for Control Applications (Polled APIs) +#include + // From module: USB - Universal Serial Bus #include diff --git a/TE_Controller/src/include/adn8831.h b/TE_Controller/src/include/adn8831.h new file mode 100644 index 0000000..9b4f239 --- /dev/null +++ b/TE_Controller/src/include/adn8831.h @@ -0,0 +1,16 @@ +/* + * adn8831.h + * + * Created: 04.01.2021 19:13:57 + * Author: Lexus + */ + + +#ifndef ADN8831_H_ +#define ADN8831_H_ +#include +#define MAX_STR_FLOAT 12 +void make_float2str(char * str, uint16_t len, float value); +void ADN8831_control(void); + +#endif /* ADN8831_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/include/backlight.h b/TE_Controller/src/include/backlight.h new file mode 100644 index 0000000..4d8039c --- /dev/null +++ b/TE_Controller/src/include/backlight.h @@ -0,0 +1,27 @@ +/* + * backlight.h + * + * Created: 10.04.2020 0:41:41 + * Author: User + */ + + +#ifndef BACKLIGHT_H_ +#define BACKLIGHT_H_ + + +void backlight_event_100ms(void); +void backlight_event_1s(void); +void backlight_mode_demo(void); +void backlight_init(void); +void backlight_ws2812_sendarray(void); +void backlight_color_show(uint8_t R, uint8_t G, uint8_t B); + +enum backlight_mode +{ + mode_none=0, + mode_constant, + mode_demo +}; + +#endif /* BACKLIGHT_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/include/dht.h b/TE_Controller/src/include/dht.h new file mode 100644 index 0000000..20ced1b --- /dev/null +++ b/TE_Controller/src/include/dht.h @@ -0,0 +1,36 @@ +/* + * dht.h + * + * Created: 04.01.2021 21:06:23 + * Author: Lexus + */ + + +#ifndef DHT_H_ +#define DHT_H_ + +#include + +/* Структура возвращаемых датчиком данных */ +typedef struct { + float hum; + float temp; +} DHT_data; +/* Тип используемого датчика */ +typedef enum { + DHT11, + DHT22 +} DHT_type; + +/* Настройки */ +#define DHT_Pin PIN_PA15 //Пин линии данных +#define DHT_timeout 1000000 //Количество итераций, после которых функция вернёт пустые значения + +/* Прототипы функций */ +uint8_t DHT_getData(DHT_type t, DHT_data* p_data); //Получить данные с датчика +uint8_t _DHT_getData(DHT_type t, DHT_data* p_data); +void measurement_DHT22(void); + + + +#endif /* DHT_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/include/light_ws2812_cortex.c b/TE_Controller/src/include/light_ws2812_cortex.c new file mode 100644 index 0000000..f9a2c37 --- /dev/null +++ b/TE_Controller/src/include/light_ws2812_cortex.c @@ -0,0 +1,128 @@ +/* + * light weight WS2812 lib - ARM Cortex M0/M0+ version + * + * Created: 07.07.2013 + * Author: Tim (cpldcpu@gmail.com) + */ + +#include "light_ws2812_cortex.h" +/* +* The total length of each bit is 1.25Вµs (25 cycles @ 20Mhz) +* At 0Вµs the dataline is pulled high. +* To send a zero the dataline is pulled low after 0.375Вµs +* To send a one the dataline is pulled low after 0.625Вµs +*/ + +#define ws2812_ctot (((F_CPU/1000)*1250)/1000000) +#define ws2812_t1 (((F_CPU/1000)*375 )/1000000) // floor +#define ws2812_t2 (((F_CPU/1000)*625+500000)/1000000) // ceil + +#define w1 (ws2812_t1-2) +#define w2 (ws2812_t2-ws2812_t1-2) +#define w3 (ws2812_ctot-ws2812_t2-5) + +#define ws2812_DEL1 " nop \n\t" +#define ws2812_DEL2 ws2812_DEL1 ws2812_DEL1 +//#define ws2812_DEL2 " b .+2 \n\t" +#define ws2812_DEL4 ws2812_DEL2 ws2812_DEL2 +#define ws2812_DEL8 ws2812_DEL4 ws2812_DEL4 +#define ws2812_DEL16 ws2812_DEL8 ws2812_DEL8 + +#define ws2812_DEL ws2812_DEL8 ws2812_DEL2 + + +void ws2812_sendarray(uint8_t *data,int datlen) +{ + uint8_t gpio_pin = PIN_PA23; + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + uint32_t maskhi = pin_mask; + uint32_t masklo = pin_mask; + volatile uint32_t *set = &port_base->OUTSET.reg; + volatile uint32_t *clr = &port_base->OUTCLR.reg; + uint32_t i=0; + uint32_t curbyte; + + while (datlen--) { + curbyte=*data++; + + asm volatile( + " lsl %[dat],#24 \n\t" + " movs %[ctr],#8 \n\t" + "ilop%=: \n\t" + " lsl %[dat], #1 \n\t" + " str %[maskhi], [%[set]] \n\t" +ws2812_DEL +// ws2812_DEL19 +/* +#if (w1&1) + ws2812_DEL1 +#endif +#if (w1&2) + ws2812_DEL2 +#endif +#if (w1&4) + ws2812_DEL4 +#endif +#if (w1&8) + ws2812_DEL8 +#endif +#if (w1&16) + ws2812_DEL16 +#endif +*/ + " bcs one%= \n\t" + " str %[masklo], [%[clr]] \n\t" + "one%=: \n\t" + +ws2812_DEL + +/* +#if (w2&1) + ws2812_DEL1 +#endif +#if (w2&2) + ws2812_DEL2 +#endif +#if (w2&4) + ws2812_DEL4 +#endif +#if (w2&8) + ws2812_DEL8 +#endif +#if (w2&16) + ws2812_DEL16 +#endif +*/ + " sub %[ctr], #1 \n\t" + " str %[masklo], [%[clr]] \n\t" + " beq end%= \n\t" + +ws2812_DEL + +/* +#if (w3&1) + ws2812_DEL1 +#endif +#if (w3&2) + ws2812_DEL2 +#endif +#if (w3&4) + ws2812_DEL4 +#endif +#if (w3&8) + ws2812_DEL8 +#endif +#if (w3&16) + ws2812_DEL16 +#endif +*/ + + " b ilop%= \n\t" + "end%=: \n\t" + : [ctr] "+r" (i) + : [dat] "r" (curbyte), [set] "r" (set), [clr] "r" (clr), [masklo] "r" (masklo), [maskhi] "r" (maskhi) + ); + } +} diff --git a/TE_Controller/src/include/light_ws2812_cortex.h b/TE_Controller/src/include/light_ws2812_cortex.h new file mode 100644 index 0000000..b7a412d --- /dev/null +++ b/TE_Controller/src/include/light_ws2812_cortex.h @@ -0,0 +1,110 @@ +/* + * light weight WS2812 lib - ARM Cortex M0/M0+ version + * + * Created: 07.07.2013 + * Author: Tim (cpldcpu@gmail.com) + */ + +#ifndef LIGHT_WS2812_H_ +#define LIGHT_WS2812_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +#define F_CPU 48000000LU +#define LIGHT_WS2812_SAM + +/////////////////////////////////////////////////////////////////////// +// User defined area: CPU specific CMSIS include +/////////////////////////////////////////////////////////////////////// + +#if defined(LIGHT_WS2812_UC_LPC8XX) + #include "LPC8XX.h" + #define LIGHT_WS2812_LPC +#elif defined(LIGHT_WS2812_UC_STM32L0XX) + #include "stm32l0xx_hal.h" + #define LIGHT_WS2812_STM32 +#elif defined(LIGHT_WS2812_UC_FSL) +#include "fsl_port.h" +#include "fsl_gpio.h" +#define LIGHT_WS2812_FSL +#elif defined(LIGHT_WS2812_SAM) +#include +#else +#error "Error: Please define WS2812_UC_XXXXX" +#endif + +/////////////////////////////////////////////////////////////////////// +// User defined area: Define I/O pin +/////////////////////////////////////////////////////////////////////// + +// Data port and pin definition for your CPU. Depending on the way +// port access is implemented in your Cortex CPU, the set and clr +// mask and addresses may be the same. +#ifdef LIGHT_WS2812_LPC + // This example is for the NXP LPC81X + #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->SET0) // Address of the data port register to set the pin + #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->CLR0) // Address of the data port register to clear the pin + + #define ws2812_mask_set (1<<2) // Bitmask to set the data out pin + #define ws2812_mask_clr (1<<2) // Bitmask to clear the data out pin +#endif +#ifdef LIGHT_WS2812_STM32 + // This example is for STM32 family + #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->BSRR) // Address of the data port register to set the pin + #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->BRR) // Address of the data port register to clear the pin + + #define ws2812_mask_set LIGHT_WS2812_GPIO_PIN // Bitmask to set the data out pin + #define ws2812_mask_clr LIGHT_WS2812_GPIO_PIN // Bitmask to clear the data out pin +#endif +#ifdef LIGHT_WS2812_FSL + // This example is for Freescale family + #define ws2812_port_set ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->PSOR) // Address of the data port register to set the pin + #define ws2812_port_clr ((uint32_t*)&LIGHT_WS2812_GPIO_PORT->PCOR) // Address of the data port register to clear the pin + + #define ws2812_mask_set 1u << 2u // Bitmask to set the data out pin + #define ws2812_mask_clr 1u << 2u // Bitmask to clear the data out pin +#endif +/////////////////////////////////////////////////////////////////////// +// CPU clock speed +// +// The current implementation of the sendarray routine uses cycle accurate +// active waiting. The routine is automatically adjusted according to +// the clockspeed defined below. Only values between 8 Mhz and 60 Mhz +// are allowable. +// +// Important: The timing calculation assumes that there are no waitstates +// for code memory access. If there are waitstates you may have to reduce +// the value below until you get acceptable timing. It is highly recommended +// to use this library only on devices without flash waitstates and +// predictable code execution timing. +/////////////////////////////////////////////////////////////////////// + +#ifndef F_CPU + #error "Error: F_CPU (CPU clock speed) is not defined" +#endif + +#if (F_CPU<8000000) + #error "Minimum clockspeed for ARM ws2812 library is 8 Mhz!" +#endif + +#if (F_CPU>60000000) + #error "Maximum clockspeed for ARM ws2812 library is 60 Mhz!" +#endif + + +/////////////////////////////////////////////////////////////////////// +// Main function call +// +// Call with address to led color array (order is Green-Red-Blue) +// Numer of bytes to be transmitted is leds*3 +/////////////////////////////////////////////////////////////////////// + +void ws2812_sendarray(uint8_t *ledarray,int length); + +#ifdef __cplusplus +} +#endif + +#endif /* LIGHT_WS2812_H_ */ diff --git a/TE_Controller/src/include/ntc.h b/TE_Controller/src/include/ntc.h new file mode 100644 index 0000000..d36eb3a --- /dev/null +++ b/TE_Controller/src/include/ntc.h @@ -0,0 +1,27 @@ +/* + * ntc.h + * + * Created: 04.01.2021 18:57:42 + * Author: Lexus + */ + + +#ifndef NTC_H_ +#define NTC_H_ +#include + + // ADC value to R + float NTC_MCU_value2R(uint16_t value); + + float NTC_TEC_value2R(uint16_t value); + + // Resistance to Temp + float NTC_R2T(float R); + + // Read ADC and calculate temperature in Cenlsius. + float NTC_MCU_get_temp(void); + + float NTC_TEC_get_temp(uint16_t *p_value, float *p_R); + + +#endif /* NTC_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/include/realsence.h b/TE_Controller/src/include/realsence.h index 7c59e4f..b9e90fd 100644 --- a/TE_Controller/src/include/realsence.h +++ b/TE_Controller/src/include/realsence.h @@ -8,8 +8,8 @@ #ifndef REALSENCE_H_ #define REALSENCE_H_ - +#include void rs_configure_port_pins(void); -void rs_set(_Bool value); +void rs_set(bool value); #endif /* REALSENCE_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/include/tec.h b/TE_Controller/src/include/tec.h new file mode 100644 index 0000000..3539076 --- /dev/null +++ b/TE_Controller/src/include/tec.h @@ -0,0 +1,19 @@ +/* + * tec.h + * + * Created: 04.01.2021 17:08:46 + * Author: Lexus + */ + + +#ifndef TEC_H_ +#define TEC_H_ +#include + +bool VTEC_read(float *p_Vin, float *p_VTEC); +bool ITEC_read(float *p_Vin, float *p_ITEC); +void TEC_L_set(bool value); +void TEC_set_level(float value); +void TEC_set_TEMPSET_volt(float value); +void pin_set_output(uint8_t pin, bool output_flag, uint8_t value); +#endif /* TEC_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/include/tm_ds18b20.h b/TE_Controller/src/include/tm_ds18b20.h new file mode 100644 index 0000000..e86a86a --- /dev/null +++ b/TE_Controller/src/include/tm_ds18b20.h @@ -0,0 +1,273 @@ +/** + * @author Tilen Majerle + * @email tilen@majerle.eu + * @website http://stm32f4-discovery.net + * @link http://stm32f4-discovery.net/2015/07/hal-library-06-ds18b20-for-stm32fxxx/ + * @version v1.0 + * @ide Keil uVision + * @license MIT + * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors. + * +\verbatim + ---------------------------------------------------------------------- + Copyright (c) 2016 Tilen Majerle + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ---------------------------------------------------------------------- +\endverbatim + */ +#ifndef TM_DS18B20_H +#define TM_DS18B20_H 100 + +/** + * @addtogroup TM_STM32Fxxx_HAL_Libraries + * @{ + */ + +/** + * @defgroup TM_DS12820 + * @brief Library for interfacing DS18B20 temperature sensor from Dallas semiconductors - http://stm32f4-discovery.net/2015/07/hal-library-06-ds18b20-for-stm32fxxx/ + * @{ + * + * With this you can read temperature, set and get temperature resolution from 9 to 12 bits and check if device is DS18B20. + * + * Pin for STM32Fxxx is the same as set with @ref TM_ONEWIRE library. + * + * \par Changelog + * +\verbatim + Version 1.0 + - First release +\endverbatim + * + * \par Dependencies + * +\verbatim + - STM32Fxxx HAL + - TM ONEWIRE + - TM GPIO + - defines.h +\endverbatim + */ + +#include "tm_onewire.h" + +/* OneWire version check */ +#if TM_ONEWIRE_H < 100 +#error "Please update TM ONEWIRE LIB, minimum required version is 2.0.0. Download available on stm32f4-discovery.net website" +#endif + +/** + * @defgroup TM_DS18B20_Macros + * @brief Library defines + * @{ + */ + +/* Every onewire chip has different ROM code, but all the same chips has same family code */ +/* in case of DS18B20 this is 0x28 and this is first byte of ROM address */ +#define DS18B20_FAMILY_CODE 0x28 +#define DS18B20_CMD_ALARMSEARCH 0xEC + +/* DS18B20 read temperature command */ +#define DS18B20_CMD_CONVERTTEMP 0x44 /* Convert temperature */ +#define DS18B20_DECIMAL_STEPS_12BIT 0.0625 +#define DS18B20_DECIMAL_STEPS_11BIT 0.125 +#define DS18B20_DECIMAL_STEPS_10BIT 0.25 +#define DS18B20_DECIMAL_STEPS_9BIT 0.5 + +/* Bits locations for resolution */ +#define DS18B20_RESOLUTION_R1 6 +#define DS18B20_RESOLUTION_R0 5 + +/* CRC enabled */ +#ifdef DS18B20_USE_CRC +#define DS18B20_DATA_LEN 9 +#else +#define DS18B20_DATA_LEN 2 +#endif + +/** + * @} + */ + +/** + * @defgroup TM_DS18B20_Typedefs + * @brief Library Typedefs + * @{ + */ + +/** + * @brief DS18B0 Resolutions available + */ +typedef enum { + TM_DS18B20_Resolution_9bits = 9, /*!< DS18B20 9 bits resolution */ + TM_DS18B20_Resolution_10bits = 10, /*!< DS18B20 10 bits resolution */ + TM_DS18B20_Resolution_11bits = 11, /*!< DS18B20 11 bits resolution */ + TM_DS18B20_Resolution_12bits = 12 /*!< DS18B20 12 bits resolution */ +} TM_DS18B20_Resolution_t; + +/** + * @} + */ + +/** + * @defgroup TM_DS18B20_Functions + * @brief Library Functions + * @{ + */ + +/** + * @brief Starts temperature conversion for specific DS18B20 on specific onewire channel + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @retval 1 if device is DS18B20 or 0 if not + */ +uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWireStruct, uint8_t* ROM); + +/** + * @brief Starts temperature conversion for all DS18B20 devices on specific onewire channel + * @note This mode will skip ROM addressing + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @retval None + */ +void TM_DS18B20_StartAll(TM_OneWire_t* OneWireStruct); + +/** + * @brief Reads temperature from DS18B20 + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @param *destination: Pointer to float variable to store temperature + * @retval Temperature status: + * - 0: Device is not DS18B20 or conversion is not done yet or CRC failed + * - > 0: Temperature is read OK + */ +uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWireStruct, uint8_t* ROM, float* destination); + +/** + * @brief Gets resolution for temperature conversion from DS18B20 device + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @retval Resolution: + * - 0: Device is not DS18B20 + * - 9 - 12: Resolution of DS18B20 + */ +uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM); + +/** + * @brief Sets resolution for specific DS18B20 device + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @param resolution: Resolution for DS18B20 device. This parameter can be a value of @ref TM_DS18B20_Resolution_t enumeration. + * @retval Success status: + * - 0: Device is not DS18B20 + * - > 0: Resolution set OK + */ +uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWireStruct, uint8_t* ROM, TM_DS18B20_Resolution_t resolution); + +/** + * @brief Checks if device with specific ROM number is DS18B20 + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @retval Device status + * - 0: Device is not DS18B20 + * - > 0: Device is DS18B20 + */ +uint8_t TM_DS18B20_Is(uint8_t* ROM); + +/** + * @brief Sets high alarm temperature to specific DS18B20 sensor + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @param temp: integer value for temperature between -55 to 125 degrees + * @retval Success status: + * - 0: Device is not DS18B20 + * - > 0: High alarm set OK + */ +uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp); + +/** + * @brief Sets low alarm temperature to specific DS18B20 sensor + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @param temp: integer value for temperature between -55 to 125 degrees + * @retval Success status: + * - 0: Device is not DS18B20 + * - > 0: Low alarm set OK + */ +uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM, int8_t temp); + +/** + * @brief Disables alarm temperature for specific DS18B20 sensor + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @param *ROM: Pointer to first byte of ROM address for desired DS12B80 device. + * Entire ROM address is 8-bytes long + * @retval Success status: + * - 0: Device is not DS18B20 + * - > 0: Alarm disabled OK + */ +uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWireStruct, uint8_t* ROM); + +/** + * @brief Searches for devices with alarm flag set + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @retval Alarm search status + * - 0: No device found with alarm flag set + * - > 0: Device is found with alarm flag + * @note To get all devices on one onewire channel with alarm flag set, you can do this: +\verbatim +while (TM_DS18B20_AlarmSearch(&OneWireStruct)) { + //Read device ID here + //Print to user device by device +} +\endverbatim + * @retval 1 if any device has flag, otherwise 0 + */ +uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWireStruct); + +/** + * @brief Checks if all DS18B20 sensors are done with temperature conversion + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working structure (OneWire channel) + * @retval Conversion status + * - 0: Not all devices are done + * - > 0: All devices are done with conversion + */ +uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWireStruct); + +/** + * @} + */ +void measurement_DS1820(void); +/** + * @} + */ + +/** + * @} + */ + +#endif + diff --git a/TE_Controller/src/include/tm_onewire.h b/TE_Controller/src/include/tm_onewire.h new file mode 100644 index 0000000..b7a5e68 --- /dev/null +++ b/TE_Controller/src/include/tm_onewire.h @@ -0,0 +1,293 @@ +/** + * @author Tilen Majerle + * @email tilen@majerle.eu + * @website http://stm32f4-discovery.net + * @link http://stm32f4-discovery.net/2015/07/hal-library-05-onewire-for-stm32fxxx/ + * @version v1.0 + * @ide Keil uVision + * @license MIT + * @brief Onewire library for STM32Fxxx devices + * +\verbatim + ---------------------------------------------------------------------- + Copyright (c) 2016 Tilen Majerle + + Permission is hereby granted, free of charge, to any person + obtaining a copy of this software and associated documentation + files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, + publish, distribute, sublicense, and/or sell copies of the Software, + and to permit persons to whom the Software is furnished to do so, + subject to the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + OTHER DEALINGS IN THE SOFTWARE. + ---------------------------------------------------------------------- +\endverbatim + */ +#ifndef TM_ONEWIRE_H +#define TM_ONEWIRE_H 100 + +/* C++ detection */ +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @addtogroup TM_STM32Fxxx_HAL_Libraries + * @{ + */ + +/** + * @defgroup TM_ONEWIRE + * @brief Onewire library for STM32Fxxx devices - http://stm32f4-discovery.net/2015/07/hal-library-05-onewire-for-stm32fxxx/ + * @{ + * + * \par Changelog + * +\verbatim + Version 1.0 + - First release +\endverbatim + * + * \par Dependencies + * +\verbatim + - STM32Fxxx HAL + - defines.h + - TM DELAY + - TM GPIO +\endverbatim + */ + +#include + +/** + * @defgroup TM_ONEWIRE_Macros + * @brief Library defines + * @{ + */ + +/* OneWire delay */ +#define ONEWIRE_DELAY(x) delay_us(x) + +/* Pin settings */ +#define ONEWIRE_LOW(structure) port_pin_set_output_level((structure)->GPIO_Pin, 0) +#define ONEWIRE_HIGH(structure) port_pin_set_output_level((structure)->GPIO_Pin, 1) +#define ONEWIRE_GET_VALUE(structure) port_pin_get_input_level((structure)->GPIO_Pin) +//#define ONEWIRE_INPUT(structure) TM_GPIO_SetPinAsInput(structure->GPIOx, (structure)->GPIO_Pin) +//#define ONEWIRE_OUTPUT(structure) TM_GPIO_SetPinAsOutput(structure->GPIOx, (structure)->GPIO_Pin) + +/* OneWire commands */ +#define ONEWIRE_CMD_RSCRATCHPAD 0xBE +#define ONEWIRE_CMD_WSCRATCHPAD 0x4E +#define ONEWIRE_CMD_CPYSCRATCHPAD 0x48 +#define ONEWIRE_CMD_RECEEPROM 0xB8 +#define ONEWIRE_CMD_RPWRSUPPLY 0xB4 +#define ONEWIRE_CMD_SEARCHROM 0xF0 +#define ONEWIRE_CMD_READROM 0x33 +#define ONEWIRE_CMD_MATCHROM 0x55 +#define ONEWIRE_CMD_SKIPROM 0xCC + +/** + * @} + */ + +/** + * @defgroup TM_ONEWIRE_Typedefs + * @brief Library Typedefs + * @{ + */ + +/** + * @brief OneWire working struct + * @note Except ROM_NO member, everything is fully private and should not be touched by user + */ +typedef struct { + uint8_t GPIO_Pin; /*!< GPIO Pin to be used for I/O functions */ + uint8_t LastDiscrepancy; /*!< Search private */ + uint8_t LastFamilyDiscrepancy; /*!< Search private */ + uint8_t LastDeviceFlag; /*!< Search private */ + uint8_t ROM_NO[8]; /*!< 8-bytes address of last search device */ +} TM_OneWire_t; + +/** + * @} + */ + +/** + * @defgroup TM_ONEWIRE_Functions + * @brief Library Functions + * @{ + */ + +/** + * @brief Initializes OneWire bus + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t empty working onewire structure + * @param *Pointer to GPIO port used for onewire channel + * @param GPIO_Pin: GPIO Pin on specific GPIOx to be used for onewire channel + * @retval None + */ +void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, uint8_t GPIO_Pin); + +/** + * @brief Resets OneWire bus + * + * @note Sends reset command for OneWire + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure + * @retval None + */ +uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct); + +/** + * @brief Reads byte from one wire bus + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure + * @retval Byte from read operation + */ +uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct); + +/** + * @brief Writes byte to bus + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure + * @param byte: 8-bit value to write over OneWire protocol + * @retval None + */ +void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte); + +/** + * @brief Writes single bit to onewire bus + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure + * @param bit: Bit value to send, 1 or 0 + * @retval None + */ +void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit); + +/** + * @brief Reads single bit from one wire bus + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure + * @retval Bit value: + * - 0: Bit is low (zero) + * - > 0: Bit is high (one) + */ +uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct); + +/** + * @brief Searches for OneWire devices on specific Onewire port + * @note Not meant for public use. Use @ref TM_OneWire_First and @ref TM_OneWire_Next for this. + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire structure where to search + * @param Device status: + * - 0: No devices detected + * - > 0: Device detected + */ +uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command); + +/** + * @brief Resets search states + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values + * @retval None + */ +void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct); + +/** + * @brief Starts search, reset states first + * @note When you want to search for ALL devices on one onewire port, you should first use this function. +\code +//...Initialization before +status = TM_OneWire_First(&OneWireStruct); +while (status) { + //Save ROM number from device + TM_OneWire_GetFullROM(ROM_Array_Pointer); + //Check for new device + status = TM_OneWire_Next(&OneWireStruct); +} +\endcode + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire where to reset search values + * @param Device status: + * - 0: No devices detected + * - > 0: Device detected + */ +uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct); + +/** + * @brief Reads next device + * @note Use @ref TM_OneWire_First to start searching + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire + * @param Device status: + * - 0: No devices detected any more + * - > 0: New device detected + */ +uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct); + +/** + * @brief Gets ROM number from device from search + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire + * @param index: Because each device has 8-bytes long ROm address, you have to call this 8 times, to get ROM bytes from 0 to 7 + * @reetval ROM byte for index (0 to 7) at current found device + */ +uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index); + +/** + * @brief Gets all 8 bytes ROM value from device from search + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire + * @param *firstIndex: Pointer to first location for first byte, other bytes are automatically incremented + * @retval None + */ +void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex); + +/** + * @brief Selects specific slave on bus + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire + * @param *addr: Pointer to first location of 8-bytes long ROM address + * @retval None + */ +void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr); + +/** + * @brief Selects specific slave on bus with pointer address + * @param *OneWireStruct: Pointer to @ref TM_OneWire_t working onewire + * @param *ROM: Pointer to first byte of ROM address + * @retval None + */ +void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t* ROM); + +/** + * @brief Calculates 8-bit CRC for 1-wire devices + * @param *addr: Pointer to 8-bit array of data to calculate CRC + * @param len: Number of bytes to check + * + * @retval Calculated CRC from input data + */ +uint8_t TM_OneWire_CRC8(uint8_t* addr, uint8_t len); + + +void ONEWIRE_OUTPUT(TM_OneWire_t* OneWireStruct); +void ONEWIRE_INPUT(TM_OneWire_t* OneWireStruct); + +/** + * @} + */ + int TM_OneWire_Verify(TM_OneWire_t* OneWireStruct); +/** + * @} + */ + void TM_OneWire_TargetSetup(TM_OneWire_t* OneWireStruct, uint8_t family_code); +/** + * @} + */ + void TM_OneWire_FamilySkipSetup(TM_OneWire_t* OneWireStruct); +/* C++ detection */ +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/TE_Controller/src/include/tmpgood.h b/TE_Controller/src/include/tmpgood.h index 6853152..2324905 100644 --- a/TE_Controller/src/include/tmpgood.h +++ b/TE_Controller/src/include/tmpgood.h @@ -8,8 +8,8 @@ #ifndef TMPGOOD_H_ #define TMPGOOD_H_ - +#include void tmpgood_configure_port_pins(void); -_Bool tmpgood_get_state(void); +bool tmpgood_get_state(void); #endif /* TMPGOOD_H_ */ \ No newline at end of file diff --git a/TE_Controller/src/main.c b/TE_Controller/src/main.c index aeb88ac..13b0829 100644 --- a/TE_Controller/src/main.c +++ b/TE_Controller/src/main.c @@ -50,15 +50,9 @@ char str[128] = {0}; UBaseType_t uxHighWaterMark_cdc_rx_check; UBaseType_t uxHighWaterMark_led_blink; static volatile bool main_b_cdc_enable = false; +struct measured_params m_params; + -void prvGetRegistersFromStack (uint32_t *pulFaultStackAddress); -void led_configure_port_pins(void); -void vApplicationMallocFailedHook (void); -void vApplicationStackOverflowHook (void); -void Task_cdc_rx_check(void *parameters); -void Task_led_blink(void *parameters); -void InitTask_cdc_rx_check(void); -void InitTask_led_blink(void); /*! \brief Main function. Execution starts here. */ int main(void) diff --git a/TE_Controller/src/main.h b/TE_Controller/src/main.h index 2944919..1b1df87 100644 --- a/TE_Controller/src/main.h +++ b/TE_Controller/src/main.h @@ -39,6 +39,25 @@ #include "usb_protocol_cdc.h" +struct measured_params{ + float TEC_Temp; + float MCU_Temp; + float Vin_LFB; + float Vin_SFB; + float Vin_CS; + float DHT22_Temp; + float DHT22_Hum; + float DS1820_Temp; + float TEC_Power; +}; +void prvGetRegistersFromStack (uint32_t *pulFaultStackAddress); +void led_configure_port_pins(void); +void vApplicationMallocFailedHook (void); +void vApplicationStackOverflowHook (void); +void Task_cdc_rx_check(void *parameters); +void Task_led_blink(void *parameters); +void InitTask_cdc_rx_check(void); +void InitTask_led_blink(void); /*! \brief Opens the communication port * This is called by CDC interface when USB Host enable it. * diff --git a/TE_Controller/src/source/adc_user.c b/TE_Controller/src/source/adc_user.c index 0081d44..3879ef8 100644 --- a/TE_Controller/src/source/adc_user.c +++ b/TE_Controller/src/source/adc_user.c @@ -5,7 +5,7 @@ * Author: Lexus */ #include "adc_user.h" -#include "adc.h" +#include struct adc_module adc_instance; // init ADC void configure_adc(void) diff --git a/TE_Controller/src/source/adc_user.h b/TE_Controller/src/source/adc_user.h index 460b888..8ad6123 100644 --- a/TE_Controller/src/source/adc_user.h +++ b/TE_Controller/src/source/adc_user.h @@ -8,7 +8,7 @@ #ifndef ADC_H_ #define ADC_H_ -#include +#include #define chan_NTC_MCU ADC_POSITIVE_INPUT_PIN1 #define chan_NTC_TEC ADC_POSITIVE_INPUT_PIN5 #define chan_LFB ADC_POSITIVE_INPUT_PIN19 diff --git a/TE_Controller/src/source/adn8831.c b/TE_Controller/src/source/adn8831.c new file mode 100644 index 0000000..282a4db --- /dev/null +++ b/TE_Controller/src/source/adn8831.c @@ -0,0 +1,60 @@ +/* + * adn8831.c + * + * Created: 04.01.2021 19:13:33 + * Author: Lexus + */ +#include "adn8831.h" +#include "ntc.h" +#include "tec.h" +#include "tmpgood.h" + +void make_float2str(char * str, uint16_t len, float value){ + bool neg_flag; + if(value >= 0) + neg_flag = false; + else{ + neg_flag = true; + value = value * -1; + } + + int a1 = value; + int a2 = (value - a1)*100.0; + snprintf(str, len, "%c%d.%2.2d",neg_flag?'-':'+', a1, a2); +} + +void ADN8831_control(void){ + char t_TEC_str[MAX_STR_FLOAT]; + char t_MCU_str[MAX_STR_FLOAT]; + char v_VTEC_str[MAX_STR_FLOAT]; + char v_ITEC_str[MAX_STR_FLOAT]; + char VTEC_str[MAX_STR_FLOAT]; + char ITEC_str[MAX_STR_FLOAT]; + + TEC_set_TEMPSET_volt(0.9); + + // MCU temp + float t = NTC_MCU_get_temp(); + make_float2str(t_MCU_str, MAX_STR_FLOAT, (float)t); + + + // TEC temp + uint16_t value_TEC; + float R_TEC; + float t_TEC = NTC_TEC_get_temp(&value_TEC, &R_TEC); + make_float2str(t_TEC_str, MAX_STR_FLOAT, (float)t_TEC); + + bool TMPGD = tmpgood_get_state(); + + // VTEC & ITEC + float v_VTEC=0, v_ITEC=0, VTEC=0, ITEC=0; + VTEC_read(&v_VTEC, &VTEC); + ITEC_read(&v_ITEC, &ITEC); + + make_float2str(v_VTEC_str, MAX_STR_FLOAT, v_VTEC); + make_float2str(v_ITEC_str, MAX_STR_FLOAT, v_ITEC); + make_float2str(VTEC_str, MAX_STR_FLOAT, VTEC); + make_float2str(ITEC_str, MAX_STR_FLOAT, ITEC); + + printf("Info: t_MCU: %10s, t_TEC:%10s, TMPGD: %d, VTEC: %10s, v_VTEC: %10s, ITEC: %10s, v_ITEC: %10s\r\n",t_MCU_str, t_TEC_str, (int)TMPGD, VTEC_str, v_VTEC_str, ITEC_str, v_ITEC_str); +} \ No newline at end of file diff --git a/TE_Controller/src/source/backlight.c b/TE_Controller/src/source/backlight.c new file mode 100644 index 0000000..44bee0f --- /dev/null +++ b/TE_Controller/src/source/backlight.c @@ -0,0 +1,127 @@ +/* + * backlight.c + * + * Created: 10.04.2020 0:41:24 + * Author: User + */ + +#include +#include + +#include "light_ws2812_cortex.h" +#include "backlight.h" + +enum backlight_mode mode=mode_none; + +bool mode_run_light=false; +uint8_t mode_run_light_cnt=0; + +uint8_t led_data[LEN_WS2812*3]; + + +void backlight_event_100ms(void){ + if(mode == mode_demo){ + if(mode_run_light){ + for(uint16_t i=0; i < LEN_WS2812/2;i++){ + if(mode_run_light_cnt == i){ + led_data[0 + i*3] = 0xff; + led_data[1 + i*3] = 0x00; + led_data[2 + i*3] = 0x00; + + led_data[0 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00; + led_data[1 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0xff; + led_data[2 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00; + }else{ + led_data[0 + i*3] = 0x00; + led_data[1 + i*3] = 0x00; + led_data[2 + i*3] = 0x00; + + led_data[0 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00; + led_data[1 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00; + led_data[2 + (LEN_WS2812/2 - i - 1)*3 + (LEN_WS2812/2)*3] = 0x00; + } + } + backlight_ws2812_sendarray(); + mode_run_light_cnt++; + if(mode_run_light_cnt >= LEN_WS2812/2){ + mode_run_light=false; + } + } + } +} + +uint32_t s1_cnt=0; +void backlight_event_1s(void){ + // LED WS2812 + + if(mode == mode_demo){ + uint8_t modes = 6; + if(!mode_run_light){ + if((s1_cnt % modes) == 0){ + for(uint16_t i=0; i < LEN_WS2812;i++){ + led_data[0 + i*3] = 0xff; + led_data[1 + i*3] = 0xff; + led_data[2 + i*3] = 0xff; + } + }else if((s1_cnt % modes) == 1){ + for(uint16_t i=0; i < LEN_WS2812;i++){ + led_data[0 + i*3] = 0xff; + led_data[1 + i*3] = 0x00; + led_data[2 + i*3] = 0x00; + } + }else if((s1_cnt % modes) == 2){ + for(uint16_t i=0; i < LEN_WS2812;i++){ + led_data[0 + i*3] = 0x00; + led_data[1 + i*3] = 0xff; + led_data[2 + i*3] = 0x00; + } + }else if((s1_cnt % modes) == 3){ + for(uint16_t i=0; i < LEN_WS2812;i++){ + led_data[0 + i*3] = 0x00; + led_data[1 + i*3] = 0x00; + led_data[2 + i*3] = 0xff; + } + }else if((s1_cnt % modes) == 4){ + for(uint16_t i=0; i < LEN_WS2812;i++){ + led_data[0 + i*3] = 0x00; + led_data[1 + i*3] = 0x00; + led_data[2 + i*3] = 0x00; + } + }else if((s1_cnt % modes) == 5){ + mode_run_light=true; + mode_run_light_cnt=0; + } + backlight_ws2812_sendarray(); + s1_cnt++; + } + } +} + +void backlight_mode_demo(void){ + mode = mode_demo; +} + +void backlight_init(void){ + mode = mode_none; +// memset(led_data, 0, sizeof(led_data)); + backlight_color_show(0,0,0); +// for(uint16_t i=0; i < LEN_WS2812*3; i++){ +// printf("%d: %d\r\n", i, (int)led_data[i]); +// } +} + +void backlight_ws2812_sendarray(void){ + cpu_irq_disable(); + ws2812_sendarray(led_data,sizeof(led_data)); + cpu_irq_enable(); +} + +void backlight_color_show(uint8_t R, uint8_t G, uint8_t B){ + for(uint16_t i=0; i < LEN_WS2812; i++){ + led_data[0 + i*3] = G; + led_data[1 + i*3] = R; + led_data[2 + i*3] = B; +// printf("%d: R: %d, G: %d, B: %d\r\n",(int)i, (int)led_data[1 + i*3], (int)led_data[0 + i*3], (int)led_data[2 + i*3]); + } + backlight_ws2812_sendarray(); +} \ No newline at end of file diff --git a/TE_Controller/src/source/dac_user.c b/TE_Controller/src/source/dac_user.c index abd2d51..8ed5eb0 100644 --- a/TE_Controller/src/source/dac_user.c +++ b/TE_Controller/src/source/dac_user.c @@ -4,9 +4,11 @@ * Created: 04.01.2021 0:51:07 * Author: Lexus */ -#include #include "dac_user.h" +#include + struct dac_module dac_instance; + void configure_dac_channel(void) { struct dac_chan_config config_dac_chan; diff --git a/TE_Controller/src/source/dht.c b/TE_Controller/src/source/dht.c new file mode 100644 index 0000000..c7799c6 --- /dev/null +++ b/TE_Controller/src/source/dht.c @@ -0,0 +1,128 @@ +/* + * dht.c + * + * Created: 04.01.2021 21:06:09 + * Author: Lexus + */ + +#include "dht.h" + +#define lineDown() port_pin_set_output_level(DHT_Pin, 0) +#define lineUp() port_pin_set_output_level(DHT_Pin, 1) +#define getLine() port_pin_get_input_level(DHT_Pin) +#define Delay(d) delay_ms(d) + +#define CPU_IRQ_enable() cpu_irq_enable() +#define CPU_IRQ_disable() cpu_irq_disable() +extern struct measured_params m_params; +static void goToOutput(void) { + + // по умолчанию на линии высокий уровень + port_pin_set_output_level(DHT_Pin, 1); + + struct port_config config_port_pin; + port_get_config_defaults(&config_port_pin); + config_port_pin.direction = PORT_PIN_DIR_OUTPUT; + config_port_pin.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(DHT_Pin, &config_port_pin); +} + +static void goToInput(void) { + struct port_config config_port_pin; + port_get_config_defaults(&config_port_pin); + config_port_pin.direction = PORT_PIN_DIR_INPUT; + config_port_pin.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(DHT_Pin, &config_port_pin); +} + +uint8_t DHT_getData(DHT_type t, DHT_data* p_data){ + uint8_t ret; + CPU_IRQ_disable(); + ret = _DHT_getData(t, p_data); + CPU_IRQ_enable(); + return ret; +} + +uint8_t _DHT_getData(DHT_type t, DHT_data* p_data) { + p_data->hum=0.0f; + p_data->temp=0.0f; + + + /* Запрос данных у датчика */ + //Перевод пина "на выход" + goToOutput(); + //Опускание линии данных на 15 мс + lineDown(); + Delay(15); + //Подъём линии, перевод порта "на вход" + lineUp(); + goToInput(); + + /* Ожидание ответа от датчика */ + uint32_t timeout = 0; + //Ожидание спада + while(getLine()) { + timeout++; + if (timeout > DHT_timeout) return 0x01; + } + timeout = 0; + //Ожидание подъёма + while(!getLine()) { + timeout++; + if (timeout > DHT_timeout) return 0x02; + } + timeout = 0; + //Ожидание спада + while(getLine()) { + timeout++; + if (timeout > DHT_timeout) return 0x03; + } + + /* Чтение ответа от датчика */ + uint8_t rawData[5] = {0,0,0,0,0}; + for(uint8_t a = 0; a < 5; a++) { + for(uint8_t b = 7; b != 255; b--) { + uint32_t hT = 0, lT = 0; + //Пока линия в низком уровне, инкремент переменной lT + while(!getLine()) lT++; + //Пока линия в высоком уровне, инкремент переменной hT + while(getLine()) hT++; + //Если hT больше lT, то пришла единица + if(hT > lT) rawData[a] |= (1<hum = (float)(((uint16_t)rawData[0]<<8) | rawData[1])*0.1f; + //Проверка на отрицательность температуры + if(!(rawData[2] & (1<<7))) { + p_data->temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*0.1f; + } else { + rawData[2] &= ~(1<<7); + p_data->temp = (float)(((uint16_t)rawData[2]<<8) | rawData[3])*-0.1f; + } + } + if (t == DHT11) { + p_data->hum = (float)rawData[0]; + p_data->temp = (float)rawData[2]; + } + }else{ + return 0x04; + } + + return 0; +} + +void measurement_DHT22(){ + DHT_data d; + uint8_t ret = DHT_getData(DHT22, &d); + if(ret){ + printf("DHT22 error: %d\r\n",(int)ret); + }else{ + m_params.DHT22_Temp = d.temp; + m_params.DHT22_Hum = d.hum; + } +} diff --git a/TE_Controller/src/source/light_ws2812_cortex.c b/TE_Controller/src/source/light_ws2812_cortex.c new file mode 100644 index 0000000..f9a2c37 --- /dev/null +++ b/TE_Controller/src/source/light_ws2812_cortex.c @@ -0,0 +1,128 @@ +/* + * light weight WS2812 lib - ARM Cortex M0/M0+ version + * + * Created: 07.07.2013 + * Author: Tim (cpldcpu@gmail.com) + */ + +#include "light_ws2812_cortex.h" +/* +* The total length of each bit is 1.25Вµs (25 cycles @ 20Mhz) +* At 0Вµs the dataline is pulled high. +* To send a zero the dataline is pulled low after 0.375Вµs +* To send a one the dataline is pulled low after 0.625Вµs +*/ + +#define ws2812_ctot (((F_CPU/1000)*1250)/1000000) +#define ws2812_t1 (((F_CPU/1000)*375 )/1000000) // floor +#define ws2812_t2 (((F_CPU/1000)*625+500000)/1000000) // ceil + +#define w1 (ws2812_t1-2) +#define w2 (ws2812_t2-ws2812_t1-2) +#define w3 (ws2812_ctot-ws2812_t2-5) + +#define ws2812_DEL1 " nop \n\t" +#define ws2812_DEL2 ws2812_DEL1 ws2812_DEL1 +//#define ws2812_DEL2 " b .+2 \n\t" +#define ws2812_DEL4 ws2812_DEL2 ws2812_DEL2 +#define ws2812_DEL8 ws2812_DEL4 ws2812_DEL4 +#define ws2812_DEL16 ws2812_DEL8 ws2812_DEL8 + +#define ws2812_DEL ws2812_DEL8 ws2812_DEL2 + + +void ws2812_sendarray(uint8_t *data,int datlen) +{ + uint8_t gpio_pin = PIN_PA23; + PortGroup *const port_base = port_get_group_from_gpio_pin(gpio_pin); + uint32_t pin_mask = (1UL << (gpio_pin % 32)); + + uint32_t maskhi = pin_mask; + uint32_t masklo = pin_mask; + volatile uint32_t *set = &port_base->OUTSET.reg; + volatile uint32_t *clr = &port_base->OUTCLR.reg; + uint32_t i=0; + uint32_t curbyte; + + while (datlen--) { + curbyte=*data++; + + asm volatile( + " lsl %[dat],#24 \n\t" + " movs %[ctr],#8 \n\t" + "ilop%=: \n\t" + " lsl %[dat], #1 \n\t" + " str %[maskhi], [%[set]] \n\t" +ws2812_DEL +// ws2812_DEL19 +/* +#if (w1&1) + ws2812_DEL1 +#endif +#if (w1&2) + ws2812_DEL2 +#endif +#if (w1&4) + ws2812_DEL4 +#endif +#if (w1&8) + ws2812_DEL8 +#endif +#if (w1&16) + ws2812_DEL16 +#endif +*/ + " bcs one%= \n\t" + " str %[masklo], [%[clr]] \n\t" + "one%=: \n\t" + +ws2812_DEL + +/* +#if (w2&1) + ws2812_DEL1 +#endif +#if (w2&2) + ws2812_DEL2 +#endif +#if (w2&4) + ws2812_DEL4 +#endif +#if (w2&8) + ws2812_DEL8 +#endif +#if (w2&16) + ws2812_DEL16 +#endif +*/ + " sub %[ctr], #1 \n\t" + " str %[masklo], [%[clr]] \n\t" + " beq end%= \n\t" + +ws2812_DEL + +/* +#if (w3&1) + ws2812_DEL1 +#endif +#if (w3&2) + ws2812_DEL2 +#endif +#if (w3&4) + ws2812_DEL4 +#endif +#if (w3&8) + ws2812_DEL8 +#endif +#if (w3&16) + ws2812_DEL16 +#endif +*/ + + " b ilop%= \n\t" + "end%=: \n\t" + : [ctr] "+r" (i) + : [dat] "r" (curbyte), [set] "r" (set), [clr] "r" (clr), [masklo] "r" (masklo), [maskhi] "r" (maskhi) + ); + } +} diff --git a/TE_Controller/src/source/ntc.c b/TE_Controller/src/source/ntc.c new file mode 100644 index 0000000..dc6fbf1 --- /dev/null +++ b/TE_Controller/src/source/ntc.c @@ -0,0 +1,77 @@ +/* + * ntc.c + * + * Created: 04.01.2021 18:57:53 + * Author: Lexus + */ +#include "ntc.h" +#include +#include "adc_user.h" + +#define MCU_CONTROL +// ADC value to R +float NTC_MCU_value2R(uint16_t value) +{ + float R10 = 17800.0; + float R11 = 7680.0; + + float Q = adc_get_Q(value); + + return ((R10*Q)/(1 - Q) - R11); +} + +float NTC_TEC_value2R(uint16_t value) +{ + #ifdef MCU_CONTROL + float R32 = 17800.0; + float R36 = 7680.0; + float Q = adc_get_Q(value); + + return ((R32*Q)/(1 - Q) - R36); + #else + float R36 = 7680.0; + float Uref = 2.5/2.; + float Uvcc = 3.3; + float Q = adc_get_Q(value); + + return R36/(Uref/(Q*Uvcc) - 1); + #endif +} + +// Resistance to Temp +float NTC_R2T(float R) +{ + float K0 = 273.15; + float T0 = 25.0 + K0; + float R0 = 10000.0; + + float B = 3863.737706; + return (1.0/((log(R/R0)/B) + (1/T0)) - K0); +} + +// Read ADC and calculate temperature in Cenlsius. +float NTC_MCU_get_temp(void) +{ + uint16_t adc_val = adc_read_value_spec(chan_NTC_MCU); + + float R = NTC_MCU_value2R(adc_val); + float t = NTC_R2T(R); + return t; +} + +float NTC_TEC_get_temp(uint16_t *p_value, float *p_R) +{ + uint16_t adc_val = adc_read_value_spec(chan_NTC_TEC); + + if(p_value){ + *p_value = adc_val; + } + + float R = NTC_TEC_value2R(adc_val); + + if(p_R){ + *p_R = R; + } + float t = NTC_R2T(R); + return t; +} \ No newline at end of file diff --git a/TE_Controller/src/source/realsence.c b/TE_Controller/src/source/realsence.c index f37c740..e046f5a 100644 --- a/TE_Controller/src/source/realsence.c +++ b/TE_Controller/src/source/realsence.c @@ -5,8 +5,8 @@ * Author: Lexus */ #include "realsence.h" -#include "port.h" #include "conf_board.h" + bool rs_power; void rs_configure_port_pins(void) @@ -18,7 +18,7 @@ void rs_configure_port_pins(void) port_pin_set_config(PIN_RS_POWER, &config_port_pin); } -void rs_set(_Bool value){ +void rs_set(bool value){ port_pin_set_output_level(PIN_RS_POWER, value?0:1); rs_power = value; } diff --git a/TE_Controller/src/source/tec.c b/TE_Controller/src/source/tec.c new file mode 100644 index 0000000..2c2b5e2 --- /dev/null +++ b/TE_Controller/src/source/tec.c @@ -0,0 +1,124 @@ +/* + * tec.c + * + * Created: 04.01.2021 17:08:34 + * Author: Lexus + */ + +#include "tec.h" +#include +#include "adc_user.h" +#include "dac_user.h" +struct tcc_module tcc_instance; +extern struct dac_module dac_instance; +bool VTEC_read(float *p_Vin, float *p_VTEC){ + float Vin= adc_get_V_spec(chan_VTEC); + if(p_Vin){ + *p_Vin = Vin; + } + if(p_VTEC){ + //float K __attribute__((used)) =3.67 ; + // *p_VTEC = ((Vin - 1.25)*K)/0.25; + *p_VTEC = ((Vin - 1.25))/0.25; + } + return true; +} + +bool ITEC_read(float *p_Vin, float *p_ITEC){ + float Vin= adc_get_V_spec(chan_ITEC); + if(p_Vin){ + *p_Vin = Vin; + } + if(p_ITEC){ + float Rsense = 0.005; + *p_ITEC = (Vin-1.25)/(25*Rsense); + } + return true; +} + +void TEC_L_set(bool value){ + + // switch off + pin_set_output(PIN_LPGATE, true, 1); + pin_set_output(PIN_LNGATE, true, 0); + + if(value){ + // L to +12 + pin_set_output(PIN_LPGATE, true, 0); + }else{ + // L to GND + pin_set_output(PIN_LNGATE, true, 1); + } +} + +void pin_set_output(uint8_t pin, bool output_flag, uint8_t value){ + + struct port_config config_port_pin; + port_get_config_defaults(&config_port_pin); + if(output_flag){ + port_pin_set_output_level(pin, value); + config_port_pin.direction = PORT_PIN_DIR_OUTPUT; + }else{ + config_port_pin.direction = PORT_PIN_DIR_INPUT; + } + config_port_pin.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(pin, &config_port_pin); +} + +// Range from -1 to 0 +void TEC_set_level(float value){ + tcc_reset(&tcc_instance); + if(fpclassify(value) == FP_ZERO){//if(value == (float)0.0){// + // TEC OFF + pin_set_output(PIN_SPGATE, true, 1); + pin_set_output(PIN_SNGATE, true, 0); + pin_set_output(PIN_LPGATE, true, 1); + pin_set_output(PIN_LNGATE, true, 0); + }else{ + struct port_config config_port_pin; + port_get_config_defaults(&config_port_pin); + config_port_pin.direction = PORT_PIN_DIR_INPUT; + config_port_pin.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(PIN_SNGATE, &config_port_pin); + + struct tcc_config config_tcc; + tcc_get_config_defaults(&config_tcc, CONF_PWM_MODULE); + config_tcc.counter.clock_prescaler = TCC_CLOCK_PRESCALER_DIV1; + config_tcc.counter.period = PWM_GCLK_PERIOD; + + config_tcc.compare.wave_generation = TCC_WAVE_GENERATION_SINGLE_SLOPE_PWM; + + uint8_t pin_output, chan; + if(value > 0.0){ + TEC_L_set(true); // to +12 + pin_set_output(PIN_SPGATE, true, 1); + pin_set_output(PIN_SNGATE, false, 0); + pin_output=7; + chan=3; + config_tcc.pins.wave_out_pin[pin_output] = PIN_PA17F_TCC0_WO7; + config_tcc.pins.wave_out_pin_mux[pin_output] = MUX_PA17F_TCC0_WO7; + + config_tcc.compare.match[chan] = PWM_GCLK_PERIOD*value; + }else{ + TEC_L_set(false); // to GND + pin_set_output(PIN_SPGATE, false, 0); + pin_set_output(PIN_SNGATE, true, 0); + pin_output=6; + chan=2; + config_tcc.pins.wave_out_pin[pin_output] = PIN_PA16F_TCC0_WO6; + config_tcc.pins.wave_out_pin_mux[pin_output] = MUX_PA16F_TCC0_WO6; + config_tcc.compare.match[chan] = PWM_GCLK_PERIOD*value*(-1.0); + config_tcc.wave_ext.invert[pin_output]=true; + } + config_tcc.pins.enable_wave_out_pin[pin_output] = true; + tcc_init(&tcc_instance, CONF_PWM_MODULE, &config_tcc); + tcc_enable(&tcc_instance); + } +} + +void TEC_set_TEMPSET_volt(float value) +{ + float Uref=3.3; + uint16_t dig_value = (value*1024)/Uref; + dac_chan_write(&dac_instance, DAC_CHANNEL_0, dig_value); +} \ No newline at end of file diff --git a/TE_Controller/src/source/tm_ds18b20.c b/TE_Controller/src/source/tm_ds18b20.c new file mode 100644 index 0000000..369b2f0 --- /dev/null +++ b/TE_Controller/src/source/tm_ds18b20.c @@ -0,0 +1,420 @@ +/** + * |---------------------------------------------------------------------- + * | Copyright (c) 2016 Tilen Majerle + * | + * | Permission is hereby granted, free of charge, to any person + * | obtaining a copy of this software and associated documentation + * | files (the "Software"), to deal in the Software without restriction, + * | including without limitation the rights to use, copy, modify, merge, + * | publish, distribute, sublicense, and/or sell copies of the Software, + * | and to permit persons to whom the Software is furnished to do so, + * | subject to the following conditions: + * | + * | The above copyright notice and this permission notice shall be + * | included in all copies or substantial portions of the Software. + * | + * | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * | AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * | OTHER DEALINGS IN THE SOFTWARE. + * |---------------------------------------------------------------------- + */ +#include "tm_ds18b20.h" +TM_OneWire_t ow_instance; +extern struct measured_params m_params; +uint8_t TM_DS18B20_Start(TM_OneWire_t* OneWire, uint8_t *ROM) { + /* Check if device is DS18B20 */ + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Start temperature conversion */ + TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP); + + return 1; +} + +void TM_DS18B20_StartAll(TM_OneWire_t* OneWire) { + /* Reset pulse */ + TM_OneWire_Reset(OneWire); + /* Skip rom */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_SKIPROM); + /* Start conversion on all connected devices */ + TM_OneWire_WriteByte(OneWire, DS18B20_CMD_CONVERTTEMP); +} + +uint8_t TM_DS18B20_Read(TM_OneWire_t* OneWire, uint8_t *ROM, float *destination) { + uint16_t temperature; + uint8_t resolution; + int8_t digit, minus = 0; + float decimal; + uint8_t i = 0; + uint8_t data[9]; + uint8_t crc; + + /* Check if device is DS18B20 */ + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + + /* Check if line is released, if it is, then conversion is complete */ + if (!TM_OneWire_ReadBit(OneWire)) { + /* Conversion is not finished yet */ + return 0; + } + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Read scratchpad command by onewire protocol */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); + + /* Get data */ + for (i = 0; i < 9; i++) { + /* Read byte by byte */ + data[i] = TM_OneWire_ReadByte(OneWire); + } + + /* Calculate CRC */ + crc = TM_OneWire_CRC8(data, 8); + + /* Check if CRC is ok */ + if (crc != data[8]) { + /* CRC invalid */ + return 0; + } + + /* First two bytes of scratchpad are temperature values */ + temperature = data[0] | (data[1] << 8); + + /* Reset line */ + TM_OneWire_Reset(OneWire); + + /* Check if temperature is negative */ + if (temperature & 0x8000) { + /* Two's complement, temperature is negative */ + temperature = ~temperature + 1; + minus = 1; + } + + + /* Get sensor resolution */ + resolution = ((data[4] & 0x60) >> 5) + 9; + + + /* Store temperature integer digits and decimal digits */ + digit = temperature >> 4; + digit |= ((temperature >> 8) & 0x7) << 4; + + /* Store decimal digits */ + switch (resolution) { + case 9: { + decimal = (temperature >> 3) & 0x01; + decimal *= (float)DS18B20_DECIMAL_STEPS_9BIT; + } break; + case 10: { + decimal = (temperature >> 2) & 0x03; + decimal *= (float)DS18B20_DECIMAL_STEPS_10BIT; + } break; + case 11: { + decimal = (temperature >> 1) & 0x07; + decimal *= (float)DS18B20_DECIMAL_STEPS_11BIT; + } break; + case 12: { + decimal = temperature & 0x0F; + decimal *= (float)DS18B20_DECIMAL_STEPS_12BIT; + } break; + default: { + decimal = 0xFF; + digit = 0; + } + } + + /* Check for negative part */ + decimal = digit + decimal; + if (minus) { + decimal = 0 - decimal; + } + + /* Set to pointer */ + *destination = decimal; + + /* Return 1, temperature valid */ + return 1; +} + +uint8_t TM_DS18B20_GetResolution(TM_OneWire_t* OneWire, uint8_t *ROM) { + uint8_t conf; + + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Read scratchpad command by onewire protocol */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); + + /* Ignore first 4 bytes */ + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + + /* 5th byte of scratchpad is configuration register */ + conf = TM_OneWire_ReadByte(OneWire); + + /* Return 9 - 12 value according to number of bits */ + return ((conf & 0x60) >> 5) + 9; +} + +uint8_t TM_DS18B20_SetResolution(TM_OneWire_t* OneWire, uint8_t *ROM, TM_DS18B20_Resolution_t resolution) { + uint8_t th, tl, conf; + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Read scratchpad command by onewire protocol */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); + + /* Ignore first 2 bytes */ + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + + th = TM_OneWire_ReadByte(OneWire); + tl = TM_OneWire_ReadByte(OneWire); + conf = TM_OneWire_ReadByte(OneWire); + + if (resolution == TM_DS18B20_Resolution_9bits) { + conf &= ~(1 << DS18B20_RESOLUTION_R1); + conf &= ~(1 << DS18B20_RESOLUTION_R0); + } else if (resolution == TM_DS18B20_Resolution_10bits) { + conf &= ~(1 << DS18B20_RESOLUTION_R1); + conf |= 1 << DS18B20_RESOLUTION_R0; + } else if (resolution == TM_DS18B20_Resolution_11bits) { + conf |= 1 << DS18B20_RESOLUTION_R1; + conf &= ~(1 << DS18B20_RESOLUTION_R0); + } else if (resolution == TM_DS18B20_Resolution_12bits) { + conf |= 1 << DS18B20_RESOLUTION_R1; + conf |= 1 << DS18B20_RESOLUTION_R0; + } + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD); + + /* Write bytes */ + TM_OneWire_WriteByte(OneWire, th); + TM_OneWire_WriteByte(OneWire, tl); + TM_OneWire_WriteByte(OneWire, conf); + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Copy scratchpad to EEPROM of DS18B20 */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD); + + return 1; +} + +uint8_t TM_DS18B20_Is(uint8_t *ROM) { + /* Checks if first byte is equal to DS18B20's family code */ + if (*ROM == DS18B20_FAMILY_CODE) { + return 1; + } + return 0; +} + +uint8_t TM_DS18B20_SetAlarmLowTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) { + uint8_t tl, th, conf; + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + if (temp > 125) { + temp = 125; + } + if (temp < -55) { + temp = -55; + } + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Read scratchpad command by onewire protocol */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); + + /* Ignore first 2 bytes */ + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + + th = TM_OneWire_ReadByte(OneWire); + tl = TM_OneWire_ReadByte(OneWire); + conf = TM_OneWire_ReadByte(OneWire); + + tl = (uint8_t)temp; + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD); + + /* Write bytes */ + TM_OneWire_WriteByte(OneWire, th); + TM_OneWire_WriteByte(OneWire, tl); + TM_OneWire_WriteByte(OneWire, conf); + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Copy scratchpad to EEPROM of DS18B20 */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD); + + return 1; +} + +uint8_t TM_DS18B20_SetAlarmHighTemperature(TM_OneWire_t* OneWire, uint8_t *ROM, int8_t temp) { + uint8_t tl, th, conf; + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + if (temp > 125) { + temp = 125; + } + if (temp < -55) { + temp = -55; + } + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Read scratchpad command by onewire protocol */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); + + /* Ignore first 2 bytes */ + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + + th = TM_OneWire_ReadByte(OneWire); + tl = TM_OneWire_ReadByte(OneWire); + conf = TM_OneWire_ReadByte(OneWire); + + th = (uint8_t)temp; + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD); + + /* Write bytes */ + TM_OneWire_WriteByte(OneWire, th); + TM_OneWire_WriteByte(OneWire, tl); + TM_OneWire_WriteByte(OneWire, conf); + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Copy scratchpad to EEPROM of DS18B20 */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD); + + return 1; +} + +uint8_t TM_DS18B20_DisableAlarmTemperature(TM_OneWire_t* OneWire, uint8_t *ROM) { + uint8_t tl, th, conf; + if (!TM_DS18B20_Is(ROM)) { + return 0; + } + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Read scratchpad command by onewire protocol */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_RSCRATCHPAD); + + /* Ignore first 2 bytes */ + TM_OneWire_ReadByte(OneWire); + TM_OneWire_ReadByte(OneWire); + + th = TM_OneWire_ReadByte(OneWire); + tl = TM_OneWire_ReadByte(OneWire); + conf = TM_OneWire_ReadByte(OneWire); + + th = 125; + tl = (uint8_t)-55; + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Write scratchpad command by onewire protocol, only th, tl and conf register can be written */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_WSCRATCHPAD); + + /* Write bytes */ + TM_OneWire_WriteByte(OneWire, th); + TM_OneWire_WriteByte(OneWire, tl); + TM_OneWire_WriteByte(OneWire, conf); + + /* Reset line */ + TM_OneWire_Reset(OneWire); + /* Select ROM number */ + TM_OneWire_SelectWithPointer(OneWire, ROM); + /* Copy scratchpad to EEPROM of DS18B20 */ + TM_OneWire_WriteByte(OneWire, ONEWIRE_CMD_CPYSCRATCHPAD); + + return 1; +} + +uint8_t TM_DS18B20_AlarmSearch(TM_OneWire_t* OneWire) { + /* Start alarm search */ + return TM_OneWire_Search(OneWire, DS18B20_CMD_ALARMSEARCH); +} + +uint8_t TM_DS18B20_AllDone(TM_OneWire_t* OneWire) { + /* If read bit is low, then device is not finished yet with calculation temperature */ + return TM_OneWire_ReadBit(OneWire); +} + +void measurement_DS1820(void){ + uint8_t ret; + cpu_irq_disable(); + if (TM_OneWire_First(&ow_instance)) { + if(TM_DS18B20_Is(ow_instance.ROM_NO)){ + if(TM_DS18B20_AllDone(&ow_instance)){ + ret = TM_DS18B20_Read(&ow_instance, ow_instance.ROM_NO, &m_params.DS1820_Temp); + if(!ret){ + printf("TM_DS18B20_Read() - error\r\n"); + } + ret = TM_DS18B20_Start(&ow_instance, ow_instance.ROM_NO); + if(!ret){ + printf("TM_DS18B20_Start() - ROM isn't correct\r\n"); + } + } + } + } + cpu_irq_enable(); +} diff --git a/TE_Controller/src/source/tm_onewire.c b/TE_Controller/src/source/tm_onewire.c new file mode 100644 index 0000000..629e49f --- /dev/null +++ b/TE_Controller/src/source/tm_onewire.c @@ -0,0 +1,389 @@ +/** + * https://stm32f4-discovery.net/2015/07/hal-library-05-onewire-for-stm32fxxx/ + * https://github.com/MaJerle/stm32fxxx-hal-libraries/blob/master/06-STM32Fxxx_DS18B20/User/main.c + * |---------------------------------------------------------------------- + * | Copyright (c) 2016 Tilen Majerle + * | + * | Permission is hereby granted, free of charge, to any person + * | obtaining a copy of this software and associated documentation + * | files (the "Software"), to deal in the Software without restriction, + * | including without limitation the rights to use, copy, modify, merge, + * | publish, distribute, sublicense, and/or sell copies of the Software, + * | and to permit persons to whom the Software is furnished to do so, + * | subject to the following conditions: + * | + * | The above copyright notice and this permission notice shall be + * | included in all copies or substantial portions of the Software. + * | + * | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE + * | AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * | OTHER DEALINGS IN THE SOFTWARE. + * |---------------------------------------------------------------------- + */ +#include "tm_onewire.h" + +void ONEWIRE_OUTPUT(TM_OneWire_t* OneWireStruct){ + // по умолчанию на линии высокий уровень + struct port_config config_port_pin; + port_get_config_defaults(&config_port_pin); + config_port_pin.direction = PORT_PIN_DIR_OUTPUT; + config_port_pin.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(OneWireStruct->GPIO_Pin, &config_port_pin); +} + +void ONEWIRE_INPUT(TM_OneWire_t* OneWireStruct){ + struct port_config config_port_pin; + port_get_config_defaults(&config_port_pin); + config_port_pin.direction = PORT_PIN_DIR_INPUT; + config_port_pin.input_pull = PORT_PIN_PULL_NONE; + port_pin_set_config(OneWireStruct->GPIO_Pin, &config_port_pin); +} + +void TM_OneWire_Init(TM_OneWire_t* OneWireStruct, uint8_t GPIO_Pin) { + + /* Save settings */ + OneWireStruct->GPIO_Pin = GPIO_Pin; + ONEWIRE_INPUT(OneWireStruct); +} + +uint8_t TM_OneWire_Reset(TM_OneWire_t* OneWireStruct) { + uint8_t i; + + /* Line low, and wait 480us */ + ONEWIRE_LOW(OneWireStruct); + ONEWIRE_OUTPUT(OneWireStruct); + ONEWIRE_DELAY(480); + + /* Release line and wait for 70us */ + ONEWIRE_INPUT(OneWireStruct); + ONEWIRE_DELAY(70); + + /* Check bit value */ + i = ONEWIRE_GET_VALUE(OneWireStruct); + + /* Delay for 410 us */ + ONEWIRE_DELAY(410); + + /* Return value of presence pulse, 0 = OK, 1 = ERROR */ + return i; +} + +void TM_OneWire_WriteBit(TM_OneWire_t* OneWireStruct, uint8_t bit) { + if (bit) { + /* Set line low */ + ONEWIRE_LOW(OneWireStruct); + ONEWIRE_OUTPUT(OneWireStruct); + ONEWIRE_DELAY(10); + + /* Bit high */ + ONEWIRE_INPUT(OneWireStruct); + + /* Wait for 55 us and release the line */ + ONEWIRE_DELAY(55); + ONEWIRE_INPUT(OneWireStruct); + } else { + /* Set line low */ + ONEWIRE_LOW(OneWireStruct); + ONEWIRE_OUTPUT(OneWireStruct); + ONEWIRE_DELAY(65); + + /* Bit high */ + ONEWIRE_INPUT(OneWireStruct); + + /* Wait for 5 us and release the line */ + ONEWIRE_DELAY(5); + ONEWIRE_INPUT(OneWireStruct); + } +} + +uint8_t TM_OneWire_ReadBit(TM_OneWire_t* OneWireStruct) { + uint8_t bit = 0; + + /* Line low */ + ONEWIRE_LOW(OneWireStruct); + ONEWIRE_OUTPUT(OneWireStruct); + ONEWIRE_DELAY(3); + + /* Release line */ + ONEWIRE_INPUT(OneWireStruct); + ONEWIRE_DELAY(10); + + /* Read line value */ + if (ONEWIRE_GET_VALUE(OneWireStruct)) { + /* Bit is HIGH */ + bit = 1; + } + + /* Wait 50us to complete 60us period */ + ONEWIRE_DELAY(50); + + /* Return bit value */ + return bit; +} + +void TM_OneWire_WriteByte(TM_OneWire_t* OneWireStruct, uint8_t byte) { + uint8_t i = 8; + /* Write 8 bits */ + while (i--) { + /* LSB bit is first */ + TM_OneWire_WriteBit(OneWireStruct, byte & 0x01); + byte >>= 1; + } +} + +uint8_t TM_OneWire_ReadByte(TM_OneWire_t* OneWireStruct) { + uint8_t i = 8, byte = 0; + while (i--) { + byte >>= 1; + byte |= (TM_OneWire_ReadBit(OneWireStruct) << 7); + } + + return byte; +} + +uint8_t TM_OneWire_First(TM_OneWire_t* OneWireStruct) { + /* Reset search values */ + TM_OneWire_ResetSearch(OneWireStruct); + + /* Start with searching */ + return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM); +} + +uint8_t TM_OneWire_Next(TM_OneWire_t* OneWireStruct) { + /* Leave the search state alone */ + return TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM); +} + +void TM_OneWire_ResetSearch(TM_OneWire_t* OneWireStruct) { + /* Reset the search state */ + OneWireStruct->LastDiscrepancy = 0; + OneWireStruct->LastDeviceFlag = 0; + OneWireStruct->LastFamilyDiscrepancy = 0; +} + +uint8_t TM_OneWire_Search(TM_OneWire_t* OneWireStruct, uint8_t command) { + uint8_t id_bit_number; + uint8_t last_zero, rom_byte_number, search_result; + uint8_t id_bit, cmp_id_bit; + uint8_t rom_byte_mask, search_direction; + + /* Initialize for search */ + id_bit_number = 1; + last_zero = 0; + rom_byte_number = 0; + rom_byte_mask = 1; + search_result = 0; + + /* Check if any devices */ + if (!OneWireStruct->LastDeviceFlag) { + /* 1-Wire reset */ + if (TM_OneWire_Reset(OneWireStruct)) { + /* Reset the search */ + OneWireStruct->LastDiscrepancy = 0; + OneWireStruct->LastDeviceFlag = 0; + OneWireStruct->LastFamilyDiscrepancy = 0; + return 0; + } + + /* Issue the search command */ + TM_OneWire_WriteByte(OneWireStruct, command); + + /* Loop to do the search */ + do { + /* Read a bit and its complement */ + id_bit = TM_OneWire_ReadBit(OneWireStruct); + cmp_id_bit = TM_OneWire_ReadBit(OneWireStruct); + + /* Check for no devices on 1-wire */ + if ((id_bit == 1) && (cmp_id_bit == 1)) { + break; + } else { + /* All devices coupled have 0 or 1 */ + if (id_bit != cmp_id_bit) { + /* Bit write value for search */ + search_direction = id_bit; + } else { + /* If this discrepancy is before the Last Discrepancy on a previous next then pick the same as last time */ + if (id_bit_number < OneWireStruct->LastDiscrepancy) { + search_direction = ((OneWireStruct->ROM_NO[rom_byte_number] & rom_byte_mask) > 0); + } else { + /* If equal to last pick 1, if not then pick 0 */ + search_direction = (id_bit_number == OneWireStruct->LastDiscrepancy); + } + + /* If 0 was picked then record its position in LastZero */ + if (search_direction == 0) { + last_zero = id_bit_number; + + /* Check for Last discrepancy in family */ + if (last_zero < 9) { + OneWireStruct->LastFamilyDiscrepancy = last_zero; + } + } + } + + /* Set or clear the bit in the ROM byte rom_byte_number with mask rom_byte_mask */ + if (search_direction == 1) { + OneWireStruct->ROM_NO[rom_byte_number] |= rom_byte_mask; + } else { + OneWireStruct->ROM_NO[rom_byte_number] &= ~rom_byte_mask; + } + + /* Serial number search direction write bit */ + TM_OneWire_WriteBit(OneWireStruct, search_direction); + + /* Increment the byte counter id_bit_number and shift the mask rom_byte_mask */ + id_bit_number++; + rom_byte_mask <<= 1; + + /* If the mask is 0 then go to new SerialNum byte rom_byte_number and reset mask */ + if (rom_byte_mask == 0) { + rom_byte_number++; + rom_byte_mask = 1; + } + } + /* Loop until through all ROM bytes 0-7 */ + } while (rom_byte_number < 8); + + /* If the search was successful then */ + if (!(id_bit_number < 65)) { + /* Search successful so set LastDiscrepancy, LastDeviceFlag, search_result */ + OneWireStruct->LastDiscrepancy = last_zero; + + /* Check for last device */ + if (OneWireStruct->LastDiscrepancy == 0) { + OneWireStruct->LastDeviceFlag = 1; + } + + search_result = 1; + } + } + + /* If no device found then reset counters so next 'search' will be like a first */ + if (!search_result || !OneWireStruct->ROM_NO[0]) { + OneWireStruct->LastDiscrepancy = 0; + OneWireStruct->LastDeviceFlag = 0; + OneWireStruct->LastFamilyDiscrepancy = 0; + search_result = 0; + } + + return search_result; +} + +int TM_OneWire_Verify(TM_OneWire_t* OneWireStruct) { + unsigned char rom_backup[8]; + int i,rslt,ld_backup,ldf_backup,lfd_backup; + + /* Keep a backup copy of the current state */ + for (i = 0; i < 8; i++) + rom_backup[i] = OneWireStruct->ROM_NO[i]; + ld_backup = OneWireStruct->LastDiscrepancy; + ldf_backup = OneWireStruct->LastDeviceFlag; + lfd_backup = OneWireStruct->LastFamilyDiscrepancy; + + /* Set search to find the same device */ + OneWireStruct->LastDiscrepancy = 64; + OneWireStruct->LastDeviceFlag = 0; + + if (TM_OneWire_Search(OneWireStruct, ONEWIRE_CMD_SEARCHROM)) { + /* Check if same device found */ + rslt = 1; + for (i = 0; i < 8; i++) { + if (rom_backup[i] != OneWireStruct->ROM_NO[i]) { + rslt = 1; + break; + } + } + } else { + rslt = 0; + } + + /* Restore the search state */ + for (i = 0; i < 8; i++) { + OneWireStruct->ROM_NO[i] = rom_backup[i]; + } + OneWireStruct->LastDiscrepancy = ld_backup; + OneWireStruct->LastDeviceFlag = ldf_backup; + OneWireStruct->LastFamilyDiscrepancy = lfd_backup; + + /* Return the result of the verify */ + return rslt; +} + +void TM_OneWire_TargetSetup(TM_OneWire_t* OneWireStruct, uint8_t family_code) { + uint8_t i; + + /* Set the search state to find SearchFamily type devices */ + OneWireStruct->ROM_NO[0] = family_code; + for (i = 1; i < 8; i++) { + OneWireStruct->ROM_NO[i] = 0; + } + + OneWireStruct->LastDiscrepancy = 64; + OneWireStruct->LastFamilyDiscrepancy = 0; + OneWireStruct->LastDeviceFlag = 0; +} + +void TM_OneWire_FamilySkipSetup(TM_OneWire_t* OneWireStruct) { + /* Set the Last discrepancy to last family discrepancy */ + OneWireStruct->LastDiscrepancy = OneWireStruct->LastFamilyDiscrepancy; + OneWireStruct->LastFamilyDiscrepancy = 0; + + /* Check for end of list */ + if (OneWireStruct->LastDiscrepancy == 0) { + OneWireStruct->LastDeviceFlag = 1; + } +} + +uint8_t TM_OneWire_GetROM(TM_OneWire_t* OneWireStruct, uint8_t index) { + return OneWireStruct->ROM_NO[index]; +} + +void TM_OneWire_Select(TM_OneWire_t* OneWireStruct, uint8_t* addr) { + uint8_t i; + TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM); + + for (i = 0; i < 8; i++) { + TM_OneWire_WriteByte(OneWireStruct, *(addr + i)); + } +} + +void TM_OneWire_SelectWithPointer(TM_OneWire_t* OneWireStruct, uint8_t *ROM) { + uint8_t i; + TM_OneWire_WriteByte(OneWireStruct, ONEWIRE_CMD_MATCHROM); + + for (i = 0; i < 8; i++) { + TM_OneWire_WriteByte(OneWireStruct, *(ROM + i)); + } +} + +void TM_OneWire_GetFullROM(TM_OneWire_t* OneWireStruct, uint8_t *firstIndex) { + uint8_t i; + for (i = 0; i < 8; i++) { + *(firstIndex + i) = OneWireStruct->ROM_NO[i]; + } +} + +uint8_t TM_OneWire_CRC8(uint8_t *addr, uint8_t len) { + uint8_t crc = 0, inbyte, i, mix; + + while (len--) { + inbyte = *addr++; + for (i = 8; i; i--) { + mix = (crc ^ inbyte) & 0x01; + crc >>= 1; + if (mix) { + crc ^= 0x8C; + } + inbyte >>= 1; + } + } + + /* Return calculated CRC */ + return crc; +} diff --git a/TE_Controller/src/source/tmpgood.c b/TE_Controller/src/source/tmpgood.c index 3155c14..0cf954a 100644 --- a/TE_Controller/src/source/tmpgood.c +++ b/TE_Controller/src/source/tmpgood.c @@ -4,8 +4,9 @@ * Created: 03.01.2021 23:22:04 * Author: Lexus */ +#include "tmpgood.h" #include "conf_board.h" -#include "port.h" + void tmpgood_configure_port_pins(void) { struct port_config config_port_pin; @@ -15,7 +16,7 @@ void tmpgood_configure_port_pins(void) port_pin_set_config(TC_TMPGD, &config_port_pin); } -_Bool tmpgood_get_state(void) +bool tmpgood_get_state(void) { return port_pin_get_input_level(TC_TMPGD); } \ No newline at end of file diff --git a/TE_Controller/src/source/ws2812.c b/TE_Controller/src/source/ws2812.c index c65fdce..a31e175 100644 --- a/TE_Controller/src/source/ws2812.c +++ b/TE_Controller/src/source/ws2812.c @@ -6,7 +6,7 @@ */ #include "ws2812.h" #include "conf_board.h" -#include "port.h" +#include void ws2812_configure_port_pins(void) {