From 468fe59d9747078830dd489668b8c8ee8520b4a5 Mon Sep 17 00:00:00 2001 From: jaseg Date: Sat, 22 Dec 2018 14:38:07 +0900 Subject: [PATCH] First AC/mux test working --- center/.~lock.8seg-bom.ods# | 1 - center/8seg-bom.ods | Bin 27356 -> 28489 bytes center/center.kicad_pcb | 27 +- center/center.kicad_pcb-bak | 50 +++- driver_fw/.gitignore | 13 + driver_fw/Makefile | 62 +++++ driver_fw/cmsis_exports.c | 62 +++++ driver_fw/gen_cmsis_exports.py | 30 +++ driver_fw/main.c | 108 ++++++++ driver_fw/openocd.cfg | 14 + driver_fw/startup_stm32f103xb.s | 379 +++++++++++++++++++++++++++ driver_fw/stm32_flash.ld | 137 ++++++++++ driver_fw/system_stm32f1xx.c | 438 ++++++++++++++++++++++++++++++++ fw/base.c | 4 + fw/main.c | 43 +++- 15 files changed, 1343 insertions(+), 25 deletions(-) delete mode 100644 center/.~lock.8seg-bom.ods# create mode 100644 driver_fw/.gitignore create mode 100644 driver_fw/Makefile create mode 100644 driver_fw/cmsis_exports.c create mode 100644 driver_fw/gen_cmsis_exports.py create mode 100644 driver_fw/main.c create mode 100644 driver_fw/openocd.cfg create mode 100644 driver_fw/startup_stm32f103xb.s create mode 100644 driver_fw/stm32_flash.ld create mode 100644 driver_fw/system_stm32f1xx.c diff --git a/center/.~lock.8seg-bom.ods# b/center/.~lock.8seg-bom.ods# deleted file mode 100644 index 8d13aed..0000000 --- a/center/.~lock.8seg-bom.ods# +++ /dev/null @@ -1 +0,0 @@ -,user,localhost,27.11.2018 17:14,file:///home/user/.config/libreoffice/4; \ No newline at end of file diff --git a/center/8seg-bom.ods b/center/8seg-bom.ods index 6410120c1bb5fe7abb1e8b03190c105b1f80d9b6..13bb9d92160a756a8e9876a108283aeed95a5555 100644 GIT binary patch delta 25798 zcmca}mGR^~M&1B#W)=|!1`Y;>=Yq8pc?0>L3)cE(<;-F^Z@|EC-e6)*wt=~swz09X zxs|bvk&%_DwT+FDjg5_+rGt%wrL~8LqnVk5t%<9ZrI($pv#pD}o7H4?Mtk;{Xs?iv zkkHA#j7B^e>7hjlaRqsiB}FllyBWIFp|LpHM%cuXsj7-Hd5fljWFX#X2WXo;-W@?B@9k=JYR^H*wLl1%0!Z zPM#ddq$0jzS=)kD(-*CsxoqRy4QqS%EttD$L*LHrlY5v-RTmvNyY1+uT_>*XJ9T6K z#dFKAAJ}*O@|wFhH$FYE@8R7oFQ4uD@MiyHWo8xTyKgQ|_GLEZzVYSFkuPs9{rh$L z-{f9qwfgt(tN$@D=yrL!IEGZ*dRxmKB7J?XdB5}NcbdM3)qZbn&6QKRp|yq4GHeg0 zia?6Mw<~5d)@*dycXLwBu>>Khj~fC*rYq%M_hUJx>VAX8Q*~O-o5|C&Zz<~^vv7Uz zVzR&_88eYM{lCBZ{eOGK zGk>Q!T@zTV80EaBEra*sb_qe=OSLU0^g1|rIXSzhUHZ2(vAzWuo*u#xXrcaNH3ms?Xl$*A(S9i|e^cQ=*l{qzLF%+=`91CbT^lW*A z#|)l%0y6^Kcs)=4(0;zxOW8wdT5s=q3zxuuZBIWaa`k^ux9@#XJ;!ZgV~5GUyHlK{ z&t5b7wj%da&2bCo3wIB{)wrf#xuHHF{$Z(IAlJ;Gux{417yubw~nY0!Ff>Da%6R|r-rC>lYZYg0);o7?X4B1dnUaL>DoQ3tp3PXLe__owL*0{y zUF<%JS*?8Kb#bbLBPRg10-j5J*2ucn?-0tAacfs9EOHalUX&XnXds;# zxaNeQAQ$U2T|OHIYkj}fq6S$mU6(RsPMvtfqH?rb)UcywrUR!;NAoj1slbvcIxLTs zd^-B1Rrx2nalbH_XyYQH*6(1dXcTb$f=Bfdj?N|~ZKlBX7fKZwD{Mu&r!}z)8Hh3J^|7J?>A(@`uM#`vag_J!u>Lr ziHU_hZpSmWWOdHk=)Lc6$D4(-0)oUm+gC4r#j(=r&c-E{iQk!&RAPj*mL5_Oj7TY& z!JxFMRcD^hcLpV^p7vv|hI<4;gtfTE@35OFsfs+FaA8JE%9En4Vv~b}e%(GNdF{!? zSb@xd5ZlS8Lbj~eyIn8CqZQj)6tMBe5noMBD@)HvB`5V(QOUO)OcNEDdOMhOLfnn{ z=F0j-s(Q{n+!myue3GNlcWo;FEyLSfzFSmF&DyxGzRECSNzO4-m{{>pI7fL-cgu@6 zQ9|?DCMxpzuzN9I*nG6`#fqB(uEr4^Vx5oN5*KpxPig(AGV6kd3QK)=M-T7i7FW;5 z0*)>@ETYnK(z}comsOR7Vb!4IW*ZYYF&s{xq^)@^AGm&RH;cl>Vg3=n*Pp(vSo}r zR$3)&5}3pPnn687Qq$k5$WzjZOJL$GCl|q>fH1+G4DVzW_qSJ?WE4!?Y=3{k{yG?WWoS*4!Y|H{Tmj(*0 zby0Gxmk3c3G*lAQTCg*SQ=CE2bBBtS;00rW!Vj~4Rmi;mBeY+xzVJrtudut)i?gX@`XKO%;cT zQ#%=WA8_%xB{@rMEfaJ3eY&Vd{Jn-(=nsLbCeNmA<*yfCy6dCS(JewfI-kE!D^5;4 z|8(tqE}N&){MPKBlKZTeD=%8o(W1DtBV=t`+`AaTCZizJ#ghX#7Kfg1TCwG!d)}Uh zO#fV!-_>1dU!kwNe%U^`^S1G~41~`cU49Xk@1NxVZL06NL%Hm8*ZzDu+fKgJ&vgl- zC1=LLt=tlBtDbJ!Q{Q*xghbSV6FJ5LQ=cu_zP)&!zSOb1J6~pgwU}qtBfj(VmoEF~ zOO}`0PMG&@meZ`K?j}2OtN%GXn)xaB_P<%W8CvgG<}%Gm5)x!`F;JRh6f|R{pbOXc z10wAmZ?Xh;+1&YkY*Q`6qCj<>{g;hjC5GEfmh8@$c&9qC!Y!gm_w=En`uuIvEaxr` zcDZ;;Ns3eD?51VXc2bt^jB?A<*_Nm(7M;ESXa9_v4X4AOD{RfLR4APDxME$697m>M zM@*{4zvbnQ6V1Pyp8IZKsk7$)jE0z5w>$cI#Gh`P-qaqr`GwWFwd+`j%>D5A_%F}hgMatEdGcWW-_GKX{rk@c%G|vE zt}3gRUE@sa*M=QG>W^G6dBRiNCVrfuc21(kyHlO_);4#Zi*0?%?E7p2JC(54fb zHzqQ*XgghU=w004!<1oCcq69c&YVr(zV6T#RVXSJsqbf!ZJZnx%>U})z0avT-KDNQ zmSqTBIdAca)t?xD@6gDj`<5?)tJ4I2_$3#8-MCWnu>{D5ntgpp(a)V4Z&%uWe10x{`ITkGU*`B9mA?*6D?Deg zWp$}@{-dc!uJNvw=6n8p{=Eyr4$703hcYvVFJ@cC%oN2ZyL$7>3M*@^>1QKff6zbo z`0(4R82dZ-u3x;jbp7?>f?8#blH=2Vw7Pw7Ro<`v_IGW&_xrpzS>>j?>c94yf7vjp zRHn4F^x<>q##i_DdHm}6QTqPgvbgluQ?-v**{1jL&z1c1dZvR^pw)tB7YvdUOc!sB z;$3z%D^WjU!lx5+cki?-h@Q`;b?ej%!Mbw~KKe{udph}}u5GW*w?DU!*u4C&tG$Tz z_0sxik7xOnlRJ)0o323b$Pn)w9iQw>*TG=vV(auSd~g&$p+1@jAKxmA0-C44)GFC(!pD_uHlG7P}W* zmoNNt`nt$Y-iqp#_hJ`&?6o`mC%WmT$)kMl?VQ1_tM*4;jXk)1h1Qw7x@uEzB&`kL zigYolpT6nzmOv9_2h*aU2OMk{|7}r@e>7*`Uh(=DUH8|&@bP`U%5v5H>DQ*#ZDd=) zWLf1Zw_N+H)$%R-=1wkqc;cU=OXQ@xCQO2V@BGp~B~jdDzHI4*Svu>2LL=&@rG8OP zViA&F>}sN-6!(lM{^Eg>@D>ta{pgq2b2=d)v|kyf$8#Q$tVFFicgvTbN_={%eMO zI~`Wv)Z6TNCCh6WCtF~YyZG}%yY?+QceWx+a>+$j*T3_iVEA^Vh5x2W9i+ zAs6?(W3Am?=aoDo;dVXaTiN&-wN3ZG{kyY!_s$!$6M8exZMxR!d)Fyj_I||k#ezHM z9@!DKR-|x4$CHB!uc~V2%e~jh-G8sce23`zo#(E9nOe4O_v?=`EB5X5s=r^slCOVh z_vu&CF{!5SB7Yp@IK8b+JmUW`U)^o8k>>^Pik`hTjVpM2Ylh(LwW3;6``zlxR`wJn zEa}~rDAZZydFOZd&V$o(ZlwvVneA%a^xN{V(P`zT9ky?cYm?u6J5zk@&rOLRciOuD zACNfnKyZCNYfW0D^ymLKw{QE?@$Tss50`tL+!f6G9$W8;d#@!LpUQh`*HU19=$ ztp1w&>)TmVGe?O@n}m2C6x}zjG;VRqZmZvLW5%KUkFjBMrY2McL|lw<74VM?=j*z@ z{f$}w`o^Q@_rBB+nHb1%XoaiIB&SNHDc+w0MA*DtS+Bh55L)x#JxijdS!uXnO{(d^ z=g}QgMAmPbsnBzzaoUo!Zu3rq^mQ@{3oVvfFSAK9*Ye~St>0$Q z!*DpDzKwmyyfF0zk|K`}D%M6F$S~Qg9QAyEUgu6%PlhUinGBE52Xl0E7^GAkeJ->{ zm2G32=P=lL3w&qE~hF=u9?MZe9^4RPVBV!iHHLI+InkldA-m*FV?! z5Sv(aaPO+F-#=OQubQ=?tGCo^k^RZ657(_2-+WdJbaS|!!g087?G4GfGD<<&>Fz1# z9;7oY-L9o}Sm8;yVB}18otk|MmAJPpopHuT)SlbpJIiU~n;2S`fB`##?$ zD&#HyEQ`(8P9$hVOWNKR$LQ?Y<|Utyv?n+F*6xR6!kQ zg;hUW%#ByK^7DnC@ob#Q(Y*N67vtp-PsQxlcMB_8MJXlba5!CDQSZ^xA>qQ3J}bjz zk)^=W8JxxD6>5>12X=@%YeuJTnwGLbtLgd#AC2e^l|pkx6WyuiXJ)Qy{h#EuQf&H> z8Lfw2X(g6V3%Ge!|C@INqw{Bj*&R>snel2TvZ{oLRTLM!m)L(OnN3OkG}o#5GgDuj zKP3`4pZof}Qb;LFe8z^9G>J1}@{3mGDRn-$t|@+`BK<;I zj#c}Nn5~~0&nayA(0QgyYxB+{5wW>u%yS(r78)z?U0Tk{$k}a~(Uw%Q>E{-O`h8sn zDUGkAChv7KOcWA2DSB7U?*952YQkEo6&;UMF0VOXWf{SIK}!2oSEJsPkZ{Kt+C68l zwpborHS3DxB1xfZR%@jaZ>$rRTO4>eCTo84^~&G1Hf$Md5}u~nJASENTjwCw-MZo1 zW_Ix-f5fKg#8rH*`>^$Zbfj*<^sC2Tdt9i`cn~6GQO`E1eJ0#(;->X_8J-<5pDvy>!s*v21 z2OSNZViQ|GeCiZSxRuUydTPGXfv0~vb{%Dy7@2d+H>Gj%ntLLvgJv?l-p%E}s-mPd ztJl-}v1GuZuGVKd^-A7zuHMlxlMyi6uG0IxnmIdEWs{+eT=PN^;SPdzwoQqq~Ma|TCO$gO$(t;zYGSnwvTgRgrn8M-GrUAZdgV7lss z+NvqtX{~Q8Pd+yaIeL%fYV)co#Yr1a&RDogW2N>-?}&L}3F0dPJENA=KhD~j60qmo znkL;#+(oNTaoy%hZ1~IfY?@eec&eJuT{q!3cAJ@EPp)B-Il&+)e`Vq>PUZ;4=(g6+ zzcy;d7N_aId1Fv{R!e(_+zHO9H=jJ_5&80b!^IxnWDVV&yUgC)xU=kD66>42SyTJZ zF5FPJ`!o>w4AiHJSJij_r0uf^X8qK~ ztUCD!5inm$7TU z>A~Fw_YCTrGajUcUUgE~Gy@W49vm?w=)D&S{*ABHUBOii4iLt5dXixl+ z()yk)7&c>dr&i)LSDl=&S$mHj5_3)q-P&(_!X+w7X_K`}y@sx^=f28HlWi_+|IeOW zyivhAGToRdzwcg4<`jw4{cnEx{$IELedXN5X|apXahi7qKHp+_f1az-r*jga-~8mW z;*2KkocY7I|FZqg*`-Dnb_TqHZ>3$9J(u&IXSr#Q^+|^Ir9o?s9({9SQ`hHtQ^ zr*khpOTQmgP=46=`LR!@_uiatUU|w~?o*6j#h-|TwaKb$W{EIxMl)P%a+;E(_N&o@ z(d=cTPSgDu*A$JlcAU{1DmmQ|980t>w5&OORQgz&f|SL?8&9v8pqmWQ=g_v^m3 zIk9_g@ZP>@$M)vmV=?NR@pI-cX8Yt~ozJpTt=AvEw^V25p{eR_7ea<@P%eJ5ATs}8{ z9$VYAo)tB(uQ?S=ZH%2CXT4?bR`vONgQ6Ecclnv>|90z7xd%pS&pSU#i_V$Z<nTSC(9b*H!bov*)e@VM=5cCK4|>(~_1-+o)R z?EQDS)9YoecI;ig;BCZ$meP)l#;~@VtV^QwmN&opUS<~;Ig?}k#?{XY)~07?e^a{_ zYI||>YnPwbVsE#H$z4o%UBkjE(gCmskdX(rw)g=es6qb zJaTSVU4FJs4w^c*JZMWUW2E2d>XW__IcAg8pd%D>v?cvg0GRXra+&$h~_ z^_J|}+1Yb*{rqotUQOW6ZLgYhTrZxj^7g}n+xFMp5_?hqf%`D#*;@t!Hu_4?EHUig!gFM4^AK<_=})_A+Q3s>&h!`bj^rA=9-c#6%_3s*m0 zK0NRA*5-NFt~$M*^I^Ttn?gUwmXn^x>eZHKY~@?SW-5L5=aHGlw`a{cw|2R?+-<8X zS0>;8W-(y{YrpmO?_zO!F`^c0pXMH~zjQnJ=Bu2wG8z_l#Ts5_2Q_?rBjlsK$(#7-^%GYczO5N0u}@L_FF>j5uCTfB5uyA-;ge<5Sq6p zMfJ@=mw>O94iwbIe@QyepIOV$Zh1YXB!)=_U*NKFriJQ$mAzx8*;;~Fk(gouQ z_FGo}`E+XY$Hrxf8B^8yQswW|?X>ytlH~CJ+I1DDk6Y@4+8GK@JZ0kI^h#e*YIQrx z_T0AEt>LrU_~NX$aIZMXe0wwZoVCpJ4sTt3@EHG7d3mijmJ{zku?Z>o`Qz#3wT*Ke z)elN+ow8&})-kn!4=UDL69Vo9zxm5qP;K=^uQ%29rA7-lV*@aT@vb){eNB9=JbDhwJQPuWoD|c0jPJLS>ZO~{?zKIbogHH_FY5fu zss;ZpE}ktq+w%Rp+P!;A(yLdkc5HmSbiMe~qJ1&tC9$>V>dxJpHP`)l@7}EzE}FWU ztJ*{Sx756s*{|w6r;@KvU;e}S@5?Ich1`xDR$-dypq{}Fy}$O~@07ngzfAV{^@9r(-Y%`sTYh-zufuaKe^0lKxcav4-;VQ} zELK`9y-=XA(?XTgFDuRczpGMv$b$(ATl~%`t9Hcl31n{Nv*?dF zdluFk%lhkP?LWuZA@ybF%DEQl#yjFytu9nwt}O0<_s+eO4|n{sdjG0(&xQB7Wp#5m z*f)EuTBpR5q-?$E&U^XDf3H$?&nq5S!m)HRw@lE^2C)Q#E7xjFvi!aE4@(!Fib<`= zynimHwl>rK*Uw-3YAdR&rJWvsofWi4$N%EgxTsqjE$g@Ev)&5ayn*RM%u67`=5`yF=yS_ntgfq)#>WD zZpU&RI<vQB)NtNCF3s0-qm_&EGDxS(b@bO1??90sAyYKAW z`7(B?{*vcqN0%?XK4ssB466eI`z_C|cPx3z*2LFi{ji_AEV*hz^X?;p$%zMFEMDx~ ze$4dh%fI)GL^c{4v0Sv6VBvDgz(~-Gk-OlYg?i?WfA7y1TYcn{$Xm5p`ER|FhPCvP zrNW!?&DrJaME+cRKBer~`#a{Ir!ouGnGT)4BN6El&>KDPPj0L4{r79{?30x+T>CS3 zYUAH~@wR6#SgmbItl%?SCcHR}rHuXTZ1KRr@VIq#vOCK5SbzT+6#nbp->!4}@6Wl{ z5%1GpUbA3X$>!aU9|c$ZZVj1ZT=Tulyk4%&;Kqth=l=Qc-rlv^a4~qt+Xn&Jj&-RF zz59}$++4xT+BT1E#&eaY3ljF|>iF5|FFLn(=hEko@9wa^_w<-_@umKG?>{8&E1dM(f#*!3j3F`PpP=~LDfRe=Y!QWx9O+N9ajJOe5$wIhMBdqu~s_%{z8dQ z%MJE))*oTZXgO&h?KN5C@LX}heedpG>TA2Q=}Mcu-PhG6tkJLkU0+`p`hNLEtNXq2 z8s4p|nybacj8rWo>>TG#REV&#_0HVsY^7lRA%d8tjUXub6t^n*8evdg1qr>4()Ssb{1_Y zQ&AQSVbM`xbNevos$J3U?`Au`P22TKw6gZCYu7p>2G{s0t8cu&wS9a2>eVZB!p|o~ zn$KB%{G(EM)L*|p-B(s#Y)b2wk?xt3x_EEt^pNOPQ_iY-PTM8qe3~)2bmPIGn5WKP zN~cVl_*Zyk=;}bPcO6@dHTaz~Z>7uMd~q{7Hd%1qw>;;(sOrc2zRJGrs#s859J91* zdC~cD+y8%#w%z&BrQe7j$tpI-ug=OV?oi4Wizi6tv zB937l=hUj82X|CcuIDa_&)g)%x%pCpsn+k_utO`hR7Lk3`}oi5!$JdVXR92OV>cwM z*M_Ywoe`CLc*WHEjvUKJ>}Klg_i1mO7AyDnx%u2YJ@ZAIy}kZhev~{fwx>tWei6Ta zokYN~{)BJ;_8)xnck}z^wcqXQRE2H4+gwoJ<+ZB>h z>G!LiTy?+q>%m`shn4mgKR^CHU-#wV$^QHQu5V8N{^rN^@Ez9Y>O|`6K27XD|L$h- zr?->S!&Q2P%zeYwAAMw+9=S&CP}0_>IR=t{K6R)+e<{%Eq9l6b(G|zDZq~m!D*njZ z{kbzaeSYohli}a@d_D2o|KI%d`}Y_H_U?K~Oi6PV@f9 z=o$42{n^#?ZpJi~r_FaIy{;|xI=Q}n)rarZ#_=x&y3|}n7GFE!S?Z`*B@y>+;%5JS z|KGIxzx(l^Ioemdn56!u9oJrOxAXbh^zu11Kdy$)|8v&ezfOYT>6?<0?znS( zn>Jc)j^LcF;-h6I;~}Qz`=#1=%NubX&K%o>-C0fD%d5Vf+RjEAH}>|wANFmQ|9{tA-sZQA!qMpS`##;7XPbV0 zUd=a4hMeQStMApnd%QXSZRL-hvhu#`OHMasO$p#S`m8?7Ddx=fDIBj~orzl*koh3| zhwZ9>C)<7XyHYrmE_pS7UhygZ`{VHVnU$OSnLkxV{t(i-`>FVS_P!@J2ftnUb?x}~ z*x4TEG^0M&haJjYf{mi|8&Ya0N`f_H? z$Gw6RTigV;vOS#G(IH+hvZ$qQzW&euZCbUPG~G_br#xwNT`rW^rnqcYyioE3?xRWj zy7bp%JWKy6a5IHRX{wheW6l4fg3o)IlS+kLO1EluKlrYn9I!=dog;!0x2QEoO@G)gaC*;{STEb=j4d~rZuGrq{cKh2Dd3a%_0^N4io0)D zzTEG3C+_K%Hy!KhF2Ae~6S$~(|NPSW{VexB?49an;;C|ZO2ph}uFAJQ?Oq)&znewx zZ|8yXZu5Jbdlbu)-u6yk7x(w;)z$SkioPyyO1~Gw=(5=}VwU!)YZEz`X3PmwxMZmE z{awerx?iv4mHhYaOg+6+-2Ub!)&-Txr@R0EJ2y>t{@y)LpPsMKxBqr?n(nLkyqzUq z^Y5RQ6x~i`mSBL-4l+2FZ8j$fUJba4EjIP#GS&7>NZseTc>9~4wt7U?P z$4uT6*LSbxWw_`)J?>V~tGVTJ)#;~C>;IJ!`PO^C_EX85{Q8fl>%;#)ID5bL+hgg96P@7ed) zJb#s}zyIgGmE!t81sb<~W49mFP`ME}eSNLh%0VXGsTy z(&HofQUYUiq?YcrUbMQte=oDZ-(MT2Z~yb~rTM*v4!i1KOQ&z&^ZCYX`yXHZ@BjF? za{j)LMk`9f_5Xfi-=Erj;M%T_E_$ZSTl?bYUW)Zm39-L1HzZugY}Vx0M?zH(oqVyl zCr06VmWL&m@+Z!Bev7@s?RWk^#g&u_F{Znv}Q<>dV}MK6WwGaQy5 z_;z*m{JB=8Cy#TlkBdr+W1lgH)xdm#(d@lp`X>?_jOwqrlzB)VmJvBSpmSLrHA`;|LgtdICbP*gR}XK!nM-o|BmJT&z&e)m;7#fUTh84^~+2OzFhw(J#qh`&w7u3hnBQ?J= zb7wDKTjo(;vCI6!+ftM3>!w=mu+p8r_gn8O#3H)q@5+W7B; z_>X6N+joC%H~sy!LVS++lRCS#+WZqfYS#K4@Bi}gu=a;%FOJMRb@^s}?V}Pe;r|tt z2SfT-S=*S_IGbFM*s||thDpummJlobMT^~wylOiN!kuR+z5Q7~r*`ffzP+dIFTeb` z?)hh_%UMB%f0E7}xwAIYxk}l4(ZrPCw@=U9dvo#B5w-r}S?;3Fw^fvGSgyHdpmeG2 zM#jXs3rjzrEAf(j_D27$NA{0T9_KFpdfmJ8&7HO4cdp;Hb9ra7=S`#DowGaRu1$RI zZel4~n)LSAlkQ%zAF~cdJ3p4I4~^FTY`<0~!}m}20{5v?)OMCJx)y25_X_k}%UH4F zr+{Wb>+6i^zr%N$=9S+(cRl870bh8P-@Dg4y62WHI&gPqLU?st^J|VcW1HI+uX{O< zZSN>Qa_^JO8T&t#|7KqM<2?WRyH~ltw!E!S=-sk{WdqX;!wK>MN+PODSJbxd`2M7R z!^hsGSFFyrxHQ>KTzpRT*Wr7!Cgq*mWcHQi)3db~qYFO%_tEM0-JagNDT!6`hn`#d z2Yb06&(bEuO4qxc%iee0vcLYp#y~Tx&i{gao4V_BYou%3*6Zec)Y&ceFbo6o!FpL-X0)!uTG&uzm= zjI*?4Qut2EZ~K&xq&?y4)9CXm)70ZU*PJP<&3VY;pI$R>(LA>$+ipMF!s9O&0vdyRe(saA+;icd zKbynn*jvZczrMrLVfv#o>EXv)zH7I(&plY3pm*%@6;6RvjmhV2mv{x)T{-)`Une~* zRP^`pM9nsJ=TsG56NO2RP2I(l{t7#EENr)1pCfgv^v{LF^lzd8uQ%O3mvg_Q^7nbR z<NcG{-oZ@RdleDg-D$z2am6nPb1YT-S7VFlmj#Mu(O7hcwELo%6Bfa+d zpAHv^)bgd?TIl&Tlbio$Wn|Is4B1 z-+aMIU*giH^CeQUf3toG{g_$GDEadAiIq2h)URWm-TdWh&EhTPVvQ%ve^=BLpAvoN z^KPf{=NEftInDU3d$+#hpS`4d)LX%N#$%K9^u?H;3)W7q*H@e@kj}%+j939bxnAEC zEVo@h1WfZ8n1g9eL&eGV8C+;;6(`R(5P{2|MU#JHUaAN4dmnxUO#vtE6Q-X*A+|UoV%~W zX8ht<`yuFt@QkglF_)8!W=$<#Tz~ex(BCirR5)J#wtKVq!Y<~-%6XGl?pov(weu>zMHaL`@A<6OATl45C8RGN>-k1LV~i9%9`5V z`KDjq2X2u0pY>2C^mW;BiBQAViF{f10u>o;UBTN9njAH`^~u8}}g&HEjyoL=5-_cQ1E zeDv}CJx-n*-A)@M&v+hvjK!O!`>@K*6v^{HmMLhPJ!f3{_rrz_ukK9Q`s-oXYCpl1T%R5-ICqF>wr-s~K+LJw-LVq{O-~erum~3w> zTmL%mwwcJk{mTumBt|rzob)E8ckhjZ+upHlalLr@A778l={p*M3pA{6p5J@w-#g83 z8r73zCoNi2{p5z{t(?3I$DWk)@$WBIRNeGkJX}yV*TA2%TYQ>%*;>KATCoWhF%j?Y z*XGZU6hG~M?q-&2jSc^d`K}gXWm@Yr{oEB~mKWcx-?_m^?!2Uzr&WJo%jKOPp6eXk zC^&2S#bVPbd4Z?ey0i--qaJ7*hD0Q3Z+cPm;{;dCG(L-4e4^7L9&FLsm*m{KJ}7Jb zjJKOL9GkAJ*|A9FUvA>sR*z?WoA2fwzx{H?#|t0RHqTsK#ohduX?n^Wt&j)SGmvP}DN(Tqi#d{py(1xE=i~;tkF%GP}g^+_Ju5!$-HaJ&whe zFa6Fg=R3~%c#%Ph>7E;m){~V&uPZIOyHcx~*W`)g1uoX&WqeC?ReJX-R{UNPbo$rN z`IcNE>*Dt^&3o2x#CEt|ztGd004MSPK0PTa+SK8aI#3ytEP zy`;2SrzT`=T00|XwbZdU8e2Vi>K%_ws`T77>1U>uXzsd-@5d(AZi@+BkoWBI6tT;l zTTQf|cO6`{)5&fd^P9^hmFu+QF4|nWzjPw^Yu(cpCVx8~U5pl4zBoTVQh9|Bo2+2f z-VJunoZkDhoJx0_uHsQ}eIsz(pxk3&iT9-|MZbD092c}{^J|=)D|V%zxm{mbNU6qq zMWOVOPOb~mKG}X%Uw9WElvB~H>0YUkU=!B;@X)Eydk<~qJ&wP4KGJ@#>KTEo^}&sc zopY)VUUTW0_n5aUki+P1-Fn9NM|X+&?>jhI$tI_A7VVHb#g+U;;>7#x z%agTDWLNFEdgYX_#L@7-UECLDT?rMBwci^gm$k62a^3fpKg+g0;y-&%`}(Rzx1ZZP zj%3~BaMV*!ocQ%nF!R;rQJ&VG3A zZ_j-+yj$r_z@!Uva&`+%W8al!wAXTre9M9&fu1}`VaB{;M?Sw_^R(W+{?Aoe(e{m% zUk?1wpIG0sB|xz@BWjM^EV0XW=Y8z$&dVHoX1n}ovhsh8%)+XcEfwDw^IP7Xc-j8( zYlWFpxy$=Nr{6apE__=x@3!O}-)V;zoczRp|II|!SgwEnJ|DibLGILBJDGdM$7*uc zS)AJ3%=i7UjCQ>9{I?TLarC;LY z>73(*K8jb0#MCuej<;-_yJ`y4zY|j@zqc@|7hQTx)>-4J&;6&H7GCrIoc^vrd2XwVb;k6lwf@m~(5mxrIc zel}UxN+#l}?r)X<=CR3ZE}ri0?k-+_Z^m{NQ=zPR)8p3Y_4L|KdA3aA@76iq|6FIS zmA^P`p5*!~*9;D>ST*5ZcGKktAJww%KQZsBo-x;ChUx5+0q?q&IR2irR(j6U=aUy& zsn*||m+qf-?NX`i*T=hdiVE%cla#{Kmlvk%=(hFw*}ap0o=mBE=C^$E<(1Y`ozGnL zH+;FxV9mMr50freoYCZ7AufCR<{F&^x8G?@oBQq6!!7^!FL=5iRGS6*sTA*LXJ807 zL95Mt8IS-E!)7;YT}Eb51F6hLr(RLBb7o7Q;+Nn`!x3sb<|NZE+(gFA46Bdh}1g)$KnyTz!^GexhZ-`si_a8AoFa3Gl z8+Zy#F5c`kD~)arE>+Zl+&i0*D7}I+Ne}N ztxv~5$$$DOpNU$;#97v6WxXP{S4JIt9qy-Vfh3}uP>>9aOv z-+ygu_UOdXfOLTflMu7XNs^~LU0N=M=xgOW*41M{&ny} zZO5|BbJv9XzfQlk@5gaQj()+951D@5-jcBA_q4F;C3PF0+Q}TQc#yyGBQ#z=x#iXHq?xl0(lh;p_FIReB+qr(> z?&veaZ zGB~fWE&0RqjhfmD6-7Lol9W-=ppRtpzk2~-A)OlgO zMv2n`RqdC{6`MU(XE{Ioruf*wE&R{tM{Cs&?q9k{=S7i^onvmW&rLCtWu3gC*`+J(sN3WUM{#Ua3*A@tIM9<}>i` zB3IVLFXOlHR9sU1X2Ox;v{#oI!_4X*s4*^dK5&Vs<#{6?-sCw&l@s8QvGrJAEE);K@_U~rrxn1XX zS2MOJ{ST|N5-^;Qae4ihFH0w|M$A~eaWv_?(IIm|1M3A-GA|De=*OOb;gtK`@h>;zixJ8TTfhgt;tu{*;}66v|oMh zu!C_{*%O-@Uis;3tMv~|yuW$+TZhS?xBa;rdN889tt|VUVDe9kV_DWa=2qMG>`gDd z$hXQ^|AVu+L0ZF&^L6XHVvE+_-SYUyFR$n3RX_TpqtEPhIJG_h!a~yk)wk)})347d zTyyg0jhB}G=bDA&doS*st6t7xeeBHp(tW*Ev5#(SSLAUk zU7fy~^L*9u6;*p#+rl5tjsD&9bf@p$V(Tq$!cM=-lD(aGSK?bvQty_&!uoa6wbs*W z=0qjGJ-IRC?kdZJj;qSG|EEl8vGq`JzIUBIh~yQb_s@m=v}-mdm~`z5>CQluKU z&t3UdQsLywn2aeG&O6A?w7gx~;JJOr+|BC(wco$bKd7m6-RS?>-V2KV{J+af&AtD1 z`NRde4SPA5CrZ|S`W;-kZF%4e?>BGK^3JJ!&)1y4PV)mVryu9J$Nww6CV8(lhe&3E3}|CvCgv|HDK2c4`83>!7jO6ko;PEC+v zdAqY-eXIDsU8UA5Wy~|*{&4l%b-T~qdE$gK(q18+T7BOS|9va2kQzD7Wu}2+*QA+} z)?%zp&l%X+pEEi`vRzWc6iAK&Hte!gW7e;8~~)~~mcxveZEd+c1I!NSMwyZOX} z<<-u6t#|pjcmD5hDjy%+HT)~}eDBQVwMFaip8x*@B$AhL|LNYD%Trr-Rs2>sQT_S) z3HIiOslPIkj^CRk5?`DD=jV$DW_{}IZ@=BWJGaPvih|6xiK&rqpWNPg;GE6f6scdH zTGum!=YMK<&0Vsf{+shH!QQufK7HKMt<<}Gu^n%*c(3ej?X6avnMWoWl*mg_hwqe4Q>n|+I&wB&>qzXL@|5G-CBJ5GJAY&P$@QBryYJ?5 zubhAMvYn=u`WLmGSABx@@5!?qj0vf8zI8*m(6A-T`tP0zzw(kl?Y_`mpSfegotrc6 zY^+U>dvq`(cHzd76=#DOezng2vq$h_Q-@LBfwx~?S3Wv%_RO#Q>C0oEPwRVg{K&n} zosH&wN!5QMj1{#&ab+xb1)7rtKSd+LZ{ z?lZRtWwv;ms_)y?_myt8jd-haagqJq`U>Wz+<9sDR3c05t^OBSyr0i@u;k6MJOy2z zU!_jY{q?E8Pv*A!7e#DIu&;2Ow%IOMv0c6I-r|4GujjAcVm4cWVR45fv+=Klq8$a_ zFV`u{)SjI#YyRbctj_ZtS6kA_u7zSyHH$$P_sj(eV)DWtRX z^xq#xMTGUsW`zGwYLC0bGEXo!^yRhljqkZcf+p4VuGm&D-ST+JZ+oj5sgaB1j(@3t z>wo#|(cKf&{4d^fH?55_+@ErU_`+4^aEZ1Y zNl^|xxlEc%NXLAu(ajK6u4%KwW*$sjvZCqG%TUgAsjk${lW8HU(uS?P=hpa`t(dWD zMow7jCPmllM^l_P81biT1cdB3^@}a7aMpsO3t#RF3L|kjU=`q*^p@lrB8=i`_T8W5wCfYmONnhAgS8*EAoPmBe{XYu%b= z1Jj3b^5NGV9hS^!S}PiU-Fd~dg!A%gh2au+bUlx))9IR8cU1pgP=1B<=jGaB^*_=& zmkY8URQcw%jbH4&+>JUHSC;b{SH(H%`wCt?iBqeP@oRl@?!}~d1@ns{E5g*u-SYo# z`m}A!DjwBs*Q0+NJ~~nMs0oX3wa3B3FRmPz_v_=NFm9=(!42!geQSQ#g-zIe=SN7Z zxm;7=gH3b(2pstv8hE*L@92?8Nd}lli4zx8L8ARn{r9?LF^t1+Qa=XZ)>*mp9^n*>bD+qqtA@znp4`Ta$0A zmj9XY@}i^2?Zm8;%GNTQioU&Uc*+v2zDMCmSH{T&H;wBb@6x%g68YrsbXDbwYZ;TW z%Qt_!5HGjxX=kHs<+mRXr?u)|-YvH;u3mrsuP-mJzuEnqbJFk6<*g>G)$c6iTAmzU zSNeR#)pV_O8D~=(7xm0a+;w+jknbML`G$|=Uq!^&T)+MMq^|63L(#VivRPAO+G=nA zwBh;5qtY+b{NcreeCGP&p|L6|DPkqlHJ&6~D3?)G-27m-jiTlf=5SFVBkn_|g*Uwq zn40C}ly=W*&L5 zt=c=YX9{0kr;cNd_u(Lwlet%pRvoD^i(P*0-VATS;)ANY4tzVtF5aD8bo1r4-a{*T z10|AVlMNki_MUQFVYaoo#UbYGtN`tL+nh*mm%d~}PQ-alRUf9A{2xn&$%=d`)cT)lYpj2UZ>oSyK?v}Vqc z^~d__y=Do;O)9!QIW%hKi%H9c&)n@WnjRu9+j@X|@8MtS(@h0W&)cIM*b;WF!tUCt zDDMSRO^r9KIFuciyKJhdPlu;$`$N$m?UZ-0-jgM?HRfW|WZNfse z=%+S9T&XMUXFqg~K0SZAVzftaS=+QXJU`u@Oe#Ke`JahkvP-4Zf{4D#s09&ymw08K zW;Q1o+1*c@6ll{Z^LdMeq2y;1$&E6f>u)G`yQ@6^Vf5bOwuFhVRHMnIrSC2>HhoC- z=WX6?+W+LYfWGH(qiA*M`zBu=a%kP2A0%+!UxRtFTjb7tiu!&xYU-j+Te;%i zX{BjRdNs2kTJ!I6ySG;9<`qER;J5Kf`u$ms&u;a)pwTZLU)J?;U z_pe#DuXo$_W%-e7mi_VlENS_9dh@Q8N>ZO|e4lxKx)onvc)ZHzva-|OgqS;r#l)YV z6~Fzt@|?Zs^tQ!Lj)i(T&o|pH5&AXnk!!Kp3E`)9>g{nceck+}8>YM~G5TmL<)tzC zQQ0R2pVe}y#gg~0JN9h;eA=qxW8s^lr4t@2rIc@9D#BGiJGje4*RoaFd!E>Qdo8`b zIGLG2g^v`r)pC9ksn?fFGg~`R)_VKVr4RFaPH4}aCem!yb^XTe^?fa?CIwhrFEM%P z=YBNR@ac?R@4q+lEFD!AF8rKXpQ-dWv_J3Fgrmzf{#fL)!Rix)Vi3TZ*KXx>e11nyKm>kH#~9<{2a>Vy7=7dUml0**F0qrs#p~F zLTJsh9gnLYS34Cwk>Y94(an#Nqd7_pqm$Q;zi~Ff0 zx-hJtzouweqQ~)bfB&3r=XPh8-+laaYWu>Zwc=It&d0pj|M^J3p$DZ(RlklZaJUEG zx3l74Yj>~L+W*r0t^L&Rzj|4&E?89mDRA0JZ>)VUo7#* zG}XWJ{cVx;e*V*Yb@OlB86z97$@eeXy*XHa);^)5q@y~jzi{cie`eJzk#CMC%rEhNe%)v5 z@~oD>sfqul&x(0GzcfWHJn@tC#``Q%C-3X{CvBMjr0#6ee&1lmhgyp8PVO(ub;Ws zq4QePZ<5oT>P7)022GuRc7f*St~!g#-4l}MZTR`iFT`fcP3L!RU5QWl>lZ~lD%yD4 zW5ewU&C3KhUmTk}{q$Y8Q+GE_QD(ZBKWR_Q2eYsPwCL;w~|7N6ZN`;S*-6g&JZPde!yCH=PyPq^fz`Y4M-N zyh(dvPMC!&+@50WyCPvuy@{e{tWnBrf5qE1TsI@ZLDKRD8YD?i>i1?dr_45=#Jk;Z z-q%w;3el53U)=IX+i%hpRp+urcbvRM>StJ;xX$o;GshRp6Z0N!Ie+5U3}H?WrpN=2 z3NF0eW4(Xhzqj@ee*FFUF?zw?hj0F_^xd#fSoZaW2I=Q(6~j!fE4AI*ZdbN1;raT% zX&Eb|n7w4!XS5`>9d2Q`d_W{(ns;b-K-LN~hgU)_&v$0uSJ-9os3dC7p=G*jPR>|! zPru2|t$su8Ld~hXd!O8Ykyw9YTjaLA^(o#Ww)GPZ2~YRl7Ur~Vn#v~A4vs$?pDdlU zcIu?Ja$3hvUW-zU_P(SuXBGDvp{Fao)uLZ(-i-1;Y3BV}O8<_Z$%N$Tw+qyZc3j&v zF>Bk`PpiYj4s8uuC82%d)cUANyHeKqPKnNFUte*x?D^r}_v`PK-LGem+Vi4>QJJ-m zN8bOyjC+lWvi^GwS!?QFwST>lAarLVgZV7A-x0t6WPdZ??Ns~fNaBP0pJh8`tCOtd z=KIV`J#Lg%|4&+Sv7mDDKWZlH#udcC&I-V=cJglwE*0xd2L1M!kH#zQ%%@d{{KH4DoetJtu z=&^Q>`yRVmuCDN1Xy@=D=DXf~|L=23CguiCHu6%vka*!0Ps2$r))#G$6QrZ1UMX*| zVV?7RSzAfCr}(B{2@9-qUvvGu@@sqH*82D(r_b!zV6dm-)uXOm-!x|Rapwo>c+cVE zPQJIn$ZofZea(*x6BDeD#`9XdEjh|knJV(XDt&wFqAea7 z%In-$zgA2yFpPSdq|({FQIYAGPU+2ro@oapbQ=q&Ju;nV=2to)ZQiaE(Hy%(4B~8a z-l!(j_vEES=YMtG$k`Lfb!^hANYPt74!YIG4WC2y9%YL>%&2uU<&E{k$sazb@Z4D` z%sl?B>;(V4e3x{mJSaL`EM38uUENVEq-OBirMN!*@`b*qx<2|EXZ6F=PnfJP z`7+IXzd4&_Ud6hHJKLT=Tgc|rruOAi`p*1qN;Z#o_6Q_Tzv^AVxBipNG-1K+gw;pH zZx~1L>2H*YOWLWk^!1q{i&RU^Wh*t8HKeMoTzaPH+S=?JJ-t8DmP?;ZOFN=zeClIK zY1ZH8E3>+L_dPsnQ@^LeY;V%W;(XJLTBn|#rYc$PmjU@5g~o z66eG+}_2GQI00 zme%GitT&kx7VWotQ|+rOZZlqId(5bOJo$Au+hwtuyv@t=n6u8jes0e`QGI%W&v&(e z;PeH{ytpPVP~2j+`NyUe=^nnZ^{S?!L2J5A7V1`Ry>vZomG_EedJChbJ-S`SH9OJQ zH_>-eBiB~Dl&jCTx_))r^*1a|WOjhBZ=mlqd7%n*W6xN#RVy`Dtz4gZ`Ib(|>pNA# z1+L2akJhV}Eq{2ROv8eE+2a`-Z{~;B6wC1l95-rO!*+VphMpQV-f5;0YE7vvCK2`9 zv^S^oP7Cc!O}d=Ev@d$U^R1p!CXtuZoi?Ydx>a#b&Rp%Y>||BE-;>;(pTZ-uyj_;* z3Pw)5b^9Cp>`ou=PM=AIT_!fZZCR5Ve0ERF-7|Ii5jDBXL2{ErPP(K7?f$d1Kguil z7I#KY`uUeNoV|jFGJ1~p7)xCaDb>$hV=1wzK1Iv=^Rat3Z(p9g%cM(B_UM(JYr8F$ zFSpvma9pcJ=$lr?g*A?wYn_aBwpglo$LY;}X>4{`b>qymt~EcBPkJviuAO?W#8X;T zsgYN4(v{TDGxr@y|0Og(RdZkN@(nZ3f0=TAiG+sO%~_(SZ_EmnTJX}m=xw>Q>&DIt zU#47G5@H-w&(nDGjY{dwo@L8>mYMfF+b;it=}%7k!s7v&mTwH1?#}P8zWZ9G>P@Lh z$^*9ZMn4|!ss8kBS1DuH@jumO@z-qkv+Xc5PMiPc0{603<Lveb+=Gm1$e*>$y~>T}WE~=zWi^ z^Mqqsj#87BdGItU-=1_ORd~rpmkGy&9Md%S<*IL+sUWPYBB>Fy<_|Y-<)dE$OA3{* z*KH3Jnay#@gEOdWwky{rmviQ+D^II=D64urHWf^{7Abfp)d$o}s<7*;n(#E{ zgcO!b2Ib%GOQ*y(PvQDe?{wzLk)xk4NLMA_W}m+KveizZu+^W`RcEJzjnc7NGo zl?{uMV~u}Vz5H?Ug~_e=lU3MeEps}pkZ|A=(<=s{1f^KkZM?d^#iiE^Vi>0TO*&B= z%>3j-RCMKGTVI9+wFdN-?}oVI&55$W!4f_zTrx$^TwG@8-Gr+O)d&D zyrrna_M?1)0gHzO)1SgJHiZjy>_3F-Q|xE_UGe5PLrbmNe2(7_mpeu{{B`+Z*>z)6 z$z6qCYCo=;hHY%I3UK`{|4`#!t?=J}%;m3+@7H!JWJ(jiZdBm3`HkeNRhDbk$ZX~h z2{&!zEM>njA!>#~=+>3Hdd^n9V{8pCzuMc_EiZC|^Znu*-=d%0-2LC|&u$g&&51XE z7ns(+*?mLv%9o0+xwjvzaeLA&5}INap<8Wr!|UYrNn2Pu8j3t$6&<`jtMUE6%;^Q| zx1QR2O>ds?2bs@N-eqUDvP4h`GBX;FzQ|hrg7z0icxnFf`|s~aO0VR*bS7B%)_m{D8zUUgm1yd-pM18vb<>T8QXk#E(oI@XXHGAA zq@QlvT(+{R+qbB{eSzw{jT7CrE#O{v@bZRD*Ari`neLdbze?)p^z2*pcDZ+hW`7Lg zu3diW#>(RTAKo%)&w9fbd93B$zYTt|>0iq7Kx6s@t^ie;jE4JdZWxW&3R?_YRotDc}2SW zxn9rW(hkktX!-81NSNBw4FWQIyz8Al$g$0`l44}J(tUGj{DG6AvYQrhSIaI*+_GFn zIrsEj{XP*mmD)=S}Tpp-vMf{Rud`?XZ>q)##i_Kcg4TTCXS;FCKF>=)`38 z-)|nIB&y7plV-ixa7=;k?Z?9lrC;V*XTG?tHseKrvEs3e&(o|8H+RI%Iu3PwhPCFgAa&xh4`#1Jw_1iWr^_w^Q8}FS|8J(5MHxBK; z-gNMl$=43kkXKy$W9_1ZvaQ_q$L-Gz>wR~?Cu?)omR&PLLSK~dt33QO-&e*bO~xlB zv99)tx5bP#MFtZ~w=B7^#Lzp|jD4~ypPIMKoTU|W!+R%9X;PiJTyfKqn=8&=RNW(? z0&a12HhFp-te>6qp1Mo5kI($vmSvT{!Yk@`{W9*aPjxDH?pboK zB9s5BcZFx{Q`JzfBbgcz=lk0{Uu~-NjD4h9+Btob$o*aHw-0z{o$?MkQ*6D@)qJVI z`AnYf>zn1}n>BZ(X850zJDA=Jgdccsa$=_v$8p|p zlbDI+yX@}g)NYLlyeYl?cl|L@C3b1=TN*mjnp;FPO)L$!dmM=UB=_n43_neOk4wHO zZijS&x3j2i37v7_2}?55!mhZ3Y5g&m)ioCCE_9i8D|_y=nddX7?tcHba#gd+={0)} zEh%g%+x&RhZb_vrB1%to%&*#eVA;|i3$A`=-Dca|etG+Go!6YXzI!&dh_9B)t1r;d z?BiXeuN!)jXW68Oywi7ExgM+Dqx4zuC)?*NN8ZJ|448w?{Ml&gA7f$ZtAf3c2PV9UIqmML9sTw7dr z2~OLUGwDL`qzmyzf`Mmu-wI;te10$fklIBC?oW=>?^-Y}zxTn6?YL}l2xOJVR*@w%QeOe3xFCM#m+2`8s zL;KodWiQuX_WwSA-S^+F>Mo{NO*j}st{Vi*-N%}9ysU9`bl*b*O&@P&4&A*kr#xS` z>ciGKrlmLi&+K0{-~X0)j>&b$9PzjXC-$!1ckOS9{k)F_9`-&?N|JNimu0M(__S<; z=ci3ye;@erTfx)*or;dqhpwtw|5UZS7-|+E~Wmez(x^S?w;mlFHZ+g zY&UR|IwTQP;1ycZD52)7=V)8nd~>SFzK+j*`imaDUs%Tx@x4xC;hZhvQzy^c9r${7 z)dF8p$F7hgm;XfWT0V32vSm{GFZ~qtj@!k3IKr-7*tGHW(Kv%`wFja%$-2+pHzztg zr`=hq`GOq3=7!km$G5w)*WZoyN?ua(@!^~G*>4kk%Ra}vIeBD1dv}%J@$EVi-zpvU zq?~eRzyIUoclU&Y(qGPwO;e-W`4Ws*=^bM$-1}!}&)z`4tc8EO?~9 zLv~H4ev-8AadA(Rje1(#6TVJpo!$3+Y1GB{4`Tnctfw0Ge&MHNY8LadF=*@6@<8hXD(x6Pd~|Gek%+-LkvnJ)s=78F~5 zi};soUQoYG`C8KLb+Wewzl*$mY|ODRGfO~AxO_vPbmx@7D?+U9d%N^5?{MIdY~b)? z6_K^JdS7~eeYN&Li zQ)I5TNpSdWPnODTzx49s94x_%^5J zv0m8`y>+YDgb()WbgeSKEpEHDYxOa$BC+VJhUv+oyAwpOCTabQ$?douQGfJw*V!o?k7XNDY@16L;IRDMuy|%WQZHMRUZ_iTPy0LHWrao=X&ym^Y z{1*%N^>UP6oV!KkyWt<1E6e&%CaNEOxOLZCt=SeS+K=NFsdK&G)VqeSY37E=``ho8 z?oryD5p$e7*1ho39ZBiT825MALgwU@*B{f8I{$IgF_j(rU+T^FF#h<>$Wnjx+@#84 zzmSNxG4aoKZ@9|$K=0k5m%Z%wX0Sc}^7s0}*W34AkpH=h>*Esp2k-a)Gx<>S>z?f; zlhE=|+3c1V0=L$@F%_NGw{1dh&u3jIdq2njx#?L>v*v9(5AS`X zT;yxAyFRV3wM#$qu4MkjFBMHZIcSIk*2-)+M>Coh~FFE3G7X2{rOcwi{E*5^Ye(`6uJ2#4jD_yhMrGzUd z&eJ6W* zi^F=)zG*%iQggs5*|<8P-uP;s%7q(e-rYWvdUW~m53a0N4_(MHb-u*)kZr=}UB-Ci+yS(*iSA?w35X{JcS$^X(c;M|FZll%1Lcp*l>wsjPyOEaA` zoZOdgssOqN18G?-gA6i)tgItEZGlc_1PoXgbLvCtGqFzOA4lIPA z-t$FX0nCM>E6|jIp}3?nC$$)xzAfJ~F0nE)Ff=nWFz|SyX!NjUV8~6(%S=lxF3~GW zNkg|1c{v*oiq3Ys$u?P1V9!NnNi%u5Om=hc#BmMq)h HERZMwnt5(h delta 24626 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 $@ + +%.o: %.c + $(CC) -c $(CFLAGS) -o $@ $^ + $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ + +%.o: %.s + $(CC) -c $(CFLAGS) -o $@ $^ + $(CC) -E $(CFLAGS) -o $(@:.o=.pp) $^ + +%.dot: %.elf + r2 -a arm -qc 'aa;agC' $< 2>/dev/null >$@ + +main.elf: main.o startup_stm32f103xb.o system_stm32f1xx.o $(HAL_PATH)/Src/stm32f1xx_ll_utils.o cmsis_exports.o + $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) + $(OBJCOPY) -O ihex $@ $(@:.elf=.hex) + $(OBJCOPY) -O binary $@ $(@:.elf=.bin) + $(OBJDUMP) -St $@ >$(@:.elf=.lst) + $(SIZE) $@ + +program: main.elf openocd.cfg + openocd -f openocd.cfg -c "program $< verify reset exit" + +clean: + rm -f **.o + rm -f main.elf main.hex main.bin main.map main.lst + rm -f **.expand + diff --git a/driver_fw/cmsis_exports.c b/driver_fw/cmsis_exports.c new file mode 100644 index 0000000..a43fbcf --- /dev/null +++ b/driver_fw/cmsis_exports.c @@ -0,0 +1,62 @@ +#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__ +#define __GENERATED_CMSIS_HEADER_EXPORTS__ + +#include + +/* stm32f103xb.h */ +TIM_TypeDef *tim2 = TIM2; +TIM_TypeDef *tim3 = TIM3; +TIM_TypeDef *tim4 = TIM4; +RTC_TypeDef *rtc = RTC; +WWDG_TypeDef *wwdg = WWDG; +IWDG_TypeDef *iwdg = IWDG; +SPI_TypeDef *spi2 = SPI2; +USART_TypeDef *usart2 = USART2; +USART_TypeDef *usart3 = USART3; +I2C_TypeDef *i2c1 = I2C1; +I2C_TypeDef *i2c2 = I2C2; +USB_TypeDef *usb = USB; +CAN_TypeDef *can1 = CAN1; +BKP_TypeDef *bkp = BKP; +PWR_TypeDef *pwr = PWR; +AFIO_TypeDef *afio = AFIO; +EXTI_TypeDef *exti = EXTI; +GPIO_TypeDef *gpioa = GPIOA; +GPIO_TypeDef *gpiob = GPIOB; +GPIO_TypeDef *gpioc = GPIOC; +GPIO_TypeDef *gpiod = GPIOD; +GPIO_TypeDef *gpioe = GPIOE; +ADC_TypeDef *adc1 = ADC1; +ADC_TypeDef *adc2 = ADC2; +ADC_Common_TypeDef *adc12_common = ADC12_COMMON; +TIM_TypeDef *tim1 = TIM1; +SPI_TypeDef *spi1 = SPI1; +USART_TypeDef *usart1 = USART1; +SDIO_TypeDef *sdio = SDIO; +DMA_TypeDef *dma1 = DMA1; +DMA_Channel_TypeDef *dma1_channel1 = DMA1_Channel1; +DMA_Channel_TypeDef *dma1_channel2 = DMA1_Channel2; +DMA_Channel_TypeDef *dma1_channel3 = DMA1_Channel3; +DMA_Channel_TypeDef *dma1_channel4 = DMA1_Channel4; +DMA_Channel_TypeDef *dma1_channel5 = DMA1_Channel5; +DMA_Channel_TypeDef *dma1_channel6 = DMA1_Channel6; +DMA_Channel_TypeDef *dma1_channel7 = DMA1_Channel7; +RCC_TypeDef *rcc = RCC; +CRC_TypeDef *crc = CRC; +FLASH_TypeDef *flash = FLASH; +OB_TypeDef *ob = OB; +DBGMCU_TypeDef *dbgmcu = DBGMCU; + +#include + +/* core_cm3.h */ +SCnSCB_Type *scnscb = SCnSCB; +SCB_Type *scb = SCB; +SysTick_Type *systick = SysTick; +NVIC_Type *nvic = NVIC; +ITM_Type *itm = ITM; +DWT_Type *dwt = DWT; +TPI_Type *tpi = TPI; +CoreDebug_Type *coredebug = CoreDebug; + +#endif//__GENERATED_CMSIS_HEADER_EXPORTS__ diff --git a/driver_fw/gen_cmsis_exports.py b/driver_fw/gen_cmsis_exports.py new file mode 100644 index 0000000..ba3422b --- /dev/null +++ b/driver_fw/gen_cmsis_exports.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import re +import os + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument('cmsis_device_header', nargs='+', type=argparse.FileType('rb')) + args = parser.parse_args() + + print('#ifndef __GENERATED_CMSIS_HEADER_EXPORTS__') + print('#define __GENERATED_CMSIS_HEADER_EXPORTS__') + print() + for header in args.cmsis_device_header: + lines = header.readlines() + name = os.path.basename(header.name) + print('#include <{}>'.format(name)) + print() + + print('/* {} */'.format(name)) + for l in lines: + match = re.match(b'^#define (\w+)\s+\W*(\w+_TypeDef|\w+_Type).*$', l) + if match: + inst, typedef = match.groups() + inst, typedef = inst.decode(), typedef.decode() + print('{} *{} = {};'.format(typedef, inst.lower(), inst)) + print() + print('#endif//__GENERATED_CMSIS_HEADER_EXPORTS__') + diff --git a/driver_fw/main.c b/driver_fw/main.c new file mode 100644 index 0000000..d814b0e --- /dev/null +++ b/driver_fw/main.c @@ -0,0 +1,108 @@ + + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" +#include +#pragma GCC diagnostic pop + +#include + +#include +#include +#include +#include + +/* Part number: STM32F030F4C6 */ + +static volatile unsigned int sys_time; + +uint32_t get_tick() { + return SysTick->VAL; +} + +int main(void) { + /* External crystal: 8MHz */ + RCC->CR |= RCC_CR_HSEON; + while (!(RCC->CR&RCC_CR_HSERDY)); + + /* Sysclk = HCLK = 48MHz */ + RCC->CFGR = (RCC->CFGR & (~RCC_CFGR_PLLMULL_Msk & ~RCC_CFGR_SW_Msk & ~RCC_CFGR_PPRE1_Msk & ~RCC_CFGR_PPRE2_Msk & ~RCC_CFGR_HPRE_Msk)) + | (10<CR |= RCC_CR_PLLON; + while (!(RCC->CR&RCC_CR_PLLRDY)); + + /* Switch to PLL */ + RCC->CFGR |= (2<CFGR = (RCC->CFGR & (~RCC_CFGR_PPRE1_Msk & ~RCC_CFGR_PPRE2_Msk)) + // | (4<APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_IOPCEN; + + GPIOA->CRL = + (0<CRL = + (0<CRH = + (0<BRR |= 1<<6 | 1<<7; + GPIOB->BRR |= 1<<0 | 1<<1; + + while (42) { +#define FOO 100000 + for (int i=0; iBRR |= 1<<6 | 1<<7; + GPIOB->BRR |= 1<<0 | 1<<1; + + GPIOA->BSRR |= 1<<6; + GPIOB->BSRR |= 1<<1; + + for (int i=0; iBRR |= 1<<6 | 1<<7; + GPIOB->BRR |= 1<<0 | 1<<1; + + GPIOA->BSRR |= 1<<7; + GPIOB->BSRR |= 1<<0; + + GPIOC->ODR ^= 1<<13; + } +} + +void NMI_Handler(void) { +} + +void HardFault_Handler(void) __attribute__((naked)); +void HardFault_Handler() { + asm volatile ("bkpt"); +} + +void SVC_Handler(void) { +} + + +void PendSV_Handler(void) { +} + +void SysTick_Handler(void) { + sys_time++; +} + +void _init(void) { +} + +void MemManage_Handler(void) __attribute__((naked)); +void MemManage_Handler() { + asm volatile ("bkpt"); +} + +void BusFault_Handler(void) __attribute__((naked)); +void BusFault_Handler() { + asm volatile ("bkpt"); +} diff --git a/driver_fw/openocd.cfg b/driver_fw/openocd.cfg new file mode 100644 index 0000000..f8b4766 --- /dev/null +++ b/driver_fw/openocd.cfg @@ -0,0 +1,14 @@ +telnet_port 4444 +gdb_port 3333 + +source [find interface/stlink-v2.cfg] +#hla_serial "000000000001" +transport select hla_swd + +source [find target/stm32f1x.cfg] +#adapter_khz 10000 + +init +arm semihosting enable + +#flash bank sysflash.alias stm32f0x 0x00000000 0 0 0 $_TARGETNAME diff --git a/driver_fw/startup_stm32f103xb.s b/driver_fw/startup_stm32f103xb.s new file mode 100644 index 0000000..1bdd524 --- /dev/null +++ b/driver_fw/startup_stm32f103xb.s @@ -0,0 +1,379 @@ +/** + *************** (C) COPYRIGHT 2017 STMicroelectronics ************************ + * @file startup_stm32f103xb.s + * @author MCD Application Team + * @version V4.2.0 + * @date 31-March-2017 + * @brief STM32F103xB Devices vector table for Atollic toolchain. + * This module performs: + * - Set the initial SP + * - Set the initial PC == Reset_Handler, + * - Set the vector table entries with the exceptions ISR address + * - Configure the clock system + * - Branches to main in the C library (which eventually + * calls main()). + * After Reset the Cortex-M3 processor is in Thread mode, + * priority is Privileged, and the Stack is set to Main. + ****************************************************************************** + * + *

© COPYRIGHT(c) 2017 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + + .syntax unified + .cpu cortex-m3 + .fpu softvfp + .thumb + +.global g_pfnVectors +.global Default_Handler + +/* start address for the initialization values of the .data section. +defined in linker script */ +.word _sidata +/* start address for the .data section. defined in linker script */ +.word _sdata +/* end address for the .data section. defined in linker script */ +.word _edata +/* start address for the .bss section. defined in linker script */ +.word _sbss +/* end address for the .bss section. defined in linker script */ +.word _ebss + +.equ BootRAM, 0xF108F85F +/** + * @brief This is the code that gets called when the processor first + * starts execution following a reset event. Only the absolutely + * necessary set is performed, after which the application + * supplied main() routine is called. + * @param None + * @retval : None +*/ + + .section .text.Reset_Handler + .weak Reset_Handler + .type Reset_Handler, %function +Reset_Handler: + +/* Copy the data segment initializers from flash to SRAM */ + movs r1, #0 + b LoopCopyDataInit + +CopyDataInit: + ldr r3, =_sidata + ldr r3, [r3, r1] + str r3, [r0, r1] + adds r1, r1, #4 + +LoopCopyDataInit: + ldr r0, =_sdata + ldr r3, =_edata + adds r2, r0, r1 + cmp r2, r3 + bcc CopyDataInit + ldr r2, =_sbss + b LoopFillZerobss +/* Zero fill the bss segment. */ +FillZerobss: + movs r3, #0 + str r3, [r2], #4 + +LoopFillZerobss: + ldr r3, = _ebss + cmp r2, r3 + bcc FillZerobss + +/* Call the clock system intitialization function.*/ + bl SystemInit +/* Call static constructors */ + bl __libc_init_array +/* Call the application's entry point.*/ + bl main + bx lr +.size Reset_Handler, .-Reset_Handler + +/** + * @brief This is the code that gets called when the processor receives an + * unexpected interrupt. This simply enters an infinite loop, preserving + * the system state for examination by a debugger. + * + * @param None + * @retval : None +*/ + .section .text.Default_Handler,"ax",%progbits +Default_Handler: +Infinite_Loop: + b Infinite_Loop + .size Default_Handler, .-Default_Handler +/****************************************************************************** +* +* The minimal vector table for a Cortex M3. Note that the proper constructs +* must be placed on this to ensure that it ends up at physical address +* 0x0000.0000. +* +******************************************************************************/ + .section .isr_vector,"a",%progbits + .type g_pfnVectors, %object + .size g_pfnVectors, .-g_pfnVectors + + +g_pfnVectors: + + .word _estack + .word Reset_Handler + .word NMI_Handler + .word HardFault_Handler + .word MemManage_Handler + .word BusFault_Handler + .word UsageFault_Handler + .word 0 + .word 0 + .word 0 + .word 0 + .word SVC_Handler + .word DebugMon_Handler + .word 0 + .word PendSV_Handler + .word SysTick_Handler + .word WWDG_IRQHandler + .word PVD_IRQHandler + .word TAMPER_IRQHandler + .word RTC_IRQHandler + .word FLASH_IRQHandler + .word RCC_IRQHandler + .word EXTI0_IRQHandler + .word EXTI1_IRQHandler + .word EXTI2_IRQHandler + .word EXTI3_IRQHandler + .word EXTI4_IRQHandler + .word DMA1_Channel1_IRQHandler + .word DMA1_Channel2_IRQHandler + .word DMA1_Channel3_IRQHandler + .word DMA1_Channel4_IRQHandler + .word DMA1_Channel5_IRQHandler + .word DMA1_Channel6_IRQHandler + .word DMA1_Channel7_IRQHandler + .word ADC1_2_IRQHandler + .word USB_HP_CAN1_TX_IRQHandler + .word USB_LP_CAN1_RX0_IRQHandler + .word CAN1_RX1_IRQHandler + .word CAN1_SCE_IRQHandler + .word EXTI9_5_IRQHandler + .word TIM1_BRK_IRQHandler + .word TIM1_UP_IRQHandler + .word TIM1_TRG_COM_IRQHandler + .word TIM1_CC_IRQHandler + .word TIM2_IRQHandler + .word TIM3_IRQHandler + .word TIM4_IRQHandler + .word I2C1_EV_IRQHandler + .word I2C1_ER_IRQHandler + .word I2C2_EV_IRQHandler + .word I2C2_ER_IRQHandler + .word SPI1_IRQHandler + .word SPI2_IRQHandler + .word USART1_IRQHandler + .word USART2_IRQHandler + .word USART3_IRQHandler + .word EXTI15_10_IRQHandler + .word RTC_Alarm_IRQHandler + .word USBWakeUp_IRQHandler + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word 0 + .word BootRAM /* @0x108. This is for boot in RAM mode for + STM32F10x Medium Density devices. */ + +/******************************************************************************* +* +* Provide weak aliases for each Exception handler to the Default_Handler. +* As they are weak aliases, any function with the same name will override +* this definition. +* +*******************************************************************************/ + + .weak NMI_Handler + .thumb_set NMI_Handler,Default_Handler + + .weak HardFault_Handler + .thumb_set HardFault_Handler,Default_Handler + + .weak MemManage_Handler + .thumb_set MemManage_Handler,Default_Handler + + .weak BusFault_Handler + .thumb_set BusFault_Handler,Default_Handler + + .weak UsageFault_Handler + .thumb_set UsageFault_Handler,Default_Handler + + .weak SVC_Handler + .thumb_set SVC_Handler,Default_Handler + + .weak DebugMon_Handler + .thumb_set DebugMon_Handler,Default_Handler + + .weak PendSV_Handler + .thumb_set PendSV_Handler,Default_Handler + + .weak SysTick_Handler + .thumb_set SysTick_Handler,Default_Handler + + .weak WWDG_IRQHandler + .thumb_set WWDG_IRQHandler,Default_Handler + + .weak PVD_IRQHandler + .thumb_set PVD_IRQHandler,Default_Handler + + .weak TAMPER_IRQHandler + .thumb_set TAMPER_IRQHandler,Default_Handler + + .weak RTC_IRQHandler + .thumb_set RTC_IRQHandler,Default_Handler + + .weak FLASH_IRQHandler + .thumb_set FLASH_IRQHandler,Default_Handler + + .weak RCC_IRQHandler + .thumb_set RCC_IRQHandler,Default_Handler + + .weak EXTI0_IRQHandler + .thumb_set EXTI0_IRQHandler,Default_Handler + + .weak EXTI1_IRQHandler + .thumb_set EXTI1_IRQHandler,Default_Handler + + .weak EXTI2_IRQHandler + .thumb_set EXTI2_IRQHandler,Default_Handler + + .weak EXTI3_IRQHandler + .thumb_set EXTI3_IRQHandler,Default_Handler + + .weak EXTI4_IRQHandler + .thumb_set EXTI4_IRQHandler,Default_Handler + + .weak DMA1_Channel1_IRQHandler + .thumb_set DMA1_Channel1_IRQHandler,Default_Handler + + .weak DMA1_Channel2_IRQHandler + .thumb_set DMA1_Channel2_IRQHandler,Default_Handler + + .weak DMA1_Channel3_IRQHandler + .thumb_set DMA1_Channel3_IRQHandler,Default_Handler + + .weak DMA1_Channel4_IRQHandler + .thumb_set DMA1_Channel4_IRQHandler,Default_Handler + + .weak DMA1_Channel5_IRQHandler + .thumb_set DMA1_Channel5_IRQHandler,Default_Handler + + .weak DMA1_Channel6_IRQHandler + .thumb_set DMA1_Channel6_IRQHandler,Default_Handler + + .weak DMA1_Channel7_IRQHandler + .thumb_set DMA1_Channel7_IRQHandler,Default_Handler + + .weak ADC1_2_IRQHandler + .thumb_set ADC1_2_IRQHandler,Default_Handler + + .weak USB_HP_CAN1_TX_IRQHandler + .thumb_set USB_HP_CAN1_TX_IRQHandler,Default_Handler + + .weak USB_LP_CAN1_RX0_IRQHandler + .thumb_set USB_LP_CAN1_RX0_IRQHandler,Default_Handler + + .weak CAN1_RX1_IRQHandler + .thumb_set CAN1_RX1_IRQHandler,Default_Handler + + .weak CAN1_SCE_IRQHandler + .thumb_set CAN1_SCE_IRQHandler,Default_Handler + + .weak EXTI9_5_IRQHandler + .thumb_set EXTI9_5_IRQHandler,Default_Handler + + .weak TIM1_BRK_IRQHandler + .thumb_set TIM1_BRK_IRQHandler,Default_Handler + + .weak TIM1_UP_IRQHandler + .thumb_set TIM1_UP_IRQHandler,Default_Handler + + .weak TIM1_TRG_COM_IRQHandler + .thumb_set TIM1_TRG_COM_IRQHandler,Default_Handler + + .weak TIM1_CC_IRQHandler + .thumb_set TIM1_CC_IRQHandler,Default_Handler + + .weak TIM2_IRQHandler + .thumb_set TIM2_IRQHandler,Default_Handler + + .weak TIM3_IRQHandler + .thumb_set TIM3_IRQHandler,Default_Handler + + .weak TIM4_IRQHandler + .thumb_set TIM4_IRQHandler,Default_Handler + + .weak I2C1_EV_IRQHandler + .thumb_set I2C1_EV_IRQHandler,Default_Handler + + .weak I2C1_ER_IRQHandler + .thumb_set I2C1_ER_IRQHandler,Default_Handler + + .weak I2C2_EV_IRQHandler + .thumb_set I2C2_EV_IRQHandler,Default_Handler + + .weak I2C2_ER_IRQHandler + .thumb_set I2C2_ER_IRQHandler,Default_Handler + + .weak SPI1_IRQHandler + .thumb_set SPI1_IRQHandler,Default_Handler + + .weak SPI2_IRQHandler + .thumb_set SPI2_IRQHandler,Default_Handler + + .weak USART1_IRQHandler + .thumb_set USART1_IRQHandler,Default_Handler + + .weak USART2_IRQHandler + .thumb_set USART2_IRQHandler,Default_Handler + + .weak USART3_IRQHandler + .thumb_set USART3_IRQHandler,Default_Handler + + .weak EXTI15_10_IRQHandler + .thumb_set EXTI15_10_IRQHandler,Default_Handler + + .weak RTC_Alarm_IRQHandler + .thumb_set RTC_Alarm_IRQHandler,Default_Handler + + .weak USBWakeUp_IRQHandler + .thumb_set USBWakeUp_IRQHandler,Default_Handler + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ + diff --git a/driver_fw/stm32_flash.ld b/driver_fw/stm32_flash.ld new file mode 100644 index 0000000..ec1b5a7 --- /dev/null +++ b/driver_fw/stm32_flash.ld @@ -0,0 +1,137 @@ +/* Entry Point */ +ENTRY(Reset_Handler) + +/* Highest address of the user mode stack */ +_estack = 0x20004FFF; /* end of RAM */ + +/* Generate a link error if heap and stack don't fit into RAM */ +_Min_Heap_Size = 0x200; /* required amount of heap */ +_Min_Stack_Size = 0x400; /* required amount of stack */ + +/* Specify the memory areas */ +MEMORY +{ +FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 64K +RAM (xrw) : ORIGIN = 0x20000000, LENGTH = 20K +} + +/* Define output sections */ +SECTIONS +{ + /* The startup code goes first into FLASH */ + .isr_vector : + { + . = ALIGN(4); + KEEP(*(.isr_vector)) /* Startup code */ + . = ALIGN(4); + } >FLASH + + /* The program code and other data goes into FLASH */ + .text : + { + . = ALIGN(4); + *(.text) /* .text sections (code) */ + *(.text*) /* .text* sections (code) */ + *(.glue_7) /* glue arm to thumb code */ + *(.glue_7t) /* glue thumb to arm code */ + *(.eh_frame) + + KEEP (*(.init)) + KEEP (*(.fini)) + + . = ALIGN(4); + _etext = .; /* define a global symbols at end of code */ + } >FLASH + + /* Constant data goes into FLASH */ + .rodata : + { + . = ALIGN(4); + *(.rodata) /* .rodata sections (constants, strings, etc.) */ + *(.rodata*) /* .rodata* sections (constants, strings, etc.) */ + . = ALIGN(4); + } >FLASH + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >FLASH + .ARM : { + __exidx_start = .; + *(.ARM.exidx*) + __exidx_end = .; + } >FLASH + + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array*)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } >FLASH + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array*)) + PROVIDE_HIDDEN (__init_array_end = .); + } >FLASH + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT(.fini_array.*))) + KEEP (*(.fini_array*)) + PROVIDE_HIDDEN (__fini_array_end = .); + } >FLASH + + /* used by the startup to initialize data */ + _sidata = LOADADDR(.data); + + /* Initialized data sections goes into RAM, load LMA copy after code */ + .data : + { + . = ALIGN(4); + _sdata = .; /* create a global symbol at data start */ + *(.data) /* .data sections */ + *(.data*) /* .data* sections */ + + . = ALIGN(4); + _edata = .; /* define a global symbol at data end */ + } >RAM AT> FLASH + + + /* Uninitialized data section */ + . = ALIGN(4); + .bss : + { + /* This is used by the startup in order to initialize the .bss secion */ + _sbss = .; /* define a global symbol at bss start */ + __bss_start__ = _sbss; + *(.bss) + *(.bss*) + *(COMMON) + + . = ALIGN(4); + _ebss = .; /* define a global symbol at bss end */ + __bss_end__ = _ebss; + } >RAM + + /* User_heap_stack section, used to check that there is enough RAM left */ + ._user_heap_stack : + { + . = ALIGN(4); + PROVIDE ( end = . ); + PROVIDE ( _end = . ); + . = . + _Min_Heap_Size; + . = . + _Min_Stack_Size; + . = ALIGN(4); + } >RAM + + + + /* Remove information from the standard libraries */ + /DISCARD/ : + { + libc.a ( * ) + libm.a ( * ) + libgcc.a ( * ) + } + + .ARM.attributes 0 : { *(.ARM.attributes) } +} diff --git a/driver_fw/system_stm32f1xx.c b/driver_fw/system_stm32f1xx.c new file mode 100644 index 0000000..ff7aa57 --- /dev/null +++ b/driver_fw/system_stm32f1xx.c @@ -0,0 +1,438 @@ +/** + ****************************************************************************** + * @file system_stm32f1xx.c + * @author MCD Application Team + * @version V1.5.0 + * @date 14-April-2017 + * @brief CMSIS Cortex-M3 Device Peripheral Access Layer System Source File. + * + * 1. This file provides two functions and one global variable to be called from + * user application: + * - SystemInit(): Setups the system clock (System clock source, PLL Multiplier + * factors, AHB/APBx prescalers and Flash settings). + * This function is called at startup just after reset and + * before branch to main program. This call is made inside + * the "startup_stm32f1xx_xx.s" file. + * + * - SystemCoreClock variable: Contains the core clock (HCLK), it can be used + * by the user application to setup the SysTick + * timer or configure other parameters. + * + * - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must + * be called whenever the core clock is changed + * during program execution. + * + * 2. After each device reset the HSI (8 MHz) is used as system clock source. + * Then SystemInit() function is called, in "startup_stm32f1xx_xx.s" file, to + * configure the system clock before to branch to main program. + * + * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depending on + * the product used), refer to "HSE_VALUE". + * When HSE is used as system clock source, directly or through PLL, and you + * are using different crystal you have to adapt the HSE value to your own + * configuration. + * + ****************************************************************************** + * @attention + * + *

© COPYRIGHT(c) 2016 STMicroelectronics

+ * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of STMicroelectronics nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + ****************************************************************************** + */ + +/** @addtogroup CMSIS + * @{ + */ + +/** @addtogroup stm32f1xx_system + * @{ + */ + +/** @addtogroup STM32F1xx_System_Private_Includes + * @{ + */ + +#include "stm32f1xx.h" + +/** + * @} + */ + +/** @addtogroup STM32F1xx_System_Private_TypesDefinitions + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F1xx_System_Private_Defines + * @{ + */ + +#if !defined (HSE_VALUE) + #define HSE_VALUE ((uint32_t)8000000) /*!< Default value of the External oscillator in Hz. + This value can be provided and adapted by the user application. */ +#endif /* HSE_VALUE */ + +#if !defined (HSI_VALUE) + #define HSI_VALUE ((uint32_t)8000000) /*!< Default value of the Internal oscillator in Hz. + This value can be provided and adapted by the user application. */ +#endif /* HSI_VALUE */ + +/*!< Uncomment the following line if you need to use external SRAM */ +#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) +/* #define DATA_IN_ExtSRAM */ +#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */ + +/*!< Uncomment the following line if you need to relocate your vector Table in + Internal SRAM. */ +/* #define VECT_TAB_SRAM */ +#define VECT_TAB_OFFSET 0x0 /*!< Vector Table base offset field. + This value must be a multiple of 0x200. */ + + +/** + * @} + */ + +/** @addtogroup STM32F1xx_System_Private_Macros + * @{ + */ + +/** + * @} + */ + +/** @addtogroup STM32F1xx_System_Private_Variables + * @{ + */ + +/******************************************************************************* +* Clock Definitions +*******************************************************************************/ +#if defined(STM32F100xB) ||defined(STM32F100xE) + uint32_t SystemCoreClock = 24000000; /*!< System Clock Frequency (Core Clock) */ +#else /*!< HSI Selected as System Clock source */ + uint32_t SystemCoreClock = 72000000; /*!< System Clock Frequency (Core Clock) */ +#endif + +const uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9}; +const uint8_t APBPrescTable[8] = {0, 0, 0, 0, 1, 2, 3, 4}; +/** + * @} + */ + +/** @addtogroup STM32F1xx_System_Private_FunctionPrototypes + * @{ + */ + +#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) +#ifdef DATA_IN_ExtSRAM + static void SystemInit_ExtMemCtl(void); +#endif /* DATA_IN_ExtSRAM */ +#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */ + +/** + * @} + */ + +/** @addtogroup STM32F1xx_System_Private_Functions + * @{ + */ + +/** + * @brief Setup the microcontroller system + * Initialize the Embedded Flash Interface, the PLL and update the + * SystemCoreClock variable. + * @note This function should be used only after reset. + * @param None + * @retval None + */ +void SystemInit (void) +{ + /* Reset the RCC clock configuration to the default reset state(for debug purpose) */ + /* Set HSION bit */ + RCC->CR |= (uint32_t)0x00000001; + + /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */ +#if !defined(STM32F105xC) && !defined(STM32F107xC) + RCC->CFGR &= (uint32_t)0xF8FF0000; +#else + RCC->CFGR &= (uint32_t)0xF0FF0000; +#endif /* STM32F105xC */ + + /* Reset HSEON, CSSON and PLLON bits */ + RCC->CR &= (uint32_t)0xFEF6FFFF; + + /* Reset HSEBYP bit */ + RCC->CR &= (uint32_t)0xFFFBFFFF; + + /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */ + RCC->CFGR &= (uint32_t)0xFF80FFFF; + +#if defined(STM32F105xC) || defined(STM32F107xC) + /* Reset PLL2ON and PLL3ON bits */ + RCC->CR &= (uint32_t)0xEBFFFFFF; + + /* Disable all interrupts and clear pending bits */ + RCC->CIR = 0x00FF0000; + + /* Reset CFGR2 register */ + RCC->CFGR2 = 0x00000000; +#elif defined(STM32F100xB) || defined(STM32F100xE) + /* Disable all interrupts and clear pending bits */ + RCC->CIR = 0x009F0000; + + /* Reset CFGR2 register */ + RCC->CFGR2 = 0x00000000; +#else + /* Disable all interrupts and clear pending bits */ + RCC->CIR = 0x009F0000; +#endif /* STM32F105xC */ + +#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) + #ifdef DATA_IN_ExtSRAM + SystemInit_ExtMemCtl(); + #endif /* DATA_IN_ExtSRAM */ +#endif + +#ifdef VECT_TAB_SRAM + SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */ +#else + SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */ +#endif +} + +/** + * @brief Update SystemCoreClock variable according to Clock Register Values. + * The SystemCoreClock variable contains the core clock (HCLK), it can + * be used by the user application to setup the SysTick timer or configure + * other parameters. + * + * @note Each time the core clock (HCLK) changes, this function must be called + * to update SystemCoreClock variable value. Otherwise, any configuration + * based on this variable will be incorrect. + * + * @note - The system frequency computed by this function is not the real + * frequency in the chip. It is calculated based on the predefined + * constant and the selected clock source: + * + * - If SYSCLK source is HSI, SystemCoreClock will contain the HSI_VALUE(*) + * + * - If SYSCLK source is HSE, SystemCoreClock will contain the HSE_VALUE(**) + * + * - If SYSCLK source is PLL, SystemCoreClock will contain the HSE_VALUE(**) + * or HSI_VALUE(*) multiplied by the PLL factors. + * + * (*) HSI_VALUE is a constant defined in stm32f1xx.h file (default value + * 8 MHz) but the real value may vary depending on the variations + * in voltage and temperature. + * + * (**) HSE_VALUE is a constant defined in stm32f1xx.h file (default value + * 8 MHz or 25 MHz, depending on the product used), user has to ensure + * that HSE_VALUE is same as the real frequency of the crystal used. + * Otherwise, this function may have wrong result. + * + * - The result of this function could be not correct when using fractional + * value for HSE crystal. + * @param None + * @retval None + */ +void SystemCoreClockUpdate (void) +{ + uint32_t tmp = 0, pllmull = 0, pllsource = 0; + +#if defined(STM32F105xC) || defined(STM32F107xC) + uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0; +#endif /* STM32F105xC */ + +#if defined(STM32F100xB) || defined(STM32F100xE) + uint32_t prediv1factor = 0; +#endif /* STM32F100xB or STM32F100xE */ + + /* Get SYSCLK source -------------------------------------------------------*/ + tmp = RCC->CFGR & RCC_CFGR_SWS; + + switch (tmp) + { + case 0x00: /* HSI used as system clock */ + SystemCoreClock = HSI_VALUE; + break; + case 0x04: /* HSE used as system clock */ + SystemCoreClock = HSE_VALUE; + break; + case 0x08: /* PLL used as system clock */ + + /* Get PLL clock source and multiplication factor ----------------------*/ + pllmull = RCC->CFGR & RCC_CFGR_PLLMULL; + pllsource = RCC->CFGR & RCC_CFGR_PLLSRC; + +#if !defined(STM32F105xC) && !defined(STM32F107xC) + pllmull = ( pllmull >> 18) + 2; + + if (pllsource == 0x00) + { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } + else + { + #if defined(STM32F100xB) || defined(STM32F100xE) + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + /* HSE oscillator clock selected as PREDIV1 clock entry */ + SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; + #else + /* HSE selected as PLL clock entry */ + if ((RCC->CFGR & RCC_CFGR_PLLXTPRE) != (uint32_t)RESET) + {/* HSE oscillator clock divided by 2 */ + SystemCoreClock = (HSE_VALUE >> 1) * pllmull; + } + else + { + SystemCoreClock = HSE_VALUE * pllmull; + } + #endif + } +#else + pllmull = pllmull >> 18; + + if (pllmull != 0x0D) + { + pllmull += 2; + } + else + { /* PLL multiplication factor = PLL input clock * 6.5 */ + pllmull = 13 / 2; + } + + if (pllsource == 0x00) + { + /* HSI oscillator clock divided by 2 selected as PLL clock entry */ + SystemCoreClock = (HSI_VALUE >> 1) * pllmull; + } + else + {/* PREDIV1 selected as PLL clock entry */ + + /* Get PREDIV1 clock source and division factor */ + prediv1source = RCC->CFGR2 & RCC_CFGR2_PREDIV1SRC; + prediv1factor = (RCC->CFGR2 & RCC_CFGR2_PREDIV1) + 1; + + if (prediv1source == 0) + { + /* HSE oscillator clock selected as PREDIV1 clock entry */ + SystemCoreClock = (HSE_VALUE / prediv1factor) * pllmull; + } + else + {/* PLL2 clock selected as PREDIV1 clock entry */ + + /* Get PREDIV2 division factor and PLL2 multiplication factor */ + prediv2factor = ((RCC->CFGR2 & RCC_CFGR2_PREDIV2) >> 4) + 1; + pll2mull = ((RCC->CFGR2 & RCC_CFGR2_PLL2MUL) >> 8 ) + 2; + SystemCoreClock = (((HSE_VALUE / prediv2factor) * pll2mull) / prediv1factor) * pllmull; + } + } +#endif /* STM32F105xC */ + break; + + default: + SystemCoreClock = HSI_VALUE; + break; + } + + /* Compute HCLK clock frequency ----------------*/ + /* Get HCLK prescaler */ + tmp = AHBPrescTable[((RCC->CFGR & RCC_CFGR_HPRE) >> 4)]; + /* HCLK clock frequency */ + SystemCoreClock >>= tmp; +} + +#if defined(STM32F100xE) || defined(STM32F101xE) || defined(STM32F101xG) || defined(STM32F103xE) || defined(STM32F103xG) +/** + * @brief Setup the external memory controller. Called in startup_stm32f1xx.s + * before jump to __main + * @param None + * @retval None + */ +#ifdef DATA_IN_ExtSRAM +/** + * @brief Setup the external memory controller. + * Called in startup_stm32f1xx_xx.s/.c before jump to main. + * This function configures the external SRAM mounted on STM3210E-EVAL + * board (STM32 High density devices). This SRAM will be used as program + * data memory (including heap and stack). + * @param None + * @retval None + */ +void SystemInit_ExtMemCtl(void) +{ +/*!< FSMC Bank1 NOR/SRAM3 is used for the STM3210E-EVAL, if another Bank is + required, then adjust the Register Addresses */ + + /* Enable FSMC clock */ + RCC->AHBENR = 0x00000114; + + /* Enable GPIOD, GPIOE, GPIOF and GPIOG clocks */ + RCC->APB2ENR = 0x000001E0; + +/* --------------- SRAM Data lines, NOE and NWE configuration ---------------*/ +/*---------------- SRAM Address lines configuration -------------------------*/ +/*---------------- NOE and NWE configuration --------------------------------*/ +/*---------------- NE3 configuration ----------------------------------------*/ +/*---------------- NBL0, NBL1 configuration ---------------------------------*/ + + GPIOD->CRL = 0x44BB44BB; + GPIOD->CRH = 0xBBBBBBBB; + + GPIOE->CRL = 0xB44444BB; + GPIOE->CRH = 0xBBBBBBBB; + + GPIOF->CRL = 0x44BBBBBB; + GPIOF->CRH = 0xBBBB4444; + + GPIOG->CRL = 0x44BBBBBB; + GPIOG->CRH = 0x44444B44; + +/*---------------- FSMC Configuration ---------------------------------------*/ +/*---------------- Enable FSMC Bank1_SRAM Bank ------------------------------*/ + + FSMC_Bank1->BTCR[4] = 0x00001011; + FSMC_Bank1->BTCR[5] = 0x00000200; +} +#endif /* DATA_IN_ExtSRAM */ +#endif /* STM32F100xE || STM32F101xE || STM32F101xG || STM32F103xE || STM32F103xG */ + +/** + * @} + */ + +/** + * @} + */ + +/** + * @} + */ +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/fw/base.c b/fw/base.c index 277c662..8e7c03b 100644 --- a/fw/base.c +++ b/fw/base.c @@ -1,5 +1,6 @@ #include +#include int __errno = 0; void *_impure_ptr = NULL; @@ -19,3 +20,6 @@ size_t strlen(const char *s) { while (*s++); return s - start - 1; } + +void __assert_func(bool value) { +} diff --git a/fw/main.c b/fw/main.c index b599cff..e00f3a6 100644 --- a/fw/main.c +++ b/fw/main.c @@ -38,8 +38,8 @@ int main(void) { RCC->APB1ENR |= RCC_APB1ENR_TIM3EN; GPIOA->MODER |= - (3<ODR &= ~(!a<<3 | !b<<7 | c<<6 | d<<4); GPIOA->ODR |= a<<3 | b<<7 | !c<<6 | !d<<4; } + set_outputs(0); + + uint8_t out_state = 0x01; +#define DEBOUNCE 100 + int debounce_ctr = 0; + int val_last = 0; + int ctr = 0; +#define RESET 1000 + int reset_ctr = 0; while (42) { #define FOO 500000 + if (reset_ctr) + reset_ctr--; + else + set_outputs(0); + + if (debounce_ctr) { + debounce_ctr--; + } else { + int val = !!(GPIOA->IDR & 1); + debounce_ctr = DEBOUNCE; + + if (val != val_last) { + if (val) + set_outputs(out_state & 0xf); + else + set_outputs(out_state >> 4); + reset_ctr = RESET; + val_last = val; + ctr++; + + if (ctr == 100) { + ctr = 0; + out_state = out_state<<1 | out_state>>7; + } + } + } + /* for (int i=0; iODR ^= 4; } }