From 3779afe88d0f5872023b962408ae5c2d97f868e6 Mon Sep 17 00:00:00 2001 From: Paul Molloy Date: Sat, 22 Jul 2017 17:03:23 -0500 Subject: [PATCH] Successfully building avr & stm core with one set of files. Two different Makefiles, specify which with -f file flag: make -f Make_avr clean program make -f Make_stm clean program made release dir to put released .hex firmware files Need to make separate avr build folder Need to make one master Makefile that calls one of the other makefiles as instructed. Currently device is recognized by PC but does nothing else other than being recognized by app during connection process: arm-none-eabi-size -t build_stm/inlretro_stm.elf text data bss dec hex filename 1332 0 20 1352 548 build_stm/inlretro_stm.elf 1332 0 20 1352 548 (TOTALS) avr-size avr_kazzo.elf text data bss dec hex filename 1496 2 43 1541 605 avr_kazzo.elf --- firmware/{Makefile => Make_avr} | 2 +- firmware/Make_stm | 100 + firmware/Makefile.avr | 79 - firmware/build_stm/inlretro_stm.bin | Bin 0 -> 1332 bytes firmware/build_stm/inlretro_stm.elf | Bin 0 -> 78492 bytes firmware/build_stm/inlretro_stm.hex | 87 + firmware/build_stm/inlretro_stm.map | 395 ++ firmware/include_stm/README_cortexM0.md | 38 + firmware/include_stm/cmsis_gcc.h | 1373 ++++ firmware/include_stm/core_cm0.h | 798 +++ firmware/include_stm/core_cmFunc.h | 87 + firmware/include_stm/core_cmInstr.h | 87 + firmware/include_stm/nokeep.ld | 212 + firmware/include_stm/startup_ARMCM0.S | 326 + firmware/include_stm/stm32f070x6.h | 5576 ++++++++++++++++ firmware/include_stm/stm32f070xb.h | 5763 +++++++++++++++++ firmware/include_stm/stm32f0xx.h | 244 + .../main_green_v1_2.hex | 0 .../main_purple_v1_1_v3_0.hex | 0 .../main_v1_2b-v1_4.hex | 0 firmware/source/main.c | 55 +- firmware/source/usb.c | 33 +- firmware/source/usb.h | 27 +- firmware/source_stm_only/stm_init.c | 167 + firmware/source_stm_only/stm_init.h | 5 + firmware/source_stm_only/usb_descriptors.h | 271 + firmware/source_stm_only/usbstm.c | 959 +++ firmware/source_stm_only/usbstm.h | 249 + 28 files changed, 16826 insertions(+), 107 deletions(-) rename firmware/{Makefile => Make_avr} (97%) create mode 100644 firmware/Make_stm delete mode 100644 firmware/Makefile.avr create mode 100644 firmware/build_stm/inlretro_stm.bin create mode 100644 firmware/build_stm/inlretro_stm.elf create mode 100644 firmware/build_stm/inlretro_stm.hex create mode 100644 firmware/build_stm/inlretro_stm.map create mode 100644 firmware/include_stm/README_cortexM0.md create mode 100644 firmware/include_stm/cmsis_gcc.h create mode 100644 firmware/include_stm/core_cm0.h create mode 100644 firmware/include_stm/core_cmFunc.h create mode 100644 firmware/include_stm/core_cmInstr.h create mode 100644 firmware/include_stm/nokeep.ld create mode 100644 firmware/include_stm/startup_ARMCM0.S create mode 100644 firmware/include_stm/stm32f070x6.h create mode 100644 firmware/include_stm/stm32f070xb.h create mode 100644 firmware/include_stm/stm32f0xx.h rename firmware/{avr_release => release}/main_green_v1_2.hex (100%) rename firmware/{avr_release => release}/main_purple_v1_1_v3_0.hex (100%) rename firmware/{avr_release => release}/main_v1_2b-v1_4.hex (100%) create mode 100644 firmware/source_stm_only/stm_init.c create mode 100644 firmware/source_stm_only/stm_init.h create mode 100644 firmware/source_stm_only/usb_descriptors.h create mode 100644 firmware/source_stm_only/usbstm.c create mode 100644 firmware/source_stm_only/usbstm.h diff --git a/firmware/Makefile b/firmware/Make_avr similarity index 97% rename from firmware/Makefile rename to firmware/Make_avr index 0929d5a..ad3a34b 100644 --- a/firmware/Makefile +++ b/firmware/Make_avr @@ -13,7 +13,7 @@ PROJ = avr_kazzo #SOURCES=$(wildcard source/**/*.c source/*.c) SOURCES=$(wildcard source/*.c) -CFLAGS = -Iusbdrv_Vusb -Isource -DDEBUG_LEVEL=0 +CFLAGS = -Iusbdrv_Vusb -Isource -DDEBUG_LEVEL=0 -DAVR_CORE USBOBJ = usbdrv_Vusb/usbdrv.o usbdrv_Vusb/usbdrvasm.o usbdrv_Vusb/oddebug.o OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) $(USBOBJ) diff --git a/firmware/Make_stm b/firmware/Make_stm new file mode 100644 index 0000000..b5c3338 --- /dev/null +++ b/firmware/Make_stm @@ -0,0 +1,100 @@ + +#Build directory +BUILD = build_stm + +#project name +#doesn't need to be associated with any file names +PROJ = inlretro_stm + + +# Selecting Core +CORTEX_M=0 + +# Use newlib-nano. To disable it, specify USE_NANO= +#USE_NANO=--specs=nano.specs +USE_NANO= + +# Use seimhosting or not +USE_SEMIHOST=--specs=rdimon.specs +USE_NOHOST=--specs=nosys.specs + +CORE=CM$(CORTEX_M) +BASE=. + +# Compiler & Linker +CC=arm-none-eabi-gcc +CXX=arm-none-eabi-g++ +OBJCOPY=arm-none-eabi-objcopy +SIZE=arm-none-eabi-size + +# Options for specific architecture +ARCH_FLAGS=-mthumb -mcpu=cortex-m$(CORTEX_M) + +# Startup code +STARTUP=$(BASE)/include_stm/startup_ARM$(CORE).S + +# -Os -flto -ffunction-sections -fdata-sections to compile for code size +CFLAGS=$(ARCH_FLAGS) $(STARTUP_DEFS) -Os -flto -ffunction-sections -fdata-sections -g +CXXFLAGS=$(CFLAGS) + +# Link for code size +GC=-Wl,--gc-sections + +# Create map file +MAP=-Wl,-Map=$(BUILD)/$(PROJ).map + +STARTUP_DEFS=-D__STARTUP_CLEAR_BSS -D__START=main -D__NO_SYSTEM_INIT + +LDSCRIPTS=-L. -L$(BASE)/include_stm -T nokeep.ld +LFLAGS=$(USE_NANO) $(USE_NOHOST) $(LDSCRIPTS) $(GC) $(MAP) + +DEFINE+=\ + -DSTM32F070xB \ + -DF_CPU=16000000 \ + -DSTM_CORE +#128KB version of all packages (LQFP-48,64,100) + +# -DSTM32F072x8 \ #64KB version of all packages (LQFP-48,64,100) +# -DSTM32F070xB \ #128KB version of both packages (LQFP-48,64) +# -DSTM32F070x6 \ #32KB version of both packages (TSSOP-20,LQFP-48) +# -DF_CPU=8000000 +INCLUDE=-I ./include_stm +CFLAGS+= $(DEFINE) $(INCLUDE) + +#SOURCES=$(wildcard source/**/*.c source/*.c) +SOURCES=$(wildcard source/*.c source_stm_only/*.c) +OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) + +#all: dir $(BUILD)/$(PROJ).axf $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size +all: dir $(BUILD)/$(PROJ).elf $(BUILD)/$(PROJ).hex $(BUILD)/$(PROJ).bin size + +#build axf file output (basically elf with DWARF debug info) +# $@ is shortcut for the target, $^ is shortcut for prereqs +# TARGET: PREREQS +$(BUILD)/$(PROJ).axf: $(STARTUP) $(OBJECTS) + $(CC) $^ $(CFLAGS) $(LFLAGS) -o $@ + +$(BUILD)/$(PROJ).elf: $(STARTUP) $(OBJECTS) + $(CC) $^ $(CFLAGS) $(LFLAGS) -o $@ + +$(BUILD)/$(PROJ).hex: $(BUILD)/$(PROJ).elf + $(OBJCOPY) -O ihex $^ $@ + +$(BUILD)/$(PROJ).bin: $(BUILD)/$(PROJ).elf + $(OBJCOPY) -O binary $^ $@ + +dir: + mkdir -p $(BUILD) + +size: $(BUILD)/$(PROJ).elf + $(SIZE) -t $^ + +program: all + ST-LINK_CLI.exe -c -P $(BUILD)\$(PROJ).hex 0x08000000 -Rst + +disassm: all + arm-none-eabi-objdump $(BUILD)\$(PROJ).elf -d -g + +clean: + rm -rf $(BUILD) + rm -f $(OBJECTS) diff --git a/firmware/Makefile.avr b/firmware/Makefile.avr deleted file mode 100644 index 0929d5a..0000000 --- a/firmware/Makefile.avr +++ /dev/null @@ -1,79 +0,0 @@ -# Name: Makefile -# Project: custom-class example -# Author: Christian Starkjohann -# Creation Date: 2008-04-07 -# Tabsize: 4 -# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH -# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) - -DEVICE = atmega164a -F_CPU = 16000000 # in Hz -PROJ = avr_kazzo -# Fuses and ISP programming handled in bootloader firmware build - -#SOURCES=$(wildcard source/**/*.c source/*.c) -SOURCES=$(wildcard source/*.c) -CFLAGS = -Iusbdrv_Vusb -Isource -DDEBUG_LEVEL=0 -USBOBJ = usbdrv_Vusb/usbdrv.o usbdrv_Vusb/usbdrvasm.o usbdrv_Vusb/oddebug.o -OBJECTS=$(patsubst %.c,%.o,$(SOURCES)) $(USBOBJ) - -COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) - -# symbolic targets: -help: - @echo "This Makefile has no default rule. Use one of the following:" - @echo "make hex ............ to build $(PROJ).hex" - @echo "make program ........ windows flash firmware via bootloader" - @echo "make program_unix ... unix flash firmware via bootloader" - @echo "make clean .......... to delete objects and hex file" - -hex: $(PROJ).hex - -program: $(PROJ).hex - ../bootloader/commandline/bootloadHID.exe -r $< - -program_unix: $(PROJ).hex - ../bootloader/commandline/bootloadHID -r $< - -# rule for deleting dependent files (those which can be built by Make): -clean: - rm -f $(PROJ).hex $(PROJ).lst $(PROJ).obj $(PROJ).cof $(PROJ).list $(PROJ).map $(PROJ).eep.hex $(PROJ).elf $(OBJECTS) $(PROJ).s usbdrv_Vusb/oddebug.s usbdrv_Vusb/usbdrv.s source/shared_* - -# Generic rule for compiling C files: -.c.o: - $(COMPILE) -c $< -o $@ - -# Generic rule for assembling Assembler source files: -.S.o: - $(COMPILE) -x assembler-with-cpp -c $< -o $@ -# "-x assembler-with-cpp" should not be necessary since this is the default -# file type for the .S (with capital S) extension. However, upper case -# characters are not always preserved on Windows. To ensure WinAVR -# compatibility define the file type manually. - -# Generic rule for compiling C to assembler, used for debugging only. -.c.s: - $(COMPILE) -S $< -o $@ - -# file targets: - -$(PROJ).elf: shared $(OBJECTS) - $(COMPILE) -o $(PROJ).elf $(OBJECTS) - -$(PROJ).hex: $(PROJ).elf - rm -f $(PROJ).hex $(PROJ).eep.hex - avr-objcopy -j .text -j .data -O ihex $(PROJ).elf $(PROJ).hex -# avr-size -C --mcu=${DEVICE} $(PROJ).elf - avr-size $(PROJ).elf - -# debugging targets: - -disasm: $(PROJ).elf - avr-objdump -d $(PROJ).elf - -cpp: - $(COMPILE) -E $(PROJ).c - -#copy shared .h files which are used in host and firmware -shared: - cp -r ../shared/* source/ diff --git a/firmware/build_stm/inlretro_stm.bin b/firmware/build_stm/inlretro_stm.bin new file mode 100644 index 0000000000000000000000000000000000000000..f3eb682fb2d41e51c7e195bb8a96d2c924b6d9f7 GIT binary patch literal 1332 zcmc&!O>7%Q6n;Cqw$^Jx*It^|6R7q_7K+`pNk}T7LS1=LWY4T3*X5A991IoU2o)@- zP!5$CxMUlN8s(Y`2M%zx6mC&MPaHQ@3$2qNb3iMBD)mOI{w#0ZL>!QS8zX)5-n@N3 z^S-yca1_k%0o2Ect1_tY4=eFGc%10}H#Q_tGc}EAe2vO`%IO~#!urEqwWcyK8I6vTfs`@ zx7(^Ci@TAIchV3@vgx+Ktsq`U5X2k;-UL^OINt2WaTu>l@FxG=I>|7lBkZA9}DrR!D;q; zw9}KyS_ox1B;{un9hc+K&;8t5`EtN@2|@W^|_5 zPR|fvIl)P0xCk%Fe}WgVGwMxn>Q3;cyV|qGao+DXQt4a5DkJ}3_m@lD5uJ^3J{H`I zkcaf$TTbvIW)XItB-~{A*peuJ6CPp45|n=qg_ZT5uVn=|M(3v};kbKf_?DYh(EGK8XOnw2$+=Txd_OYaVS0dzBR0xyqwZvd_0QuZfoP?FKo}ZtQD?c0<|s zSDyL{i@uMRi^9IWm{*9`f9vh^@_q)=|i3B@ey}oRVykA79vqd3_ zIscMW6uNJT>&tpgM^=TUvrIaN_3w0VfQE4+Y=l#hd_SNQmtZe-MA8>vKMEr0>!8Pk zQ}_i2fIKXqet&&yEN zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaajO1egF5U;<2l2`~XBzyz286JP>N zfC(@GCcp%k025#WOn?b60Vco%m;e)C0!)AjFaaj;e~7?pp*=5z@4pc5lEU{t^^9yB zJ>~zm+uDJHc+L$<=H*k|IwS`=Yzi%qSb5m zT|@uPxE$%nm*@7@g#1rdPSk{IdaGs!d;_BYrs|+STQ#e;+<(3*Yn80~L`judQn`P@ z>V}(E1sq&#T#**{ZC+rz})FThZkYR<$?P4z@pVz9j2^wzRi; z_Dtu$z3!`(*$*!J(WhcWK-SuiiuO*#ZbTJvFQOP0?b+=7{BvjL=Zj#Id~&F_c6QBq zu~ocr*QMIo8{j)zThUdUMX6W(@b*gwf~Tr0CX}lxj`oJCrdNo2x(RCeKoU466q4Csa=l|pI{Ps&%2j9E=#(8CH@ddF}UQoA|T=0p1y}Uix z67pzOM=xF87HkY{+h29`jmxdUhEOYV|9Dw!_MuJh7BAXt4ptZ)vZ}6zP*r>!d5x<4FMGEmNq*oyIz@{Jd&)z#fPjg0d z_#Et;nuI7q8@-5H3-TymhWY&XvJm&xTp22tl@m=*7I#%0&DPwnR!)?4esn>pIWke) zbrVXCObn<_?ln7CIWgd|?LC%#wz}#zlti*MuSd&0YS+c^$WyAeGSpso@$8D;JGw5O zzIayINvWtQ-~YntnrwM*9inerT{c@+)*Dmmvi{!c>_EhqKItE zV$d=}xgykgJXz*ezUdXJq6)<$7kjqI9uXH~B8qENWP~9OAf`nxq~m5TAR;0mVz!sh zl3W3w2jD>y1MrX$Db#Ne{boA;Ssbtp6JP>NfC(@GCcp%k025#W|8EF%Y{F2(MtCGD zly%5@w+}Y-iJ~Qo`W7qYp5@94WtCj5R4Mzqx^`>z`wkq`h7yU%v^JJVX&nQ7+Md{m zF*<6DYW=B1#7L(Tsq|)Td!QxIthF>XZ*OjC+NRZ~j7cM$Ha2TFqe`P;S83SZFp>(# zBNJN6I37($6LGDj^{O3L?fRU!4LwoCRdiK;Q@RwVE1a){Kvbgf$mG0;RR9j=Cye7~n*9TMu z&cCfvb8%GuM04rHR4QV&rYGW)Gs2QZpwZor$nN1}Dlwi4$F#BNq>#llL}KY^S|5)@0uutS03wN$p+{m(mZXmwW8taEjGmcE8flc_%!|nw zjm9$&ytx)8s0FlUxkLsP(~(p(nZXi)r9D$feexx#V3ElQO|I5tNkC3%#0vD-o$nmKJ&$~Yh?A|rj~2vxl;jI z+;-=N_43CeAg>6>hm;59`(J2lxn0f#8rL_OfAS;fUie}_mbG0Yzo)dp$;l>pk8+3n z3~L795-dkmZXl0#clhMTe5-*51B*pc_>**m%~t% zK8?&GvFrtEP?2A1~v%CVbDp zt8%XVZP+M5rQ%jf+a=vTuTb{fVVEvYll@U?jsx~976G6VmekTp>f0}2j=WGlFRz8^ zDg$Npr2GY4RN-qUY>{U8FX-M9g3BISMGqgqK)$F&AeFW@#2Xi%Il#}HY??qsN!zriXE_# zuOW}S zj&8V3k0QUhgFL@OCSLilQ{x9tjWV(6ugU5)a(oLFdnLUR-b`aGUTGE3JLCEt@T1Hr zOYj8nO1}`A&qJ%eewfOiQ7G?~AfeU2MLM$n)Rsaop}SrC#()XhJCy{-QFaT#>#tzB*q8esoZ#)Rk70$kH{X z2UnFT{#95GD}^lGU2=6vPX$iDoRfUHCObtP6r$WNE74HBBA{GX>GV2hL@g}0+l3z$NLDO}xOLYl z%@qU6!BvM#j(EvPZ?iR+Txf+L9?dlrDni5QWIhImwD{8Gp$%a-zBdv4z zY^o$e8y$p}xM?H6W6>_)Q1LUid0~=B+yc>_KoYI67711&0#+-+99G1&X3n~_B2mSc zakccqehNF!T<6i|Je{1X@4~JZkHI3bWdBjo{?GvOb1vDjqlfWlv7_g5tE)cw`>IQJ z{LvHo+^3Y&^Xy7QRb2m&V@quZVB3U9eITEsh!cpDi1r-%p&5JHOJu8r#?CL zsc)a9KK0qDPt5)R@#~26>~_jc#>5$s_)XbQ&^F^VGx_Vu(U zHMckWdiwf%_x#Q$7p))Sj_IS(lt?GTk=u-nI5^m;_YB;yKO7&OG*Wi8ov5YjMm#(+Y3R|^F>&Bf zPnW*OlwmB|aF&aXMI+JhaW=1-gUdsZ9mF#ddpApB_u$+$Hv- zXM4?~l*7q2zCo&(KLAw8_Yloc-|Suht~qs9pBK7=#zyUqw^$uV|B?v|U5Al4(QCxV zGZW%>IvAGUd+Cy;=J~+9_vqe4rnA&{r+TjDW5Y%RQw_?v!64%ikKz`(5IpU4VGAaf(P3Z+=;(o%m)7e)k)M|?QnfYj+f zl{8Te2O#uUlbj2dJw&^sir52T&Lxw-pB2dOx@5Bd$R$I}1?ms!(aD_u{Uq9Rk5AzE zE{$EeOHcN+29O|FdVdb2)jwJXj-Kpk9XK-iYtKF3t@bWT*d+L8eW)d7^@cCm_?F+>z%XKMdKjw|LOu0L2K3_&Z!lrad|x z4{7{##z2Cgh>N(A+-6Gle2~fvrQ))aMe5A=!tbj!U(+ssE_2iVAPrnN<5R_0flTiU z-1;*G@`DBPpBKn99^zwqvByVz+%oZT>~8<{0{#01@;u}zn4~o8RBH1#+N3F4%;0B$M6PLk;&P zBH_v5Ap>tDBassW$?JPN0|~KVR19XY+tdfKPZj%(aMH?c$Q1071ie3SZ~YhcMzq;m zkerR%LW#L|f|0qmUDyV?cb)EYMBer=Z+~nF_WmofyYW-L7BqhP*Mi1{uLX@G(RgDZ z&^Q?#X~fI<#=MUQWEW^|G!Gw*$G11c8Y9?EgOje0VPB|+Q>pL_Hs7Q91?GEV6q#E` zw@or-e4@-%;MB`Eb4qD8I`P2=j%gQ+&jZ-n>$(`~>1)=zy4**Dp}{=ylY8Qh?k?21 zzOUb1Yj7q#6vf;-8|QuuZ17M{JkZyZ%j3i`9UYxEhu+fyUwP*e1IM$B7(k!81_tw0 zG>G1444Z6SA4#WkgBa}Z$#a51ZP&Xy@`m9wY5_So*fB74mEP+1zvu8!Pm6w)yU3gb zfj+jlONrSIcR|-4bhhJwyQu$Aw|=O*yXX46ngixx$U)TI*8z?b;dtDbY}L2v+x0xJ z_Dq4JJx|-+4Oj$n%DisVNLuygZEkyaV|lQ;?T<%JuV{36Tu_kLFEYq;P0cmwc}@#X zo0yK!lBZ3ZY?l#f#f;d+uJd?-|f;g$s0A1(K`o1`oVsEXkZ`RBkl?! zke-QU!XrpCDJz|Da^|8BmYU85uTyCMk_+_nM4=jy?C^6=L2LDrv=AI=6N+ea=-APlJnScO!SQz`N}M|M`@56; z;Wy9;_6AezLIHdwo${UdY*g9V4X9c= __HeapLimit), region RAM overflowed with stack) +OUTPUT(build_stm/inlretro_stm.elf elf32-littlearm) + +.ARM.attributes + 0x00000000 0x28 + .ARM.attributes + 0x00000000 0x1e c:/program files (x86)/gnu tools arm embedded/6.2 2016q4/bin/../lib/gcc/arm-none-eabi/6.2.1/thumb/v6-m/crti.o + .ARM.attributes + 0x0000001e 0x1b C:\Users\Paul\AppData\Local\Temp\ccwRpOLB.o + .ARM.attributes + 0x00000039 0x2f C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.comment 0x00000000 0x6e + .comment 0x00000000 0x6e C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + 0x6f (size before relaxing) + +.debug_line 0x00000000 0x31d + .debug_line 0x00000000 0x6f C:\Users\Paul\AppData\Local\Temp\ccwRpOLB.o + .debug_line 0x0000006f 0x2ae C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.debug_info 0x00000000 0x501 + .debug_info 0x00000000 0x83 C:\Users\Paul\AppData\Local\Temp\ccwRpOLB.o + .debug_info 0x00000083 0x47e C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.debug_abbrev 0x00000000 0x277 + .debug_abbrev 0x00000000 0x14 C:\Users\Paul\AppData\Local\Temp\ccwRpOLB.o + .debug_abbrev 0x00000014 0x263 C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.debug_aranges 0x00000000 0x58 + .debug_aranges + 0x00000000 0x20 C:\Users\Paul\AppData\Local\Temp\ccwRpOLB.o + .debug_aranges + 0x00000020 0x38 C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.debug_loc 0x00000000 0xa4 + .debug_loc 0x00000000 0xa4 C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.debug_ranges 0x00000000 0xc0 + .debug_ranges 0x00000000 0xc0 C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + +.debug_str 0x00000000 0x360 + .debug_str 0x00000000 0x360 C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o + 0x38a (size before relaxing) + +.debug_frame 0x00000000 0x70 + .debug_frame 0x00000000 0x70 C:\Users\Paul\AppData\Local\Temp\ccKBE1yb.ltrans0.ltrans.o diff --git a/firmware/include_stm/README_cortexM0.md b/firmware/include_stm/README_cortexM0.md new file mode 100644 index 0000000..7878be3 --- /dev/null +++ b/firmware/include_stm/README_cortexM0.md @@ -0,0 +1,38 @@ +Paul's super awesome bare cortex M0 bare metal project. + +Got tired sifting through existing bare metal template projects and not liking how everything was setup. +Also feel silly starting such a simple project with some sort of licensing to bother with. +Stumbled upon the example projects included with arm-none-eabi-gcc compiler and decided that was as good as starting point as any. +So that's where the files originated from. + +I cut out files not used by cortex M0 or the minimum example. +Then reorganized the directory into how I like things by default. +Combined everything into one single Makefile and added creation of hex/binary file output and size reporting. + +This could easily be migrated to different core M0plus etc, just by including the proper startup file and modifying Makefile. + +When using as template first thing to do is modify linker file for memory sizes of target chip. +Don't forget to update CPU frequency as needed for any time functions. +Then bring in some library/header files for registers included with target chip. +Finally do something useful in init and main. + +There is option to use nano new lib or not in Makefile for things like printf and malloc which doesn't sound very bare metal to me.. +But whatev it's there and ready to turn on if needed. + +Current size: + text data bss dec hex filename + 148 0 0 148 94 build/baremetal.elf + +Pertenent sections of readme from samples dir: + +ldscripts/mem.ld defines address ranges for flash and RAM. Modify them to +reflect start address and length of flash/RAM banks in your board, by +following the embedded comments. + +Recommend to make clean after modifying mem.ld. + +** minimum - A minimum skeleton to start a C program with limited features. +This case has a empty main. Code size built from it is only about 150 bytes, +since it has almost no "fat" for a Cortex-M C program. Be noticed that this +case doesn't support semihosting or C++ global constructor/destructor. + diff --git a/firmware/include_stm/cmsis_gcc.h b/firmware/include_stm/cmsis_gcc.h new file mode 100644 index 0000000..bb89fbb --- /dev/null +++ b/firmware/include_stm/cmsis_gcc.h @@ -0,0 +1,1373 @@ +/**************************************************************************//** + * @file cmsis_gcc.h + * @brief CMSIS Cortex-M Core Function/Instruction Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#ifndef __CMSIS_GCC_H +#define __CMSIS_GCC_H + +/* ignore some GCC warnings */ +#if defined ( __GNUC__ ) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wsign-conversion" +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wunused-parameter" +#endif + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ + */ + +/** + \brief Enable IRQ Interrupts + \details Enables IRQ interrupts by clearing the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void) +{ + __ASM volatile ("cpsie i" : : : "memory"); +} + + +/** + \brief Disable IRQ Interrupts + \details Disables IRQ interrupts by setting the I-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void) +{ + __ASM volatile ("cpsid i" : : : "memory"); +} + + +/** + \brief Get Control Register + \details Returns the content of the Control Register. + \return Control Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, control" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Control Register + \details Writes the given value to the Control Register. + \param [in] control Control Register value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control) +{ + __ASM volatile ("MSR control, %0" : : "r" (control) : "memory"); +} + + +/** + \brief Get IPSR Register + \details Returns the content of the IPSR Register. + \return IPSR Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, ipsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get APSR Register + \details Returns the content of the APSR Register. + \return APSR Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, apsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get xPSR Register + \details Returns the content of the xPSR Register. + + \return xPSR Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, xpsr" : "=r" (result) ); + return(result); +} + + +/** + \brief Get Process Stack Pointer + \details Returns the current value of the Process Stack Pointer (PSP). + \return PSP Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, psp\n" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Process Stack Pointer + \details Assigns the given value to the Process Stack Pointer (PSP). + \param [in] topOfProcStack Process Stack Pointer value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack) +{ + __ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp"); +} + + +/** + \brief Get Main Stack Pointer + \details Returns the current value of the Main Stack Pointer (MSP). + \return MSP Register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void) +{ + register uint32_t result; + + __ASM volatile ("MRS %0, msp\n" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Main Stack Pointer + \details Assigns the given value to the Main Stack Pointer (MSP). + + \param [in] topOfMainStack Main Stack Pointer value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack) +{ + __ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp"); +} + + +/** + \brief Get Priority Mask + \details Returns the current state of the priority mask bit from the Priority Mask Register. + \return Priority Mask value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, primask" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Priority Mask + \details Assigns the given value to the Priority Mask Register. + \param [in] priMask Priority Mask + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask) +{ + __ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory"); +} + + +#if (__CORTEX_M >= 0x03U) + +/** + \brief Enable FIQ + \details Enables FIQ interrupts by clearing the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void) +{ + __ASM volatile ("cpsie f" : : : "memory"); +} + + +/** + \brief Disable FIQ + \details Disables FIQ interrupts by setting the F-bit in the CPSR. + Can only be executed in Privileged modes. + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void) +{ + __ASM volatile ("cpsid f" : : : "memory"); +} + + +/** + \brief Get Base Priority + \details Returns the current value of the Base Priority register. + \return Base Priority register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, basepri" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Base Priority + \details Assigns the given value to the Base Priority register. + \param [in] basePri Base Priority value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value) +{ + __ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory"); +} + + +/** + \brief Set Base Priority with condition + \details Assigns the given value to the Base Priority register only if BASEPRI masking is disabled, + or the new value increases the BASEPRI priority level. + \param [in] basePri Base Priority value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t value) +{ + __ASM volatile ("MSR basepri_max, %0" : : "r" (value) : "memory"); +} + + +/** + \brief Get Fault Mask + \details Returns the current value of the Fault Mask register. + \return Fault Mask register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void) +{ + uint32_t result; + + __ASM volatile ("MRS %0, faultmask" : "=r" (result) ); + return(result); +} + + +/** + \brief Set Fault Mask + \details Assigns the given value to the Fault Mask register. + \param [in] faultMask Fault Mask value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask) +{ + __ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory"); +} + +#endif /* (__CORTEX_M >= 0x03U) */ + + +#if (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) + +/** + \brief Get FPSCR + \details Returns the current value of the Floating Point Status/Control register. + \return Floating Point Status/Control register value + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + uint32_t result; + + /* Empty asm statement works as a scheduling barrier */ + __ASM volatile (""); + __ASM volatile ("VMRS %0, fpscr" : "=r" (result) ); + __ASM volatile (""); + return(result); +#else + return(0); +#endif +} + + +/** + \brief Set FPSCR + \details Assigns the given value to the Floating Point Status/Control register. + \param [in] fpscr Floating Point Status/Control value to set + */ +__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr) +{ +#if (__FPU_PRESENT == 1U) && (__FPU_USED == 1U) + /* Empty asm statement works as a scheduling barrier */ + __ASM volatile (""); + __ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc"); + __ASM volatile (""); +#endif +} + +#endif /* (__CORTEX_M == 0x04U) || (__CORTEX_M == 0x07U) */ + + + +/*@} end of CMSIS_Core_RegAccFunctions */ + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/* Define macros for porting to both thumb1 and thumb2. + * For thumb1, use low register (r0-r7), specified by constraint "l" + * Otherwise, use general registers, specified by constraint "r" */ +#if defined (__thumb__) && !defined (__thumb2__) +#define __CMSIS_GCC_OUT_REG(r) "=l" (r) +#define __CMSIS_GCC_USE_REG(r) "l" (r) +#else +#define __CMSIS_GCC_OUT_REG(r) "=r" (r) +#define __CMSIS_GCC_USE_REG(r) "r" (r) +#endif + +/** + \brief No Operation + \details No Operation does nothing. This instruction can be used for code alignment purposes. + */ +__attribute__((always_inline)) __STATIC_INLINE void __NOP(void) +{ + __ASM volatile ("nop"); +} + + +/** + \brief Wait For Interrupt + \details Wait For Interrupt is a hint instruction that suspends execution until one of a number of events occurs. + */ +__attribute__((always_inline)) __STATIC_INLINE void __WFI(void) +{ + __ASM volatile ("wfi"); +} + + +/** + \brief Wait For Event + \details Wait For Event is a hint instruction that permits the processor to enter + a low-power state until one of a number of events occurs. + */ +__attribute__((always_inline)) __STATIC_INLINE void __WFE(void) +{ + __ASM volatile ("wfe"); +} + + +/** + \brief Send Event + \details Send Event is a hint instruction. It causes an event to be signaled to the CPU. + */ +__attribute__((always_inline)) __STATIC_INLINE void __SEV(void) +{ + __ASM volatile ("sev"); +} + + +/** + \brief Instruction Synchronization Barrier + \details Instruction Synchronization Barrier flushes the pipeline in the processor, + so that all instructions following the ISB are fetched from cache or memory, + after the instruction has been completed. + */ +__attribute__((always_inline)) __STATIC_INLINE void __ISB(void) +{ + __ASM volatile ("isb 0xF":::"memory"); +} + + +/** + \brief Data Synchronization Barrier + \details Acts as a special kind of Data Memory Barrier. + It completes when all explicit memory accesses before this instruction complete. + */ +__attribute__((always_inline)) __STATIC_INLINE void __DSB(void) +{ + __ASM volatile ("dsb 0xF":::"memory"); +} + + +/** + \brief Data Memory Barrier + \details Ensures the apparent order of the explicit memory operations before + and after the instruction, without ensuring their completion. + */ +__attribute__((always_inline)) __STATIC_INLINE void __DMB(void) +{ + __ASM volatile ("dmb 0xF":::"memory"); +} + + +/** + \brief Reverse byte order (32 bit) + \details Reverses the byte order in integer value. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV(uint32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) + return __builtin_bswap32(value); +#else + uint32_t result; + + __ASM volatile ("rev %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +#endif +} + + +/** + \brief Reverse byte order (16 bit) + \details Reverses the byte order in two unsigned short values. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __REV16(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rev16 %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief Reverse byte order in signed short value + \details Reverses the byte order in a signed short value with sign extension to integer. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE int32_t __REVSH(int32_t value) +{ +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + return (short)__builtin_bswap16(value); +#else + int32_t result; + + __ASM volatile ("revsh %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +#endif +} + + +/** + \brief Rotate Right in unsigned value (32 bit) + \details Rotate Right (immediate) provides the value of the contents of a register rotated by a variable number of bits. + \param [in] value Value to rotate + \param [in] value Number of Bits to rotate + \return Rotated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __ROR(uint32_t op1, uint32_t op2) +{ + return (op1 >> op2) | (op1 << (32U - op2)); +} + + +/** + \brief Breakpoint + \details Causes the processor to enter Debug state. + Debug tools can use this to investigate system state when the instruction at a particular address is reached. + \param [in] value is ignored by the processor. + If required, a debugger can use it to store additional information about the breakpoint. + */ +#define __BKPT(value) __ASM volatile ("bkpt "#value) + + +/** + \brief Reverse bit order of value + \details Reverses the bit order of the given value. + \param [in] value Value to reverse + \return Reversed value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RBIT(uint32_t value) +{ + uint32_t result; + +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + __ASM volatile ("rbit %0, %1" : "=r" (result) : "r" (value) ); +#else + int32_t s = 4 /*sizeof(v)*/ * 8 - 1; /* extra shift needed at end */ + + result = value; /* r will be reversed bits of v; first get LSB of v */ + for (value >>= 1U; value; value >>= 1U) + { + result <<= 1U; + result |= value & 1U; + s--; + } + result <<= s; /* shift when v's highest bits are zero */ +#endif + return(result); +} + + +/** + \brief Count leading zeros + \details Counts the number of leading zeros of a data value. + \param [in] value Value to count the leading zeros + \return number of leading zeros in value + */ +#define __CLZ __builtin_clz + + +#if (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) + +/** + \brief LDR Exclusive (8 bit) + \details Executes a exclusive LDR instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDREXB(volatile uint8_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexb %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexb %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (16 bit) + \details Executes a exclusive LDR instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDREXH(volatile uint16_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrexh %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrexh %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDR Exclusive (32 bit) + \details Executes a exclusive LDR instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDREXW(volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("ldrex %0, %1" : "=r" (result) : "Q" (*addr) ); + return(result); +} + + +/** + \brief STR Exclusive (8 bit) + \details Executes a exclusive STR instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXB(uint8_t value, volatile uint8_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexb %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (16 bit) + \details Executes a exclusive STR instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXH(uint16_t value, volatile uint16_t *addr) +{ + uint32_t result; + + __ASM volatile ("strexh %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" ((uint32_t)value) ); + return(result); +} + + +/** + \brief STR Exclusive (32 bit) + \details Executes a exclusive STR instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + \return 0 Function succeeded + \return 1 Function failed + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __STREXW(uint32_t value, volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("strex %0, %2, %1" : "=&r" (result), "=Q" (*addr) : "r" (value) ); + return(result); +} + + +/** + \brief Remove the exclusive lock + \details Removes the exclusive lock which is created by LDREX. + */ +__attribute__((always_inline)) __STATIC_INLINE void __CLREX(void) +{ + __ASM volatile ("clrex" ::: "memory"); +} + + +/** + \brief Signed Saturate + \details Saturates a signed value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (1..32) + \return Saturated value + */ +#define __SSAT(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Unsigned Saturate + \details Saturates an unsigned value. + \param [in] value Value to be saturated + \param [in] sat Bit position to saturate to (0..31) + \return Saturated value + */ +#define __USAT(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + + +/** + \brief Rotate Right with Extend (32 bit) + \details Moves each bit of a bitstring right by one bit. + The carry input is shifted in at the left end of the bitstring. + \param [in] value Value to rotate + \return Rotated value + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __RRX(uint32_t value) +{ + uint32_t result; + + __ASM volatile ("rrx %0, %1" : __CMSIS_GCC_OUT_REG (result) : __CMSIS_GCC_USE_REG (value) ); + return(result); +} + + +/** + \brief LDRT Unprivileged (8 bit) + \details Executes a Unprivileged LDRT instruction for 8 bit value. + \param [in] ptr Pointer to data + \return value of type uint8_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint8_t __LDRBT(volatile uint8_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrbt %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrbt %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint8_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (16 bit) + \details Executes a Unprivileged LDRT instruction for 16 bit values. + \param [in] ptr Pointer to data + \return value of type uint16_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint16_t __LDRHT(volatile uint16_t *addr) +{ + uint32_t result; + +#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8) + __ASM volatile ("ldrht %0, %1" : "=r" (result) : "Q" (*addr) ); +#else + /* Prior to GCC 4.8, "Q" will be expanded to [rx, #0] which is not + accepted by assembler. So has to use following less efficient pattern. + */ + __ASM volatile ("ldrht %0, [%1]" : "=r" (result) : "r" (addr) : "memory" ); +#endif + return ((uint16_t) result); /* Add explicit type cast here */ +} + + +/** + \brief LDRT Unprivileged (32 bit) + \details Executes a Unprivileged LDRT instruction for 32 bit values. + \param [in] ptr Pointer to data + \return value of type uint32_t at (*ptr) + */ +__attribute__((always_inline)) __STATIC_INLINE uint32_t __LDRT(volatile uint32_t *addr) +{ + uint32_t result; + + __ASM volatile ("ldrt %0, %1" : "=r" (result) : "Q" (*addr) ); + return(result); +} + + +/** + \brief STRT Unprivileged (8 bit) + \details Executes a Unprivileged STRT instruction for 8 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRBT(uint8_t value, volatile uint8_t *addr) +{ + __ASM volatile ("strbt %1, %0" : "=Q" (*addr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (16 bit) + \details Executes a Unprivileged STRT instruction for 16 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRHT(uint16_t value, volatile uint16_t *addr) +{ + __ASM volatile ("strht %1, %0" : "=Q" (*addr) : "r" ((uint32_t)value) ); +} + + +/** + \brief STRT Unprivileged (32 bit) + \details Executes a Unprivileged STRT instruction for 32 bit values. + \param [in] value Value to store + \param [in] ptr Pointer to location + */ +__attribute__((always_inline)) __STATIC_INLINE void __STRT(uint32_t value, volatile uint32_t *addr) +{ + __ASM volatile ("strt %1, %0" : "=Q" (*addr) : "r" (value) ); +} + +#endif /* (__CORTEX_M >= 0x03U) || (__CORTEX_SC >= 300U) */ + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + + +/* ################### Compiler specific Intrinsics ########################### */ +/** \defgroup CMSIS_SIMD_intrinsics CMSIS SIMD Intrinsics + Access to dedicated SIMD instructions + @{ +*/ + +#if (__CORTEX_M >= 0x04U) /* only for Cortex-M4 and above */ + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHADD16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhadd16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSUB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsub16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHASX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhasx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("ssax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __QSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("qsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("shsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UQSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uqsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UHSAX(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uhsax %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USAD8(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("usad8 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __USADA8(uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("usada8 %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#define __SSAT16(ARG1,ARG2) \ +({ \ + int32_t __RES, __ARG1 = (ARG1); \ + __ASM ("ssat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +#define __USAT16(ARG1,ARG2) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1); \ + __ASM ("usat16 %0, %1, %2" : "=r" (__RES) : "I" (ARG2), "r" (__ARG1) ); \ + __RES; \ + }) + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("uxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __UXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("uxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTB16(uint32_t op1) +{ + uint32_t result; + + __ASM volatile ("sxtb16 %0, %1" : "=r" (result) : "r" (op1)); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SXTAB16(uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sxtab16 %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUAD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuad %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUADX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smuadx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLAD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlad %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLADX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smladx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLALDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSD (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMUSDX (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("smusdx %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSD (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsd %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMLSDX (uint32_t op1, uint32_t op2, uint32_t op3) +{ + uint32_t result; + + __ASM volatile ("smlsdx %0, %1, %2, %3" : "=r" (result) : "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLD (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint64_t __SMLSLDX (uint32_t op1, uint32_t op2, uint64_t acc) +{ + union llreg_u{ + uint32_t w32[2]; + uint64_t w64; + } llr; + llr.w64 = acc; + +#ifndef __ARMEB__ /* Little endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) ); +#else /* Big endian */ + __ASM volatile ("smlsldx %0, %1, %2, %3" : "=r" (llr.w32[1]), "=r" (llr.w32[0]): "r" (op1), "r" (op2) , "0" (llr.w32[1]), "1" (llr.w32[0]) ); +#endif + + return(llr.w64); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SEL (uint32_t op1, uint32_t op2) +{ + uint32_t result; + + __ASM volatile ("sel %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QADD( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qadd %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __QSUB( int32_t op1, int32_t op2) +{ + int32_t result; + + __ASM volatile ("qsub %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) ); + return(result); +} + +#define __PKHBT(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + __ASM ("pkhbt %0, %1, %2, lsl %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +#define __PKHTB(ARG1,ARG2,ARG3) \ +({ \ + uint32_t __RES, __ARG1 = (ARG1), __ARG2 = (ARG2); \ + if (ARG3 == 0) \ + __ASM ("pkhtb %0, %1, %2" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2) ); \ + else \ + __ASM ("pkhtb %0, %1, %2, asr %3" : "=r" (__RES) : "r" (__ARG1), "r" (__ARG2), "I" (ARG3) ); \ + __RES; \ + }) + +__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __SMMLA (int32_t op1, int32_t op2, int32_t op3) +{ + int32_t result; + + __ASM volatile ("smmla %0, %1, %2, %3" : "=r" (result): "r" (op1), "r" (op2), "r" (op3) ); + return(result); +} + +#endif /* (__CORTEX_M >= 0x04) */ +/*@} end of group CMSIS_SIMD_intrinsics */ + + +#if defined ( __GNUC__ ) +#pragma GCC diagnostic pop +#endif + +#endif /* __CMSIS_GCC_H */ diff --git a/firmware/include_stm/core_cm0.h b/firmware/include_stm/core_cm0.h new file mode 100644 index 0000000..711dad5 --- /dev/null +++ b/firmware/include_stm/core_cm0.h @@ -0,0 +1,798 @@ +/**************************************************************************//** + * @file core_cm0.h + * @brief CMSIS Cortex-M0 Core Peripheral Access Layer Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CM0_H_GENERIC +#define __CORE_CM0_H_GENERIC + +#include + +#ifdef __cplusplus + extern "C" { +#endif + +/** + \page CMSIS_MISRA_Exceptions MISRA-C:2004 Compliance Exceptions + CMSIS violates the following MISRA-C:2004 rules: + + \li Required Rule 8.5, object/function definition in header file.
+ Function definitions in header files are used to allow 'inlining'. + + \li Required Rule 18.4, declaration of union type or object of union type: '{...}'.
+ Unions are used for effective representation of core registers. + + \li Advisory Rule 19.7, Function-like macro defined.
+ Function-like macros are used to allow more efficient code. + */ + + +/******************************************************************************* + * CMSIS definitions + ******************************************************************************/ +/** + \ingroup Cortex_M0 + @{ + */ + +/* CMSIS CM0 definitions */ +#define __CM0_CMSIS_VERSION_MAIN (0x04U) /*!< [31:16] CMSIS HAL main version */ +#define __CM0_CMSIS_VERSION_SUB (0x1EU) /*!< [15:0] CMSIS HAL sub version */ +#define __CM0_CMSIS_VERSION ((__CM0_CMSIS_VERSION_MAIN << 16U) | \ + __CM0_CMSIS_VERSION_SUB ) /*!< CMSIS HAL version number */ + +#define __CORTEX_M (0x00U) /*!< Cortex-M Core */ + + +#if defined ( __CC_ARM ) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #define __ASM __asm /*!< asm keyword for ARM Compiler */ + #define __INLINE __inline /*!< inline keyword for ARM Compiler */ + #define __STATIC_INLINE static __inline + +#elif defined ( __GNUC__ ) + #define __ASM __asm /*!< asm keyword for GNU Compiler */ + #define __INLINE inline /*!< inline keyword for GNU Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __ICCARM__ ) + #define __ASM __asm /*!< asm keyword for IAR Compiler */ + #define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */ + #define __STATIC_INLINE static inline + +#elif defined ( __TMS470__ ) + #define __ASM __asm /*!< asm keyword for TI CCS Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __TASKING__ ) + #define __ASM __asm /*!< asm keyword for TASKING Compiler */ + #define __INLINE inline /*!< inline keyword for TASKING Compiler */ + #define __STATIC_INLINE static inline + +#elif defined ( __CSMC__ ) + #define __packed + #define __ASM _asm /*!< asm keyword for COSMIC Compiler */ + #define __INLINE inline /*!< inline keyword for COSMIC Compiler. Use -pc99 on compile line */ + #define __STATIC_INLINE static inline + +#else + #error Unknown compiler +#endif + +/** __FPU_USED indicates whether an FPU is used or not. + This core does not support an FPU at all +*/ +#define __FPU_USED 0U + +#if defined ( __CC_ARM ) + #if defined __TARGET_FPU_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #if defined __ARM_PCS_VFP + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __GNUC__ ) + #if defined (__VFP_FP__) && !defined(__SOFTFP__) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __ICCARM__ ) + #if defined __ARMVFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TMS470__ ) + #if defined __TI_VFP_SUPPORT__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __TASKING__ ) + #if defined __FPU_VFP__ + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#elif defined ( __CSMC__ ) + #if ( __CSMC__ & 0x400U) + #error "Compiler generates FPU instructions for a device without an FPU (check __FPU_PRESENT)" + #endif + +#endif + +#include "core_cmInstr.h" /* Core Instruction Access */ +#include "core_cmFunc.h" /* Core Function Access */ + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0_H_GENERIC */ + +#ifndef __CMSIS_GENERIC + +#ifndef __CORE_CM0_H_DEPENDANT +#define __CORE_CM0_H_DEPENDANT + +#ifdef __cplusplus + extern "C" { +#endif + +/* check device defines and use defaults */ +#if defined __CHECK_DEVICE_DEFINES + #ifndef __CM0_REV + #define __CM0_REV 0x0000U + #warning "__CM0_REV not defined in device header file; using default!" + #endif + + #ifndef __NVIC_PRIO_BITS + #define __NVIC_PRIO_BITS 2U + #warning "__NVIC_PRIO_BITS not defined in device header file; using default!" + #endif + + #ifndef __Vendor_SysTickConfig + #define __Vendor_SysTickConfig 0U + #warning "__Vendor_SysTickConfig not defined in device header file; using default!" + #endif +#endif + +/* IO definitions (access restrictions to peripheral registers) */ +/** + \defgroup CMSIS_glob_defs CMSIS Global Defines + + IO Type Qualifiers are used + \li to specify the access to peripheral variables. + \li for automatic generation of peripheral register debug information. +*/ +#ifdef __cplusplus + #define __I volatile /*!< Defines 'read only' permissions */ +#else + #define __I volatile const /*!< Defines 'read only' permissions */ +#endif +#define __O volatile /*!< Defines 'write only' permissions */ +#define __IO volatile /*!< Defines 'read / write' permissions */ + +/* following defines should be used for structure members */ +#define __IM volatile const /*! Defines 'read only' structure member permissions */ +#define __OM volatile /*! Defines 'write only' structure member permissions */ +#define __IOM volatile /*! Defines 'read / write' structure member permissions */ + +/*@} end of group Cortex_M0 */ + + + +/******************************************************************************* + * Register Abstraction + Core Register contain: + - Core Register + - Core NVIC Register + - Core SCB Register + - Core SysTick Register + ******************************************************************************/ +/** + \defgroup CMSIS_core_register Defines and Type Definitions + \brief Type definitions and defines for Cortex-M processor based devices. +*/ + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CORE Status and Control Registers + \brief Core Register type definitions. + @{ + */ + +/** + \brief Union type to access the Application Program Status Register (APSR). + */ +typedef union +{ + struct + { + uint32_t _reserved0:28; /*!< bit: 0..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} APSR_Type; + +/* APSR Register Definitions */ +#define APSR_N_Pos 31U /*!< APSR: N Position */ +#define APSR_N_Msk (1UL << APSR_N_Pos) /*!< APSR: N Mask */ + +#define APSR_Z_Pos 30U /*!< APSR: Z Position */ +#define APSR_Z_Msk (1UL << APSR_Z_Pos) /*!< APSR: Z Mask */ + +#define APSR_C_Pos 29U /*!< APSR: C Position */ +#define APSR_C_Msk (1UL << APSR_C_Pos) /*!< APSR: C Mask */ + +#define APSR_V_Pos 28U /*!< APSR: V Position */ +#define APSR_V_Msk (1UL << APSR_V_Pos) /*!< APSR: V Mask */ + + +/** + \brief Union type to access the Interrupt Program Status Register (IPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:23; /*!< bit: 9..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} IPSR_Type; + +/* IPSR Register Definitions */ +#define IPSR_ISR_Pos 0U /*!< IPSR: ISR Position */ +#define IPSR_ISR_Msk (0x1FFUL /*<< IPSR_ISR_Pos*/) /*!< IPSR: ISR Mask */ + + +/** + \brief Union type to access the Special-Purpose Program Status Registers (xPSR). + */ +typedef union +{ + struct + { + uint32_t ISR:9; /*!< bit: 0.. 8 Exception number */ + uint32_t _reserved0:15; /*!< bit: 9..23 Reserved */ + uint32_t T:1; /*!< bit: 24 Thumb bit (read 0) */ + uint32_t _reserved1:3; /*!< bit: 25..27 Reserved */ + uint32_t V:1; /*!< bit: 28 Overflow condition code flag */ + uint32_t C:1; /*!< bit: 29 Carry condition code flag */ + uint32_t Z:1; /*!< bit: 30 Zero condition code flag */ + uint32_t N:1; /*!< bit: 31 Negative condition code flag */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} xPSR_Type; + +/* xPSR Register Definitions */ +#define xPSR_N_Pos 31U /*!< xPSR: N Position */ +#define xPSR_N_Msk (1UL << xPSR_N_Pos) /*!< xPSR: N Mask */ + +#define xPSR_Z_Pos 30U /*!< xPSR: Z Position */ +#define xPSR_Z_Msk (1UL << xPSR_Z_Pos) /*!< xPSR: Z Mask */ + +#define xPSR_C_Pos 29U /*!< xPSR: C Position */ +#define xPSR_C_Msk (1UL << xPSR_C_Pos) /*!< xPSR: C Mask */ + +#define xPSR_V_Pos 28U /*!< xPSR: V Position */ +#define xPSR_V_Msk (1UL << xPSR_V_Pos) /*!< xPSR: V Mask */ + +#define xPSR_T_Pos 24U /*!< xPSR: T Position */ +#define xPSR_T_Msk (1UL << xPSR_T_Pos) /*!< xPSR: T Mask */ + +#define xPSR_ISR_Pos 0U /*!< xPSR: ISR Position */ +#define xPSR_ISR_Msk (0x1FFUL /*<< xPSR_ISR_Pos*/) /*!< xPSR: ISR Mask */ + + +/** + \brief Union type to access the Control Registers (CONTROL). + */ +typedef union +{ + struct + { + uint32_t _reserved0:1; /*!< bit: 0 Reserved */ + uint32_t SPSEL:1; /*!< bit: 1 Stack to be used */ + uint32_t _reserved1:30; /*!< bit: 2..31 Reserved */ + } b; /*!< Structure used for bit access */ + uint32_t w; /*!< Type used for word access */ +} CONTROL_Type; + +/* CONTROL Register Definitions */ +#define CONTROL_SPSEL_Pos 1U /*!< CONTROL: SPSEL Position */ +#define CONTROL_SPSEL_Msk (1UL << CONTROL_SPSEL_Pos) /*!< CONTROL: SPSEL Mask */ + +/*@} end of group CMSIS_CORE */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_NVIC Nested Vectored Interrupt Controller (NVIC) + \brief Type definitions for the NVIC Registers + @{ + */ + +/** + \brief Structure type to access the Nested Vectored Interrupt Controller (NVIC). + */ +typedef struct +{ + __IOM uint32_t ISER[1U]; /*!< Offset: 0x000 (R/W) Interrupt Set Enable Register */ + uint32_t RESERVED0[31U]; + __IOM uint32_t ICER[1U]; /*!< Offset: 0x080 (R/W) Interrupt Clear Enable Register */ + uint32_t RSERVED1[31U]; + __IOM uint32_t ISPR[1U]; /*!< Offset: 0x100 (R/W) Interrupt Set Pending Register */ + uint32_t RESERVED2[31U]; + __IOM uint32_t ICPR[1U]; /*!< Offset: 0x180 (R/W) Interrupt Clear Pending Register */ + uint32_t RESERVED3[31U]; + uint32_t RESERVED4[64U]; + __IOM uint32_t IP[8U]; /*!< Offset: 0x300 (R/W) Interrupt Priority Register */ +} NVIC_Type; + +/*@} end of group CMSIS_NVIC */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SCB System Control Block (SCB) + \brief Type definitions for the System Control Block Registers + @{ + */ + +/** + \brief Structure type to access the System Control Block (SCB). + */ +typedef struct +{ + __IM uint32_t CPUID; /*!< Offset: 0x000 (R/ ) CPUID Base Register */ + __IOM uint32_t ICSR; /*!< Offset: 0x004 (R/W) Interrupt Control and State Register */ + uint32_t RESERVED0; + __IOM uint32_t AIRCR; /*!< Offset: 0x00C (R/W) Application Interrupt and Reset Control Register */ + __IOM uint32_t SCR; /*!< Offset: 0x010 (R/W) System Control Register */ + __IOM uint32_t CCR; /*!< Offset: 0x014 (R/W) Configuration Control Register */ + uint32_t RESERVED1; + __IOM uint32_t SHP[2U]; /*!< Offset: 0x01C (R/W) System Handlers Priority Registers. [0] is RESERVED */ + __IOM uint32_t SHCSR; /*!< Offset: 0x024 (R/W) System Handler Control and State Register */ +} SCB_Type; + +/* SCB CPUID Register Definitions */ +#define SCB_CPUID_IMPLEMENTER_Pos 24U /*!< SCB CPUID: IMPLEMENTER Position */ +#define SCB_CPUID_IMPLEMENTER_Msk (0xFFUL << SCB_CPUID_IMPLEMENTER_Pos) /*!< SCB CPUID: IMPLEMENTER Mask */ + +#define SCB_CPUID_VARIANT_Pos 20U /*!< SCB CPUID: VARIANT Position */ +#define SCB_CPUID_VARIANT_Msk (0xFUL << SCB_CPUID_VARIANT_Pos) /*!< SCB CPUID: VARIANT Mask */ + +#define SCB_CPUID_ARCHITECTURE_Pos 16U /*!< SCB CPUID: ARCHITECTURE Position */ +#define SCB_CPUID_ARCHITECTURE_Msk (0xFUL << SCB_CPUID_ARCHITECTURE_Pos) /*!< SCB CPUID: ARCHITECTURE Mask */ + +#define SCB_CPUID_PARTNO_Pos 4U /*!< SCB CPUID: PARTNO Position */ +#define SCB_CPUID_PARTNO_Msk (0xFFFUL << SCB_CPUID_PARTNO_Pos) /*!< SCB CPUID: PARTNO Mask */ + +#define SCB_CPUID_REVISION_Pos 0U /*!< SCB CPUID: REVISION Position */ +#define SCB_CPUID_REVISION_Msk (0xFUL /*<< SCB_CPUID_REVISION_Pos*/) /*!< SCB CPUID: REVISION Mask */ + +/* SCB Interrupt Control State Register Definitions */ +#define SCB_ICSR_NMIPENDSET_Pos 31U /*!< SCB ICSR: NMIPENDSET Position */ +#define SCB_ICSR_NMIPENDSET_Msk (1UL << SCB_ICSR_NMIPENDSET_Pos) /*!< SCB ICSR: NMIPENDSET Mask */ + +#define SCB_ICSR_PENDSVSET_Pos 28U /*!< SCB ICSR: PENDSVSET Position */ +#define SCB_ICSR_PENDSVSET_Msk (1UL << SCB_ICSR_PENDSVSET_Pos) /*!< SCB ICSR: PENDSVSET Mask */ + +#define SCB_ICSR_PENDSVCLR_Pos 27U /*!< SCB ICSR: PENDSVCLR Position */ +#define SCB_ICSR_PENDSVCLR_Msk (1UL << SCB_ICSR_PENDSVCLR_Pos) /*!< SCB ICSR: PENDSVCLR Mask */ + +#define SCB_ICSR_PENDSTSET_Pos 26U /*!< SCB ICSR: PENDSTSET Position */ +#define SCB_ICSR_PENDSTSET_Msk (1UL << SCB_ICSR_PENDSTSET_Pos) /*!< SCB ICSR: PENDSTSET Mask */ + +#define SCB_ICSR_PENDSTCLR_Pos 25U /*!< SCB ICSR: PENDSTCLR Position */ +#define SCB_ICSR_PENDSTCLR_Msk (1UL << SCB_ICSR_PENDSTCLR_Pos) /*!< SCB ICSR: PENDSTCLR Mask */ + +#define SCB_ICSR_ISRPREEMPT_Pos 23U /*!< SCB ICSR: ISRPREEMPT Position */ +#define SCB_ICSR_ISRPREEMPT_Msk (1UL << SCB_ICSR_ISRPREEMPT_Pos) /*!< SCB ICSR: ISRPREEMPT Mask */ + +#define SCB_ICSR_ISRPENDING_Pos 22U /*!< SCB ICSR: ISRPENDING Position */ +#define SCB_ICSR_ISRPENDING_Msk (1UL << SCB_ICSR_ISRPENDING_Pos) /*!< SCB ICSR: ISRPENDING Mask */ + +#define SCB_ICSR_VECTPENDING_Pos 12U /*!< SCB ICSR: VECTPENDING Position */ +#define SCB_ICSR_VECTPENDING_Msk (0x1FFUL << SCB_ICSR_VECTPENDING_Pos) /*!< SCB ICSR: VECTPENDING Mask */ + +#define SCB_ICSR_VECTACTIVE_Pos 0U /*!< SCB ICSR: VECTACTIVE Position */ +#define SCB_ICSR_VECTACTIVE_Msk (0x1FFUL /*<< SCB_ICSR_VECTACTIVE_Pos*/) /*!< SCB ICSR: VECTACTIVE Mask */ + +/* SCB Application Interrupt and Reset Control Register Definitions */ +#define SCB_AIRCR_VECTKEY_Pos 16U /*!< SCB AIRCR: VECTKEY Position */ +#define SCB_AIRCR_VECTKEY_Msk (0xFFFFUL << SCB_AIRCR_VECTKEY_Pos) /*!< SCB AIRCR: VECTKEY Mask */ + +#define SCB_AIRCR_VECTKEYSTAT_Pos 16U /*!< SCB AIRCR: VECTKEYSTAT Position */ +#define SCB_AIRCR_VECTKEYSTAT_Msk (0xFFFFUL << SCB_AIRCR_VECTKEYSTAT_Pos) /*!< SCB AIRCR: VECTKEYSTAT Mask */ + +#define SCB_AIRCR_ENDIANESS_Pos 15U /*!< SCB AIRCR: ENDIANESS Position */ +#define SCB_AIRCR_ENDIANESS_Msk (1UL << SCB_AIRCR_ENDIANESS_Pos) /*!< SCB AIRCR: ENDIANESS Mask */ + +#define SCB_AIRCR_SYSRESETREQ_Pos 2U /*!< SCB AIRCR: SYSRESETREQ Position */ +#define SCB_AIRCR_SYSRESETREQ_Msk (1UL << SCB_AIRCR_SYSRESETREQ_Pos) /*!< SCB AIRCR: SYSRESETREQ Mask */ + +#define SCB_AIRCR_VECTCLRACTIVE_Pos 1U /*!< SCB AIRCR: VECTCLRACTIVE Position */ +#define SCB_AIRCR_VECTCLRACTIVE_Msk (1UL << SCB_AIRCR_VECTCLRACTIVE_Pos) /*!< SCB AIRCR: VECTCLRACTIVE Mask */ + +/* SCB System Control Register Definitions */ +#define SCB_SCR_SEVONPEND_Pos 4U /*!< SCB SCR: SEVONPEND Position */ +#define SCB_SCR_SEVONPEND_Msk (1UL << SCB_SCR_SEVONPEND_Pos) /*!< SCB SCR: SEVONPEND Mask */ + +#define SCB_SCR_SLEEPDEEP_Pos 2U /*!< SCB SCR: SLEEPDEEP Position */ +#define SCB_SCR_SLEEPDEEP_Msk (1UL << SCB_SCR_SLEEPDEEP_Pos) /*!< SCB SCR: SLEEPDEEP Mask */ + +#define SCB_SCR_SLEEPONEXIT_Pos 1U /*!< SCB SCR: SLEEPONEXIT Position */ +#define SCB_SCR_SLEEPONEXIT_Msk (1UL << SCB_SCR_SLEEPONEXIT_Pos) /*!< SCB SCR: SLEEPONEXIT Mask */ + +/* SCB Configuration Control Register Definitions */ +#define SCB_CCR_STKALIGN_Pos 9U /*!< SCB CCR: STKALIGN Position */ +#define SCB_CCR_STKALIGN_Msk (1UL << SCB_CCR_STKALIGN_Pos) /*!< SCB CCR: STKALIGN Mask */ + +#define SCB_CCR_UNALIGN_TRP_Pos 3U /*!< SCB CCR: UNALIGN_TRP Position */ +#define SCB_CCR_UNALIGN_TRP_Msk (1UL << SCB_CCR_UNALIGN_TRP_Pos) /*!< SCB CCR: UNALIGN_TRP Mask */ + +/* SCB System Handler Control and State Register Definitions */ +#define SCB_SHCSR_SVCALLPENDED_Pos 15U /*!< SCB SHCSR: SVCALLPENDED Position */ +#define SCB_SHCSR_SVCALLPENDED_Msk (1UL << SCB_SHCSR_SVCALLPENDED_Pos) /*!< SCB SHCSR: SVCALLPENDED Mask */ + +/*@} end of group CMSIS_SCB */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_SysTick System Tick Timer (SysTick) + \brief Type definitions for the System Timer Registers. + @{ + */ + +/** + \brief Structure type to access the System Timer (SysTick). + */ +typedef struct +{ + __IOM uint32_t CTRL; /*!< Offset: 0x000 (R/W) SysTick Control and Status Register */ + __IOM uint32_t LOAD; /*!< Offset: 0x004 (R/W) SysTick Reload Value Register */ + __IOM uint32_t VAL; /*!< Offset: 0x008 (R/W) SysTick Current Value Register */ + __IM uint32_t CALIB; /*!< Offset: 0x00C (R/ ) SysTick Calibration Register */ +} SysTick_Type; + +/* SysTick Control / Status Register Definitions */ +#define SysTick_CTRL_COUNTFLAG_Pos 16U /*!< SysTick CTRL: COUNTFLAG Position */ +#define SysTick_CTRL_COUNTFLAG_Msk (1UL << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */ + +#define SysTick_CTRL_CLKSOURCE_Pos 2U /*!< SysTick CTRL: CLKSOURCE Position */ +#define SysTick_CTRL_CLKSOURCE_Msk (1UL << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */ + +#define SysTick_CTRL_TICKINT_Pos 1U /*!< SysTick CTRL: TICKINT Position */ +#define SysTick_CTRL_TICKINT_Msk (1UL << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */ + +#define SysTick_CTRL_ENABLE_Pos 0U /*!< SysTick CTRL: ENABLE Position */ +#define SysTick_CTRL_ENABLE_Msk (1UL /*<< SysTick_CTRL_ENABLE_Pos*/) /*!< SysTick CTRL: ENABLE Mask */ + +/* SysTick Reload Register Definitions */ +#define SysTick_LOAD_RELOAD_Pos 0U /*!< SysTick LOAD: RELOAD Position */ +#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFUL /*<< SysTick_LOAD_RELOAD_Pos*/) /*!< SysTick LOAD: RELOAD Mask */ + +/* SysTick Current Register Definitions */ +#define SysTick_VAL_CURRENT_Pos 0U /*!< SysTick VAL: CURRENT Position */ +#define SysTick_VAL_CURRENT_Msk (0xFFFFFFUL /*<< SysTick_VAL_CURRENT_Pos*/) /*!< SysTick VAL: CURRENT Mask */ + +/* SysTick Calibration Register Definitions */ +#define SysTick_CALIB_NOREF_Pos 31U /*!< SysTick CALIB: NOREF Position */ +#define SysTick_CALIB_NOREF_Msk (1UL << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */ + +#define SysTick_CALIB_SKEW_Pos 30U /*!< SysTick CALIB: SKEW Position */ +#define SysTick_CALIB_SKEW_Msk (1UL << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */ + +#define SysTick_CALIB_TENMS_Pos 0U /*!< SysTick CALIB: TENMS Position */ +#define SysTick_CALIB_TENMS_Msk (0xFFFFFFUL /*<< SysTick_CALIB_TENMS_Pos*/) /*!< SysTick CALIB: TENMS Mask */ + +/*@} end of group CMSIS_SysTick */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_CoreDebug Core Debug Registers (CoreDebug) + \brief Cortex-M0 Core Debug Registers (DCB registers, SHCSR, and DFSR) are only accessible over DAP and not via processor. + Therefore they are not covered by the Cortex-M0 header file. + @{ + */ +/*@} end of group CMSIS_CoreDebug */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_bitfield Core register bit field macros + \brief Macros for use with bit field definitions (xxx_Pos, xxx_Msk). + @{ + */ + +/** + \brief Mask and shift a bit field value for use in a register bit range. + \param[in] field Name of the register bit field. + \param[in] value Value of the bit field. + \return Masked and shifted value. +*/ +#define _VAL2FLD(field, value) ((value << field ## _Pos) & field ## _Msk) + +/** + \brief Mask and shift a register value to extract a bit filed value. + \param[in] field Name of the register bit field. + \param[in] value Value of register. + \return Masked and shifted bit field value. +*/ +#define _FLD2VAL(field, value) ((value & field ## _Msk) >> field ## _Pos) + +/*@} end of group CMSIS_core_bitfield */ + + +/** + \ingroup CMSIS_core_register + \defgroup CMSIS_core_base Core Definitions + \brief Definitions for base addresses, unions, and structures. + @{ + */ + +/* Memory mapping of Cortex-M0 Hardware */ +#define SCS_BASE (0xE000E000UL) /*!< System Control Space Base Address */ +#define SysTick_BASE (SCS_BASE + 0x0010UL) /*!< SysTick Base Address */ +#define NVIC_BASE (SCS_BASE + 0x0100UL) /*!< NVIC Base Address */ +#define SCB_BASE (SCS_BASE + 0x0D00UL) /*!< System Control Block Base Address */ + +#define SCB ((SCB_Type *) SCB_BASE ) /*!< SCB configuration struct */ +#define SysTick ((SysTick_Type *) SysTick_BASE ) /*!< SysTick configuration struct */ +#define NVIC ((NVIC_Type *) NVIC_BASE ) /*!< NVIC configuration struct */ + + +/*@} */ + + + +/******************************************************************************* + * Hardware Abstraction Layer + Core Function Interface contains: + - Core NVIC Functions + - Core SysTick Functions + - Core Register Access Functions + ******************************************************************************/ +/** + \defgroup CMSIS_Core_FunctionInterface Functions and Instructions Reference +*/ + + + +/* ########################## NVIC functions #################################### */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_NVICFunctions NVIC Functions + \brief Functions that manage interrupts and exceptions via the NVIC. + @{ + */ + +/* Interrupt Priorities are WORD accessible only under ARMv6M */ +/* The following MACROS handle generation of the register offset and byte masks */ +#define _BIT_SHIFT(IRQn) ( ((((uint32_t)(int32_t)(IRQn)) ) & 0x03UL) * 8UL) +#define _SHP_IDX(IRQn) ( (((((uint32_t)(int32_t)(IRQn)) & 0x0FUL)-8UL) >> 2UL) ) +#define _IP_IDX(IRQn) ( (((uint32_t)(int32_t)(IRQn)) >> 2UL) ) + + +/** + \brief Enable External Interrupt + \details Enables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_EnableIRQ(IRQn_Type IRQn) +{ + NVIC->ISER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Disable External Interrupt + \details Disables a device-specific interrupt in the NVIC interrupt controller. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_DisableIRQ(IRQn_Type IRQn) +{ + NVIC->ICER[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Get Pending Interrupt + \details Reads the pending register in the NVIC and returns the pending bit for the specified interrupt. + \param [in] IRQn Interrupt number. + \return 0 Interrupt status is not pending. + \return 1 Interrupt status is pending. + */ +__STATIC_INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) +{ + return((uint32_t)(((NVIC->ISPR[0U] & (1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL))) != 0UL) ? 1UL : 0UL)); +} + + +/** + \brief Set Pending Interrupt + \details Sets the pending bit of an external interrupt. + \param [in] IRQn Interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ISPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Clear Pending Interrupt + \details Clears the pending bit of an external interrupt. + \param [in] IRQn External interrupt number. Value cannot be negative. + */ +__STATIC_INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn) +{ + NVIC->ICPR[0U] = (uint32_t)(1UL << (((uint32_t)(int32_t)IRQn) & 0x1FUL)); +} + + +/** + \brief Set Interrupt Priority + \details Sets the priority of an interrupt. + \note The priority cannot be set for every core interrupt. + \param [in] IRQn Interrupt number. + \param [in] priority Priority to set. + */ +__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) +{ + if ((int32_t)(IRQn) < 0) + { + SCB->SHP[_SHP_IDX(IRQn)] = ((uint32_t)(SCB->SHP[_SHP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } + else + { + NVIC->IP[_IP_IDX(IRQn)] = ((uint32_t)(NVIC->IP[_IP_IDX(IRQn)] & ~(0xFFUL << _BIT_SHIFT(IRQn))) | + (((priority << (8U - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL) << _BIT_SHIFT(IRQn))); + } +} + + +/** + \brief Get Interrupt Priority + \details Reads the priority of an interrupt. + The interrupt number can be positive to specify an external (device specific) interrupt, + or negative to specify an internal (core) interrupt. + \param [in] IRQn Interrupt number. + \return Interrupt Priority. + Value is aligned automatically to the implemented priority bits of the microcontroller. + */ +__STATIC_INLINE uint32_t NVIC_GetPriority(IRQn_Type IRQn) +{ + + if ((int32_t)(IRQn) < 0) + { + return((uint32_t)(((SCB->SHP[_SHP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } + else + { + return((uint32_t)(((NVIC->IP[ _IP_IDX(IRQn)] >> _BIT_SHIFT(IRQn) ) & (uint32_t)0xFFUL) >> (8U - __NVIC_PRIO_BITS))); + } +} + + +/** + \brief System Reset + \details Initiates a system reset request to reset the MCU. + */ +__STATIC_INLINE void NVIC_SystemReset(void) +{ + __DSB(); /* Ensure all outstanding memory accesses included + buffered write are completed before reset */ + SCB->AIRCR = ((0x5FAUL << SCB_AIRCR_VECTKEY_Pos) | + SCB_AIRCR_SYSRESETREQ_Msk); + __DSB(); /* Ensure completion of memory access */ + + for(;;) /* wait until reset */ + { + __NOP(); + } +} + +/*@} end of CMSIS_Core_NVICFunctions */ + + + +/* ################################## SysTick function ############################################ */ +/** + \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_SysTickFunctions SysTick Functions + \brief Functions that configure the System. + @{ + */ + +#if (__Vendor_SysTickConfig == 0U) + +/** + \brief System Tick Configuration + \details Initializes the System Timer and its interrupt, and starts the System Tick Timer. + Counter is in free running mode to generate periodic interrupts. + \param [in] ticks Number of ticks between two interrupts. + \return 0 Function succeeded. + \return 1 Function failed. + \note When the variable __Vendor_SysTickConfig is set to 1, then the + function SysTick_Config is not included. In this case, the file device.h + must contain a vendor-specific implementation of this function. + */ +__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) +{ + if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) + { + return (1UL); /* Reload value impossible */ + } + + SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */ + NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */ + SysTick->VAL = 0UL; /* Load the SysTick Counter Value */ + SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | + SysTick_CTRL_TICKINT_Msk | + SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */ + return (0UL); /* Function successful */ +} + +#endif + +/*@} end of CMSIS_Core_SysTickFunctions */ + + + + +#ifdef __cplusplus +} +#endif + +#endif /* __CORE_CM0_H_DEPENDANT */ + +#endif /* __CMSIS_GENERIC */ diff --git a/firmware/include_stm/core_cmFunc.h b/firmware/include_stm/core_cmFunc.h new file mode 100644 index 0000000..652a48a --- /dev/null +++ b/firmware/include_stm/core_cmFunc.h @@ -0,0 +1,87 @@ +/**************************************************************************//** + * @file core_cmFunc.h + * @brief CMSIS Cortex-M Core Function Access Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CMFUNC_H +#define __CORE_CMFUNC_H + + +/* ########################### Core Function Access ########################### */ +/** \ingroup CMSIS_Core_FunctionInterface + \defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions + @{ +*/ + +/*------------------ RealView Compiler -----------------*/ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + +/*------------------ ARM Compiler V6 -------------------*/ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #include "cmsis_armcc_V6.h" + +/*------------------ GNU Compiler ----------------------*/ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + +/*------------------ ICC Compiler ----------------------*/ +#elif defined ( __ICCARM__ ) + #include + +/*------------------ TI CCS Compiler -------------------*/ +#elif defined ( __TMS470__ ) + #include + +/*------------------ TASKING Compiler ------------------*/ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + +/*------------------ COSMIC Compiler -------------------*/ +#elif defined ( __CSMC__ ) + #include + +#endif + +/*@} end of CMSIS_Core_RegAccFunctions */ + +#endif /* __CORE_CMFUNC_H */ diff --git a/firmware/include_stm/core_cmInstr.h b/firmware/include_stm/core_cmInstr.h new file mode 100644 index 0000000..f474b0e --- /dev/null +++ b/firmware/include_stm/core_cmInstr.h @@ -0,0 +1,87 @@ +/**************************************************************************//** + * @file core_cmInstr.h + * @brief CMSIS Cortex-M Core Instruction Access Header File + * @version V4.30 + * @date 20. October 2015 + ******************************************************************************/ +/* Copyright (c) 2009 - 2015 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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. + ---------------------------------------------------------------------------*/ + + +#if defined ( __ICCARM__ ) + #pragma system_include /* treat file as system include file for MISRA check */ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #pragma clang system_header /* treat file as system include file */ +#endif + +#ifndef __CORE_CMINSTR_H +#define __CORE_CMINSTR_H + + +/* ########################## Core Instruction Access ######################### */ +/** \defgroup CMSIS_Core_InstructionInterface CMSIS Core Instruction Interface + Access to dedicated instructions + @{ +*/ + +/*------------------ RealView Compiler -----------------*/ +#if defined ( __CC_ARM ) + #include "cmsis_armcc.h" + +/*------------------ ARM Compiler V6 -------------------*/ +#elif defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) + #include "cmsis_armcc_V6.h" + +/*------------------ GNU Compiler ----------------------*/ +#elif defined ( __GNUC__ ) + #include "cmsis_gcc.h" + +/*------------------ ICC Compiler ----------------------*/ +#elif defined ( __ICCARM__ ) + #include + +/*------------------ TI CCS Compiler -------------------*/ +#elif defined ( __TMS470__ ) + #include + +/*------------------ TASKING Compiler ------------------*/ +#elif defined ( __TASKING__ ) + /* + * The CMSIS functions have been implemented as intrinsics in the compiler. + * Please use "carm -?i" to get an up to date list of all intrinsics, + * Including the CMSIS ones. + */ + +/*------------------ COSMIC Compiler -------------------*/ +#elif defined ( __CSMC__ ) + #include + +#endif + +/*@}*/ /* end of group CMSIS_Core_InstructionInterface */ + +#endif /* __CORE_CMINSTR_H */ diff --git a/firmware/include_stm/nokeep.ld b/firmware/include_stm/nokeep.ld new file mode 100644 index 0000000..62d2edd --- /dev/null +++ b/firmware/include_stm/nokeep.ld @@ -0,0 +1,212 @@ +/* Linker script to configure memory regions. + * Need modifying for a specific board. + * FLASH.ORIGIN: starting address of flash + * FLASH.LENGTH: length of flash + * RAM.ORIGIN: starting address of RAM bank 0 + * RAM.LENGTH: length of RAM bank 0 + */ +MEMORY +{ + /* STM32F07x */ + /* $0000 0000 128KB of flash/sram depending on BOOT */ + /* $0002 0000 ~128MB of system reserved */ + /* $0800 0000 always flash size depends on part */ +/* FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 128K */ /* 0x20000 128K */ + FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 32K /* 0x20000 128K */ + /* $0802 0000 ~384MB of system reserved */ + /* $1FFF C800 12KB of system memory (bootloader and etc) */ + /* $1FFF F800 2KB of option bytes */ + /* $2000 0000 always SRAM size depends on part */ +/* RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 16K */ /* 0x04000 16K */ + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 6K /* 0x04000 16K */ + /* $2000 4000 ~512MB of system reserved */ + /* $4000 0000 128KB of APB perif regs & reserved */ + /* $4002 0000 17KB of AHB1 perif regs & reserved */ + /* $4002 4400 ~128MB system reserved */ + /* $4800 0000 6KB AHB2 GPIO perif refs */ + /* $4800 1800 ~384MB system reserved */ + /* $E000 0000 1MB Cortex M0 internal peripherals */ + /* $E010 0000 511MB system reserved */ +} + +/* Linker script to place sections and symbol values. Should be used together + * with other linker script that defines memory regions FLASH and RAM. + * It references following symbols, which must be defined in code: + * Reset_Handler : Entry of reset handler + * + * It defines following symbols, which code can use without definition: + * __exidx_start + * __exidx_end + * __copy_table_start__ + * __copy_table_end__ + * __zero_table_start__ + * __zero_table_end__ + * __etext + * __data_start__ + * __preinit_array_start + * __preinit_array_end + * __init_array_start + * __init_array_end + * __fini_array_start + * __fini_array_end + * __data_end__ + * __bss_start__ + * __bss_end__ + * __end__ + * end + * __HeapLimit + * __StackLimit + * __StackTop + * __stack + */ +ENTRY(Reset_Handler) + +SECTIONS +{ + .text : + { + KEEP(*(.isr_vector)) + *(.text*) + + *(.init) + *(.fini) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + + *(.eh_frame*) + } > FLASH + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH + __exidx_end = .; + + /* To copy multiple ROM to RAM sections, + * uncomment .copy.table section and, + * define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */ + /* + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + LONG (__etext) + LONG (__data_start__) + LONG (__data_end__ - __data_start__) + LONG (__etext2) + LONG (__data2_start__) + LONG (__data2_end__ - __data2_start__) + __copy_table_end__ = .; + } > FLASH + */ + + /* To clear multiple BSS sections, + * uncomment .zero.table section and, + * define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */ + /* + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + LONG (__bss_start__) + LONG (__bss_end__ - __bss_start__) + LONG (__bss2_start__) + LONG (__bss2_end__ - __bss2_start__) + __zero_table_end__ = .; + } > FLASH + */ + + /* Location counter can end up 2byte aligned with narrow Thumb code but + __etext is assumed by startup code to be the LMA of a section in RAM + which must be 4byte aligned */ + __etext = ALIGN (4); + + .data : AT (__etext) + { + __data_start__ = .; + *(vtable) + *(.data*) + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + *(.preinit_array) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + *(SORT(.init_array.*)) + *(.init_array) + PROVIDE_HIDDEN (__init_array_end = .); + + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + *(SORT(.fini_array.*)) + *(.fini_array) + PROVIDE_HIDDEN (__fini_array_end = .); + + *(.jcr) + . = ALIGN(4); + /* All data end */ + __data_end__ = .; + + } > RAM + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(.bss*) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM + + .heap (COPY): + { + __end__ = .; + PROVIDE(end = .); + *(.heap*) + __HeapLimit = .; + } > RAM + + /* .stack_dummy section doesn't contains any symbols. It is only + * used for linker to calculate size of stack sections, and assign + * values to stack symbols later */ + .stack_dummy (COPY): + { + *(.stack*) + } > RAM + + /* Set stack top to end of RAM, and stack limit move down by + * size of stack_dummy section */ + __StackTop = ORIGIN(RAM) + LENGTH(RAM); + __StackLimit = __StackTop - SIZEOF(.stack_dummy); + PROVIDE(__stack = __StackTop); + + /* Check if data + heap + stack exceeds RAM limit */ + ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack") +} diff --git a/firmware/include_stm/startup_ARMCM0.S b/firmware/include_stm/startup_ARMCM0.S new file mode 100644 index 0000000..1209efe --- /dev/null +++ b/firmware/include_stm/startup_ARMCM0.S @@ -0,0 +1,326 @@ +/* File: startup_ARMCM0.S + * Purpose: startup file for Cortex-M0 devices. Should use with + * GCC for ARM Embedded Processors + * Version: V2.0 + * Date: 16 August 2013 + * +/* Copyright (c) 2011 - 2013 ARM LIMITED + + All rights reserved. + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + - 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. + - Neither the name of ARM 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 COPYRIGHT HOLDERS AND 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 + .arch armv6-m + + .section .stack + .align 3 +#ifdef __STACK_SIZE + .equ Stack_Size, __STACK_SIZE +#else + .equ Stack_Size, 0xc00 +#endif + .globl __StackTop + .globl __StackLimit +__StackLimit: + .space Stack_Size + .size __StackLimit, . - __StackLimit +__StackTop: + .size __StackTop, . - __StackTop + + .section .heap + .align 3 +#ifdef __HEAP_SIZE + .equ Heap_Size, __HEAP_SIZE +#else + .equ Heap_Size, 0 +#endif + .globl __HeapBase + .globl __HeapLimit +__HeapBase: + .if Heap_Size + .space Heap_Size + .endif + .size __HeapBase, . - __HeapBase +__HeapLimit: + .size __HeapLimit, . - __HeapLimit + + .section .isr_vector + .align 2 + .globl __isr_vector +__isr_vector: + .long __StackTop /* Top of Stack */ + .long Reset_Handler /* Reset Handler */ + .long NMI_Handler /* NMI Handler */ + .long HardFault_Handler /* Hard Fault Handler */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long SVC_Handler /* SVCall Handler */ + .long 0 /* Reserved */ + .long 0 /* Reserved */ + .long PendSV_Handler /* PendSV Handler */ + .long SysTick_Handler /* SysTick Handler */ + + /* External interrupts */ + .long WWDG_IRQHandler /* Window Watchdog */ + .long PVD_VDDIO2_IRQHandler /* PVD through EXTI Line detect */ + .long RTC_IRQHand /* RTC through EXTI Line */ + .long FLASH_IRQHandler /* FLASH */ + .long RCC_CRS_IRQHandler /* RCC and CRS */ + .long EXTI0_1_IRQHandler /* EXTI Line 0 and 1 */ + .long EXTI2_3_IRQHandler /* EXTI Line 2 and 3 */ + .long EXTI4_15_IRQHandler /* EXTI Line 4 to 15 */ + .long TSC_IRQHandler /* TS */ + .long DMA1_Channel1_IRQHandler /* DMA1 Channel 1 */ + .long DMA1_Channel2_3_IRQHandler /* DMA1 Channel 2 and Channel 3 */ + .long DMA1_Channel4_5_6_7_IRQHandler /* DMA1 Channel 4, Channel 5, Channel 6 and Channel 7 */ + .long ADC1_COMP_IRQHandler /* ADC1, COMP1 and COMP2 */ + .long TIM1_BRK_UP_TRG_COM_IRQHandler /* TIM1 Break, Update, Trigger and Commutation */ + .long TIM1_CC_IRQHandler /* TIM1 Capture Compare */ + .long TIM2_IRQHandler /* TIM2 */ + .long TIM3_IRQHandler /* TIM3 */ + .long TIM6_DAC_IRQHandler /* TIM6 and DAC */ + .long TIM7_IRQHandler /* TIM7 */ + .long TIM14_IRQHandler /* TIM14 */ + .long TIM15_IRQHandler /* TIM15 */ + .long TIM16_IRQHandler /* TIM16 */ + .long TIM17_IRQHandler /* TIM17 */ + .long I2C1_IRQHandler /* I2C1 */ + .long I2C2_IRQHandler /* I2C2 */ + .long SPI1_IRQHandler /* SPI1 */ + .long SPI2_IRQHandler /* SPI2 */ + .long USART1_IRQHandler /* USART1 */ + .long USART2_IRQHandler /* USART2 */ + .long USART3_4_IRQHandler /* USART3 & USART4 */ + .long CEC_CAN_IRQHandler /* CEC and CAN */ + .long USB_IRQHandler /* USB */ + + .size __isr_vector, . - __isr_vector + + .text + .thumb + .thumb_func + .align 1 + .globl Reset_Handler + .type Reset_Handler, %function +Reset_Handler: +/* Firstly it copies data from read only memory to RAM. There are two schemes + * to copy. One can copy more than one sections. Another can only copy + * one section. The former scheme needs more instructions and read-only + * data to implement than the latter. + * Macro __STARTUP_COPY_MULTIPLE is used to choose between two schemes. */ + +#ifdef __STARTUP_COPY_MULTIPLE +/* Multiple sections scheme. + * + * Between symbol address __copy_table_start__ and __copy_table_end__, + * there are array of triplets, each of which specify: + * offset 0: LMA of start of a section to copy from + * offset 4: VMA of start of a section to copy to + * offset 8: size of the section to copy. Must be multiply of 4 + * + * All addresses must be aligned to 4 bytes boundary. + */ + ldr r4, =__copy_table_start__ + ldr r5, =__copy_table_end__ + +.L_loop0: + cmp r4, r5 + bge .L_loop0_done + ldr r1, [r4] + ldr r2, [r4, #4] + ldr r3, [r4, #8] + +.L_loop0_0: + subs r3, #4 + blt .L_loop0_0_done + ldr r0, [r1, r3] + str r0, [r2, r3] + b .L_loop0_0 + +.L_loop0_0_done: + adds r4, #12 + b .L_loop0 + +.L_loop0_done: +#else +/* Single section scheme. + * + * The ranges of copy from/to are specified by following symbols + * __etext: LMA of start of the section to copy from. Usually end of text + * __data_start__: VMA of start of the section to copy to + * __data_end__: VMA of end of the section to copy to + * + * All addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =__etext + ldr r2, =__data_start__ + ldr r3, =__data_end__ + + subs r3, r2 + ble .L_loop1_done + +.L_loop1: + subs r3, #4 + ldr r0, [r1,r3] + str r0, [r2,r3] + bgt .L_loop1 + +.L_loop1_done: +#endif /*__STARTUP_COPY_MULTIPLE */ + +/* This part of work usually is done in C library startup code. Otherwise, + * define this macro to enable it in this startup. + * + * There are two schemes too. One can clear multiple BSS sections. Another + * can only clear one section. The former is more size expensive than the + * latter. + * + * Define macro __STARTUP_CLEAR_BSS_MULTIPLE to choose the former. + * Otherwise efine macro __STARTUP_CLEAR_BSS to choose the later. + */ +#ifdef __STARTUP_CLEAR_BSS_MULTIPLE +/* Multiple sections scheme. + * + * Between symbol address __copy_table_start__ and __copy_table_end__, + * there are array of tuples specifying: + * offset 0: Start of a BSS section + * offset 4: Size of this BSS section. Must be multiply of 4 + */ + ldr r3, =__zero_table_start__ + ldr r4, =__zero_table_end__ + +.L_loop2: + cmp r3, r4 + bge .L_loop2_done + ldr r1, [r3] + ldr r2, [r3, #4] + movs r0, 0 + +.L_loop2_0: + subs r2, #4 + blt .L_loop2_0_done + str r0, [r1, r2] + b .L_loop2_0 +.L_loop2_0_done: + + adds r3, #8 + b .L_loop2 +.L_loop2_done: +#elif defined (__STARTUP_CLEAR_BSS) +/* Single BSS section scheme. + * + * The BSS section is specified by following symbols + * __bss_start__: start of the BSS section. + * __bss_end__: end of the BSS section. + * + * Both addresses must be aligned to 4 bytes boundary. + */ + ldr r1, =__bss_start__ + ldr r2, =__bss_end__ + + movs r0, 0 + + subs r2, r1 + ble .L_loop3_done + +.L_loop3: + subs r2, #4 + str r0, [r1, r2] + bgt .L_loop3 +.L_loop3_done: +#endif /* __STARTUP_CLEAR_BSS_MULTIPLE || __STARTUP_CLEAR_BSS */ + +#ifndef __NO_SYSTEM_INIT + bl SystemInit +#endif + +#ifndef __START +#define __START _start +#endif + bl __START + + .pool + .size Reset_Handler, . - Reset_Handler + + .align 1 + .thumb_func + .weak Default_Handler + .type Default_Handler, %function +Default_Handler: + b . + .size Default_Handler, . - Default_Handler + +/* Macro to define default handlers. Default handler + * will be weak symbol and just dead loops. They can be + * overwritten by other handlers */ + .macro def_irq_handler handler_name + .weak \handler_name + .set \handler_name, Default_Handler + .endm + + def_irq_handler NMI_Handler + def_irq_handler HardFault_Handler + def_irq_handler SVC_Handler + def_irq_handler PendSV_Handler + def_irq_handler SysTick_Handler + def_irq_handler DEF_IRQHandler + def_irq_handler WWDG_IRQHandler + def_irq_handler PVD_VDDIO2_IRQHandler + def_irq_handler RTC_IRQHand + def_irq_handler FLASH_IRQHandler + def_irq_handler RCC_CRS_IRQHandler + def_irq_handler EXTI0_1_IRQHandler + def_irq_handler EXTI2_3_IRQHandler + def_irq_handler EXTI4_15_IRQHandler + def_irq_handler TSC_IRQHandler + def_irq_handler DMA1_Channel1_IRQHandler + def_irq_handler DMA1_Channel2_3_IRQHandler + def_irq_handler DMA1_Channel4_5_6_7_IRQHandler + def_irq_handler ADC1_COMP_IRQHandler + def_irq_handler TIM1_BRK_UP_TRG_COM_IRQHandler + def_irq_handler TIM1_CC_IRQHandler + def_irq_handler TIM2_IRQHandler + def_irq_handler TIM3_IRQHandler + def_irq_handler TIM6_DAC_IRQHandler + def_irq_handler TIM7_IRQHandler + def_irq_handler TIM14_IRQHandler + def_irq_handler TIM15_IRQHandler + def_irq_handler TIM16_IRQHandler + def_irq_handler TIM17_IRQHandler + def_irq_handler I2C1_IRQHandler + def_irq_handler I2C2_IRQHandler + def_irq_handler SPI1_IRQHandler + def_irq_handler SPI2_IRQHandler + def_irq_handler USART1_IRQHandler + def_irq_handler USART2_IRQHandler + def_irq_handler USART3_4_IRQHandler + def_irq_handler CEC_CAN_IRQHandler + def_irq_handler USB_IRQHandler + + .end diff --git a/firmware/include_stm/stm32f070x6.h b/firmware/include_stm/stm32f070x6.h new file mode 100644 index 0000000..9e4e958 --- /dev/null +++ b/firmware/include_stm/stm32f070x6.h @@ -0,0 +1,5576 @@ +/** + ****************************************************************************** + * @file stm32f070x6.h + * @author MCD Application Team + * @version V2.3.1 + * @date 04-November-2016 + * @brief CMSIS Cortex-M0 Device Peripheral Access Layer Header File. + * This file contains all the peripheral register's definitions, bits + * definitions and memory mapping for STM32F0xx devices. + * + * This file contains: + * - Data structures and the address mapping for all peripherals + * - Peripheral's registers declarations and bits definition + * - Macros to access peripheral’s registers hardware + * + ****************************************************************************** + * @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 stm32f070x6 + * @{ + */ + +#ifndef __STM32F070x6_H +#define __STM32F070x6_H + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + /** @addtogroup Configuration_section_for_CMSIS + * @{ + */ +/** + * @brief Configuration of the Cortex-M0 Processor and Core Peripherals + */ +#define __CM0_REV 0 /*!< Core Revision r0p0 */ +#define __MPU_PRESENT 0 /*!< STM32F0xx do not provide MPU */ +#define __NVIC_PRIO_BITS 2 /*!< STM32F0xx uses 2 Bits for the Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + +/** + * @} + */ + +/** @addtogroup Peripheral_interrupt_number_definition + * @{ + */ + +/** + * @brief STM32F0xx Interrupt Number Definition, according to the selected device + * in @ref Library_configuration_section + */ + + /*!< Interrupt Number Definition */ +typedef enum +{ +/****** Cortex-M0 Processor Exceptions Numbers **************************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13, /*!< 3 Cortex-M0 Hard Fault Interrupt */ + SVC_IRQn = -5, /*!< 11 Cortex-M0 SV Call Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M0 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M0 System Tick Interrupt */ + +/****** STM32F0 specific Interrupt Numbers ******************************************************************/ + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + RTC_IRQn = 2, /*!< RTC Interrupt through EXTI Lines 17, 19 and 20 */ + FLASH_IRQn = 3, /*!< FLASH global Interrupt */ + RCC_IRQn = 4, /*!< RCC global Interrupt */ + EXTI0_1_IRQn = 5, /*!< EXTI Line 0 and 1 Interrupt */ + EXTI2_3_IRQn = 6, /*!< EXTI Line 2 and 3 Interrupt */ + EXTI4_15_IRQn = 7, /*!< EXTI Line 4 to 15 Interrupt */ + DMA1_Channel1_IRQn = 9, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_3_IRQn = 10, /*!< DMA1 Channel 2 and Channel 3 Interrupt */ + DMA1_Channel4_5_IRQn = 11, /*!< DMA1 Channel 4 and Channel 5 Interrupt */ + ADC1_IRQn = 12, /*!< ADC1 Interrupt */ + TIM1_BRK_UP_TRG_COM_IRQn = 13, /*!< TIM1 Break, Update, Trigger and Commutation Interrupt */ + TIM1_CC_IRQn = 14, /*!< TIM1 Capture Compare Interrupt */ + TIM3_IRQn = 16, /*!< TIM3 global Interrupt */ + TIM14_IRQn = 19, /*!< TIM14 global Interrupt */ + TIM16_IRQn = 21, /*!< TIM16 global Interrupt */ + TIM17_IRQn = 22, /*!< TIM17 global Interrupt */ + I2C1_IRQn = 23, /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */ + SPI1_IRQn = 25, /*!< SPI1 global Interrupt */ + USART1_IRQn = 27, /*!< USART1 global Interrupt & EXTI Line25 Interrupt (USART1 wakeup) */ + USART2_IRQn = 28, /*!< USART2 global Interrupt */ + USB_IRQn = 31 /*!< USB global Interrupt & EXTI Line18 Interrupt */ +} IRQn_Type; + +/** + * @} + */ + +#include "core_cm0.h" /* Cortex-M0 processor and core peripherals */ +#include "system_stm32f0xx.h" /* STM32F0xx System Header */ +#include + +/** @addtogroup Peripheral_registers_structures + * @{ + */ + +/** + * @brief Analog to Digital Converter + */ + +typedef struct +{ + __IO uint32_t ISR; /*!< ADC interrupt and status register, Address offset: 0x00 */ + __IO uint32_t IER; /*!< ADC interrupt enable register, Address offset: 0x04 */ + __IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */ + __IO uint32_t CFGR1; /*!< ADC configuration register 1, Address offset: 0x0C */ + __IO uint32_t CFGR2; /*!< ADC configuration register 2, Address offset: 0x10 */ + __IO uint32_t SMPR; /*!< ADC sampling time register, Address offset: 0x14 */ + uint32_t RESERVED1; /*!< Reserved, 0x18 */ + uint32_t RESERVED2; /*!< Reserved, 0x1C */ + __IO uint32_t TR; /*!< ADC analog watchdog 1 threshold register, Address offset: 0x20 */ + uint32_t RESERVED3; /*!< Reserved, 0x24 */ + __IO uint32_t CHSELR; /*!< ADC group regular sequencer register, Address offset: 0x28 */ + uint32_t RESERVED4[5]; /*!< Reserved, 0x2C */ + __IO uint32_t DR; /*!< ADC group regular data register, Address offset: 0x40 */ +} ADC_TypeDef; + +typedef struct +{ + __IO uint32_t CCR; /*!< ADC common configuration register, Address offset: ADC1 base address + 0x308 */ +} ADC_Common_TypeDef; + +/** + * @brief CRC calculation unit + */ + +typedef struct +{ + __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ + __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ + uint8_t RESERVED0; /*!< Reserved, 0x05 */ + uint16_t RESERVED1; /*!< Reserved, 0x06 */ + __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ + uint32_t RESERVED2; /*!< Reserved, 0x0C */ + __IO uint32_t INIT; /*!< Initial CRC value register, Address offset: 0x10 */ + __IO uint32_t RESERVED3; /*!< Reserved, 0x14 */ +} CRC_TypeDef; + +/** + * @brief Debug MCU + */ + +typedef struct +{ + __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ + __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ + __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */ + __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */ +}DBGMCU_TypeDef; + +/** + * @brief DMA Controller + */ + +typedef struct +{ + __IO uint32_t CCR; /*!< DMA channel x configuration register */ + __IO uint32_t CNDTR; /*!< DMA channel x number of data register */ + __IO uint32_t CPAR; /*!< DMA channel x peripheral address register */ + __IO uint32_t CMAR; /*!< DMA channel x memory address register */ +} DMA_Channel_TypeDef; + +typedef struct +{ + __IO uint32_t ISR; /*!< DMA interrupt status register, Address offset: 0x00 */ + __IO uint32_t IFCR; /*!< DMA interrupt flag clear register, Address offset: 0x04 */ +} DMA_TypeDef; + +/** + * @brief External Interrupt/Event Controller + */ + +typedef struct +{ + __IO uint32_t IMR; /*!
© 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 stm32f070xb + * @{ + */ + +#ifndef __STM32F070xB_H +#define __STM32F070xB_H + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + + /** @addtogroup Configuration_section_for_CMSIS + * @{ + */ +/** + * @brief Configuration of the Cortex-M0 Processor and Core Peripherals + */ +#define __CM0_REV 0 /*!< Core Revision r0p0 */ +#define __MPU_PRESENT 0 /*!< STM32F0xx do not provide MPU */ +#define __NVIC_PRIO_BITS 2 /*!< STM32F0xx uses 2 Bits for the Priority Levels */ +#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */ + +/** + * @} + */ + +/** @addtogroup Peripheral_interrupt_number_definition + * @{ + */ + +/** + * @brief STM32F0xx Interrupt Number Definition, according to the selected device + * in @ref Library_configuration_section + */ + + /*!< Interrupt Number Definition */ +typedef enum +{ +/****** Cortex-M0 Processor Exceptions Numbers **************************************************************/ + NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */ + HardFault_IRQn = -13, /*!< 3 Cortex-M0 Hard Fault Interrupt */ + SVC_IRQn = -5, /*!< 11 Cortex-M0 SV Call Interrupt */ + PendSV_IRQn = -2, /*!< 14 Cortex-M0 Pend SV Interrupt */ + SysTick_IRQn = -1, /*!< 15 Cortex-M0 System Tick Interrupt */ + +/****** STM32F0 specific Interrupt Numbers ******************************************************************/ + WWDG_IRQn = 0, /*!< Window WatchDog Interrupt */ + RTC_IRQn = 2, /*!< RTC Interrupt through EXTI Lines 17, 19 and 20 */ + FLASH_IRQn = 3, /*!< FLASH global Interrupt */ + RCC_IRQn = 4, /*!< RCC global Interrupt */ + EXTI0_1_IRQn = 5, /*!< EXTI Line 0 and 1 Interrupt */ + EXTI2_3_IRQn = 6, /*!< EXTI Line 2 and 3 Interrupt */ + EXTI4_15_IRQn = 7, /*!< EXTI Line 4 to 15 Interrupt */ + DMA1_Channel1_IRQn = 9, /*!< DMA1 Channel 1 Interrupt */ + DMA1_Channel2_3_IRQn = 10, /*!< DMA1 Channel 2 and Channel 3 Interrupt */ + DMA1_Channel4_5_IRQn = 11, /*!< DMA1 Channel 4 and Channel 5 Interrupt */ + ADC1_IRQn = 12, /*!< ADC1 Interrupt */ + TIM1_BRK_UP_TRG_COM_IRQn = 13, /*!< TIM1 Break, Update, Trigger and Commutation Interrupt */ + TIM1_CC_IRQn = 14, /*!< TIM1 Capture Compare Interrupt */ + TIM3_IRQn = 16, /*!< TIM3 global Interrupt */ + TIM6_IRQn = 17, /*!< TIM6 global Interrupt */ + TIM7_IRQn = 18, /*!< TIM7 global Interrupt */ + TIM14_IRQn = 19, /*!< TIM14 global Interrupt */ + TIM15_IRQn = 20, /*!< TIM15 global Interrupt */ + TIM16_IRQn = 21, /*!< TIM16 global Interrupt */ + TIM17_IRQn = 22, /*!< TIM17 global Interrupt */ + I2C1_IRQn = 23, /*!< I2C1 Event Interrupt & EXTI Line23 Interrupt (I2C1 wakeup) */ + I2C2_IRQn = 24, /*!< I2C2 Event Interrupt */ + SPI1_IRQn = 25, /*!< SPI1 global Interrupt */ + SPI2_IRQn = 26, /*!< SPI2 global Interrupt */ + USART1_IRQn = 27, /*!< USART1 global Interrupt */ + USART2_IRQn = 28, /*!< USART2 global Interrupt */ + USART3_4_IRQn = 29, /*!< USART3 and USART4 global Interrupt */ + USB_IRQn = 31 /*!< USB global Interrupt & EXTI Line18 Interrupt */ +} IRQn_Type; + +/** + * @} + */ + +#include "core_cm0.h" /* Cortex-M0 processor and core peripherals */ +//create our own system functions! #include "system_stm32f0xx.h" /* STM32F0xx System Header */ +#include + +/** @addtogroup Peripheral_registers_structures + * @{ + */ + +/** + * @brief Analog to Digital Converter + */ + +typedef struct +{ + __IO uint32_t ISR; /*!< ADC interrupt and status register, Address offset: 0x00 */ + __IO uint32_t IER; /*!< ADC interrupt enable register, Address offset: 0x04 */ + __IO uint32_t CR; /*!< ADC control register, Address offset: 0x08 */ + __IO uint32_t CFGR1; /*!< ADC configuration register 1, Address offset: 0x0C */ + __IO uint32_t CFGR2; /*!< ADC configuration register 2, Address offset: 0x10 */ + __IO uint32_t SMPR; /*!< ADC sampling time register, Address offset: 0x14 */ + uint32_t RESERVED1; /*!< Reserved, 0x18 */ + uint32_t RESERVED2; /*!< Reserved, 0x1C */ + __IO uint32_t TR; /*!< ADC analog watchdog 1 threshold register, Address offset: 0x20 */ + uint32_t RESERVED3; /*!< Reserved, 0x24 */ + __IO uint32_t CHSELR; /*!< ADC group regular sequencer register, Address offset: 0x28 */ + uint32_t RESERVED4[5]; /*!< Reserved, 0x2C */ + __IO uint32_t DR; /*!< ADC group regular data register, Address offset: 0x40 */ +} ADC_TypeDef; + +typedef struct +{ + __IO uint32_t CCR; /*!< ADC common configuration register, Address offset: ADC1 base address + 0x308 */ +} ADC_Common_TypeDef; + +/** + * @brief CRC calculation unit + */ + +typedef struct +{ + __IO uint32_t DR; /*!< CRC Data register, Address offset: 0x00 */ + __IO uint8_t IDR; /*!< CRC Independent data register, Address offset: 0x04 */ + uint8_t RESERVED0; /*!< Reserved, 0x05 */ + uint16_t RESERVED1; /*!< Reserved, 0x06 */ + __IO uint32_t CR; /*!< CRC Control register, Address offset: 0x08 */ + uint32_t RESERVED2; /*!< Reserved, 0x0C */ + __IO uint32_t INIT; /*!< Initial CRC value register, Address offset: 0x10 */ + __IO uint32_t RESERVED3; /*!< Reserved, 0x14 */ +} CRC_TypeDef; + +/** + * @brief Debug MCU + */ + +typedef struct +{ + __IO uint32_t IDCODE; /*!< MCU device ID code, Address offset: 0x00 */ + __IO uint32_t CR; /*!< Debug MCU configuration register, Address offset: 0x04 */ + __IO uint32_t APB1FZ; /*!< Debug MCU APB1 freeze register, Address offset: 0x08 */ + __IO uint32_t APB2FZ; /*!< Debug MCU APB2 freeze register, Address offset: 0x0C */ +}DBGMCU_TypeDef; + +/** + * @brief DMA Controller + */ + +typedef struct +{ + __IO uint32_t CCR; /*!< DMA channel x configuration register */ + __IO uint32_t CNDTR; /*!< DMA channel x number of data register */ + __IO uint32_t CPAR; /*!< DMA channel x peripheral address register */ + __IO uint32_t CMAR; /*!< DMA channel x memory address register */ +} DMA_Channel_TypeDef; + +typedef struct +{ + __IO uint32_t ISR; /*!< DMA interrupt status register, Address offset: 0x00 */ + __IO uint32_t IFCR; /*!< DMA interrupt flag clear register, Address offset: 0x04 */ +} DMA_TypeDef; + +/** + * @brief External Interrupt/Event Controller + */ + +typedef struct +{ + __IO uint32_t IMR; /*!
© 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 stm32f0xx + * @{ + */ + +#ifndef __STM32F0xx_H +#define __STM32F0xx_H + +#ifdef __cplusplus + extern "C" { +#endif /* __cplusplus */ + +/** @addtogroup Library_configuration_section + * @{ + */ + +/** + * @brief STM32 Family + */ +#if !defined (STM32F0) +#define STM32F0 +#endif /* STM32F0 */ + +/* Uncomment the line below according to the target STM32 device used in your + application + */ + +#if !defined (STM32F030x6) && !defined (STM32F030x8) && \ + !defined (STM32F031x6) && !defined (STM32F038xx) && \ + !defined (STM32F042x6) && !defined (STM32F048xx) && !defined (STM32F070x6) && \ + !defined (STM32F051x8) && !defined (STM32F058xx) && \ + !defined (STM32F071xB) && !defined (STM32F072xB) && !defined (STM32F078xx) && !defined (STM32F070xB) && \ + !defined (STM32F091xC) && !defined (STM32F098xx) && !defined (STM32F030xC) + /* #define STM32F030x6 */ /*!< STM32F030x4, STM32F030x6 Devices (STM32F030xx microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */ + /* #define STM32F030x8 */ /*!< STM32F030x8 Devices (STM32F030xx microcontrollers where the Flash memory is 64 Kbytes) */ + /* #define STM32F031x6 */ /*!< STM32F031x4, STM32F031x6 Devices (STM32F031xx microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */ + /* #define STM32F038xx */ /*!< STM32F038xx Devices (STM32F038xx microcontrollers where the Flash memory is 32 Kbytes) */ + /* #define STM32F042x6 */ /*!< STM32F042x4, STM32F042x6 Devices (STM32F042xx microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */ + /* #define STM32F048x6 */ /*!< STM32F048xx Devices (STM32F042xx microcontrollers where the Flash memory is 32 Kbytes) */ + /* #define STM32F051x8 */ /*!< STM32F051x4, STM32F051x6, STM32F051x8 Devices (STM32F051xx microcontrollers where the Flash memory ranges between 16 and 64 Kbytes) */ + /* #define STM32F058xx */ /*!< STM32F058xx Devices (STM32F058xx microcontrollers where the Flash memory is 64 Kbytes) */ + /* #define STM32F070x6 */ /*!< STM32F070x6 Devices (STM32F070x6 microcontrollers where the Flash memory ranges between 16 and 32 Kbytes) */ + /* #define STM32F070xB */ /*!< STM32F070xB Devices (STM32F070xB microcontrollers where the Flash memory ranges between 64 and 128 Kbytes) */ + /* #define STM32F071xB */ /*!< STM32F071x8, STM32F071xB Devices (STM32F071xx microcontrollers where the Flash memory ranges between 64 and 128 Kbytes) */ + /* #define STM32F072xB */ /*!< STM32F072x8, STM32F072xB Devices (STM32F072xx microcontrollers where the Flash memory ranges between 64 and 128 Kbytes) */ + /* #define STM32F078xx */ /*!< STM32F078xx Devices (STM32F078xx microcontrollers where the Flash memory is 128 Kbytes) */ + /* #define STM32F030xC */ /*!< STM32F030xC Devices (STM32F030xC microcontrollers where the Flash memory is 256 Kbytes) */ + /* #define STM32F091xC */ /*!< STM32F091xB, STM32F091xC Devices (STM32F091xx microcontrollers where the Flash memory ranges between 128 and 256 Kbytes) */ + /* #define STM32F098xx */ /*!< STM32F098xx Devices (STM32F098xx microcontrollers where the Flash memory is 256 Kbytes) */ +#endif + +/* Tip: To avoid modifying this file each time you need to switch between these + devices, you can define the device in your toolchain compiler preprocessor. + */ +#if !defined (USE_HAL_DRIVER) +/** + * @brief Comment the line below if you will not use the peripherals drivers. + In this case, these drivers will not be included and the application code will + be based on direct access to peripherals registers + */ + /*#define USE_HAL_DRIVER */ +#endif /* USE_HAL_DRIVER */ + +/** + * @brief CMSIS Device version number V2.3.1 + */ +#define __STM32F0_DEVICE_VERSION_MAIN (0x02) /*!< [31:24] main version */ +#define __STM32F0_DEVICE_VERSION_SUB1 (0x03) /*!< [23:16] sub1 version */ +#define __STM32F0_DEVICE_VERSION_SUB2 (0x01) /*!< [15:8] sub2 version */ +#define __STM32F0_DEVICE_VERSION_RC (0x00) /*!< [7:0] release candidate */ +#define __STM32F0_DEVICE_VERSION ((__STM32F0_DEVICE_VERSION_MAIN << 24)\ + |(__STM32F0_DEVICE_VERSION_SUB1 << 16)\ + |(__STM32F0_DEVICE_VERSION_SUB2 << 8 )\ + |(__STM32F0_DEVICE_VERSION_RC)) + +/** + * @} + */ + +/** @addtogroup Device_Included + * @{ + */ + +#if defined(STM32F030x6) + #include "stm32f030x6.h" +#elif defined(STM32F030x8) + #include "stm32f030x8.h" +#elif defined(STM32F031x6) + #include "stm32f031x6.h" +#elif defined(STM32F038xx) + #include "stm32f038xx.h" +#elif defined(STM32F042x6) + #include "stm32f042x6.h" +#elif defined(STM32F048xx) + #include "stm32f048xx.h" +#elif defined(STM32F051x8) + #include "stm32f051x8.h" +#elif defined(STM32F058xx) + #include "stm32f058xx.h" +#elif defined(STM32F070x6) + #include "stm32f070x6.h" +#elif defined(STM32F070xB) + #include "stm32f070xb.h" +#elif defined(STM32F071xB) + #include "stm32f071xb.h" +#elif defined(STM32F072xB) + #include "stm32f072xb.h" +#elif defined(STM32F078xx) + #include "stm32f078xx.h" +#elif defined(STM32F091xC) + #include "stm32f091xc.h" +#elif defined(STM32F098xx) + #include "stm32f098xx.h" +#elif defined(STM32F030xC) + #include "stm32f030xc.h" +#else + #error "Please select first the target STM32F0xx device used in your application (in stm32f0xx.h file)" +#endif + +/** + * @} + */ + +/** @addtogroup Exported_types + * @{ + */ +typedef enum +{ + RESET = 0, + SET = !RESET +} FlagStatus, ITStatus; + +typedef enum +{ + DISABLE = 0, + ENABLE = !DISABLE +} FunctionalState; +#define IS_FUNCTIONAL_STATE(STATE) (((STATE) == DISABLE) || ((STATE) == ENABLE)) + +typedef enum +{ + ERROR = 0, + SUCCESS = !ERROR +} ErrorStatus; + +/** + * @} + */ + + +/** @addtogroup Exported_macros + * @{ + */ +#define SET_BIT(REG, BIT) ((REG) |= (BIT)) + +#define CLEAR_BIT(REG, BIT) ((REG) &= ~(BIT)) + +#define READ_BIT(REG, BIT) ((REG) & (BIT)) + +#define CLEAR_REG(REG) ((REG) = (0x0)) + +#define WRITE_REG(REG, VAL) ((REG) = (VAL)) + +#define READ_REG(REG) ((REG)) + +#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) + + +/** + * @} + */ + +#if defined (USE_HAL_DRIVER) + #include "stm32f0xx_hal.h" +#endif /* USE_HAL_DRIVER */ + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __STM32F0xx_H */ +/** + * @} + */ + +/** + * @} + */ + + + + +/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ diff --git a/firmware/avr_release/main_green_v1_2.hex b/firmware/release/main_green_v1_2.hex similarity index 100% rename from firmware/avr_release/main_green_v1_2.hex rename to firmware/release/main_green_v1_2.hex diff --git a/firmware/avr_release/main_purple_v1_1_v3_0.hex b/firmware/release/main_purple_v1_1_v3_0.hex similarity index 100% rename from firmware/avr_release/main_purple_v1_1_v3_0.hex rename to firmware/release/main_purple_v1_1_v3_0.hex diff --git a/firmware/avr_release/main_v1_2b-v1_4.hex b/firmware/release/main_v1_2b-v1_4.hex similarity index 100% rename from firmware/avr_release/main_v1_2b-v1_4.hex rename to firmware/release/main_v1_2b-v1_4.hex diff --git a/firmware/source/main.c b/firmware/source/main.c index 2dd4230..b525708 100644 --- a/firmware/source/main.c +++ b/firmware/source/main.c @@ -1,15 +1,24 @@ -#include -#include -#include -#include "usbdrv.h" -//#include "io.h" -//#include "pinport.h" -//#include "buffer.h" +#include "usb.h" + +#ifdef AVR_CORE + #include + #include + #include + #include "usbdrv.h" +#endif + +#ifdef STM_CORE + #include + #include "../source_stm_only/stm_init.h" +#endif + + int main(void) { +#ifdef AVR_CORE //set watch dog timer with 1 second timer wdt_enable(WDTO_1S); /* Even if you don't use the watchdog, turn it off here. On newer devices, @@ -20,9 +29,6 @@ int main(void) * additional hardware initialization. */ - //odDebugInit(); //intialize debuging printing via serial port - //DBG1(0x00, 0, 0); //debug serial op: main starts - //initialize V-usb driver before interupts enabled and entering main loop usbInit(); //disconnect from host enforce re-enumeration, interupts must be disabled during this. @@ -43,18 +49,45 @@ int main(void) //enable interrupts sei(); +#endif + +#ifdef STM_CORE + //System is running at reset defaults + + //Default clock is in operation + //Change system clock as needed + init_clock(); + + //Initialize periphery clocks as needed + init_usb_clock(); + + //Initialize WDT, core features, etc + + //enable interrupts + __enable_irq(); //clear's processor PRIMASK register bit to allow interrupts to be taken + //I think this gets done automatically when enabling individual IRQs + + //Initialize io, periphery, etc + //setup LED as outputs and turn them on + //setup user switch as input + + init_usb(); + //Initialize board/system +#endif //================= //MAIN LOOP //================= while (1) { +#ifdef AVR_CORE //pet the watch doggie to keep him happy wdt_reset(); //must call at regular intervals no longer than 50msec - //checks for setup packets from what I understand + //keeps 8Byte EP buffer moving from what I understand usbPoll(); +#endif //check buffer status' and instruct them to //flash/dump as needed to keep data moving diff --git a/firmware/source/usb.c b/firmware/source/usb.c index 84042f0..b24c6ec 100644 --- a/firmware/source/usb.c +++ b/firmware/source/usb.c @@ -2,7 +2,7 @@ #include "usb.h" //used to store success/error code of last transfer for debugging -static uint8_t usbWrite_status; +//static uint8_t usbWrite_status; //USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]); /* This function is called when the driver receives a SETUP transaction from @@ -41,21 +41,26 @@ static uint8_t usbWrite_status; //}usbRequest_t; - +#ifdef AVR_CORE USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) { +#endif +#ifdef STM_CORE +uint16_t usbFunctionSetup(uint8_t data[8]) { +#endif //defined and controled by buffer.c // extern buffer *cur_usb_load_buff; -// -// //cast incoming data into the the usb setup packet it is + + //cast incoming data into the the usb setup packet it is // setup_packet *spacket = (void *)data; -// -// //8 Byte buffer to be used for returning error code and return values -// //must be static so V-USB driver can still access after function return + + //8 Byte buffer to be used for returning error code and return values + //must be static so V-USB driver can still access after function return // static uint8_t rv[RETURN_BUFF_SIZE]; -// //rv[RV_ERR_IDX] contains opcode success/error code -// //rv[1-7] available for return data, start with index 1 -// //rv[RETURN_BUFF_FIRST_IDX-RETURN_BUFFER_LAST_IDX] + static uint8_t rv[8]; + //rv[RV_ERR_IDX] contains opcode success/error code + //rv[1-7] available for return data, start with index 1 + //rv[RETURN_BUFF_FIRST_IDX-RETURN_BUFFER_LAST_IDX] /* (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data * block and return the length of the data in 'usbFunctionSetup()'. The driver @@ -275,7 +280,12 @@ USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]) { // with checks: using 8bit rlen = 18sec = 28.3KBps //#define MAKECHECKS 0 +#ifdef AVR_CORE USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) { +#endif +#ifdef STM_CORE +uint8_t usbFunctionWrite(uint8_t *data, uint8_t len) { +#endif /* //defined and controled by buffer.c @@ -333,8 +343,7 @@ USB_PUBLIC uchar usbFunctionWrite(uchar *data, uchar len) { return NOT_DONE; } -*/ - + */ return 0; } diff --git a/firmware/source/usb.h b/firmware/source/usb.h index bce00ff..096dcf6 100644 --- a/firmware/source/usb.h +++ b/firmware/source/usb.h @@ -1,13 +1,30 @@ #ifndef _usb_h #define _usb_h -#include -#include "usbdrv.h" +//Define the target core, only define one of these +//these defines are made in Makefile +//#define AVR_CORE +//#define STM_CORE + +//== AVR CORE == AVR CORE == AVR CORE == AVR CORE == AVR CORE +#ifdef AVR_CORE +// #include + + #include "usbdrv.h" +#endif +//end AVR CORE + +//== STM CORE == STM CORE == STM CORE == STM CORE == STM CORE +#ifdef STM_CORE + #include "..\source_stm_only\usbstm.h" +#endif +//end STM CORE + /* -#include "logic.h" -#include "types.h" #include "shared_dictionaries.h" +#include "types.h" +#include "logic.h" #include "shared_errors.h" #include "pinport.h" #include "io.h" @@ -16,6 +33,7 @@ #include "buffer.h" */ +/* #define ENDPOINT_BIT 0x80 //Bit 7 of bmRequest type determines endpoint #define ENDPOINT_IN 0x80 //In: device-to-host. #define ENDPOINT_OUT 0x00 //Out: host-to-device. @@ -27,6 +45,7 @@ #define STALL 0xFF #define PAYLD_DONE 1 #define NOT_DONE 0 +*/ diff --git a/firmware/source_stm_only/stm_init.c b/firmware/source_stm_only/stm_init.c new file mode 100644 index 0000000..028b2c5 --- /dev/null +++ b/firmware/source_stm_only/stm_init.c @@ -0,0 +1,167 @@ + +#include "stm_init.h" + +void HardFault_Handler(void) +{ + + //TODO test out this function + //should retrieve PC of the instruction that follows whatever caused the hardfault + //This didn't work for me earlier bc the stack itself was broke +// asm( +// "movs r0, #4 \n" +// "movs r1, lr \n" +// "tst r0, r1 \n" +// "beq _MSP \n" +// "mrs r0, psp \n" +// "b _HALT \n" +// "_MSP: \n" +// " mrs r0, msp \n" +// "_HALT: \n" +// " ldr r1, [r0,#20] \n" +// //" bkpt #0 \n" +// ); + + while (1) { + } +} + +/* stm32f0x2 devices have HSI48 available which isn't on stm32f0x0 devices + * I'm primarily targetting f070 devices which will require external xtal + * Most generic setup would be to use HSI 8MHz * PLL which is available on all devices + * but can't keep all devices running at 16Mhz while also properly clocking usb with that setup. + * + * After reset all devices select HSI 8MHz as SYSCLK + * To prevent usb over/under run problems, APB clock must be atleast 10Mhz + * 070 can only use PLL to feed USB clock. + * + * Current goal is to have PLL output 48Mhz from a 16Mhz HSE to support 070 devices + * 072 devices won't have ext xtal though, and use HSI 48Mhz for usb block + * Would like to have SYSCLK = 16Mhz to align stm32 and avr kazzo devices core clocks for now + * Have to also supply APB with 10Mhz or more, which is derived from SYSCLK with AHB & APB dividers + * + * While these goals are possible, we have to code them based on 072/070 devices + * 072: HSI 8Mhz -> PLL * 2 = 16Mhz -> SYSCLK -> no division to AHB & APB clocks + * HSI 48Mhz -> USB block + * 070: HSE 16Mhz -> PLL * 4 = 48Mhz -> USB block + * HSE 16Mhz -> SYSCLK -> no division to AHB & APB clocks + * + * Difference between these two is the PLL. + * 072 uses PLL to create 16Mhz SYSCLK from HSI, USB fed directly from HSI 48Mhz + * -HSE not available/used on 072 + * 070 uses PLL to create 48Mhz for USB from HSE, SYSCLK fed directly from 16Mhz HSE. + * -HSI not used for anything on 070 + */ + +//pick define based on xtal setup for init_clock and init_usb_clock functions +//#define NO_XTAL +#define XTAL_16Mhz +void init_clock() +{ +#ifdef NO_XTAL // setup PLL for HSI * 2 = 16Mhz and set SYSCLK to use it + + // To modify the PLL configuration, proceed as follows: + // 1.Disable the PLL by setting PLLON to 0. + // 2. Wait until PLLRDY is cleared. The PLL is now fully stopped. + // * PLL is off and unlocked after reset + + // 3. Change the desired parameter. + // * PLL MUL is set to *2 at reset + + // 4. Enable the PLL again by setting PLLON to 1. + // 5. Wait until PLLRDY is set. + +//Copied from reference manual optimizations possible assuming post-reset +//Cut out parts not needed due to values @ reset, saved 60Bytes! +// /* (1) Test if PLL is used as System clock */ +// if ((RCC->CFGR & RCC_CFGR_SWS) == RCC_CFGR_SWS_PLL) { +// RCC->CFGR &= (uint32_t) (~RCC_CFGR_SW); /* (2) Select HSI as system clock */ +// while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) /* (3) Wait for HSI switched */ +// { /* For robust implementation, add here time-out management */ } +// } +// +// RCC->CR &= (uint32_t)(~RCC_CR_PLLON);/* (4) Disable the PLL */ +// while((RCC->CR & RCC_CR_PLLRDY) != 0) /* (5) Wait until PLLRDY is cleared */ +// { /* For robust implementation, add here time-out management */ } +// +// /* (6) Set the PLL multiplier to 2-16 all integers */ +// RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PLLMUL) | RCC_CFGR_PLLMUL2; /* PLLMUL set to *2 at reset) */ + +// // PLL PREDIV should be getting set to zero too! They just assumed not present/reset values... +// RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PLLSRC) | RCC_CFGR_PLLSRC_HSI_PREDIV; /* PLLMUL set to *2 at reset) */ + +// // They also didn't address flash wait states! +// FLASH->ACR |= (uint32_t) 0x01; //If >24Mhz SYSCLK, must add wait state to flash + +// PREDIV is / 2 post reset, so PLL is being sourced with 4Mhz + RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PLLMUL) | RCC_CFGR_PLLMUL4; /* PLLMUL set to *2 at reset) */ + RCC->CR |= RCC_CR_PLLON; /* (7) Enable the PLL */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) /* (8) Wait until PLLRDY is set */ + { /* For robust implementation, add here time-out management */ } + + RCC->CFGR |= (uint32_t) (RCC_CFGR_SW_PLL); /* (9) Select PLL as system clock */ + while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) /* (10) Wait until the PLL is switched on */ + { /* For robust implementation, add here time-out management */ } + +#endif + + +#ifdef XTAL_16Mhz + + //Turn on HSE + /* (2) Enable the CSS + * Enable the HSE and set HSEBYP to use the internal clock + * Enable HSE */ + RCC->CR |= (RCC_CR_CSSON | RCC_CR_HSEON); /* (2) */ + + /* (1) Check the flag HSE ready */ + while ((RCC->CR & RCC_CR_HSERDY) == 0) /* (1) */ + { /*spin while waiting for HSE to be ready */ } + + + /* (3) Switch the system clock to HSE */ + //at startup HSI is selected SW = 00 + RCC->CFGR |= RCC_CFGR_SW_HSE; + + //Now the SYSCLK is running directly off the HSE 16Mhz xtal + + /* (1) Test if PLL is used as System clock */ +// if ((RCC->CFGR & RCC_CFGR_SWS) == RCC_CFGR_SWS_PLL) { +// RCC->CFGR &= (uint32_t) (~RCC_CFGR_SW); /* (2) Select HSI as system clock */ +// while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) /* (3) Wait for HSI switched */ +// { /* For robust implementation, add here time-out management */ } +// } +// +// RCC->CR &= (uint32_t)(~RCC_CR_PLLON);/* (4) Disable the PLL */ +// while((RCC->CR & RCC_CR_PLLRDY) != 0) /* (5) Wait until PLLRDY is cleared */ +// { /* For robust implementation, add here time-out management */ } + + //Set PLL Source to HSE, the PLL must be off to do this + RCC->CFGR |= RCC_CFGR_PLLSRC_HSE_PREDIV; //by default HSE isn't divided + + //Set PLL to 16 * 3 = 48Mhz for USB + //RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_PLLMUL) | RCC_CFGR_PLLMUL3; /* PLLMUL set to *2 at reset) */ + RCC->CFGR |= RCC_CFGR_PLLMUL3; /* PLLMUL set to *2 at reset) */ + RCC->CR |= RCC_CR_PLLON; /* (7) Enable the PLL */ + while((RCC->CR & RCC_CR_PLLRDY) == 0) /* (8) Wait until PLLRDY is set */ + { /* For robust implementation, add here time-out management */ } + + //test SYSCLK with 48Mhz +// FLASH->ACR |= (uint32_t) 0x01; //If >24Mhz SYSCLK, must add wait state to flash +// RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_PLL; /* (9) Select PLL as system clock */ +// while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) /* (10) Wait until the PLL is switched on */ +// { /* For robust implementation, add here time-out management */ } + +#endif + + // The USB peripheral logic uses a dedicated clock. The frequency of this + // dedicated clock is fixed by the requirements of the USB standard at 48 MHz, + // and this can be different from the clock used for the interface to the APB bus. + // Different clock configurations are possible where the APB clock frequency can be higher or lower than the USB peripheral + // one. + // Due to USB data rate and packet memory interface requirements, + // the APB clock must have a minimum frequency of 10 MHz to avoid data overrun/underrun problems. + + //AHB APB clock setup: + //these are not divided by default +} + diff --git a/firmware/source_stm_only/stm_init.h b/firmware/source_stm_only/stm_init.h new file mode 100644 index 0000000..91e7a8e --- /dev/null +++ b/firmware/source_stm_only/stm_init.h @@ -0,0 +1,5 @@ + +#include + +void init_clock(); + diff --git a/firmware/source_stm_only/usb_descriptors.h b/firmware/source_stm_only/usb_descriptors.h new file mode 100644 index 0000000..dbd4275 --- /dev/null +++ b/firmware/source_stm_only/usb_descriptors.h @@ -0,0 +1,271 @@ +#ifndef _usb_descriptors_h +#define _usb_descriptors_h + +/* Contains all the device, configuration, interface, endpoint, and string descriptor definitions + * The excellent breakdown of the USB standard and field comments have been copy pasted from the + * almighty documentation "USB in a Nutshell" article by BeyondLogic: + * http://www.beyondlogic.org/usbnutshell/usb5.shtml#DeviceDescriptors + */ +#define EP0_SIZE 0x08 //8Bytes same as usb 1.1 for now + +#define bLength 0 //offset of bLength in descriptor array +#define bDescriptorType 1 //offset of bDescriptorType in descriptor array +#define DESC_TYPE_MASK 0xFF00 //Descriptor type is upper byte of wValue +#define DESC_IDX_MASK 0x00FF //Descriptor index is lower byte of wValue +#define DESC_TYPE_DEVICE 0x01 +#define DESC_TYPE_CONFIG 0x02 +#define DESC_TYPE_STRING 0x03 +#define DESC_TYPE_INTERFACE 0x04 +#define DESC_TYPE_ENDPOINT 0x05 + +#define DEVICE_DESC_LEN 18 +const uint8_t device_desc[DEVICE_DESC_LEN] = { +// 0 bLength 1 Number Size of the Descriptor in Bytes (18 bytes) + DEVICE_DESC_LEN, +// 1 bDescriptorType 1 Constant Device Descriptor (0x01) + DESC_TYPE_DEVICE, +// 2 bcdUSB 2 BCD USB Specification Number which device complies too. + 0x00, 0x02, +// 4 bDeviceClass 1 Class Class Code (Assigned by USB Org) + 0xFF, +// If equal to Zero, each interface specifies itÎéÎ÷s own class code +// If equal to 0xFF, the class code is vendor specified. +// Otherwise field is valid Class Code. +// 5 bDeviceSubClass 1 SubClass Subclass Code (Assigned by USB Org) + 0x00, +// 6 bDeviceProtocol 1 Protocol Protocol Code (Assigned by USB Org) + 0x00, +// 7 bMaxPacketSize 1 Number Maximum Packet Size for Zero Endpoint. Valid Sizes are 8, 16, 32, 64 (for usb 2.0) + EP0_SIZE, +// 8 idVendor 2 ID Vendor ID (Assigned by USB Org) + 0xC0, 0x16, +// 10 idProduct 2 ID Product ID (Assigned by Manufacturer) + 0xDC, 0x05, +// 12 bcdDevice 2 BCD Device Release Number + 0x00, 0x02, +// 14 iManufacturer 1 Index Index of Manufacturer String Descriptor + 0x01, +// 15 iProduct 1 Index Index of Product String Descriptor + 0x02, +// 16 iSerialNumber 1 Index Index of Serial Number String Descriptor + 0x00, +// 17 bNumConfigurations 1 Integer Number of Possible Configurations + 0x01 }; + + +// The bcdUSB field reports the highest version of USB the device supports. The value is in binary coded decimal +// with a format of 0xJJMN where JJ is the major version number, M is the minor version number and N is the sub minor +// version number. e.g. USB 2.0 is reported as 0x0200, USB 1.1 as 0x0110 and USB 1.0 as 0x0100. +// +// The bDeviceClass, bDeviceSubClass and bDeviceProtocol are used by the operating system to find a class driver +// for your device. Typically only the bDeviceClass is set at the device level. Most class specifications choose to +// identify itself at the interface level and as a result set the bDeviceClass as 0x00. This allows for the one +// device to support multiple classes. +// +// The bMaxPacketSize field reports the maximum packet size for endpoint zero. All devices must support endpoint zero. +// +// The idVendor and idProduct are used by the operating system to find a driver for your device. The Vendor ID is assigned by the USB-IF. +// +// The bcdDevice has the same format than the bcdUSB and is used to provide a device version number. This value is assigned by the developer. +// +// Three string descriptors exist to provide details of the manufacturer, product and serial number. There is no +// requirement to have string descriptors. If no string descriptor is present, a index of zero should be used. +// +// bNumConfigurations defines the number of configurations the device supports at its current speed. + + +//Configuration Descriptors +// +// A USB device can have several different configurations although the majority of devices are simple and only have one. +// The configuration descriptor specifies how the device is powered, what the maximum power consumption is, the number of +// interfaces it has. Therefore it is possible to have two configurations, one for when the device is bus powered and another +// when it is mains powered. As this is a "header" to the Interface descriptors, its also feasible to have one configuration +// using a different transfer mode to that of another configuration. +// +// Once all the configurations have been examined by the host, the host will send a SetConfiguration command with a non zero +// value which matches the bConfigurationValue of one of the configurations. This is used to select the desired configuration. +// +#define CONFIG_DESC_LEN 9 +#define INTERFACE_DESC_LEN 9 +#define ENDPOINT_DESC_LEN 0 //only describe EP's other than EP0 + //NOTE: current table broken if total is greater 255 bytes!!! +#define CONFIG_TOTAL_LEN (CONFIG_DESC_LEN + INTERFACE_DESC_LEN + ENDPOINT_DESC_LEN) +#define wTotalLength 2 //offset of wTotalLength in descriptor array +const uint8_t config_desc[CONFIG_TOTAL_LEN] = { +// Off Field Size Value Description +// 0 bLength 1 Number Size of Descriptor in Bytes + CONFIG_DESC_LEN, +// 1 bDescriptorType 1 Constant Configuration Descriptor (0x02) + DESC_TYPE_CONFIG, +// 2 wTotalLength 2 Number Total length in bytes of data returned + CONFIG_TOTAL_LEN, 0x00, +// 4 bNumInterfaces 1 Number Number of Interfaces + 0x01, +// 5 bConfigurationValue 1 Number Value to use as an argument to select this configuration + 0x01, +// 6 iConfiguration 1 Index Index of String Descriptor describing this configuration + 0x00, +// 7 bmAttributes 1 Bitmap D7 Reserved, set to 1. (USB 1.0 Bus Powered) +// D6 Self Powered +// D5 Remote Wakeup +// D4..0 Reserved, set to 0. + 0x80, +// 8 bMaxPower 1 mA Maximum Power Consumption in 2mA units +// bus powered devices should request more than 100mA + 100/2, +// +// When the configuration descriptor is read, it returns the entire configuration hierarchy which includes all related +// interface and endpoint descriptors. The wTotalLength field reflects the number of bytes in the hierarchy. +// +// bNumInterfaces specifies the number of interfaces present for this configuration. +// +// bConfigurationValue is used by the SetConfiguration request to select this configuration. +// +// iConfiguration is a index to a string descriptor describing the configuration in human readable form. +// +// bmAttributes specify power parameters for the configuration. If a device is self powered, it sets D6. Bit D7 was used in +// USB 1.0 to indicate a bus powered device, but this is now done by bMaxPower. If a device uses any power from the bus, +// whether it be as a bus powered device or as a self powered device, it must report its power consumption in bMaxPower. +// Devices can also support remote wakeup which allows the device to wake up the host when the host is in suspend. +// +// bMaxPower defines the maximum power the device will drain from the bus. This is in 2mA units, thus a maximum of +// approximately 500mA can be specified. The specification allows a high powered bus powered device to drain no more than +// 500mA from Vbus. If a device loses external power, then it must not drain more than indicated in bMaxPower. It should +// fail any operation it cannot perform without external power. +// +// +// +// +//Interface Descriptors +// +// The interface descriptor could be seen as a header or grouping of the endpoints into a functional group performing a +// single feature of the device. The interface descriptor conforms to the following format, +// +// Off Field Size Value Description +// 0 bLength 1 Number Size of Descriptor in Bytes (9 Bytes) + INTERFACE_DESC_LEN, +// 1 bDescriptorType 1 Constant Interface Descriptor (0x04) + DESC_TYPE_INTERFACE, +// 2 bInterfaceNumber 1 Number Number of Interface + 0x00, +// 3 bAlternateSetting 1 Number Value used to select alternative setting + 0x00, +// 4 bNumEndpoints 1 Number Number of Endpoints used for this interface + 0x00, +// 5 bInterfaceClass 1 Class Class Code (Assigned by USB Org) + 0x00, +// 6 bInterfaceSubClass 1 SubClass Subclass Code (Assigned by USB Org) + 0x00, +// 7 bInterfaceProtocol 1 Protocol Protocol Code (Assigned by USB Org) + 0x00, +// 8 iInterface 1 Index Index of String Descriptor Describing this interface + 0x00}; +// +// bInterfaceNumber indicates the index of the interface descriptor. This should be zero based, and incremented once +// for each new interface descriptor. +// +// bAlternativeSetting can be used to specify alternative interfaces. These alternative interfaces can be selected +// with the Set Interface request. +// +// bNumEndpoints indicates the number of endpoints used by the interface. This value should exclude endpoint zero +// and is used to indicate the number of endpoint descriptors to follow. +// +// bInterfaceClass, bInterfaceSubClass and bInterfaceProtocol can be used to specify supported classes +// (e.g. HID, communications, mass storage etc.) This allows many devices to use class drivers preventing the +// need to write specific drivers for your device. +// +// iInterface allows for a string description of the interface. +// +//Endpoint Descriptors +// +// Endpoint descriptors are used to describe endpoints other than endpoint zero. Endpoint zero is always assumed to be a +// control endpoint and is configured before any descriptors are even requested. The host will use the information returned +// from these descriptors to determine the bandwidth requirements of the bus. +// +// Off Field Size Value Description +// 0 bLength 1 Number Size of Descriptor in Bytes (7 bytes) +// 1 bDescriptorType 1 Constant Endpoint Descriptor (0x05) +// 2 bEndpointAddress 1 Endpoint Endpoint Address +// Bits 0..3b Endpoint Number. +// Bits 4..6b Reserved. Set to Zero +// Bits 7 Direction 0 = Out, 1 = In (Ignored for Control Endpoints) +// 3 bmAttributes 1 Bitmap Bits 0..1 Transfer Type +// 00 = Control 01 = Isochronous 10 = Bulk 11 = Interrupt +// Bits 2..7 are reserved. If Isochronous endpoint, +// Bits 3..2 = Synchronisation Type (Iso Mode) +// 00 = No Synchonisation 01 = Asynchronous 10 = Adaptive 11 = Synchronous +// Bits 5..4 = Usage Type (Iso Mode) +// 00 = Data Endpoint 01 = Feedback Endpoint +// 10 = Explicit Feedback Data Endpoint 11 = Reserved +// 4 wMaxPacketSize 2 Number Maximum Packet Size this endpoint is capable of sending or receiving +// 6 bInterval 1 Number Interval for polling endpoint data transfers. Value in frame counts. +// Ignored for Bulk & Control Endpoints. Isochronous must equal 1 and field may +// range from 1 to 255 for interrupt endpoints. +// +// bEndpointAddress indicates what endpoint this descriptor is describing. +// +// bmAttributes specifies the transfer type. This can either be Control, Interrupt, Isochronous or Bulk Transfers. +// If an Isochronous endpoint is specified, additional attributes can be selected such as the Synchronisation and usage types. +// +// wMaxPacketSize indicates the maximum payload size for this endpoint. +// +// bInterval is used to specify the polling interval of certain transfers. The units are expressed in frames, +// thus this equates to either 1ms for low/full speed devices and 125us for high speed devices. +// +//String Descriptors +// +// String descriptors provide human readable information and are optional. If they are not used, any +// string index fields of descriptors must be set to zero indicating there is no string descriptor available. +// +// The strings are encoded in the Unicode format and products can be made to support multiple languages. +// String Index 0 should return a list of supported languages. A list of USB Language IDs can be found in +// Universal Serial Bus Language Identifiers (LANGIDs) version 1.0 +// +#define STRING0_DESC_LEN 4 +const uint8_t string0_desc[STRING0_DESC_LEN] = { +// Off Field Size Value Description +// 0 bLength 1 Number Size of Descriptor in Bytes + STRING0_DESC_LEN, +// 1 bDescriptorType 1 Constant String Descriptor (0x03) + DESC_TYPE_STRING, +// 2 wLANGID[0] 2 number Supported Language Code Zero +// (e.g. 0x0409 English - United States) + 0x09, 0x04}; +// 4 wLANGID[1] 2 number Supported Language Code One +// (e.g. 0x0c09 English - Australian) +// n wLANGID[x] 2 number Supported Language Code x +// (e.g. 0x0407 German - Standard) +// +// The above String Descriptor shows the format of String Descriptor Zero. The host should read this descriptor to +// determine what languages are available. If a language is supported, it can then be referenced by sending the +// language ID in the wIndex field of a Get Descriptor(String) request. +// +// All subsequent strings take on the format below, +// +// Off Field Size Value Description +// 0 bLength 1 Number Size of Descriptor in Bytes +// 1 bDescriptorType 1 Constant String Descriptor (0x03) +// 2 bString n Unicode Unicode Encoded String +// +// +// + +//Defining string arrays as uint16_t effectively makes the strings UTF-16 as required +#define BYTES_PER_HWORD 2 +#define STRING1_DESC_LEN (21*BYTES_PER_HWORD) //characters plus 1 for bLength & bDescriptorType +const uint16_t string1_desc[STRING1_DESC_LEN] = { +// 0 bLength 1 Number Size of Descriptor in Bytes +// 1 bDescriptorType 1 Constant String Descriptor (0x03) + ((uint16_t)DESC_TYPE_STRING<<8 | STRING1_DESC_LEN), +// 2 bString n Unicode Unicode Encoded String +'I','n','f','i','n','i','t','e','N','e','s','L','i','v','e','s','.','c','o','m'}; + +#define STRING2_DESC_LEN (15*BYTES_PER_HWORD) //characters plus 1 for bLength & bDescriptorType +const uint16_t string2_desc[STRING2_DESC_LEN] = { +// 0 bLength 1 Number Size of Descriptor in Bytes +// 1 bDescriptorType 1 Constant String Descriptor (0x03) + ((uint16_t)DESC_TYPE_STRING<<8 | STRING2_DESC_LEN), +// 2 bString n Unicode Unicode Encoded String +'I','N','L',' ','R','e','t','r','o','-','P','r','o','g'}; + +#endif diff --git a/firmware/source_stm_only/usbstm.c b/firmware/source_stm_only/usbstm.c new file mode 100644 index 0000000..3abf629 --- /dev/null +++ b/firmware/source_stm_only/usbstm.c @@ -0,0 +1,959 @@ +#include "usbstm.h" +#include "usb_descriptors.h" + + +static int log = 0; + +//include target board library files +//this is junk... #include + +//kaz6 is PB1 +//#define LED (1U) +//#define IOP_LED_EN RCC_AHBENR_GPIOBEN +//#define GPIO_LED GPIOB + + ////kaz adapter is PC13 + //#define LED (13U) + //#define IOP_LED_EN RCC_AHBENR_GPIOCEN + //#define GPIO_LED GPIOC + // + ////kaz adapter data0 debug is PB8 + //#define DEBUG (8U) + //#define IOP_DEBUG_EN RCC_AHBENR_GPIOBEN + //#define GPIO_DEBUG GPIOB + // + //#define LED_ON() (GPIO_LED->ODR |= (0x1U<ODR &= ~(0x1U<ODR |= (0x1U<ODR &= ~(0x1U<CFGR3 |= RCC_CFGR3_USBSW_PLLCLK; +#endif + +#ifdef NO_XTAL + //Turn on HSI48 supposedly it will turn itself on if USB is enabled with HSI48 selected as clock + RCC->CR2 |= RCC_CR2_HSI48ON; + + while ((RCC->CR2 & RCC_CR2_HSI48RDY) != RCC_CR2_HSI48RDY) /* (10) Wait until the HSI48 is stable */ + { /* For robust implementation, add here time-out management */ } + + //by default the 072 has HSI 48Mhz selected as USB clock + RCC->CFGR3 &= ~RCC_CFGR3_USBSW_Msk; + //on the 070 this equates to off, so 070 must set USBSW bit + //CRS system must be turned on to keep HSI 48Mhz calibrated + RCC->APB1ENR |= RCC_APB1ENR_CRSEN; + //Default settings are good using SOF packets for calibration +#endif + + //enable USB block by providing clock + RCC->APB1ENR |= RCC_APB1ENR_USBEN; + + +} + + +void usb_reset_recovery(){ + +// USB->CNTR |= USB_CNTR_FRES; +// USB->CNTR &= ~USB_CNTR_FRES; + + //Endpoint-specific registers + //The number of these registers varies according to the number of endpoints that the USB peripheral is designed to handle. + //The USB peripheral supports up to 8 bidirectional endpoints. Each USB device must support a control endpoint whose + //address (EA bits) must be set to 0. The USB peripheral behaves in an undefined way if multiple endpoints + //are enabled having the same endpoint number value. For each endpoint, an USB_EPnR register is available to store + //the endpoint specific information. + + //Enable the USB device and set address to zero + //USB device address (USB_DADDR) + //bit7 must be set to enable USB functionality, bits 6:0 are the address, must be 0 prior to enumeration + USB->DADDR = (uint16_t) USB_DADDR_EF; + + //They are also reset when an USB reset is received from the USB bus or forced through bit FRES in the CTLR register, + //except the CTR_RX and CTR_TX bits, which are kept unchanged to avoid missing a correct packet notification + //immediately followed by an USB reset event. Each endpoint has its USB_EPnR register where n is the endpoint identifier. + //Read-modify-write cycles on these registers should be avoided because between the read and the write operations + //some bits could be set by the hardware and the next write would modify them before the CPU has the time to detect the change. + //For this purpose, all bits affected by this problem have an "invariant" value that must be used whenever their + //modification is not required. It is recommended to modify these registers with a load instruction where all the bits, + //which can be modified only by the hardware, are written with their "invariant" value. + // + //USB endpoint n register (USB_EPnR), n=[0..7] + //Address offset: 0x00 to 0x1C + //Reset value: 0x0000 + // + //Bit 15 CTR_RX: Correct Transfer for reception + // Hardware sets on successful completetion of OUT/SETUP transaction + // a failed transaction won't set this bit + // Software can only clear this bit + // SETUP bit11 signifies if OUT/SETUP was received + // USE: read this bit after interrupt to determine/verify interrupt was due to success + // service OUT/SETUP packet then clear the bit so subsequent interrupt can be detected properly + // write 0 to clear, write 1 to leave as-is + // + //Bit 14 DTOG_RX: Data Toggle, for reception transfers + // For non-isosync xfrs this bit contains Data0/1 expectation of next data packet + // Hardware toggles this bit after ACK'ing the host from successful PID match + // For control EPs HW clears this bit after receiving SETUP PID + // For double buffered, or isosync EPs this bit has other meanings + // Software can toggle this value by writting a 1, writting 0 has no effect. + // -This is manditory for non-control EPs! + // USE: For control endpoints: Seems this bit can be used to determine if upcoming xfr is DATA0/1 + // Shouldn't have to do/care much with this bit for control endpoints + // write 1 to toggle, write 0 to leave as-is + // + // + //Bits 13:12 STAT_RX [1:0]: Status bits, for reception transfers + // 00: Disabled, all reception requests to this EP are ignored (default post-reset) + // 01: Stall, EP is stalled and all reception requests will get STALL handshake + // 10: NAK, all reception requests will get NAK handshake + // 11: Valid, this endpoint is enabled for reception + // Hardware sets these bits to NAK after successful OUT/SETUP xfr + // Software can toggle these bits by writting a 1, writting 0 has no effect + // USE: to enable the endpoint toggle these bits to set. HW will clear bit12 when xfr is recieved. + // That way subsequent xfrs will get NAK'd until software processes EP and ready's it for another. + // Once processed toggle back to VALID so next xfr can occur + // write 1 to toggle, write 0 to leave as-is + // + // + //Bit 11 SETUP: Setup transaction completed + // This bit is read-only and indicates if last completed transaction was a SETUP. + // This bit only gets set for control endpoints. It remains set while CTR_RX is set. + // USE: For control EPs read this bit to determine if received xfr is SETUP or OUT. + // writes have no effect, read only + // + //Bits 10:9 EP_TYPE[1:0]: Endpoint type + // 00: BULK + // 01: CONTROL + // 10: ISO + // 11: INTERRUPT + // EP0 must always be CONTROL and always available (set by address==0) + // USE: set these bits to desired endpoint type. Hardware uses these bits to dictate it's behavior. + // bits are read/write, RMW to leave as is + // + //Bit 8 EP_KIND: Endpoint kind + // BULK: DBL_BUF, this bit is set by software to indicate double buffered EP + // CONTROL: STATUS_OUT, this bit is set by software to indicate that STATUS_OUT is expected. + // This will cause all OUT transactions with more than zero data bytes to be STALL'd instead of ACK. + // When clear, OUT transactions of any data length will be allowed. + // ISO/INT: unused + // USE: set for BULK EPs if want to double buffer the endpoint + // set for CONTROL EPs for robustness, when a STATUS_OUT is expected and want non-zero data to be STALL'd + // Think we can get by ignoring this bit for now + // bit is read/write, RMW to leave as-is + // + //Bit 7 CTR_TX: Correct Transfer for transmission + // Similar to CTR_RX, but for transmissions. Hardware sets this bit on successful transmission completion. + // This won't get set if transfer failed. Software can only write this bit to 0. + // USE: read this bit after interrupt to determine if source of interrupt was due to successful transmission. + // process what's needed for upcoming transmission if needed, and clear this bit to subsequent interrupts + // will be properly detected. + // write 0 to clear, write 1 to leave as-is + // + // + //Bit 6 DTOG_TX: Data Toggle, for transmission transfers + // Similar to DTOG_RX, but for transmissions. Hardware toggles this bit after an ACK of data transmit. + // For control EPs HW sets this bit at reception of SETUP PID + // For double buffered, and iso EPs this bit has different functions + // Software can toggle this bit by writting a 1, writting 0 is ignored. Required for non-control EPs + // USE: should be able to ignore for control EPs. + // To leave as-is write a 0. + // + //Bits 5:4 STAT_TX [1:0]: Status bits, for transmission transfers + // 00: Disabled, all transmission requests to this EP are ignored (default post-reset) + // 01: Stall, EP is stalled and all transmission requests will get STALL handshake + // 10: NAK, all transmission requests will get NAK handshake + // 11: Valid, this endpoint is enabled for transmission + // Hardware changes these bits from Valid to NAK after successful transmission. + // That way subsequent transmit requests will be NAK'd until software can prepare the next one. + // These bits will toggle when wrote to with a 1, writting a 0 doesn't affect them. + // USE: Toggle the bits to Valid when data has been loaded into buffer and ready for transmission. + // write 1 to toggle, write 0 to leave as-is + // + //Bits 3:0 EA[3:0]: Endpoint address + // Software must write the address to these bits to enable the endpoint. + // USE: set these bits to the "endpoint number" ie 0 for EP0, 1 for EP1, etc. + // These default to 0, so post reset all USB_EPnR are set to be EP0. + // But because nothing is initialized they'll all ignore anything going on. + // bits are read/write, RMW to leave as is + + //Reset done, now setup as if USB reset has occured + //USB reset (RESET interrupt) + //When this event occurs, the USB peripheral is put in the same conditions it is left by the system + //reset after the initialization described in the previous paragraph: communication is disabled in all + //endpoint registers (the USB peripheral will not respond to any packet). + //As a response to the USB reset event, the USB function must be enabled, having as USB address 0, + //implementing only the default control endpoint (endpoint address is 0 too). + //This is accomplished by setting the Enable Function (EF) bit of the USB_DADDR register and + //initializing the EP0R register and its related packet buffers accordingly. + // + //During USB enumeration process, the host assigns a unique address to this device, + //which must be written in the ADD[6:0] bits of the USB_DADDR register, and configures any other necessary endpoint. + //When a RESET interrupt is received, the application software is responsible to enable again + //the default endpoint of USB function 0 within 10 ms from the end of reset sequence which triggered the interrupt. + + //clear any pending interrupts + USB->ISTR = 0; + + //initialize EP specific register for EP0 as CONTROL and ready for RX of any OUT + //assuming reset condition with all bits clear, except CTR_RX/TX holding prior to reset value + USB->EP0R = (uint16_t) (USB_EP_RX_VALID | USB_EP_CONTROL | USB_EP_TX_NAK); + //clears CTR_RX/TX bits, ready to recieve, transmit disabled, sets to control type, expect any out, set addr to EP0 + // + + + +} + + +//Create pointer to 16bit array with 512 entries (1024Bytes) +//can only be accessed in byte or half words, not full 32bit words! +//uint16_t volatile (* const usb_buff)[512] = (void*)USB_PMAADDR; +//this was suggestion by: http://a3f.at/articles/register-syntax-sugar +//which errors on compilation due to assigning of type array +uint16_t volatile (* const usb_buff) = (void*)USB_PMAADDR; + + +//#define TSSOP20 //defined when using TSSOP-20 part to get PA11/12 alternate mapping to the pins + +void init_usb() +{ + + + //initialize i/o + // TSSOP-20: On STM32F070x6 devices, pin pair PA11/12 can be remapped instead of pin pair PA9/10 using SYSCFG_CFGR1 register. +#ifdef TSSOP20 + //by default PA9/10 are configured to pins 17/18, have to set bits to map PA11/12 which contain USB PHY + SYSCFG->CFGR1 |= PA11_PA12_RMP; +#endif + // + // ensure GPIO bank A is enabled after the discussion below, I'm not even sure this is needed.. +// RCC->AHBENR |= (uint32_t) (1<APB1RSTR |= RCC_APB1RSTR_USBRST; //reset +// RCC->APB1RSTR &= ~RCC_APB1RSTR_USBRST; //release reset + + + //Sections copied from reference manual + //As a first step application software needs to activate register macrocell clock and de-assert + //macrocell specific reset signal using related control bits provided by device clock management logic. + // + //clock was already done in init_usb_clk function. + //de-assert translates to set reset high I believe, but I'm still not sure I understand. + //The next section talks about removing the reset condition with FRES/CNTR reg, but that can't be done yet. + //So I think it's just covering bases to say the RCC_APB1RSTR register can't be set "in reset condition" + //Actually I think this section of the datasheet is referring to how the first thing a host does once + //a device is detected is send it a reset condition (lack of SOF packets) and as this code is being ran that + //has yet to occur. So we need to set things up to expect the first "USB command" to be recieved via the cable + //as reset which equates to enabling the reset interrupt and having it call reset recovery routine. + + //After that, the analog part of the device related to the USB transceiver must be + //switched on using the PDWN bit in CNTR register, which requires a special handling. + USB->CNTR &= ~USB_CNTR_PDWN; //default is set, clear to power up USB + + //This bit is intended to switch on the internal voltage references that supply the port transceiver. + //This circuit has a defined startup time (tSTARTUP specified in the datasheet) tSTARTUP = 1usec + //during which the behavior of the USB transceiver is not defined. + int delay = 0; + for( delay = 0; delay < 48; delay++ ){ + //16Mhz = 62.5nsec clock, 1usec = 1Mhz + //need 16 clocks to delay 1usec this loop will take a few instruction cycles at least + //Perhaps this code will be ran while the core is running at 48Mhz + //So future proof by waiting 3 times as long + } + + //It is thus necessary to wait this time, after setting the PDWN bit in the CNTR register, + //before removing the reset condition on the USB part (by clearing the FRES bit in the CNTR register). + USB->CNTR &= ~USB_CNTR_FRES; //default set, clear to remove reset + + //Clearing the ISTR register then removes any spurious pending interrupt before any other macrocell operation is enabled. + //Entire register is read, or clear by writing 0. + USB->ISTR = 0; + + //At system reset, the microcontroller must initialize all required registers and the packet buffer description table, + //to make the USB peripheral able to properly generate interrupts and data transfers. + // + //Structure and usage of packet buffers + //Each bidirectional endpoint may receive or transmit data from/to the host. The received data + //is stored in a dedicated memory buffer reserved for that endpoint, while another memory + //buffer contains the data to be transmitted by the endpoint. Access to this memory is + //performed by the packet buffer interface block, which delivers a memory access request + //and waits for its acknowledgment. Since the packet buffer memory has to be accessed by + //the microcontroller also, an arbitration logic takes care of the access conflicts, using half + //APB cycle for microcontroller access and the remaining half for the USB peripheral access. + //In this way, both the agents can operate as if the packet memory is a dual-port SRAM, + //without being aware of any conflict even when the microcontroller is performing back-to- + //back accesses. The USB peripheral logic uses a dedicated clock. The frequency of this + //dedicated clock is fixed by the requirements of the USB standard at 48 MHz, and this can be + //different from the clock used for the interface to the APB bus. Different clock configurations + //are possible where the APB clock frequency can be higher or lower than the USB peripheral + //one. + // + //Note: Due to USB data rate and packet memory interface requirements, the APB clock must have a minimum + //frequency of 10 MHz to avoid data overrun/underrun problems. + // + //Each endpoint is associated with two packet buffers (usually one for transmission and the + //other one for reception). Buffers can be placed anywhere inside the packet memory + //because their location and size is specified in a buffer description table, which is also + //located in the packet memory at the address indicated by the USB_BTABLE register. + // + //Each table entry is associated to an endpoint register and it is composed of four 16-bit half-words + //so that table start address must always be aligned to an 8-byte boundary (the lowest three + //bits of USB_BTABLE register are always "000"). Buffer descriptor table entries are + //described in the Section30.6.2: Buffer descriptor table. If an endpoint is unidirectional and it + //is neither an Isochronous nor a double-buffered bulk, only one packet buffer is required + //(the one related to the supported transfer direction). Other table locations related to unsupported + //transfer directions or unused endpoints, are available to the user. Isochronous and double- + //buffered bulk endpoints have special handling of packet buffers (Refer to Section 30.5.4: + //Isochronous transfers and Section 30.5.3: Double-buffered endpoints respectively). The + //relationship between buffer description table entries and packet buffer areas is depicted in Figure323. + // + //Each packet buffer is used either during reception or transmission starting from the bottom. + //The USB peripheral will never change the contents of memory locations adjacent to the + //allocated memory buffers; if a packet bigger than the allocated buffer length is received + //(buffer overrun condition) the data will be copied to the memory only up to the last available + //location. + // + //Buffer descriptor table + //Although the buffer descriptor table is located inside the packet buffer memory, its entries + //can be considered as additional registers used to configure the location and size of the + //packet buffers used to exchange data between the USB macro cell and the device. + //The first packet memory location is located at 0x40006000. The buffer descriptor table + //entry associated with the USB_EPnR registers is described below. The packet memory + //should be accessed only by byte (8-bit) or half-word (16-bit) accesses. Word (32-bit) accesses are not allowed. + // + //Buffer table address (USB_BTABLE) this is the address of the buffer table which is contained in the 1KB of RAM itself + //By default this value is set to zero, that's what I would have choosen anyway, so doesn't need initialized + //But let's go ahead and do it so it's easy to move later if needed and gives us defines to use for addressing + USB->BTABLE = USB_BTABLE_BASE; + + + //Endpoint initialization + //The first step to initialize an endpoint is to write appropriate values to the ADDRn_TX/ADDRn_RX registers + //so that the USB peripheral finds the data to be transmitted already available and the data to be received can be buffered. + //The EP_TYPE bits in the USB_EPnR register must be set according to the endpoint type, eventually using + //the EP_KIND bit to enable any special required feature. + //On the transmit side, the endpoint must be enabled using the STAT_TX bits in the USB_EPnR register + //and COUNTn_TX must be initialized. + //For reception, STAT_RX bits must be set to enable reception and COUNTn_RX must be written with + //the allocated buffer size using the BL_SIZE and NUM_BLOCK fields. + + //only setup endpoint zero buffers for now that's all that's required to satisfy USB and get started + usb_buff[USB_ADDR0_TX] = EP0_TX_ADDR; + //TX count is set to the number of bytes to xfr in next packet + //usb_buff[USB_COUNT0_TX] = EP0_SIZE; + usb_buff[USB_ADDR0_RX] = EP0_RX_ADDR; + //RX count is made up of 3 parts + //the MSB is block size 0->2Bytes, 1->32Bytes + //bit 14:10 is number of blocks + //end point size = block size * num blocks + //bits 9:0 are set by USB block based on actual count received + //usb_buff[USB_COUNT0_RX] = (uint16_t) ((BL_SIZE2) | ((EP0_SIZE/2)<CNTR |= (USB_CNTR_CTRM | USB_CNTR_PMAOVRM | USB_CNTR_ERRM | USB_CNTR_WKUPM | +// USB_CNTR_SUSPM | USB_CNTR_RESETM | USB_CNTR_SOFM | USB_CNTR_ESOFM | USB_CNTR_L1REQM ); + USB->CNTR |= ( USB_CNTR_RESETM ); + //USB control register (USB_ISTR) will indicate what endpoint and direction created the interrupt + //Apparently you don't even need to set the CTRM interrupt as it's not of much use + //The EP0R register creates it's own interrupt which is always enabled upon completion of transfer + //The ITSR is still useful for determining which EP and dir of transfer that occured. + //Having the reset interrupt is vital as apparently the first thing that occurs over the USB bus is a reset. + //Not sure if that's caused by the host intentionally, or just the nature of hot plugging where some + //SOF's are missed during the mating of the connectors or what. Banged my head for awhile till actually + //serviced the reset interrupt as needed + + //Battery charging detector (USB_BCDR) + //Bit 15 DPPU: DP pull-up control + //This bit is set by software to enable the embedded pull-up on the DP line. Clearing it to Î÷Îõ0ÎéÎ÷ + //can be used to signalize disconnect to the host when needed by the user software. + //all other bits have to do with battery charging which is off by default + // + //Enable the data plus pull up resistor to signal to host that USB device is connected + USB->BCDR = USB_BCDR_DPPU; +} + + + + +static uint16_t num_bytes_req; +static uint16_t num_bytes_sending; +static uint16_t num_bytes_expecting; +static uint16_t num_bytes_xfrd; +static uint8_t req_dir; +uint16_t *usbMsgPtr; + +//function gets called after reception of setup packet for IN transfer, +//and each time an interrupt for successful data tx from control EP +//So it's as if this function gets called *AFTER* each transmission +//Therefore it's task is to prep the next transmission should there be one needed +//If we don't need another transmission, prepare to receive status from host +//currently hardcoded for EP0 only +//num_bytes_sending, num_bytes_xfrd, and *usbMsgPtr must be initialized prior to entry + +static void control_xfr_in(){ + //determine if have data remaining to be sent + +// We should never get to this point, if we did there was an error and should prob send STALL +// if ( num_bytes_xfrd == num_bytes_sending ) { +// //no more data to send +// //wrap up transfer and prep endpoint for next setup packet +// // +// //While enabling the last data stage, the opposite direction should be set to NAK, so that, if +// //the host reverses the transfer direction (to perform the status stage) immediately, it is kept +// //waiting for the completion of the control operation. If the control operation completes +// //successfully, the software will change NAK to VALID, otherwise to STALL. At the same time, +// //if the status stage will be an OUT, the STATUS_OUT (EP_KIND in the USB_EPnR register) +// //bit should be set, so that an error is generated if a status transaction is performed with not- +// //zero data. When the status transaction is serviced, the application clears the STATUS_OUT +// //bit and sets STAT_RX to VALID (to accept a new command) and STAT_TX to NAK (to delay +// //a possible status stage immediately following the next setup). +// +// return; +// } + + //copy over 8bytes from transmit data to EP0 buffer + //copy data into EP0 buffer table ram + //usb buffer ram is only accessible in halfwords/bytes (16/8bits) + usb_buff[EP0_TX_BASE] = usbMsgPtr[num_bytes_xfrd/2]; + num_bytes_xfrd += 2; + usb_buff[EP0_TX_BASE+1] = usbMsgPtr[num_bytes_xfrd/2]; + num_bytes_xfrd += 2; + usb_buff[EP0_TX_BASE+2] = usbMsgPtr[num_bytes_xfrd/2]; + num_bytes_xfrd += 2; + usb_buff[EP0_TX_BASE+3] = usbMsgPtr[num_bytes_xfrd/2]; + num_bytes_xfrd += 2; + + //if there aren't 8bytes of data to send, junk will be copied into end of EP0 TX buffer + //to correct for this, simply set tx count to amount of good data + if ( num_bytes_xfrd > num_bytes_sending ) { + //set tx count to number of bytes we actually want to send + usb_buff[USB_COUNT0_TX] = EP0_SIZE - (num_bytes_xfrd - num_bytes_sending); + //stop lying about how many bytes will be sent + num_bytes_xfrd = num_bytes_sending; + } else if ( num_bytes_req < num_bytes_xfrd ) { + //set tx count to number bytes requested since host didn't want everything + usb_buff[USB_COUNT0_TX] = EP0_SIZE - (num_bytes_xfrd - num_bytes_req); + num_bytes_xfrd = num_bytes_req; + } else { + //update tx count + usb_buff[USB_COUNT0_TX] = EP0_SIZE; + } + +// if (num_bytes_xfrd == num_bytes_sending ) { +// //expect next token to be OUT STATUS zero data length from host to end transaction +// //setting EP_KIND to STATUS_OUT: +// //STATUS_OUT: This bit is set by the software to indicate that a status out transaction is +// //expected: in this case all OUT transactions containing more than zero data bytes are +// //answered "STALL" instead of "ACK". This bit may be used to improve the robustness of the +// //application to protocol errors during control transfers and its usage is intended for control +// //endpoints only. When STATUS_OUT is reset, OUT transactions can have any number of +// //bytes, as required. +// +// //Don't really feel like doing this on only the last packet, and really should be fine without it. +// //The host doesn't always take all the data it asks for in the setup packet, sometimes it simply +// //sends an OUT in the midst of large IN xfr asking the device to end current transfer +// //This seems like something we should just do during init of SETUP with IN xfr to follow. +// } + + + //setup EP0R for transmit + USB_EP0R_TX_VALID(); + + return; +} + + //Need to decode the setup packet to determine what type of standard request was made + //Beyondlogic.com's USB in a nutshell is the best resource for this stuff: + //http://www.beyondlogic.org/usbnutshell/usb6.shtml + // + // + //STANDARD DEVICE REQUESTS + //bmRequestType bRequest (1Byte) wValue (2Bytes) wIndex (2Bytes) wLength (2Bytes) Data(based on SETUP) + //1000 0000b GET_STATUS (0x00) Zero Zero Two Device Status +#define STD_REQ_GET_STATUS 0x00 + //0000 0000b CLEAR_FEATURE (0x01) Feature Selector Zero Zero None +#define STD_REQ_CLEAR_FEATURE 0x01 + //0000 0000b SET_FEATURE (0x03) Feature Selector Zero Zero None +#define STD_REQ_SET_FEATURE 0x03 + //0000 0000b SET_ADDRESS (0x05) Device Address Zero Zero None +#define STD_REQ_SET_ADDRESS 0x05 + //1000 0000b GET_DESCRIPTOR (0x06) Descriptor Type & Index Zero or Language ID Descriptor Length Descriptor +#define STD_REQ_GET_DESCRIPTOR 0x06 + //0000 0000b SET_DESCRIPTOR (0x07) Descriptor Type & Index Zero or Language ID Descriptor Length Descriptor +#define STD_REQ_SET_DESCRIPTOR 0x07 + //1000 0000b GET_CONFIGURATION (0x08) Zero Zero 1 Configuration Value +#define STD_REQ_GET_CONFIGURATION 0x08 + //0000 0000b SET_CONFIGURATION (0x09) Configuration Value Zero Zero None +#define STD_REQ_SET_CONFIGURATION 0x09 + // + // + // The Get Status request directed at the device will return two bytes during the data stage with the following format, + // D15 - D2 D1 D0 + // Reserved Remote Wakeup Self Powered + // If D0 is set, then this indicates the device is self powered. If clear, the device is bus powered. If D1 is set, + // the device has remote wakeup enabled and can wake the host up during suspend. The remote wakeup bit can be by the + // SetFeature and ClearFeature requests with a feature selector of DEVICE_REMOTE_WAKEUP (0x01) + // + // Clear Feature and Set Feature requests can be used to set boolean features. When the designated recipient is the device, + // the only two feature selectors available are DEVICE_REMOTE_WAKEUP and TEST_MODE. Test mode allows the device to exhibit + // various conditions. These are further documented in the USB Specification Revision 2.0. + // + // + // Set Descriptor/Get Descriptor is used to return the specified descriptor in wValue. A request for the configuration + // descriptor will return the device descriptor and all interface and endpoint descriptors in the one request. + // Endpoint Descriptors cannot be accessed directly by a GetDescriptor/SetDescriptor Request. + // Interface Descriptors cannot be accessed directly by a GetDescriptor/SetDescriptor Request. + // String Descriptors include a Language ID in wIndex to allow for multiple language support. + // + // Get Configuration/Set Configuration is used to request or set the current device configuration. In the case of a + // Get Configuration request, a byte will be returned during the data stage indicating the devices status. A zero value + // means the device is not configured and a non-zero value indicates the device is configured. + // Set Configuration is used to enable a device. It should contain the value of bConfigurationValue of the desired + // configuration descriptor in the lower byte of wValue to select which configuration to enable. + // + +//void control_xfr_out(uint16_t len){ +// +// usbFunctionWrite( +// +//} + +//flag and value, since can't change address until after STATUS stage, must use this value +//to denote that the USB device address needs updated after the status stage. +static uint8_t new_address = 0; + + +//return number of bytes expected +static uint16_t standard_req_out( usbRequest_t *spacket ){ + + switch ( spacket->bRequest ) { + + //STANDARD DEVICE REQUESTS + //bmRequestType bRequest (1Byte) wValue (2Bytes) wIndex (2Bytes) wLength (2Bytes) Data(based on SETUP) + //0000 0000b CLEAR_FEATURE (0x01) Feature Selector Zero Zero None + case STD_REQ_CLEAR_FEATURE: + break; + + //0000 0000b SET_FEATURE (0x03) Feature Selector Zero Zero None + case STD_REQ_SET_FEATURE: + break; + + //0000 0000b SET_ADDRESS (0x05) Device Address Zero Zero None + // Set Address is used during enumeration to assign a unique address to the USB device. The address is specified in wValue + // and can only be a maximum of 127. This request is unique in that the device does not set its address until after the + // completion of the status stage. (See Control Transfers.) All other requests must complete before the status stage. + case STD_REQ_SET_ADDRESS: + new_address = spacket->wValue; + usb_buff[LOG0] = new_address; + return 0; + break; + + //0000 0000b SET_DESCRIPTOR (0x07) Descriptor Type & Index Zero or Language ID Descriptor Length Descriptor + case STD_REQ_GET_CONFIGURATION: + break; + + //0000 0000b SET_CONFIGURATION (0x09) Configuration Value Zero Zero None + case STD_REQ_SET_CONFIGURATION: + break; + + default: + //ERROR send STALL? + break; + + } + + + +} + +static uint16_t standard_req_in( usbRequest_t *spacket ){ + + switch ( spacket->bRequest ) { + + //STANDARD DEVICE REQUESTS + //bmRequestType bRequest (1Byte) wValue (2Bytes) wIndex (2Bytes) wLength (2Bytes) Data(based on SETUP) + //1000 0000b GET_STATUS (0x00) Zero Zero Two Device Status + case STD_REQ_GET_STATUS: + break; + + //1000 0000b GET_DESCRIPTOR (0x06) Descriptor Type & Index Zero or Language ID Descriptor Length Descriptor + case STD_REQ_GET_DESCRIPTOR: + switch ( (spacket->wValue & DESC_TYPE_MASK)>>8) { //must mask out upper byte and shift to get desc type + case DESC_TYPE_DEVICE: + usbMsgPtr = (uint16_t *)device_desc; + return device_desc[bLength]; + case DESC_TYPE_CONFIG: //Must return all config, interface, and endpoint descriptors in one shot + usbMsgPtr = (uint16_t *)config_desc; + return config_desc[wTotalLength]; + case DESC_TYPE_STRING: + //determine which string index + switch ( spacket->wValue & DESC_IDX_MASK ) { //Must mask out index from lower byte + case 0: usbMsgPtr = (uint16_t *)string0_desc; + return string0_desc[bLength]; + case 1: usbMsgPtr = (uint16_t *)string1_desc; + return string1_desc[bLength]; + case 2: usbMsgPtr = (uint16_t *)string2_desc; + return string2_desc[bLength]; + default: //error send stall + return 0; + } + // interface and endpoint descriptors can't be accessed directly, get them via config desc + // case DESC_TYPE_INTERFACE: + // usbMsgPtr = (uint16_t *)interface_desc; + // return interface_desc[bLength]; + // case DESC_TYPE_ENDPOINT: + // usbMsgPtr = (uint16_t *)endpoint_desc; + // return endpoint_desc[bLength]; + default: + //TODO error send stall + return 0; + } + + //1000 0000b GET_CONFIGURATION (0x08) Zero Zero 1 Configuration Value + case STD_REQ_GET_CONFIGURATION: + break; + + } + + //just return device descriptor for now + + +} + +//USB IRQ handler calls this function after recieving a control setup packet +//function is responsible for preparing follow on data/status transfers to complete control xfr +//must set everything up for control_xfr_in/out functions to be called during data packets +static void control_xfr_init( usbRequest_t *spacket ) { + + //determine number of requested data payload bytes + num_bytes_req = spacket->wLength; + num_bytes_xfrd = 0; + + //Vusb calls usbFunctionSetup which sets usbMsgPtr to point to IN data array + //and returns length of data to be returned. + //Vusb needs nothing else for IN transfers as it already has the data + //Vusb calls usbFunctionWrite for OUT xfr on subsequent of data packet arrival (8bytes max) + + //if data is IN (tx) need to aquire pointer to data that we'd like to transmit + //don't think we'll get a zero data length IN as that would mean the host sends all packets + //I suppose this is possible for poorly written host application..? + //Vusb had option to provide function that would be called for each IN data packet + //I found that to be slow and best avoided, so not going to bother supporting that for now.. + //Also need to get amount of data that the device would like to return, possible the + //device has less data to send back than requested in wLength. + + +/*USB_PUBLIC usbMsgLen_t usbFunctionSetup(uchar data[8]); + * If the SETUP indicates a control-in transfer, you should provide the + * requested data to the driver. There are two ways to transfer this data: + * (1) Set the global pointer 'usbMsgPtr' to the base of the static RAM data + * block and return the length of the data in 'usbFunctionSetup()'. The driver + * will handle the rest. Or (2) return USB_NO_MSG in 'usbFunctionSetup()'. The + * driver will then call 'usbFunctionRead()' when data is needed. See the + * documentation for usbFunctionRead() for details. + * + * If the SETUP indicates a control-out transfer, the only way to receive the + * data from the host is through the 'usbFunctionWrite()' call. If you + * implement this function, you must return USB_NO_MSG in 'usbFunctionSetup()' + * to indicate that 'usbFunctionWrite()' should be used. See the documentation + * of this function for more information. If you just want to ignore the data + * sent by the host, return 0 in 'usbFunctionSetup()'. + */ + //setup packets not handled by standard requests sent to usbFunctionSetup (just like Vusb) + if ((spacket->bmRequestType & REQ_TYPE) != REQ_TYPE_STD) { + //function must set usbMsgPtr to point to return data for IN transfers + num_bytes_sending = usbFunctionSetup( (uint8_t*) spacket ); + } + + + if ( (spacket->bmRequestType & REQ_DIR) == REQ_DIR_IN ) { + //IN transfer Host wants us to send data (tx) + switch ( spacket->bmRequestType & REQ_TYPE ) { + case REQ_TYPE_STD: + num_bytes_sending = standard_req_in( spacket ); + break; + // case REQ_TYPE_CLASS: + // num_bytes_sending = 0;//class_req_in( spacket ); + // break; + // case REQ_TYPE_VEND: + // num_bytes_sending = 0;//vendor_req_in( spacket ); + // break; + // case REQ_TYPE_RES: + // default: + // num_bytes_sending = 0; + // break; + } + //A USB device can determine the number and + //direction of data stages by interpreting the data transferred in the SETUP stage, and is + //required to STALL the transaction in the case of errors. To do so, at all data stages before + //the last, the unused direction should be set to STALL, so that, if the host reverses the + //transfer direction too soon, it gets a STALL as a status stage. + // + //WRONG!!! This ended up being a shot in the foot. The VERY first request from the host is a + //SETUP device descriptor request for 16KBytes worth of data!! + //HOWEVER, the host tells us the device to shut it's mouth after the first data stage as if + //it doesn't want any more info by sending a STATUS state (OUT xfr expecting zero data) + //So we need to be ready for this condition and be prepared to recieve a STATUS OUT zero data "shutup" command + //Maybe this is only an issue for standard type requests during enumeration..? + // + //Need to set RX to stall it should be NAK right now + + //TODO decide if want to set EP_KIND to STATUS_OUT during this time. I don't think there is much benefit + //currently and will cause more hassle than it's worth currently, since have to ensure it's clear for other OUT xfrs + USB_EP0R_RX_VALID_STATUS_OUT(); + + //TODO decide if want to set EP0_RX_COUNT to 0 so we can only receive STATUS OUT with zero data, however that + //is effectively what EP_KIND= STATUS_OUT is intended for.. I don't think RX count matters since it can't overflow + + //Now we've got the pointer to return data initialized + //and number of bytes the firmware would like to return + control_xfr_in(); + + } else { + //OUT transfer Host is sending us data (rx) + //if data is OUT (rx) need a function pointer of what to call when data is received + //or if there is no data stage, we just need to send status packet + + //num_byte_req contains number of bytes expected to be transferred in upcoming OUT xfrs + + switch ( spacket->bmRequestType & REQ_TYPE ) { + case REQ_TYPE_STD: + num_bytes_expecting = standard_req_out( spacket ); + break; + // case REQ_TYPE_CLASS: + // //num_bytes_sending = 0;//class_req_in( spacket ); + // //break; + // case REQ_TYPE_VEND: + // //num_bytes_sending = 0;//vendor_req_in( spacket ); + // //num_bytes_sending = usbFunctionSetup( spacket ); + // break; + // case REQ_TYPE_RES: + // default: + // //num_bytes_sending = 0; + // break; + } + + //Clear EP_KIND so OUT transfers of any length are accepted + USB_EP0R_EP_KIND_ANY(); + + //TODO if there is no DATA stage, then we expect the next token to be IN + //in which case device need to be prepared to send IN transfer of zero data length + + //prepare IN STATUS packet of zero length + usb_buff[USB_COUNT0_TX] = 0; + //enable any packet + USB_EP0R_RXTX_VALID(); + + + + //control_xfr_out(); + } + +} + + + + +//This is the ISR that gets called for USB interrupts + //At the end of the transaction, an endpoint-specific interrupt is generated, reading status registers + //and/or using different interrupt response routines. The microcontroller can determine: + // -which endpoint has to be served, + // -which type of transaction took place, if errors occurred (bit stuffing, format, CRC, + // protocol, missing ACK, over/underrun, etc.). + + //USB interrupt status register (USB_ISTR) + //This register contains the status of all the interrupt sources allowing application + //software to determine, which events caused an interrupt request. +void USB_IRQHandler(void) +{ + + //all interrupts enabled by USB_CNTR, plus any successful rx/tx to an endpoint triggers this ISR + + //should be our goal to get out of this ISR asap, signal the transaction to the main thread + //and let the main thread process the data. + //That isn't really how V-usb is setup which we're looking to replace and be compatible with for starters. + //So for now this isn't going to be setup ideally, but if USB is our top priority then maybe it's not so bad.. + + //Plan is to determine source of interrupt + //Service what's needed for the interrupt + //Clear the pending/active interrupts which have been serviced + //If there are other interrupts occuring simulateously we don't have to catch em all + // they'll trigger this ISR again + //Return from interrupt + + //First check for successful transfer of USB packets + //High level we can determine this by USB_ISTR: + // CTR:set if correct transfer occured (read only, cleared via the EP) + // DIR: 0-TX, 1-RX + // EP_ID[3:0]: endpoint that triggered the interrupt with following priority: + // -isosync & double-buffered bulk are considered first getting hi pri + // -then EPnR register number ie EP0R gets priority over EP2R + // NOTE: you can put whatever endpoint number in whichever register you choose + // endpoint0 doesn't have to go in EP0R register, the endpoint number is programmable! + // would probably make more sense if they used letters to define EPnR registers.. + //Low level we don't have to use EP_ID's priority assignments we could just check EPnR CTR_RX/TX bits + //Kinda like EP_ID though as it allows us to focus on a single EP for the given ISR call + + //CAUTION!!! usb_buff data can only be accessed in half words, or bytes. No 32bit accesses!!! + + usbRequest_t *setup_packet; + uint8_t endpoint_num; + + + //only have EP0 for now + + //check for OUT/SETUP + if ( USB->EP0R & USB_EP_CTR_RX ) { + + + //clear RX interrupt leave everything else unaffected, reference manual says this should be the first thing + //we do, but with control endpoints, any subsequent SETUP will stomp over the prior one if CTR_RX is clear + //It'll stomp it even if STAT is set to STALL/NAK, setting to DISABLE is only way to prevent it.. + //If last setup data is vital to maintain it should be stored more permanently somewhere besides buffer ram. + EP0R_CLR_CTR_RX(); + //Note: clearing CTR_RX on a control EP, is enough for another setup packet to be accepted + //this is true even if STAT_RX is STALL/NAK, so if the data needs retained it must be copied + //elsewhere, or set STAT_RX to DISABLED to keep it from being stomped by the next setup + + if ( USB->EP0R & USB_EP_SETUP ) { //SETUP packet + log ++; //inc log for each setup packet used for debugging purposes to trigger logic analyzer at desired packet +#define LOG_COUNT 3 +// if ( log >= LOG_COUNT) { DEBUG_HI(); DEBUG_LO(); } +//usb_buff[LOG0] = USB->EP0R; + //set pointer to usb buffer, type ensures 8/16bit accesses to usb_buff + setup_packet = (void*) &usb_buff[EP0_RX_BASE]; + req_dir = (setup_packet->bmRequestType & REQ_DIR); //set to REQ_DIR_IN/OUT for data stage dir + control_xfr_init( setup_packet ); + + } else { //OUT packet +// if ( log >= LOG_COUNT) { DEBUG_HI(); DEBUG_LO(); } + //number of bytes received is denoted in USB_COUNTn_RX buffer table + //control_xfr_out(); + usbFunctionWrite((uint8_t*) &usb_buff[EP0_RX_BASE], (usb_buff[USB_COUNT0_RX] & RX_COUNT_MSK)); + } + + + } else if ( USB->EP0R & USB_EP_CTR_TX ) { //IN packet +// if ( log >= LOG_COUNT) { DEBUG_HI(); DEBUG_LO(); } +//DEBUG_HI(); DEBUG_LO(); + // log ++; + //LED_ON(); + // if (log >= 2) { + // LED_ON(); + // } + //Servicing of the CTR_TX event starts clearing the interrupt bit; + +//usb_buff[LOG4] = USB->EP0R; + //clear TX interrupt + EP0R_CLR_CTR_TX(); + //USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX) //set rx field to keep from accidentally clearing + // & USB_EPREG_MASK ) //mask out toggle feilds making them zero + // & ~USB_EP_CTR_TX ); //clear tx bit removing active interrupt + +// LED_ON(); +//usb_buff[LOG8] = USB->EP0R; + + //the application software then prepares another buffer full of data to be sent, + //updates the COUNTn_TX table location with the number of byte to be transmitted during the next transfer, + //and finally sets STAT_TX to 11 (VALID) to re-enable transmissions. + //this is only done if the IN transfer had data, if there was no data, it was a status stage + //if ( (usb_buff[USB_COUNT0_RX] & RX_COUNT_MSK) != 0 ) { + if ( req_dir == REQ_DIR_IN ) { + control_xfr_in(); + } else { + //OUT request, IN denotes STATUS stage + + //check if USB device address needs set must be after completion of STATUS stage + if (new_address) { + USB->DADDR = (new_address | USB_DADDR_EF); //update address and keep USB function enabled + new_address = 0; //clear flag value so don't come back here again + //LED_ON(); + } + } + +//usb_buff[LOGC] = USB->EP0R; +//usb_buff[LOG10] = log; + //While the STAT_TX bits are equal to 10 (NAK), any IN request addressed to that endpoint is NAKed, + //indicating a flow control condition: the USB host will retry the transaction until it succeeds. + //It is mandatory to execute the sequence of operations in the above mentioned order to avoid losing the + //notification of a second IN transaction addressed to the same endpoint immediately following the one + //which triggered the CTR interrupt. + + //I wasn't doing things in this order thinking that explains why I can't get a second transfer out + + } + + if ( USB->ISTR & USB_ISTR_RESET ) { //USB reset event occured + //Anytime a reset condition occurs, the EPnR registers are cleared + //Must re-enable the USB function and setup EP0 after any reset condition within 10msec + usb_reset_recovery(); + //handled in reset recovery: USB->ISTR &= ~USB_ISTR_RESET; + } + +} + diff --git a/firmware/source_stm_only/usbstm.h b/firmware/source_stm_only/usbstm.h new file mode 100644 index 0000000..a7e1c56 --- /dev/null +++ b/firmware/source_stm_only/usbstm.h @@ -0,0 +1,249 @@ +#ifndef _usbstm_h +#define _usbstm_h + + +//include target chip port definition library files +#include + + +//clear RX interrupt +//set tx field to keep from accidentally clearing //mask out toggle feilds making them zero //clear rx bit removing active interrupt +#define EP0R_CLR_CTR_RX() USB->EP0R = (((USB->EP0R | USB_EP_CTR_TX) & USB_EPREG_MASK ) & ~USB_EP_CTR_RX ) + +//clear TX interrupt +#define EP0R_CLR_CTR_TX() USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX) & USB_EPREG_MASK ) & ~USB_EP_CTR_TX ) + +//VALID need to get both status bits set +//XOR the current value of status bits with 1 to write back inverted value, gets all status bits set +// OR in bits that need set, AND in bits to keep or avail for XOR, XOR toggles to invert +#define USB_EP0R_RXTX_VALID() USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & ~(USB_EP_DTOG_RX | USB_EP_DTOG_TX)) ^ (USB_EPTX_STAT | USB_EPRX_STAT)) +#define USB_EP0R_RX_VALID() USB->EP0R = ((((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX)) & (USB_EPREG_MASK | USB_EPRX_STAT)) ^ USB_EPRX_STAT ) +#define USB_EP0R_TX_VALID() USB->EP0R = ((((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX)) & (USB_EPREG_MASK | USB_EPTX_STAT)) ^ USB_EPTX_STAT ) +#define USB_EP0R_RX_VALID_STATUS_OUT() USB->EP0R = ((((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX | USB_EP_KIND)) & (USB_EPREG_MASK | USB_EPRX_STAT)) ^ USB_EPRX_STAT ) +#define USB_EP0R_EP_KIND_ANY() USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX)) & (USB_EPREG_MASK & ~USB_EP_KIND)) + +//DISABLE need to get both bits cleared +//write back current value of status bits to toggle all 1's to zeros +// OR in bits that need set AND in bits to keep or toggle from 1 to 0 +#define USB_EP0R_RXTX_DIS() USB->EP0R = ((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & ~(USB_EP_DTOG_RX | USB_EP_DTOG_TX)) +#define USB_EP0R_RX_DIS() USB->EP0R = ((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK | USB_EPRX_STAT)) +#define USB_EP0R_TX_DIS() USB->EP0R = ((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK | USB_EPTX_STAT)) + +//NAK/STALL need to get one bit set, and the other cleared +//Easiest way would be to DISABLE, and then set desired bit, uses two accesses to EP0R +// DISABLE first OR in bits that need set AND in bits to keep or toggle +#define USB_EP0R_RX_NAK() USB_EP0R_RX_DIS(); USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK)) | USB_EP_RX_NAK) +#define USB_EP0R_TX_NAK() USB_EP0R_TX_DIS(); USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK)) | USB_EP_TX_NAK) +#define USB_EP0R_RXTX_NAK() USB_EP0R_RXTX_DIS(); USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK)) | (USB_EP_RX_NAK | USB_EP_TX_NAK)) + +#define USB_EP0R_RX_STALL() USB_EP0R_RX_DIS(); USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK)) | USB_EP_RX_STALL) +#define USB_EP0R_TX_STALL() USB_EP0R_TX_DIS(); USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK)) | USB_EP_TX_STALL) +#define USB_EP0R_RXTX_STALL() USB_EP0R_RXTX_DIS(); USB->EP0R = (((USB->EP0R | USB_EP_CTR_RX | USB_EP_CTR_TX) & (USB_EPREG_MASK)) | (USB_EP_RX_STALL | USB_EP_TX_STALL)) + +//USB_COUNTn_RX table entries are a little annoying.. +//create some macros to simplify setting RX COUNT +#define BL_SIZE32 (uint16_t) 0x8000 +#define BL_SIZE2 (uint16_t) 0x0000 +#define NUM_BLOCKS 10U //shift number of blocks by this amount +#define RX_COUNT_MSK (uint16_t) 0x03FF + +// Cannot setup for 0 bytes to be received, that's equivalent of STATUS OUT packet which isn't a true data reception +#define _ADDRX_SET(oper) _DATA_OP(); DATA_OUT = oper; _AXL_CLK(); _DATA_IP(); +#define USB_RX_2TO62_MUL2B(oper) ((uint16_t) ((BL_SIZE2) | ((oper/2)<