From 58fe6ef3b1f20a4916111529b627e2f638805de5 Mon Sep 17 00:00:00 2001 From: Eggert Jung Date: Tue, 4 Jun 2024 18:45:10 +0200 Subject: [PATCH] initial --- Firmware/.gitignore | 8 + Firmware/Builds/main.elf | Bin 0 -> 14752 bytes Firmware/Builds/main.hex | 300 +++++++++++++++ Firmware/Builds/src/main.o | Bin 0 -> 15764 bytes Firmware/Builds/src/music.o | Bin 0 -> 1872 bytes Firmware/Makefile | 59 +++ Firmware/README.md | 161 ++++++++ Firmware/boards/emgdmm_v3.json | 40 ++ Firmware/boards/optiboot_atmega1284p_dmm.hex | 55 +++ Firmware/include/README | 39 ++ Firmware/include/music.h | 43 +++ Firmware/lib/README | 46 +++ Firmware/platformio.ini | 55 +++ Firmware/src/main.c | 551 +++++++++++++++++++++++++++ Firmware/src/music.c | 109 ++++++ Firmware/test/README | 11 + Firmware/test/test_demo.c | 41 ++ Firmware/test/unittest_transport.h | 32 ++ Hardware/.gitignore | 26 ++ Hardware/README.md | 4 + README.md | 42 ++ Slides/README.md | 3 + dmm-demo-master/Firmware/src/main.o | Bin 0 -> 15408 bytes dmm-demo-master/Firmware/src/music.o | Bin 0 -> 1872 bytes dmm-libs-master/src/dataflash.o | Bin 0 -> 3328 bytes dmm-libs-master/src/fifo.o | Bin 0 -> 1520 bytes dmm-libs-master/src/lcd.o | Bin 0 -> 10288 bytes dmm-libs-master/src/spi.o | Bin 0 -> 1448 bytes dmm-libs-master/src/twi.o | Bin 0 -> 2120 bytes dmm-libs-master/src/uart.o | Bin 0 -> 3008 bytes 30 files changed, 1625 insertions(+) create mode 100644 Firmware/.gitignore create mode 100755 Firmware/Builds/main.elf create mode 100644 Firmware/Builds/main.hex create mode 100644 Firmware/Builds/src/main.o create mode 100644 Firmware/Builds/src/music.o create mode 100644 Firmware/Makefile create mode 100644 Firmware/README.md create mode 100644 Firmware/boards/emgdmm_v3.json create mode 100644 Firmware/boards/optiboot_atmega1284p_dmm.hex create mode 100644 Firmware/include/README create mode 100644 Firmware/include/music.h create mode 100644 Firmware/lib/README create mode 100644 Firmware/platformio.ini create mode 100644 Firmware/src/main.c create mode 100644 Firmware/src/music.c create mode 100644 Firmware/test/README create mode 100644 Firmware/test/test_demo.c create mode 100644 Firmware/test/unittest_transport.h create mode 100644 Hardware/.gitignore create mode 100644 Hardware/README.md create mode 100644 README.md create mode 100644 Slides/README.md create mode 100644 dmm-demo-master/Firmware/src/main.o create mode 100644 dmm-demo-master/Firmware/src/music.o create mode 100644 dmm-libs-master/src/dataflash.o create mode 100644 dmm-libs-master/src/fifo.o create mode 100644 dmm-libs-master/src/lcd.o create mode 100644 dmm-libs-master/src/spi.o create mode 100644 dmm-libs-master/src/twi.o create mode 100644 dmm-libs-master/src/uart.o diff --git a/Firmware/.gitignore b/Firmware/.gitignore new file mode 100644 index 0000000..7890015 --- /dev/null +++ b/Firmware/.gitignore @@ -0,0 +1,8 @@ +depends +.pio +.vscode + +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/Firmware/Builds/main.elf b/Firmware/Builds/main.elf new file mode 100755 index 0000000000000000000000000000000000000000..e2ce1c46bdebcacbed554112bf52ac5d5238b44a GIT binary patch literal 14752 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 Zk)lx2eKu~l?y@(DK&JR72X%gX{}13txRd|@ literal 0 HcmV?d00001 diff --git a/Firmware/Builds/main.hex b/Firmware/Builds/main.hex new file mode 100644 index 0000000..c6fba7e --- /dev/null +++ b/Firmware/Builds/main.hex @@ -0,0 +1,300 @@ +:100000000C9446030C9465030C9465030C946503EF +:100010000C9465030C9465030C9465030C946503C0 +:100020000C9465030C9402040C9465030C94650312 +:100030000C9465030C9465030C9465030C946503A0 +:100040000C9465030C9465030C9465030C94650390 +:100050000C9439040C9465040C9465030C946503AA +:100060000C9465030C9465030C9465030C94650370 +:100070000C9465030C9465030C9465030C94650360 +:100080000C9465030C9465030C9465030000000058 +:100090000000003E4551453E003E6B6F6B3E001C2C +:1000A0003E7C3E1C00183C7E3C180030367F3630CB +:1000B00000185C7E5C1800000000000000000000DA +:1000C0000000000000000000000000000000003000 +:1000D000484A360E00062979290600000000000073 +:1000E00000607E0A353F002A1C361C2A00007F3E35 +:1000F0001C0800081C3E7F000014367F36140000E8 +:100100005F005F000006097F017F00224D555922E4 +:100110000060606060000014B6FFB6140004067F43 +:1001200006040010307F30100008083E1C0800084C +:100130001C3E080800784040404000083E083E0849 +:1001400000303C3F3C3000030F3F0F030000000035 +:1001500000000000065F06000007030007030024FC +:100160007E247E2400242B6A12000063130864633B +:1001700000364956205000000703000000003E41B1 +:1001800000000000413E000000083E1C3E08000840 +:10019000083E08080000E0600000000808080808A1 +:1001A000000060600000002010080402003E514979 +:1001B000453E0000427F400000625149494600220E +:1001C00049494936001814127F10002F4949493116 +:1001D000003C4A494930000171090503003649498C +:1001E000493600064949291E00006C6C00000000D9 +:1001F000EC6C000000081422410000242424242474 +:10020000000041221408000201590906003E415D28 +:10021000551E007E1111117E007F49494936003E6E +:1002200041414122007F4141413E007F49494941CE +:10023000007F09090901003E4149497A007F080809 +:10024000087F0000417F410000304040403F007F78 +:1002500008142241007F40404040007F0204027F9A +:10026000007F0204087F003E4141413E007F0909B2 +:100270000906003E4151215E007F090919660026EA +:10028000494949320001017F0101003F4040403FA0 +:10029000001F2040201F003F403C403F00631408E7 +:1002A0001463000708700807007149454300000007 +:1002B0007F414100000204081020000041417F00FE +:1002C0000004020102048080808080800000030717 +:1002D0000000002054545478007F444444380038CF +:1002E0004444442800384444447F0038545454085B +:1002F00000087E0909000018A4A4A47C007F04045F +:1003000078000000007D4000004080847D00007F78 +:10031000102844000000007F4000007C041804788E +:10032000007C0404780000384444443800FC444411 +:1003300044380038444444FC00447844040800082D +:100340005454542000043E442400003C40207C00CF +:10035000001C2040201C003C6030603C006C1010F1 +:100360006C00009CA0603C00006454544C000008E9 +:100370003E414100000000770000000041413E087E +:10038000000201020100003C2623263C001EA1E1E0 +:100390002112003D40207D000038545455090020B2 +:1003A00055555578002055545578002055555478AA +:1003B000002057555778001CA2E2221400385555EA +:1003C0005508003855545508003855555408000054 +:1003D000017C41000000017D41000000017C4000E3 +:1003E00000702924297000782F252F78007C545420 +:1003F00055450034547C5458007E097F49490038E3 +:100400004545390000384544390000394544380035 +:10041000003C41217D00003D41207C00009CA1600A +:100420003D00003D42423D00003C41403D008070A7 +:100430006858380400483E494962007E615D433F88 +:100440000022140814220040887E0902002054551E +:1004500055780000007D4100003844453900003CDB +:1004600040217D00007A090A7100007A112279008A +:1004700000085555555E004E51514E000030484D14 +:1004800040203E415D4B553E04040404041C00170B +:10049000084C6A50001708342A780000307D30007C +:1004A0000008140008140014080014084411441132 +:1004B0004411AA55AA55AA55BBEEBBEEBBEE0000EF +:1004C00000FF0000080808FF0000007028252970C0 +:1004D0000070292529700070292528703E415D553E +:1004E000413E0AFB00FF000000FF00FF00000AFA87 +:1004F00002FE00000A0B080F00000018246624000A +:1005000000292A7C2A29080808F800000000000FAA +:1005100008080808080F0808080808F80808000074 +:1005200000FF0808080808080808080808FF080865 +:1005300000205655567900702A252A71000F080BA5 +:100540000A0A00FE02FA0A0A0A0B080B0A0A0AFA49 +:1005500002FA0A0A00FF00FB0A0A0A0A0A0A0A0A41 +:100560000AFB00FB0A0A005D2222225D0022555987 +:10057000300000087F49413E007C55555544007CC1 +:1005800055545544007C5555544400000007000064 +:100590000000447D45000000457D45000000457C8D +:1005A00045000808080F0000000000F80808FFFFD9 +:1005B000FFFFFFFFF0F0F0F0F0F000000077000028 +:1005C0000000457D44000F0F0F0F0F0F003C42430A +:1005D0003D0000FE4A4A3400003C43433D00003DDC +:1005E00043423C000032494A3100003A4546390056 +:1005F00000FC20201C0000FEAA28100000FFA524FB +:100600001800003C40413D00003C41413D00003DA0 +:1006100041403C00009CA0613D00000408710904B9 +:1006200000000202020000000703000000000808AA +:1006300008000000242E240000242424242405176C +:100640000A342A780006097F017F00224D5559227D +:100650000008082A08080000081818000006090900 +:10066000060000000800080000000800000000026A +:100670000F00000000090F05000000090D0A00002E +:10068000003C3C3C3C0000000000000011241FBE68 +:10069000CFEFD0E4DEBFCDBF11E0A0E0B1E0EAE4EF +:1006A000F2E100E00BBF02C007900D92A635B10742 +:1006B000D9F725E0A6E5B1E001C01D92AC3BB20739 +:1006C000E1F70E94C1050C9423090C940000FC0181 +:1006D0001082758364837383628341834783468377 +:1006E0000895FC0180818823B9F0A281B3819D0126 +:1006F0002F5F3F4F8C919681915019F49181291B66 +:1007000031093383228396832FB7F89490819150D7 +:1007100090832FBF90E008958FEF9FEF0895FC0125 +:10072000908181819817B8F4A481B5819D012F5FD4 +:100730003F4F6C938781815019F48181281B3109C7 +:100740008783358324839FB7F89480818F5F80836C +:100750009FBF81E0089580E0089587B18C7F87B9BD +:1007600088B1836088B983E08093B80087E0809384 +:10077000B10082E0809370008DE78093B30078949D +:1007800008958AE08093560184EA8093BC0004C0F7 +:100790008091BC0087FD04C0809156018111F8CF83 +:1007A00080915601882329F08091B900887F90E0DC +:1007B00008958FEF9FEF08959AE0909356018093EC +:1007C000BB0084E88093BC0004C08091BC0087FD1E +:1007D00004C0809156018111F8CF80915601882381 +:1007E00029F08091B900887F90E008958FEF9FEF06 +:1007F00008950C94DC038AE08093560184E9809389 +:10080000BC0008951F920F920FB60F9211248F9380 +:100810008091B30083588093B30080915601882360 +:1008200029F0809156018150809356018F910F904D +:100830000FBE0F901F9018958FB7F89427E630E001 +:100840003093C5002093C40098E99093C10090ECC8 +:100850009093C0008FBF40E16CEA71E084EA91E0C0 +:100860000E94670340E464E671E08CE591E00C943B +:1008700067031F920F920FB60F9211240BB60F92BF +:100880002F933F934F935F936F937F938F939F9398 +:10089000AF93BF93EF93FF936091C60084EA91E01A +:1008A0000E948F03FF91EF91BF91AF919F918F9124 +:1008B0007F916F915F914F913F912F910F900BBE60 +:1008C0000F900FBE0F901F9018951F920F920FB6AA +:1008D0000F9211240BB60F922F933F934F935F9378 +:1008E0006F937F938F939F93AF93BF93EF93FF93F8 +:1008F00080915C01811118C08091C1008F7D80932F +:10090000C100FF91EF91BF91AF919F918F917F9126 +:100910006F915F914F913F912F910F900BBE0F9070 +:100920000FBE0F901F9018958CE591E00E94710307 +:100930008093C600E6CF8091570180FD0DC084B141 +:10094000806A84B980E58CBD81E08DBD81E090E056 +:10095000909358018093570108958EBD0DB407FE02 +:10096000FDCF0895249A2C9A0C949B04BF92CF92A9 +:10097000DF92EF92FF920F931F93CF93DF93BFB657 +:10098000F8948CE3C82E85E0D82E97E0E92EF12C60 +:100990000AC081E0E81AF10880E8C81AD1088FEF90 +:1009A000E816F80621F180915B0190E00E2C02C060 +:1009B000959587950A94E2F780FFEBCF4698479884 +:1009C0008E2D806B0E94AD0480E10E94AD0480E01A +:1009D0000E94AD04479A860100581F4FE601899195 +:1009E0000E94AD04C017D107D1F7469AD2CF10921A +:1009F0005B01BFBEDF91CF911F910F91FF90EF90F0 +:100A0000DF90CF90BF900895ECEBF1E0CF018058DC +:100A10009F4F1192E817F907E1F785E0EC3BF807E3 +:100A2000A9F78FEF80935B010C94B6048A3091F1A3 +:100A30008D3069F13091590120915A0196E0899FDA +:100A4000F0011124E457FF4F86E0289FD0011124C4 +:100A500090E8399FA00DB11D1124A454BE4F86E02B +:100A600094919D93815031968111FACF81E090E06D +:100A700001C0880F3A95EAF790915B01892B80932A +:100A80005B01243170F42F5F20935A010895109276 +:100A90005A01089580915901873018F48F5F80932F +:100AA00059010895CF93DF93EC019881992339F090 +:100AB0002196892F0E94160589918111FBCFDF9124 +:100AC000CF91089580935A016093590108950E942F +:100AD000C10384EC0E94F90381E10E94DC0380E001 +:100AE0000E94DC0380E00E94DC0380E00E94DC03C3 +:100AF00080E00E94DC0380E00E94DC030C94FB0396 +:100B0000CF930E949B0487B1806C87B9CFB7F894CC +:100B10004798469882EE0E94AD0483EA0E94AD0495 +:100B200081E80E94AD0488E00E94AD0480EA0E9442 +:100B3000AD0488EC0E94AD0485E20E94AD048FE212 +:100B40000E94AD048FEA0E94AD04469A479A0E9423 +:100B50000405CFBF0E94AD030E946705CF910C949E +:100B6000B204CF93C82F0E94C10384EC0E94F90302 +:100B700085E10E94DC038C2F0E94DC03CF910C9452 +:100B8000FB03CF93DF93CDB7DEB764970FB6F8942E +:100B9000DEBF0FBECDBF81B1877081B982B1886FD2 +:100BA00082B98FE084B985B18F6085B90E941C0439 +:100BB0000E948005789484E00E94B10581E0C12CF8 +:100BC000D12C76019E012F5F3F4F490190E0A92E65 +:100BD00091E0B92E0FC010E0813021F19FEFC91ACA +:100BE000D90AE90AF90A8FE99FE00197F1F700C0F5 +:100BF0000000812F11E00399EECF882331F02FEF11 +:100C0000C21AD20AE20AF20AEECF3FEF89EF90E071 +:100C1000315080409040E1F700C00000C12CD12C41 +:100C20007601EDCF2FEF39EF80E02150304080404A +:100C3000E1F700C000000E94040560E080E00E942F +:100C40006205FF92EF92DF92CF92BF92AF929F9296 +:100C50008F920E943A06C4010E9452050E94B60477 +:100C60000FB6F894DEBF0FBECDBFC12CD12C7601DC +:100C7000C394B9CF0F931F93CF93DF93CDB7DEB754 +:100C80002E970FB6F894DEBF0FBECDBF0D891E891B +:100C900086E08C831A8309838FEF9FE79E838D8381 +:100CA000AE01475E5F4F6F89788DCE0101960E943D +:100CB0006906EF81F885E00FF11F10822E960FB6BE +:100CC000F894DEBF0FBECDBFDF91CF911F910F9182 +:100CD00008952F923F924F925F926F927F928F92E0 +:100CE0009F92AF92BF92CF92DF92EF92FF920F93BB +:100CF0001F93CF93DF93CDB7DEB72B970FB6F89442 +:100D0000DEBF0FBECDBF6C017B018A01FC011782E3 +:100D10001682838181FFCCC1CE0101963C01F60190 +:100D20009381F70193FD859193FF81917F01882342 +:100D300009F4BAC1853239F493FD859193FF81910D +:100D40007F01853229F4B60190E00E948908E7CF3F +:100D5000912C212C312CFFE1F315D8F08B3279F056 +:100D600038F4803279F08332A1F4232D20611DC044 +:100D70008D3261F0803369F4232D216016C0832DFC +:100D80008260382EE32DE4603E2E2AC0F32DF860F9 +:100D90001DC037FC2DC020ED280F2A3040F08E32C8 +:100DA000B9F436FC81C1232D2064322E19C036FEE1 +:100DB00006C08AE0989E200D1124922E11C0EAE010 +:100DC0002E9E200D1124222EF32DF0623F2E08C0FE +:100DD0008C3621F4832D8068382E02C0883641F489 +:100DE000F70193FD859193FF81917F018111B3CF2D +:100DF000982F9F7D9554933028F40C5F1F4F9FE3ED +:100E000099830DC0833631F0833771F0833509F053 +:100E100059C021C0F801808189830E5F1F4F88244B +:100E20008394912C530113C02801F2E04F0E511C02 +:100E3000F801A080B18036FE03C0692D70E002C0C9 +:100E40006FEF7FEFC5010E947E084C018201F32DF8 +:100E5000FF773F2E16C0280122E0420E511CF801F8 +:100E6000A080B18036FE03C0692D70E002C06FEF34 +:100E70007FEFC5010E9473084C01F32DF0683F2EEF +:100E8000820133FC1BC0822D90E088169906B0F4D5 +:100E9000B60180E290E00E9489082A94F4CFF5011F +:100EA00037FC859137FE81915F01B60190E00E9489 +:100EB000890821102A9421E0821A91088114910452 +:100EC00071F7E8C0843611F0893641F5F80137FE34 +:100ED00007C060817181828193810C5F1F4F08C0C0 +:100EE00060817181072E000C880B990B0E5F1F4FDC +:100EF000F32DFF763F2E97FF09C090958095709552 +:100F000061957F4F8F4F9F4FF0683F2E2AE030E072 +:100F1000A3010E94C508882E861845C0853731F484 +:100F2000232D2F7EB22E2AE030E025C0932D997F0D +:100F3000B92E8F36C1F018F4883579F0B5C08037F6 +:100F400019F0883721F0B0C0E92FE061BE2EB4FE61 +:100F50000DC0FB2DF460BF2E09C034FE0AC0292F3E +:100F60002660B22E06C028E030E005C020E130E067 +:100F700002C020E132E0F801B7FE07C06081718154 +:100F8000828193810C5F1F4F06C06081718180E078 +:100F900090E00E5F1F4FA3010E94C508882E86189F +:100FA000FB2DFF773F2E36FE0DC0232D2E7FA22E68 +:100FB000891458F434FE0BC032FC09C0832D8E7E98 +:100FC000A82E05C0B82CA32C03C0B82C01C0B92C86 +:100FD000A4FE0FC0FE01E80DF11D8081803321F4D5 +:100FE0009A2D997EA92E09C0A2FE06C0B394B3948F +:100FF00004C08A2D867809F0B394A3FC11C0A0FE2A +:1010000006C0B21488F4280C922C9B180EC0B2149F +:1010100060F4B60180E290E00E948908B394F7CFB3 +:10102000B21418F42B1802C0982C212CA4FE10C066 +:10103000B60180E390E00E948908A2FE17C0A1FCDF +:1010400003C088E790E002C088E590E0B6010CC0DC +:101050008A2D867859F0A1FE02C08BE201C080E2A1 +:10106000A7FC8DE2B60190E00E948908891438F44B +:10107000B60180E390E00E9489089A94F7CF8A94A1 +:10108000F301E80DF11D8081B60190E00E9489080E +:101090008110F5CF222009F442CEB60180E290E023 +:1010A0000E9489082A94F6CFF6018681978102C0B2 +:1010B0008FEF9FEF2B960FB6F894DEBF0FBECDBF1C +:1010C000DF91CF911F910F91FF90EF90DF90CF9024 +:1010D000BF90AF909F908F907F906F905F904F9058 +:1010E0003F902F900895FC010590615070400110D1 +:1010F000D8F7809590958E0F9F1F0895FC01615041 +:10110000704001900110D8F7809590958E0F9F1F29 +:1011100008950F931F93CF93DF93FB01238121FD4C +:1011200003C08FEF9FEF2CC022FF16C0468157816E +:10113000248135814217530744F4A081B1819D0178 +:101140002F5F3F4F318320838C93268137812F5F20 +:101150003F4F3783268314C08B01EC01FB010084D1 +:10116000F185E02D0995892BE1F6D80116968D9130 +:101170009C911797019617969C938E931697CE0184 +:10118000DF91CF911F910F910895FA01AA2728307E +:1011900051F1203181F1E8946F936E7F6E5F7F4F44 +:1011A0008F4F9F4FAF4FB1E03ED0B4E03CD0670FC0 +:1011B000781F891F9A1FA11D680F791F8A1F911D13 +:1011C000A11D6A0F711D811D911DA11D20D009F463 +:1011D00068943F912AE0269F11243019305D3193A5 +:1011E000DEF6CF010895462F4770405D4193B3E08E +:1011F0000FD0C9F7F6CF462F4F70405D4A3318F035 +:10120000495D31FD4052419302D0A9F7EACFB4E0E5 +:10121000A6959795879577956795BA95C9F700979D +:101220006105710508959B01AC010A2E069457953E +:10123000479537952795BA95C9F7620F731F841F95 +:0A124000951FA01D0895F894FFCF3C +:10124A0074696D653A202564004A6F79737469631D +:10125A006B2055702E0D0A004A6F79737469636B9F +:10126A0020446F776E2E0D0A004A6F797374696392 +:10127A006B204C6566742E0D0A004A6F7973746987 +:10128A00636B2052696768742E0D0A004578697489 +:06129A002E0D0A0A0000FF +:00000001FF diff --git a/Firmware/Builds/src/main.o b/Firmware/Builds/src/main.o new file mode 100644 index 0000000000000000000000000000000000000000..9ef91549e4c873d5e71af86cde633120aff4db6e GIT binary patch literal 15764 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 T@IK()>CU$hi=fRF(E0us#cYqo literal 0 HcmV?d00001 diff --git a/Firmware/Builds/src/music.o b/Firmware/Builds/src/music.o new file mode 100644 index 0000000000000000000000000000000000000000..1f64cee44d75b7a413852280e6d10a8064d7dce2 GIT binary patch literal 1872 zcma)6VQ5=b6h5~}m#*!$tgC}jM&3klLb$f9{+Z5A>da)T3F`_f;#-!6HLTf-Njj}q z`l9|=LFmhi+HHyz{Iy?0lrfmFOi=bisER0vu&e(ZqfH=4DPsK2%X{5hQ1rm}&UeoF z?z!jX-j}(<$DR>FkY|F%=w3vW>m>RN#bHOVmwIV4#cka->^XbEUb3&)H|%Bmw!LaM z?QNAvWx4W>7{64yYgSB}S7xO|VcR0JQl|4ON90@Td6|s9619Gtm*qPb<)XSQKaGB= z)`T+a=CA$rplDEaO*~lISNch8eV6DHVLLt}7R4czP+y79op?`TX!Bs@B59QibhH1v zpr~nTP$^YYH$R~2t?O@>EoHv26t^n#*!?^Wy>BWtxE2zPNA-j8=mQ5jskWdjwfcKg z4K4DnMA)Lyt4HF#X=+q`vxJve6t#a+QZ;Owc*E9PhV3#fmm}qE<)*c2-L{sk8`c$T z$y%`HEW^^RxYhMurDL5|#4Po6%+gWtmY=0-VjXDZS#uP1uC0hyg{S3w58!F}NWwdI z?i$z~(KIcxdtlej9pNqAq0RuGpa^t^y0=hlWMsd#H}>54BidtfSPt@{HuIl%km^l; zIdI=?APP{2zl=D58$tBsMz-GU13%!42fz>d;)lQ=_r-F9GpRTC<9TnU_IZL7bM=~| z3%OCt1!z-S++Od(4R6^K*rbnwl=7_zgBxw}8*ZF{-;VzCZFR~{7cwcCB3&O#=tp$D zMUJ(|@xw8P9Diyw@uI_u*_@tFpLY1`>Ac|vh0NKsK4lnZrgJpP9reUia^^%nnL2}p z)7j~%$xI=$kNHIAT-KNo6#qd#U#CiIXilYPQt$o z1i)9|CxO20c))T%A0HUZ1U!yU&slp5{t~chD;}^9fso5T2Irn1!C!Ur8vHeY^~}Ej zcm~#d?Q-t-z01Fa{{i4WKf?d)=D&fz<8q$)F2I_T@C|@__Tv2hbon~`UjS?P@&p0a z{DH6=obw8tWML*-OrC--=39Q!W5x7qMUu`>Cr=d$B=hO1q~xq@KM$EVSSRoM`DHF| zoX)1RP7CQjPMI>Y+4R{W5AgqtzZs0Zahr$RmT`@355PRY0qoy&52Mxv{FiPBn)ZG9 zJMqk;Q6z%EA-C`g8uz2v?dG}G3&a3k98^;YK5&&PLFu?D@p8w **In `debug` darf daher kein UART genutzt werden, da es zur Kommunikation mit +> GDB dient**. Entsprechende Programmteile müssen gegebenenfalls mit +>`#ifndef GDBSTUB` deaktiviert werden! + +Bauen von `release`: +``` +$ pio run -e release +``` + +Bauen von `debug`: +``` +$ pio run -e debug + +``` +Wenn man `-e ` weglässt, wird immer `debug` gebaut, da dies die +Standartkonfiguration ist, die von dem Debugger von VSCode genutzt werden soll. + +Die für die DMM-Projekte vorgesehenen +[Bibliotheken](git@git.rz.tu-bs.de:emg/lehre/dmm/dmm-libs.git) sowie die +Toolchain werden durch `pio run` automatisch heruntergeladen und müssen nicht +extra installiert werden. Die Bibliotheken werden dabei im Ordner +`dmm-demo/depends` hinterlegt. + +### Programmierung & Nutzung + +*GUI*: die hier aufgeführten Befehle können auch aus dem PlatformIO-Toolbar des +VSCode per Mausklick ausgeführt werden. +#### Aufspielen des Bootloaders + +Auf einem neuen Board muss zunächst mittels JTAGICE3 ein Bootloader aufgespielt +werden. Dazu wird es mit dem JTAG-Header verbunden (Polung beachten!). +``` +$ pio run -t bootloader -e jtag +``` + +> Sollte es beim Aufruf zum Fehler `TypeError: expected str, bytes or +> os.PathLike object, not NoneType ... +> join(platform.get_package_dir("tool-avrdude"), "avrdude.conf")` +> kommen, kann dieser durch einmaliges Aufrufen von +> `$ pio run -t upload -e jtag` +> vor der Installation des Bootloaders behoben werden. + +#### Aufspielen des Programms + +Das Board muss per USB verbunden und Bootloader gestarted werden. +**Zum Start des Bootloaders den Joystick in Richtung unten halten, Reset-Taste +drücken und den Joystick loslassen. Die Aktivierung des Bootloaders erkennt man +an dreimaligem Blinken und anschließendem Dauerleuchten der LED4 auf dem Board**. +``` +$ pio run -e release -t upload +``` +Anschließend Reset-Taste drücken um das Programm zu starten. + +#### UART-Kommunikation + +Ein Teil des Demos beschäftigt sich mit Kommunikation über einen virtuellen +SerialPort via USB. Der `COMx` (Windows) oder `/dev/ttyUSBx` (Linux) Port wird +von PlattformIO automatisch erkannt. Dies geschieht anhand des `hwid` Parameters +unter `boards/emgdmm_v3.json`, der den VID/PID des FTDI-Chips des DMM-Boards +angibt. Ein Terminal kann somit einfach geöffnet werden: +``` +$ pio device monitor +``` + +Beim Drücken des Joystick im entsprechenden Teil des Demos wird nun eine Meldung +angezeigt. + +#### Unit-Test + +Die Demo enthält im Ordner `tests` einen Beispiel zur Ausführung von Unit-Tests +auf dem Mikrocontroller. Dazu muss wie oben beschrieben der Bootloader aktiviert +werden. +``` +$ pio test +``` +Nach dem Befehl wird eine Firmware auf das Board heruntergeladen, die bei der +Ausführung per UART (wie auch bei `pio device monitor`) die Ergebnisse der +Tests im Terminal ausgibt. + +#### Debugging mit avr-stub + +Normallerweise ist zum Debuggen (also Setzen von Breakpoints und Auslesen der +Register) ein JTAG-Adapter notwendig. PlattformIO kann +mittels einer [Bibliothek](https://github.com/jdolinay/avr_debug) die Funktion +der Hardware-Debugger unter Inkaufnahme einiger Nachteile teilweise ersetzen. +Die Kommunikation erfolgt dabei per UART, der nicht mehr im eigenen Programm +genutzt werden kann. +Die Konfiguration `debug` bindet die nötige Bibliothek ein, und schaltet +Optimierung über das Setzen von `build_type` aus und definiert `GDBSTUB`. Am +Anfang des programms muss `debug_init()` aus `avr8-stub.h` aufgerufen werden. + +Debugging wird in VScode mittels "Run & Debug" Tab gestartet. Vorher muss +der Bootloader aktiv sein. + +Zu beachten ist: + * Beakpoints funktionieren nur in Programmteilen, wo Interrupts aktiviert + sind. **Das setzen eines Breakpoints innerhalb einer Interruptroutine führt + immer zum Aufhängen des Programms**. + * Breakpoints werden über das Neuschreiben vom Flash gesetzt. Dies hat einen + Verschleiß zufolge, da der Flash nur für 10000 Schreibzyklen ausgelegt ist. + Das "Steppen" einzelner Befehle ist daher sparsam zu verwenden. + * Der Debugger nutzt den Watchdog-Interrupt, daher darf WDT nicht vom Programm + genutzt werden. Außerdem können die gelegentlichen Interrupts die Timings + beeinflussen. + +> **TODO:** aktuell muss der Port des Debuggers manuell in `platformio.ini` +> unter `debug_port` gesetzt werden! +> (z.B. `/dev/ttyUSBx` unter Linux oder `COMx` unter Windows). +> Für automatisches Auflösen des Ports siehe +> [Issue 253](https://github.com/platformio/platform-atmelavr/issues/253). \ No newline at end of file diff --git a/Firmware/boards/emgdmm_v3.json b/Firmware/boards/emgdmm_v3.json new file mode 100644 index 0000000..ab9fb0d --- /dev/null +++ b/Firmware/boards/emgdmm_v3.json @@ -0,0 +1,40 @@ +{ + "build": { + "f_cpu": "16000000L", + "hwids": [ + [ + "0x0403", + "0x6001" + ] + ], + "mcu": "atmega1284p" + }, + "platforms": [ + "atmelavr" + ], + "name": "EMG DMM Board", + "upload": { + "maximum_ram_size": 16384, + "maximum_size": 130048, + "protocol": "arduino", + "require_upload_port": true + }, + "bootloader": { + "file": "boards/optiboot_atmega1284p_dmm.hex", + "lfuse": "0xFF", + "hfuse": "0x9C", + "efuse": "0xFC", + "lock_bits": "0xFF" + }, + "debug": { + "simavr_target": "atmega1284p", + "avr-stub": { + "speed": 115200 + } + }, + "test": { + "speed": 115200 + }, + "url": "https://www.emg.tu-bs.de/lehre/vl/vl_dmm_d.html", + "vendor": "EMG, TU Braunschweig" +} diff --git a/Firmware/boards/optiboot_atmega1284p_dmm.hex b/Firmware/boards/optiboot_atmega1284p_dmm.hex new file mode 100644 index 0000000..80ab0b3 --- /dev/null +++ b/Firmware/boards/optiboot_atmega1284p_dmm.hex @@ -0,0 +1,55 @@ +:020000021000EC +:10FC000001C020C1112484B7882391F00E98169A60 +:10FC100090B1282F2A70223011F496FF09C081FF7D +:10FC200002C097EF94BF282E80E0F7D00C9400001C +:10FC300085E08093810082E08093C00088E180931A +:10FC4000C10086E08093C20080E18093C40080E020 +:10FC5000E4D0239A86E020E33CEF91E030938500E6 +:10FC60002093840096BBB09BFECF1B9AA895409131 +:10FC7000C00047FD02C0815089F743E0B42EAA249A +:10FC8000A39451E1752EBDD0813471F4BAD0C82F40 +:10FC9000CAD081E0C23821F088E0C13809F083E0A1 +:10FCA000A9D080E1A7D0EFCF823419F484E1C3D08A +:10FCB000F8CF853411F485E0FACF853581F4A1D0F1 +:10FCC000082F9FD0182F87FF07C08BB781608BBF8D +:10FCD000000F111FA8D0E5CF8BB78E7FF8CF8635E8 +:10FCE00081F48FD08D3459F48CD0CBB78AD0C170C9 +:10FCF000880F8C2B8BBF81E09ED080E0D1CF83E03A +:10FD0000FBCF843609F046C07CD0E82EF12CFE2CC7 +:10FD1000EE2477D0E82A75D0682EE701C12CDD24C7 +:10FD2000D39446018FEFC81AD80A6BD0F4018083B0 +:10FD30002197B9F778D0F5E46F120DC0FE01F39565 +:10FD4000EC16FD0609F4ADCF6081CE01800F911F46 +:10FD500091D02196F3CFF801B7BEE89507B600FC25 +:10FD6000FDCFFE01E00FF11FDE01B3958D919C9157 +:10FD70000C01A7BEE89511242296EC16FD0689F722 +:10FD800085E0F80187BFE89507B600FCFDCF77BE98 +:10FD9000E89587CF8437F9F434D0C82FD0E0DC2F32 +:10FDA000CC272FD0C82B2DD0D82E3DD07801F5E40C +:10FDB000DF120AC0C70156D01DD021978FEFE81A75 +:10FDC000F80A2097B9F76DCFF70187917F0112D01C +:10FDD0002197D1F766CF853739F425D08EE10AD047 +:10FDE00087E908D085E05CCF813509F073CF88E0E2 +:10FDF00014D070CF9091C00095FFFCCF8093C600C7 +:10FE000008958091C00087FFFCCF8091C00084FDE1 +:10FE100001C0A8958091C6000895E0E6F0E098E161 +:10FE2000908380830895EDDF803219F088E0F5DF5C +:10FE3000FFCF84E1DFCFCF93C82FE3DFC150E9F7D5 +:10FE4000CF91F1CFFC010A0167BFE895112407B6F5 +:10FE500000FCFDCF667029F0452B19F481E187BFC6 +:10FE6000E8950895F999FECF92BD81BDF89A99273A +:10FE700080B50895262FF999FECF1FBA92BD81BD96 +:10FE800020BD0FB6F894FA9AF99A0FBE019608951C +:10FE900056657273696F6E3D382E31004F5054496C +:10FEA000424F4F545F435553544F4D5645523D308A +:10FEB000004465766963653D61746D6567613132E3 +:10FEC00038347000465F4350553D31363030303065 +:10FED00030304C00424947424F4F543D310042754B +:10FEE000696C743A41707220313820323032313AC4 +:10FEF00032323A30333A303000554152543D3000BE +:10FF0000424155445F524154453D313135323030E4 +:10FF1000004C45443D4233004C45445F53544152EC +:0CFF2000545F464C41534845533D3300AC +:02FFFE000108F8 +:040000031000FC00ED +:00000001FF diff --git a/Firmware/include/README b/Firmware/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/Firmware/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/Firmware/include/music.h b/Firmware/include/music.h new file mode 100644 index 0000000..295596a --- /dev/null +++ b/Firmware/include/music.h @@ -0,0 +1,43 @@ +#ifndef MUSIC_H_ +#define MUSIC_H_ + +typedef struct +{ + uint16_t tone; + uint16_t duration; +} MUSIC_Note; + +#define MUSIC_END { 0, 0 } +#define MUSIC_IS_END(_note_) (!((_note_).tone) && !((_note_).duration)) + +#define MUSIC_A4 440 +#define MUSIC_B4 494 +#define MUSIC_C4 262 +#define MUSIC_D4 293 +#define MUSIC_E4 330 +#define MUSIC_F4 349 +#define MUSIC_G4 392 + +#define MUSIC_A5 880 +#define MUSIC_B5 988 +#define MUSIC_C5 523 +#define MUSIC_D5 587 +#define MUSIC_E5 659 +#define MUSIC_F5 698 +#define MUSIC_G5 784 + +#define MUSIC_1 1000 +#define MUSIC_2 (MUSIC_1/2) +#define MUSIC_4 (MUSIC_1/4) +#define MUSIC_8 (MUSIC_1/8) +#define MUSIC_16 (MUSIC_1/16) +#define MUSIC_32 (MUSIC_1/32) + + +typedef const MUSIC_Note* MUSIC_Track; +extern const MUSIC_Note MUSIC_Tetris[]; + +void Music_PlayTrack (MUSIC_Track track); + + +#endif /* MUSIC_H_ */ \ No newline at end of file diff --git a/Firmware/lib/README b/Firmware/lib/README new file mode 100644 index 0000000..6debab1 --- /dev/null +++ b/Firmware/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in a an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/Firmware/platformio.ini b/Firmware/platformio.ini new file mode 100644 index 0000000..14d55b1 --- /dev/null +++ b/Firmware/platformio.ini @@ -0,0 +1,55 @@ +; PlatformIO Project Configuration File +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[platformio] +default_envs = debug +libdeps_dir = depends + +[env] +platform = atmelavr @ ^3.3.0 + +board = emgdmm_v3 +monitor_speed = 9600 +test_transport = custom +test_speed = 115200 + +lib_deps = + git@git.rz.tu-bs.de:emg/lehre/dmm/dmm-libs.git + +[env:release] ; for flash via bootloader +; keep defaults, see board definitions for programming support + + +[env:debug] ; for debugging using avr-stub, see documentation +build_type = debug +build_flags = + -D DEBUG + -D GDBSTUB ; program should disable any own UART use if this is defined + -D AVR8_BREAKPOINT_MODE=2 + +debug_tool = avr-stub +;debug_port = /dev/ttyUSB0 ; Linux Port TODO: this should be infered automagically +debug_port = COM6 ; Windows COM Port + +; add GDB stub implementation +lib_deps = + ${env.lib_deps} + jdolinay/avr-debugger @ ^1.3 + + +[env:jtag] ; for JTAG bootloader flashing and potentialy debugging once supported +build_type = debug +build_flags = + -D DEBUG + +upload_protocol = jtag3 +upload_flags = -p, atmega1284, -F ; fix signature error with JTAGICE +upload_port = usb + +; Atmel-ICE based AVR debug is not directly supported by PIO as of 04.2020. As not +; available at home, not an issue for DMM at the moment. +; Potentially solveable by using avarice as a server. +; See: https://github.com/platformio/platform-atmelavr/issues/53 + diff --git a/Firmware/src/main.c b/Firmware/src/main.c new file mode 100644 index 0000000..a5cb933 --- /dev/null +++ b/Firmware/src/main.c @@ -0,0 +1,551 @@ +#include +#include +#include +#include +#include +#include + +#ifdef GDBSTUB + #include "avr8-stub.h" +#else + #include "uart.h" +#endif + +#include "lcd.h" +#include "twi.h" +#include "dataflash.h" +#include "music.h" + +#define wait_joy_button() \ + { \ + LCD_GotoXY(20, 7); \ + LCD_PutChar(0x10); \ + LCD_Update(); \ + while (((PINA)&0x08)) \ + ; \ + while (!((PINA)&0x08)) \ + ; \ + _delay_ms(20); \ + while (((PINA)&0x08)) \ + ; \ + } + +/* clang-format off */ +const uint8_t PROGMEM emg_logo[640] = +{ + 0x80, 0xe0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xe0, 0x80, 0x00, 0x00, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf8, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xf8, 0xf8, 0xf0, 0xe0, 0xc0, 0xe0, 0xf0, 0xf8, 0xf8, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xe0, 0x80, 0x00, 0x00, 0x80, 0xe0, 0xf0, + 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, + 0xfc, 0xfc, 0xfc, 0xf8, 0xf8, 0xf0, 0xe0, 0x80, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xf3, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, + 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf1, 0xf7, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x1f, 0x07, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x03, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x07, 0x03, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0x1f, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x03, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xf1, 0xe1, 0xc1, 0xc1, 0x81, 0x81, 0x81, 0x81, 0xc1, 0xc1, 0xc1, + 0xc1, 0xc1, 0xc1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, 0xe1, + 0xe1, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, + 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xe0, + 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, + 0xc0, 0xe0, 0xf0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x01, 0x07, 0x07, 0x0f, 0x0f, 0x0f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x0f, 0x0f, 0x0f, 0x07, 0x07, 0x03, 0x00, 0x00, 0x00, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x03, 0x07, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, + 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x8f, 0xcf, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, + 0x1f, 0x0f, 0x07, 0x01, +}; +/* clang-format on */ + +void demo_backlight(void); +void demo_start(void); +void demo_display(void); +void demo_show_emg(void); +void demo_uart(void); +void demo_music(void); + +int main(void) +{ + // set PA3-PA7 as input and activated internal Pull-Up + DDRA &= ~((1 << PINA3) | (1 << PINA4) | (1 << PINA5) | (1 << PINA6) | (1 << PINA7)); // Required for DMM Board 2013 + PORTA |= ((1 << PINA3) | (1 << PINA4) | (1 << PINA5) | (1 << PINA6) | (1 << PINA7)); // Required for DMM Board 2013 + + // set PB0-PB3 as output + DDRB = 0x0F; + // set PB0-PB3 on high-level + PORTB |= 0x0F; // Required for DMM Board DMM Board 2013 + +#ifdef GDBSTUB + debug_init(); // required for debugging via UART +#else + UART_Init(); +#endif + + LCD_Init(); + sei(); // enable interrupts after drivers initialized + + //demo_start(); + //demo_show_emg(); + + //#ifndef GDBSTUB // UART unavailable if used by GDB stub for debugging + //demo_uart(); + //#endif + + //demo_display(); + //demo_backlight(); + //demo_music(); + + Backlight_LED(BL_GREEN_ON); + + + //Backlight_Off(); + //LCD_Clear(); + + // loop forever + uint32_t counter = 0; + uint8_t button_state = 1; + uint8_t button_state_old = 1; + while (1){ + button_state = !(PINA & 0x08); + + if( button_state == 1 && button_state_old == 0 ){ + _delay_ms(20); + counter = 0; + } + if( button_state == 0 && button_state_old == 1 ){ + _delay_ms(20); + + /* print to LCD */ + LCD_Clear(); + LCD_GotoXY(0, 0); + char msg[20]; + sprintf(msg, "time: %d", counter); + LCD_PutString(msg); + LCD_Update(); + /* ------------ */ + + counter = 0; + } + + counter++; + button_state_old = button_state; + _delay_ms(1); + } +} + +void demo_start(void) +{ + // Turn on green backlight + Backlight_LED(BL_GREEN_ON); + + // Place program memory strings in framebuffer + LCD_PutString_P(PSTR("-DMM AVR-Board Demo- \r\n\n")); + LCD_PutString_P(PSTR("Always push the \r\n")); + LCD_PutString_P(PSTR("joystick button to \r\n")); + LCD_PutString_P(PSTR("proceed to the next \r\n")); + LCD_PutString_P(PSTR("screen. \r\n\n")); + LCD_PutString_P(PSTR("Enjoy the Fuck You! ")); + + // Copy framebuffer to display + LCD_Update(); + + // Wait for joystick button + wait_joy_button(); +} + +void demo_show_emg(void) +{ + // Some counters + uint16_t emg_offset = 0; + uint8_t fb_x; + uint8_t fb_y; + + // Turn on white backlight (red, green and blue) + Backlight_LED(BL_RED_ON | BL_GREEN_ON | BL_BLUE_ON); + + // Clear precautionally + LCD_Clear(); + + // Copy emglogo into framebuffer + for (fb_y = 0; fb_y < 5; fb_y++) + for (fb_x = 0; fb_x < 128; fb_x++) + lcd_framebuffer[fb_y][fb_x] = pgm_read_byte(&emg_logo[emg_offset++]); + + // Mark pages 0-4 for update + lcd_frameupdate = 0x1f; + + // Add some text + LCD_GotoXY(0, 5); + LCD_PutString_P(PSTR(" Institut f\x81r Messt. \r\n")); + LCD_PutString_P(PSTR(" und Grundlagen der \r\n")); + LCD_PutString_P(PSTR(" Elektrotechnik \r\n")); + + // And copy framebuffer to display + LCD_Update(); + + wait_joy_button(); +} + +#ifndef GDBSTUB +void demo_uart(void) +{ + unsigned char loop = 1; + signed int c; + char buffer[10]; + + LCD_Clear(); + Backlight_LED(BL_BLUE_ON); + + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("UART-Demonstration \r\n\n")); + LCD_PutString_P(PSTR("Setup your terminal: \r\n")); + LCD_PutString_P(PSTR("9600 Baud, 8N1 \r\n")); + LCD_PutString_P(PSTR("Use joystick to send \r\n")); + LCD_PutString_P(PSTR("some strings. \r\n")); + + LCD_GotoXY(20, 7); + LCD_PutChar(0x10); + + LCD_Update(); + + while ((!((PINA)&0x08))) + ; + _delay_ms(20); + while (!((PINA)&0x08)) + ; + + while (loop) + { + // Get net character from uart fifo + c = UART_GetChar(); + + // c = -1 means fifo empty + if (c > -1) + { + // wipe last lcd line + LCD_WipeLine(7); + + LCD_GotoXY(0, 7); + LCD_PutString_P(PSTR("RX-ASCII-Code: ")); + // Convert interger to ascii + itoa(c, buffer, 10); + + LCD_PutString(buffer); + LCD_GotoXY(20, 7); + LCD_PutChar(0x10); + LCD_Update(); + _delay_ms(10); + } + + _delay_ms(20); + while (!((PINA)&0xF8)) + ; // Different to DMM 2012 and before + + switch (((PINA)&0xF8)) + { + case 0x78: + // Joystick Up + UART_PutString("Joystick Up.\r\n"); + break; + case 0xB8: + // Joystick Down + UART_PutString("Joystick Down.\r\n"); + break; + case 0xD8: + // Joystick Left + UART_PutString("Joystick Left.\r\n"); + break; + case 0xE8: + // Joystick Right + UART_PutString("Joystick Right.\r\n"); + break; + case 0xF0: + // Joystick Button + UART_PutString("Exit.\r\n\n"); + loop = 0; + break; + } + + _delay_ms(200); + } +} +#endif + +void demo_music(void) +{ + LCD_Clear(); + Backlight_LED(BL_RED_ON); + + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Let's dance!\r\n\n")); + LCD_PutString_P(PSTR("(Finest PWM sounds!)\r\n\n")); + LCD_Update(); + + Music_PlayTrack(MUSIC_Tetris); + + LCD_PutString_P(PSTR("OK, that's enough...\r\n\n")); + LCD_Update(); + + wait_joy_button(); +} + +void demo_display(void) +{ + // switch white backlight on + Backlight_LED(BL_RED_ON | BL_GREEN_ON | BL_BLUE_ON); + + // clear display + LCD_Clear(); + + // talking to the user + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Set some pixels.")); + + LCD_DrawPixel(10, 10, 1); + LCD_DrawPixel(12, 44, 1); + LCD_DrawPixel(111, 62, 1); + LCD_DrawPixel(101, 22, 1); + LCD_Update(); + + wait_joy_button(); + + // one display page requires 8 pages in dataflash + LCD_SavePage(0); + LCD_WipeLine(0); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Connecting.")); + + LCD_DrawLine(10, 10, 12, 44, 1); + LCD_DrawLine(12, 44, 111, 62, 1); + LCD_DrawLine(111, 62, 101, 22, 1); + LCD_DrawLine(101, 22, 10, 10, 1); + LCD_Update(); + + wait_joy_button(); + + // first display page was stored at flash page 0 + // second display page will start at 8 + LCD_SavePage(8); + LCD_WipeLine(0); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Adding circles.")); + + LCD_DrawCircle(64, 32, 10, 1); + LCD_DrawCircle(70, 30, 20, 1); + LCD_Update(); + + wait_joy_button(); + + // talking to the user + LCD_SavePage(16); + LCD_Clear(); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Clear/Set/XOR Demo.")); + + for (unsigned int fill = 0; fill < 128; fill++) + LCD_DrawLine(fill, 10, fill, 53, (fill / 8) & 1); + + // Clear + LCD_DrawLine(0, 20, 127, 20, 0); + + // Set + LCD_DrawLine(0, 30, 127, 30, 1); + + // XOR + LCD_DrawLine(0, 40, 127, 40, 2); + + LCD_Update(); + + wait_joy_button(); + + // talking to the user + LCD_SavePage(24); + LCD_Clear(); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Use the joystick to\r\n")); + LCD_PutString_P(PSTR("recall the last\r\n")); + LCD_PutString_P(PSTR("screens. Again,\r\n")); + LCD_PutString_P(PSTR("button means exit.\r\n")); + LCD_Update(); + + unsigned char loop = 1; + + while (loop) + { + // wait + while ((!((PINA)&0xF8))) + ; // Different to DMM 2012 and before + _delay_ms(300); + while (!((PINA)&0xF8)) + ; // Different to DMM 2012 and before + + switch ((~PINA) & 0xF8) // Different to DMM 2012 and before + { + case 0x80: + // UP + LCD_LoadPage(0); + LCD_WipeLine(0); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Screen 1")); + LCD_Update(); + break; + case 0x40: + // DOWN + LCD_LoadPage(24); + LCD_WipeLine(0); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Screen 4")); + LCD_Update(); + break; + case 0x20: + // LEFT + LCD_LoadPage(8); + LCD_WipeLine(0); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Screen 2")); + LCD_Update(); + break; + case 0x10: + // RIGHT + LCD_LoadPage(16); + LCD_WipeLine(0); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Screen 3")); + LCD_Update(); + break; + case 0x08: + // BUTTON + loop = 0; + break; + } + } + + // talking to the user + LCD_Clear(); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Push button for\r\n")); + LCD_PutString_P(PSTR("next demonstration.\r\n")); + + wait_joy_button(); +} + +void demo_backlight(void) +{ + unsigned char led_active = 0x80; + + // white backlight + Backlight_LED(BL_RED_ON | BL_GREEN_ON | BL_BLUE_ON); + + LCD_Clear(); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR("Use the joystick to\r\n")); + LCD_PutString_P(PSTR("toggle the backlight\r\n")); + LCD_PutString_P(PSTR("on the next screen.")); + LCD_Update(); + + wait_joy_button(); + + // no backlight + Backlight_Off(); + + LCD_Clear(); + LCD_GotoXY(0, 0); + LCD_PutString_P(PSTR(" Red \r\n")); + LCD_PutString_P(PSTR(" \r\n")); + LCD_PutString_P(PSTR(" \x18 \r\n")); + LCD_PutString_P(PSTR(" Green \x1b Exit \x1a Blue \r\n")); + LCD_PutString_P(PSTR(" \x19 \r\n")); + LCD_PutString_P(PSTR(" \r\n")); + LCD_PutString_P(PSTR(" Toggle \r\n")); + LCD_PutString_P(PSTR(" all \x10\r\n")); + LCD_Update(); + + while (!((PINA)&0x08)) + ; + _delay_ms(20); + while (!((PINA)&0x08)) + ; + + while (led_active & 0x80) + { + + while ((~(PINA)&0xF8)) + ; // Different to DMM 2012 and before + _delay_ms(300); + while (!((PINA)&0xF8)) + ; // Different to DMM 2012 and before + + switch ((~PINA) & 0xF8) // Different to DMM 2012 and before + { + case 0x08: + // Button -> Exit + led_active = 0x00; + + break; + case 0x80: + // Up -> Toggle Red + led_active ^= 0x01; + break; + case 0x20: + // Up -> Toggle Green + led_active ^= 0x04; + break; + case 0x10: + // Up -> Toggle Blue + led_active ^= 0x10; + break; + case 0x40: + // Up -> Toggle All + led_active ^= 0x15; + break; + } + + while (!(PINA & 0xf8)) + ; + + Backlight_LED(led_active & 0x15); + + PORTB &= ~0x0f; + if (led_active & 0x01) + PORTB |= 0x01; + if (led_active & 0x04) + PORTB |= 0x02; + if (led_active & 0x10) + PORTB |= 0x04; + } + + LCD_Clear(); +} diff --git a/Firmware/src/music.c b/Firmware/src/music.c new file mode 100644 index 0000000..5f30063 --- /dev/null +++ b/Firmware/src/music.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include + +#include "music.h" + +/* Sine lookup table for the PWM generator (pp = 32) */ +static const PROGMEM unsigned char sine_lookup[]={ + 0x10,0x13,0x16,0x19,0x1b,0x1d,0x1f,0x20, + 0x20,0x20,0x1f,0x1d,0x1b,0x19,0x16,0x13, + 0x10,0x0d,0x0a,0x07,0x05,0x03,0x01,0x00, + 0x00,0x00,0x01,0x03,0x05,0x07,0x0a,0x0d +}; + +const MUSIC_Note MUSIC_Tetris[] = { + { MUSIC_E5, MUSIC_4 }, + { MUSIC_B4, MUSIC_8 }, + { MUSIC_C5, MUSIC_8 }, + { MUSIC_D5, MUSIC_4 }, + { MUSIC_C5, MUSIC_8 }, + { MUSIC_D5, MUSIC_8 }, + + { MUSIC_A4, MUSIC_4 }, + { MUSIC_A4, MUSIC_8 }, + { MUSIC_C5, MUSIC_8 }, + { MUSIC_E5, MUSIC_4 }, + { MUSIC_D5, MUSIC_8 }, + { MUSIC_C5, MUSIC_8 }, + + { MUSIC_B4, MUSIC_4 + MUSIC_8 }, + { MUSIC_C5, MUSIC_8 }, + { MUSIC_D5, MUSIC_4 }, + { MUSIC_E5, MUSIC_4 }, + + { MUSIC_C5, MUSIC_4 }, + { MUSIC_A4, MUSIC_4 }, + { MUSIC_A4, MUSIC_8 }, + + MUSIC_END }; + +static void delay_ms(uint16_t delay); +static void pwm_init (void); +static void pwm_deinit (void); +static void pwm_gen(uint16_t tone, uint16_t periods); + +void Music_PlayTrack (MUSIC_Track track) +{ + pwm_init(); + + while (!MUSIC_IS_END(*track)) { + + if (track->tone == 0) { + delay_ms(track->duration); + } else { + uint16_t periods = (uint32_t)track->duration * (uint32_t)track->tone / 1000; + pwm_gen(track->tone, periods); + + delay_ms(MUSIC_32 / 2); + } + + ++track; + } + + pwm_deinit(); +} + +static void delay_ms(uint16_t delay) +{ + while (delay--) + _delay_ms(1); +} + +void pwm_init (void) +{ + //setup PWM timer + DDRD |= _BV(PIND5); // speaker pin => output + TCCR1A = _BV(COM1A1) | _BV(COM1A0) | _BV(WGM10); //set on match + TCCR1B = _BV(CS10) | _BV(WGM12); //fast PWM (8 bit), clk/1 source + + //setup sample timer (CTC Mode) + TCCR3A = 0; + TCCR3B = _BV(CS30) | _BV(WGM32); // clk/1 +} + +void pwm_deinit (void) +{ + TCCR1A = 0; + TCCR1B = 0; + TCCR3A = 0; + TCCR3B = 0; +} + +void pwm_gen(uint16_t tone, uint16_t periods) +{ + //calculate single sine sample duration + OCR3A = F_CPU / tone / sizeof(sine_lookup) - 1; + + for (uint16_t period=0; period < periods; ++period) { + for (uint8_t spl=0; spl < sizeof(sine_lookup); ++spl) { + //wait for timer ready for next spl + loop_until_bit_is_set(TIFR3, OCF1A); + TIFR3 = _BV(OCF1A); //clear OCF + + OCR1A = pgm_read_byte(sine_lookup + spl) + 0x70; + } + } +} \ No newline at end of file diff --git a/Firmware/test/README b/Firmware/test/README new file mode 100644 index 0000000..df5066e --- /dev/null +++ b/Firmware/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PIO Unit Testing and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PIO Unit Testing: +- https://docs.platformio.org/page/plus/unit-testing.html diff --git a/Firmware/test/test_demo.c b/Firmware/test/test_demo.c new file mode 100644 index 0000000..a3fcda5 --- /dev/null +++ b/Firmware/test/test_demo.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include "fifo.h" + +#include "unittest_transport.h" + +void test_fifo(void) +{ + uint8_t buf[3]; + fifo_t f; + fifo_init(&f, buf, sizeof(buf)); + fifo_put(&f, 0x11); + fifo_put(&f, 0x22); + fifo_put(&f, 0x33); + + TEST_ASSERT_EQUAL(0x11, fifo_get_nowait(&f)); + TEST_ASSERT_EQUAL(0x22, fifo_get_nowait(&f)); + TEST_ASSERT_EQUAL(0x33, fifo_get_nowait(&f)); +} + +int main() +{ + // NOTE!!! Wait for >2 secs + // if board doesn't support software reset via Serial.DTR/RTS + _delay_ms(2000); + + DDRB |= 0x2; + PORTB &= ~0x2; + + UNITY_BEGIN(); // IMPORTANT LINE! + RUN_TEST(test_fifo); + UNITY_END(); // stop unit testing + + PORTB |= 0x2; + DDRB |= 0x4; + PORTB &= ~0x4; + + while (1) + ; +} diff --git a/Firmware/test/unittest_transport.h b/Firmware/test/unittest_transport.h new file mode 100644 index 0000000..0910c2e --- /dev/null +++ b/Firmware/test/unittest_transport.h @@ -0,0 +1,32 @@ +#ifndef UNITTEST_TRANSPORT_H +#define UNITTEST_TRANSPORT_H + +#include +#include +#include "uart.h" + +void unittest_uart_begin() +{ + // Set Baudrate according to datasheet (16MHz -> 115200 Baud, U2X=1) + UBRR0 = 0x10; + UCSR0B |= (1<>> +**Aufgabenstellung des emg:** + +Es ist mit dem DMM-Board XYZ zu implementieren... +>>> + +### Aufgabenverteilung +@ilyelens: PlatformIO eindrichten, PWM-Demonstration. +... + +### Zeitplan +... + +## Dokumentation +### Hardware +Bauteilliste, Dokumentation, ... + +### Software +Dokumentation + +## Ergebnisse + +Bilder oder Auswertungen vom Tests, ggf. Link zum Video usw. \ No newline at end of file diff --git a/Slides/README.md b/Slides/README.md new file mode 100644 index 0000000..d7de983 --- /dev/null +++ b/Slides/README.md @@ -0,0 +1,3 @@ +# Präsentation + +Hier soll die Präsentation (ggf. mit LaTeX Code) hinterlegt werden. \ No newline at end of file diff --git a/dmm-demo-master/Firmware/src/main.o b/dmm-demo-master/Firmware/src/main.o new file mode 100644 index 0000000000000000000000000000000000000000..fc10c5cf46d073f0bb9277b4d1fc560d8e0965b3 GIT binary patch literal 15408 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 literal 0 HcmV?d00001 diff --git a/dmm-demo-master/Firmware/src/music.o b/dmm-demo-master/Firmware/src/music.o new file mode 100644 index 0000000000000000000000000000000000000000..1f64cee44d75b7a413852280e6d10a8064d7dce2 GIT binary patch literal 1872 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 literal 0 HcmV?d00001 diff --git a/dmm-libs-master/src/spi.o b/dmm-libs-master/src/spi.o new file mode 100644 index 0000000000000000000000000000000000000000..16581d8159cf3c7094b60a171678b5904871cc94 GIT binary patch literal 1448 zcma)5%W4!s6un~)X3Rs)>_iu%2u6@bA%ZBr2$M0G$S@N@1Zg@mon&NQboWBtI6}~k zhKNSoxbp)Pb>SkAPw*46@dM@qbUdfJtEbW=>V@h$=iXbV>fWw;TAZKFWHO>HBUKqP zk+LQ71;J^RFeOK1TzaoXdcS0Q?Q`$p+V|eims`(vUSVwPY`j4PBe%J}HSu-iw`>p5 z`nTMslxAiw7p6*g?w&1Nw5RR!dfQ|+_s&XxkOTm%T_+vjFcX+1sd9u5*EjgItxfCBw@i8gJp3|7~l9k1nv$9DUl?O5B z$~^SDF&|evCof{oiM2}5ZP+z&oNC#*ZZ$;rJp5KW{ zwLIr6xIyUobL~bbq{~frMS;k_=)3J;+4J{sRXn$jZR;JU*7RK8SqcIii}hp=^MInd zWQ~ci_a`vuXO9ap#uVkCNUmd7t%(SW9XxJ@?h@wEkLFd4Lhn&1cHIqKvAL`5drjA- z*G^TmXC$fVuTfPV<&~yti(TuqT3$Qkx&POWBat=h8xy^+;c9*7PR4n7hRXKKJA){1 z+rRQIASb;q@18cjFW&)g_l-EPiXXw(ir=98jPVZM#xV8nft$Bn>&?P%>b-{^*He!@ z(0UDEQ*Q~JdD^sI9S&3PqoKz>XuapaW?$OiNKH)Zy@iLEHPV=uS19^0#xaSZd(6lu khl#&vK z^TUB?Q`>fl5LpsIn-(ovv<`Ru*qDDn*mvH$cjo#asss0(?>pz-@142lzB|)hz2`h0 z4@vV-jLM8CQc1LoWUDm&vWt+%NV-cY}_fKj`_H$*s`*bau^OTv&g)?k_%B%VJfg@P=l; z{ol%(MI!Oe@4V7qY|01nftP`Nuz8`7$t}~&FxSQvIB!NJQLb?z7sv+Q2C_}rh9Y%$ zcD98h-F<^c!pF2$twnB4$*cQQK^vQ;1b}bL?lJeOX>cD^A#$b^-Po)HKCSTGz-JYH z0Qi)`kCrfljm;BymTPj?Q?X^XkI+!XoNCGeA8juaARkq`c&&>ET)d9DL?i+qq6+F0 z{J704X;^TsIY-|GwdTJ7HyVMXVVf=Nr?N?P#|c*}JBRf#NP$|5Zhx8kJn-e?@qN}I2l#(2CO zbNb*4I&E+Tm5#VFF$>L6VoIO50!{6*HkwK%jR^}s<{xb@=JC1SCg#h1l*>8CwjYDB zj|uEg^A02D$N1Ykz7yQ<<(^2B?`=mwop%YGze{Oy9^W_I^LCN2P{05%pBKJCILBvq z5JT0=gY$PRP3lDvQ1w12dVC*By=%a#-bayxvrXz5V5(jt2-m~)@eL;RW`R|`PvHC= zNt1fh2&j4yMUQVlsrMLI)%yaj_D<^IPi2c~Eor=l2VX1ltZ*)Y7rkd7Olq@N|CyQ*c!9AKaUNV>9R}~Es`nX-o*^bp>iq@` Chz`vF literal 0 HcmV?d00001 diff --git a/dmm-libs-master/src/uart.o b/dmm-libs-master/src/uart.o new file mode 100644 index 0000000000000000000000000000000000000000..8349dda855e8459e9cea10aa8a66d98d70aeb58e GIT binary patch literal 3008 zcma)6T}&KR6h7;&fGuHVLlu7_Scyea7iiGb8U;cMt*Ju5M%2V%q05iLE-r&slZGXl zm^4Oq7-;)OAAB_FgGuqBfs)k5m)a+diKg8qjmCteVq!vk!S9=$!(J8|Imwy(ednC} z-8(bq-l?M}+5>@rs0E})@(j@uk#8|Hc?GpnDf?t*aeeN!ugQf!GwzCH zRx|EZnOSbR)0Z93rn8xB*_=qrU1g z4*ZJ29|vwW_%pyS8~piAOt7}`5}x@z749drr8+1@1)RIdTTu4o2~bc<3wT)pf4G20 z3V4OI`;j9UBNCD>jNC70mdoE8@A{lOAs@o1#+nb|tZ#ucf5zupe-@nf2t0!KJMXdF zgYz%?ycc5xU;i7Qk9vHMeCKlxtpCC1)Q{l(f7-&!7VEsQnKZG%YNXY*gx%Z7o zMgHe__4^CBOvX}nbU-Ytr^`BKSvhbb2fB}Tc%ZxW^{#h3WRHzosrZnGKaHo7J~`Ri z{ibz1F=Bgi)<~j%a!}#m$Y4_VKv)ZsllEo>uvg+~bWPfA!?9GZetgo#c0P&^*vXW2 zsKLOExq_j%Z6%T)#~|y??uh4Ro5XsHX>Wa&=ZmpakDVGx4CUs69#7cup?C`GjM&MT zl^7U~4}1W2DrpUj#$zd~e`124yBc1!k4R)cyx7Mzz(s5X*t76rAJ+m$9%WP{3NNbk zpfq48_A&oo(PO!I6XQO95m@K)G;0k{me%l8MV`O|RtMKT90b-qa9yq8enP%JYl1jd z?_s2?ejl*v_X9_s!UOg`ob`u2mS2l|)3vxat!J6;XIstF%!)v6b6xhduFKP`d*=5H z;d7|Y6~LaMvDZw~>w&+9 zIOr$uS9bt;-c|os*NB?Jb$Lgr>ALJk_D_qS7=2LWG%$}6~+=q64=x`2Ez5!RPPG}Og-D!AHSRGeGP2tb=^mAp+N6~p~rKpdMgEbz0l*G zrpC2sSK#LUu0W6XAm5i~U-fske#=yi%#h`$P5CfT_o|XxBiP yS7VOOt3-R5xlpmlzXZOqhQ^Winc6Q1^dZ1&z5>p5`92T9O})cNG^z-43jYJ(DbiE` literal 0 HcmV?d00001