diff --git a/README.md b/README.md index e367e72..f76515d 100644 --- a/README.md +++ b/README.md @@ -8,8 +8,10 @@ ## Платы, входящие в состав пакета Пакет включает в себя поддержку следующих плат: -- [Elbear Ace-Uno](./docs/Elbear_description.md) 8 Mb / 16 Mb / 32 Mb -- [START-MIK32](./docs/Start_mik32_description.md) +- [Elbear Ace-Uno](./docs/Elbear_description.md) 8 Mb / 16 Mb / 32 Mb +- [Elbear Nano](./docs/nano_description.md) +- [Elsomik](./docs/elsomik_description.md) +- [START-MIK32](./docs/Start_mik32_description.md) ## Особенности использования пакета в ArduinoIDE ### Цифровые выводы @@ -49,7 +51,7 @@ |Библиотека|Описание|Заметки| |---------|---------|------| -|[SPI](https://docs.arduino.cc/language-reference/en/functions/communication/SPI/)|Библиотека для работы с интерфейсом SPI|Для работы используется встроенный SPI1. Доступные делители частоты - `SPI_CLOCK_DIV2`, `SPI_CLOCK_DIV4`, `SPI_CLOCK_DIV8`, `SPI_CLOCK_DIV16`, `SPI_CLOCK_DIV32`, `SPI_CLOCK_DIV64`, `SPI_CLOCK_DIV128`, `SPI_CLOCK_DIV256`, обеспечивают частоту работы от 125 кГц до 16 МГц. Скорость работы по умолчанию - 4 МГц. Для задания режима и скорости работы рекомендуется использовать `SPISettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)`, а не соответствующие отдельные функции| +|[SPI](https://docs.arduino.cc/language-reference/en/functions/communication/SPI/)|Библиотека для работы с интерфейсом SPI|Для работы доступно два экземпляра класса - SPI (используется аппаратный SPI1) и SPI1 (используется аппаратный SPI0). Выводы, на которых доступны интерфейсы, перечислены в описании каждой платы. Доступные делители частоты - `SPI_CLOCK_DIV2`, `SPI_CLOCK_DIV4`, `SPI_CLOCK_DIV8`, `SPI_CLOCK_DIV16`, `SPI_CLOCK_DIV32`, `SPI_CLOCK_DIV64`, `SPI_CLOCK_DIV128`, `SPI_CLOCK_DIV256`, обеспечивают частоту работы от 125 кГц до 16 МГц. Скорость работы по умолчанию - 4 МГц. Для задания режима и скорости работы рекомендуется использовать `SPISettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)`, а не соответствующие отдельные функции| |[Wire](https://docs.arduino.cc/language-reference/en/functions/communication/Wire/)|Библиотека для работы с интерфейсом I2C|Для работы используется встроенный I2C1. Доступные частоты работы интерфейса: 100 кГц (`WIRE_FREQ_100K`), 400 кГц (`WIRE_FREQ_400K`), 1000 кГц (`WIRE_FREQ_1000K`). Скорость работы по умолчанию - 100 кГц. В режиме работы в качестве ведомого устройства функции, заданные через `void onReceive( void (*)(int)` и `void onRequest( void (*)(void) )`, выполняются в прерывании| |[SoftwareSerial](https://docs.arduino.cc/learn/built-in-libraries/software-serial/)|Библиотека, реализующая программный последовательный интерфейс.|Доступные скорости работы - от 300 до 57600 бод. Для отправки данных (TX) можно использовать любой цифровой вывод. Для приема данных (RX) можно использовать только выводы, поддерживающие прерывания. Обработчик прерывания и связанные с ним функции располагаются в памяти RAM| |[EEPROM](https://docs.arduino.cc/learn/built-in-libraries/eeprom/)|Библиотека для работы с памятью EEPROM|Для использования доступно 1024 байта встроенной EEPROM памяти. Для корректной работы библиотеки обязательно вызывать функцию `void EEPROM.begin()` перед началом работы с памятью| @@ -94,7 +96,8 @@ # Полезные ссылки * [Материалы по платам ELBEAR ACE-UNO](https://elron.tech/support/#elbear) -* [Телеграмм-канал компании (обновления по проекту ELBEAR и другим)](https://t.me/elrontech) +* [Материалы по платам ELSOMIK](https://elron.tech/support/#elsomik) * [Материалы по плате START-MIK32](https://wiki.mik32.ru/%D0%9E%D1%82%D0%BB%D0%B0%D0%B4%D0%BE%D1%87%D0%BD%D0%B0%D1%8F_%D0%BF%D0%BB%D0%B0%D1%82%D0%B0_%D0%A1%D1%82%D0%B0%D1%80%D1%82) +* [Телеграмм-канал компании](https://t.me/elrontech) При возникновении вопросов или выявлении проблем можно оставить заявку [здесь](https://gitflic.ru/project/elron-tech/elbear_arduino_bsp/issue). diff --git a/boards.txt b/boards.txt index 0e5ff7b..78ea872 100644 --- a/boards.txt +++ b/boards.txt @@ -14,7 +14,7 @@ aceUno8Mb.upload.speed=230400 # tool for bootloader update aceUno8Mb.bootloader.tool=mik32_upload aceUno8Mb.bootloader.tool.default=mik32_upload -aceUno8Mb.bootloader.file=ace-uno/bootloader.hex +aceUno8Mb.bootloader.file=elbear/bootloader.hex aceUno8Mb.bootloader.interface=ftdi/mikron-link.cfg # build options @@ -40,7 +40,7 @@ aceUno16Mb.upload.speed=230400 # tool for bootloader update aceUno16Mb.bootloader.tool=mik32_upload aceUno16Mb.bootloader.tool.default=mik32_upload -aceUno16Mb.bootloader.file=ace-uno/bootloader.hex +aceUno16Mb.bootloader.file=elbear/bootloader.hex aceUno16Mb.bootloader.interface=ftdi/mikron-link.cfg # build options @@ -66,7 +66,7 @@ aceUno32Mb.upload.speed=230400 # tool for bootloader update aceUno32Mb.bootloader.tool=mik32_upload aceUno32Mb.bootloader.tool.default=mik32_upload -aceUno32Mb.bootloader.file=ace-uno/bootloader.hex +aceUno32Mb.bootloader.file=elbear/bootloader.hex aceUno32Mb.bootloader.interface=ftdi/mikron-link.cfg # build options @@ -78,6 +78,56 @@ aceUno32Mb.build.variant=elbear_ace_uno aceUno32Mb.build.extra_flags= aceUno32Mb.build.flags= +##################### Nano ##################### +nano.name=Elbear Nano + +# tool for firmware update +nano.upload.tool=elbear_uploader +nano.upload.protocol=elbear_uploader +nano.upload.maximum_size=8388608 +nano.upload.maximum_data_size=16384 +nano.upload.speed=230400 + +# tool for bootloader update +nano.bootloader.tool=mik32_upload +nano.bootloader.tool.default=mik32_upload +nano.bootloader.file=elbear/bootloader.hex +nano.bootloader.interface=ftdi/mikron-link.cfg + +# build options +nano.build.mcu=MIK32_Amur +nano.build.f_cpu=32000000UL +nano.build.board=ELBEAR_NANO +nano.build.core=arduino +nano.build.variant=elbear_nano +nano.build.extra_flags= +nano.build.flags= + +##################### Elsomik ##################### +elsomik.name=Elsomik + +# tool for firmware update +elsomik.upload.tool=elbear_uploader +elsomik.upload.protocol=elbear_uploader +elsomik.upload.maximum_size=8388608 +elsomik.upload.maximum_data_size=16384 +elsomik.upload.speed=230400 + +# tool for bootloader update +elsomik.bootloader.tool=mik32_upload +elsomik.bootloader.tool.default=mik32_upload +elsomik.bootloader.file=elsomik/bootloader.hex +elsomik.bootloader.interface=ftdi/mikron-link.cfg + +# build options +elsomik.build.mcu=MIK32_Amur +elsomik.build.f_cpu=32000000UL +elsomik.build.board=ELSOMIK +elsomik.build.core=arduino +elsomik.build.variant=elsomik +elsomik.build.extra_flags= +elsomik.build.flags= + ##################### START-MIK32-V1 ##################### start-mik32-v1.name=START-MIK32-V1 diff --git a/bootloaders/ace-uno/bootloader.hex b/bootloaders/elbear/bootloader.hex similarity index 100% rename from bootloaders/ace-uno/bootloader.hex rename to bootloaders/elbear/bootloader.hex diff --git a/bootloaders/elsomik/bootloader.hex b/bootloaders/elsomik/bootloader.hex new file mode 100644 index 0000000..3e826ca --- /dev/null +++ b/bootloaders/elsomik/bootloader.hex @@ -0,0 +1,261 @@ +:020000040100F9 +:10000000FD62938202400100FD12E39E02FE374131 +:10001000000213010100B701000293810100B7152E +:100020000001938505FF3716000113060602B70687 +:1000300000029386060039A083A2050023A0560083 +:1000400091059106E3EAC5FEB71500019385050207 +:100050003716000113060602B7060002938606262D +:1000600039A083A2050023A0560091059106E3EA7A +:10007000C5FEB70500029385050337060002130687 +:10008000062621A023A005009105E3EDC5FEB700DB +:100090000001E780C00AB7000001E780C00AB7107E +:1000A0000001E780808473005010F5BF828000005B +:1000B0000000000000000000000000000000000040 +:1000C0006F004000197106C20AC40EC612C816CAD3 +:1000D0001ACC1ECE22D026D22AD42ED632D836DA48 +:1000E0003ADC3EDEC2C0C6C2CAC4CEC6D2C8D6CA78 +:1000F000DACCDECEE2D0E6D2EAD4EED6F2D8F6DA28 +:10010000FADCFEDE970000009380E00482909240CB +:100110002241B2414242D2426243F24302549254DB +:100120002255B2554256D2566257F2570648964863 +:100130002649B649464AD64A664BF64B065C965C5B +:10014000265DB65D465ED65E665FF65F096173004A +:10015000203001A03D432A876373C3029377F700E1 +:10016000BDEFADE5937606FF3D8ABA960CC34CC34E +:100170000CC74CC74107E36BD7FE11E28280B30680 +:10018000C3408A069702000096966780A600230760 +:10019000B700A306B7002306B700A305B7002305E1 +:1001A000B700A304B7002304B700A303B7002303D9 +:1001B000B700A302B7002302B700A301B7002301D1 +:1001C000B700A300B7002300B700828093F5F50FB6 +:1001D00093968500D58D93960501D58D61B793963D +:1001E00027009702000096968682E78086FA96801E +:1001F000C1171D8F3E96E374C3F8A5B7B707050076 +:100200000947D8CFB7170500938707C0984385667D +:1002100093860640558F98C398471367074098C741 +:10022000B71708009387074023A0070023A2070001 +:1002300023A407001307A008D8C77D57D8CF354798 +:1002400098C3D84F935657018D8AE5DE8280B71741 +:1002500008009387074023A0070023A2070023A4D8 +:10026000070023A607007D57D8CF23A40702B7179E +:100270000500938707C09843F1769386F63F758F04 +:1002800098C398471377F7BF98C7B7070500094782 +:1002900098D38280B71708009387074088D7D84F34 +:1002A000137707046DDF82803707000203234704BA +:1002B000B706000237150800B7450F0023A406044F +:1002C0008147014613050540938515240328C50180 +:1002D000B308F30013780802630C080205C2232256 +:1002E000170537470F0023A4F60413070724639765 +:1002F000E700B707000205472383E700B7170800A8 +:1003000093870740C85342054181828005467DBFDF +:100310008507E39DB7FE7DD2B7470F00938707247B +:1003200023A4F60423221705E9B7411106C622C407 +:1003300026C2AA84EF00B022E1689388086A0148C7 +:100340008147014781460146B70520C72685379476 +:100350009800EF003006130414687D1419E40D456D +:10036000B240224492444101828085452685EF00B7 +:10037000702005897DF10145E5B7411122C437049C +:100380000002930704008C43B70700804AC0BE9563 +:10039000B707000223AEB70206C626C293974501EF +:1003A000130404003709000289E713058900EF00F0 +:1003B00090290C40B70400029386C4041306001071 +:1003C00013058900EF0070231C4037070002835695 +:1003D0008703938707101CC013060010B68763F4C9 +:1003E000C600930700101384C4041305F400938718 +:1003F00007F01306100F814513040410231CF702A5 +:10040000913BA2851385C4043D46EF0010282320AC +:1004100004002322040023240400231604002307DD +:100420000400B240224492440249410182805D713D +:10043000130680028145280886C6293BBD47230C48 +:10044000F1008947230EF1003ED2E1779387070838 +:100450002C080A85231AF102E52BB64061618280DF +:100460005D71A2C4370400021305840086C6A6C2CB +:10047000CAC0652513058400EF00807D85451305FE +:100480008400EF00300F8D47814463E3A700AA8406 +:10049000894513058400EF00F00D937725002A8627 +:1004A00089E7136625001376F60FA68513058400E9 +:1004B000EF00B00FE1689388086A0148814701475F +:1004C00081460146B705203813058400E525E1681B +:1004D00038009388086A1308000285468147014660 +:1004E000B70599EB1305840023040100E125B71536 +:1004F00000015146938505FD6800EF0010191309AE +:100500008400832709006C0051463ED085473ED2C7 +:100510006810C1673ED4EF005017B70607009C4231 +:100520003707F1FF7D17F98F08109CC20D2DB640DB +:1005300026449644064961618280411106C6013B0A +:100540000537B707008073905730B700008082905E +:10055000B2404101828041113707000222C406C621 +:100560009307070083C76700854613040700638E5F +:10057000D70009476388E70023030400B240224400 +:10058000410182801305000F3133B71708009387AC +:100590000740D84F218B09C7D84F13678700D8CFA2 +:1005A000693FD9BF411106C622C426C24AC083474B +:1005B000350005476383E70811472A846389E7000C +:1005C0008DCFB24022449244024941018280B70754 +:1005D000000283D7870391C34D3383474400034709 +:1005E0005400E2074207BA97370700022320F704B6 +:1005F000370700022320F700E9B7370900028354C8 +:1006000089030346050093054500370500021305DD +:10061000C5042695EF00700783470400BE94C2040A +:10062000C180231C99029307F00FE3FC97F8224442 +:10063000B24092440249410189B33D45A139B7070F +:10064000000283D7870391C30D3B2244B2409244FA +:1006500002494101DDB53707000241119306070049 +:1006600003DF460026C4B704000283A2840422C626 +:100670003715080037040002B7480F0037430F0052 +:10068000370E00024AC28147232A04021309FFFFE2 +:10069000814E814681458143014801461307070089 +:1006A000130505409388182413030324130ECE1555 +:1006B000636FE60363850E0009462303C70089C6FE +:1006C000B7060002A388F60299C1232A74026304C4 +:1006D000080023A4540483476700A9E73244A244D6 +:1006E0001249370500021305C515410165BD814258 +:1006F0000328C50113780802631B08028502E399E9 +:1007000012FF89C6B7060002A388F60299C1232A00 +:100710007402B7470F009387072423A4F404854786 +:100720002303F7003244A244124941018280E38A44 +:1007300062FC03284502937FF80F637D260113783E +:10074000F80FC29385453308CE002300F801050653 +:100750000548B9BFB307704093F7F70F6394FF00E4 +:100760008546D5B7854EEDBF011122CC4EC652C489 +:1007700037040002B7490F00371ADCBA26CA4AC844 +:1007800056C25AC006CE13040400370900029389EA +:10079000F923930A0003B7040002391A370B000249 +:1007A000213683274904A303A40063F3F9007133BE +:1007B0008347640099C34533E5B783467400638873 +:1007C0005605930700066381F60603C704038D47A9 +:1007D000998F8E07B357FA0093F7F70F6393F606D6 +:1007E0009307170093F7F70F2388F4021147639DCF +:1007F000E7003D45453413058B00053E29C113052F +:10080000000F493C238804022322090451BF3D45BF +:100810002322090423880402B53C793405052312F8 +:10082000A4003D45853CADBF3D45232209042388F6 +:1008300004028D340D3583476400B5FFDDB73D45B7 +:10084000C9B723880402A9BF011106CE22CCC53640 +:100850003704000213058400C92413058400CD2E3B +:10086000E1689388086A0148814778008546014617 +:10087000B705D9EB1305840023060100252EE16896 +:100880009388086A01488147014781460146B705B8 +:1008900038FF13058400392E9532F9350547AA87AC +:1008A0006305E50209476300E506054591EBB706D8 +:1008B0000600DC4A7D771307F73FF98FDCCA014554 +:1008C00082807D1719EB0D4582809306004037A783 +:1008D000070013070712B7050500905D7D8E75D2DE +:1008E000370606005C4A7D771307F73FF98FD58FEF +:1008F00041115CCA02C613073006B2476359F700BC +:10090000014541018280856693860680C9B7B2475A +:1009100085073EC6DDB791476307F50263EAA70086 +:100920008547630AF50489476309F5040545828014 +:10093000A147E31DF5FE0947094501A8FD1781EF11 +:10094000C8D20D45828005470D45B7A7070093879C +:100950000712B7060500905E798E6DD28A05C98DA3 +:100960004111CCD202C613073006B247635AF700D2 +:100970000145410182801147C9BF21470145F1B7B7 +:10098000B24785073EC6D5B70547AA876305E50286 +:1009900009476302E506054591EBB70606009C4A48 +:1009A0007D771307F73FF98F9CCA014582807D1739 +:1009B00019EB0D4582809306004037A70700130707 +:1009C0000712B7050500905D7D8E75D237070600CA +:1009D0001C4B7D761306F63FF18FD58F1CCB8547D8 +:1009E0001CCF411102C613073006B2476359F70006 +:1009F0000145410182808566938606807DBFB247AE +:100A000085073EC6DDB711C98547630DF50205456B +:100A10008280FD1791EB0D4582800946B7A707003C +:100A200093870712B7060500985E718F7DD3411139 +:100A3000C8D602C613073006B2476357F700014510 +:100A4000410182800546D9BFB24785073EC6EDB752 +:100A5000011126CAB7040600DC4806CE22CC4AC8DB +:100A60004EC652C456C2F19BDCC89C482A89C84570 +:100A7000F19B9CC883C7C5012E848A07DCC883C745 +:100A8000D5018A079CC8193D0C44AA8A0345440035 +:100A900059351848B70705002A8A98C3584808509E +:100AA000D8C3184C98C7CD35AA894850A93F834769 +:100AB00004002A8793F6170089E6D44893E62600B7 +:100AC000D4C893F6270099E637060600544A93E601 +:100AD000160054CA93F6470099E637060600144AF2 +:100AE00093E6260014CAA18B99E7B70606009C4A34 +:100AF00093E717009CCAF240624423205901232245 +:100B00004901232439012326E900D244B249224A6B +:100B1000924A4A85424905618280011106CE22CC63 +:100B200002C402C62147B707050037550800D8C7D9 +:100B300005448D478A85130505803EC022C2292AB7 +:100B4000375508009307C0038A851305058022C224 +:100B500022C43EC01122F2406244056182804111EC +:100B600022C406C62A84553F18405C4F93E707010C +:100B70005CCF1C441CCB5C4085CB1C43B7061000EB +:100B8000D58F1CC3144C5C48B240D606CE07D58F17 +:100B900083460401C206D58F8346C4012244E2067F +:100BA000D58F1CCF410182801C43B706F0FFFD1694 +:100BB000F58FC1BF032305002A8E0325C3011365EA +:100BC0000502232EA3002324C30013962601498285 +:100BD0004D8E232603012322C3001396050163547F +:100BE000060299C20545B1CB01476346D700639C15 +:100BF00008020D4582803386E7000346060005079C +:100C0000230AC300DDB799C2054505CB8147E3D070 +:100C1000D7FE03260E00034546013306F70085077D +:100C20002300A600EDB783270E00FD18DC4F93F7D5 +:100C30000702D5DF11656D8D11E18280B7070700CE +:100C400083C7470113F585001D8D3335A0008280D1 +:100C50001C414147D8CF8280B7470800938707409F +:100C60002A886304F508B757080093870780630450 +:100C7000F50A37470800630DE50A05458280331EF3 +:100C80001F013376DE0129C683A3450088431393F1 +:100C9000180033966F001346F6FF13F43300718D7E +:100CA00033146400418D88C3638B5302638C030249 +:100CB000084303AEC500718D331E6E003365C50158 +:100CC00008C38842698E884533156500498E90C2F5 +:100CD000850833D51E0145F5324441018280232623 +:100CE000C801F9B72324C801E1B7B71605003717C3 +:100CF0000500B7170500938646C1130707C1938700 +:100D0000C7C083AE05008148054F8D4F914233D552 +:100D10001E0105ED8280B716050037170500B717CD +:100D20000500938606C21307C7C1938787C1D1BF49 +:100D3000B716050037170500B7170500938686C05C +:100D4000130747C0938707C06DBF331E1F0133765B +:100D5000DE0119E2850865BF411122C635B7E16899 +:100D60009388086A01488147014781460146B705D3 +:100D7000200689B5011106CEA307010089476393B8 +:100D8000F502B7052035E1681307F1009388086A7A +:100D90000148814785460146313DF2400345F10057 +:100DA00005618280B7052005F9BF011106CE22CC6E +:100DB00026CA2306B100AA84A306C1004D37E16804 +:100DC0009388086A01487C00014789460146B78537 +:100DD000200126850964F93B130414717D1419E47C +:100DE0000D45F2406244D2440561828085452685E6 +:100DF0005137058965F50145EDB7011106CE22CCC5 +:100E000026CA2E844AC8AA84328936C6893FB24788 +:100E1000E16822869388086A01480147CA86B78537 +:100E200080022685616479331304146A7D1411C429 +:100E3000854526858137058975F9F2406244D2449B +:100E4000424905618280011106CE22CC26CA2EC6F7 +:100E5000AA8431373246E1689388086A014881479D +:100E600001478146B705802026856164A1331304BC +:100E7000146A7D1411C485452685ED3D058975F9F3 +:100E8000F2406244D24405618280B3C7A5008D8BD5 +:100E9000B308C500B1E78D4763F4C7049377350005 +:100EA0002A87B9EB13F6C8FFB306E64093070002A2 +:100EB00063C8D706AE86BA876371C70203A8060067 +:100EC0009107910623AE07FFE3EAC7FE9307F6FFFB +:100ED000998FF19B91073E97BE95636617018280BB +:100EE0002A87637E150383C7050005078505A30FC1 +:100EF000F7FEE39AE8FE828083C605000507937734 +:100F00003700A30FD7FE8505D1DF83C6050005078F +:100F100093773700A30FD7FE8505F9FF61B782806D +:100F2000411122C61304000283A3050083A24500D9 +:100F300083AF850003AFC50083AE050103AE450155 +:100F400003A3850103A8C501945113074702B30702 +:100F5000E640232E77FC232057FE2322F7FF23248D +:100F6000E7FF2326D7FF2328C7FF232A67FE232C6A +:100F700007FF232ED7FE93854502E347F4FAAE869A +:100F8000BA876371C70203A806009107910623AED2 +:100F900007FFE3EAC7FE9307F6FF998FF19B9107DE +:100FA0003E97BE956365170132444101828083C735 +:100FB000050005078505A30FF7FEE387E8FE83C755 +:100FC000050005078505A30FF7FEE392E8FEE9BFDC +:100FD00020000000010000000300000006000000E7 +:100FE000EB00000000000000000000000000000016 +:100FF000000000800000000000000700000000006A +:1010000000000000000000000000000000000000E0 +:1010100000000000000000000000000000000000D0 +:0400000501000000F6 +:00000001FF diff --git a/cores/arduino/Tone.cpp b/cores/arduino/Tone.cpp index 8dba4e1..6c9f04d 100644 --- a/cores/arduino/Tone.cpp +++ b/cores/arduino/Tone.cpp @@ -45,7 +45,7 @@ static void Timer16_Init(uint8_t prescaler) htimer16_1.Trigger.TimeOut = TIMER16_TIMEOUT_DISABLE; htimer16_1.Filter.ExternalClock = TIMER16_FILTER_NONE; htimer16_1.Filter.Trigger = TIMER16_FILTER_NONE; - htimer16_1.Waveform.Enable = TIMER16_WAVEFORM_GENERATION_ENABLE; + htimer16_1.Waveform.Enable = TIMER16_WAVEFORM_GENERATION_DISABLE; htimer16_1.Waveform.Polarity = TIMER16_WAVEFORM_POLARITY_NONINVERTED; htimer16_1.EncoderMode = TIMER16_ENCODER_DISABLE; HAL_Timer16_Init(&htimer16_1); diff --git a/cores/arduino/WInterrupts.c b/cores/arduino/WInterrupts.c index 6b4783f..0f63b22 100644 --- a/cores/arduino/WInterrupts.c +++ b/cores/arduino/WInterrupts.c @@ -6,6 +6,9 @@ #include "WInterrupts.h" #include "wiring_LL.h" +// interrupts are enabled by default after setup() +static bool intIsEnabled = true; + typedef void (*voidFuncPtr)(void); // empty irq handler @@ -18,14 +21,20 @@ static void nothing(void) void interrupts(void) { GLOBAL_IRQ_ENABLE(); + intIsEnabled = true; } // disable global interrupts void noInterrupts(void) { GLOBAL_IRQ_DISABLE(); + intIsEnabled = false; } +bool isInterruptsEnabled(void) +{ + return intIsEnabled; +} // we can provide no more than 8 interrupts on gpio at the same time static volatile voidFuncPtr intFunc[EXTERNAL_INTERRUPTS_QTY] = { diff --git a/cores/arduino/WInterrupts.h b/cores/arduino/WInterrupts.h index 4bab44e..50b3b9b 100644 --- a/cores/arduino/WInterrupts.h +++ b/cores/arduino/WInterrupts.h @@ -6,10 +6,12 @@ extern "C" { #endif #include +#include "stdbool.h" // enable/disable interrupts void interrupts(void); void noInterrupts(void); +bool isInterruptsEnabled(void); // attach/detach interrupt to pin void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode); diff --git a/cores/arduino/board.cpp b/cores/arduino/board.cpp index da0f39b..591676c 100644 --- a/cores/arduino/board.cpp +++ b/cores/arduino/board.cpp @@ -25,8 +25,8 @@ extern "C" void SystemInit(void) // called after setup() void post_init(void) { - // enable global interrupts by default - interrupts(); + if(isInterruptsEnabled()) // if user has called noInterrupts() in setup(), this value is false + interrupts(); // enable global interrupts } // --------------------- other --------------------- // diff --git a/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_timer16.h b/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_timer16.h index 60dcc2c..5798938 100644 --- a/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_timer16.h +++ b/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_timer16.h @@ -144,8 +144,8 @@ typedef enum __HAL_Timer16_EncoderTypeDef */ typedef enum __HAL_Timer16_WaveformGenTypeDef { - TIMER16_WAVEFORM_GENERATION_ENABLE = 0, /**< Выключить генерацию волновой формы. */ - TIMER16_WAVEFORM_GENERATION_DISABLE = 1 /**< Включить генерацию волновой формы. */ + TIMER16_WAVEFORM_GENERATION_ENABLE = 0, /**< Включить генерацию волновой формы. */ + TIMER16_WAVEFORM_GENERATION_DISABLE = 1 /**< Выключить генерацию волновой формы. */ } HAL_Timer16_WaveformGenTypeDef; /** diff --git a/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_tsens.h b/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_tsens.h index 661c10b..b7a3814 100644 --- a/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_tsens.h +++ b/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_tsens.h @@ -105,7 +105,7 @@ typedef enum __HAL_TSENS_ClockTypeDef /** * @brief Определение структуры TSENS Handle. */ -typedef struct __SPI_HandleTypeDef +typedef struct __TSENS_HandleTypeDef { ANALOG_REG_TypeDef *Instance; /**< Адрес регистров блока управления аналоговой подсистемой. */ @@ -119,7 +119,7 @@ typedef struct __SPI_HandleTypeDef /** * @brief Возвращаемая структура для функции @ref HAL_TSENS_SingleStart. */ -typedef struct __WDT_ClockTypeDef +typedef struct __TSENS_ValueTypeDef { HAL_StatusTypeDef statusHAL; /**< Статус HAL. */ diff --git a/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_wdt.h b/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_wdt.h index 9708e0f..a89626a 100644 --- a/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_wdt.h +++ b/cores/arduino/mik32/hal/peripherals/Include/mik32_hal_wdt.h @@ -105,7 +105,7 @@ typedef struct __WDT_ClockTypeDef } WDT_ClockTypeDef; -void HAL_RTC_MspInit(WDT_HandleTypeDef* hwdt); +void HAL_WDT_MspInit(WDT_HandleTypeDef* hwdt); HAL_StatusTypeDef HAL_WDT_Init(WDT_HandleTypeDef *hwdt, uint32_t timeout); HAL_StatusTypeDef HAL_WDT_Refresh(WDT_HandleTypeDef *hwdt, uint32_t timeout); HAL_StatusTypeDef HAL_WDT_Start(WDT_HandleTypeDef *hwdt, uint32_t timeout); diff --git a/cores/arduino/mik32/hal/peripherals/Source/mik32_hal_wdt.c b/cores/arduino/mik32/hal/peripherals/Source/mik32_hal_wdt.c index 7c39985..9b12a7a 100644 --- a/cores/arduino/mik32/hal/peripherals/Source/mik32_hal_wdt.c +++ b/cores/arduino/mik32/hal/peripherals/Source/mik32_hal_wdt.c @@ -3,14 +3,56 @@ uint16_t TimeOut = 20; uint16_t WDT_prescale[] = {1, 2, 4, 16, 64, 256, 1024, 4096}; +/** + * @brief Запись слова в регистр CON (конфигурация WDT) + * @param hwdt указатель на структуру WDT_HandleTypeDef, которая содержит + * информацию о конфигурации для модуля WDT. + * @param conValue 32-х битное слово + */ +static void __attribute__( ( noinline, section(".ram_text") ) ) HAL_WDT_Write_Word_To_CON(WDT_HandleTypeDef* hwdt, uint32_t conValue) +{ + //Если позволить компилятору inlining, станет невозможно выделить функцию в отдельную секцию. + intptr_t ptr = (intptr_t)(hwdt->Instance); + /** + * Попытки избежать использования отдельной переменной-указателя, такие как: + * "sb a0,0x9C(%a0)\n\t" + * : "m" (*(hwdt->Instance)) + * не работают из-за бага GCC (internal compiler error <...> riscv_print_operand_address) + * */ + asm volatile( + "li a0,0x1E\n\t" //Store unlock byte somewhere + "sb a0,0x9C(%0)\n\t" //Write UNLOCK byte into WDT KEY register + "sw %1,0x84(%0)\n\t" //Write payload + : + : "r" (ptr), "r" (conValue) + : "a0" + ); +} +/** + * @brief Запись байта в регистр KEY (пуск/остановка WDT) + * @param hwdt указатель на структуру WDT_HandleTypeDef, которая содержит + * информацию о конфигурации для модуля WDT. + * @param key байт для записи ( @ref WDT_KEY_START или @ref WDT_KEY_STOP ) + */ +static void __attribute__( ( noinline, section(".ram_text") ) ) HAL_WDT_Write_Byte_To_KEY(WDT_HandleTypeDef* hwdt, uint8_t key) +{ + intptr_t ptr = (intptr_t)(hwdt->Instance); + asm volatile( + "li a0,0x1E\n\t" //Store unlock byte somewhere + "sb a0,0x9C(%0)\n\t" //Write UNLOCK byte into WDT KEY register + "sb %1,0x9C(%0)\n\t" //Write payload + : + : "r" (ptr), "r" (key) + : "a0" + ); +} + /** * @brief Инициализация WDT MSP. * @param hwdt указатель на структуру WDT_HandleTypeDef, которая содержит * информацию о конфигурации для модуля WDT. - * - * информацию о конфигурации для модуля WDT. */ -__attribute__((weak)) void HAL_RTC_MspInit(WDT_HandleTypeDef *hwdt) +__attribute__((weak)) void HAL_WDT_MspInit(WDT_HandleTypeDef *hwdt) { __HAL_PCC_WDT_CLK_ENABLE(); } @@ -82,7 +124,7 @@ HAL_StatusTypeDef HAL_WDT_Init(WDT_HandleTypeDef *hwdt, uint32_t timeout) return HAL_ERROR; } - HAL_RTC_MspInit(hwdt); + HAL_WDT_MspInit(hwdt); if (HAL_WDT_Stop(hwdt, timeout) != HAL_OK) @@ -100,8 +142,7 @@ HAL_StatusTypeDef HAL_WDT_Init(WDT_HandleTypeDef *hwdt, uint32_t timeout) } uint32_t conValue = (wdtClock.divIndex << WDT_CON_PRESCALE_S) | WDT_CON_PRELOAD(wdtClock.tick); - hwdt->Instance->KEY = WDT_KEY_UNLOCK; - hwdt->Instance->CON = conValue; + HAL_WDT_Write_Word_To_CON(hwdt, conValue); return HAL_OK; } @@ -115,8 +156,7 @@ HAL_StatusTypeDef HAL_WDT_Init(WDT_HandleTypeDef *hwdt, uint32_t timeout) */ HAL_StatusTypeDef HAL_WDT_Refresh(WDT_HandleTypeDef *hwdt, uint32_t timeout) { - hwdt->Instance->KEY = WDT_KEY_UNLOCK; - hwdt->Instance->KEY = WDT_KEY_START; + HAL_WDT_Write_Byte_To_KEY(hwdt, WDT_KEY_START); while (timeout--) { @@ -139,8 +179,7 @@ HAL_StatusTypeDef HAL_WDT_Refresh(WDT_HandleTypeDef *hwdt, uint32_t timeout) */ HAL_StatusTypeDef HAL_WDT_Start(WDT_HandleTypeDef *hwdt, uint32_t timeout) { - hwdt->Instance->KEY = WDT_KEY_UNLOCK; - hwdt->Instance->KEY = WDT_KEY_START; + HAL_WDT_Write_Byte_To_KEY(hwdt, WDT_KEY_START); while (timeout--) { @@ -162,8 +201,7 @@ HAL_StatusTypeDef HAL_WDT_Start(WDT_HandleTypeDef *hwdt, uint32_t timeout) */ HAL_StatusTypeDef HAL_WDT_Stop(WDT_HandleTypeDef *hwdt, uint32_t timeout) { - hwdt->Instance->KEY = WDT_KEY_UNLOCK; - hwdt->Instance->KEY = WDT_KEY_STOP; + HAL_WDT_Write_Byte_To_KEY(hwdt, WDT_KEY_STOP); while (timeout--) { @@ -185,8 +223,7 @@ HAL_StatusTypeDef HAL_WDT_Stop(WDT_HandleTypeDef *hwdt, uint32_t timeout) void HAL_WDT_SetPrescale(WDT_HandleTypeDef *hwdt, HAL_WDT_Prescale prescale) { uint32_t conValue = (hwdt->Instance->CON & (~WDT_CON_PRESCALE_M)) | ((prescale << WDT_CON_PRESCALE_S) & WDT_CON_PRESCALE_M); - hwdt->Instance->KEY = WDT_KEY_UNLOCK; - hwdt->Instance->CON = conValue; + HAL_WDT_Write_Word_To_CON(hwdt, conValue); } /** @@ -198,6 +235,5 @@ void HAL_WDT_SetPrescale(WDT_HandleTypeDef *hwdt, HAL_WDT_Prescale prescale) void HAL_WDT_SetPreload(WDT_HandleTypeDef *hwdt, HAL_WDT_Prescale preload) { uint32_t conValue = (hwdt->Instance->CON & (~WDT_CON_PRELOAD_M)) | WDT_CON_PRELOAD(preload); - hwdt->Instance->KEY = WDT_KEY_UNLOCK; - hwdt->Instance->CON = conValue; + HAL_WDT_Write_Word_To_CON(hwdt, conValue); } \ No newline at end of file diff --git a/cores/arduino/trap_handler.c b/cores/arduino/trap_handler.c index 3010ac2..5754182 100644 --- a/cores/arduino/trap_handler.c +++ b/cores/arduino/trap_handler.c @@ -5,7 +5,7 @@ extern void serial_interrupt_handler(uint8_t uartNumInt); extern void gpio_interrupt_handler(void); extern void tone_interrupt_handler(void); -void __attribute__((weak)) wire_interrupt_handler(void) +void __attribute__((weak)) wire_interrupt_handler(uint8_t num) { // dummy function for case when wire library is not in use } @@ -70,9 +70,12 @@ void __attribute__((noinline, section(".ram_text"), optimize("O3"))) trap_handle if (EPIC_CHECK_UART_1()) serial_interrupt_handler(1); - // i2c interrupt + // i2c0 interrupt + if (EPIC_CHECK_I2C_0()) + wire_interrupt_handler(0); + if (EPIC_CHECK_I2C_1()) - wire_interrupt_handler(); + wire_interrupt_handler(1); // reset all interrupts EPIC_CLEAR_ALL(); diff --git a/cores/arduino/wiring_analog.c b/cores/arduino/wiring_analog.c index 73c0c55..f33a733 100644 --- a/cores/arduino/wiring_analog.c +++ b/cores/arduino/wiring_analog.c @@ -73,6 +73,7 @@ uint32_t analogRead(uint32_t PinNumber) // extra least significant bits read from the ADC are discarded value = (value >> (MCU_ADC_RESOLUTION - currentResolution)); } + additionalPinsDeinit(PinNumber); } else ErrorMsgHandler("analogRead(): invalid analog pin number"); diff --git a/docs/Elbear_description.md b/docs/Elbear_description.md index 150508e..7980e5e 100644 --- a/docs/Elbear_description.md +++ b/docs/Elbear_description.md @@ -4,11 +4,24 @@ ![Pinout](pinout.PNG) ### Цифровые выводы На плате Elbear Ace-Uno доступны встроенные светодиод и кнопка. Для их использования необходимо воспользоваться макросами `LED_BUILTIN` и `BTN_BUILTIN`, передавая их в качестве аргументов функции вместо номера цифрового вывода. Макросу `LED_BUILTIN` соответствует номер вывода D22, а макросу `BTN_BUILTIN` - D23. +### Аналоговые выводы +Выводы A0...A5 на плате могут использоваться как в аналоговом, так и в цифровом режиме. +Для использования вывода в качестве аналогового необходимо перевести соответствующий DIP-переключатель, расположенный рядом с аналоговыми выводами, в положение OFF. В этом режиме внешнее напряжение, подаваемое на вывод, будет понижаться резистивным делителем перед подачей на микроконтроллер. +Для использования вывода в качестве цифрового нужно перевести переключатель в положение ON. В этом случае напряжение с вывода платы передается на микроконтроллер без изменений. +Таблица соответствия выводов платы и номера DIP-переключателя представлена ниже. Переключатель 5 относится сразу к двум аналоговым выводам - А4, А5. +|Вывод|Номер переключателя| +|---------|---------| +|А0|1| +|А1|2| +|А2|3| +|А3|4| +|А4|5| +|А5|5| #### ШИМ -На плате Elbear Ace-Uno доступны следующие выводы для формирования ШИМ-сигнала: D3, D5, D6, D9, D10, D11. Генерация сигнала осуществляется с помощью 32-битного таймера. Выводы D3, D5, D6, D9 подключены к таймеру 1, выводы D10, D11 подключены к таймеру 2. Выводы, подключенные к одному и тому же таймеру, выдают ШИМ-сигнал одинаковой частоты. +На плате Elbear Ace-Uno доступно 8 выводов для формирования ШИМ-сигнала: D3, D5, D6, D9...D13. Генерация сигнала осуществляется с помощью 32-битного таймера. Выводы D3, D5, D6, D9 подключены к таймеру 1, выводы D10...D13 подключены к таймеру 2. Выводы, подключенные к одному и тому же таймеру, выдают ШИМ-сигнал одинаковой частоты. Цифровой вывод D10 не может быть использован для генерации ШИМ, если одновременно активен интерфейс SPI. Это ограничение связано с особенностями работы микроконтроллера. Ограничение не распространяется на использование D10 в качестве цифрового вывода при активном SPI. ### Прерывания -На плате Elbear Ace-Uno доступно 7 прерываний, настраиваемых функцией `void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)`: +На плате Elbear Ace-Uno доступно 8 прерываний, настраиваемых функцией `void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)`: |Цифровой вывод|Номер прерывания| |---------|---------| @@ -18,8 +31,15 @@ |D5|3| |D8|4| |D9|5| -|`BTN_BUILTIN`|6| +|A1|6| +|`BTN_BUILTIN`|7| + +При использовании аналогового вывода A1 для работы с прерываниями необходимо предварительно перевести вывод в режим цифрового. Для этого нужно перевести DIP-переключатель номер 2 в положение ON. ### Serial Интерфейс UART0 доступен на выводах D0, D1, для работы с ним используется экземпляр класса под названием `Serial`. -Интерфейс UART1 доступен на выводах D7, D8, используемый экземпляр класса - `Serial1`. \ No newline at end of file +Интерфейс UART1 доступен на выводах D7, D8, используемый экземпляр класса - `Serial1`. + +### SPI +Интерфейс SPI1 доступен на выводах D11, D12, D13. Для работы с ним используется экземпляр класса под названием `SPI`. +Интерфейс SPI0 доступен на выводах D3, D5, D6. Используемый экземпляр класса - `SPI1`. \ No newline at end of file diff --git a/docs/Start_mik32_description.md b/docs/Start_mik32_description.md index e3f909d..869194a 100644 --- a/docs/Start_mik32_description.md +++ b/docs/Start_mik32_description.md @@ -56,4 +56,9 @@ Интерфейс UART0 доступен на выводах P0_5, P0_6, для работы с ним используется экземпляр класса под названием `Serial`. Интерфейс UART1 доступен на выводах P1_8, P1_9, используемый экземпляр класса - `Serial1`. USB-UART преобразователь, установленный на плате, поддерживает стандартные скорости UART до 57600 бод. Нестандартные скорости должны быть кратны -12*32=384, например, 240000 бод, 768000 бод. \ No newline at end of file +12*32=384, например, 240000 бод, 768000 бод. + +### SPI +Интерфейс SPI1 доступен на выводах P1_0, P1_1, P1_2. Для работы с ним используется экземпляр класса под названием `SPI`. +Интерфейс SPI0 доступен на выводах P0_0, P0_1, P0_2. Используемый экземпляр класса - `SPI1`. +Для корректной работы аппаратного SPI микроконтроллер так же использует выводы P1_3 при работе SPI1 и P0_3 при работе SPI0. В связи с этим данные выводы недоступны для использования при работе соответствующего SPI. \ No newline at end of file diff --git a/docs/elsomikOEM_pinout.png b/docs/elsomikOEM_pinout.png new file mode 100644 index 0000000..d8c18e3 Binary files /dev/null and b/docs/elsomikOEM_pinout.png differ diff --git a/docs/elsomikSE_pinout.png b/docs/elsomikSE_pinout.png new file mode 100644 index 0000000..8494850 Binary files /dev/null and b/docs/elsomikSE_pinout.png differ diff --git a/docs/elsomik_description.md b/docs/elsomik_description.md new file mode 100644 index 0000000..39ff3a5 --- /dev/null +++ b/docs/elsomik_description.md @@ -0,0 +1,90 @@ +# Elsomik +Особенности работы с платой Elsomik в среде программирования ArduinoIDE. +### Функциональное назначение выводов для плат Elsomik OEM и Elsomik SE +![elsomikOEM_pinout.png](elsomikOEM_pinout.png) +![elsomikSE_pinout.png](elsomikSE_pinout.png) +|Номер вывода|Доступные функции|Номер вывода|Доступные функции| +|---------|---------|---------|---------| +|P0_0|PWM, MISO0|P1_0|PWM, MISO1| +|P0_1|PWM, MOSI0|P1_1|PWM, MOSI1| +|P0_2|PWM, SCLK0, ADC2|P1_2|PWM, SCLK1| +|P0_3|PWM, NSS0|P1_3|PWM, NSS1| +|P0_4|ADC3|P1_4|INT1| +|P0_5|RX0|P1_5|ADC0, INT2| +|P0_6|TX0|P1_6|INT3| +|P0_7|ADC4|P1_7|ADC1| +|P0_8|INT0|P1_8|RX1| +|P0_9|SDA0, ADC5|P1_9|TX1, INT4| +|P0_10|SCL0|P1_10|INT5| +|P0_11|TDI, ADC6|P1_11|REF| +|P0_12|TCK|P1_12|SDA1| +|P0_13|TMS, ADC7|P1_13|SCL1| +|P0_14|TRST|P1_14|-| +|P0_15|TDO|P1_15|INT6| +|P2_6|-|P2_7|INT7| + +### Загрузка скетчей +На плате отсутствуют встроенные преобразователи, позволяющие загружать скетчи по USB через COM-порт, однако каждая плата поставляется с предварительно записанным начальным загрузчиком. Для записи скетчей через USB потребуется использование внешнего USB-UART преобразователя, подключаемого к выводам платы P0_5 (RX0) и P0_6 (TX0), которые соответствуют интерфейсу UART0. +Перед загрузкой скетча необходимо кратковременно ввести контроллер в состояние RESET. Если используется USB-UART преобразователь с выведенным сигналом DTR, необходимо соединить DTR с выводом RST на плате через керамический конденсатор емкостью от 0,47 мкФ до 2,2 мкФ. В случае отсутствия сигнала DTR, необходимо вручную соединить вывод RST платы с землей и отпустить его непосредственно перед началом записи скетча. +### Цифровые выводы +Выводы на плате Elsomik пронумерованы в соответствии с их принадлежностью к определенному GPIO-порту и конкретному пину внутри порта. Чтобы использовать цифровой вывод, необходимо передать в функцию номер порта и номер пина в формате `P0_1`, где "0" — это номер порта, а "1" — номер пина внутри порта. Например, для инициализации вывода 5 порта 1 на выход необходимо вызвать функцию `pinMode(P1_5, OUTPUT)`. +Для использования доступны следующие выводы: `P0_0 ... P0_15, P1_0 ... P1_15, P2_6, P2_7`. Выводы `P0_11 ... P0_15` на плате обозначены иначе, ниже представлена таблица соответствия: +|Обозначение на плате|Номер вывода| +|---------|---------| +|TDI|P0_11| +|TCK|P0_12| +|TMS|P0_13| +|TRST|P0_14| +|TDO|P0_15| + +### АЦП +На плате доступно 8 выводов, которые можно использовать в качестве каналов АЦП. Для работы с ними в функцию `analogRead()` необходимо передать номер канала или номер соответствующего цифрового вывода. Доступные каналы и их соответствие номерам выводов платы: + +|Цифровой вывод|Номер канала АЦП| +|---------|---------| +|P1_5|A0| +|P1_7|A1| +|P0_2|A2| +|P0_4|A3| +|P0_7|A4| +|P0_9|A5| +|P0_11|A6| +|P0_13|A7| +#### ШИМ +На плате Elsomik в ArduinoIDE доступно 8 выводов для формирования ШИМ-сигнала. Генерация сигнала осуществляется с помощью 32-битного таймера. Выводы, подключенные к одному и тому же таймеру, выдают ШИМ-сигнал одинаковой частоты. +Доступные выводы: + +|Цифровой вывод|Используемый таймер| +|---------|---------| +|P0_0|таймер 1| +|P0_1|таймер 1| +|P0_2|таймер 1| +|P0_3|таймер 1| +|P1_0|таймер 2| +|P1_1|таймер 2| +|P1_2|таймер 2| +|P1_3|таймер 2| + +При использовании SPI формирование ШИМ сигнала на выводах P1_0 ... P1_3 недоступно. +### Прерывания +На плате Elsomik доступно 8 прерываний, настраиваемых функцией `void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)`: + +|Цифровой вывод|Номер прерывания| +|---------|---------| +|P0_8|0| +|P1_4|1| +|P1_5|2| +|P1_6|3| +|P1_9|4| +|P1_10|5| +|P1_15|6| +|P2_7|7| + +### Serial +Интерфейс UART0 доступен на выводах P0_5, P0_6, для работы с ним используется экземпляр класса под названием `Serial`. +Интерфейс UART1 доступен на выводах P1_8, P1_9, используемый экземпляр класса - `Serial1`. + +### SPI +Интерфейс SPI1 доступен на выводах P1_0, P1_1, P1_2. Для работы с ним используется экземпляр класса под названием `SPI`. +Интерфейс SPI0 доступен на выводах P0_0, P0_1, P0_2. Используемый экземпляр класса - `SPI1`. +Для корректной работы аппаратного SPI микроконтроллер так же использует выводы P1_3 при работе SPI1 и P0_3 при работе SPI0. В связи с этим данные выводы недоступны для использования при работе соответствующего SPI. \ No newline at end of file diff --git a/docs/nano_description.md b/docs/nano_description.md new file mode 100644 index 0000000..ee30e8a --- /dev/null +++ b/docs/nano_description.md @@ -0,0 +1,48 @@ +# Elbear Nano +Особенности работы с платами Elbear Nano в среде программирования ArduinoIDE. +### Функциональное назначение выводов +![Pinout_nano](Pinout_nano.PNG) +### Цифровые выводы +На плате Elbear Nano доступен встроенный светодиод. Для его использования необходимо воспользоваться макросом `LED_BUILTIN`, передавая его в качестве аргумента функции вместо номера цифрового вывода. Макросу соответствует номер вывода D22. +### Аналоговые выводы +Выводы A0...A7 на плате могут использоваться как в аналоговом, так и в цифровом режиме. +Для использования вывода в качестве аналогового необходимо перевести соответствующий DIP-переключатель, расположенный рядом с аналоговыми выводами, в положение OFF. В этом режиме внешнее напряжение, подаваемое на вывод, будет понижаться резистивным делителем перед подачей на микроконтроллер. +Для использования вывода в качестве цифрового нужно перевести переключатель в положение ON. В этом случае напряжение с вывода платы передается на микроконтроллер без изменений. +Выводы А4...А7 используют один и тот же канал АЦП, поэтому не могут использоваться одновременно. +Таблица соответствия выводов платы и номера DIP-переключателя представлена ниже. Переключатель 5 относится сразу к четырем аналоговым выводам - А4...А7. +|Вывод|Номер переключателя| +|---------|---------| +|А0|1| +|А1|2| +|А2|3| +|А3|4| +|А4|5| +|А5|5| +|А6|5| +|А7|5| +#### ШИМ +На плате Elbear Nano доступно 8 выводов для формирования ШИМ-сигнала: D3, D5, D6, D9...D13. Генерация сигнала осуществляется с помощью 32-битного таймера. Выводы D3, D5, D6, D9 подключены к таймеру 1, выводы D10...D13 подключены к таймеру 2. Выводы, подключенные к одному и тому же таймеру, выдают ШИМ-сигнал одинаковой частоты. +Цифровой вывод D10 не может быть использован для генерации ШИМ, если одновременно активен интерфейс SPI. Это ограничение связано с особенностями работы микроконтроллера. Ограничение не распространяется на использование D10 в качестве цифрового вывода при активном SPI. +### Прерывания +На плате Elbear Nano доступно 8 прерываний, настраиваемых функцией `void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)`: + +|Цифровой вывод|Номер прерывания| +|---------|---------| +|D2|0| +|D3|1| +|D4|2| +|D5|3| +|D6|4| +|D8|5| +|D9|6| +|A1|7| + +При использовании аналогового вывода A1 для работы с прерываниями необходимо предварительно перевести вывод в режим цифрового. Для этого нужно перевести DIP-переключатель номер 2 в положение ON. + +### Serial +Интерфейс UART0 доступен на выводах D0, D1, для работы с ним используется экземпляр класса под названием `Serial`. +Интерфейс UART1 доступен на выводах D7, D8, используемый экземпляр класса - `Serial1`. + +### SPI +Интерфейс SPI1 доступен на выводах D11, D12, D13. Для работы с ним используется экземпляр класса под названием `SPI`. +Интерфейс SPI0 доступен на выводах D3, D5, D6. Используемый экземпляр класса - `SPI1`. \ No newline at end of file diff --git a/libraries/IRremote/src/private/IRTimer.hpp b/libraries/IRremote/src/private/IRTimer.hpp index c34dd52..ad1db69 100644 --- a/libraries/IRremote/src/private/IRTimer.hpp +++ b/libraries/IRremote/src/private/IRTimer.hpp @@ -2076,11 +2076,14 @@ extern "C" void __attribute__((noinline, section(".ram_text"), optimize("O3"))) # if defined(SEND_PWM_BY_TIMER) #include "pins_arduino.h" -# if defined(ARDUINO_START_MIK32_V1) +# if (defined(ARDUINO_START_MIK32_V1) || defined(ARDUINO_ELSOMIK)) #define IR_SEND_PIN P0_0 -# else +# elif (defined(ARDUINO_ACE_UNO_8MB) || defined(ARDUINO_ACE_UNO_16MB) || \ + defined(ARDUINO_ACE_UNO_32MB) || defined(ARDUINO_ELBEAR_NANO)) #define IR_SEND_PIN 3 -# endif // START_MIK32_V1 +# else +#error "Unknown MIK32V2 board!" +# endif static TIMER32_HandleTypeDef ir_sender_htimer; static TIMER32_CHANNEL_HandleTypeDef ir_sender_htimer_channel; diff --git a/libraries/SPI/examples/ADC_read_write_registers/ADC_read_write_registers.ino b/libraries/SPI/examples/ADC_read_write_registers/ADC_read_write_registers.ino index 00c931f..5d7f87d 100644 --- a/libraries/SPI/examples/ADC_read_write_registers/ADC_read_write_registers.ino +++ b/libraries/SPI/examples/ADC_read_write_registers/ADC_read_write_registers.ino @@ -5,7 +5,7 @@ #include "SPI.h" -#define CS_PIN 9 +#define CS_PIN 9 // P1_8 // address of register to read and write const int reg_to_test = 0x03; @@ -42,7 +42,7 @@ void ADC_write_register(uint8_t registerAddress, uint8_t registerValueToWrite) // ----------------------------------------- // void setup() { - Serial.begin(115200); + Serial.begin(9600); Serial.println("Start spi test"); // init chip select pin diff --git a/libraries/SPI/src/SPI.cpp b/libraries/SPI/src/SPI.cpp index 1670372..1050ef6 100644 --- a/libraries/SPI/src/SPI.cpp +++ b/libraries/SPI/src/SPI.cpp @@ -1,22 +1,16 @@ #include "SPI.h" -#include "mik32_hal_spi.h" -SPI_HandleTypeDef hspi; +SPIClass SPI(1); +#if SPI_COMMON_QTY > 1 +SPIClass SPI1(0); +#endif -bool newConfig = false; -bool isInited = false; -uint32_t currentSpeed = 0; -int8_t currentDataOrder = MSBFIRST; -int8_t currentDataMode = -1; static uint8_t reverse_bits(uint8_t byte); -// ------------------------------------------------------------------ // - -void SPISettings::spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode) +void SPIClass::updateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode) { // update config only if something has changed - if ((currentSpeed != speedMaximum) || (currentDataOrder != dataOrder) || - (currentDataMode != dataMode)) + if ((_speed != speedMaximum) || (_dataOrder != dataOrder) || (_dataMode != dataMode)) { // Find the fastest clock that is less than or equal to the // given clock rate. If nothing is slow enough - use the slowest. @@ -33,63 +27,64 @@ void SPISettings::spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, ui // if break didn't call in cycle, it will be the greatest divRegVal (and divider) // update params in struct - hspi.Init.CLKPhase = dataMode & 0b00000001; - hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1; - hspi.Init.BaudRateDiv = divRegVal; + _hspi.Init.CLKPhase = dataMode & 0b00000001; + _hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1; + _hspi.Init.BaudRateDiv = divRegVal; - currentSpeed = speedMaximum; - currentDataOrder = dataOrder; - currentDataMode = dataMode; - newConfig = true; + _speed = speedMaximum; + _dataOrder = dataOrder; + _dataMode = dataMode; + _newConfig = true; } } -// ------------------------------------------------------------------ // - -SPIClass SPI; -bool SPIClass::spiInUse = false; -uint8_t SPIClass::interruptMode = 0; -uint8_t SPIClass::interruptMask = 0; - void SPIClass::begin() { - spi_onBegin(); + spi_onBegin(_spiNum); // set constant parameters in spi struct - hspi.Instance = SPI_1; - hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode used - hspi.Init.ThresholdTX = 4; - hspi.Init.Decoder = SPI_DECODER_NONE; - hspi.Init.ManualCS = SPI_MANUALCS_ON; - hspi.Init.ChipSelect = SPI_CS_NONE; + if (_spiNum == 0) + _hspi.Instance = SPI_0; + else + _hspi.Instance = SPI_1; + _hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode used + _hspi.Init.ThresholdTX = 4; + _hspi.Init.Decoder = SPI_DECODER_NONE; + _hspi.Init.ManualCS = SPI_MANUALCS_ON; + _hspi.Init.ChipSelect = SPI_CS_NONE; // adjustable parameters default values as in SPISettings() - hspi.Init.BaudRateDiv = SPI_CLOCK_DIV8; - hspi.Init.CLKPhase = SPI_MODE0 & 0b00000001; - hspi.Init.CLKPolarity = (SPI_MODE0 & 0b00000010)>>1; + _hspi.Init.BaudRateDiv = SPI_CLOCK_DIV8; + _hspi.Init.CLKPhase = SPI_MODE0 & 0b00000001; + _hspi.Init.CLKPolarity = (SPI_MODE0 & 0b00000010)>>1; - spiInUse = true; + _spiInUse = true; } void SPIClass::end() { - if (spiInUse && isInited) + if (_spiInUse && _isInited) { // turn off spi - HAL_SPI_Disable(&hspi); + HAL_SPI_Disable(&_hspi); // deinit spi gpio pins - if (hspi.Instance == SPI_1) // only spi1 is using in currunt version + if (_hspi.Instance == SPI_0) + { + HAL_GPIO_PinConfig(GPIO_0, (HAL_PinsTypeDef)(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2), + HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + } + else if (_hspi.Instance == SPI_1) { HAL_GPIO_PinConfig(GPIO_1, (HAL_PinsTypeDef)(GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2), HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); } - spi_onEnd(); + spi_onEnd(_spiNum); - spiInUse = false; - isInited = false; - interruptMode = 0; - interruptMask = 0; + _spiInUse = false; + _isInited = false; + _interruptMode = 0; + _interruptMask = 0; } } @@ -98,9 +93,9 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber) if(interruptNumber < EXTERNAL_INTERRUPTS_QTY) { noInterrupts(); // prevent transactionBegin - interruptMask |= (1 << interruptNumber); // add new interrupt to mask - if (!interruptMode) - interruptMode = 1; + _interruptMask |= (1 << interruptNumber); // add new interrupt to mask + if (!_interruptMode) + _interruptMode = 1; interrupts(); } } @@ -110,34 +105,40 @@ void SPIClass::notUsingInterrupt(uint8_t interruptNumber) if(interruptNumber < EXTERNAL_INTERRUPTS_QTY) { noInterrupts(); // prevent transactionBegin - interruptMask &= ~(1< 0)) + if (_spiInUse && (_interruptMode > 0)) { for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) { - if (interruptMask & (1 << i)) + if (_interruptMask & (1 << i)) // disable every interrupt by it's number disableInterrupt(i); } } - // initialize spi bus or update config - if(spiInUse && ((!isInited) || newConfig)) + // initialize spi bus or update config if needed + if(_spiInUse && ((!_isInited) || _newConfig)) { // initialize spi with given settings - if (HAL_SPI_Init(&hspi) != HAL_OK) + if (HAL_SPI_Init(&_hspi) != HAL_OK) ErrorMsgHandler("SPI.beginTransaction(): initialization error"); else - isInited = true; + { + _isInited = true; + _newConfig = false; + } } } @@ -145,19 +146,19 @@ uint8_t SPIClass::transfer(uint8_t data) { uint8_t rxByte = 0; - if (isInited) + if (_isInited) { // reverse bits if LSB mode needed - if (currentDataOrder == LSBFIRST) + if (_dataOrder == LSBFIRST) data = reverse_bits(data); // send and recieve data - HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, &data, &rxByte, 1, SPI_TIMEOUT_DEFAULT*2); + HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&_hspi, &data, &rxByte, 1, SPI_TIMEOUT_DEFAULT*2); if (SPI_Status != HAL_OK) - HAL_SPI_ClearError(&hspi); + HAL_SPI_ClearError(&_hspi); // reverse bits again if LSB mode needed - if (currentDataOrder == LSBFIRST) + if (_dataOrder == LSBFIRST) rxByte = reverse_bits(rxByte); } return rxByte; @@ -167,10 +168,10 @@ uint16_t SPIClass::transfer16(uint16_t data) { uint8_t buf[2]; uint16_t rxVal = 0; - if (isInited) + if (_isInited) { // prepare data for send - if (currentDataOrder == LSBFIRST) + if (_dataOrder == LSBFIRST) { // least significant byte is forward and reverse bits inside each byte buf[0] = reverse_bits(data&0xFF); @@ -184,12 +185,12 @@ uint16_t SPIClass::transfer16(uint16_t data) } // send and recieve data - HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, buf, buf, 2, SPI_TIMEOUT_DEFAULT*2); + HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&_hspi, buf, buf, 2, SPI_TIMEOUT_DEFAULT*2); if (SPI_Status != HAL_OK) - HAL_SPI_ClearError(&hspi); + HAL_SPI_ClearError(&_hspi); // process the received data - if (currentDataOrder == LSBFIRST) + if (_dataOrder == LSBFIRST) // reverse bits for LSB mode rxVal = ( ((uint16_t)reverse_bits(buf[1]) ) << 8) | reverse_bits(buf[0]); else @@ -203,24 +204,24 @@ void SPIClass::transfer(void *buf, size_t count) if (count == 0) return; - if (isInited) + if (_isInited) { uint8_t *p = (uint8_t *)buf; // reverse bits in buffer if LSB mode needed - if (currentDataOrder == LSBFIRST) + if (_dataOrder == LSBFIRST) { for (uint32_t i = 0; i < count; i++) *(p+i) = reverse_bits(*(p+i)); } // send and recieve data using the same buffer - HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&hspi, (uint8_t*)buf, (uint8_t*)buf, count, SPI_TIMEOUT_DEFAULT*2); + HAL_StatusTypeDef SPI_Status = HAL_SPI_Exchange(&_hspi, (uint8_t*)buf, (uint8_t*)buf, count, SPI_TIMEOUT_DEFAULT*2); if (SPI_Status != HAL_OK) - HAL_SPI_ClearError(&hspi); + HAL_SPI_ClearError(&_hspi); // reverse bits if LSB mode needed - if (currentDataOrder == LSBFIRST) + if (_dataOrder == LSBFIRST) { p = (uint8_t *)buf; // return to buf beginning for (uint32_t i = 0; i < count; i++) @@ -232,11 +233,11 @@ void SPIClass::transfer(void *buf, size_t count) void SPIClass::endTransaction(void) { // enable interrupts in use - if (spiInUse && (interruptMode > 0)) + if (_spiInUse && (_interruptMode > 0)) { for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) { - if (interruptMask & (1 << i)) + if (_interruptMask & (1 << i)) // enable every interrupt in use by it's number enableInterrupt(i); } @@ -246,20 +247,20 @@ void SPIClass::endTransaction(void) // ------------------------------------ // void SPIClass::setBitOrder(uint8_t bitOrder) { - if (spiInUse) - currentDataOrder = bitOrder; + if (_spiInUse) + _dataOrder = bitOrder; else ErrorMsgHandler("SPI.setBitOrder():SPI.begin() need to be called first"); } void SPIClass::setDataMode(uint8_t dataMode) { - if (spiInUse) + if (_spiInUse) { - hspi.Init.CLKPhase = (dataMode&0b00000001); - hspi.Init.CLKPolarity = (dataMode&0b00000010)>>1; - HAL_SPI_Set_Clock_Mode(&hspi); - currentDataMode = dataMode; + _hspi.Init.CLKPhase = (dataMode&0b00000001); + _hspi.Init.CLKPolarity = (dataMode&0b00000010)>>1; + HAL_SPI_Set_Clock_Mode(&_hspi); + _dataMode = dataMode; } else ErrorMsgHandler("SPI.setDataMode():SPI.begin() need to be called first"); @@ -267,7 +268,7 @@ void SPIClass::setDataMode(uint8_t dataMode) void SPIClass::setClockDivider(uint8_t clockDiv) { - if (spiInUse) + if (_spiInUse) { // if divider is valid if ((clockDiv == SPI_CLOCK_DIV2) || (clockDiv == SPI_CLOCK_DIV4) || @@ -275,9 +276,9 @@ void SPIClass::setClockDivider(uint8_t clockDiv) (clockDiv == SPI_CLOCK_DIV32) || (clockDiv == SPI_CLOCK_DIV64) || (clockDiv == SPI_CLOCK_DIV128) || (clockDiv == SPI_CLOCK_DIV256)) { - hspi.Init.BaudRateDiv = clockDiv; - currentSpeed = F_CPU >> (clockDiv+1); - HAL_SPI_Set_Clock_Divider(&hspi); + _hspi.Init.BaudRateDiv = clockDiv; + _speed = F_CPU >> (clockDiv+1); + HAL_SPI_Set_Clock_Divider(&_hspi); } else ErrorMsgHandler("SPI.setClockDivider(): Invalid clock devider"); diff --git a/libraries/SPI/src/SPI.h b/libraries/SPI/src/SPI.h index b54e6b2..cee0433 100644 --- a/libraries/SPI/src/SPI.h +++ b/libraries/SPI/src/SPI.h @@ -15,6 +15,7 @@ #define _SPI_H_INCLUDED #include +#include "mik32_hal_spi.h" // SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), // usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) @@ -32,7 +33,6 @@ #define SPI_DEFAULT_SPEED 4000000 - // dividers for setClockDivider() #define SPI_CLOCK_DIV2 0x00 // 16 MHz #define SPI_CLOCK_DIV4 0x01 // 8 MHz @@ -49,45 +49,49 @@ #define SPI_MODE2 0b10 #define SPI_MODE3 0b11 - -class SPISettings -{ +class SPISettings { public: - SPISettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode) - { - spiUpdateSettings(speedMaximum, dataOrder, dataMode); - } - - SPISettings() - { - spiUpdateSettings(SPI_DEFAULT_SPEED, MSBFIRST, SPI_MODE0); - } - -private: - void spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode); - - friend class SPIClass; + uint32_t speedMaximum; + uint8_t newDataOrder; + uint8_t newDataMode; + // save values from arguments + SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t mode) + : speedMaximum(clock), newDataOrder(bitOrder), newDataMode(mode) {} }; class SPIClass { private: - static bool spiInUse; - static uint8_t interruptMode; // 0=none, 1=mask - static uint8_t interruptMask; // which interrupts to mask + uint8_t _spiNum; + SPI_HandleTypeDef _hspi = {0}; + uint32_t _speed = 0; + uint8_t _dataOrder = MSBFIRST; + uint8_t _dataMode = -1; + bool _isInited = false; + bool _newConfig = false; + bool _spiInUse = false; + uint8_t _interruptMode = 0; // 0=none, 1=mask + uint8_t _interruptMask = 0; // which interrupts to mask + + void updateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode); public: + inline SPIClass(uint8_t num) + { + // Set the SPI to be used + _spiNum = (num < SPI_COMMON_QTY) ? num : 1; // SPI1 by default + } // Initialize the SPI library - static void begin(); + void begin(); // If SPI is used from within an interrupt, this function registers // that interrupt with the SPI library, so beginTransaction() can // prevent conflicts. The input interruptNumber is the number used // with attachInterrupt. - static void usingInterrupt(uint8_t interruptNumber); + void usingInterrupt(uint8_t interruptNumber); // And this does the opposite. - static void notUsingInterrupt(uint8_t interruptNumber); + void notUsingInterrupt(uint8_t interruptNumber); // Note: the usingInterrupt and notUsingInterrupt functions should // not to be called from ISR context or inside a transaction. // For details see: @@ -109,7 +113,7 @@ public: void endTransaction(void); // Disable the SPI bus - static void end(); + void end(); // This function is deprecated. New applications should use // beginTransaction() to configure SPI settings. @@ -124,5 +128,8 @@ public: }; extern SPIClass SPI; +#if SPI_COMMON_QTY > 1 +extern SPIClass SPI1; +#endif #endif diff --git a/libraries/SoftwareSerial/src/SoftwareSerial.cpp b/libraries/SoftwareSerial/src/SoftwareSerial.cpp index 0f312a2..bf7dacf 100644 --- a/libraries/SoftwareSerial/src/SoftwareSerial.cpp +++ b/libraries/SoftwareSerial/src/SoftwareSerial.cpp @@ -205,6 +205,8 @@ void SoftwareSerial::setRX(uint8_t rx) PIN_SET_PAD_CONFIG(PORT_0_PUPD, pinNumber, HAL_GPIO_PULL_UP); else if (((GPIO_TypeDef*)_receivePortRegister) == GPIO_1) PIN_SET_PAD_CONFIG(PORT_1_PUPD, pinNumber, HAL_GPIO_PULL_UP); + else if (((GPIO_TypeDef*)_receivePortRegister) == GPIO_2) + PIN_SET_PAD_CONFIG(PORT_2_PUPD, pinNumber, HAL_GPIO_PULL_UP); } // turn off int line for while (it turning on in attachInterrupt()) GPIO_IRQ_LINE_DISABLE(_int_maskLine); diff --git a/libraries/Wire/src/Wire.cpp b/libraries/Wire/src/Wire.cpp index c82dbe4..10ee740 100644 --- a/libraries/Wire/src/Wire.cpp +++ b/libraries/Wire/src/Wire.cpp @@ -4,31 +4,9 @@ extern "C" #include #include #include -#include "utility/twi.h" } #include "Wire.h" -// Initialize Class Variables -uint8_t TwoWire::rxBuffer[BUFFER_LENGTH]; -uint8_t TwoWire::rxBufferIndex = 0; -uint8_t TwoWire::rxBufferLength = 0; - -uint8_t TwoWire::txAddress = 0; // 7 bits without shift -uint8_t TwoWire::txBuffer[BUFFER_LENGTH]; -uint8_t TwoWire::txBufferIndex = 0; -uint8_t TwoWire::txBufferLength = 0; - -uint8_t TwoWire::transmitting = 0; -uint8_t TwoWire::slaveAddress = 0; // 7 bits without shift in slave mode - -void (*TwoWire::user_onRequest)(void); -void (*TwoWire::user_onReceive)(int); - -// Constructors -TwoWire::TwoWire() -{ -} - // --------------------------- Public Methods --------------------------- // void TwoWire::begin(void) { @@ -36,10 +14,7 @@ void TwoWire::begin(void) rxBufferLength = 0; txBufferIndex = 0; txBufferLength = 0; - twi_init(slaveAddress); - - twi_attachSlaveTxEvent(onRequestService); // default callback must exist - twi_attachSlaveRxEvent(onReceiveService); // default callback must exist + twi_init(&wireHandler, slaveAddress); } void TwoWire::begin(uint8_t address) @@ -56,13 +31,13 @@ void TwoWire::begin(int address) void TwoWire::end(void) { flush(); // wait for transmission complete - twi_deinit(); + twi_deinit(&wireHandler); slaveAddress = 0; } void TwoWire::setClock(uint32_t clock) { - if (twi_setFrequency(clock, false) != I2C_OK) + if (twi_setFrequency(&wireHandler, clock, false) != I2C_OK) ErrorMsgHandler("Wire.setClock(): invalid frequency or Wire was not begin"); } @@ -88,7 +63,7 @@ uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity, uint32_t iaddres quantity = BUFFER_LENGTH; // perform blocking read into buffer - uint8_t read = twi_masterReadFrom(address, rxBuffer, quantity, sendStop); + uint8_t read = twi_masterReadFrom(&(wireHandler.i2c_param), address, rxBuffer, quantity, sendStop); // set rx buffer iterator vars rxBufferIndex = 0; @@ -147,7 +122,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop) if (transmitting) { // transmit buffer (blocking) - ret = twi_masterWriteTo(txAddress, txBuffer, txBufferLength, sendStop); + ret = twi_masterWriteTo(&(wireHandler.i2c_param), txAddress, txBuffer, txBufferLength, sendStop); // reset tx buffer iterator vars txBufferIndex = 0; txBufferLength = 0; @@ -189,7 +164,7 @@ size_t TwoWire::write(uint8_t data) else { // in slave send mode - reply to master - if (twi_slaveWrite(&data, 1) != I2C_OK) + if (twi_slaveWrite(&(wireHandler.i2c_param), &data, 1) != I2C_OK) ret = 0; } return ret; @@ -215,7 +190,7 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity) else { // in slave send mode - reply to master - if (twi_slaveWrite((uint8_t *)data, quantity) != I2C_OK) + if (twi_slaveWrite(&(wireHandler.i2c_param), (uint8_t *)data, quantity) != I2C_OK) ret = 0; } return ret; @@ -309,10 +284,18 @@ void TwoWire::onRequest( void (*function)(void) ) } // С function for trap handler -extern "C" void __attribute__((optimize("O3"))) wire_interrupt_handler(void) +extern "C" void __attribute__((optimize("O3"))) wire_interrupt_handler(uint8_t num) { - twi_interruptHandler(); + if (num == 1) + twi_interruptHandler(Wire.getHandler()); +#if I2C_COMMON_QTY>1 + else if (num == 0) + twi_interruptHandler(Wire1.getHandler()); +#endif } // ----------------------------- Preinstantiate Objects ----------------------------- // -TwoWire Wire = TwoWire( ); +TwoWire Wire = TwoWire(1); +#if I2C_COMMON_QTY>1 +TwoWire Wire1 = TwoWire(0); +#endif diff --git a/libraries/Wire/src/Wire.h b/libraries/Wire/src/Wire.h index ba99bbf..ca62b8e 100644 --- a/libraries/Wire/src/Wire.h +++ b/libraries/Wire/src/Wire.h @@ -4,6 +4,10 @@ #include "Stream.h" #include "Arduino.h" +extern "C" +{ +#include "utility/twi.h" +} #define BUFFER_LENGTH 32 @@ -13,23 +17,45 @@ class TwoWire : public Stream { private: - static uint8_t rxBuffer[]; - static uint8_t rxBufferIndex; - static uint8_t rxBufferLength; + WireHandler_TypeDef wireHandler; - static uint8_t txAddress; - static uint8_t txBuffer[]; - static uint8_t txBufferIndex; - static uint8_t txBufferLength; + uint8_t rxBuffer[BUFFER_LENGTH]; + uint8_t rxBufferIndex = 0; + uint8_t rxBufferLength = 0; - static uint8_t transmitting; - static uint8_t slaveAddress; - static void (*user_onRequest)(void); - static void (*user_onReceive)(int numBytes); - static void onRequestService(void); - static void onReceiveService(uint8_t* inBytes, int numBytes); + uint8_t txAddress = 0; // 7 bits without shift + uint8_t txBuffer[BUFFER_LENGTH]; + uint8_t txBufferIndex = 0; + uint8_t txBufferLength = 0; + + uint8_t transmitting = 0; + uint8_t slaveAddress = 0; + void (*user_onRequest)(void); + void (*user_onReceive)(int numBytes); + void onRequestService(void); + void onReceiveService(uint8_t* inBytes, int numBytes); + static inline void staticOnRequestService(void* instance) + { + // cast pointer to TwoWire type and call method + static_cast(instance)->onRequestService(); + } + static inline void staticOnReceiveService(void* instance, uint8_t* inBytes, int numBytes) + { + static_cast(instance)->onReceiveService(inBytes, numBytes); + } public: - TwoWire(); + inline TwoWire(uint8_t num) + { + wireHandler.i2c_num = (num < I2C_COMMON_QTY) ? num : 1; // I2C1 by default + wireHandler.instance = this; + // save pointers to static functions to wire handler + wireHandler.onSlaveTransmit = &TwoWire::staticOnRequestService; + wireHandler.onSlaveReceive = &TwoWire::staticOnReceiveService; + } + WireHandler_TypeDef* getHandler() + { + return &wireHandler; + } void begin(); void begin(uint8_t); void begin(int); @@ -65,5 +91,8 @@ class TwoWire : public Stream }; extern TwoWire Wire; +#if I2C_COMMON_QTY>1 +extern TwoWire Wire1; +#endif #endif diff --git a/libraries/Wire/src/utility/twi.c b/libraries/Wire/src/utility/twi.c index 1978655..ed8fb69 100644 --- a/libraries/Wire/src/utility/twi.c +++ b/libraries/Wire/src/utility/twi.c @@ -2,162 +2,149 @@ #include #include "Arduino.h" #include "twi.h" -#include "mik32_hal_i2c.h" #include "mik32_hal_irq.h" #define TIMEOUT_TICKS 1000000 #define TWI_FREQ_DEF WIRE_FREQ_100K // default is 100 kHz -static void (*twi_onSlaveTransmit)(void); -static void (*twi_onSlaveReceive)(uint8_t*, int); - -static uint8_t twi_rxBuffer[TWI_BUFFER_LENGTH]; -static volatile uint8_t twi_rxBufferIndex; - -I2C_HandleTypeDef hi2c; -static uint32_t CurrentFrequency = TWI_FREQ_DEF; -static bool twiIsOn = false; - // ---------------------------------------------------------------- // /* * Function twi_init * Desc readys twi pins and sets twi bitrate - * Input slaveAddress - address of Arduino if working in slave mode + * Input handler - pointer to wire common handler, + * slaveAddress - address of Arduino if working in slave mode * Output none */ -uint8_t twi_init(uint8_t slaveAddress) +uint8_t twi_init(WireHandler_TypeDef* handler, uint8_t slaveAddress) { // Common settings uint32_t EPICmask; -#if I2C_NUM == 0 - hi2c.Instance = I2C_0; - EPICmask = HAL_EPIC_I2C_0_MASK; -#elif I2C_NUM == 1 - hi2c.Instance = I2C_1; - EPICmask = HAL_EPIC_I2C_1_MASK; -#else - #error "Unsupported I2C_NUM value in pins_arduino.h" -#endif + if (handler->i2c_num == 0) + { + handler->i2c_param.Instance = I2C_0; + EPICmask = HAL_EPIC_I2C_0_MASK; + } + else if (handler->i2c_num == 1) + { + handler->i2c_param.Instance = I2C_1; + EPICmask = HAL_EPIC_I2C_1_MASK; + } + else + return I2C_ERROR; - hi2c.Init.DigitalFilter = I2C_DIGITALFILTER_2CLOCKCYCLES; - hi2c.Init.AnalogFilter = I2C_ANALOGFILTER_DISABLE; + handler->i2c_param.Init.DigitalFilter = I2C_DIGITALFILTER_2CLOCKCYCLES; + handler->i2c_param.Init.AnalogFilter = I2C_ANALOGFILTER_DISABLE; if (slaveAddress == 0) // if there is no address - master mode { - hi2c.Init.Mode = HAL_I2C_MODE_MASTER; - hi2c.Init.AutoEnd = I2C_AUTOEND_ENABLE; + handler->i2c_param.Init.Mode = HAL_I2C_MODE_MASTER; + handler->i2c_param.Init.AutoEnd = I2C_AUTOEND_ENABLE; } else { // 7-bit address without any additional bits - hi2c.Init.Mode = HAL_I2C_MODE_SLAVE; - hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // stretch is used - hi2c.Init.OwnAddress1 = slaveAddress; + handler->i2c_param.Init.Mode = HAL_I2C_MODE_SLAVE; + handler->i2c_param.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // stretch is used + handler->i2c_param.Init.OwnAddress1 = slaveAddress; } // set the frequency - if (hi2c.Init.Mode == HAL_I2C_MODE_MASTER) - twi_setFrequency(CurrentFrequency, true); + if (handler->i2c_param.Init.Mode == HAL_I2C_MODE_MASTER) + twi_setFrequency(handler, TWI_FREQ_DEF, true); else - twi_setFrequency(0, true); + twi_setFrequency(handler, 0, true); - if (HAL_I2C_Init(&hi2c) != HAL_OK) + if (HAL_I2C_Init(&(handler->i2c_param)) != HAL_OK) return I2C_ERROR; // enable interrupts for slave mode - if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE) + if (handler->i2c_param.Init.Mode == HAL_I2C_MODE_SLAVE) { // enable interrupts for addressing, byte reception and transfer completion - HAL_I2C_InterruptDisable(&hi2c, I2C_INTMASK); - HAL_I2C_InterruptEnable(&hi2c, I2C_CR1_ADDRIE_M | I2C_CR1_RXIE_M | I2C_CR1_STOPIE_M); + HAL_I2C_InterruptDisable(&(handler->i2c_param), I2C_INTMASK); + HAL_I2C_InterruptEnable(&(handler->i2c_param), I2C_CR1_ADDRIE_M | I2C_CR1_RXIE_M | I2C_CR1_STOPIE_M); // enable interrupt from i2c HAL_EPIC_MaskLevelSet(EPICmask); } - twiIsOn = true; + handler->isInited = true; return I2C_OK; } /* * Function twi_deinit * Desc disables twi pins - * Input none + * Input handler - pointer to wire common handler * Output none */ -void twi_deinit(void) +void twi_deinit(WireHandler_TypeDef* handler) { - uint32_t EPICmask; - -#if I2C_NUM == 0 - hi2c.Instance = I2C_0; - EPICmask = HAL_EPIC_I2C_0_MASK; -#elif I2C_NUM == 1 - hi2c.Instance = I2C_1; - EPICmask = HAL_EPIC_I2C_1_MASK; -#else - #error "Unsupported I2C_NUM value in pins_arduino.h" -#endif - - HAL_I2C_Deinit(&hi2c); + HAL_I2C_Deinit(&(handler->i2c_param)); // for slave mode disable interrupts from i2c - if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE) - HAL_EPIC_MaskLevelClear(EPICmask); + if (handler->i2c_param.Init.Mode == HAL_I2C_MODE_SLAVE) + { + if (handler->i2c_num == 0) + HAL_EPIC_MaskLevelClear(HAL_EPIC_I2C_0_MASK); + else + HAL_EPIC_MaskLevelClear(HAL_EPIC_I2C_1_MASK); + } - twiIsOn = false; + handler->isInited = false; } /* * Function twi_setClock * Desc sets twi bit rate - * Input Clock Frequency - 100000 / 400000 / 1000000, + * Input handler - pointer to wire common handler + * Clock Frequency - 100000 / 400000 / 1000000, * onInit = true only if function is called from twi_init() * Output I2C_OK - frequency changed, I2C_ERROR - frequency didn't change */ -uint8_t twi_setFrequency(uint32_t frequency, bool onInit) +uint8_t twi_setFrequency(WireHandler_TypeDef* handler, uint32_t frequency, bool onInit) { uint8_t ret = I2C_OK; // change the frequency only during or after bus initialization - if (twiIsOn || onInit) + if (handler->isInited || onInit) { // You can change the frequency only when the interface is turned off - HAL_I2C_Disable(&hi2c); + HAL_I2C_Disable(&(handler->i2c_param)); if (frequency == WIRE_FREQ_100K) // 100 kHz { - hi2c.Clock.PRESC = 2; - hi2c.Clock.SCLDEL = 8; - hi2c.Clock.SDADEL = 2; - hi2c.Clock.SCLH = 49; - hi2c.Clock.SCLL = 49; - CurrentFrequency = WIRE_FREQ_100K; + handler->i2c_param.Clock.PRESC = 2; + handler->i2c_param.Clock.SCLDEL = 8; + handler->i2c_param.Clock.SDADEL = 2; + handler->i2c_param.Clock.SCLH = 49; + handler->i2c_param.Clock.SCLL = 49; + // CurrentFrequency = WIRE_FREQ_100K; } else if (frequency == WIRE_FREQ_400K) // 400 kHz { - hi2c.Clock.PRESC = 0; - hi2c.Clock.SCLDEL = 3; - hi2c.Clock.SDADEL = 2; - hi2c.Clock.SCLH = 30; - hi2c.Clock.SCLL = 30; - CurrentFrequency = WIRE_FREQ_400K; + handler->i2c_param.Clock.PRESC = 0; + handler->i2c_param.Clock.SCLDEL = 3; + handler->i2c_param.Clock.SDADEL = 2; + handler->i2c_param.Clock.SCLH = 30; + handler->i2c_param.Clock.SCLL = 30; + // CurrentFrequency = WIRE_FREQ_400K; } else if (frequency == WIRE_FREQ_1000K)// 1000 kHz { - hi2c.Clock.PRESC = 0; - hi2c.Clock.SCLDEL = 1; - hi2c.Clock.SDADEL = 2; - hi2c.Clock.SCLH = 6; - hi2c.Clock.SCLL = 6; - CurrentFrequency = WIRE_FREQ_1000K; + handler->i2c_param.Clock.PRESC = 0; + handler->i2c_param.Clock.SCLDEL = 1; + handler->i2c_param.Clock.SDADEL = 2; + handler->i2c_param.Clock.SCLH = 6; + handler->i2c_param.Clock.SCLL = 6; + // CurrentFrequency = WIRE_FREQ_1000K; } else if (frequency == 0) // slave mode { - hi2c.Clock.PRESC = 0; - hi2c.Clock.SCLDEL = 0; - hi2c.Clock.SDADEL = 2; - hi2c.Clock.SCLH = 0; - hi2c.Clock.SCLL = 0; + handler->i2c_param.Clock.PRESC = 0; + handler->i2c_param.Clock.SCLDEL = 0; + handler->i2c_param.Clock.SDADEL = 2; + handler->i2c_param.Clock.SCLH = 0; + handler->i2c_param.Clock.SCLL = 0; } else // frequency does not change @@ -165,11 +152,11 @@ uint8_t twi_setFrequency(uint32_t frequency, bool onInit) // write the timings to the register if everything is OK if (ret == I2C_OK) - HAL_I2C_SetClockSpeed(&hi2c); + HAL_I2C_SetClockSpeed(&(handler->i2c_param)); //turn the interface back only if initialization has already passed - if (twiIsOn) - HAL_I2C_Enable(&hi2c); + if (handler->isInited) + HAL_I2C_Enable(&(handler->i2c_param)); } else ret = I2C_ERROR; @@ -181,26 +168,27 @@ uint8_t twi_setFrequency(uint32_t frequency, bool onInit) * Function twi_masterReadFrom * Desc attempts to become twi bus master and read a * series of bytes from a device on the bus - * Input address: 7bit i2c device address + * Input hi2c: pointer to hardware i2c handler + * address: 7bit i2c device address * data: pointer to byte array * length: number of bytes to read into array * sendStop: Boolean indicating whether to send a stop at the end * Output number of bytes read */ -uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) +uint8_t twi_masterReadFrom(I2C_HandleTypeDef* hi2c, uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) { uint8_t ret = 0; // if there are errors left from previous transactions, you need to restart // the interface for correct operation - if (hi2c.ErrorCode != I2C_ERROR_NONE) - HAL_I2C_Reset(&hi2c); + if (hi2c->ErrorCode != I2C_ERROR_NONE) + HAL_I2C_Reset(hi2c); - if (sendStop) hi2c.Init.AutoEnd = 1; - else hi2c.Init.AutoEnd = 0; + if (sendStop) hi2c->Init.AutoEnd = 1; + else hi2c->Init.AutoEnd = 0; // put the data directly into the external buffer - if (HAL_I2C_Master_Receive(&hi2c, address, data, length, TIMEOUT_TICKS) == HAL_OK) + if (HAL_I2C_Master_Receive(hi2c, address, data, length, TIMEOUT_TICKS) == HAL_OK) ret = length; return ret; @@ -210,7 +198,8 @@ uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8 * Function twi_masterWriteTo * Desc attempts to become twi bus master and write a * series of bytes to a device on the bus - * Input address: 7bit i2c device address + * Input hi2c: pointer to hardware i2c handler + * address: 7bit i2c device address * data: pointer to byte array * length: number of bytes in array * sendStop: boolean indicating whether or not to send a stop at the end @@ -221,28 +210,28 @@ uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8 * 4 .. other twi error (lost bus arbitration, bus error, ..) * 5 .. timeout */ -uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) +uint8_t twi_masterWriteTo(I2C_HandleTypeDef* hi2c, uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) { uint8_t ret = I2C_OK; // if there are errors left from previous transactions, you need to restart // the interface for correct operation - if (hi2c.ErrorCode != I2C_ERROR_NONE) - HAL_I2C_Reset(&hi2c); + if (hi2c->ErrorCode != I2C_ERROR_NONE) + HAL_I2C_Reset(hi2c); - if (sendStop) hi2c.Init.AutoEnd = 1; - else hi2c.Init.AutoEnd = 0; + if (sendStop) hi2c->Init.AutoEnd = 1; + else hi2c->Init.AutoEnd = 0; // take data from an external buffer - HAL_I2C_Master_Transmit(&hi2c, address, data, length, TIMEOUT_TICKS); + HAL_I2C_Master_Transmit(hi2c, address, data, length, TIMEOUT_TICKS); // parse errors // check separately, because in hal libraries not all functions look at this - if (HAL_I2C_Get_Interrupts_Status(&hi2c) & I2C_ISR_NACKF_M) - hi2c.ErrorCode = I2C_ERROR_NACK; - if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_TIMEOUT) ret = I2C_TIMEOUT; // timeout - else if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_NACK) ret = I2C_NACK_DATA; // didn't receive ACK - else if (hi2c.ErrorCode != (HAL_I2C_ErrorTypeDef)I2C_OK) ret = I2C_ERROR; // any other error + if (HAL_I2C_Get_Interrupts_Status(hi2c) & I2C_ISR_NACKF_M) + hi2c->ErrorCode = I2C_ERROR_NACK; + if (hi2c->ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_TIMEOUT) ret = I2C_TIMEOUT; // timeout + else if (hi2c->ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_NACK) ret = I2C_NACK_DATA; // didn't receive ACK + else if (hi2c->ErrorCode != (HAL_I2C_ErrorTypeDef)I2C_OK) ret = I2C_ERROR; // any other error return ret; } @@ -251,97 +240,79 @@ uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_ * Function twi_slaveWrite * Desc attempts to become twi bus slave and write a * series of bytes to a master after it asks - * Input txData: pointer to byte array + * Input hi2c: pointer to hardware i2c handler + * txData: pointer to byte array * bytesNum: number of bytes in array * Output 0 .. success * 5 .. timeout */ -i2c_status_e twi_slaveWrite(uint8_t *txData, uint8_t bytesNum) +i2c_status_e twi_slaveWrite(I2C_HandleTypeDef* hi2c, uint8_t *txData, uint8_t bytesNum) { - if ((hi2c.ErrorCode != I2C_ERROR_NONE)) - HAL_I2C_Reset(&hi2c); + if ((hi2c->ErrorCode != I2C_ERROR_NONE)) + HAL_I2C_Reset(hi2c); // send data HAL_StatusTypeDef error_code = HAL_OK; - HAL_I2C_Clear_Reload(&hi2c); - if (!(HAL_I2C_Get_CR1_Content(&hi2c) & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0 - HAL_I2C_Reset_TXDR_Content(&hi2c); - HAL_I2C_Write_TXDR(&hi2c, txData[0]); // first recording is made in advance + HAL_I2C_Clear_Reload(hi2c); + if (!(HAL_I2C_Get_CR1_Content(hi2c) & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0 + HAL_I2C_Reset_TXDR_Content(hi2c); + HAL_I2C_Write_TXDR(hi2c, txData[0]); // first recording is made in advance // write byte for (uint32_t tx_count = 1; tx_count < bytesNum; tx_count++) { - if ((error_code = HAL_I2C_Slave_WaitTXIS(&hi2c, TIMEOUT_TICKS)) != HAL_OK) + if ((error_code = HAL_I2C_Slave_WaitTXIS(hi2c, TIMEOUT_TICKS)) != HAL_OK) { // failed to write - HAL_I2C_Reset_TXDR_Content(&hi2c); - HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus - HAL_I2C_Reset(&hi2c); + HAL_I2C_Reset_TXDR_Content(hi2c); + HAL_I2C_Reset_Interrupt_Flag(hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus + HAL_I2C_Reset(hi2c); return I2C_TIMEOUT; } - HAL_I2C_Write_TXDR(&hi2c, txData[tx_count]); + HAL_I2C_Write_TXDR(hi2c, txData[tx_count]); } - if ((error_code = HAL_I2C_WaitBusy(&hi2c, TIMEOUT_TICKS)) != HAL_OK) + if ((error_code = HAL_I2C_WaitBusy(hi2c, TIMEOUT_TICKS)) != HAL_OK) { // failed to complete transaction - HAL_I2C_Reset(&hi2c); + HAL_I2C_Reset(hi2c); return I2C_TIMEOUT; } - HAL_I2C_Reset_TXDR_Content(&hi2c); - HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus + HAL_I2C_Reset_TXDR_Content(hi2c); + HAL_I2C_Reset_Interrupt_Flag(hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus return I2C_OK; } -/* - * Function twi_attachSlaveRxEvent - * Desc sets function called before a slave read operation - * Input function: callback function to use - * Output none - */ -void twi_attachSlaveRxEvent( void (*function)(uint8_t*, int) ) -{ - twi_onSlaveReceive = function; -} - -/* - * Function twi_attachSlaveTxEvent - * Desc sets function called before a slave write operation - * Input function: callback function to use - * Output none - */ -void twi_attachSlaveTxEvent( void (*function)(void) ) -{ - twi_onSlaveTransmit = function; -} - - /* * Function twi_interruptHandler * Desc handles an interrupts from twi - * Input none + * Input handler - pointer to wire common handler * Output none */ -void __attribute__((optimize("O3"))) twi_interruptHandler(void) +void __attribute__((optimize("O3"))) twi_interruptHandler(WireHandler_TypeDef* handler) { - uint32_t int_mask = HAL_I2C_Get_CR1_Content(&hi2c) & I2C_INTMASK; // interrupts allowed - uint32_t interrupt_status = HAL_I2C_Get_Interrupts_Status(&hi2c); // current flags + uint32_t int_mask = HAL_I2C_Get_CR1_Content(&(handler->i2c_param)) & I2C_INTMASK; // interrupts allowed + uint32_t interrupt_status = HAL_I2C_Get_Interrupts_Status(&(handler->i2c_param)); // current flags // master calls by address, device in slave mode if ((interrupt_status & I2C_ISR_ADDR_M) && (int_mask & I2C_CR1_ADDRIE_M)) { // reset ADDR flag - HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_ADDRCF_M); + HAL_I2C_Reset_Interrupt_Flag(&(handler->i2c_param), I2C_ICR_ADDRCF_M); // look at the transmission direction and respond to the request if (interrupt_status & I2C_ISR_DIR_M) // master reads, slave sends - twi_onSlaveTransmit(); // slave send data + { + // twi_onSlaveTransmit(); // slave send data + if (handler->onSlaveTransmit) + handler->onSlaveTransmit(handler->instance); + } else // master writes, slave reads { - twi_rxBufferIndex = 0; // write from the beginning of the buffer - hi2c.State = HAL_I2C_STATE_BUSY; - HAL_I2C_Clear_Reload(&hi2c); + handler->rxBufferIndex = 0; // write from the beginning of the buffer + handler->i2c_param.State = HAL_I2C_STATE_BUSY; + HAL_I2C_Clear_Reload(&(handler->i2c_param)); // wait for interrupts by receiving a byte or a stop condition } } @@ -350,16 +321,16 @@ void __attribute__((optimize("O3"))) twi_interruptHandler(void) if ((interrupt_status & I2C_ISR_RXNE_M) && (int_mask & I2C_CR1_RXIE_M)) { // put new byte into buffer - twi_rxBuffer[twi_rxBufferIndex++] = HAL_I2C_Get_RXDR(&hi2c); + handler->rxBuffer[handler->rxBufferIndex++] = HAL_I2C_Get_RXDR(&(handler->i2c_param)); } // master sent a STOP to the bus if ((interrupt_status & I2C_ISR_STOPF_M) && (int_mask & I2C_CR1_STOPIE_M)) { - hi2c.State = HAL_I2C_STATE_END; - HAL_I2C_Reset_TXDR_Content(&hi2c); - HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus + handler->i2c_param.State = HAL_I2C_STATE_END; + HAL_I2C_Reset_TXDR_Content(&(handler->i2c_param)); + HAL_I2C_Reset_Interrupt_Flag(&(handler->i2c_param), I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus // pass the received data to callback function - twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); + handler->onSlaveReceive(handler->instance, handler->rxBuffer, handler->rxBufferIndex); } } \ No newline at end of file diff --git a/libraries/Wire/src/utility/twi.h b/libraries/Wire/src/utility/twi.h index 4d83a97..e4a814d 100644 --- a/libraries/Wire/src/utility/twi.h +++ b/libraries/Wire/src/utility/twi.h @@ -5,10 +5,24 @@ extern "C" { #endif +#include "mik32_hal_i2c.h" + #ifndef TWI_BUFFER_LENGTH #define TWI_BUFFER_LENGTH 32 #endif +typedef struct +{ + I2C_HandleTypeDef i2c_param; + uint8_t i2c_num; + bool isInited; + uint8_t rxBuffer[TWI_BUFFER_LENGTH]; + volatile uint8_t rxBufferIndex; + void (*onSlaveTransmit)(void*); + void (*onSlaveReceive) (void*, uint8_t*, int); + void *instance; +}WireHandler_TypeDef; + // I2C state typedef enum { @@ -21,17 +35,16 @@ typedef enum I2C_BUSY = 6 } i2c_status_e; -uint8_t twi_init(uint8_t slaveAddress); -void twi_deinit(void); -uint8_t twi_setFrequency(uint32_t frequency, bool onInit); +uint8_t twi_init (WireHandler_TypeDef* handler, uint8_t slaveAddress); +void twi_deinit(WireHandler_TypeDef* handler); -uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop); -uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop); -i2c_status_e twi_slaveWrite(uint8_t *txData, uint8_t bytesNum); +uint8_t twi_setFrequency(WireHandler_TypeDef* handler, uint32_t frequency, bool onInit); -void twi_attachSlaveRxEvent(void (*function)(uint8_t*, int)); -void twi_attachSlaveTxEvent(void (*function)(void)); -void twi_interruptHandler(void); +uint8_t twi_masterReadFrom (I2C_HandleTypeDef* hi2c, uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop); +uint8_t twi_masterWriteTo (I2C_HandleTypeDef* hi2c, uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop); +i2c_status_e twi_slaveWrite (I2C_HandleTypeDef* hi2c, uint8_t *txData, uint8_t bytesNum); + +void twi_interruptHandler(WireHandler_TypeDef* handler); #ifdef __cplusplus } diff --git a/variants/elbear_ace_uno/pins_arduino.h b/variants/elbear_ace_uno/pins_arduino.h index 7a7f3ce..3095d54 100644 --- a/variants/elbear_ace_uno/pins_arduino.h +++ b/variants/elbear_ace_uno/pins_arduino.h @@ -67,6 +67,7 @@ volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x); volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x); // the function initializes additional MCU pins depending on the specified pin number void additionalPinsInit(uint32_t PinNumber); +static inline void additionalPinsDeinit(uint32_t PinNumber){} // UART // available uarts quantity @@ -87,23 +88,35 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber); HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber); // SPI -#define PIN_SPI_SS (10) -#define PIN_SPI_MOSI (11) -#define PIN_SPI_MISO (12) -#define PIN_SPI_SCK (13) +#define SPI_COMMON_QTY 2 + +#define PIN_SPI_SS 10 +#define PIN_SPI_MOSI 11 +#define PIN_SPI_MISO 12 +#define PIN_SPI_SCK 13 static const uint8_t SS = PIN_SPI_SS; static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; + +#define PIN_SPI1_SS 9 +#define PIN_SPI1_MOSI 5 +#define PIN_SPI1_MISO 3 +#define PIN_SPI1_SCK 6 +static const uint8_t SS1 = PIN_SPI1_SS; +static const uint8_t MOSI1 = PIN_SPI1_MOSI; +static const uint8_t MISO1 = PIN_SPI1_MISO; +static const uint8_t SCK1 = PIN_SPI1_SCK; + // config SEL_NSS1 to replace D10 to different controller pin, -// because pin 1.3 which is D10 by default is needed to spi -void spi_onBegin(void); -void spi_onEnd(void); +// because NSS which is D9/D10 by default is needed to spi +void spi_onBegin(uint8_t spiNum); +void spi_onEnd(uint8_t spiNum); // I2C -#define PIN_WIRE_SDA (18) -#define PIN_WIRE_SCL (19) -#define I2C_NUM (1) // i2c number 1 +#define PIN_WIRE_SDA (18) +#define PIN_WIRE_SCL (19) +#define I2C_COMMON_QTY (1) static const uint8_t SDA = PIN_WIRE_SDA; static const uint8_t SCL = PIN_WIRE_SCL; // available frequencies @@ -112,7 +125,7 @@ static const uint8_t SCL = PIN_WIRE_SCL; #define WIRE_FREQ_1000K 1000000 // interrupts -#define EXTERNAL_INTERRUPTS_QTY 7 +#define EXTERNAL_INTERRUPTS_QTY 8 extern uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3]; // determines the board pin number by interrupt number #define interruptToDigitalPin(interruptNum) (interruptInfo[interruptNum][0]) diff --git a/variants/elbear_ace_uno/variant.c b/variants/elbear_ace_uno/variant.c index 1d5e306..ef112c0 100644 --- a/variants/elbear_ace_uno/variant.c +++ b/variants/elbear_ace_uno/variant.c @@ -16,7 +16,22 @@ #include "wiring_analog.h" #include "wiring_LL.h" -bool spiNssPinIsBlocked = false; +#define SPI0_SWITCH_PORT GPIO_1 +#define SPI0_SWITCH_PIN GPIO_PIN_10 +#define SPI0_NSS_IN_PORT GPIO_0 +#define SPI0_NSS_IN_PIN GPIO_PIN_3 +#define SPI0_NSS_OUT_PORT GPIO_1 +#define SPI0_NSS_OUT_PIN GPIO_PIN_14 + +#define SPI1_SWITCH_PORT GPIO_1 +#define SPI1_SWITCH_PIN GPIO_PIN_6 +#define SPI1_NSS_IN_PORT GPIO_1 +#define SPI1_NSS_IN_PIN GPIO_PIN_3 +#define SPI1_NSS_OUT_PORT GPIO_1 +#define SPI1_NSS_OUT_PIN GPIO_PIN_4 + +bool spi0NssPinIsBlocked = false; +bool spi1NssPinIsBlocked = false; // list of pin numbers from both ports with pins inside the port const HAL_PinsTypeDef digitalPinToGpioPinArray[] = @@ -51,17 +66,16 @@ const HAL_PinsTypeDef digitalPinToGpioPinArray[] = GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber) { GPIO_TypeDef* gpioNum = 0; - // port 0 - board pins 0...6, 9, 16(A2), 17(A3), 20(A4), 21(A5) - if ((digPinNumber >= 0 && digPinNumber <= 6) || digPinNumber == 9 || digPinNumber == 16 - || digPinNumber == 17 || digPinNumber == 20 || digPinNumber == 21) // 12 pieces - gpioNum = GPIO_0; + // port 2 - led and button + if (digPinNumber == LED_BUILTIN || digPinNumber == BTN_BUILTIN) + gpioNum = GPIO_2; // port 1 - board pins 7, 8, 10...13, 14(А0), 15(А1), 18,19 else if (digPinNumber == 7 || digPinNumber == 8 || (digPinNumber >= 10 && digPinNumber <= 15) - || digPinNumber == 18 || digPinNumber == 19) // 10 pieces + || digPinNumber == 18 || digPinNumber == 19 || (digPinNumber == 9 && spi0NssPinIsBlocked)) // 10 pieces gpioNum = GPIO_1; - // port 2 - led and button - else if (digPinNumber == LED_BUILTIN || digPinNumber == BTN_BUILTIN) - gpioNum = GPIO_2; + // port 0 - board pins 0...6, 9, 16(A2), 17(A3), 20(A4), 21(A5) + else + gpioNum = GPIO_0; return gpioNum; } @@ -72,9 +86,11 @@ HAL_PinsTypeDef digitalPinToBitMask(uint32_t digPinNumber) if (digPinNumber < pinCommonQty()) { HAL_PinsTypeDef mask; - // if spi is on default pin 1.3 is needed for spi, D10 is replaced to pin 1.4 - if (spiNssPinIsBlocked && (digPinNumber == 10)) - mask = GPIO_PIN_4; + // if spi is on default pin NSS_IN is needed for spi, board pin is replaced to pin NSS_OUT + if ((digPinNumber == 10) && spi1NssPinIsBlocked) + mask = SPI1_NSS_OUT_PIN; + else if ((digPinNumber == 9) && spi0NssPinIsBlocked) + mask = SPI0_NSS_OUT_PIN; else mask = digitalPinToGpioPinArray[digPinNumber]; return mask; @@ -101,20 +117,22 @@ volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x) } // the function initializes additional MCU pins depending on the specified pin number +#define SELA45_PORT GPIO_1 +#define SELA45_PIN GPIO_PIN_15 +static bool selaSwitchIsInited = false; void additionalPinsInit(uint32_t PinNumber) { - // if we use pin A5, we need to set SELA45 (1.15) to 1 to switch the output from A4 to A5 + if (!selaSwitchIsInited) + { + HAL_GPIO_PinConfig(SELA45_PORT, SELA45_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + selaSwitchIsInited = true; + } + // if we use pin A5, we need to set SELA45 to 1 to switch the output from A4 to A5 if (PinNumber == A5) - { - HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_15, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); - HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_15, GPIO_PIN_HIGH); - } + HAL_GPIO_WritePin(SELA45_PORT, SELA45_PIN, GPIO_PIN_HIGH); else if(PinNumber == A4) - { // return the switch to A4 in case A5 was previously read - HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_15, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); - HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_15, GPIO_PIN_LOW); - } + HAL_GPIO_WritePin(SELA45_PORT, SELA45_PIN, GPIO_PIN_LOW); } // ---------------------- ADC ---------------------- // @@ -153,25 +171,14 @@ uint32_t analogInputToChannelNumber(uint32_t PinNumber) // ---------------------- PWM ---------------------- // // use only if digitalPinHasPWM() == true -#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)) ? 1:0) -// use only if digitalPinHasPWM() == true -static inline uint8_t pwmPinToGpioPinShift(uint8_t digitalPin) -{ - if (digitalPin == 3) - return 0; - else if ((digitalPin == 5) || (digitalPin == 11)) - return 1; - else if (digitalPin == 6) - return 2; - else // pins 9 10 - return 3; -} +#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)||(pin==12)||(pin==13)) ? 1:0) + // use only if digitalPinHasPWM() == true // return true if digitalPin configured as pwm bool digitalPinPwmIsOn(uint8_t digitalPin) { uint8_t config = 0; - uint8_t pinShift = pwmPinToGpioPinShift(digitalPin); + uint8_t pinShift = PIN_MASK_TO_PIN_NUMBER(digitalPinToBitMask(digitalPin)); if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); @@ -187,10 +194,10 @@ bool digitalPinPwmIsOn(uint8_t digitalPin) bool digitalPinHasPWM(uint8_t p) { bool ret = false; - // if spi is in use D10 cannot work as pwm - if (spiNssPinIsBlocked && (p == 10)) + // if spi is in use D9 or D10 cannot work as pwm + if (((p == 9) && spi0NssPinIsBlocked) || ((p == 10) && spi1NssPinIsBlocked)) ret = false; - else if ((p) == 3 || (p) == 5 || (p) == 6 || (p) == 9 || (p) == 10 || (p) == 11) + else if (p == 3 || p == 5 || p == 6 || (p >= 9 && p <= 13)) ret = true; return ret; } @@ -204,7 +211,7 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber) if (digPinNumber == 3 || digPinNumber == 5 || digPinNumber == 6 || digPinNumber == 9) timerNum = TIMER32_1; // timer 2 - else if (digPinNumber == 10 || digPinNumber == 11) + else if (digPinNumber == 10 || digPinNumber == 11 || digPinNumber == 12 || digPinNumber == 13) timerNum = TIMER32_2; return timerNum; @@ -214,9 +221,9 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber) HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber) { HAL_TIMER32_CHANNEL_IndexTypeDef channel = 0; - if (digPinNumber == 3) channel = TIMER32_CHANNEL_0; + if (digPinNumber == 3 || digPinNumber == 12) channel = TIMER32_CHANNEL_0; else if (digPinNumber == 5 || digPinNumber == 11) channel = TIMER32_CHANNEL_1; - else if (digPinNumber == 6) channel = TIMER32_CHANNEL_2; + else if (digPinNumber == 6 || digPinNumber == 13) channel = TIMER32_CHANNEL_2; else if (digPinNumber == 9 || digPinNumber == 10) channel = TIMER32_CHANNEL_3; return channel; } @@ -232,7 +239,9 @@ uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3] = { 5, GPIO_LINE_1, GPIO_MUX_LINE_1_PORT0_1}, // INT3 { 8, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_9}, // INT4 { 9, GPIO_LINE_3, GPIO_MUX_LINE_3_PORT0_3}, // INT5 - {BTN_BUILTIN, GPIO_LINE_6, GPIO_MUX_LINE_6_PORT2_6}, // INT6 (button) + { A1, GPIO_LINE_7, GPIO_MUX_LINE_7_PORT1_7}, // INT6 + {BTN_BUILTIN, GPIO_LINE_6, GPIO_MUX_LINE_6_PORT2_6}, // INT7 (button) + }; int8_t digitalPinToGpioIntMux(uint8_t digPinNumber) @@ -275,44 +284,94 @@ int8_t digitalPinToInterrupt(uint32_t digPinNumber) } // ---------------------- SPI ---------------------- // -void spi_onBegin(void) +void spi_onBegin(uint8_t spiNum) { - // On Elbear Ace-Uno rev1.1.0 there is a seller on pin 1.6 which replace D10 from spi NSS pin 1.3 to pin 1.4, - // because spi needs pin 1.3 for correct work + // On Elbear Ace-Uno rev1.1.0 spi0 needs pin 0.3, spi1 needs pin 1.3 for correct work (NSS_IN). + // This pins are connected to board digital pins D9 and D10. There is a seller on each pin which + // replace board digital pin from NSS_IN pin to different free pin (NSS_OUT) + + // replace config from NSS_IN to NSS_OUT + uint8_t config; + if (spiNum == 1) + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)); + else + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN)); - // replace config from 1.3 to 1.4 - uint8_t config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)); if (config == 0) // common gpio { - // get info from pin gpio1.3 and set config to gpio1.4 - HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_4, HAL_GPIO_GetPinDirection(GPIO_1, GPIO_PIN_3), - (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)), - HAL_GPIO_DS_2MA); - HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_4, (GPIO_PinState)GPIO_GET_PIN_STATE(GPIO_1, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3))); - - // pin D10 was switched to different gpio and can be used further + if (spiNum == 1) + { + // get info from pin NSS_IN and set config to NSS_OUT + HAL_GPIO_PinConfig(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)), + HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_IN_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN))); + + // pin D10 was switched to different gpio and can be used further + } + else + { + // get info from pin NSS_IN and set config to NSS_OUT + HAL_GPIO_PinConfig(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_0_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN)), + HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI0_NSS_IN_PORT, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN))); + // pin D9 was switched to different gpio and can be used further + } } else if(config == 2) // timer for pwm { - // if D10 (spi NSS pin) was used as pwm, we need to stop timer, because 1.4 don't support it - analogWriteStop(10); - ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running"); + // if spi NSS_IN pin was used as pwm, we need to stop timer, because another pins don't support it + if (spiNum == 1) + { + analogWriteStop(10); + ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running"); + } + else + { + analogWriteStop(9); + ErrorMsgHandler("analogWrite(): D9 cannot be used as PWM pin while SPI1 is running"); + } } - // switch seller to pin 1.4 - HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_6, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); - HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_HIGH); - spiNssPinIsBlocked = true; // block spi pin + // switch seller to pin NSS_OUT + if (spiNum == 1) + { + HAL_GPIO_PinConfig(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_HIGH); + spi1NssPinIsBlocked = true; // block spi pin + } + else + { + HAL_GPIO_PinConfig(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_HIGH); + spi0NssPinIsBlocked = true; // block spi pin + } } -void spi_onEnd(void) +void spi_onEnd(uint8_t spiNum) { - // get info from pin gpio1.4 and set config to gpio1.3 - HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_3, HAL_GPIO_GetPinDirection(GPIO_1, GPIO_PIN_4), - (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_4)), HAL_GPIO_DS_2MA); - HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_3, (GPIO_PinState)GPIO_GET_PIN_STATE(GPIO_1, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_4))); + // get info from pin NSS_OUT and set config to NSS_IN + if (spiNum == 1) + { + HAL_GPIO_PinConfig(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN)), HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, + (GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN))); - // switch seller back to pin 1.3 - HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW); - spiNssPinIsBlocked = false; // unblock spi pin + // switch seller back to NSS_IN + HAL_GPIO_WritePin(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_LOW); + spi1NssPinIsBlocked = false; // unblock spi pin + } + else + { + HAL_GPIO_PinConfig(SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_OUT_PIN)), HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN, + (GPIO_PinState)GPIO_GET_PIN_STATE(SPI0_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_OUT_PIN))); + + // switch seller back to NSS_IN + HAL_GPIO_WritePin(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_LOW); + spi0NssPinIsBlocked = false; // unblock spi pin + } } \ No newline at end of file diff --git a/variants/elbear_nano/pins_arduino.h b/variants/elbear_nano/pins_arduino.h new file mode 100644 index 0000000..db4e8c7 --- /dev/null +++ b/variants/elbear_nano/pins_arduino.h @@ -0,0 +1,157 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include "wiring_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mik32_hal_gpio.h" +#include "mik32_hal_timer32.h" + +// analog pins +#define PIN_A0 (14) +#define PIN_A1 (15) +#define PIN_A2 (16) +#define PIN_A3 (17) +// there are D18 and D19 between them for SDA and SCL +#define PIN_A4 (20) +#define PIN_A5 (21) +// there are led (22) and btn (23) on the ace-uno between them +#define PIN_A6 (24) +#define PIN_A7 (25) +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; +static const uint8_t A6 = PIN_A5; +static const uint8_t A7 = PIN_A5; + + +// digital pins +// D0...D13, D18, D19 + +// User led and button +#define LED_BUILTIN (22) + +// determines the address of the port by the board pin number to which this pin belongs on the MCU +GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber); +// determines the pin address inside the port by the board pin number +HAL_PinsTypeDef digitalPinToBitMask(uint32_t digPinNumber); +// total number of pins available for initialization +uint16_t pinCommonQty(void); +// the function returns a reference to the OUTPUT address of the GPIO register +volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x); +// the function returns a reference to the STATE address of the GPIO register +volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x); +// the function initializes additional MCU pins depending on the specified pin number +void additionalPinsInit(uint32_t PinNumber); +void additionalPinsDeinit(uint32_t PinNumber); + +// UART +// available uarts quantity +#define SERIAL_PORT_QTY 2 + +// ADC +#define MCU_ADC_RESOLUTION 12 // bits +// determines the ADC channel number by the board pin number +uint32_t analogInputToChannelNumber(uint32_t PinNumber); + +// PWM +#define PWM_FREQUENCY_MAX 1000000 // Hz +bool digitalPinHasPWM(uint8_t p); +bool digitalPinPwmIsOn(uint8_t digitalPin); // use only if digitalPinHasPWM() == true +// determines which timer the pin belongs to +TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber); +// determines which timer channel the pin belongs to +HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber); + +// SPI +#define SPI_COMMON_QTY 2 + +#define PIN_SPI_SS 10 +#define PIN_SPI_MOSI 11 +#define PIN_SPI_MISO 12 +#define PIN_SPI_SCK 13 +static const uint8_t SS = PIN_SPI_SS; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + + +#define PIN_SPI1_SS 9 +#define PIN_SPI1_MOSI 5 +#define PIN_SPI1_MISO 3 +#define PIN_SPI1_SCK 6 +static const uint8_t SS1 = PIN_SPI1_SS; +static const uint8_t MOSI1 = PIN_SPI1_MOSI; +static const uint8_t MISO1 = PIN_SPI1_MISO; +static const uint8_t SCK1 = PIN_SPI1_SCK; + +// config SEL_NSS1 to replace D10 to different controller pin, +// because NSS which is D9/D10 by default is needed to spi +void spi_onBegin(uint8_t spiNum); +void spi_onEnd(uint8_t spiNum); + +// I2C +#define PIN_WIRE_SDA 18 +#define PIN_WIRE_SCL 19 +#define I2C_COMMON_QTY 1 +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; +// available frequencies +#define WIRE_FREQ_100K 100000 +#define WIRE_FREQ_400K 400000 +#define WIRE_FREQ_1000K 1000000 + +// interrupts +#define EXTERNAL_INTERRUPTS_QTY 8 +extern uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3]; +// determines the board pin number by interrupt number +#define interruptToDigitalPin(interruptNum) (interruptInfo[interruptNum][0]) +// determines gpio interrupt line by interrupt number +#define interruptToGpioIntLine(interruptNum) ((uint8_t)interruptInfo[interruptNum][1]) +// determines gpio interrupt mux by interrupt number +#define interruptToGpioIntMux(interruptNum) ((uint8_t)interruptInfo[interruptNum][2]) +// determines interrupt number by the board pin number +int8_t digitalPinToInterrupt(uint32_t digPinNumber); +// determines interrupt number by the gpio interrupt line +int8_t gpioIntLineToInterrupt(uint32_t gpioIntLine); +// determines gpio interrupt mux by the board pin number +int8_t digitalPinToGpioIntMux(uint8_t digPinNumber); +// determines gpio interrupt line by the board pin number +int8_t digitalPinToGpioIntLine(uint8_t digPinNumber); + + + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/variants/elbear_nano/variant.c b/variants/elbear_nano/variant.c new file mode 100644 index 0000000..907e301 --- /dev/null +++ b/variants/elbear_nano/variant.c @@ -0,0 +1,413 @@ +/** + ******************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * All rights reserved. + * + * This software component is licensed by WCH under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ + +#include "pins_arduino.h" +#include "mik32_hal_adc.h" +#include "wiring_analog.h" +#include "wiring_LL.h" + +#define SPI0_SWITCH_PORT GPIO_1 +#define SPI0_SWITCH_PIN GPIO_PIN_10 +#define SPI0_NSS_IN_PORT GPIO_0 +#define SPI0_NSS_IN_PIN GPIO_PIN_3 +#define SPI0_NSS_OUT_PORT GPIO_1 +#define SPI0_NSS_OUT_PIN GPIO_PIN_14 + +#define SPI1_SWITCH_PORT GPIO_1 +#define SPI1_SWITCH_PIN GPIO_PIN_6 +#define SPI1_NSS_IN_PORT GPIO_1 +#define SPI1_NSS_IN_PIN GPIO_PIN_3 +#define SPI1_NSS_OUT_PORT GPIO_1 +#define SPI1_NSS_OUT_PIN GPIO_PIN_4 + +bool spi0NssPinIsBlocked = false; +bool spi1NssPinIsBlocked = false; + +// list of pin numbers from both ports with pins inside the port +const HAL_PinsTypeDef digitalPinToGpioPinArray[] = +{ + GPIO_PIN_5, // D0 + GPIO_PIN_6, // D1 + GPIO_PIN_10,// D2 + GPIO_PIN_0, // D3 + GPIO_PIN_8, // D4 + GPIO_PIN_1, // D5 + GPIO_PIN_2, // D6 + GPIO_PIN_8, // D7 + GPIO_PIN_9, // D8 + GPIO_PIN_3, // D9 + GPIO_PIN_3, // D10 + GPIO_PIN_1, // D11 + GPIO_PIN_0, // D12 + GPIO_PIN_2, // D13 + GPIO_PIN_5, // D14/A0 + GPIO_PIN_7, // D15/A1 + GPIO_PIN_4, // D16/A2 + GPIO_PIN_7, // D17/A3 + GPIO_PIN_12,// D18 + GPIO_PIN_13,// D19 + GPIO_PIN_9, // A4 (pin 20) + GPIO_PIN_9, // A5 (pin 21) + GPIO_PIN_7, // LED(pin 22) + 0, // dummy pin for backward compatibility with ace-uno + GPIO_PIN_9, // A6 (pin 24) + GPIO_PIN_9, // A7 (pin 25) +}; + +// determines the address of the port by the board pin number to which this pin belongs on the MCU +GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber) +{ + GPIO_TypeDef* gpioNum = 0; + // port 2 - led (22) + if (digPinNumber == LED_BUILTIN) + gpioNum = GPIO_2; + // port 1 - board pins 7, 8, 10...13, 14(А0), 15(А1), 18,19 + else if (digPinNumber == 7 || digPinNumber == 8 || (digPinNumber >= 10 && digPinNumber <= 15) + || digPinNumber == 18 || digPinNumber == 19 || (digPinNumber == 9 && spi0NssPinIsBlocked)) + gpioNum = GPIO_1; + // port 0 - board pins 0...6, 9, 16(A2), 17(A3), 20(A4), 21(A5), 24(A6), 25(A7) + else + gpioNum = GPIO_0; + + return gpioNum; +} + +// determines the pin address inside the port by the board pin number +HAL_PinsTypeDef digitalPinToBitMask(uint32_t digPinNumber) +{ + if (digPinNumber < pinCommonQty()) + { + HAL_PinsTypeDef mask; + // if spi is on default pin NSS_IN is needed for spi, board pin is replaced to pin NSS_OUT + if ((digPinNumber == 10) && spi1NssPinIsBlocked) + mask = SPI1_NSS_OUT_PIN; + else if ((digPinNumber == 9) && spi0NssPinIsBlocked) + mask = SPI0_NSS_OUT_PIN; + else + mask = digitalPinToGpioPinArray[digPinNumber]; + return mask; + } + else + return NC; +} + +uint16_t pinCommonQty(void) +{ + return (uint16_t)(sizeof(digitalPinToGpioPinArray)/sizeof(digitalPinToGpioPinArray[0])); +} + +// the function returns a reference to the OUTPUT address of the GPIO register +volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x) +{ + return &GPIO_x->OUTPUT_; +} + +// the function returns a reference to the STATE address of the GPIO register +volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x) +{ + return &GPIO_x->STATE; +} + +// the function initializes additional MCU pins depending on the specified pin number +#define SELA_A_PORT GPIO_1 +#define SELA_A_PIN GPIO_PIN_15 +#define SELA_B_PORT GPIO_1 +#define SELA_B_PIN GPIO_PIN_11 +static bool selaSwitchesIsInited = false; + +void additionalPinsInit(uint32_t PinNumber) +{ + // init switches + if (!selaSwitchesIsInited) + { + // SELA_A + HAL_GPIO_PinConfig(SELA_A_PORT, SELA_A_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + // SELA_B + HAL_GPIO_PinConfig(SELA_B_PORT, SELA_B_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + selaSwitchesIsInited = true; + } + + if (PinNumber == A4) + { + HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_LOW); + HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_LOW); + } + else if(PinNumber == A5) + { + HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_HIGH); + HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_LOW); + } + else if(PinNumber == A6) + { + HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_LOW); + HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_HIGH); + } + else if(PinNumber == A7) + { + HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_HIGH); + HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_HIGH); + } +} + +void additionalPinsDeinit(uint32_t PinNumber) +{ + if (PinNumber == A4 || PinNumber == A5) + { + // select A7 via switches selaA, selaB to allow using A4 and A5 as digital outputs + HAL_GPIO_WritePin(SELA_A_PORT, SELA_A_PIN, GPIO_PIN_HIGH); + HAL_GPIO_WritePin(SELA_B_PORT, SELA_B_PIN, GPIO_PIN_HIGH); + } +} + +// ---------------------- ADC ---------------------- // +// determines the ADC channel number by the board pin number +uint32_t analogInputToChannelNumber(uint32_t PinNumber) +{ + uint32_t adcChannel = 0; + + // if get a value 0...5 instead of A0...A7 + if (PinNumber < 4) PinNumber += 14; // A0...A3 + else if (PinNumber < 6) PinNumber += 16; // A4, A5 + else if (PinNumber < 8) PinNumber += 18; // A6, A7 + + switch (PinNumber) + { + case PIN_A0: + adcChannel = ADC_CHANNEL0; + break; + case PIN_A1: + adcChannel = ADC_CHANNEL1; + break; + case PIN_A2: + adcChannel = ADC_CHANNEL3; + break; + case PIN_A3: + adcChannel = ADC_CHANNEL4; + break; + case PIN_A4: + case PIN_A5: + case PIN_A6: + case PIN_A7: + adcChannel = ADC_CHANNEL5; + break; + default: + adcChannel = NC; + } + return adcChannel; +} + +// ---------------------- PWM ---------------------- // +// use only if digitalPinHasPWM() == true +#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)||(pin==12)||(pin==13)) ? 1:0) + +// use only if digitalPinHasPWM() == true +// return true if digitalPin configured as pwm +bool digitalPinPwmIsOn(uint8_t digitalPin) +{ + uint8_t config = 0; + uint8_t pinShift = PIN_MASK_TO_PIN_NUMBER(digitalPinToBitMask(digitalPin)); + + if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); + else + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, pinShift); + + if (config == 2) + return true; + else + return false; +} + +bool digitalPinHasPWM(uint8_t p) +{ + bool ret = false; + // if spi is in use D10 cannot work as pwm + if (((p == 9) && spi0NssPinIsBlocked) || ((p == 10) && spi1NssPinIsBlocked)) + ret = false; + else if (p == 3 || p == 5 || p == 6 || (p >= 9 && p <= 13)) + ret = true; + return ret; +} + +// function is used only if digitalPinHasPWM() is true +TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber) +{ + TIMER32_TypeDef* timerNum = NULL; + + // timer 1 + if (digPinNumber == 3 || digPinNumber == 5 || digPinNumber == 6 || digPinNumber == 9) + timerNum = TIMER32_1; + // timer 2 + else if ((digPinNumber >= 10) && (digPinNumber <= 13)) + timerNum = TIMER32_2; + + return timerNum; +} + +// function is used only if digitalPinHasPWM() is true +HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber) +{ + HAL_TIMER32_CHANNEL_IndexTypeDef channel = 0; + if (digPinNumber == 3 || digPinNumber == 12) channel = TIMER32_CHANNEL_0; + else if (digPinNumber == 5 || digPinNumber == 11) channel = TIMER32_CHANNEL_1; + else if (digPinNumber == 6 || digPinNumber == 13) channel = TIMER32_CHANNEL_2; + else if (digPinNumber == 9 || digPinNumber == 10) channel = TIMER32_CHANNEL_3; + return channel; +} + +// ---------------------- interrupts ---------------------- // +// interrupt table is stored in ram to improve performance +// index = interrupt number. In each row {digitalPinNumber, IntLineValue, IntMuxValue} +uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3] = +{ + { 2, GPIO_LINE_2, GPIO_MUX_LINE_2_PORT0_10}, // INT0 + { 3, GPIO_LINE_0, GPIO_MUX_LINE_0_PORT0_0}, // INT1 + { 4, GPIO_LINE_4, GPIO_MUX_LINE_4_PORT0_8}, // INT2 + { 5, GPIO_LINE_1, GPIO_MUX_LINE_1_PORT0_1}, // INT3 + { 6, GPIO_LINE_6, GPIO_MUX_LINE_6_PORT0_2}, // INT4 + { 8, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_9}, // INT5 + { 9, GPIO_LINE_3, GPIO_MUX_LINE_3_PORT0_3}, // INT6 + { A1, GPIO_LINE_7, GPIO_MUX_LINE_7_PORT1_7}, // INT7 +}; + +int8_t digitalPinToGpioIntMux(uint8_t digPinNumber) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][0] == digPinNumber) + return interruptInfo[i][2]; + } + return NOT_AN_INTERRUPT; +} +int8_t digitalPinToGpioIntLine(uint8_t digPinNumber) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][0] == digPinNumber) + return interruptInfo[i][1]; + } + return NOT_AN_INTERRUPT; +} + +int8_t gpioIntLineToInterrupt(uint32_t gpioIntLine) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][1] == gpioIntLine) + return i; + } + return NOT_AN_INTERRUPT; +} + +int8_t digitalPinToInterrupt(uint32_t digPinNumber) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][0] == digPinNumber) + return i; + } + return NOT_AN_INTERRUPT; +} + +// ---------------------- SPI ---------------------- // +void spi_onBegin(uint8_t spiNum) +{ + // On Elbear Nano spi0 needs pin 0.3, spi1 needs pin 1.3 for correct work (NSS_IN). + // This pins are connected to board digital pins D9 and D10. There is a seller on each pin which + // replace board digital pin from NSS_IN pin to different free pin (NSS_OUT) + + // replace config from NSS_IN to NSS_OUT + uint8_t config; + if (spiNum == 1) + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)); + else + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN)); + + if (config == 0) // common gpio + { + if (spiNum == 1) + { + // get info from pin NSS_IN and set config to NSS_OUT + HAL_GPIO_PinConfig(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)), + HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_IN_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN))); + + // pin D10 was switched to different gpio and can be used further + } + else + { + // get info from pin NSS_IN and set config to NSS_OUT + HAL_GPIO_PinConfig(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_0_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN)), + HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN, (GPIO_PinState)GPIO_GET_PIN_STATE(SPI0_NSS_IN_PORT, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_IN_PIN))); + // pin D9 was switched to different gpio and can be used further + } + } + else if(config == 2) // timer for pwm + { + // if spi NSS_IN pin was used as pwm, we need to stop timer, because another pins don't support it + if (spiNum == 1) + { + analogWriteStop(10); + ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running"); + } + else + { + analogWriteStop(9); + ErrorMsgHandler("analogWrite(): D9 cannot be used as PWM pin while SPI1 is running"); + } + } + + // switch seller to pin NSS_OUT + if (spiNum == 1) + { + HAL_GPIO_PinConfig(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_HIGH); + spi1NssPinIsBlocked = true; // block spi pin + } + else + { + HAL_GPIO_PinConfig(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_HIGH); + spi0NssPinIsBlocked = true; // block spi pin + } +} + +void spi_onEnd(uint8_t spiNum) +{ + // get info from pin NSS_OUT and set config to NSS_IN + if (spiNum == 1) + { + HAL_GPIO_PinConfig(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN)), HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, + (GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN))); + + // switch seller back to NSS_IN + HAL_GPIO_WritePin(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_LOW); + spi1NssPinIsBlocked = false; // unblock spi pin + } + else + { + HAL_GPIO_PinConfig(SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI0_NSS_OUT_PORT, SPI0_NSS_OUT_PIN), + (HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_OUT_PIN)), HAL_GPIO_DS_2MA); + HAL_GPIO_WritePin (SPI0_NSS_IN_PORT, SPI0_NSS_IN_PIN, + (GPIO_PinState)GPIO_GET_PIN_STATE(SPI0_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI0_NSS_OUT_PIN))); + + // switch seller back to NSS_IN + HAL_GPIO_WritePin(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_LOW); + spi0NssPinIsBlocked = false; // unblock spi pin + } +} \ No newline at end of file diff --git a/variants/elsomik/pins_arduino.h b/variants/elsomik/pins_arduino.h new file mode 100644 index 0000000..f0ff4df --- /dev/null +++ b/variants/elsomik/pins_arduino.h @@ -0,0 +1,201 @@ +/* + pins_arduino.h - Pin definition functions for Arduino + Part of Arduino - http://www.arduino.cc/ + + Copyright (c) 2007 David A. Mellis + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include "wiring_constants.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mik32_hal_gpio.h" +#include "mik32_hal_timer32.h" + +// digital pins +typedef enum +{ + P0_0 = 0, // 0 + P0_1, // 1 + P0_2, // 2 + P0_3, // 3 + P0_4, // 4 + P0_5, // 5 + P0_6, // 6 + P0_7, // 7 + P0_8, // 8 + P0_9, // 9 + P0_10, // 10 + P0_11, // 11 // TDI + P0_12, // 12 // TCK + P0_13, // 13 // TMS + P0_14, // 14 // TRST + P0_15, // 15 // TDO + P1_0, // 16 + P1_1, // 17 + P1_2, // 18 + P1_3, // 19 + P1_4, // 20 + P1_5, // 21 + P1_6, // 22 + P1_7, // 23 + P1_8, // 24 + P1_9, // 25 + P1_10, // 26 + P1_11, // 27 + P1_12, // 28 + P1_13, // 29 + P1_14, // 30 + P1_15, // 31 + P2_6, // 32 + P2_7, // 33 + PINS_COMMON_QTY, // 34 +} DigitalPinsTypeDef; + +// analog pins +#define PIN_A0 (P1_5) +#define PIN_A1 (P1_7) +#define PIN_A2 (P0_2) +#define PIN_A3 (P0_4) +#define PIN_A4 (P0_7) +#define PIN_A5 (P0_9) +#define PIN_A6 (P0_11) +#define PIN_A7 (P0_13) + +static const uint8_t A0 = PIN_A0; +static const uint8_t A1 = PIN_A1; +static const uint8_t A2 = PIN_A2; +static const uint8_t A3 = PIN_A3; +static const uint8_t A4 = PIN_A4; +static const uint8_t A5 = PIN_A5; +static const uint8_t A6 = PIN_A6; +static const uint8_t A7 = PIN_A7; + + +// determines the address of the port by the board pin number to which this pin belongs on the MCU +GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber); +// determines the pin address inside the port by the board pin number +static inline HAL_PinsTypeDef digitalPinToBitMask(uint32_t digitalPinNumber) +{ + if (digitalPinNumber >= P2_6) + return (HAL_PinsTypeDef)(1 << ((digitalPinNumber+6) & 0xF)); + else + return (HAL_PinsTypeDef)(1 << (digitalPinNumber & 0xF)); +} +// total number of pins available for initialization +static inline uint16_t pinCommonQty(void) +{ + return (uint16_t)PINS_COMMON_QTY; +} +// the function returns a reference to the OUTPUT address of the GPIO register +volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x); +// the function returns a reference to the STATE address of the GPIO register +volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x); +// functions are needed for compatibility with other boards +static inline void additionalPinsInit(uint32_t PinNumber) {} +static inline void additionalPinsDeinit(uint32_t PinNumber){} + +// UART +// available uarts quantity +#define SERIAL_PORT_QTY 2 + +// ADC +#define MCU_ADC_RESOLUTION 12 // bits +// determines the ADC channel number by the board pin number +uint32_t analogInputToChannelNumber(uint32_t PinNumber); + +// PWM +#define PWM_FREQUENCY_MAX 1000000 // Hz +bool digitalPinHasPWM(uint8_t p); +bool digitalPinPwmIsOn(uint8_t digitalPin); // use only if digitalPinHasPWM() == true +// determines which timer the pin belongs to +TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber); +// determines which timer channel the pin belongs to +HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber); + +// SPI +#define SPI_COMMON_QTY 2 + +#define PIN_SPI_SS P1_3 +#define PIN_SPI_MOSI P1_1 +#define PIN_SPI_MISO P1_0 +#define PIN_SPI_SCK P1_2 +static const uint8_t SS = PIN_SPI_SS; +static const uint8_t MOSI = PIN_SPI_MOSI; +static const uint8_t MISO = PIN_SPI_MISO; +static const uint8_t SCK = PIN_SPI_SCK; + +#define PIN_SPI1_SS P0_3 +#define PIN_SPI1_MOSI P0_1 +#define PIN_SPI1_MISO P0_0 +#define PIN_SPI1_SCK P0_2 +static const uint8_t SS1 = PIN_SPI1_SS; +static const uint8_t MOSI1 = PIN_SPI1_MOSI; +static const uint8_t MISO1 = PIN_SPI1_MISO; +static const uint8_t SCK1 = PIN_SPI1_SCK; + +// check if pwm is used on spi pins +void spi_onBegin(uint8_t spiNum); +static inline void spi_onEnd(uint8_t spiNum){} + +// I2C +#define I2C_COMMON_QTY 2 +// Wire (I2C1) +#define PIN_WIRE_SDA P1_12 +#define PIN_WIRE_SCL P1_13 +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; +// Wire1 (I2C0) +#define PIN_WIRE_SDA1 P0_9 +#define PIN_WIRE_SCL1 P0_10 +static const uint8_t SDA1 = PIN_WIRE_SDA1; +static const uint8_t SCL1 = PIN_WIRE_SCL1; +// available frequencies +#define WIRE_FREQ_100K 100000 +#define WIRE_FREQ_400K 400000 +#define WIRE_FREQ_1000K 1000000 + +// interrupts +#define EXTERNAL_INTERRUPTS_QTY 8 +extern uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3]; +// determines the board pin number by interrupt number +#define interruptToDigitalPin(interruptNum) (interruptInfo[interruptNum][0]) +// determines gpio interrupt line by interrupt number +#define interruptToGpioIntLine(interruptNum) ((uint8_t)interruptInfo[interruptNum][1]) +// determines gpio interrupt mux by interrupt number +#define interruptToGpioIntMux(interruptNum) ((uint8_t)interruptInfo[interruptNum][2]) +// determines interrupt number by the board pin number +int8_t digitalPinToInterrupt(uint32_t digPinNumber); +// determines interrupt number by the gpio interrupt line +int8_t gpioIntLineToInterrupt(uint32_t gpioIntLine); +// determines gpio interrupt mux by the board pin number +int8_t digitalPinToGpioIntMux(uint8_t digPinNumber); +// determines gpio interrupt line by the board pin number +int8_t digitalPinToGpioIntLine(uint8_t digPinNumber); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/variants/elsomik/variant.c b/variants/elsomik/variant.c new file mode 100644 index 0000000..3480f52 --- /dev/null +++ b/variants/elsomik/variant.c @@ -0,0 +1,222 @@ +/** + ******************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * All rights reserved. + * + * This software component is licensed by WCH under BSD 3-Clause license, + * the "License"; You may not use this file except in compliance with the + * License. You may obtain a copy of the License at: + * opensource.org/licenses/BSD-3-Clause + * + ******************************************************************************* + */ + +#include "pins_arduino.h" +#include "mik32_hal_adc.h" +#include "wiring_analog.h" +#include "wiring_LL.h" + +/** + * @brief Determines the address of the port by the board pin number to which this pin belongs on the MCU + * @return The address of the port corresponding to the board pin number. Can return 0 if the pin not exists + */ + +GPIO_TypeDef *digitalPinToPort(uint32_t digitalPinNumber) +{ + if (digitalPinNumber <= P0_15) + return GPIO_0; + else if ((digitalPinNumber >= P1_0) && (digitalPinNumber <= P1_15)) + return GPIO_1; + else if ((digitalPinNumber >= P2_6) && (digitalPinNumber < PINS_COMMON_QTY)) + return GPIO_2; + else + return NULL; +} + +// the function returns a reference to the OUTPUT address of the GPIO register +volatile uint32_t *portOutputRegister(GPIO_TypeDef *GPIO_x) +{ + return &GPIO_x->OUTPUT_; +} + +// the function returns a reference to the STATE address of the GPIO register +volatile uint32_t *portInputRegister(GPIO_TypeDef *GPIO_x) +{ + return &GPIO_x->STATE; +} + +// ---------------------- ADC ---------------------- // +// determines the ADC channel number by the board pin number +uint32_t analogInputToChannelNumber(uint32_t PinNumber) +{ + uint32_t adcChannel = 0; + + switch (PinNumber) + { + case PIN_A0: + adcChannel = ADC_CHANNEL0; + break; + case PIN_A1: + adcChannel = ADC_CHANNEL1; + break; + case PIN_A2: + adcChannel = ADC_CHANNEL2; + break; + case PIN_A3: + adcChannel = ADC_CHANNEL3; + break; + case PIN_A4: + adcChannel = ADC_CHANNEL4; + break; + case PIN_A5: + adcChannel = ADC_CHANNEL5; + break; + case PIN_A6: + adcChannel = ADC_CHANNEL6; + break; + case PIN_A7: + adcChannel = ADC_CHANNEL7; + break; + default: + adcChannel = NC; + } + return adcChannel; +} + +// ---------------------- PWM ---------------------- // +// use only if digitalPinHasPWM() == true +#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin) & 16) ? 1 : 0) + +// use only if digitalPinHasPWM() == true +// return true if digitalPin configured as pwm +bool digitalPinPwmIsOn(uint8_t digitalPin) +{ + uint8_t config = 0; + uint8_t pinShift = digitalPin & 0x3; + + if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); + else + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, pinShift); + + if (config == 2) + return true; + else + return false; +} + +bool digitalPinHasPWM(uint8_t digitalPin) +{ + return (digitalPin <= P1_15) && ((digitalPin & 0xF) < 4); +} + +// function is used only if digitalPinHasPWM() is true +TIMER32_TypeDef *pwmPinToTimer(uint32_t digPinNumber) +{ + if (digPinNumber <= P0_15) + return TIMER32_1; + else if ((digPinNumber >= P1_0) && (digPinNumber <= P1_15)) + return TIMER32_2; + else + return NULL; +} + +// function is used only if digitalPinHasPWM() is true +HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber) +{ + switch (digPinNumber & 0x3) + { + case 0: + return TIMER32_CHANNEL_0; + case 1: + return TIMER32_CHANNEL_1; + case 2: + return TIMER32_CHANNEL_2; + case 3: + return TIMER32_CHANNEL_3; + default: + return 255; + } +} + +// ---------------------- interrupts ---------------------- // +// interrupt table is stored in ram to improve performance +// index = interrupt number. In each row {digitalPinNumber, IntLineValue, IntMuxValue} +uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3] = +{ + {P0_8, GPIO_LINE_0, GPIO_MUX_LINE_0_PORT0_8}, // INT0 + {P1_4, GPIO_LINE_4, GPIO_MUX_LINE_4_PORT1_4}, // INT1 + {P1_5, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_5}, // INT2 + {P1_6, GPIO_LINE_6, GPIO_MUX_LINE_6_PORT1_6}, // INT3 + {P1_9, GPIO_LINE_1, GPIO_MUX_LINE_1_PORT1_9}, // INT4 + {P1_10, GPIO_LINE_2, GPIO_MUX_LINE_2_PORT1_10}, // INT5 + {P1_15, GPIO_LINE_3, GPIO_MUX_LINE_3_PORT1_15}, // INT6 + {P2_7, GPIO_LINE_7, GPIO_MUX_LINE_7_PORT2_7}, // INT7 +}; + +int8_t digitalPinToGpioIntMux(uint8_t digPinNumber) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][0] == digPinNumber) + return interruptInfo[i][2]; + } + return NOT_AN_INTERRUPT; +} +int8_t digitalPinToGpioIntLine(uint8_t digPinNumber) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][0] == digPinNumber) + return interruptInfo[i][1]; + } + return NOT_AN_INTERRUPT; +} + +int8_t gpioIntLineToInterrupt(uint32_t gpioIntLine) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][1] == gpioIntLine) + return i; + } + return NOT_AN_INTERRUPT; +} + +int8_t digitalPinToInterrupt(uint32_t digPinNumber) +{ + for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) + { + if (interruptInfo[i][0] == digPinNumber) + return i; + } + return NOT_AN_INTERRUPT; +} + +// ---------------------- SPI ---------------------- // +void spi_onBegin(uint8_t spiNum) +{ + // On mik32 spi0 needs pin 0.3, spi1 needs pin 1.3 for correct work. + // This pins also can be used as pwm. If pwm is working when spi begins, we should stop the pwm channel + + // get pin NSS_IN config + uint8_t config; + if (spiNum == 1) + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)); + else + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)); + + if(config == 2) // timer for pwm + { + if (spiNum == 1) + { + analogWriteStop(P1_3); + ErrorMsgHandler("analogWrite(): P1_3 cannot be used as PWM pin while SPI is running"); + } + else + { + analogWriteStop(P0_3); + ErrorMsgHandler("analogWrite(): P0_3 cannot be used as PWM pin while SPI1 is running"); + } + } +} \ No newline at end of file diff --git a/variants/start/pins_arduino.h b/variants/start/pins_arduino.h index 58c4dff..1c0907c 100644 --- a/variants/start/pins_arduino.h +++ b/variants/start/pins_arduino.h @@ -32,49 +32,51 @@ extern "C" { #include "mik32_hal_gpio.h" #include "mik32_hal_timer32.h" -#define PORT_PIN_MASK 0xF - // digital pins -#define P0_0 0 -#define P0_1 1 -#define P0_2 2 -#define P0_3 3 -#define P0_4 4 -#define P0_5 5 -#define P0_6 6 -#define P0_7 7 -#define P0_8 8 -#define P0_9 9 -#define P0_10 10 -#define P0_11 11 -#define P0_12 12 -#define P0_13 13 -#define P0_14 14 -#define P0_15 15 -#define P1_0 16 -#define P1_1 17 -#define P1_2 18 -#define P1_3 19 -#define P1_4 20 -#define P1_5 21 -#define P1_6 22 -#define P1_7 23 -#define P1_8 24 -#define P1_9 25 -#define P1_10 26 -#define P1_11 27 -#define P1_12 28 -#define P1_13 29 -#define P1_14 30 -#define P1_15 31 -#define P2_0 32 -#define P2_1 33 -#define P2_2 34 -#define P2_3 35 -#define P2_4 36 -#define P2_5 37 -#define P2_6 38 -#define P2_7 39 +typedef enum +{ + P0_0 = 0, // 0 + P0_1, // 1 + P0_2, // 2 + P0_3, // 3 + P0_4, // 4 + P0_5, // 5 + P0_6, // 6 + P0_7, // 7 + P0_8, // 8 + P0_9, // 9 + P0_10, // 10 + P0_11, // 11 + P0_12, // 12 + P0_13, // 13 + P0_14, // 14 + P0_15, // 15 + P1_0, // 16 + P1_1, // 17 + P1_2, // 18 + P1_3, // 19 + P1_4, // 20 + P1_5, // 21 + P1_6, // 22 + P1_7, // 23 + P1_8, // 24 + P1_9, // 25 + P1_10, // 26 + P1_11, // 27 + P1_12, // 28 + P1_13, // 29 + P1_14, // 30 + P1_15, // 31 + P2_0, // 32 + P2_1, // 33 + P2_2, // 34 + P2_3, // 35 + P2_4, // 36 + P2_5, // 37 + P2_6, // 38 + P2_7, // 39 + PINS_COMMON_QTY, // 40 +} DigitalPinsTypeDef; // analog pins #define PIN_A0 (P1_5) @@ -112,14 +114,15 @@ static inline HAL_PinsTypeDef digitalPinToBitMask(uint32_t digitalPinNumber) // total number of pins available for initialization static inline uint16_t pinCommonQty(void) { - return (uint16_t)40; + return (uint16_t)PINS_COMMON_QTY; } // the function returns a reference to the OUTPUT address of the GPIO register volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x); // the function returns a reference to the STATE address of the GPIO register volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x); -// the function is needed for compatibility with other boards +// functions are needed for compatibility with other boards static inline void additionalPinsInit(uint32_t PinNumber) {} +static inline void additionalPinsDeinit(uint32_t PinNumber){} // UART // available uarts quantity @@ -140,24 +143,42 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber); HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber); // SPI -#define PIN_SPI_SS (P1_3) -#define PIN_SPI_MOSI (P1_1) -#define PIN_SPI_MISO (P1_0) -#define PIN_SPI_SCK (P1_2) +#define SPI_COMMON_QTY 2 + +#define PIN_SPI_SS P1_3 +#define PIN_SPI_MOSI P1_1 +#define PIN_SPI_MISO P1_0 +#define PIN_SPI_SCK P1_2 static const uint8_t SS = PIN_SPI_SS; static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t SCK = PIN_SPI_SCK; -// functions is needed for compatibility with other boards -static inline void spi_onBegin(void) {} -static inline void spi_onEnd(void) {} + +#define PIN_SPI1_SS P0_3 +#define PIN_SPI1_MOSI P0_1 +#define PIN_SPI1_MISO P0_0 +#define PIN_SPI1_SCK P0_2 +static const uint8_t SS1 = PIN_SPI1_SS; +static const uint8_t MOSI1 = PIN_SPI1_MOSI; +static const uint8_t MISO1 = PIN_SPI1_MISO; +static const uint8_t SCK1 = PIN_SPI1_SCK; + +// check if pwm is used on spi pins +void spi_onBegin(uint8_t spiNum); +static inline void spi_onEnd(uint8_t spiNum){} // I2C -#define PIN_WIRE_SDA (P1_12) -#define PIN_WIRE_SCL (P1_13) -#define I2C_NUM (1) // i2c number 1 -static const uint8_t SDA = PIN_WIRE_SDA; -static const uint8_t SCL = PIN_WIRE_SCL; +#define I2C_COMMON_QTY 2 +// Wire (I2C1) +#define PIN_WIRE_SDA P1_12 +#define PIN_WIRE_SCL P1_13 +static const uint8_t SDA = PIN_WIRE_SDA; +static const uint8_t SCL = PIN_WIRE_SCL; +// Wire1 (I2C0) +#define PIN_WIRE_SDA1 P0_9 +#define PIN_WIRE_SCL1 P0_10 +static const uint8_t SDA1 = PIN_WIRE_SDA1; +static const uint8_t SCL1 = PIN_WIRE_SCL1; // available frequencies #define WIRE_FREQ_100K 100000 #define WIRE_FREQ_400K 400000 diff --git a/variants/start/variant.c b/variants/start/variant.c index d220902..c19e64f 100644 --- a/variants/start/variant.c +++ b/variants/start/variant.c @@ -94,17 +94,13 @@ uint32_t analogInputToChannelNumber(uint32_t PinNumber) // ---------------------- PWM ---------------------- // // use only if digitalPinHasPWM() == true #define PWM_PIN_TO_PORT_NUMBER(pin) (((pin) & 16) ? 1 : 0) -// use only if digitalPinHasPWM() == true -static inline uint8_t pwmPinToGpioPinShift(uint8_t digitalPin) -{ - return digitalPin & 3; -} + // use only if digitalPinHasPWM() == true // return true if digitalPin configured as pwm bool digitalPinPwmIsOn(uint8_t digitalPin) { uint8_t config = 0; - uint8_t pinShift = pwmPinToGpioPinShift(digitalPin); + uint8_t pinShift = digitalPin & 3; if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); @@ -209,4 +205,32 @@ int8_t digitalPinToInterrupt(uint32_t digPinNumber) return i; } return NOT_AN_INTERRUPT; +} + +// ---------------------- SPI ---------------------- // +void spi_onBegin(uint8_t spiNum) +{ + // On mik32 spi0 needs pin 0.3, spi1 needs pin 1.3 for correct work. + // This pins also can be used as pwm. If pwm is working when spi begins, we should stop the pwm channel + + // get pin NSS_IN config + uint8_t config; + if (spiNum == 1) + config = PIN_GET_PAD_CONFIG(PORT_1_CFG, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)); + else + config = PIN_GET_PAD_CONFIG(PORT_0_CFG, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)); + + if(config == 2) // timer for pwm + { + if (spiNum == 1) + { + analogWriteStop(P1_3); + ErrorMsgHandler("analogWrite(): P1_3 cannot be used as PWM pin while SPI is running"); + } + else + { + analogWriteStop(P0_3); + ErrorMsgHandler("analogWrite(): P0_3 cannot be used as PWM pin while SPI1 is running"); + } + } } \ No newline at end of file