- добавлена поддержка плат nano, elsomik

- добавлена поддержка аппаратного i2c0
- добавлена поддержка аппаратного spi0
- на elbear добавлена поддержка еще двух каналов ШИМ и одного прерывания
- мелкие исправления в глобальном разрешении прерываний, в работе tone, в hal модуле сторожевого таймера
This commit is contained in:
KLASSENTS 2025-02-04 09:29:17 +07:00
commit a247ca2467
37 changed files with 2159 additions and 512 deletions

View File

@ -8,8 +8,10 @@
## Платы, входящие в состав пакета ## Платы, входящие в состав пакета
Пакет включает в себя поддержку следующих плат: Пакет включает в себя поддержку следующих плат:
- [Elbear Ace-Uno](./docs/Elbear_description.md) 8 Mb / 16 Mb / 32 Mb - [Elbear Ace-Uno](./docs/Elbear_description.md) 8 Mb / 16 Mb / 32 Mb
- [START-MIK32](./docs/Start_mik32_description.md) - [Elbear Nano](./docs/nano_description.md)
- [Elsomik](./docs/elsomik_description.md)
- [START-MIK32](./docs/Start_mik32_description.md)
## Особенности использования пакета в ArduinoIDE ## Особенности использования пакета в 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) )`, выполняются в прерывании| |[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| |[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()` перед началом работы с памятью| |[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 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) * [Материалы по плате 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). При возникновении вопросов или выявлении проблем можно оставить заявку [здесь](https://gitflic.ru/project/elron-tech/elbear_arduino_bsp/issue).

View File

@ -14,7 +14,7 @@ aceUno8Mb.upload.speed=230400
# tool for bootloader update # tool for bootloader update
aceUno8Mb.bootloader.tool=mik32_upload aceUno8Mb.bootloader.tool=mik32_upload
aceUno8Mb.bootloader.tool.default=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 aceUno8Mb.bootloader.interface=ftdi/mikron-link.cfg
# build options # build options
@ -40,7 +40,7 @@ aceUno16Mb.upload.speed=230400
# tool for bootloader update # tool for bootloader update
aceUno16Mb.bootloader.tool=mik32_upload aceUno16Mb.bootloader.tool=mik32_upload
aceUno16Mb.bootloader.tool.default=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 aceUno16Mb.bootloader.interface=ftdi/mikron-link.cfg
# build options # build options
@ -66,7 +66,7 @@ aceUno32Mb.upload.speed=230400
# tool for bootloader update # tool for bootloader update
aceUno32Mb.bootloader.tool=mik32_upload aceUno32Mb.bootloader.tool=mik32_upload
aceUno32Mb.bootloader.tool.default=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 aceUno32Mb.bootloader.interface=ftdi/mikron-link.cfg
# build options # build options
@ -78,6 +78,56 @@ aceUno32Mb.build.variant=elbear_ace_uno
aceUno32Mb.build.extra_flags= aceUno32Mb.build.extra_flags=
aceUno32Mb.build.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 #####################
start-mik32-v1.name=START-MIK32-V1 start-mik32-v1.name=START-MIK32-V1

View 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

View File

@ -45,7 +45,7 @@ static void Timer16_Init(uint8_t prescaler)
htimer16_1.Trigger.TimeOut = TIMER16_TIMEOUT_DISABLE; htimer16_1.Trigger.TimeOut = TIMER16_TIMEOUT_DISABLE;
htimer16_1.Filter.ExternalClock = TIMER16_FILTER_NONE; htimer16_1.Filter.ExternalClock = TIMER16_FILTER_NONE;
htimer16_1.Filter.Trigger = 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.Waveform.Polarity = TIMER16_WAVEFORM_POLARITY_NONINVERTED;
htimer16_1.EncoderMode = TIMER16_ENCODER_DISABLE; htimer16_1.EncoderMode = TIMER16_ENCODER_DISABLE;
HAL_Timer16_Init(&htimer16_1); HAL_Timer16_Init(&htimer16_1);

View File

@ -6,6 +6,9 @@
#include "WInterrupts.h" #include "WInterrupts.h"
#include "wiring_LL.h" #include "wiring_LL.h"
// interrupts are enabled by default after setup()
static bool intIsEnabled = true;
typedef void (*voidFuncPtr)(void); typedef void (*voidFuncPtr)(void);
// empty irq handler // empty irq handler
@ -18,14 +21,20 @@ static void nothing(void)
void interrupts(void) void interrupts(void)
{ {
GLOBAL_IRQ_ENABLE(); GLOBAL_IRQ_ENABLE();
intIsEnabled = true;
} }
// disable global interrupts // disable global interrupts
void noInterrupts(void) void noInterrupts(void)
{ {
GLOBAL_IRQ_DISABLE(); GLOBAL_IRQ_DISABLE();
intIsEnabled = false;
} }
bool isInterruptsEnabled(void)
{
return intIsEnabled;
}
// we can provide no more than 8 interrupts on gpio at the same time // we can provide no more than 8 interrupts on gpio at the same time
static volatile voidFuncPtr intFunc[EXTERNAL_INTERRUPTS_QTY] = static volatile voidFuncPtr intFunc[EXTERNAL_INTERRUPTS_QTY] =
{ {

View File

@ -6,10 +6,12 @@ extern "C" {
#endif #endif
#include <stdint.h> #include <stdint.h>
#include "stdbool.h"
// enable/disable interrupts // enable/disable interrupts
void interrupts(void); void interrupts(void);
void noInterrupts(void); void noInterrupts(void);
bool isInterruptsEnabled(void);
// attach/detach interrupt to pin // attach/detach interrupt to pin
void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode); void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode);

View File

@ -25,8 +25,8 @@ extern "C" void SystemInit(void)
// called after setup() // called after setup()
void post_init(void) void post_init(void)
{ {
// enable global interrupts by default if(isInterruptsEnabled()) // if user has called noInterrupts() in setup(), this value is false
interrupts(); interrupts(); // enable global interrupts
} }
// --------------------- other --------------------- // // --------------------- other --------------------- //

View File

@ -144,8 +144,8 @@ typedef enum __HAL_Timer16_EncoderTypeDef
*/ */
typedef enum __HAL_Timer16_WaveformGenTypeDef typedef enum __HAL_Timer16_WaveformGenTypeDef
{ {
TIMER16_WAVEFORM_GENERATION_ENABLE = 0, /**< Выключить генерацию волновой формы. */ TIMER16_WAVEFORM_GENERATION_ENABLE = 0, /**< Включить генерацию волновой формы. */
TIMER16_WAVEFORM_GENERATION_DISABLE = 1 /**< Включить генерацию волновой формы. */ TIMER16_WAVEFORM_GENERATION_DISABLE = 1 /**< Выключить генерацию волновой формы. */
} HAL_Timer16_WaveformGenTypeDef; } HAL_Timer16_WaveformGenTypeDef;
/** /**

View File

@ -105,7 +105,7 @@ typedef enum __HAL_TSENS_ClockTypeDef
/** /**
* @brief Определение структуры TSENS Handle. * @brief Определение структуры TSENS Handle.
*/ */
typedef struct __SPI_HandleTypeDef typedef struct __TSENS_HandleTypeDef
{ {
ANALOG_REG_TypeDef *Instance; /**< Адрес регистров блока управления аналоговой подсистемой. */ ANALOG_REG_TypeDef *Instance; /**< Адрес регистров блока управления аналоговой подсистемой. */
@ -119,7 +119,7 @@ typedef struct __SPI_HandleTypeDef
/** /**
* @brief Возвращаемая структура для функции @ref HAL_TSENS_SingleStart. * @brief Возвращаемая структура для функции @ref HAL_TSENS_SingleStart.
*/ */
typedef struct __WDT_ClockTypeDef typedef struct __TSENS_ValueTypeDef
{ {
HAL_StatusTypeDef statusHAL; /**< Статус HAL. */ HAL_StatusTypeDef statusHAL; /**< Статус HAL. */

View File

@ -105,7 +105,7 @@ typedef struct __WDT_ClockTypeDef
} 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_Init(WDT_HandleTypeDef *hwdt, uint32_t timeout);
HAL_StatusTypeDef HAL_WDT_Refresh(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); HAL_StatusTypeDef HAL_WDT_Start(WDT_HandleTypeDef *hwdt, uint32_t timeout);

View File

@ -3,14 +3,56 @@
uint16_t TimeOut = 20; uint16_t TimeOut = 20;
uint16_t WDT_prescale[] = {1, 2, 4, 16, 64, 256, 1024, 4096}; 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. * @brief Инициализация WDT MSP.
* @param hwdt указатель на структуру WDT_HandleTypeDef, которая содержит * @param hwdt указатель на структуру WDT_HandleTypeDef, которая содержит
* информацию о конфигурации для модуля WDT. * информацию о конфигурации для модуля 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(); __HAL_PCC_WDT_CLK_ENABLE();
} }
@ -82,7 +124,7 @@ HAL_StatusTypeDef HAL_WDT_Init(WDT_HandleTypeDef *hwdt, uint32_t timeout)
return HAL_ERROR; return HAL_ERROR;
} }
HAL_RTC_MspInit(hwdt); HAL_WDT_MspInit(hwdt);
if (HAL_WDT_Stop(hwdt, timeout) != HAL_OK) 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); uint32_t conValue = (wdtClock.divIndex << WDT_CON_PRESCALE_S) | WDT_CON_PRELOAD(wdtClock.tick);
hwdt->Instance->KEY = WDT_KEY_UNLOCK; HAL_WDT_Write_Word_To_CON(hwdt, conValue);
hwdt->Instance->CON = conValue;
return HAL_OK; 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) HAL_StatusTypeDef HAL_WDT_Refresh(WDT_HandleTypeDef *hwdt, uint32_t timeout)
{ {
hwdt->Instance->KEY = WDT_KEY_UNLOCK; HAL_WDT_Write_Byte_To_KEY(hwdt, WDT_KEY_START);
hwdt->Instance->KEY = WDT_KEY_START;
while (timeout--) 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) HAL_StatusTypeDef HAL_WDT_Start(WDT_HandleTypeDef *hwdt, uint32_t timeout)
{ {
hwdt->Instance->KEY = WDT_KEY_UNLOCK; HAL_WDT_Write_Byte_To_KEY(hwdt, WDT_KEY_START);
hwdt->Instance->KEY = WDT_KEY_START;
while (timeout--) 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) HAL_StatusTypeDef HAL_WDT_Stop(WDT_HandleTypeDef *hwdt, uint32_t timeout)
{ {
hwdt->Instance->KEY = WDT_KEY_UNLOCK; HAL_WDT_Write_Byte_To_KEY(hwdt, WDT_KEY_STOP);
hwdt->Instance->KEY = WDT_KEY_STOP;
while (timeout--) 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) 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); 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; HAL_WDT_Write_Word_To_CON(hwdt, conValue);
hwdt->Instance->CON = 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) 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); uint32_t conValue = (hwdt->Instance->CON & (~WDT_CON_PRELOAD_M)) | WDT_CON_PRELOAD(preload);
hwdt->Instance->KEY = WDT_KEY_UNLOCK; HAL_WDT_Write_Word_To_CON(hwdt, conValue);
hwdt->Instance->CON = conValue;
} }

View File

@ -5,7 +5,7 @@
extern void serial_interrupt_handler(uint8_t uartNumInt); extern void serial_interrupt_handler(uint8_t uartNumInt);
extern void gpio_interrupt_handler(void); extern void gpio_interrupt_handler(void);
extern void tone_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 // 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()) if (EPIC_CHECK_UART_1())
serial_interrupt_handler(1); serial_interrupt_handler(1);
// i2c interrupt // i2c0 interrupt
if (EPIC_CHECK_I2C_0())
wire_interrupt_handler(0);
if (EPIC_CHECK_I2C_1()) if (EPIC_CHECK_I2C_1())
wire_interrupt_handler(); wire_interrupt_handler(1);
// reset all interrupts // reset all interrupts
EPIC_CLEAR_ALL(); EPIC_CLEAR_ALL();

View File

@ -73,6 +73,7 @@ uint32_t analogRead(uint32_t PinNumber)
// extra least significant bits read from the ADC are discarded // extra least significant bits read from the ADC are discarded
value = (value >> (MCU_ADC_RESOLUTION - currentResolution)); value = (value >> (MCU_ADC_RESOLUTION - currentResolution));
} }
additionalPinsDeinit(PinNumber);
} }
else else
ErrorMsgHandler("analogRead(): invalid analog pin number"); ErrorMsgHandler("analogRead(): invalid analog pin number");

View File

@ -4,11 +4,24 @@
![Pinout](pinout.PNG) ![Pinout](pinout.PNG)
### Цифровые выводы ### Цифровые выводы
На плате Elbear Ace-Uno доступны встроенные светодиод и кнопка. Для их использования необходимо воспользоваться макросами `LED_BUILTIN` и `BTN_BUILTIN`, передавая их в качестве аргументов функции вместо номера цифрового вывода. Макросу `LED_BUILTIN` соответствует номер вывода D22, а макросу `BTN_BUILTIN` - D23. На плате 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. Цифровой вывод 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| |D5|3|
|D8|4| |D8|4|
|D9|5| |D9|5|
|`BTN_BUILTIN`|6| |A1|6|
|`BTN_BUILTIN`|7|
При использовании аналогового вывода A1 для работы с прерываниями необходимо предварительно перевести вывод в режим цифрового. Для этого нужно перевести DIP-переключатель номер 2 в положение ON.
### Serial ### Serial
Интерфейс UART0 доступен на выводах D0, D1, для работы с ним используется экземпляр класса под названием `Serial`. Интерфейс UART0 доступен на выводах D0, D1, для работы с ним используется экземпляр класса под названием `Serial`.
Интерфейс UART1 доступен на выводах D7, D8, используемый экземпляр класса - `Serial1`. Интерфейс UART1 доступен на выводах D7, D8, используемый экземпляр класса - `Serial1`.
### SPI
Интерфейс SPI1 доступен на выводах D11, D12, D13. Для работы с ним используется экземпляр класса под названием `SPI`.
Интерфейс SPI0 доступен на выводах D3, D5, D6. Используемый экземпляр класса - `SPI1`.

View File

@ -56,4 +56,9 @@
Интерфейс UART0 доступен на выводах P0_5, P0_6, для работы с ним используется экземпляр класса под названием `Serial`. Интерфейс UART0 доступен на выводах P0_5, P0_6, для работы с ним используется экземпляр класса под названием `Serial`.
Интерфейс UART1 доступен на выводах P1_8, P1_9, используемый экземпляр класса - `Serial1`. Интерфейс UART1 доступен на выводах P1_8, P1_9, используемый экземпляр класса - `Serial1`.
USB-UART преобразователь, установленный на плате, поддерживает стандартные скорости UART до 57600 бод. Нестандартные скорости должны быть кратны USB-UART преобразователь, установленный на плате, поддерживает стандартные скорости UART до 57600 бод. Нестандартные скорости должны быть кратны
12*32=384, например, 240000 бод, 768000 бод. 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 KiB

BIN
docs/elsomikSE_pinout.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 175 KiB

View File

@ -0,0 +1,90 @@
# Elsomik
Особенности работы с платой Elsomik в среде программирования ArduinoIDE.
### Функциональное назначение выводов для плат Elsomik OEM и Elsomik SE
![elsomikOEM_pinout.png](elsomikOEM_pinout.png)
![elsomikSE_pinout.png](elsomikSE_pinout.png)
|Номер вывода|Доступные функции|Номер вывода|Доступные функции|
|---------|---------|---------|---------|
|P0_0|PWM, MISO0|P1_0|PWM, MISO1|
|P0_1|PWM, MOSI0|P1_1|PWM, MOSI1|
|P0_2|PWM, SCLK0, ADC2|P1_2|PWM, SCLK1|
|P0_3|PWM, NSS0|P1_3|PWM, NSS1|
|P0_4|ADC3|P1_4|INT1|
|P0_5|RX0|P1_5|ADC0, INT2|
|P0_6|TX0|P1_6|INT3|
|P0_7|ADC4|P1_7|ADC1|
|P0_8|INT0|P1_8|RX1|
|P0_9|SDA0, ADC5|P1_9|TX1, INT4|
|P0_10|SCL0|P1_10|INT5|
|P0_11|TDI, ADC6|P1_11|REF|
|P0_12|TCK|P1_12|SDA1|
|P0_13|TMS, ADC7|P1_13|SCL1|
|P0_14|TRST|P1_14|-|
|P0_15|TDO|P1_15|INT6|
|P2_6|-|P2_7|INT7|
### Загрузка скетчей
На плате отсутствуют встроенные преобразователи, позволяющие загружать скетчи по USB через COM-порт, однако каждая плата поставляется с предварительно записанным начальным загрузчиком. Для записи скетчей через USB потребуется использование внешнего USB-UART преобразователя, подключаемого к выводам платы P0_5 (RX0) и P0_6 (TX0), которые соответствуют интерфейсу UART0.
Перед загрузкой скетча необходимо кратковременно ввести контроллер в состояние RESET. Если используется USB-UART преобразователь с выведенным сигналом DTR, необходимо соединить DTR с выводом RST на плате через керамический конденсатор емкостью от 0,47 мкФ до 2,2 мкФ. В случае отсутствия сигнала DTR, необходимо вручную соединить вывод RST платы с землей и отпустить его непосредственно перед началом записи скетча.
### Цифровые выводы
Выводы на плате Elsomik пронумерованы в соответствии с их принадлежностью к определенному GPIO-порту и конкретному пину внутри порта. Чтобы использовать цифровой вывод, необходимо передать в функцию номер порта и номер пина в формате `P0_1`, где "0" — это номер порта, а "1" — номер пина внутри порта. Например, для инициализации вывода 5 порта 1 на выход необходимо вызвать функцию `pinMode(P1_5, OUTPUT)`.
Для использования доступны следующие выводы: `P0_0 ... P0_15, P1_0 ... P1_15, P2_6, P2_7`. Выводы `P0_11 ... P0_15` на плате обозначены иначе, ниже представлена таблица соответствия:
|Обозначение на плате|Номер вывода|
|---------|---------|
|TDI|P0_11|
|TCK|P0_12|
|TMS|P0_13|
|TRST|P0_14|
|TDO|P0_15|
### АЦП
На плате доступно 8 выводов, которые можно использовать в качестве каналов АЦП. Для работы с ними в функцию `analogRead()` необходимо передать номер канала или номер соответствующего цифрового вывода. Доступные каналы и их соответствие номерам выводов платы:
|Цифровой вывод|Номер канала АЦП|
|---------|---------|
|P1_5|A0|
|P1_7|A1|
|P0_2|A2|
|P0_4|A3|
|P0_7|A4|
|P0_9|A5|
|P0_11|A6|
|P0_13|A7|
#### ШИМ
На плате Elsomik в ArduinoIDE доступно 8 выводов для формирования ШИМ-сигнала. Генерация сигнала осуществляется с помощью 32-битного таймера. Выводы, подключенные к одному и тому же таймеру, выдают ШИМ-сигнал одинаковой частоты.
Доступные выводы:
|Цифровой вывод|Используемый таймер|
|---------|---------|
|P0_0|таймер 1|
|P0_1|таймер 1|
|P0_2|таймер 1|
|P0_3|таймер 1|
|P1_0|таймер 2|
|P1_1|таймер 2|
|P1_2|таймер 2|
|P1_3|таймер 2|
При использовании SPI формирование ШИМ сигнала на выводах P1_0 ... P1_3 недоступно.
### Прерывания
На плате Elsomik доступно 8 прерываний, настраиваемых функцией `void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)`:
|Цифровой вывод|Номер прерывания|
|---------|---------|
|P0_8|0|
|P1_4|1|
|P1_5|2|
|P1_6|3|
|P1_9|4|
|P1_10|5|
|P1_15|6|
|P2_7|7|
### Serial
Интерфейс UART0 доступен на выводах P0_5, P0_6, для работы с ним используется экземпляр класса под названием `Serial`.
Интерфейс UART1 доступен на выводах P1_8, P1_9, используемый экземпляр класса - `Serial1`.
### SPI
Интерфейс SPI1 доступен на выводах P1_0, P1_1, P1_2. Для работы с ним используется экземпляр класса под названием `SPI`.
Интерфейс SPI0 доступен на выводах P0_0, P0_1, P0_2. Используемый экземпляр класса - `SPI1`.
Для корректной работы аппаратного SPI микроконтроллер так же использует выводы P1_3 при работе SPI1 и P0_3 при работе SPI0. В связи с этим данные выводы недоступны для использования при работе соответствующего SPI.

48
docs/nano_description.md Normal file
View File

@ -0,0 +1,48 @@
# Elbear Nano
Особенности работы с платами Elbear Nano в среде программирования ArduinoIDE.
### Функциональное назначение выводов
![Pinout_nano](Pinout_nano.PNG)
### Цифровые выводы
На плате Elbear Nano доступен встроенный светодиод. Для его использования необходимо воспользоваться макросом `LED_BUILTIN`, передавая его в качестве аргумента функции вместо номера цифрового вывода. Макросу соответствует номер вывода D22.
### Аналоговые выводы
Выводы A0...A7 на плате могут использоваться как в аналоговом, так и в цифровом режиме.
Для использования вывода в качестве аналогового необходимо перевести соответствующий DIP-переключатель, расположенный рядом с аналоговыми выводами, в положение OFF. В этом режиме внешнее напряжение, подаваемое на вывод, будет понижаться резистивным делителем перед подачей на микроконтроллер.
Для использования вывода в качестве цифрового нужно перевести переключатель в положение ON. В этом случае напряжение с вывода платы передается на микроконтроллер без изменений.
Выводы А4...А7 используют один и тот же канал АЦП, поэтому не могут использоваться одновременно.
Таблица соответствия выводов платы и номера DIP-переключателя представлена ниже. Переключатель 5 относится сразу к четырем аналоговым выводам - А4...А7.
|Вывод|Номер переключателя|
|---------|---------|
|А0|1|
|А1|2|
|А2|3|
|А3|4|
|А4|5|
|А5|5|
|А6|5|
|А7|5|
#### ШИМ
На плате Elbear Nano доступно 8 выводов для формирования ШИМ-сигнала: D3, D5, D6, D9...D13. Генерация сигнала осуществляется с помощью 32-битного таймера. Выводы D3, D5, D6, D9 подключены к таймеру 1, выводы D10...D13 подключены к таймеру 2. Выводы, подключенные к одному и тому же таймеру, выдают ШИМ-сигнал одинаковой частоты.
Цифровой вывод D10 не может быть использован для генерации ШИМ, если одновременно активен интерфейс SPI. Это ограничение связано с особенностями работы микроконтроллера. Ограничение не распространяется на использование D10 в качестве цифрового вывода при активном SPI.
### Прерывания
На плате Elbear Nano доступно 8 прерываний, настраиваемых функцией `void attachInterrupt(uint8_t interruptNum, void (*userFunc)(void), int mode)`:
|Цифровой вывод|Номер прерывания|
|---------|---------|
|D2|0|
|D3|1|
|D4|2|
|D5|3|
|D6|4|
|D8|5|
|D9|6|
|A1|7|
При использовании аналогового вывода A1 для работы с прерываниями необходимо предварительно перевести вывод в режим цифрового. Для этого нужно перевести DIP-переключатель номер 2 в положение ON.
### Serial
Интерфейс UART0 доступен на выводах D0, D1, для работы с ним используется экземпляр класса под названием `Serial`.
Интерфейс UART1 доступен на выводах D7, D8, используемый экземпляр класса - `Serial1`.
### SPI
Интерфейс SPI1 доступен на выводах D11, D12, D13. Для работы с ним используется экземпляр класса под названием `SPI`.
Интерфейс SPI0 доступен на выводах D3, D5, D6. Используемый экземпляр класса - `SPI1`.

View File

@ -2076,11 +2076,14 @@ extern "C" void __attribute__((noinline, section(".ram_text"), optimize("O3")))
# if defined(SEND_PWM_BY_TIMER) # if defined(SEND_PWM_BY_TIMER)
#include "pins_arduino.h" #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 #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 #define IR_SEND_PIN 3
# endif // START_MIK32_V1 # else
#error "Unknown MIK32V2 board!"
# endif
static TIMER32_HandleTypeDef ir_sender_htimer; static TIMER32_HandleTypeDef ir_sender_htimer;
static TIMER32_CHANNEL_HandleTypeDef ir_sender_htimer_channel; static TIMER32_CHANNEL_HandleTypeDef ir_sender_htimer_channel;

View File

@ -5,7 +5,7 @@
#include "SPI.h" #include "SPI.h"
#define CS_PIN 9 #define CS_PIN 9 // P1_8
// address of register to read and write // address of register to read and write
const int reg_to_test = 0x03; const int reg_to_test = 0x03;
@ -42,7 +42,7 @@ void ADC_write_register(uint8_t registerAddress, uint8_t registerValueToWrite)
// ----------------------------------------- // // ----------------------------------------- //
void setup() void setup()
{ {
Serial.begin(115200); Serial.begin(9600);
Serial.println("Start spi test"); Serial.println("Start spi test");
// init chip select pin // init chip select pin

View File

@ -1,22 +1,16 @@
#include "SPI.h" #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); static uint8_t reverse_bits(uint8_t byte);
// ------------------------------------------------------------------ // void SPIClass::updateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)
void SPISettings::spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode)
{ {
// update config only if something has changed // update config only if something has changed
if ((currentSpeed != speedMaximum) || (currentDataOrder != dataOrder) || if ((_speed != speedMaximum) || (_dataOrder != dataOrder) || (_dataMode != dataMode))
(currentDataMode != dataMode))
{ {
// Find the fastest clock that is less than or equal to the // Find the fastest clock that is less than or equal to the
// given clock rate. If nothing is slow enough - use the slowest. // 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) // if break didn't call in cycle, it will be the greatest divRegVal (and divider)
// update params in struct // update params in struct
hspi.Init.CLKPhase = dataMode & 0b00000001; _hspi.Init.CLKPhase = dataMode & 0b00000001;
hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1; _hspi.Init.CLKPolarity = (dataMode & 0b00000010)>>1;
hspi.Init.BaudRateDiv = divRegVal; _hspi.Init.BaudRateDiv = divRegVal;
currentSpeed = speedMaximum; _speed = speedMaximum;
currentDataOrder = dataOrder; _dataOrder = dataOrder;
currentDataMode = dataMode; _dataMode = dataMode;
newConfig = true; _newConfig = true;
} }
} }
// ------------------------------------------------------------------ //
SPIClass SPI;
bool SPIClass::spiInUse = false;
uint8_t SPIClass::interruptMode = 0;
uint8_t SPIClass::interruptMask = 0;
void SPIClass::begin() void SPIClass::begin()
{ {
spi_onBegin(); spi_onBegin(_spiNum);
// set constant parameters in spi struct // set constant parameters in spi struct
hspi.Instance = SPI_1; if (_spiNum == 0)
hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode used _hspi.Instance = SPI_0;
hspi.Init.ThresholdTX = 4; else
hspi.Init.Decoder = SPI_DECODER_NONE; _hspi.Instance = SPI_1;
hspi.Init.ManualCS = SPI_MANUALCS_ON; _hspi.Init.SPI_Mode = HAL_SPI_MODE_MASTER; // only master mode used
hspi.Init.ChipSelect = SPI_CS_NONE; _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() // adjustable parameters default values as in SPISettings()
hspi.Init.BaudRateDiv = SPI_CLOCK_DIV8; _hspi.Init.BaudRateDiv = SPI_CLOCK_DIV8;
hspi.Init.CLKPhase = SPI_MODE0 & 0b00000001; _hspi.Init.CLKPhase = SPI_MODE0 & 0b00000001;
hspi.Init.CLKPolarity = (SPI_MODE0 & 0b00000010)>>1; _hspi.Init.CLKPolarity = (SPI_MODE0 & 0b00000010)>>1;
spiInUse = true; _spiInUse = true;
} }
void SPIClass::end() void SPIClass::end()
{ {
if (spiInUse && isInited) if (_spiInUse && _isInited)
{ {
// turn off spi // turn off spi
HAL_SPI_Disable(&hspi); HAL_SPI_Disable(&_hspi);
// deinit spi gpio pins // 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_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); HAL_GPIO_MODE_GPIO_INPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
} }
spi_onEnd(); spi_onEnd(_spiNum);
spiInUse = false; _spiInUse = false;
isInited = false; _isInited = false;
interruptMode = 0; _interruptMode = 0;
interruptMask = 0; _interruptMask = 0;
} }
} }
@ -98,9 +93,9 @@ void SPIClass::usingInterrupt(uint8_t interruptNumber)
if(interruptNumber < EXTERNAL_INTERRUPTS_QTY) if(interruptNumber < EXTERNAL_INTERRUPTS_QTY)
{ {
noInterrupts(); // prevent transactionBegin noInterrupts(); // prevent transactionBegin
interruptMask |= (1 << interruptNumber); // add new interrupt to mask _interruptMask |= (1 << interruptNumber); // add new interrupt to mask
if (!interruptMode) if (!_interruptMode)
interruptMode = 1; _interruptMode = 1;
interrupts(); interrupts();
} }
} }
@ -110,34 +105,40 @@ void SPIClass::notUsingInterrupt(uint8_t interruptNumber)
if(interruptNumber < EXTERNAL_INTERRUPTS_QTY) if(interruptNumber < EXTERNAL_INTERRUPTS_QTY)
{ {
noInterrupts(); // prevent transactionBegin noInterrupts(); // prevent transactionBegin
interruptMask &= ~(1<<interruptNumber); // delete interrupt from mask _interruptMask &= ~(1<<interruptNumber); // delete interrupt from mask
if (!interruptMask) if (!_interruptMask)
interruptMode = 0; _interruptMode = 0;
interrupts(); interrupts();
} }
} }
void SPIClass::beginTransaction(SPISettings settings) void SPIClass::beginTransaction(SPISettings settings)
{ {
// update SPI settings
updateSettings(settings.speedMaximum, settings.newDataOrder, settings.newDataMode);
// disable interrupts in use if necessary // disable interrupts in use if necessary
if (spiInUse && (interruptMode > 0)) if (_spiInUse && (_interruptMode > 0))
{ {
for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) 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 // disable every interrupt by it's number
disableInterrupt(i); disableInterrupt(i);
} }
} }
// initialize spi bus or update config // initialize spi bus or update config if needed
if(spiInUse && ((!isInited) || newConfig)) if(_spiInUse && ((!_isInited) || _newConfig))
{ {
// initialize spi with given settings // initialize spi with given settings
if (HAL_SPI_Init(&hspi) != HAL_OK) if (HAL_SPI_Init(&_hspi) != HAL_OK)
ErrorMsgHandler("SPI.beginTransaction(): initialization error"); ErrorMsgHandler("SPI.beginTransaction(): initialization error");
else else
isInited = true; {
_isInited = true;
_newConfig = false;
}
} }
} }
@ -145,19 +146,19 @@ uint8_t SPIClass::transfer(uint8_t data)
{ {
uint8_t rxByte = 0; uint8_t rxByte = 0;
if (isInited) if (_isInited)
{ {
// reverse bits if LSB mode needed // reverse bits if LSB mode needed
if (currentDataOrder == LSBFIRST) if (_dataOrder == LSBFIRST)
data = reverse_bits(data); data = reverse_bits(data);
// send and recieve 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) if (SPI_Status != HAL_OK)
HAL_SPI_ClearError(&hspi); HAL_SPI_ClearError(&_hspi);
// reverse bits again if LSB mode needed // reverse bits again if LSB mode needed
if (currentDataOrder == LSBFIRST) if (_dataOrder == LSBFIRST)
rxByte = reverse_bits(rxByte); rxByte = reverse_bits(rxByte);
} }
return rxByte; return rxByte;
@ -167,10 +168,10 @@ uint16_t SPIClass::transfer16(uint16_t data)
{ {
uint8_t buf[2]; uint8_t buf[2];
uint16_t rxVal = 0; uint16_t rxVal = 0;
if (isInited) if (_isInited)
{ {
// prepare data for send // prepare data for send
if (currentDataOrder == LSBFIRST) if (_dataOrder == LSBFIRST)
{ {
// least significant byte is forward and reverse bits inside each byte // least significant byte is forward and reverse bits inside each byte
buf[0] = reverse_bits(data&0xFF); buf[0] = reverse_bits(data&0xFF);
@ -184,12 +185,12 @@ uint16_t SPIClass::transfer16(uint16_t data)
} }
// send and recieve 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) if (SPI_Status != HAL_OK)
HAL_SPI_ClearError(&hspi); HAL_SPI_ClearError(&_hspi);
// process the received data // process the received data
if (currentDataOrder == LSBFIRST) if (_dataOrder == LSBFIRST)
// reverse bits for LSB mode // reverse bits for LSB mode
rxVal = ( ((uint16_t)reverse_bits(buf[1]) ) << 8) | reverse_bits(buf[0]); rxVal = ( ((uint16_t)reverse_bits(buf[1]) ) << 8) | reverse_bits(buf[0]);
else else
@ -203,24 +204,24 @@ void SPIClass::transfer(void *buf, size_t count)
if (count == 0) if (count == 0)
return; return;
if (isInited) if (_isInited)
{ {
uint8_t *p = (uint8_t *)buf; uint8_t *p = (uint8_t *)buf;
// reverse bits in buffer if LSB mode needed // reverse bits in buffer if LSB mode needed
if (currentDataOrder == LSBFIRST) if (_dataOrder == LSBFIRST)
{ {
for (uint32_t i = 0; i < count; i++) for (uint32_t i = 0; i < count; i++)
*(p+i) = reverse_bits(*(p+i)); *(p+i) = reverse_bits(*(p+i));
} }
// send and recieve data using the same buffer // 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) if (SPI_Status != HAL_OK)
HAL_SPI_ClearError(&hspi); HAL_SPI_ClearError(&_hspi);
// reverse bits if LSB mode needed // reverse bits if LSB mode needed
if (currentDataOrder == LSBFIRST) if (_dataOrder == LSBFIRST)
{ {
p = (uint8_t *)buf; // return to buf beginning p = (uint8_t *)buf; // return to buf beginning
for (uint32_t i = 0; i < count; i++) for (uint32_t i = 0; i < count; i++)
@ -232,11 +233,11 @@ void SPIClass::transfer(void *buf, size_t count)
void SPIClass::endTransaction(void) void SPIClass::endTransaction(void)
{ {
// enable interrupts in use // enable interrupts in use
if (spiInUse && (interruptMode > 0)) if (_spiInUse && (_interruptMode > 0))
{ {
for (uint8_t i = 0; i < EXTERNAL_INTERRUPTS_QTY; i++) 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 // enable every interrupt in use by it's number
enableInterrupt(i); enableInterrupt(i);
} }
@ -246,20 +247,20 @@ void SPIClass::endTransaction(void)
// ------------------------------------ // // ------------------------------------ //
void SPIClass::setBitOrder(uint8_t bitOrder) void SPIClass::setBitOrder(uint8_t bitOrder)
{ {
if (spiInUse) if (_spiInUse)
currentDataOrder = bitOrder; _dataOrder = bitOrder;
else else
ErrorMsgHandler("SPI.setBitOrder():SPI.begin() need to be called first"); ErrorMsgHandler("SPI.setBitOrder():SPI.begin() need to be called first");
} }
void SPIClass::setDataMode(uint8_t dataMode) void SPIClass::setDataMode(uint8_t dataMode)
{ {
if (spiInUse) if (_spiInUse)
{ {
hspi.Init.CLKPhase = (dataMode&0b00000001); _hspi.Init.CLKPhase = (dataMode&0b00000001);
hspi.Init.CLKPolarity = (dataMode&0b00000010)>>1; _hspi.Init.CLKPolarity = (dataMode&0b00000010)>>1;
HAL_SPI_Set_Clock_Mode(&hspi); HAL_SPI_Set_Clock_Mode(&_hspi);
currentDataMode = dataMode; _dataMode = dataMode;
} }
else else
ErrorMsgHandler("SPI.setDataMode():SPI.begin() need to be called first"); 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) void SPIClass::setClockDivider(uint8_t clockDiv)
{ {
if (spiInUse) if (_spiInUse)
{ {
// if divider is valid // if divider is valid
if ((clockDiv == SPI_CLOCK_DIV2) || (clockDiv == SPI_CLOCK_DIV4) || 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_DIV32) || (clockDiv == SPI_CLOCK_DIV64) ||
(clockDiv == SPI_CLOCK_DIV128) || (clockDiv == SPI_CLOCK_DIV256)) (clockDiv == SPI_CLOCK_DIV128) || (clockDiv == SPI_CLOCK_DIV256))
{ {
hspi.Init.BaudRateDiv = clockDiv; _hspi.Init.BaudRateDiv = clockDiv;
currentSpeed = F_CPU >> (clockDiv+1); _speed = F_CPU >> (clockDiv+1);
HAL_SPI_Set_Clock_Divider(&hspi); HAL_SPI_Set_Clock_Divider(&_hspi);
} }
else else
ErrorMsgHandler("SPI.setClockDivider(): Invalid clock devider"); ErrorMsgHandler("SPI.setClockDivider(): Invalid clock devider");

View File

@ -15,6 +15,7 @@
#define _SPI_H_INCLUDED #define _SPI_H_INCLUDED
#include <Arduino.h> #include <Arduino.h>
#include "mik32_hal_spi.h"
// SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(), // SPI_HAS_TRANSACTION means SPI has beginTransaction(), endTransaction(),
// usingInterrupt(), and SPISetting(clock, bitOrder, dataMode) // usingInterrupt(), and SPISetting(clock, bitOrder, dataMode)
@ -32,7 +33,6 @@
#define SPI_DEFAULT_SPEED 4000000 #define SPI_DEFAULT_SPEED 4000000
// dividers for setClockDivider() // dividers for setClockDivider()
#define SPI_CLOCK_DIV2 0x00 // 16 MHz #define SPI_CLOCK_DIV2 0x00 // 16 MHz
#define SPI_CLOCK_DIV4 0x01 // 8 MHz #define SPI_CLOCK_DIV4 0x01 // 8 MHz
@ -49,45 +49,49 @@
#define SPI_MODE2 0b10 #define SPI_MODE2 0b10
#define SPI_MODE3 0b11 #define SPI_MODE3 0b11
class SPISettings {
class SPISettings
{
public: public:
SPISettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode) uint32_t speedMaximum;
{ uint8_t newDataOrder;
spiUpdateSettings(speedMaximum, dataOrder, dataMode); uint8_t newDataMode;
} // save values from arguments
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t mode)
SPISettings() : speedMaximum(clock), newDataOrder(bitOrder), newDataMode(mode) {}
{
spiUpdateSettings(SPI_DEFAULT_SPEED, MSBFIRST, SPI_MODE0);
}
private:
void spiUpdateSettings(uint32_t speedMaximum, uint8_t dataOrder, uint8_t dataMode);
friend class SPIClass;
}; };
class SPIClass class SPIClass
{ {
private: private:
static bool spiInUse; uint8_t _spiNum;
static uint8_t interruptMode; // 0=none, 1=mask SPI_HandleTypeDef _hspi = {0};
static uint8_t interruptMask; // which interrupts to mask 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: 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 // Initialize the SPI library
static void begin(); void begin();
// If SPI is used from within an interrupt, this function registers // If SPI is used from within an interrupt, this function registers
// that interrupt with the SPI library, so beginTransaction() can // that interrupt with the SPI library, so beginTransaction() can
// prevent conflicts. The input interruptNumber is the number used // prevent conflicts. The input interruptNumber is the number used
// with attachInterrupt. // with attachInterrupt.
static void usingInterrupt(uint8_t interruptNumber); void usingInterrupt(uint8_t interruptNumber);
// And this does the opposite. // And this does the opposite.
static void notUsingInterrupt(uint8_t interruptNumber); void notUsingInterrupt(uint8_t interruptNumber);
// Note: the usingInterrupt and notUsingInterrupt functions should // Note: the usingInterrupt and notUsingInterrupt functions should
// not to be called from ISR context or inside a transaction. // not to be called from ISR context or inside a transaction.
// For details see: // For details see:
@ -109,7 +113,7 @@ public:
void endTransaction(void); void endTransaction(void);
// Disable the SPI bus // Disable the SPI bus
static void end(); void end();
// This function is deprecated. New applications should use // This function is deprecated. New applications should use
// beginTransaction() to configure SPI settings. // beginTransaction() to configure SPI settings.
@ -124,5 +128,8 @@ public:
}; };
extern SPIClass SPI; extern SPIClass SPI;
#if SPI_COMMON_QTY > 1
extern SPIClass SPI1;
#endif
#endif #endif

View File

@ -205,6 +205,8 @@ void SoftwareSerial::setRX(uint8_t rx)
PIN_SET_PAD_CONFIG(PORT_0_PUPD, pinNumber, HAL_GPIO_PULL_UP); PIN_SET_PAD_CONFIG(PORT_0_PUPD, pinNumber, HAL_GPIO_PULL_UP);
else if (((GPIO_TypeDef*)_receivePortRegister) == GPIO_1) else if (((GPIO_TypeDef*)_receivePortRegister) == GPIO_1)
PIN_SET_PAD_CONFIG(PORT_1_PUPD, pinNumber, HAL_GPIO_PULL_UP); 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()) // turn off int line for while (it turning on in attachInterrupt())
GPIO_IRQ_LINE_DISABLE(_int_maskLine); GPIO_IRQ_LINE_DISABLE(_int_maskLine);

View File

@ -4,31 +4,9 @@ extern "C"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <inttypes.h> #include <inttypes.h>
#include "utility/twi.h"
} }
#include "Wire.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 --------------------------- // // --------------------------- Public Methods --------------------------- //
void TwoWire::begin(void) void TwoWire::begin(void)
{ {
@ -36,10 +14,7 @@ void TwoWire::begin(void)
rxBufferLength = 0; rxBufferLength = 0;
txBufferIndex = 0; txBufferIndex = 0;
txBufferLength = 0; txBufferLength = 0;
twi_init(slaveAddress); twi_init(&wireHandler, slaveAddress);
twi_attachSlaveTxEvent(onRequestService); // default callback must exist
twi_attachSlaveRxEvent(onReceiveService); // default callback must exist
} }
void TwoWire::begin(uint8_t address) void TwoWire::begin(uint8_t address)
@ -56,13 +31,13 @@ void TwoWire::begin(int address)
void TwoWire::end(void) void TwoWire::end(void)
{ {
flush(); // wait for transmission complete flush(); // wait for transmission complete
twi_deinit(); twi_deinit(&wireHandler);
slaveAddress = 0; slaveAddress = 0;
} }
void TwoWire::setClock(uint32_t clock) 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"); 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; quantity = BUFFER_LENGTH;
// perform blocking read into buffer // 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 // set rx buffer iterator vars
rxBufferIndex = 0; rxBufferIndex = 0;
@ -147,7 +122,7 @@ uint8_t TwoWire::endTransmission(uint8_t sendStop)
if (transmitting) if (transmitting)
{ {
// transmit buffer (blocking) // 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 // reset tx buffer iterator vars
txBufferIndex = 0; txBufferIndex = 0;
txBufferLength = 0; txBufferLength = 0;
@ -189,7 +164,7 @@ size_t TwoWire::write(uint8_t data)
else else
{ {
// in slave send mode - reply to master // 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; ret = 0;
} }
return ret; return ret;
@ -215,7 +190,7 @@ size_t TwoWire::write(const uint8_t *data, size_t quantity)
else else
{ {
// in slave send mode - reply to master // 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; ret = 0;
} }
return ret; return ret;
@ -309,10 +284,18 @@ void TwoWire::onRequest( void (*function)(void) )
} }
// С function for trap handler // С 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 ----------------------------- // // ----------------------------- Preinstantiate Objects ----------------------------- //
TwoWire Wire = TwoWire( ); TwoWire Wire = TwoWire(1);
#if I2C_COMMON_QTY>1
TwoWire Wire1 = TwoWire(0);
#endif

View File

@ -4,6 +4,10 @@
#include "Stream.h" #include "Stream.h"
#include "Arduino.h" #include "Arduino.h"
extern "C"
{
#include "utility/twi.h"
}
#define BUFFER_LENGTH 32 #define BUFFER_LENGTH 32
@ -13,23 +17,45 @@
class TwoWire : public Stream class TwoWire : public Stream
{ {
private: private:
static uint8_t rxBuffer[]; WireHandler_TypeDef wireHandler;
static uint8_t rxBufferIndex;
static uint8_t rxBufferLength;
static uint8_t txAddress; uint8_t rxBuffer[BUFFER_LENGTH];
static uint8_t txBuffer[]; uint8_t rxBufferIndex = 0;
static uint8_t txBufferIndex; uint8_t rxBufferLength = 0;
static uint8_t txBufferLength;
static uint8_t transmitting; uint8_t txAddress = 0; // 7 bits without shift
static uint8_t slaveAddress; uint8_t txBuffer[BUFFER_LENGTH];
static void (*user_onRequest)(void); uint8_t txBufferIndex = 0;
static void (*user_onReceive)(int numBytes); uint8_t txBufferLength = 0;
static void onRequestService(void);
static void onReceiveService(uint8_t* inBytes, int numBytes); 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: 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();
void begin(uint8_t); void begin(uint8_t);
void begin(int); void begin(int);
@ -65,5 +91,8 @@ class TwoWire : public Stream
}; };
extern TwoWire Wire; extern TwoWire Wire;
#if I2C_COMMON_QTY>1
extern TwoWire Wire1;
#endif
#endif #endif

View File

@ -2,162 +2,149 @@
#include <inttypes.h> #include <inttypes.h>
#include "Arduino.h" #include "Arduino.h"
#include "twi.h" #include "twi.h"
#include "mik32_hal_i2c.h"
#include "mik32_hal_irq.h" #include "mik32_hal_irq.h"
#define TIMEOUT_TICKS 1000000 #define TIMEOUT_TICKS 1000000
#define TWI_FREQ_DEF WIRE_FREQ_100K // default is 100 kHz #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 * Function twi_init
* Desc readys twi pins and sets twi bitrate * 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 * Output none
*/ */
uint8_t twi_init(uint8_t slaveAddress) uint8_t twi_init(WireHandler_TypeDef* handler, uint8_t slaveAddress)
{ {
// Common settings // Common settings
uint32_t EPICmask; uint32_t EPICmask;
#if I2C_NUM == 0 if (handler->i2c_num == 0)
hi2c.Instance = I2C_0; {
EPICmask = HAL_EPIC_I2C_0_MASK; handler->i2c_param.Instance = I2C_0;
#elif I2C_NUM == 1 EPICmask = HAL_EPIC_I2C_0_MASK;
hi2c.Instance = I2C_1; }
EPICmask = HAL_EPIC_I2C_1_MASK; else if (handler->i2c_num == 1)
#else {
#error "Unsupported I2C_NUM value in pins_arduino.h" handler->i2c_param.Instance = I2C_1;
#endif EPICmask = HAL_EPIC_I2C_1_MASK;
}
else
return I2C_ERROR;
hi2c.Init.DigitalFilter = I2C_DIGITALFILTER_2CLOCKCYCLES; handler->i2c_param.Init.DigitalFilter = I2C_DIGITALFILTER_2CLOCKCYCLES;
hi2c.Init.AnalogFilter = I2C_ANALOGFILTER_DISABLE; handler->i2c_param.Init.AnalogFilter = I2C_ANALOGFILTER_DISABLE;
if (slaveAddress == 0) // if there is no address - master mode if (slaveAddress == 0) // if there is no address - master mode
{ {
hi2c.Init.Mode = HAL_I2C_MODE_MASTER; handler->i2c_param.Init.Mode = HAL_I2C_MODE_MASTER;
hi2c.Init.AutoEnd = I2C_AUTOEND_ENABLE; handler->i2c_param.Init.AutoEnd = I2C_AUTOEND_ENABLE;
} }
else else
{ {
// 7-bit address without any additional bits // 7-bit address without any additional bits
hi2c.Init.Mode = HAL_I2C_MODE_SLAVE; handler->i2c_param.Init.Mode = HAL_I2C_MODE_SLAVE;
hi2c.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // stretch is used handler->i2c_param.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; // stretch is used
hi2c.Init.OwnAddress1 = slaveAddress; handler->i2c_param.Init.OwnAddress1 = slaveAddress;
} }
// set the frequency // set the frequency
if (hi2c.Init.Mode == HAL_I2C_MODE_MASTER) if (handler->i2c_param.Init.Mode == HAL_I2C_MODE_MASTER)
twi_setFrequency(CurrentFrequency, true); twi_setFrequency(handler, TWI_FREQ_DEF, true);
else 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; return I2C_ERROR;
// enable interrupts for slave mode // 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 // enable interrupts for addressing, byte reception and transfer completion
HAL_I2C_InterruptDisable(&hi2c, I2C_INTMASK); HAL_I2C_InterruptDisable(&(handler->i2c_param), I2C_INTMASK);
HAL_I2C_InterruptEnable(&hi2c, I2C_CR1_ADDRIE_M | I2C_CR1_RXIE_M | I2C_CR1_STOPIE_M); HAL_I2C_InterruptEnable(&(handler->i2c_param), I2C_CR1_ADDRIE_M | I2C_CR1_RXIE_M | I2C_CR1_STOPIE_M);
// enable interrupt from i2c // enable interrupt from i2c
HAL_EPIC_MaskLevelSet(EPICmask); HAL_EPIC_MaskLevelSet(EPICmask);
} }
twiIsOn = true; handler->isInited = true;
return I2C_OK; return I2C_OK;
} }
/* /*
* Function twi_deinit * Function twi_deinit
* Desc disables twi pins * Desc disables twi pins
* Input none * Input handler - pointer to wire common handler
* Output none * Output none
*/ */
void twi_deinit(void) void twi_deinit(WireHandler_TypeDef* handler)
{ {
uint32_t EPICmask; HAL_I2C_Deinit(&(handler->i2c_param));
#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);
// for slave mode disable interrupts from i2c // for slave mode disable interrupts from i2c
if (hi2c.Init.Mode == HAL_I2C_MODE_SLAVE) if (handler->i2c_param.Init.Mode == HAL_I2C_MODE_SLAVE)
HAL_EPIC_MaskLevelClear(EPICmask); {
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 * Function twi_setClock
* Desc sets twi bit rate * 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() * onInit = true only if function is called from twi_init()
* Output I2C_OK - frequency changed, I2C_ERROR - frequency didn't change * 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; uint8_t ret = I2C_OK;
// change the frequency only during or after bus initialization // 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 // 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 if (frequency == WIRE_FREQ_100K) // 100 kHz
{ {
hi2c.Clock.PRESC = 2; handler->i2c_param.Clock.PRESC = 2;
hi2c.Clock.SCLDEL = 8; handler->i2c_param.Clock.SCLDEL = 8;
hi2c.Clock.SDADEL = 2; handler->i2c_param.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 49; handler->i2c_param.Clock.SCLH = 49;
hi2c.Clock.SCLL = 49; handler->i2c_param.Clock.SCLL = 49;
CurrentFrequency = WIRE_FREQ_100K; // CurrentFrequency = WIRE_FREQ_100K;
} }
else if (frequency == WIRE_FREQ_400K) // 400 kHz else if (frequency == WIRE_FREQ_400K) // 400 kHz
{ {
hi2c.Clock.PRESC = 0; handler->i2c_param.Clock.PRESC = 0;
hi2c.Clock.SCLDEL = 3; handler->i2c_param.Clock.SCLDEL = 3;
hi2c.Clock.SDADEL = 2; handler->i2c_param.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 30; handler->i2c_param.Clock.SCLH = 30;
hi2c.Clock.SCLL = 30; handler->i2c_param.Clock.SCLL = 30;
CurrentFrequency = WIRE_FREQ_400K; // CurrentFrequency = WIRE_FREQ_400K;
} }
else if (frequency == WIRE_FREQ_1000K)// 1000 kHz else if (frequency == WIRE_FREQ_1000K)// 1000 kHz
{ {
hi2c.Clock.PRESC = 0; handler->i2c_param.Clock.PRESC = 0;
hi2c.Clock.SCLDEL = 1; handler->i2c_param.Clock.SCLDEL = 1;
hi2c.Clock.SDADEL = 2; handler->i2c_param.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 6; handler->i2c_param.Clock.SCLH = 6;
hi2c.Clock.SCLL = 6; handler->i2c_param.Clock.SCLL = 6;
CurrentFrequency = WIRE_FREQ_1000K; // CurrentFrequency = WIRE_FREQ_1000K;
} }
else if (frequency == 0) // slave mode else if (frequency == 0) // slave mode
{ {
hi2c.Clock.PRESC = 0; handler->i2c_param.Clock.PRESC = 0;
hi2c.Clock.SCLDEL = 0; handler->i2c_param.Clock.SCLDEL = 0;
hi2c.Clock.SDADEL = 2; handler->i2c_param.Clock.SDADEL = 2;
hi2c.Clock.SCLH = 0; handler->i2c_param.Clock.SCLH = 0;
hi2c.Clock.SCLL = 0; handler->i2c_param.Clock.SCLL = 0;
} }
else else
// frequency does not change // 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 // write the timings to the register if everything is OK
if (ret == I2C_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 //turn the interface back only if initialization has already passed
if (twiIsOn) if (handler->isInited)
HAL_I2C_Enable(&hi2c); HAL_I2C_Enable(&(handler->i2c_param));
} }
else else
ret = I2C_ERROR; ret = I2C_ERROR;
@ -181,26 +168,27 @@ uint8_t twi_setFrequency(uint32_t frequency, bool onInit)
* Function twi_masterReadFrom * Function twi_masterReadFrom
* Desc attempts to become twi bus master and read a * Desc attempts to become twi bus master and read a
* series of bytes from a device on the bus * 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 * data: pointer to byte array
* length: number of bytes to read into array * length: number of bytes to read into array
* sendStop: Boolean indicating whether to send a stop at the end * sendStop: Boolean indicating whether to send a stop at the end
* Output number of bytes read * 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; uint8_t ret = 0;
// if there are errors left from previous transactions, you need to restart // if there are errors left from previous transactions, you need to restart
// the interface for correct operation // the interface for correct operation
if (hi2c.ErrorCode != I2C_ERROR_NONE) if (hi2c->ErrorCode != I2C_ERROR_NONE)
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(hi2c);
if (sendStop) hi2c.Init.AutoEnd = 1; if (sendStop) hi2c->Init.AutoEnd = 1;
else hi2c.Init.AutoEnd = 0; else hi2c->Init.AutoEnd = 0;
// put the data directly into the external buffer // 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; ret = length;
return ret; return ret;
@ -210,7 +198,8 @@ uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8
* Function twi_masterWriteTo * Function twi_masterWriteTo
* Desc attempts to become twi bus master and write a * Desc attempts to become twi bus master and write a
* series of bytes to a device on the bus * 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 * data: pointer to byte array
* length: number of bytes in array * length: number of bytes in array
* sendStop: boolean indicating whether or not to send a stop at the end * 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, ..) * 4 .. other twi error (lost bus arbitration, bus error, ..)
* 5 .. timeout * 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; uint8_t ret = I2C_OK;
// if there are errors left from previous transactions, you need to restart // if there are errors left from previous transactions, you need to restart
// the interface for correct operation // the interface for correct operation
if (hi2c.ErrorCode != I2C_ERROR_NONE) if (hi2c->ErrorCode != I2C_ERROR_NONE)
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(hi2c);
if (sendStop) hi2c.Init.AutoEnd = 1; if (sendStop) hi2c->Init.AutoEnd = 1;
else hi2c.Init.AutoEnd = 0; else hi2c->Init.AutoEnd = 0;
// take data from an external buffer // 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 // parse errors
// check separately, because in hal libraries not all functions look at this // check separately, because in hal libraries not all functions look at this
if (HAL_I2C_Get_Interrupts_Status(&hi2c) & I2C_ISR_NACKF_M) if (HAL_I2C_Get_Interrupts_Status(hi2c) & I2C_ISR_NACKF_M)
hi2c.ErrorCode = I2C_ERROR_NACK; hi2c->ErrorCode = I2C_ERROR_NACK;
if (hi2c.ErrorCode == (HAL_I2C_ErrorTypeDef)I2C_ERROR_TIMEOUT) ret = I2C_TIMEOUT; // timeout 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_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 else if (hi2c->ErrorCode != (HAL_I2C_ErrorTypeDef)I2C_OK) ret = I2C_ERROR; // any other error
return ret; return ret;
} }
@ -251,97 +240,79 @@ uint8_t twi_masterWriteTo(uint8_t address, uint8_t* data, uint8_t length, uint8_
* Function twi_slaveWrite * Function twi_slaveWrite
* Desc attempts to become twi bus slave and write a * Desc attempts to become twi bus slave and write a
* series of bytes to a master after it asks * 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 * bytesNum: number of bytes in array
* Output 0 .. success * Output 0 .. success
* 5 .. timeout * 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)) if ((hi2c->ErrorCode != I2C_ERROR_NONE))
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(hi2c);
// send data // send data
HAL_StatusTypeDef error_code = HAL_OK; HAL_StatusTypeDef error_code = HAL_OK;
HAL_I2C_Clear_Reload(&hi2c); HAL_I2C_Clear_Reload(hi2c);
if (!(HAL_I2C_Get_CR1_Content(&hi2c) & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0 if (!(HAL_I2C_Get_CR1_Content(hi2c) & I2C_CR1_NOSTRETCH_M)) // NOSTRETCH = 0
HAL_I2C_Reset_TXDR_Content(&hi2c); HAL_I2C_Reset_TXDR_Content(hi2c);
HAL_I2C_Write_TXDR(&hi2c, txData[0]); // first recording is made in advance HAL_I2C_Write_TXDR(hi2c, txData[0]); // first recording is made in advance
// write byte // write byte
for (uint32_t tx_count = 1; tx_count < bytesNum; tx_count++) 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 // failed to write
HAL_I2C_Reset_TXDR_Content(&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_Interrupt_Flag(hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(hi2c);
return I2C_TIMEOUT; 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 // failed to complete transaction
HAL_I2C_Reset(&hi2c); HAL_I2C_Reset(hi2c);
return I2C_TIMEOUT; return I2C_TIMEOUT;
} }
HAL_I2C_Reset_TXDR_Content(&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_Interrupt_Flag(hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus
return I2C_OK; 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 * Function twi_interruptHandler
* Desc handles an interrupts from twi * Desc handles an interrupts from twi
* Input none * Input handler - pointer to wire common handler
* Output none * 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 int_mask = HAL_I2C_Get_CR1_Content(&(handler->i2c_param)) & I2C_INTMASK; // interrupts allowed
uint32_t interrupt_status = HAL_I2C_Get_Interrupts_Status(&hi2c); // current flags uint32_t interrupt_status = HAL_I2C_Get_Interrupts_Status(&(handler->i2c_param)); // current flags
// master calls by address, device in slave mode // master calls by address, device in slave mode
if ((interrupt_status & I2C_ISR_ADDR_M) && (int_mask & I2C_CR1_ADDRIE_M)) if ((interrupt_status & I2C_ISR_ADDR_M) && (int_mask & I2C_CR1_ADDRIE_M))
{ {
// reset ADDR flag // 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 // look at the transmission direction and respond to the request
if (interrupt_status & I2C_ISR_DIR_M) // master reads, slave sends 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 else // master writes, slave reads
{ {
twi_rxBufferIndex = 0; // write from the beginning of the buffer handler->rxBufferIndex = 0; // write from the beginning of the buffer
hi2c.State = HAL_I2C_STATE_BUSY; handler->i2c_param.State = HAL_I2C_STATE_BUSY;
HAL_I2C_Clear_Reload(&hi2c); HAL_I2C_Clear_Reload(&(handler->i2c_param));
// wait for interrupts by receiving a byte or a stop condition // 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)) if ((interrupt_status & I2C_ISR_RXNE_M) && (int_mask & I2C_CR1_RXIE_M))
{ {
// put new byte into buffer // 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 // master sent a STOP to the bus
if ((interrupt_status & I2C_ISR_STOPF_M) && (int_mask & I2C_CR1_STOPIE_M)) if ((interrupt_status & I2C_ISR_STOPF_M) && (int_mask & I2C_CR1_STOPIE_M))
{ {
hi2c.State = HAL_I2C_STATE_END; handler->i2c_param.State = HAL_I2C_STATE_END;
HAL_I2C_Reset_TXDR_Content(&hi2c); HAL_I2C_Reset_TXDR_Content(&(handler->i2c_param));
HAL_I2C_Reset_Interrupt_Flag(&hi2c, I2C_ICR_STOPCF_M); // Clear the STOP detection flag on the bus 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 // pass the received data to callback function
twi_onSlaveReceive(twi_rxBuffer, twi_rxBufferIndex); handler->onSlaveReceive(handler->instance, handler->rxBuffer, handler->rxBufferIndex);
} }
} }

View File

@ -5,10 +5,24 @@
extern "C" { extern "C" {
#endif #endif
#include "mik32_hal_i2c.h"
#ifndef TWI_BUFFER_LENGTH #ifndef TWI_BUFFER_LENGTH
#define TWI_BUFFER_LENGTH 32 #define TWI_BUFFER_LENGTH 32
#endif #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 // I2C state
typedef enum typedef enum
{ {
@ -21,17 +35,16 @@ typedef enum
I2C_BUSY = 6 I2C_BUSY = 6
} i2c_status_e; } i2c_status_e;
uint8_t twi_init(uint8_t slaveAddress); uint8_t twi_init (WireHandler_TypeDef* handler, uint8_t slaveAddress);
void twi_deinit(void); void twi_deinit(WireHandler_TypeDef* handler);
uint8_t twi_setFrequency(uint32_t frequency, bool onInit);
uint8_t twi_masterReadFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop); uint8_t twi_setFrequency(WireHandler_TypeDef* handler, uint32_t frequency, bool onInit);
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);
void twi_attachSlaveRxEvent(void (*function)(uint8_t*, int)); uint8_t twi_masterReadFrom (I2C_HandleTypeDef* hi2c, uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop);
void twi_attachSlaveTxEvent(void (*function)(void)); uint8_t twi_masterWriteTo (I2C_HandleTypeDef* hi2c, uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop);
void twi_interruptHandler(void); i2c_status_e twi_slaveWrite (I2C_HandleTypeDef* hi2c, uint8_t *txData, uint8_t bytesNum);
void twi_interruptHandler(WireHandler_TypeDef* handler);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -67,6 +67,7 @@ volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x);
volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x); volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x);
// the function initializes additional MCU pins depending on the specified pin number // the function initializes additional MCU pins depending on the specified pin number
void additionalPinsInit(uint32_t PinNumber); void additionalPinsInit(uint32_t PinNumber);
static inline void additionalPinsDeinit(uint32_t PinNumber){}
// UART // UART
// available uarts quantity // available uarts quantity
@ -87,23 +88,35 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber);
HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber); HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber);
// SPI // SPI
#define PIN_SPI_SS (10) #define SPI_COMMON_QTY 2
#define PIN_SPI_MOSI (11)
#define PIN_SPI_MISO (12) #define PIN_SPI_SS 10
#define PIN_SPI_SCK (13) #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 SS = PIN_SPI_SS;
static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK; 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, // config SEL_NSS1 to replace D10 to different controller pin,
// because pin 1.3 which is D10 by default is needed to spi // because NSS which is D9/D10 by default is needed to spi
void spi_onBegin(void); void spi_onBegin(uint8_t spiNum);
void spi_onEnd(void); void spi_onEnd(uint8_t spiNum);
// I2C // I2C
#define PIN_WIRE_SDA (18) #define PIN_WIRE_SDA (18)
#define PIN_WIRE_SCL (19) #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 SDA = PIN_WIRE_SDA;
static const uint8_t SCL = PIN_WIRE_SCL; static const uint8_t SCL = PIN_WIRE_SCL;
// available frequencies // available frequencies
@ -112,7 +125,7 @@ static const uint8_t SCL = PIN_WIRE_SCL;
#define WIRE_FREQ_1000K 1000000 #define WIRE_FREQ_1000K 1000000
// interrupts // interrupts
#define EXTERNAL_INTERRUPTS_QTY 7 #define EXTERNAL_INTERRUPTS_QTY 8
extern uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3]; extern uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3];
// determines the board pin number by interrupt number // determines the board pin number by interrupt number
#define interruptToDigitalPin(interruptNum) (interruptInfo[interruptNum][0]) #define interruptToDigitalPin(interruptNum) (interruptInfo[interruptNum][0])

View File

@ -16,7 +16,22 @@
#include "wiring_analog.h" #include "wiring_analog.h"
#include "wiring_LL.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 // list of pin numbers from both ports with pins inside the port
const HAL_PinsTypeDef digitalPinToGpioPinArray[] = const HAL_PinsTypeDef digitalPinToGpioPinArray[] =
@ -51,17 +66,16 @@ const HAL_PinsTypeDef digitalPinToGpioPinArray[] =
GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber) GPIO_TypeDef* digitalPinToPort(uint32_t digPinNumber)
{ {
GPIO_TypeDef* gpioNum = 0; GPIO_TypeDef* gpioNum = 0;
// port 0 - board pins 0...6, 9, 16(A2), 17(A3), 20(A4), 21(A5) // port 2 - led and button
if ((digPinNumber >= 0 && digPinNumber <= 6) || digPinNumber == 9 || digPinNumber == 16 if (digPinNumber == LED_BUILTIN || digPinNumber == BTN_BUILTIN)
|| digPinNumber == 17 || digPinNumber == 20 || digPinNumber == 21) // 12 pieces gpioNum = GPIO_2;
gpioNum = GPIO_0;
// port 1 - board pins 7, 8, 10...13, 14(А0), 15(А1), 18,19 // port 1 - board pins 7, 8, 10...13, 14(А0), 15(А1), 18,19
else if (digPinNumber == 7 || digPinNumber == 8 || (digPinNumber >= 10 && digPinNumber <= 15) 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; gpioNum = GPIO_1;
// port 2 - led and button // port 0 - board pins 0...6, 9, 16(A2), 17(A3), 20(A4), 21(A5)
else if (digPinNumber == LED_BUILTIN || digPinNumber == BTN_BUILTIN) else
gpioNum = GPIO_2; gpioNum = GPIO_0;
return gpioNum; return gpioNum;
} }
@ -72,9 +86,11 @@ HAL_PinsTypeDef digitalPinToBitMask(uint32_t digPinNumber)
if (digPinNumber < pinCommonQty()) if (digPinNumber < pinCommonQty())
{ {
HAL_PinsTypeDef mask; HAL_PinsTypeDef mask;
// if spi is on default pin 1.3 is needed for spi, D10 is replaced to pin 1.4 // if spi is on default pin NSS_IN is needed for spi, board pin is replaced to pin NSS_OUT
if (spiNssPinIsBlocked && (digPinNumber == 10)) if ((digPinNumber == 10) && spi1NssPinIsBlocked)
mask = GPIO_PIN_4; mask = SPI1_NSS_OUT_PIN;
else if ((digPinNumber == 9) && spi0NssPinIsBlocked)
mask = SPI0_NSS_OUT_PIN;
else else
mask = digitalPinToGpioPinArray[digPinNumber]; mask = digitalPinToGpioPinArray[digPinNumber];
return mask; 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 // 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) 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) if (PinNumber == A5)
{ HAL_GPIO_WritePin(SELA45_PORT, SELA45_PIN, GPIO_PIN_HIGH);
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);
}
else if(PinNumber == A4) else if(PinNumber == A4)
{
// return the switch to A4 in case A5 was previously read // 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(SELA45_PORT, SELA45_PIN, GPIO_PIN_LOW);
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_15, GPIO_PIN_LOW);
}
} }
// ---------------------- ADC ---------------------- // // ---------------------- ADC ---------------------- //
@ -153,25 +171,14 @@ uint32_t analogInputToChannelNumber(uint32_t PinNumber)
// ---------------------- PWM ---------------------- // // ---------------------- PWM ---------------------- //
// use only if digitalPinHasPWM() == true // use only if digitalPinHasPWM() == true
#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)) ? 1:0) #define PWM_PIN_TO_PORT_NUMBER(pin) (((pin==10)||(pin==11)||(pin==12)||(pin==13)) ? 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;
}
// use only if digitalPinHasPWM() == true // use only if digitalPinHasPWM() == true
// return true if digitalPin configured as pwm // return true if digitalPin configured as pwm
bool digitalPinPwmIsOn(uint8_t digitalPin) bool digitalPinPwmIsOn(uint8_t digitalPin)
{ {
uint8_t config = 0; 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) if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0)
config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift);
@ -187,10 +194,10 @@ bool digitalPinPwmIsOn(uint8_t digitalPin)
bool digitalPinHasPWM(uint8_t p) bool digitalPinHasPWM(uint8_t p)
{ {
bool ret = false; bool ret = false;
// if spi is in use D10 cannot work as pwm // if spi is in use D9 or D10 cannot work as pwm
if (spiNssPinIsBlocked && (p == 10)) if (((p == 9) && spi0NssPinIsBlocked) || ((p == 10) && spi1NssPinIsBlocked))
ret = false; 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; ret = true;
return ret; return ret;
} }
@ -204,7 +211,7 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber)
if (digPinNumber == 3 || digPinNumber == 5 || digPinNumber == 6 || digPinNumber == 9) if (digPinNumber == 3 || digPinNumber == 5 || digPinNumber == 6 || digPinNumber == 9)
timerNum = TIMER32_1; timerNum = TIMER32_1;
// timer 2 // timer 2
else if (digPinNumber == 10 || digPinNumber == 11) else if (digPinNumber == 10 || digPinNumber == 11 || digPinNumber == 12 || digPinNumber == 13)
timerNum = TIMER32_2; timerNum = TIMER32_2;
return timerNum; return timerNum;
@ -214,9 +221,9 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber)
HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber) HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber)
{ {
HAL_TIMER32_CHANNEL_IndexTypeDef channel = 0; 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 == 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; else if (digPinNumber == 9 || digPinNumber == 10) channel = TIMER32_CHANNEL_3;
return channel; return channel;
} }
@ -232,7 +239,9 @@ uint8_t interruptInfo[EXTERNAL_INTERRUPTS_QTY][3] =
{ 5, GPIO_LINE_1, GPIO_MUX_LINE_1_PORT0_1}, // INT3 { 5, GPIO_LINE_1, GPIO_MUX_LINE_1_PORT0_1}, // INT3
{ 8, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_9}, // INT4 { 8, GPIO_LINE_5, GPIO_MUX_LINE_5_PORT1_9}, // INT4
{ 9, GPIO_LINE_3, GPIO_MUX_LINE_3_PORT0_3}, // INT5 { 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) int8_t digitalPinToGpioIntMux(uint8_t digPinNumber)
@ -275,44 +284,94 @@ int8_t digitalPinToInterrupt(uint32_t digPinNumber)
} }
// ---------------------- SPI ---------------------- // // ---------------------- 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, // On Elbear Ace-Uno rev1.1.0 spi0 needs pin 0.3, spi1 needs pin 1.3 for correct work (NSS_IN).
// because spi needs pin 1.3 for correct work // 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 if (config == 0) // common gpio
{ {
// get info from pin gpio1.3 and set config to gpio1.4 if (spiNum == 1)
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)), // get info from pin NSS_IN and set config to NSS_OUT
HAL_GPIO_DS_2MA); HAL_GPIO_PinConfig(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN),
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_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_IN_PIN)),
HAL_GPIO_DS_2MA);
// pin D10 was switched to different gpio and can be used further 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 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
analogWriteStop(10); if (spiNum == 1)
ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running"); {
analogWriteStop(10);
ErrorMsgHandler("analogWrite(): D10 cannot be used as PWM pin while SPI is running");
}
else
{
analogWriteStop(9);
ErrorMsgHandler("analogWrite(): D9 cannot be used as PWM pin while SPI1 is running");
}
} }
// switch seller to pin 1.4 // switch seller to pin NSS_OUT
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_6, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA); if (spiNum == 1)
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_HIGH); {
spiNssPinIsBlocked = true; // block spi pin HAL_GPIO_PinConfig(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin (SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_HIGH);
spi1NssPinIsBlocked = true; // block spi pin
}
else
{
HAL_GPIO_PinConfig(SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, HAL_GPIO_MODE_GPIO_OUTPUT, HAL_GPIO_PULL_NONE, HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin (SPI0_SWITCH_PORT, SPI0_SWITCH_PIN, GPIO_PIN_HIGH);
spi0NssPinIsBlocked = true; // block spi pin
}
} }
void spi_onEnd(void) void spi_onEnd(uint8_t spiNum)
{ {
// get info from pin gpio1.4 and set config to gpio1.3 // get info from pin NSS_OUT and set config to NSS_IN
HAL_GPIO_PinConfig(GPIO_1, GPIO_PIN_3, HAL_GPIO_GetPinDirection(GPIO_1, GPIO_PIN_4), if (spiNum == 1)
(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))); HAL_GPIO_PinConfig(SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN, HAL_GPIO_GetPinDirection(SPI1_NSS_OUT_PORT, SPI1_NSS_OUT_PIN),
(HAL_GPIO_PullTypeDef)PIN_GET_PAD_CONFIG(PORT_1_PUPD, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN)), HAL_GPIO_DS_2MA);
HAL_GPIO_WritePin (SPI1_NSS_IN_PORT, SPI1_NSS_IN_PIN,
(GPIO_PinState)GPIO_GET_PIN_STATE(SPI1_NSS_OUT_PORT, PIN_MASK_TO_PIN_NUMBER(SPI1_NSS_OUT_PIN)));
// switch seller back to pin 1.3 // switch seller back to NSS_IN
HAL_GPIO_WritePin(GPIO_1, GPIO_PIN_6, GPIO_PIN_LOW); HAL_GPIO_WritePin(SPI1_SWITCH_PORT, SPI1_SWITCH_PIN, GPIO_PIN_LOW);
spiNssPinIsBlocked = false; // unblock spi pin 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
}
} }

View 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

View 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
}
}

View 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
View 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");
}
}
}

View File

@ -32,49 +32,51 @@ extern "C" {
#include "mik32_hal_gpio.h" #include "mik32_hal_gpio.h"
#include "mik32_hal_timer32.h" #include "mik32_hal_timer32.h"
#define PORT_PIN_MASK 0xF
// digital pins // digital pins
#define P0_0 0 typedef enum
#define P0_1 1 {
#define P0_2 2 P0_0 = 0, // 0
#define P0_3 3 P0_1, // 1
#define P0_4 4 P0_2, // 2
#define P0_5 5 P0_3, // 3
#define P0_6 6 P0_4, // 4
#define P0_7 7 P0_5, // 5
#define P0_8 8 P0_6, // 6
#define P0_9 9 P0_7, // 7
#define P0_10 10 P0_8, // 8
#define P0_11 11 P0_9, // 9
#define P0_12 12 P0_10, // 10
#define P0_13 13 P0_11, // 11
#define P0_14 14 P0_12, // 12
#define P0_15 15 P0_13, // 13
#define P1_0 16 P0_14, // 14
#define P1_1 17 P0_15, // 15
#define P1_2 18 P1_0, // 16
#define P1_3 19 P1_1, // 17
#define P1_4 20 P1_2, // 18
#define P1_5 21 P1_3, // 19
#define P1_6 22 P1_4, // 20
#define P1_7 23 P1_5, // 21
#define P1_8 24 P1_6, // 22
#define P1_9 25 P1_7, // 23
#define P1_10 26 P1_8, // 24
#define P1_11 27 P1_9, // 25
#define P1_12 28 P1_10, // 26
#define P1_13 29 P1_11, // 27
#define P1_14 30 P1_12, // 28
#define P1_15 31 P1_13, // 29
#define P2_0 32 P1_14, // 30
#define P2_1 33 P1_15, // 31
#define P2_2 34 P2_0, // 32
#define P2_3 35 P2_1, // 33
#define P2_4 36 P2_2, // 34
#define P2_5 37 P2_3, // 35
#define P2_6 38 P2_4, // 36
#define P2_7 39 P2_5, // 37
P2_6, // 38
P2_7, // 39
PINS_COMMON_QTY, // 40
} DigitalPinsTypeDef;
// analog pins // analog pins
#define PIN_A0 (P1_5) #define PIN_A0 (P1_5)
@ -112,14 +114,15 @@ static inline HAL_PinsTypeDef digitalPinToBitMask(uint32_t digitalPinNumber)
// total number of pins available for initialization // total number of pins available for initialization
static inline uint16_t pinCommonQty(void) 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 // the function returns a reference to the OUTPUT address of the GPIO register
volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x); volatile uint32_t* portOutputRegister(GPIO_TypeDef* GPIO_x);
// the function returns a reference to the STATE address of the GPIO register // the function returns a reference to the STATE address of the GPIO register
volatile uint32_t* portInputRegister(GPIO_TypeDef* GPIO_x); 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 additionalPinsInit(uint32_t PinNumber) {}
static inline void additionalPinsDeinit(uint32_t PinNumber){}
// UART // UART
// available uarts quantity // available uarts quantity
@ -140,24 +143,42 @@ TIMER32_TypeDef* pwmPinToTimer(uint32_t digPinNumber);
HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber); HAL_TIMER32_CHANNEL_IndexTypeDef pwmPinToTimerChannel(uint32_t digPinNumber);
// SPI // SPI
#define PIN_SPI_SS (P1_3) #define SPI_COMMON_QTY 2
#define PIN_SPI_MOSI (P1_1)
#define PIN_SPI_MISO (P1_0) #define PIN_SPI_SS P1_3
#define PIN_SPI_SCK (P1_2) #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 SS = PIN_SPI_SS;
static const uint8_t MOSI = PIN_SPI_MOSI; static const uint8_t MOSI = PIN_SPI_MOSI;
static const uint8_t MISO = PIN_SPI_MISO; static const uint8_t MISO = PIN_SPI_MISO;
static const uint8_t SCK = PIN_SPI_SCK; static const uint8_t SCK = PIN_SPI_SCK;
// functions is needed for compatibility with other boards
static inline void spi_onBegin(void) {} #define PIN_SPI1_SS P0_3
static inline void spi_onEnd(void) {} #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 // I2C
#define PIN_WIRE_SDA (P1_12) #define I2C_COMMON_QTY 2
#define PIN_WIRE_SCL (P1_13) // Wire (I2C1)
#define I2C_NUM (1) // i2c number 1 #define PIN_WIRE_SDA P1_12
static const uint8_t SDA = PIN_WIRE_SDA; #define PIN_WIRE_SCL P1_13
static const uint8_t SCL = PIN_WIRE_SCL; 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 // available frequencies
#define WIRE_FREQ_100K 100000 #define WIRE_FREQ_100K 100000
#define WIRE_FREQ_400K 400000 #define WIRE_FREQ_400K 400000

View File

@ -94,17 +94,13 @@ uint32_t analogInputToChannelNumber(uint32_t PinNumber)
// ---------------------- PWM ---------------------- // // ---------------------- PWM ---------------------- //
// use only if digitalPinHasPWM() == true // use only if digitalPinHasPWM() == true
#define PWM_PIN_TO_PORT_NUMBER(pin) (((pin) & 16) ? 1 : 0) #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 // use only if digitalPinHasPWM() == true
// return true if digitalPin configured as pwm // return true if digitalPin configured as pwm
bool digitalPinPwmIsOn(uint8_t digitalPin) bool digitalPinPwmIsOn(uint8_t digitalPin)
{ {
uint8_t config = 0; uint8_t config = 0;
uint8_t pinShift = pwmPinToGpioPinShift(digitalPin); uint8_t pinShift = digitalPin & 3;
if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0) if (PWM_PIN_TO_PORT_NUMBER(digitalPin) == 0)
config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift); config = PIN_GET_PAD_CONFIG(PORT_0_CFG, pinShift);
@ -209,4 +205,32 @@ int8_t digitalPinToInterrupt(uint32_t digPinNumber)
return i; return i;
} }
return NOT_AN_INTERRUPT; 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");
}
}
} }