- добавлена поддержка плат nano, elsomik
- добавлена поддержка аппаратного i2c0 - добавлена поддержка аппаратного spi0 - на elbear добавлена поддержка еще двух каналов ШИМ и одного прерывания - мелкие исправления в глобальном разрешении прерываний, в работе tone, в hal модуле сторожевого таймера
This commit is contained in:
commit
a247ca2467
@ -9,6 +9,8 @@
|
||||
## Платы, входящие в состав пакета
|
||||
Пакет включает в себя поддержку следующих плат:
|
||||
- [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).
|
||||
|
||||
56
boards.txt
56
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
|
||||
|
||||
261
bootloaders/elsomik/bootloader.hex
Normal file
261
bootloaders/elsomik/bootloader.hex
Normal file
@ -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
|
||||
@ -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);
|
||||
|
||||
@ -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] =
|
||||
{
|
||||
|
||||
@ -6,10 +6,12 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#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);
|
||||
|
||||
@ -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 --------------------- //
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -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. */
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
@ -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();
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -4,11 +4,24 @@
|
||||

|
||||
### Цифровые выводы
|
||||
На плате 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`.
|
||||
|
||||
### SPI
|
||||
Интерфейс SPI1 доступен на выводах D11, D12, D13. Для работы с ним используется экземпляр класса под названием `SPI`.
|
||||
Интерфейс SPI0 доступен на выводах D3, D5, D6. Используемый экземпляр класса - `SPI1`.
|
||||
@ -57,3 +57,8 @@
|
||||
Интерфейс UART1 доступен на выводах P1_8, P1_9, используемый экземпляр класса - `Serial1`.
|
||||
USB-UART преобразователь, установленный на плате, поддерживает стандартные скорости UART до 57600 бод. Нестандартные скорости должны быть кратны
|
||||
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.
|
||||
BIN
docs/elsomikOEM_pinout.png
Normal file
BIN
docs/elsomikOEM_pinout.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 168 KiB |
BIN
docs/elsomikSE_pinout.png
Normal file
BIN
docs/elsomikSE_pinout.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 175 KiB |
90
docs/elsomik_description.md
Normal file
90
docs/elsomik_description.md
Normal file
@ -0,0 +1,90 @@
|
||||
# Elsomik
|
||||
Особенности работы с платой Elsomik в среде программирования ArduinoIDE.
|
||||
### Функциональное назначение выводов для плат Elsomik OEM и Elsomik SE
|
||||

|
||||

|
||||
|Номер вывода|Доступные функции|Номер вывода|Доступные функции|
|
||||
|---------|---------|---------|---------|
|
||||
|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.
|
||||
48
docs/nano_description.md
Normal file
48
docs/nano_description.md
Normal file
@ -0,0 +1,48 @@
|
||||
# Elbear Nano
|
||||
Особенности работы с платами Elbear Nano в среде программирования ArduinoIDE.
|
||||
### Функциональное назначение выводов
|
||||

|
||||
### Цифровые выводы
|
||||
На плате 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`.
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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<<interruptNumber); // delete interrupt from mask
|
||||
if (!interruptMask)
|
||||
interruptMode = 0;
|
||||
_interruptMask &= ~(1<<interruptNumber); // delete interrupt from mask
|
||||
if (!_interruptMask)
|
||||
_interruptMode = 0;
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
|
||||
void SPIClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
// update SPI settings
|
||||
updateSettings(settings.speedMaximum, settings.newDataOrder, settings.newDataMode);
|
||||
|
||||
// disable interrupts in use if necessary
|
||||
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))
|
||||
// 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");
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#define _SPI_H_INCLUDED
|
||||
|
||||
#include <Arduino.h>
|
||||
#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
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -4,31 +4,9 @@ extern "C"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#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
|
||||
|
||||
@ -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<TwoWire*>(instance)->onRequestService();
|
||||
}
|
||||
static inline void staticOnReceiveService(void* instance, uint8_t* inBytes, int numBytes)
|
||||
{
|
||||
static_cast<TwoWire*>(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
|
||||
|
||||
@ -2,162 +2,149 @@
|
||||
#include <inttypes.h>
|
||||
#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;
|
||||
if (handler->i2c_num == 0)
|
||||
{
|
||||
handler->i2c_param.Instance = I2C_0;
|
||||
EPICmask = HAL_EPIC_I2C_0_MASK;
|
||||
#elif I2C_NUM == 1
|
||||
hi2c.Instance = I2C_1;
|
||||
}
|
||||
else if (handler->i2c_num == 1)
|
||||
{
|
||||
handler->i2c_param.Instance = I2C_1;
|
||||
EPICmask = HAL_EPIC_I2C_1_MASK;
|
||||
#else
|
||||
#error "Unsupported I2C_NUM value in pins_arduino.h"
|
||||
#endif
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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 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])
|
||||
|
||||
@ -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)),
|
||||
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(GPIO_1, GPIO_PIN_4, (GPIO_PinState)GPIO_GET_PIN_STATE(GPIO_1, PIN_MASK_TO_PIN_NUMBER(GPIO_PIN_3)));
|
||||
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
|
||||
// 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");
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
void spi_onEnd(void)
|
||||
else
|
||||
{
|
||||
// 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)));
|
||||
|
||||
// switch seller back to pin 1.3
|
||||
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW);
|
||||
spiNssPinIsBlocked = false; // unblock spi pin
|
||||
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
|
||||
}
|
||||
}
|
||||
157
variants/elbear_nano/pins_arduino.h
Normal file
157
variants/elbear_nano/pins_arduino.h
Normal file
@ -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
|
||||
413
variants/elbear_nano/variant.c
Normal file
413
variants/elbear_nano/variant.c
Normal file
@ -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
|
||||
}
|
||||
}
|
||||
201
variants/elsomik/pins_arduino.h
Normal file
201
variants/elsomik/pins_arduino.h
Normal file
@ -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
|
||||
222
variants/elsomik/variant.c
Normal file
222
variants/elsomik/variant.c
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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
|
||||
#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
|
||||
|
||||
@ -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);
|
||||
@ -210,3 +206,31 @@ int8_t digitalPinToInterrupt(uint32_t digPinNumber)
|
||||
}
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user